Multi-step research agent

The research agent is inspired by this project and BabyAGI.

The idea is as follows: we start with a research question and some source of data we can retrieve from. We retrieve the data relevant for the original question, but then instead of feeding it into the LLM prompt to answer the question, like a conventional RAG would do, we use it to ask an LLM what further questions, based on the retrieved context, would be most useful to answer the original question. We then pick one of these to do retrieval on, and by repeating that process, build a tree of questions, each with attached context, which we store as a knowledge graph.

When we decide we’ve done this for long enough (currently just a constraint on the number of nodes), we then walk back up the graph, first answering the leaf questions, then using these answers (along with the context retrieved for their parent question) to answer the parent question, etc.

Technically speaking, the flow consists of two tasks, QuestionTask and AnswerTask. The QuestionTask starts with a user question, and embeds this into the graph as the first un-answered question. Its get_next_unit() method looks up all the as yet un-answered questions, and chooses the one that’s most salient to the original question (so that question is the TaskUnit it returns). Its worker then retrieves the context (RAG-style) for that question, but instead of answering it, creates up to 3 further questions that would be most helpful to answer in order to answer the original question. We thus build up a tree of questions, where each non-leaf node has a retrieval context attached to it - all stored in the knowledge graph for easy retrieval. This goes on until we have enough questions (currently just a fixed number of iterations).

The AnswerTask then rolls the tree back up. It ignores all the questions without a retrieved context; and the TaskUnit that its get_next_unit() returns is then any question that has no un-answered children. Its worker then proceeds to answer that question using its retrieved context and the answers from its children, if any. This goes on until we’ve worked our way back up to answering the original question.

This shows how the tasks can create TaskUnits for themselves and for each other, which enables a whole new level of self-organization.

The different Tasks don’t have to all form part of a connected DAG either. For example, two tasks could take turns creating TaskUnits for one another - just one of many interaction patterns possible within the architecture.

[1]:
from pathlib import Path
import os

import kuzu
from dotenv import load_dotenv

# This assumes you have a .env file in the examples folder, containing your OpenAI key
load_dotenv()

WORKING_DIR = Path(os.path.realpath("."))

from motleycrew import MotleyCrew
from motleycrew.common import configure_logging, LLMFramework
from motleycrew.common.llms import init_llm
from motleycrew.applications.research_agent.question_task import QuestionTask
from motleycrew.applications.research_agent.answer_task import AnswerTask
from motleycrew.tools.simple_retriever_tool import SimpleRetrieverTool

from llama_index.embeddings.openai import OpenAIEmbedding

configure_logging(verbose=True)
[2]:
DATA_DIR = os.path.realpath(os.path.join(WORKING_DIR, "mahabharata/text/TinyTales"))
PERSIST_DIR = WORKING_DIR / "examples/data/research_agent_storage"
[ ]:
# Only run this the first time you run the notebook, to get the raw data
!git clone https://github.com/rahulnyk/mahabharata.git
[4]:
crew = MotleyCrew()
2024-09-27 22:33:38,055 - motleycrew - INFO - No db_path provided, creating temporary directory for database
2024-09-27 22:33:38,056 - motleycrew - INFO - Using Kuzu graph store with path: /var/folders/fv/tyhll76x0fn6l7j_q2nhvyg00000gn/T/tmp4obi9n3p/kuzu_db
[5]:
QUESTION = "Why did Arjuna kill Karna, his half-brother?"
MAX_ITER = 3
ANSWER_LENGTH = 200

embeddings = OpenAIEmbedding(model="text-embedding-ada-002")
llm = init_llm(LLMFramework.LANGCHAIN, llm_name="gpt-4o")

query_tool = SimpleRetrieverTool(DATA_DIR, PERSIST_DIR, return_strings_only=True, embeddings=embeddings)

# We need to pass the crew to the Tasks so they have access to the graph store
# and the crew is aware of them

# The question task is responsible for new question generation
question_recipe = QuestionTask(
    crew=crew, question=QUESTION, query_tool=query_tool, max_iter=MAX_ITER, llm=llm
)

# The answer task is responsible for rolling the answers up the tree
answer_recipe = AnswerTask(answer_length=ANSWER_LENGTH, crew=crew, llm=llm)

