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)
/Users/whimo/motleycrew/.venv/lib/python3.11/site-packages/lunary/__init__.py:3: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
from pkg_resources import parse_version
[2]:
DATA_DIR = os.path.realpath(os.path.join(WORKING_DIR, "mahabharata/text/TinyTales"))
PERSIST_DIR = WORKING_DIR / "examples/data/research_agent_storage"
[3]:
# Only run this the first time you run the notebook, to get the raw data
!git clone https://github.com/rahulnyk/mahabharata.git
fatal: destination path 'mahabharata' already exists and is not an empty directory.
[4]:
crew = MotleyCrew()
2025-08-01 19:16:37,949 - motleycrew - INFO - No db_path provided, creating temporary directory for database
2025-08-01 19:16:37,950 - motleycrew - INFO - Using Kuzu graph store with path: /var/folders/fv/tyhll76x0fn6l7j_q2nhvyg00000gn/T/tmpm5s3_0te/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")
# You can use any embedding model, e.g. OllamaEmbedding for local embeddings:
# from llama_index.embeddings.ollama import OllamaEmbedding
# ollama_embedding = OllamaEmbedding(
# model_name="nomic-embed-text",
# base_url="http://localhost:11434",
# ollama_additional_kwargs={"mirostat": 0},
# )
llm = init_llm(LLMFramework.LANGCHAIN, llm_name="gpt-4.1-mini")
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
Loading llama_index.core.storage.kvstore.simple_kvstore from /Users/whimo/motleycrew/examples/examples/data/research_agent_storage/docstore.json.
Loading llama_index.core.storage.kvstore.simple_kvstore from /Users/whimo/motleycrew/examples/examples/data/research_agent_storage/index_store.json.
2025-08-01 19:16:39,146 - motleycrew - INFO - Node table TaskNode does not exist in the database, creating
2025-08-01 19:16:39,151 - motleycrew - INFO - Property name not present in table for label TaskNode, creating
2025-08-01 19:16:39,152 - motleycrew - INFO - Property done not present in table for label TaskNode, creating
2025-08-01 19:16:39,152 - motleycrew - INFO - Node table QuestionGenerationTaskUnit does not exist in the database, creating
2025-08-01 19:16:39,154 - motleycrew - INFO - Property status not present in table for label QuestionGenerationTaskUnit, creating
2025-08-01 19:16:39,154 - motleycrew - INFO - Property output not present in table for label QuestionGenerationTaskUnit, creating
2025-08-01 19:16:39,155 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2025-08-01 19:16:39,155 - motleycrew - INFO - Property question not present in table for label QuestionGenerationTaskUnit, creating
2025-08-01 19:16:39,156 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2025-08-01 19:16:39,157 - motleycrew - INFO - Relation table QuestionGenerationTaskUnit_belongs from QuestionGenerationTaskUnit to TaskNode does not exist in the database, creating
2025-08-01 19:16:39,158 - motleycrew - INFO - Inserting new node with label TaskNode: name='QuestionTask' done=False
2025-08-01 19:16:39,162 - motleycrew - INFO - Node created OK
2025-08-01 19:16:39,163 - motleycrew - INFO - Relation table task_is_upstream from TaskNode to TaskNode does not exist in the database, creating
2025-08-01 19:16:39,164 - motleycrew - INFO - Node table Question does not exist in the database, creating
2025-08-01 19:16:39,165 - motleycrew - INFO - Property question not present in table for label Question, creating
2025-08-01 19:16:39,165 - motleycrew - INFO - Property answer not present in table for label Question, creating
2025-08-01 19:16:39,166 - motleycrew - INFO - Property context not present in table for label Question, creating
2025-08-01 19:16:39,166 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2025-08-01 19:16:39,167 - motleycrew - INFO - Inserting new node with label Question: question='Why did Arjuna kill Karna, his half-brother?' answer=None context=None
2025-08-01 19:16:39,167 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2025-08-01 19:16:39,168 - motleycrew - INFO - Node created OK
2025-08-01 19:16:39,170 - motleycrew - INFO - Node table QuestionAnsweringTaskUnit does not exist in the database, creating
2025-08-01 19:16:39,171 - motleycrew - INFO - Property status not present in table for label QuestionAnsweringTaskUnit, creating
2025-08-01 19:16:39,172 - motleycrew - INFO - Property output not present in table for label QuestionAnsweringTaskUnit, creating
2025-08-01 19:16:39,172 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2025-08-01 19:16:39,172 - motleycrew - INFO - Property question not present in table for label QuestionAnsweringTaskUnit, creating
2025-08-01 19:16:39,172 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2025-08-01 19:16:39,173 - motleycrew - INFO - Relation table QuestionAnsweringTaskUnit_belongs from QuestionAnsweringTaskUnit to TaskNode does not exist in the database, creating
2025-08-01 19:16:39,174 - motleycrew - INFO - Inserting new node with label TaskNode: name='AnswerTask' done=False
2025-08-01 19:16:39,174 - motleycrew - INFO - Node created OK
2025-08-01 19:16:39,184 - motleycrew - INFO - Creating relation task_is_upstream from TaskNode:0 to TaskNode:1
2025-08-01 19:16:39,189 - motleycrew - INFO - Relation created OK
[5]:
QuestionTask(name=QuestionTask, done=False)
[6]:
# And now run the recipes
done_items = crew.run()
2025-08-01 19:16:39,201 - motleycrew - INFO - Available tasks: [QuestionTask(name=QuestionTask, done=False)]
2025-08-01 19:16:39,202 - motleycrew - INFO - Processing task: QuestionTask(name=QuestionTask, done=False)
2025-08-01 19:16:39,278 - motleycrew - INFO - Loaded unanswered questions: [Question(id=0, question=Why did Arjuna kill Karna, his half-brother?, answer=None, context=None)]
2025-08-01 19:16:45,438 - motleycrew - INFO - Most pertinent question according to the tool: question='Why did Arjuna kill Karna, his half-brother?' answer=None context=None
2025-08-01 19:16:45,439 - motleycrew - INFO - Got a matching unit for task QuestionTask(name=QuestionTask, done=False)
2025-08-01 19:16:45,439 - motleycrew - INFO - Processing unit: TaskUnit(status=pending)
2025-08-01 19:16:45,439 - motleycrew - INFO - Assigned unit TaskUnit(status=pending) to agent MotleyTool(name=Question Generator Tool), dispatching
2025-08-01 19:16:45,440 - motleycrew - INFO - Node TaskUnit(status=running) does not exist, creating
2025-08-01 19:16:45,441 - motleycrew - INFO - Inserting new node with label QuestionGenerationTaskUnit: TaskUnit(status=running)
2025-08-01 19:16:45,441 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2025-08-01 19:16:45,441 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2025-08-01 19:16:45,443 - motleycrew - INFO - Node created OK
2025-08-01 19:16:45,445 - motleycrew - INFO - Relation from TaskUnit(status=running) to name='QuestionTask' done=False does not exist, creating
2025-08-01 19:16:45,447 - motleycrew - INFO - Creating relation QuestionGenerationTaskUnit_belongs from QuestionGenerationTaskUnit:0 to TaskNode:0
2025-08-01 19:16:45,449 - motleycrew - INFO - Relation created OK
2025-08-01 19:16:45,449 - motleycrew - INFO - ==== Started iteration 1 of 3 ====
2025-08-01 19:16:48,109 - motleycrew - INFO - Inserting question: Did Karna know about his relationship to Arjuna before their duel, and how did this knowledge affect their fight?
2025-08-01 19:16:48,112 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2025-08-01 19:16:48,116 - motleycrew - INFO - Inserting new node with label Question: question='Did Karna know about his relationship to Arjuna before their duel, and how did this knowledge affect their fight?' answer=None context=None
2025-08-01 19:16:48,116 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2025-08-01 19:16:48,118 - motleycrew - INFO - Node created OK
2025-08-01 19:16:48,120 - motleycrew - INFO - Relation table is_subquestion from Question to Question does not exist in the database, creating
2025-08-01 19:16:48,120 - motleycrew - INFO - Creating relation is_subquestion from Question:0 to Question:1
2025-08-01 19:16:48,122 - motleycrew - INFO - Relation created OK
2025-08-01 19:16:48,122 - motleycrew - INFO - Inserting question: What role did Krishna play in the duel between Arjuna and Karna, especially regarding the circumstances of Karna's death?
2025-08-01 19:16:48,122 - motleycrew - INFO - Inserting new node with label Question: question="What role did Krishna play in the duel between Arjuna and Karna, especially regarding the circumstances of Karna's death?" answer=None context=None
2025-08-01 19:16:48,123 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2025-08-01 19:16:48,124 - motleycrew - INFO - Node created OK
2025-08-01 19:16:48,125 - motleycrew - INFO - Creating relation is_subquestion from Question:0 to Question:2
2025-08-01 19:16:48,126 - motleycrew - INFO - Relation created OK
2025-08-01 19:16:48,127 - motleycrew - INFO - Inserting question: Were there any specific rules or codes of honor that influenced why Arjuna killed Karna despite him being his half-brother?
2025-08-01 19:16:48,127 - motleycrew - INFO - Inserting new node with label Question: question='Were there any specific rules or codes of honor that influenced why Arjuna killed Karna despite him being his half-brother?' answer=None context=None
2025-08-01 19:16:48,127 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2025-08-01 19:16:48,128 - motleycrew - INFO - Node created OK
2025-08-01 19:16:48,130 - motleycrew - INFO - Creating relation is_subquestion from Question:0 to Question:3
2025-08-01 19:16:48,131 - motleycrew - INFO - Relation created OK
2025-08-01 19:16:48,131 - motleycrew - INFO - Inserted 3 questions
2025-08-01 19:16:48,132 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2025-08-01 19:16:48,133 - motleycrew - INFO - Task unit TaskUnit(status=running) completed, marking as done
2025-08-01 19:16:48,136 - motleycrew - INFO - Available tasks: [QuestionTask(name=QuestionTask, done=False)]
2025-08-01 19:16:48,138 - motleycrew - INFO - Processing task: QuestionTask(name=QuestionTask, done=False)
2025-08-01 19:16:48,139 - motleycrew - INFO - Loaded unanswered questions: [Question(id=1, question=Did Karna know about his relationship to Arjuna before their duel, and how did this knowledge affect their fight?, answer=None, context=None), Question(id=2, question=What role did Krishna play in the duel between Arjuna and Karna, especially regarding the circumstances of Karna's death?, answer=None, context=None), Question(id=3, question=Were there any specific rules or codes of honor that influenced why Arjuna killed Karna despite him being his half-brother?, answer=None, context=None)]
2025-08-01 19:16:49,440 - motleycrew - INFO - Most pertinent question according to the tool: question='Were there any specific rules or codes of honor that influenced why Arjuna killed Karna despite him being his half-brother?' answer=None context=None
2025-08-01 19:16:49,441 - motleycrew - INFO - Got a matching unit for task QuestionTask(name=QuestionTask, done=False)
2025-08-01 19:16:49,442 - motleycrew - INFO - Processing unit: TaskUnit(status=pending)
2025-08-01 19:16:49,442 - motleycrew - INFO - Assigned unit TaskUnit(status=pending) to agent MotleyTool(name=Question Generator Tool), dispatching
2025-08-01 19:16:49,443 - motleycrew - INFO - Node TaskUnit(status=running) does not exist, creating
2025-08-01 19:16:49,445 - motleycrew - INFO - Inserting new node with label QuestionGenerationTaskUnit: TaskUnit(status=running)
2025-08-01 19:16:49,445 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2025-08-01 19:16:49,446 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2025-08-01 19:16:49,448 - motleycrew - INFO - Node created OK
2025-08-01 19:16:49,452 - motleycrew - INFO - Relation from TaskUnit(status=running) to name='QuestionTask' done=False does not exist, creating
2025-08-01 19:16:49,454 - motleycrew - INFO - Creating relation QuestionGenerationTaskUnit_belongs from QuestionGenerationTaskUnit:1 to TaskNode:0
2025-08-01 19:16:49,455 - motleycrew - INFO - Relation created OK
2025-08-01 19:16:49,455 - motleycrew - INFO - ==== Started iteration 2 of 3 ====
2025-08-01 19:16:55,546 - motleycrew - INFO - Inserting question: Did the concept of dharma override familial ties in the decision of Arjuna to kill Karna despite their brotherhood?
2025-08-01 19:16:55,548 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2025-08-01 19:16:55,548 - motleycrew - INFO - Inserting new node with label Question: question='Did the concept of dharma override familial ties in the decision of Arjuna to kill Karna despite their brotherhood?' answer=None context=None
2025-08-01 19:16:55,549 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2025-08-01 19:16:55,550 - motleycrew - INFO - Node created OK
2025-08-01 19:16:55,552 - motleycrew - INFO - Creating relation is_subquestion from Question:3 to Question:4
2025-08-01 19:16:55,553 - motleycrew - INFO - Relation created OK
2025-08-01 19:16:55,553 - motleycrew - INFO - Inserting question: Was there any specific code of honor or rule mentioned that justified Arjuna fighting and killing Karna even after knowing he was his half-brother?
2025-08-01 19:16:55,554 - motleycrew - INFO - Inserting new node with label Question: question='Was there any specific code of honor or rule mentioned that justified Arjuna fighting and killing Karna even after knowing he was his half-brother?' answer=None context=None
2025-08-01 19:16:55,554 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2025-08-01 19:16:55,554 - motleycrew - INFO - Node created OK
2025-08-01 19:16:55,556 - motleycrew - INFO - Creating relation is_subquestion from Question:3 to Question:5
2025-08-01 19:16:55,557 - motleycrew - INFO - Relation created OK
2025-08-01 19:16:55,557 - motleycrew - INFO - Inserting question: How did Karna’s promise to Kunti and his loyalty to Duryodhana influence the circumstances under which Arjuna killed him?
2025-08-01 19:16:55,558 - motleycrew - INFO - Inserting new node with label Question: question='How did Karna’s promise to Kunti and his loyalty to Duryodhana influence the circumstances under which Arjuna killed him?' answer=None context=None
2025-08-01 19:16:55,558 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2025-08-01 19:16:55,559 - motleycrew - INFO - Node created OK
2025-08-01 19:16:55,561 - motleycrew - INFO - Creating relation is_subquestion from Question:3 to Question:6
2025-08-01 19:16:55,561 - motleycrew - INFO - Relation created OK
2025-08-01 19:16:55,562 - motleycrew - INFO - Inserted 3 questions
2025-08-01 19:16:55,563 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2025-08-01 19:16:55,563 - motleycrew - INFO - Task unit TaskUnit(status=running) completed, marking as done
2025-08-01 19:16:55,565 - motleycrew - INFO - Available tasks: [QuestionTask(name=QuestionTask, done=False)]
2025-08-01 19:16:55,566 - motleycrew - INFO - Processing task: QuestionTask(name=QuestionTask, done=False)
2025-08-01 19:16:55,567 - motleycrew - INFO - Loaded unanswered questions: [Question(id=1, question=Did Karna know about his relationship to Arjuna before their duel, and how did this knowledge affect their fight?, answer=None, context=None), Question(id=2, question=What role did Krishna play in the duel between Arjuna and Karna, especially regarding the circumstances of Karna's death?, answer=None, context=None), Question(id=4, question=Did the concept of dharma override familial ties in the decision of Arjuna to kill Karna despite their brotherhood?, answer=None, context=None), Question(id=5, question=Was there any specific code of honor or rule mentioned that justified Arjuna fighting and killing Karna even after knowing he was his half-brother?, answer=None, context=None), Question(id=6, question=How did Karna’s promise to Kunti and his loyalty to Duryodhana influence the circumstances under which Arjuna killed him?, answer=None, context=None)]
2025-08-01 19:16:57,461 - motleycrew - INFO - Most pertinent question according to the tool: question='Did the concept of dharma override familial ties in the decision of Arjuna to kill Karna despite their brotherhood?' answer=None context=None
2025-08-01 19:16:57,462 - motleycrew - INFO - Got a matching unit for task QuestionTask(name=QuestionTask, done=False)
2025-08-01 19:16:57,463 - motleycrew - INFO - Processing unit: TaskUnit(status=pending)
2025-08-01 19:16:57,464 - motleycrew - INFO - Assigned unit TaskUnit(status=pending) to agent MotleyTool(name=Question Generator Tool), dispatching
2025-08-01 19:16:57,465 - motleycrew - INFO - Node TaskUnit(status=running) does not exist, creating
2025-08-01 19:16:57,468 - motleycrew - INFO - Inserting new node with label QuestionGenerationTaskUnit: TaskUnit(status=running)
2025-08-01 19:16:57,469 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2025-08-01 19:16:57,470 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2025-08-01 19:16:57,471 - motleycrew - INFO - Node created OK
2025-08-01 19:16:57,474 - motleycrew - INFO - Relation from TaskUnit(status=running) to name='QuestionTask' done=False does not exist, creating
2025-08-01 19:16:57,476 - motleycrew - INFO - Creating relation QuestionGenerationTaskUnit_belongs from QuestionGenerationTaskUnit:2 to TaskNode:0
2025-08-01 19:16:57,477 - motleycrew - INFO - Relation created OK
2025-08-01 19:16:57,478 - motleycrew - INFO - ==== Started iteration 3 of 3 ====
2025-08-01 19:17:07,407 - motleycrew - INFO - Inserting question: Did Arjuna know about his brotherhood with Karna before or after deciding to fight him?
2025-08-01 19:17:07,410 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2025-08-01 19:17:07,413 - motleycrew - INFO - Inserting new node with label Question: question='Did Arjuna know about his brotherhood with Karna before or after deciding to fight him?' answer=None context=None
2025-08-01 19:17:07,414 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2025-08-01 19:17:07,416 - motleycrew - INFO - Node created OK
2025-08-01 19:17:07,418 - motleycrew - INFO - Creating relation is_subquestion from Question:4 to Question:7
2025-08-01 19:17:07,420 - motleycrew - INFO - Relation created OK
2025-08-01 19:17:07,420 - motleycrew - INFO - Inserting question: How did Krishna’s emphasis on dharma over family influence Arjuna’s decision to kill Karna?
2025-08-01 19:17:07,421 - motleycrew - INFO - Inserting new node with label Question: question='How did Krishna’s emphasis on dharma over family influence Arjuna’s decision to kill Karna?' answer=None context=None
2025-08-01 19:17:07,421 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2025-08-01 19:17:07,422 - motleycrew - INFO - Node created OK
2025-08-01 19:17:07,423 - motleycrew - INFO - Creating relation is_subquestion from Question:4 to Question:8
2025-08-01 19:17:07,424 - motleycrew - INFO - Relation created OK
2025-08-01 19:17:07,424 - motleycrew - INFO - Inserting question: Did Karna’s awareness of his relationship with Arjuna affect his actions or decisions during the war?
2025-08-01 19:17:07,425 - motleycrew - INFO - Inserting new node with label Question: question='Did Karna’s awareness of his relationship with Arjuna affect his actions or decisions during the war?' answer=None context=None
2025-08-01 19:17:07,425 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[list[str]], will use JSON string
2025-08-01 19:17:07,426 - motleycrew - INFO - Node created OK
2025-08-01 19:17:07,428 - motleycrew - INFO - Creating relation is_subquestion from Question:4 to Question:9
2025-08-01 19:17:07,428 - motleycrew - INFO - Relation created OK
2025-08-01 19:17:07,429 - motleycrew - INFO - Inserted 3 questions
2025-08-01 19:17:07,429 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2025-08-01 19:17:07,430 - motleycrew - INFO - Task unit TaskUnit(status=running) completed, marking as done
2025-08-01 19:17:07,433 - motleycrew - INFO - Available tasks: [AnswerTask(name=AnswerTask, done=False)]
2025-08-01 19:17:07,434 - motleycrew - INFO - Processing task: AnswerTask(name=AnswerTask, done=False)
2025-08-01 19:17:07,438 - motleycrew - INFO - Available questions: [Question(id=4, question=Did the concept of dharma override familial ties in the decision of Arjuna to kill Karna despite their brotherhood?, answer=None, context=["Vikarna had even defended Drau...])]
2025-08-01 19:17:07,439 - motleycrew - INFO - Got a matching unit for task AnswerTask(name=AnswerTask, done=False)
2025-08-01 19:17:07,439 - motleycrew - INFO - Processing unit: TaskUnit(status=pending)
2025-08-01 19:17:07,439 - motleycrew - INFO - Assigned unit TaskUnit(status=pending) to agent MotleyTool(name=Answer Sub-Question Tool), dispatching
2025-08-01 19:17:07,439 - motleycrew - INFO - Node TaskUnit(status=running) does not exist, creating
2025-08-01 19:17:07,440 - motleycrew - INFO - Inserting new node with label QuestionAnsweringTaskUnit: TaskUnit(status=running)
2025-08-01 19:17:07,440 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2025-08-01 19:17:07,440 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2025-08-01 19:17:07,441 - motleycrew - INFO - Node created OK
2025-08-01 19:17:07,443 - motleycrew - INFO - Relation from TaskUnit(status=running) to name='AnswerTask' done=False does not exist, creating
2025-08-01 19:17:07,445 - motleycrew - INFO - Creating relation QuestionAnsweringTaskUnit_belongs from QuestionAnsweringTaskUnit:0 to TaskNode:1
2025-08-01 19:17:07,447 - motleycrew - INFO - Relation created OK
2025-08-01 19:17:11,016 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2025-08-01 19:17:11,018 - motleycrew - INFO - Task unit TaskUnit(status=running) completed, marking as done
2025-08-01 19:17:11,021 - motleycrew - INFO - Available tasks: [AnswerTask(name=AnswerTask, done=False)]
2025-08-01 19:17:11,022 - motleycrew - INFO - Processing task: AnswerTask(name=AnswerTask, done=False)
2025-08-01 19:17:11,023 - motleycrew - INFO - Available questions: [Question(id=3, question=Were there any specific rules or codes of honor that influenced why Arjuna killed Karna despite him being his half-brother?, answer=None, context=["Vikarna had even defended Drau...])]
2025-08-01 19:17:11,024 - motleycrew - INFO - Got a matching unit for task AnswerTask(name=AnswerTask, done=False)
2025-08-01 19:17:11,025 - motleycrew - INFO - Processing unit: TaskUnit(status=pending)
2025-08-01 19:17:11,025 - motleycrew - INFO - Assigned unit TaskUnit(status=pending) to agent MotleyTool(name=Answer Sub-Question Tool), dispatching
2025-08-01 19:17:11,025 - motleycrew - INFO - Node TaskUnit(status=running) does not exist, creating
2025-08-01 19:17:11,025 - motleycrew - INFO - Inserting new node with label QuestionAnsweringTaskUnit: TaskUnit(status=running)
2025-08-01 19:17:11,026 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2025-08-01 19:17:11,026 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2025-08-01 19:17:11,027 - motleycrew - INFO - Node created OK
2025-08-01 19:17:11,029 - motleycrew - INFO - Relation from TaskUnit(status=running) to name='AnswerTask' done=False does not exist, creating
2025-08-01 19:17:11,031 - motleycrew - INFO - Creating relation QuestionAnsweringTaskUnit_belongs from QuestionAnsweringTaskUnit:1 to TaskNode:1
2025-08-01 19:17:11,032 - motleycrew - INFO - Relation created OK
2025-08-01 19:17:15,165 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2025-08-01 19:17:15,168 - motleycrew - INFO - Task unit TaskUnit(status=running) completed, marking as done
2025-08-01 19:17:15,170 - motleycrew - INFO - Available tasks: [AnswerTask(name=AnswerTask, done=False)]
2025-08-01 19:17:15,171 - motleycrew - INFO - Processing task: AnswerTask(name=AnswerTask, done=False)
2025-08-01 19:17:15,172 - 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...])]
2025-08-01 19:17:15,173 - motleycrew - INFO - Got a matching unit for task AnswerTask(name=AnswerTask, done=False)
2025-08-01 19:17:15,174 - motleycrew - INFO - Processing unit: TaskUnit(status=pending)
2025-08-01 19:17:15,174 - motleycrew - INFO - Assigned unit TaskUnit(status=pending) to agent MotleyTool(name=Answer Sub-Question Tool), dispatching
2025-08-01 19:17:15,174 - motleycrew - INFO - Node TaskUnit(status=running) does not exist, creating
2025-08-01 19:17:15,174 - motleycrew - INFO - Inserting new node with label QuestionAnsweringTaskUnit: TaskUnit(status=running)
2025-08-01 19:17:15,175 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2025-08-01 19:17:15,175 - motleycrew - INFO - No known Cypher type matching annotation <class 'motleycrew.applications.research_agent.question.Question'>, will use JSON string
2025-08-01 19:17:15,176 - motleycrew - INFO - Node created OK
2025-08-01 19:17:15,178 - motleycrew - INFO - Relation from TaskUnit(status=running) to name='AnswerTask' done=False does not exist, creating
2025-08-01 19:17:15,180 - motleycrew - INFO - Creating relation QuestionAnsweringTaskUnit_belongs from QuestionAnsweringTaskUnit:2 to TaskNode:1
2025-08-01 19:17:15,181 - motleycrew - INFO - Relation created OK
2025-08-01 19:17:20,975 - motleycrew - INFO - No known Cypher type matching annotation typing.Optional[typing.Any], will use JSON string
2025-08-01 19:17:20,978 - motleycrew - INFO - Task unit TaskUnit(status=running) completed, marking as done
2025-08-01 19:17:20,981 - motleycrew - INFO - Available tasks: [AnswerTask(name=AnswerTask, done=False)]
2025-08-01 19:17:20,982 - motleycrew - INFO - Processing task: AnswerTask(name=AnswerTask, done=False)
2025-08-01 19:17:20,984 - motleycrew - INFO - Available questions: []
2025-08-01 19:17:20,986 - motleycrew - INFO - Got no matching units for task AnswerTask(name=AnswerTask, done=False)
2025-08-01 19:17:20,987 - 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:0.4.2")
print("And in the kuzu explorer at http://localhost:8000 enter")
print("MATCH (A)-[r]->(B) RETURN *;")
Question: Why did Arjuna kill Karna, his half-brother?
Answer: Arjuna killed Karna despite him being his half-brother because of the overriding principle of dharma (righteous duty) that governed the war. Although Karna was Kunti’s eldest son and thus Arjuna’s brother, Karna fought on the Kaurava side, opposing the Pandavas. Karna had promised Kunti he would spare her other sons but would fight Arjuna in mortal combat. When Kunti revealed Karna’s identity, Krishna explained that had the Pandavas known earlier, they would not have fought, but "you had to fight. It was dharma. All is as it must be." This shows that the warrior code prioritized duty to righteousness and cosmic order above familial ties. Krishna’s counsel to Bhima after killing Vikarna—"Dharma is what matters. Not family. Not friends. Dharma."—further underscores that adherence to dharma justified Arjuna’s act. Thus, Arjuna’s killing of Karna was an act fulfilling his warrior dharma, overriding personal and familial bonds in the context of the great war.
To explore the graph:
docker run -p 8000:8000 -v /var/folders/fv/tyhll76x0fn6l7j_q2nhvyg00000gn/T/tmpm5s3_0te/kuzu_db:/database --rm kuzudb/explorer:0.4.2
And in the kuzu explorer at http://localhost:8000 enter
MATCH (A)-[r]->(B) RETURN *;
This is what you will see in Kuzu explorer: