-
Notifications
You must be signed in to change notification settings - Fork 187
feat: Add deep research use case (Python) #482
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
49d7c58
init code
leehuwuj 6a36f44
simplify
leehuwuj f38e07f
add ui
leehuwuj 90a55f3
update vercel
leehuwuj acfc4ec
fix not display
leehuwuj 76c20f3
Merge remote-tracking branch 'origin' into lee/deep-research
leehuwuj b157663
add markdown render
leehuwuj ff2b25a
standards event data type
leehuwuj d5eac5d
fix typing and improve prompt
leehuwuj 578173f
add blog to simple use cases
leehuwuj 15290f1
refine prompt
leehuwuj a52ba9a
update readme for blog use case
leehuwuj a3a09d7
remove grouped question, add description and better styling
leehuwuj e7994f6
remove dead code
leehuwuj 65f5e6f
add background download task for llamacloud
leehuwuj 0b920fc
remove max retries
leehuwuj df66f07
move source nodes to shared events code
leehuwuj 8e83568
minor fixes
leehuwuj 7061dc3
reduce css
leehuwuj ade3e2b
revert blog changes, add deep research
leehuwuj c4020cb
rename writer to deep research
leehuwuj 1d46c2e
improve docs
leehuwuj f47586b
add changeset
leehuwuj 76eecec
bump chat-ui@0.0.14
leehuwuj 8fe8a91
word-smithing
marcusschiesser dd7e79d
add missing done event when canceling the workflow
leehuwuj c2136e5
fix typing
leehuwuj File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "create-llama": patch | ||
| --- | ||
|
|
||
| Add deep research over own documents use case (Python) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
templates/components/agents/python/deep_research/README-template.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| This is a [LlamaIndex](https://www.llamaindex.ai/) multi-agents project using [Workflows](https://docs.llamaindex.ai/en/stable/understanding/workflows/). | ||
|
|
||
| ## Getting Started | ||
|
|
||
| First, setup the environment with poetry: | ||
|
|
||
| > **_Note:_** This step is not needed if you are using the dev-container. | ||
|
|
||
| ```shell | ||
| poetry install | ||
| ``` | ||
|
|
||
| Then check the parameters that have been pre-configured in the `.env` file in this directory. (E.g. you might need to configure an `OPENAI_API_KEY` if you're using OpenAI as model provider). | ||
| Second, generate the embeddings of the documents in the `./data` directory: | ||
|
|
||
| ```shell | ||
| poetry run generate | ||
| ``` | ||
|
|
||
| Third, run the development server: | ||
|
|
||
| ```shell | ||
| poetry run dev | ||
| ``` | ||
|
|
||
| ## Use Case: Deep Research over own documents | ||
|
|
||
| The workflow performs deep research by retrieving and analyzing documents from the [data](./data) directory from multiple perspectives. The project includes a sample PDF about AI investment in 2024 to help you get started. You can also add your own documents by placing them in the data directory and running the generate script again to index them. | ||
|
|
||
| After starting the server, go to [http://localhost:8000](http://localhost:8000) and send a message to the agent to write a blog post. | ||
| E.g: "AI investment in 2024" | ||
|
|
||
| To update the workflow, you can edit the [deep_research.py](./app/workflows/deep_research.py) file. | ||
|
|
||
| By default, the workflow retrieves 10 results from your documents. To customize the amount of information covered in the answer, you can adjust the `TOP_K` environment variable in the `.env` file. A higher value will retrieve more results from your documents, potentially providing more comprehensive answers. | ||
|
|
||
| ## Deployments | ||
|
|
||
| For production deployments, check the [DEPLOY.md](DEPLOY.md) file. | ||
|
leehuwuj marked this conversation as resolved.
|
||
|
|
||
| ## Learn More | ||
|
|
||
| To learn more about LlamaIndex, take a look at the following resources: | ||
|
|
||
| - [LlamaIndex Documentation](https://docs.llamaindex.ai) - learn about LlamaIndex. | ||
| - [Workflows Introduction](https://docs.llamaindex.ai/en/stable/understanding/workflows/) - learn about LlamaIndex workflows. | ||
| You can check out [the LlamaIndex GitHub repository](https://github.com/run-llama/llama_index) - your feedback and contributions are welcome! | ||
3 changes: 3 additions & 0 deletions
3
templates/components/agents/python/deep_research/app/workflows/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| from .deep_research import create_workflow | ||
|
|
||
| __all__ = ["create_workflow"] |
158 changes: 158 additions & 0 deletions
158
templates/components/agents/python/deep_research/app/workflows/agents.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| from typing import List, Literal, Optional | ||
|
|
||
| from llama_index.core.base.llms.types import ( | ||
| CompletionResponse, | ||
| CompletionResponseAsyncGen, | ||
| ) | ||
| from llama_index.core.memory.simple_composable_memory import SimpleComposableMemory | ||
| from llama_index.core.prompts import PromptTemplate | ||
| from llama_index.core.schema import MetadataMode, Node, NodeWithScore | ||
| from llama_index.core.settings import Settings | ||
| from pydantic import BaseModel, Field | ||
|
|
||
|
|
||
| class AnalysisDecision(BaseModel): | ||
| decision: Literal["research", "write", "cancel"] = Field( | ||
| description="Whether to continue research, write a report, or cancel the research after several retries" | ||
| ) | ||
| research_questions: Optional[List[str]] = Field( | ||
| description="Questions to research if continuing research. Maximum 3 questions. Set to null or empty if writing a report.", | ||
| default_factory=list, | ||
| ) | ||
| cancel_reason: Optional[str] = Field( | ||
| description="The reason for cancellation if the decision is to cancel research.", | ||
| default=None, | ||
| ) | ||
|
|
||
|
|
||
| async def plan_research( | ||
| memory: SimpleComposableMemory, | ||
| context_nodes: List[Node], | ||
| user_request: str, | ||
| ) -> AnalysisDecision: | ||
| analyze_prompt = PromptTemplate( | ||
| """ | ||
| You are a professor who is guiding a researcher to research a specific request/problem. | ||
| Your task is to decide on a research plan for the researcher. | ||
| The possible actions are: | ||
| + Provide a list of questions for the researcher to investigate, with the purpose of clarifying the request. | ||
| + Write a report if the researcher has already gathered enough research on the topic and can resolve the initial request. | ||
| + Cancel the research if most of the answers from researchers indicate there is insufficient information to research the request. Do not attempt more than 3 research iterations or too many questions. | ||
| The workflow should be: | ||
| + Always begin by providing some initial questions for the researcher to investigate. | ||
| + Analyze the provided answers against the initial topic/request. If the answers are insufficient to resolve the initial request, provide additional questions for the researcher to investigate. | ||
| + If the answers are sufficient to resolve the initial request, instruct the researcher to write a report. | ||
| <User request> | ||
| {user_request} | ||
| </User request> | ||
|
|
||
| <Collected information> | ||
| {context_str} | ||
| </Collected information> | ||
|
|
||
| <Conversation context> | ||
| {conversation_context} | ||
| </Conversation context> | ||
| """ | ||
| ) | ||
| conversation_context = "\n".join( | ||
| [f"{message.role}: {message.content}" for message in memory.get_all()] | ||
| ) | ||
| context_str = "\n".join( | ||
| [node.get_content(metadata_mode=MetadataMode.LLM) for node in context_nodes] | ||
| ) | ||
| res = await Settings.llm.astructured_predict( | ||
| output_cls=AnalysisDecision, | ||
| prompt=analyze_prompt, | ||
| user_request=user_request, | ||
| context_str=context_str, | ||
| conversation_context=conversation_context, | ||
| ) | ||
| return res | ||
|
|
||
|
|
||
| async def research( | ||
| question: str, | ||
| context_nodes: List[NodeWithScore], | ||
| ) -> str: | ||
| prompt = """ | ||
| You are a researcher who is in the process of answering the question. | ||
| The purpose is to answer the question based on the collected information, without using prior knowledge or making up any new information. | ||
| Always add citations to the sentence/point/paragraph using the id of the provided content. | ||
| The citation should follow this format: [citation:id]() where id is the id of the content. | ||
|
|
||
| E.g: | ||
| If we have a context like this: | ||
| <Citation id='abc-xyz'> | ||
| Baby llama is called cria | ||
| </Citation id='abc-xyz'> | ||
|
|
||
| And your answer uses the content, then the citation should be: | ||
| - Baby llama is called cria [citation:abc-xyz]() | ||
|
|
||
| Here is the provided context for the question: | ||
| <Collected information> | ||
| {context_str} | ||
| </Collected information>` | ||
|
leehuwuj marked this conversation as resolved.
|
||
|
|
||
| No prior knowledge, just use the provided context to answer the question: {question} | ||
| """ | ||
| context_str = "\n".join( | ||
| [_get_text_node_content_for_citation(node) for node in context_nodes] | ||
| ) | ||
| res = await Settings.llm.acomplete( | ||
| prompt=prompt.format(question=question, context_str=context_str), | ||
| ) | ||
| return res.text | ||
|
|
||
|
|
||
| async def write_report( | ||
| memory: SimpleComposableMemory, | ||
| user_request: str, | ||
| stream: bool = False, | ||
| ) -> CompletionResponse | CompletionResponseAsyncGen: | ||
| report_prompt = """ | ||
| You are a researcher writing a report based on a user request and the research context. | ||
| You have researched various perspectives related to the user request. | ||
| The report should provide a comprehensive outline covering all important points from the researched perspectives. | ||
| Create a well-structured outline for the research report that covers all the answers. | ||
|
|
||
| # IMPORTANT when writing in markdown format: | ||
| + Use tables or figures where appropriate to enhance presentation. | ||
| + Preserve all citation syntax (the `[citation:id]()` parts in the provided context). Keep these citations in the final report - no separate reference section is needed. | ||
| + Do not add links, a table of contents, or a references section to the report. | ||
|
|
||
| <User request> | ||
| {user_request} | ||
| </User request> | ||
|
|
||
| <Research context> | ||
| {research_context} | ||
| </Research context> | ||
|
|
||
| Now, write a report addressing the user request based on the research provided following the format and guidelines above. | ||
| """ | ||
| research_context = "\n".join( | ||
| [f"{message.role}: {message.content}" for message in memory.get_all()] | ||
| ) | ||
|
|
||
| llm_complete_func = ( | ||
| Settings.llm.astream_complete if stream else Settings.llm.acomplete | ||
| ) | ||
|
|
||
| res = await llm_complete_func( | ||
| prompt=report_prompt.format( | ||
| user_request=user_request, | ||
| research_context=research_context, | ||
| ), | ||
| ) | ||
| return res | ||
|
|
||
|
|
||
| def _get_text_node_content_for_citation(node: NodeWithScore) -> str: | ||
| """ | ||
| Construct node content for LLM with citation flag. | ||
| """ | ||
| node_id = node.node.node_id | ||
| content = f"<Citation id='{node_id}'>\n{node.get_content(metadata_mode=MetadataMode.LLM)}</Citation id='{node_id}'>" | ||
| return content | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.