# Only kick off the answer task once the question task is done
question_recipe >> answer_recipe
2024-09-27 22:33:38,974 - motleycrew - INFO - Node table TaskNode does not exist in the database, creating
2024-09-27 22:33:38,980 - motleycrew - INFO - Property name not present in table for label TaskNode, creating
2024-09-27 22:33:38,982 - motleycrew - INFO - Property done not present in table for label TaskNode, creating
2024-09-27 22:33:38,983 - motleycrew - INFO - Node table QuestionGenerationTaskUnit does not exist in the database, creating
2024-09-27 22:33:38,985 - motleycrew - INFO - Property status not present in table for label QuestionGenerationTaskUnit, creating
2024-09-27 22:33:38,986 - motleycrew - INFO - Property output not present in table for label QuestionGenerationTaskUnit, creating
2024-09-27 22:33:38,986 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2024-09-27 22:33:38,989 - motleycrew - INFO - Property question not present in table for label QuestionGenerationTaskUnit, creating
2024-09-27 22:33:38,989 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2024-09-27 22:33:38,991 - motleycrew - INFO - Relation table QuestionGenerationTaskUnit_belongs from QuestionGenerationTaskUnit to TaskNode does not exist in the database, creating
2024-09-27 22:33:38,993 - motleycrew - INFO - Inserting new node with label TaskNode: name='QuestionTask' done=False
2024-09-27 22:33:38,997 - motleycrew - INFO - Node created OK
2024-09-27 22:33:38,998 - motleycrew - INFO - Relation table task_is_upstream from TaskNode to TaskNode does not exist in the database, creating
2024-09-27 22:33:39,000 - motleycrew - INFO - Node table Question does not exist in the database, creating
2024-09-27 22:33:39,002 - motleycrew - INFO - Property question not present in table for label Question, creating
2024-09-27 22:33:39,003 - motleycrew - INFO - Property answer not present in table for label Question, creating
2024-09-27 22:33:39,005 - motleycrew - INFO - Property context not present in table for label Question, creating
2024-09-27 22:33:39,005 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2024-09-27 22:33:39,007 - motleycrew - INFO - Inserting new node with label Question: question='Why did Arjuna kill Karna, his half-brother?' answer=None context=None
2024-09-27 22:33:39,007 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2024-09-27 22:33:39,009 - motleycrew - INFO - Node created OK
2024-09-27 22:33:39,025 - motleycrew - INFO - Node table QuestionAnsweringTaskUnit does not exist in the database, creating
2024-09-27 22:33:39,027 - motleycrew - INFO - Property status not present in table for label QuestionAnsweringTaskUnit, creating
2024-09-27 22:33:39,028 - motleycrew - INFO - Property output not present in table for label QuestionAnsweringTaskUnit, creating
2024-09-27 22:33:39,028 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2024-09-27 22:33:39,030 - motleycrew - INFO - Property question not present in table for label QuestionAnsweringTaskUnit, creating
2024-09-27 22:33:39,030 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2024-09-27 22:33:39,032 - motleycrew - INFO - Relation table QuestionAnsweringTaskUnit_belongs from QuestionAnsweringTaskUnit to TaskNode does not exist in the database, creating
2024-09-27 22:33:39,034 - motleycrew - INFO - Inserting new node with label TaskNode: name='AnswerTask' done=False
2024-09-27 22:33:39,035 - motleycrew - INFO - Node created OK
2024-09-27 22:33:39,047 - motleycrew - INFO - Creating relation task_is_upstream from TaskNode:0 to TaskNode:1
2024-09-27 22:33:39,054 - motleycrew - INFO - Relation created OK
[5]:
QuestionTask(name=QuestionTask, done=False)
[6]:
# And now run the recipes
done_items = crew.run()
2024-09-27 22:33:39,069 - motleycrew - INFO - Available tasks: [QuestionTask(name=QuestionTask, done=False)]
2024-09-27 22:33:39,073 - motleycrew - INFO - Processing task: QuestionTask(name=QuestionTask, done=False)
2024-09-27 22:33:39,084 - motleycrew - INFO - Loaded unanswered questions: [Question(id=0, question=Why did Arjuna kill Karna, his half-brother?, answer=None, context=None)]
2024-09-27 22:33:39,515 - motleycrew - INFO - Most pertinent question according to the tool: question='Why did Arjuna kill Karna, his half-brother?' answer=None context=None
2024-09-27 22:33:39,515 - motleycrew - INFO - Got a matching unit for task QuestionTask(name=QuestionTask, done=False)
2024-09-27 22:33:39,516 - motleycrew - INFO - Processing unit: TaskUnit(status=pending)
2024-09-27 22:33:39,516 - motleycrew - INFO - Assigned unit TaskUnit(status=pending) to agent MotleyTool(name=Question Generator Tool), dispatching
2024-09-27 22:33:39,516 - motleycrew - INFO - Node TaskUnit(status=running) does not exist, creating
2024-09-27 22:33:39,517 - motleycrew - INFO - Inserting new node with label QuestionGenerationTaskUnit: TaskUnit(status=running)
2024-09-27 22:33:39,518 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2024-09-27 22:33:39,518 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2024-09-27 22:33:39,522 - motleycrew - INFO - Node created OK
2024-09-27 22:33:39,528 - motleycrew - INFO - Relation from TaskUnit(status=running) to name='QuestionTask' done=False does not exist, creating
2024-09-27 22:33:39,530 - motleycrew - INFO - Creating relation QuestionGenerationTaskUnit_belongs from QuestionGenerationTaskUnit:0 to TaskNode:0
2024-09-27 22:33:39,534 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:39,534 - motleycrew - INFO - ==== Started iteration 1 of 3 ====
2024-09-27 22:33:41,163 - motleycrew - INFO - Inserting question: What role did Krishna play in Arjuna's decision to kill Karna?
2024-09-27 22:33:41,166 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2024-09-27 22:33:41,167 - motleycrew - INFO - Inserting new node with label Question: question="What role did Krishna play in Arjuna's decision to kill Karna?" answer=None context=None
2024-09-27 22:33:41,174 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2024-09-27 22:33:41,178 - motleycrew - INFO - Node created OK
2024-09-27 22:33:41,182 - motleycrew - INFO - Relation table is_subquestion from Question to Question does not exist in the database, creating
2024-09-27 22:33:41,185 - motleycrew - INFO - Creating relation is_subquestion from Question:0 to Question:1
2024-09-27 22:33:41,191 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:41,191 - motleycrew - INFO - Inserting question: How did Karna's chariot getting stuck in the mud influence the outcome of his duel with Arjuna?
2024-09-27 22:33:41,192 - motleycrew - INFO - Inserting new node with label Question: question="How did Karna's chariot getting stuck in the mud influence the outcome of his duel with Arjuna?" answer=None context=None
2024-09-27 22:33:41,193 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2024-09-27 22:33:41,195 - motleycrew - INFO - Node created OK
2024-09-27 22:33:41,198 - motleycrew - INFO - Creating relation is_subquestion from Question:0 to Question:2
2024-09-27 22:33:41,200 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:41,200 - motleycrew - INFO - Inserting question: What was the significance of Karna forgetting the mantra during his battle with Arjuna?
2024-09-27 22:33:41,201 - motleycrew - INFO - Inserting new node with label Question: question='What was the significance of Karna forgetting the mantra during his battle with Arjuna?' answer=None context=None
2024-09-27 22:33:41,201 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2024-09-27 22:33:41,204 - motleycrew - INFO - Node created OK
2024-09-27 22:33:41,207 - motleycrew - INFO - Creating relation is_subquestion from Question:0 to Question:3
2024-09-27 22:33:41,209 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:41,210 - motleycrew - INFO - Inserted 3 questions
2024-09-27 22:33:41,211 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2024-09-27 22:33:41,212 - motleycrew - INFO - Task unit TaskUnit(status=running) completed, marking as done
2024-09-27 22:33:41,216 - motleycrew - INFO - Available tasks: [QuestionTask(name=QuestionTask, done=False)]
2024-09-27 22:33:41,219 - motleycrew - INFO - Processing task: QuestionTask(name=QuestionTask, done=False)
2024-09-27 22:33:41,221 - motleycrew - INFO - Loaded unanswered questions: [Question(id=1, question=What role did Krishna play in Arjuna's decision to kill Karna?, answer=None, context=None), Question(id=2, question=How did Karna's chariot getting stuck in the mud influence the outcome of his duel with Arjuna?, answer=None, context=None), Question(id=3, question=What was the significance of Karna forgetting the mantra during his battle with Arjuna?, answer=None, context=None)]
2024-09-27 22:33:41,697 - motleycrew - INFO - Most pertinent question according to the tool: question="What role did Krishna play in Arjuna's decision to kill Karna?" answer=None context=None
2024-09-27 22:33:41,698 - motleycrew - INFO - Got a matching unit for task QuestionTask(name=QuestionTask, done=False)
2024-09-27 22:33:41,698 - motleycrew - INFO - Processing unit: TaskUnit(status=pending)
2024-09-27 22:33:41,698 - motleycrew - INFO - Assigned unit TaskUnit(status=pending) to agent MotleyTool(name=Question Generator Tool), dispatching
2024-09-27 22:33:41,699 - motleycrew - INFO - Node TaskUnit(status=running) does not exist, creating
2024-09-27 22:33:41,700 - motleycrew - INFO - Inserting new node with label QuestionGenerationTaskUnit: TaskUnit(status=running)
2024-09-27 22:33:41,700 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2024-09-27 22:33:41,701 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2024-09-27 22:33:41,704 - motleycrew - INFO - Node created OK
2024-09-27 22:33:41,712 - motleycrew - INFO - Relation from TaskUnit(status=running) to name='QuestionTask' done=False does not exist, creating
2024-09-27 22:33:41,715 - motleycrew - INFO - Creating relation QuestionGenerationTaskUnit_belongs from QuestionGenerationTaskUnit:1 to TaskNode:0
2024-09-27 22:33:41,718 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:41,719 - motleycrew - INFO - ==== Started iteration 2 of 3 ====
2024-09-27 22:33:43,771 - motleycrew - INFO - Inserting question: What did Krishna say to Arjuna about duty and action on the battlefield?
2024-09-27 22:33:43,773 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2024-09-27 22:33:43,776 - motleycrew - INFO - Inserting new node with label Question: question='What did Krishna say to Arjuna about duty and action on the battlefield?' answer=None context=None
2024-09-27 22:33:43,776 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2024-09-27 22:33:43,781 - motleycrew - INFO - Node created OK
2024-09-27 22:33:43,785 - motleycrew - INFO - Creating relation is_subquestion from Question:1 to Question:4
2024-09-27 22:33:43,790 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:43,790 - motleycrew - INFO - Inserting question: How did Krishna intervene during the duel between Karna and Arjuna?
2024-09-27 22:33:43,791 - motleycrew - INFO - Inserting new node with label Question: question='How did Krishna intervene during the duel between Karna and Arjuna?' answer=None context=None
2024-09-27 22:33:43,791 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2024-09-27 22:33:43,793 - motleycrew - INFO - Node created OK
2024-09-27 22:33:43,796 - motleycrew - INFO - Creating relation is_subquestion from Question:1 to Question:5
2024-09-27 22:33:43,799 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:43,799 - motleycrew - INFO - Inserting question: What was Krishna's response to Karna's plea for honor while he was trying to free his chariot wheel?
2024-09-27 22:33:43,800 - motleycrew - INFO - Inserting new node with label Question: question="What was Krishna's response to Karna's plea for honor while he was trying to free his chariot wheel?" answer=None context=None
2024-09-27 22:33:43,800 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2024-09-27 22:33:43,803 - motleycrew - INFO - Node created OK
2024-09-27 22:33:43,805 - motleycrew - INFO - Creating relation is_subquestion from Question:1 to Question:6
2024-09-27 22:33:43,808 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:43,808 - motleycrew - INFO - Inserted 3 questions
2024-09-27 22:33:43,809 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2024-09-27 22:33:43,811 - motleycrew - INFO - Task unit TaskUnit(status=running) completed, marking as done
2024-09-27 22:33:43,816 - motleycrew - INFO - Available tasks: [QuestionTask(name=QuestionTask, done=False)]
2024-09-27 22:33:43,817 - motleycrew - INFO - Processing task: QuestionTask(name=QuestionTask, done=False)
2024-09-27 22:33:43,820 - motleycrew - INFO - Loaded unanswered questions: [Question(id=2, question=How did Karna's chariot getting stuck in the mud influence the outcome of his duel with Arjuna?, answer=None, context=None), Question(id=3, question=What was the significance of Karna forgetting the mantra during his battle with Arjuna?, answer=None, context=None), Question(id=4, question=What did Krishna say to Arjuna about duty and action on the battlefield?, answer=None, context=None), Question(id=5, question=How did Krishna intervene during the duel between Karna and Arjuna?, answer=None, context=None), Question(id=6, question=What was Krishna's response to Karna's plea for honor while he was trying to free his chariot wheel?, answer=None, context=None)]
2024-09-27 22:33:44,307 - motleycrew - INFO - Most pertinent question according to the tool: question='How did Krishna intervene during the duel between Karna and Arjuna?' answer=None context=None
2024-09-27 22:33:44,308 - motleycrew - INFO - Got a matching unit for task QuestionTask(name=QuestionTask, done=False)
2024-09-27 22:33:44,309 - motleycrew - INFO - Processing unit: TaskUnit(status=pending)
2024-09-27 22:33:44,309 - motleycrew - INFO - Assigned unit TaskUnit(status=pending) to agent MotleyTool(name=Question Generator Tool), dispatching
2024-09-27 22:33:44,310 - motleycrew - INFO - Node TaskUnit(status=running) does not exist, creating
2024-09-27 22:33:44,311 - motleycrew - INFO - Inserting new node with label QuestionGenerationTaskUnit: TaskUnit(status=running)
2024-09-27 22:33:44,312 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2024-09-27 22:33:44,312 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2024-09-27 22:33:44,316 - motleycrew - INFO - Node created OK
2024-09-27 22:33:44,325 - motleycrew - INFO - Relation from TaskUnit(status=running) to name='QuestionTask' done=False does not exist, creating
2024-09-27 22:33:44,328 - motleycrew - INFO - Creating relation QuestionGenerationTaskUnit_belongs from QuestionGenerationTaskUnit:2 to TaskNode:0
2024-09-27 22:33:44,331 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:44,332 - motleycrew - INFO - ==== Started iteration 3 of 3 ====
2024-09-27 22:33:46,317 - motleycrew - INFO - Inserting question: How did Krishna intervene when Karna fired the serpent-arrow at Arjuna?
2024-09-27 22:33:46,320 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2024-09-27 22:33:46,322 - motleycrew - INFO - Inserting new node with label Question: question='How did Krishna intervene when Karna fired the serpent-arrow at Arjuna?' answer=None context=None
2024-09-27 22:33:46,323 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2024-09-27 22:33:46,327 - motleycrew - INFO - Node created OK
2024-09-27 22:33:46,330 - motleycrew - INFO - Creating relation is_subquestion from Question:5 to Question:7
2024-09-27 22:33:46,333 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:46,334 - motleycrew - INFO - Inserting question: What did Krishna say to Karna when Karna's chariot got stuck in the mud during his duel with Arjuna?
2024-09-27 22:33:46,335 - motleycrew - INFO - Inserting new node with label Question: question="What did Krishna say to Karna when Karna's chariot got stuck in the mud during his duel with Arjuna?" answer=None context=None
2024-09-27 22:33:46,335 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2024-09-27 22:33:46,338 - motleycrew - INFO - Node created OK
2024-09-27 22:33:46,341 - motleycrew - INFO - Creating relation is_subquestion from Question:5 to Question:8
2024-09-27 22:33:46,344 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:46,344 - motleycrew - INFO - Inserting question: How did Krishna assist Arjuna when King Bhagadatta attacked with the Vishnu-astra?
2024-09-27 22:33:46,345 - motleycrew - INFO - Inserting new node with label Question: question='How did Krishna assist Arjuna when King Bhagadatta attacked with the Vishnu-astra?' answer=None context=None
2024-09-27 22:33:46,345 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2024-09-27 22:33:46,347 - motleycrew - INFO - Node created OK
2024-09-27 22:33:46,349 - motleycrew - INFO - Creating relation is_subquestion from Question:5 to Question:9
2024-09-27 22:33:46,351 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:46,351 - motleycrew - INFO - Inserted 3 questions
2024-09-27 22:33:46,353 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2024-09-27 22:33:46,355 - motleycrew - INFO - Task unit TaskUnit(status=running) completed, marking as done
2024-09-27 22:33:46,361 - motleycrew - INFO - Available tasks: [AnswerTask(name=AnswerTask, done=False)]
2024-09-27 22:33:46,363 - motleycrew - INFO - Processing task: AnswerTask(name=AnswerTask, done=False)
2024-09-27 22:33:46,369 - motleycrew - INFO - Available questions: [Question(id=5, question=How did Krishna intervene during the duel between Karna and Arjuna?, answer=None, context=["Krishna, however, intervened. ...])]
2024-09-27 22:33:46,373 - motleycrew - INFO - Got a matching unit for task AnswerTask(name=AnswerTask, done=False)
2024-09-27 22:33:46,373 - motleycrew - INFO - Processing unit: TaskUnit(status=pending)
2024-09-27 22:33:46,373 - motleycrew - INFO - Assigned unit TaskUnit(status=pending) to agent MotleyTool(name=Answer Sub-Question Tool), dispatching
2024-09-27 22:33:46,373 - motleycrew - INFO - Node TaskUnit(status=running) does not exist, creating
2024-09-27 22:33:46,374 - motleycrew - INFO - Inserting new node with label QuestionAnsweringTaskUnit: TaskUnit(status=running)
2024-09-27 22:33:46,374 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2024-09-27 22:33:46,374 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2024-09-27 22:33:46,376 - motleycrew - INFO - Node created OK
2024-09-27 22:33:46,380 - motleycrew - INFO - Relation from TaskUnit(status=running) to name='AnswerTask' done=False does not exist, creating
2024-09-27 22:33:46,382 - motleycrew - INFO - Creating relation QuestionAnsweringTaskUnit_belongs from QuestionAnsweringTaskUnit:0 to TaskNode:1
2024-09-27 22:33:46,385 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:48,629 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2024-09-27 22:33:48,633 - motleycrew - INFO - Task unit TaskUnit(status=running) completed, marking as done
2024-09-27 22:33:48,640 - motleycrew - INFO - Available tasks: [AnswerTask(name=AnswerTask, done=False)]
2024-09-27 22:33:48,643 - motleycrew - INFO - Processing task: AnswerTask(name=AnswerTask, done=False)
2024-09-27 22:33:48,647 - motleycrew - INFO - Available questions: [Question(id=1, question=What role did Krishna play in Arjuna's decision to kill Karna?, answer=None, context=["That way, when this war is ove...])]
2024-09-27 22:33:48,650 - motleycrew - INFO - Got a matching unit for task AnswerTask(name=AnswerTask, done=False)
2024-09-27 22:33:48,651 - motleycrew - INFO - Processing unit: TaskUnit(status=pending)
2024-09-27 22:33:48,651 - motleycrew - INFO - Assigned unit TaskUnit(status=pending) to agent MotleyTool(name=Answer Sub-Question Tool), dispatching
2024-09-27 22:33:48,651 - motleycrew - INFO - Node TaskUnit(status=running) does not exist, creating
2024-09-27 22:33:48,653 - motleycrew - INFO - Inserting new node with label QuestionAnsweringTaskUnit: TaskUnit(status=running)
2024-09-27 22:33:48,653 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2024-09-27 22:33:48,653 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2024-09-27 22:33:48,656 - motleycrew - INFO - Node created OK
2024-09-27 22:33:48,660 - motleycrew - INFO - Relation from TaskUnit(status=running) to name='AnswerTask' done=False does not exist, creating
2024-09-27 22:33:48,663 - motleycrew - INFO - Creating relation QuestionAnsweringTaskUnit_belongs from QuestionAnsweringTaskUnit:1 to TaskNode:1
2024-09-27 22:33:48,665 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:51,405 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2024-09-27 22:33:51,408 - motleycrew - INFO - Task unit TaskUnit(status=running) completed, marking as done
2024-09-27 22:33:51,415 - motleycrew - INFO - Available tasks: [AnswerTask(name=AnswerTask, done=False)]
2024-09-27 22:33:51,419 - motleycrew - INFO - Processing task: AnswerTask(name=AnswerTask, done=False)
2024-09-27 22:33:51,423 - motleycrew - INFO - Available questions: [Question(id=0, question=Why did Arjuna kill Karna, his half-brother?, answer=None, context=["That way, when this war is ove...])]
2024-09-27 22:33:51,426 - motleycrew - INFO - Got a matching unit for task AnswerTask(name=AnswerTask, done=False)
2024-09-27 22:33:51,426 - motleycrew - INFO - Processing unit: TaskUnit(status=pending)
2024-09-27 22:33:51,426 - motleycrew - INFO - Assigned unit TaskUnit(status=pending) to agent MotleyTool(name=Answer Sub-Question Tool), dispatching
2024-09-27 22:33:51,427 - motleycrew - INFO - Node TaskUnit(status=running) does not exist, creating
2024-09-27 22:33:51,427 - motleycrew - INFO - Inserting new node with label QuestionAnsweringTaskUnit: TaskUnit(status=running)
2024-09-27 22:33:51,428 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2024-09-27 22:33:51,428 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2024-09-27 22:33:51,430 - motleycrew - INFO - Node created OK
2024-09-27 22:33:51,435 - motleycrew - INFO - Relation from TaskUnit(status=running) to name='AnswerTask' done=False does not exist, creating
2024-09-27 22:33:51,438 - motleycrew - INFO - Creating relation QuestionAnsweringTaskUnit_belongs from QuestionAnsweringTaskUnit:2 to TaskNode:1
2024-09-27 22:33:51,441 - motleycrew - INFO - Relation created OK
2024-09-27 22:33:53,941 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2024-09-27 22:33:53,945 - motleycrew - INFO - Task unit TaskUnit(status=running) completed, marking as done
2024-09-27 22:33:53,953 - motleycrew - INFO - Available tasks: [AnswerTask(name=AnswerTask, done=False)]
2024-09-27 22:33:53,956 - motleycrew - INFO - Processing task: AnswerTask(name=AnswerTask, done=False)
2024-09-27 22:33:53,960 - motleycrew - INFO - Available questions: []
2024-09-27 22:33:53,963 - motleycrew - INFO - Got no matching units for task AnswerTask(name=AnswerTask, done=False)
2024-09-27 22:33:53,963 - motleycrew - INFO - Nothing left to do, exiting
[7]:
final_answer = done_items[-1].question

print("Question: ", final_answer.question)
print("Answer: ", final_answer.answer)
print("To explore the graph:")
print(f"docker run -p 8000:8000  -v {crew.graph_store.database_path}:/database --rm kuzudb/explorer:latest")
print("And in the kuzu explorer at http://localhost:8000 enter")
print("MATCH (A)-[r]->(B) RETURN *;")
final_result = "{}\n\n{}".format(final_answer.question, final_answer.answer)
Question:  Why did Arjuna kill Karna, his half-brother?
Answer:  Arjuna killed Karna, his half-brother, during their duel on the battlefield of Kurukshetra. The pivotal moment came when Karna's chariot got stuck in the mud, and he requested Arjuna and Krishna to honorably allow him to free his chariot. Krishna responded by reminding Karna of his past dishonorable actions, such as humiliating Draupadi and killing Abhimanyu, thereby justifying Arjuna's actions against Karna. Additionally, when Karna attempted to use the Brahmastra, he suddenly forgot the mantra, which can be seen as divine intervention. Krishna's words and the subsequent events reinforced Arjuna's resolve to kill Karna, aligning with his duty and dharma as a warrior.
To explore the graph:
docker run -p 8000:8000  -v /var/folders/fv/tyhll76x0fn6l7j_q2nhvyg00000gn/T/tmp4obi9n3p/kuzu_db:/database --rm kuzudb/explorer:latest
And in the kuzu explorer at http://localhost:8000 enter
MATCH (A)-[r]->(B) RETURN *;

This is what you will see in Kuzu explorer: image.png