-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add RAG module into AgentScope #800
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 5 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
fc1d2e8
Fix bug
DavdGao c08bdd5
wip
DavdGao 97a93c4
WIP
DavdGao 32a8a7b
Complete the initial development of the RAG module in AgentScope
DavdGao 703d53a
Add unittests for RAG module
DavdGao 32c674c
Merge remote-tracking branch 'agentscope/main' into dev/rag
DavdGao a2adab7
Add examples for rag
DavdGao c9a7251
Unify the __call__ methods of the text embedding models
DavdGao 7b5567d
Add ImageReader; Add retrieve_knowledge method; Add rag section in tu…
DavdGao 1a1c446
Update embedding section in tutorial
DavdGao 5d26560
Support batch size limit in DashScope multimodal embedding API
DavdGao 735f01e
Change the comment to English
DavdGao a3b540b
Update dependencies
DavdGao cf24a52
Update
DavdGao 36af9cf
Fix the errors
DavdGao 832b8ee
Fix the errors
DavdGao 649c3ea
Support reading local file in `TextReader` class
DavdGao 46df8d2
Fix
DavdGao 46e535d
Fix typos
DavdGao f2fdb9a
Fix bugs
DavdGao 1ecb104
Fix
DavdGao 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,11 @@ | ||
| # RAG in AgentScope | ||
|
|
||
| This example includes two scripts to demonstrate how to use Retrieval-Augmented Generation (RAG) in AgentScope: | ||
|
|
||
| - the basic usage of RAG module in AgentScope in ``basic_usage.py`` | ||
| - a simple agentic use case of RAG in ``agentic_usage.py`` | ||
|
|
||
| We also provide a solution to integrate RAG into the `ReActAgent` class by retrieving relevant documents | ||
| at the beginning of each reply in a ``pre_reply`` hook. | ||
| Because it's too similar with the long-term memory example, we are considering if integrating the RAG module | ||
| into the `ReActAgent` class by supporting a `knowledge` argument in the constructor. |
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,146 @@ | ||
| # -*- coding: utf-8 -*- | ||
| """The agentic usage example for RAG in AgentScope, where the agent is | ||
| equipped with RAG tools to answer questions based on a knowledge base. | ||
| The example is more challenging for the agent, requiring the agent to | ||
| adjust the retrieval parameters to get relevant results. | ||
| """ | ||
| import asyncio | ||
| import os | ||
|
|
||
| from agentscope.agent import ReActAgent, UserAgent | ||
| from agentscope.embedding import DashScopeTextEmbedding | ||
| from agentscope.formatter import DashScopeChatFormatter | ||
| from agentscope.message import Msg, TextBlock | ||
| from agentscope.model import DashScopeChatModel | ||
| from agentscope.rag import SimpleKnowledge, QdrantStore, TextReader | ||
| from agentscope.tool import Toolkit, ToolResponse | ||
|
|
||
| # Create a knowledge base instance | ||
| knowledge = SimpleKnowledge( | ||
| embedding_store=QdrantStore( | ||
| location=":memory:", | ||
| collection_name="test_collection", | ||
| dimensions=1024, # The dimension of the embedding vectors | ||
| ), | ||
| embedding_model=DashScopeTextEmbedding( | ||
| api_key=os.environ["DASHSCOPE_API_KEY"], | ||
| model_name="text-embedding-v4", | ||
| ), | ||
| ) | ||
|
|
||
|
|
||
| # An agent-oriented tool function to retrieve knowledge from the knowledge base | ||
| # We expose the `limit` and `score_threshold` parameters to the agent | ||
| # for more flexible control | ||
| async def retrieve_knowledge( | ||
| query: str, | ||
| limit: int = 3, | ||
| score_threshold: float | None = 0.8, | ||
| ) -> ToolResponse: | ||
| """Retrieve relevant documents from the knowledge base, which is relevant | ||
| to John Doe's profile. Note the `query` parameter is | ||
| very important for the retrieval quality, and you can try many different | ||
| queries to get the best results. Adjust the `limit` and `score_threshold` | ||
| parameters to get more or fewer results. | ||
| Args: | ||
| query (`str`): | ||
| The query string, which should be specific and concise. For | ||
| example, you should provide the specific name instead of | ||
| "you", "my", "he", "she", etc. | ||
| limit (`int`, defaults to 3): | ||
| The number of relevant documents to retrieve. | ||
| score_threshold (`float`, defaults to 0.8): | ||
| A threshold in [0, 1] and only the relevance score above this | ||
| threshold will be returned. Reduce this value to get more results. | ||
| """ | ||
| # Retrieve relevant documents based on the given query | ||
| docs = await knowledge.retrieve( | ||
| query=query, | ||
| limit=limit, | ||
| score_threshold=score_threshold, | ||
| ) | ||
| if len(docs): | ||
| return ToolResponse( | ||
| content=[ | ||
| TextBlock( | ||
| type="text", | ||
| text=f"Score: {_.score}, " | ||
| f"Content: {_.metadata.content['text']}", | ||
| ) | ||
| for _ in docs | ||
| ], | ||
| ) | ||
| return ToolResponse( | ||
| content=[ | ||
| TextBlock( | ||
| type="text", | ||
| text="No relevant documents found. TRY to reduce the " | ||
| "`score_threshold` parameter to get " | ||
| "more results.", | ||
| ), | ||
| ], | ||
| ) | ||
|
|
||
|
|
||
| async def main() -> None: | ||
| """The main entry of the agent usage example for RAG in AgentScope.""" | ||
|
|
||
| # Store some things into the knowledge base for demonstration | ||
| # In practice, the VDB store would be pre-filled with relevant data | ||
| reader = TextReader(chunk_size=1024, split_by="sentence") | ||
| documents = await reader( | ||
| text=( | ||
| # Fake personal profile for demonstration | ||
| "I'm John Doe, 28 years old. My best friend is James " | ||
| "Smith. I live in San Francisco. I work at OpenAI as a " | ||
| "software engineer. I love hiking and photography. " | ||
| "My father is Michael Doe, a doctor. I'm very proud of him. " | ||
| "My mother is Sarah Doe, a teacher. She is very kind and " | ||
| "always helps me with my studies.\n" | ||
| "I'm now a PhD student at Stanford University, majoring in " | ||
| "Computer Science. My advisor is Prof. Jane Williams, who is " | ||
| "a leading expert in artificial intelligence. I have published " | ||
| "several papers in top conferences, such as NeurIPS and ICML. " | ||
| ), | ||
| ) | ||
| await knowledge.add_documents(documents) | ||
|
|
||
| # Create a toolkit and register the RAG tool function | ||
| toolkit = Toolkit() | ||
| toolkit.register_tool_function(retrieve_knowledge) | ||
|
|
||
| # Create an agent and a user | ||
| agent = ReActAgent( | ||
| name="Friday", | ||
| sys_prompt=( | ||
| "You're a helpful assistant named Friday. " | ||
| "You're equipped with a 'retrieve_knowledge' tool to help you " | ||
| "know about the user named John Doe. " | ||
| "NOTE to adjust the `score_threshold` parameters when you cannot " | ||
| "get relevant results. " | ||
| ), | ||
| toolkit=toolkit, | ||
| model=DashScopeChatModel( | ||
| api_key=os.environ["DASHSCOPE_API_KEY"], | ||
| model_name="qwen3-max-preview", | ||
| ), | ||
| formatter=DashScopeChatFormatter(), | ||
| ) | ||
| user = UserAgent(name="User") | ||
|
|
||
| # A simple conversation loop beginning with a preset question | ||
| msg = Msg( | ||
| "user", | ||
| "I'm John Doe. Do you know my father?", | ||
| "user", | ||
| ) | ||
| while True: | ||
| msg = await agent(msg) | ||
| msg = await user(msg) | ||
| if msg.get_text_content() == "exit": | ||
| break | ||
|
|
||
|
|
||
| asyncio.run(main()) | ||
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,79 @@ | ||
| # -*- coding: utf-8 -*- | ||
| """The main entry point of the RAG example.""" | ||
| import asyncio | ||
| import os | ||
|
|
||
| from agentscope.embedding import DashScopeTextEmbedding | ||
| from agentscope.rag import ( | ||
| TextReader, | ||
| PDFReader, | ||
| QdrantStore, | ||
| SimpleKnowledge, | ||
| ) | ||
|
|
||
|
|
||
| async def main() -> None: | ||
| """The main entry point of the RAG example.""" | ||
|
|
||
| # Create readers with chunking arguments | ||
| reader = TextReader(chunk_size=1024) | ||
| pdf_reader = PDFReader(chunk_size=1024, split_by="sentence") | ||
|
|
||
| # Read documents | ||
| documents = await reader( | ||
| text="I'm Tony Stank, my password is 123456. My best friend is James " | ||
| "Rhodes.", | ||
| ) | ||
|
|
||
| # Read a sample PDF file | ||
| pdf_path = os.path.join( | ||
| os.path.abspath(os.path.dirname(__file__)), | ||
| "example.pdf", | ||
| ) | ||
| pdf_documents = await pdf_reader(pdf_path=pdf_path) | ||
|
|
||
| # Create a knowledge base with Qdrant as the embedding store and | ||
| # DashScope as the embedding model | ||
| knowledge = SimpleKnowledge( | ||
| embedding_store=QdrantStore( | ||
| location=":memory:", | ||
| collection_name="test_collection", | ||
| dimensions=1024, # The dimension of the embedding vectors | ||
| ), | ||
| embedding_model=DashScopeTextEmbedding( | ||
| api_key=os.environ["DASHSCOPE_API_KEY"], | ||
| model_name="text-embedding-v4", | ||
| ), | ||
| ) | ||
|
|
||
| # Insert documents into the knowledge base | ||
| await knowledge.add_documents(documents + pdf_documents) | ||
|
|
||
| # Retrieve relevant documents based on a given query | ||
| docs = await knowledge.retrieve( | ||
| query="What is Tony Stank's password?", | ||
| limit=3, | ||
| score_threshold=0.7, | ||
| ) | ||
| print("Q1: What is Tony Stank's password?") | ||
| for doc in docs: | ||
| print( | ||
| f"Document ID: {doc.id}, Score: {doc.score}, " | ||
| f"Content: {doc.metadata.content['text']}", | ||
| ) | ||
|
|
||
| # Retrieve documents from the PDF file based on a query | ||
| docs = await knowledge.retrieve( | ||
| query="climate change", | ||
| limit=3, | ||
| score_threshold=0.2, | ||
| ) | ||
| print("\n\nQ2: climate change") | ||
| for doc in docs: | ||
| print( | ||
| f"Document ID: {doc.id}, Score: {doc.score}, " | ||
| f"Content: {repr(doc.metadata.content['text'])}", | ||
| ) | ||
|
|
||
|
|
||
| asyncio.run(main()) |
Binary file not shown.
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,6 +44,7 @@ | |
| "ray", | ||
| "mem0ai", | ||
| "packaging", | ||
| "pypdf", | ||
| ] | ||
|
|
||
| dev_requires = [ | ||
|
|
||
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
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.