diff --git a/docs/sphinx_doc/en/source/tutorial/209-rag.md b/docs/sphinx_doc/en/source/tutorial/209-rag.md new file mode 100644 index 000000000..df11e9bcd --- /dev/null +++ b/docs/sphinx_doc/en/source/tutorial/209-rag.md @@ -0,0 +1,126 @@ +(209-rag-en)= + +# A Quick Introduction to RAG in AgentScope + +We want to introduce three concepts related to RAG in AgentScope: Knowledge, KnowledgeBank and RAG agent. + +### Knowledge +The Knowledge modules (now only `LlamaIndexKnowledge`; support for LangChain will come soon) are responsible for handling all RAG-related operations. + +Here, we will use `LlamaIndexKnowledge` as an example to illustrate the operation within the `Knowledge` module. +When a `LlamaIndexKnowledge` object is initialized, the `LlamaIndexKnowledge.__init__` will go through the following steps: + * It processes documents and generates indexing for retrieval in `LlamaIndexKnowledge._data_to_index(...)`, which includes + * loading the documents `LlamaIndexKnowledge._data_to_docs(...)`; + * preprocessing the documents to nodes with preprocessing methods and embedding model `LlamaIndexKnowledge._docs_to_nodes(...)`; + * generating index with the processed nodes. + * If the indexing already exists, then `LlamaIndexKnowledge._load_index(...)` will be invoked to load the index and avoid repeating embedding calls. + + A RAG module can be created with a JSON configuration to specify 1) data path, 2) data loader, 3) data preprocessing methods, and 4) embedding model (model config name). + A detailed example can refer to the following: +
+ A detailed example of RAG module configuration + + ```json + [ + { + "knowledge_id": "{your_knowledge_id}", + "emb_model_config_name": "{your_embed_model_config_name}", + "data_processing": [ + { + "load_data": { + "loader": { + "create_object": true, + "module": "llama_index.core", + "class": "SimpleDirectoryReader", + "init_args": { + "input_dir": "{path_to_your_data_dir_1}", + "required_exts": [".md"] + } + } + } + }, + { + "load_data": { + "loader": { + "create_object": true, + "module": "llama_index.core", + "class": "SimpleDirectoryReader", + "init_args": { + "input_dir": "{path_to_your_python_code_data_dir}", + "recursive": true, + "required_exts": [".py"] + } + } + }, + "store_and_index": { + "transformations": [ + { + "create_object": true, + "module": "llama_index.core.node_parser", + "class": "CodeSplitter", + "init_args": { + "language": "python", + "chunk_lines": 100 + } + } + ] + } + } + ] + } + ] + ``` + +
+ +If users want to avoid the detailed configuration, we also provide a quick way in `KnowledgeBank` (see the following). +
+ +### Knowledge Bank +The knowledge bank maintains a collection of Knowledge objects (e.g., on different datasets) as a set of *knowledge*. Thus, +different agents can reuse the RAG modules without unnecessary "re-initialization". +Considering that configuring the RAG module may be too complicated for most users, the knowledge bank also provides an easy function call to create RAG modules. + * `KnowledgeBank.add_data_as_knowledge`: create RAG module. An easy way only requires to provide `knowledge_id`, `emb_model_name` and `data_dirs_and_types` + ```python + knowledge_bank.add_data_as_knowledge( + knowledge_id="agentscope_tutorial_rag", + emb_model_name="qwen_emb_config", + data_dirs_and_types={ + "../../docs/sphinx_doc/en/source/tutorial": [".md"], + }, + ) + ``` + More advance initialization, users can still pass a knowledge config as a parameter `knowledge_config`: + ```python + # load knowledge_config as dict + knowledge_bank.add_data_as_knowledge( + knowledge_id=knowledge_config["knowledge_id"], + emb_model_name=knowledge_config["emb_model_config_name"], + knowledge_config=knowledge_config, + ) + ``` +* `KnowledgeBank.get_knowledge`: It accepts two parameters, `knowledge_id` and `duplicate`. + It will return a knowledge object with the provided `knowledge_id`; if `duplicate` is true, the return will be deep copied. +* `KnowledgeBank.equip`: It accepts two parameters, `agent` and `duplicate`. + The function will first check if the agent has `rag_config`; if so, it will provide the knowledge according to the + `knowledge_id` in the `rag_config` and initialize the retriever(s) for the agent. + + + +### RAG agent +RAG agent is an agent that can generate answers based on the retrieved knowledge. + * Agent using RAG: RAG agent requires `rag_config` in its configuration, and there is a list of `knowledge_id`. + * Agent can load specific knowledge from a `KnowledgeBank` by passing it into the `KnowledgeBank.equip` function. + * Agent can use the retrievers in the `reply` function to retrieve from the `Knowledge` and compose their prompt to LLMs. + + + +**Building RAG agent yourself.** As long as your agent config has the `rag_config` attribute as a dict and there is a list of `knowledge_id`, you can pass it to the `KnowledgeBank.equip`. +Your agent will be equipped with a list of knowledge according to the list of `knowledge_id` and the corresponding retrievers. +You can decide how to use the retriever and even update and refresh the index in your agent's `reply` function. + + +[[Back to the top]](#209-rag-en) + + + diff --git a/docs/sphinx_doc/zh_CN/source/tutorial/209-rag.md b/docs/sphinx_doc/zh_CN/source/tutorial/209-rag.md new file mode 100644 index 000000000..565726c45 --- /dev/null +++ b/docs/sphinx_doc/zh_CN/source/tutorial/209-rag.md @@ -0,0 +1,121 @@ +(209-rag-zh)= + +# 简要介绍AgentScope中的RAG + +我们在此介绍AgentScope与RAG相关的三个概念:知识(Knowledge),知识库(Knowledge Bank)和RAG agent。 + +### Knowledge +知识模块(目前仅有“LlamaIndexKnowledge”;即将支持对LangChain)负责处理所有与RAG相关的操作。 + +在这里,我们将使用`LlamaIndexKnowledge`作为示例,以说明在`Knowledge`模块内的操作。 +当初始化`LlamaIndexKnowledge`对象时,`LlamaIndexKnowledge.__init__`将执行以下步骤: + * 它处理文档并生成检索索引 (`LlamaIndexKnowledge._data_to_index(...)`中完成) 其中包括 + * 加载文档 `LlamaIndexKnowledge._data_to_docs(...)`; + * 对文档进行预处理,使用预处理方法和向量模型生成nodes `LlamaIndexKnowledge._docs_to_nodes(...)`; + * 生成处理后的节点的索引。 + * 如果索引已经存在,则会调用 `LlamaIndexKnowledge._load_index(...)` 来加载索引,并避免重复的嵌入调用。 + + 用户可以使用JSON配置来创建一个RAG模块,以指定1)数据路径,2)数据加载器,3)数据预处理方法,以及4)嵌入模型(模型配置名称)。 +一个详细的示例可以参考以下内容: +
+ 详细的配置示例 + + ```json + [ + { + "knowledge_id": "{your_knowledge_id}", + "emb_model_config_name": "{your_embed_model_config_name}", + "data_processing": [ + { + "load_data": { + "loader": { + "create_object": true, + "module": "llama_index.core", + "class": "SimpleDirectoryReader", + "init_args": { + "input_dir": "{path_to_your_data_dir_1}", + "required_exts": [".md"] + } + } + } + }, + { + "load_data": { + "loader": { + "create_object": true, + "module": "llama_index.core", + "class": "SimpleDirectoryReader", + "init_args": { + "input_dir": "{path_to_your_python_code_data_dir}", + "recursive": true, + "required_exts": [".py"] + } + } + }, + "store_and_index": { + "transformations": [ + { + "create_object": true, + "module": "llama_index.core.node_parser", + "class": "CodeSplitter", + "init_args": { + "language": "python", + "chunk_lines": 100 + } + } + ] + } + } + ] + } + ] + ``` + +
+ +如果用户想要避免详细的配置,我们也在`KnowledgeBank`中提供了一种快速的方式(请参阅以下内容)。 +
+ +### Knowledge Bank +知识库将一组Knowledge模块(例如,来自不同数据集的知识)作为知识的集合进行维护。因此,不同的代理可以在没有不必要的重新初始化的情况下重复使用知识模块。考虑到配置RAG模块可能对大多数用户来说过于复杂,知识库还提供了一个简单的函数调用来创建RAG模块。 + +* `KnowledgeBank.add_data_as_knowledge`: 创建RAG模块。一种简单的方式只需要提供knowledge_id、emb_model_name和data_dirs_and_types。 + ```python + knowledge_bank.add_data_as_knowledge( + knowledge_id="agentscope_tutorial_rag", + emb_model_name="qwen_emb_config", + data_dirs_and_types={ + "../../docs/sphinx_doc/en/source/tutorial": [".md"], + }, + ) + ``` + 对于更高级的初始化,用户仍然可以将一个知识模块配置作为参数knowledge_config传递: + ```python + # load knowledge_config as dict + knowledge_bank.add_data_as_knowledge( + knowledge_id=knowledge_config["knowledge_id"], + emb_model_name=knowledge_config["emb_model_config_name"], + knowledge_config=knowledge_config, + ) + ``` +* `KnowledgeBank.get_knowledge`: 它接受两个参数,knowledge_id和duplicate。 + 如果duplicate为true,则返回提供的knowledge_id对应的知识对象;否则返回深拷贝的对象。 +* `KnowledgeBank.equip`: 它接受两个参数,`agent`和`duplicate`。 +该函数首先会检查代理是否具有rag_config;如果有,则根据rag_config中的knowledge_id提供相应的知识,并为代理初始化检索器。 +`duplicate` 同样决定是否是深拷贝。 + + +### RAG agent +RAG agent是可以基于检索到的知识生成答案的agent。 + * 让Agent使用RAG: RAG agent在其配置中需要·`rag_config`,其中有一个`knowledge_id`的列表 + * Agent可以通过将其传递给`KnowledgeBank.equip`函数来从`KnowledgeBank`加载特定的知识。 + * Agent 代理可以在`reply`函数中使用检索器(retriever)从`Knowledge`中检索,并将其提示组合到LLM中 + +**Building RAG agent yourself.** 只要您的代理配置具有`rag_config`属性并且是字典型,里面有一个`knowledge_id`列表,您就可以将其传递给`KnowledgeBank.equip`, +为它配置`knowledge_id`列表和相应的知识和检索器(retriever),您的代理将配备一系列知识。 +您可以在`reply`函数中决定如何使用检索器,甚至更新和刷新索引。 + +[[Back to the top]](#209-rag-zh) + + + diff --git a/examples/conversation_with_RAG_agents/README.md b/examples/conversation_with_RAG_agents/README.md index 71d22a98c..025dd3dad 100644 --- a/examples/conversation_with_RAG_agents/README.md +++ b/examples/conversation_with_RAG_agents/README.md @@ -7,7 +7,6 @@ you will obtain three different agents who can help you answer different questio * **What is this example for?** By this example, we want to show how the agent with retrieval augmented generation (RAG) capability can be used to build easily. -**Notice:** This example is a Beta version of the AgentScope RAG agent. A formal version will soon be added to `src/agentscope/agents`, but it may be subject to changes. ## Prerequisites * **Cloning repo:** This example requires cloning the whole AgentScope repo to local. @@ -23,35 +22,28 @@ capability can be used to build easily. **Note:** This example has been tested with `dashscope_chat` and `dashscope_text_embedding` model wrapper, with `qwen-max` and `text-embedding-v2` models. However, you are welcome to replace the Dashscope language and embedding model wrappers or models with other models you like to test. -## Start AgentScope Consultants +## Start AgentScope Copilots * **Terminal:** The most simple way to execute the AgentScope Consultants is running in terminal. ```bash python ./rag_example.py ``` - Setting `log_retrieval` to `false` in `agent_config.json` can hide the retrieved information and provide only answers of agents. + * **AS studio:** If you want to have more organized, clean UI, you can also run with our `as_studio`. ```bash as_studio ./rag_example.py ``` -### Customize AgentScope Consultants to other consultants +### Agents in the example +Customize AgentScope Consultants to other consultants After you run the example, you may notice that this example consists of three RAG agents: -* `AgentScope Tutorial Assistant`: responsible for answering questions based on AgentScope tutorials (markdown files). -* `AgentScope Framework Code Assistant`: responsible for answering questions based on AgentScope code base (python files). -* `Summarize Assistant`: responsible for summarize the questions from the above two agents. - -These agents can be configured to answering questions based on other GitHub repo, by simply modifying the `input_dir` fields in the `agent_config.json`. - -For more advanced customization, we may need to learn a little bit from the following. +* `Tutorial-Assistant`: responsible for answering questions based on AgentScope tutorials (markdown files). +* `Code-Search-Assistant`: responsible for answering questions based on AgentScope code base (python files). +* `API-Assistant`: responsible for answering questions based on AgentScope API documents (html files, generated by `sphinx`) +* `Searching-Assistant`: responsible for general search in tutorial and code base (markdown files and code files) +* `Agent-Guiding-Assistant`: responsible for referring the correct agent(s) among the above ones. -**RAG modules:** In AgentScope, RAG modules are abstract to provide three basic functions: `load_data`, `store_and_index` and `retrieve`. Refer to `src/agentscope/rag` for more details. +Besides the last `Agent-Guiding-Assistant`, all other agents can be configured to answering questions based on other GitHub repo by replacing the `knowledge`. -**RAG configs:** In the example configuration (the `rag_config` field), all parameters are optional. But if you want to customize them, you may want to learn the following: -* `load_data`: contains all parameters for the the `rag.load_data` function. -Since the `load_data` accepts a dataloader object `loader`, the `loader` in the config need to have `"create_object": true` to let a internal parse create a LlamaIndex data loader object. -The loader object is an instance of `class` in module `module`, with initialization parameters in `init_args`. +For more details about how to use the RAG module in AgentScope, please refer to the tutorial. -* `store_and_index`: contains all parameters for the the `rag.store_and_index` function. -For example, you can pass `vector_store` and `retriever` configurations in a similar way as the `loader` mentioned above. -For the `transformations` parameter, you can pass a list of dicts, each of which corresponds to building a `NodeParser`-kind of preprocessor in Llamaindex. \ No newline at end of file diff --git a/examples/conversation_with_RAG_agents/configs/agent_config.json b/examples/conversation_with_RAG_agents/configs/agent_config.json index e1c350213..5061d536b 100644 --- a/examples/conversation_with_RAG_agents/configs/agent_config.json +++ b/examples/conversation_with_RAG_agents/configs/agent_config.json @@ -41,7 +41,7 @@ "emb_model_config_name": "qwen_emb_config", "rag_config": { "knowledge_id": ["agentscope_api_rag"], - "similarity_top_k": 3, + "similarity_top_k": 2, "log_retrieval": true, "recent_n_mem": 1 } @@ -68,7 +68,6 @@ "class": "DialogAgent", "args": { "name": "Agent-Guiding-Assistant", - "description": "Agent-Guiding-Assistant is an agent that decide which agent should provide the answer next. It can answer questions about specific functions and classes in AgentScope.", "sys_prompt": "You're an assistant guiding the user to specific agent for help. The answer is in a cheerful styled language. The output starts with appreciation for the question. Next, rephrase the question in a simple declarative Sentence for example, 'I think you are asking...'. Last, if the question is about detailed code or example in AgentScope Framework, output '@ Code-Search-Assistant you might be suitable for answering the question'; if the question is about API or function calls (Example: 'Is there function related...' or 'how can I initialize ...' ) in AgentScope, output '@ API-Assistant, I think you are more suitable for the question, please tell us more about it'; if question is about where to find some context (Example:'where can I find...'), output '@ Searching-Assistant, we need your help', otherwise, output '@ Tutorial-Assistant, I think you are more suitable for the question, can you tell us more about it?'. The answer is expected to be only one sentence", "model_config_name": "qwen_config", "use_memory": false diff --git a/examples/conversation_with_RAG_agents/configs/knowledge_config.json b/examples/conversation_with_RAG_agents/configs/knowledge_config.json index 0935c3dc5..d7ef45542 100644 --- a/examples/conversation_with_RAG_agents/configs/knowledge_config.json +++ b/examples/conversation_with_RAG_agents/configs/knowledge_config.json @@ -39,7 +39,7 @@ { "knowledge_id": "agentscope_api_rag", "emb_model_config_name": "qwen_emb_config", - "chunk_size": 2048, + "chunk_size": 1024, "chunk_overlap": 40, "data_processing": [ { diff --git a/examples/conversation_with_RAG_agents/rag_example.py b/examples/conversation_with_RAG_agents/rag_example.py index 85bff1299..7604b3af2 100644 --- a/examples/conversation_with_RAG_agents/rag_example.py +++ b/examples/conversation_with_RAG_agents/rag_example.py @@ -9,7 +9,7 @@ from groupchat_utils import filter_agents import agentscope -from agentscope.agents import UserAgent, DialogAgent, LlamaIndexAgent +from agentscope.agents import UserAgent from agentscope.rag import KnowledgeBank @@ -56,14 +56,23 @@ def main() -> None: # for internal API for config in model_configs: if config.get("model_type", "") == "post_api_chat": - # for gpt4 API config["headers"]["Authorization"] = ( "Bearer " + f"{os.environ.get('HTTP_LLM_API_KEY')}" ) else: # for dashscope config["api_key"] = f"{os.environ.get('DASHSCOPE_API_KEY')}" - agentscope.init(model_configs=model_configs) + + # load config of the agents + with open("configs/agent_config.json", "r", encoding="utf-8") as f: + agent_configs = json.load(f) + + agent_list = agentscope.init( + model_configs=model_configs, + agent_configs=agent_configs, + ) + rag_agent_list = agent_list[:4] + guide_agent = agent_list[4] # the knowledge bank can be configured by loading config file with open( @@ -75,7 +84,7 @@ def main() -> None: knowledge_bank = KnowledgeBank(configs=knowledge_configs) # alternatively, we can easily input the configs to add data to RAG - knowledge_bank.add_data_for_rag( + knowledge_bank.add_data_as_knowledge( knowledge_id="agentscope_tutorial_rag", emb_model_name="qwen_emb_config", data_dirs_and_types={ @@ -83,37 +92,13 @@ def main() -> None: }, ) - # with knowledge bank loaded with RAGs, we config the agents - with open("configs/agent_config.json", "r", encoding="utf-8") as f: - agent_configs = json.load(f) - - # define RAG-based agents for tutorial, code, API and general search - tutorial_agent = LlamaIndexAgent( - knowledge_bank=knowledge_bank, - **agent_configs[0]["args"], - ) - code_explain_agent = LlamaIndexAgent( - knowledge_bank=knowledge_bank, - **agent_configs[1]["args"], - ) - api_agent = LlamaIndexAgent( - knowledge_bank=knowledge_bank, - **agent_configs[2]["args"], - ) - searching_agent = LlamaIndexAgent( - knowledge_bank=knowledge_bank, - **agent_configs[3]["args"], - ) + # let knowledgebank to equip rag agent with a (set of) knowledge + for agent in rag_agent_list: + knowledge_bank.equip(agent) - rag_agent_list = [ - tutorial_agent, - code_explain_agent, - api_agent, - searching_agent, - ] rag_agent_names = [agent.name for agent in rag_agent_list] - # define a guide agent + # update guide agent system prompt with the descriptions of rag agents rag_agent_descriptions = [ "agent name: " + agent.name @@ -122,14 +107,13 @@ def main() -> None: + "\n" for agent in rag_agent_list ] - agent_configs[4]["args"].pop("description") - agent_configs[4]["args"]["sys_prompt"] = agent_configs[4]["args"][ - "sys_prompt" - ] + AGENT_CHOICE_PROMPT.format( - "".join(rag_agent_descriptions), - ) - guide_agent = DialogAgent(**agent_configs[4]["args"]) + guide_agent.sys_prompt = ( + guide_agent.sys_prompt + + AGENT_CHOICE_PROMPT.format( + "".join(rag_agent_descriptions), + ) + ) user_agent = UserAgent() while True: diff --git a/examples/conversation_with_RAG_agents/studio/__init__.py b/examples/conversation_with_RAG_agents/studio/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/conversation_with_RAG_agents/studio/assets/app.css b/examples/conversation_with_RAG_agents/studio/assets/app.css deleted file mode 100644 index b13c6ec82..000000000 --- a/examples/conversation_with_RAG_agents/studio/assets/app.css +++ /dev/null @@ -1,55 +0,0 @@ -.agent-box { - flex-grow: 1; - width: 100%; - background-color: #ADD8E6; - border-radius: 10px; - margin-bottom: 15px; - font-size: 18px; - display: flex; - text-align: center; - align-items: center; - justify-content: center; - box-shadow: 5px 5px 10px rgba(0,0,0,0.2); - transition: background-color 0.3s, box-shadow 0.3s; /* Smooth transition for hover effects */ -} - -.agent-box:hover { - background-color: #B0E0E6; /* Lighter shade of blue */ - box-shadow: 0 0 15px rgba(0,0,0,0.3); /* More pronounced shadow */ -} - -.hint { - top: 0; - left: 0; - width: 100%; - background-color: rgba(128, 128, 128, 0.05); /* 灰色背景,半透明 */ - text-align: center; - padding: 10px 0; - font-size: 16px; - color: rgba(0, 0, 0, 0.7); /* 文本颜色半透明 */ - z-index: 1000; /* 确保提示条位于页面元素上方 */ - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); /* 可选:为提示条添加阴影,增加立体感 */ - padding-left: 20px; -} - -.button { - background-color: green; - color: #3d2e2e; /* White text */ - border: none; - padding: 15px 32px; - text-align: left; - text-decoration: none; - display: inline-block; - font-size: 14px; - margin: 4px 2px; - cursor: pointer; - border-radius: 12px; /* Rounded corners */ - transition-duration: 0.4s; /* Smooth transitions */ - white-space: pre-line; - font-weight: bold; /* Bold text */ -} - -.button:hover { - background-color: white; - color: #4CAF50; -} diff --git a/examples/conversation_with_RAG_agents/studio/studio.py b/examples/conversation_with_RAG_agents/studio/studio.py deleted file mode 100644 index 6985b0f65..000000000 --- a/examples/conversation_with_RAG_agents/studio/studio.py +++ /dev/null @@ -1,326 +0,0 @@ -# -*- coding: utf-8 -*- -"""run web ui""" -import argparse -import os -import sys -import threading -import time -import json -from collections import defaultdict -from typing import Optional, Callable -import traceback - -try: - import gradio as gr -except ImportError: - gr = None - -try: - import modelscope_studio as mgr -except ImportError: - mgr = None - -from agentscope.web.studio.utils import ( - send_player_input, - get_chat_msg, - SYS_MSG_PREFIX, - ResetException, - check_uuid, - send_msg, - generate_image_from_name, - send_reset_msg, - thread_local_data, -) - -MAX_NUM_DISPLAY_MSG = 20 -FAIL_COUNT_DOWN = 30 - - -def init_uid_list() -> list: - """Initialize an empty list for storing user IDs.""" - return [] - - -glb_history_dict = defaultdict(init_uid_list) -glb_signed_user = [] - - -def get_new_uid(request: gr.Request) -> str: - """extract user ID from request""" - headers = request.headers - splits = headers.get("referer").split("?", 1) - if len(splits) > 1: - uid = splits[1] - else: - uid = "local_user" - return uid - - -def reset_glb_var(uid: str) -> None: - """Reset global variables for a given user ID.""" - global glb_history_dict - glb_history_dict[uid] = init_uid_list() - - -def get_chat(uid: str) -> list[list]: - """Retrieve chat messages for a given user ID.""" - uid = check_uuid(uid) - global glb_history_dict - line = get_chat_msg(uid=uid) - # TODO: Optimize the display effect, currently there is a problem of - # output display jumping - if line: - glb_history_dict[uid] += [line] - dial_msg = [] - for line in glb_history_dict[uid]: - _, msg = line - if isinstance(msg, dict): - dial_msg.append(line) - else: - # User chat, format: (msg, None) - dial_msg.append(line) - return dial_msg[-MAX_NUM_DISPLAY_MSG:] - - -def send_image(image_term: str, uid: str) -> None: - """Send an image as a chat message.""" - uid = check_uuid(uid) - send_player_input(image_term, uid=uid) - - msg = f"""""" - avatar = generate_image_from_name("Me") - send_msg(msg, is_player=True, role="Me", uid=uid, avatar=avatar) - - -def send_message(msg: str, uid: str) -> str: - """Send a generic message to the player.""" - uid = check_uuid(uid) - send_player_input(msg, uid=uid) - avatar = generate_image_from_name("Me") - send_msg(msg, is_player=True, role="Me", uid=uid, avatar=avatar) - return "" - - -def fn_choice(data: gr.EventData, uid: str) -> None: - """Handle a selection event from the chatbot interface.""" - uid = check_uuid(uid) - # pylint: disable=protected-access - send_player_input(data._data["value"], uid=uid) - - -def import_function_from_path( - module_path: str, - function_name: str, - module_name: Optional[str] = None, -) -> Callable: - """Import a function from the given module path.""" - import importlib.util - - script_dir = os.path.dirname(os.path.abspath(module_path)) - - # Temporarily add a script directory to sys.path - original_sys_path = sys.path[:] - sys.path.insert(0, script_dir) - - try: - # If a module name is not provided, you can use the filename ( - # without extension) as the module name - if module_name is None: - module_name = os.path.splitext(os.path.basename(module_path))[0] - # Creating module specifications and loading modules - spec = importlib.util.spec_from_file_location( - module_name, - module_path, - ) - if spec is not None: - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - # Getting a function from a module - function = getattr(module, function_name) - else: - raise ImportError( - f"Could not find module spec for {module_name} at" - f" {module_path}", - ) - except AttributeError as exc: - raise AttributeError( - f"The module '{module_name}' does not have a function named '" - f"{function_name}'. Please put your code in the main function, " - f"read README.md for details.", - ) from exc - finally: - # Restore the original sys.path - sys.path = original_sys_path - - return function - - -# pylint: disable=too-many-statements -def run_app() -> None: - """Entry point for the web UI application.""" - assert gr is not None, "Please install [full] version of AgentScope." - - parser = argparse.ArgumentParser() - parser.add_argument("script", type=str, help="Script file to run") - args = parser.parse_args() - - # Make sure script_path is an absolute path - script_path = os.path.abspath(args.script) - - # Get the directory where the script is located - script_dir = os.path.dirname(script_path) - # Save the current working directory - # Change the current working directory to the directory where - os.chdir(script_dir) - - def start_game(uid: str) -> None: - """Start the main game loop.""" - thread_local_data.uid = uid - main = import_function_from_path(script_path, "main") - - while True: - try: - main() - except ResetException: - print(f"Reset Successfully:{uid} ") - except Exception as e: - trace_info = "".join( - traceback.TracebackException.from_exception(e).format(), - ) - for i in range(FAIL_COUNT_DOWN, 0, -1): - send_msg( - f"{SYS_MSG_PREFIX} error {trace_info}, reboot " - f"in {i} seconds", - uid=uid, - ) - time.sleep(1) - reset_glb_var(uid) - - def check_for_new_session(uid: str) -> None: - """ - Check for a new user session and start a game thread if necessary. - """ - uid = check_uuid(uid) - if uid not in glb_signed_user: - glb_signed_user.append(uid) - print("==========Signed User==========") - print(f"Total number of users: {len(glb_signed_user)}") - run_thread = threading.Thread( - target=start_game, - args=(uid,), - ) - run_thread.start() - - with gr.Blocks(css="studio/assets/app.css") as demo: - warning_html_code = """ -
-

If you want to start over, please click the - reset - button and refresh the page

-
- """ - gr.HTML(warning_html_code) - uuid = gr.Textbox(label="modelscope_uuid", visible=False) - tabs = gr.Tabs(visible=True) - with tabs: - conversation_tab = gr.Tab("Q&A", id=0) - agent_tab = gr.Tab("available agents / 可选智能体", id=1) - with conversation_tab: - with gr.Row(): - chatbot = mgr.Chatbot( - label="Dialog", - show_label=False, - bubble_full_width=False, - visible=True, - ) - agent_buttons = [] - with agent_tab: - agent_info = """ -
-

- According to the information in agent_config.json, - there are following agents ready to answer - questions for you. -
- 根据agent_config.json中的配置信息,有以下agent为您答疑解惑。 -

-
- """ - gr.HTML(agent_info) - with open("configs/agent_config.json", "r", encoding="utf-8") as f: - agent_configs = json.load(f) - for config in agent_configs: - agent_args = config["args"] - button_value = ( - f'{agent_args["name"]}: ' - f'\n 🔥{agent_args.get("description", "No description.")}' - ) - with gr.Row(): - agent_buttons.append( - ( - gr.Button( - value=button_value, - elem_classes=["button"], - ), - gr.Textbox( - value=agent_args["name"], - visible=False, - ), - ), - ) - - with gr.Column(): - user_chat_input = gr.Textbox( - label="user_chat_input", - placeholder="Say something here", - show_label=False, - interactive=True, - ) - send_button = gr.Button(value="📣Send") - with gr.Column(): - reset_button = gr.Button(value="Reset") - - # submit message - send_button.click( - send_message, - [user_chat_input, uuid], - user_chat_input, - ) - user_chat_input.submit( - send_message, - [user_chat_input, uuid], - user_chat_input, - ) - - def mention(text: str) -> str: - return f"@{text}" - - for button_pair in agent_buttons: - button_pair[0].click( - fn=mention, - inputs=[button_pair[1]], - outputs=user_chat_input, - ) - - reset_button.click(send_reset_msg, inputs=[uuid]) - - demo.load(get_new_uid, None, uuid).then( - check_for_new_session, - inputs=[uuid], - ).then( - get_chat, - inputs=[uuid], - outputs=[chatbot], - every=0.5, - ) - - chatbot.custom(fn=fn_choice, inputs=[uuid]) - demo.queue() - demo.launch() - - -if __name__ == "__main__": - run_app() diff --git a/src/agentscope/agents/__init__.py b/src/agentscope/agents/__init__.py index 7d1e7c711..7ddd84b5f 100644 --- a/src/agentscope/agents/__init__.py +++ b/src/agentscope/agents/__init__.py @@ -8,7 +8,7 @@ from .text_to_image_agent import TextToImageAgent from .rpc_agent import RpcAgent, RpcAgentServerLauncher from .react_agent import ReActAgent -from .rag_agents import RAGAgentBase, LlamaIndexAgent +from .rag_agents import LlamaIndexAgent __all__ = [ @@ -21,6 +21,5 @@ "ReActAgent", "RpcAgent", "RpcAgentServerLauncher", - "RAGAgentBase", "LlamaIndexAgent", ] diff --git a/src/agentscope/agents/rag_agents.py b/src/agentscope/agents/rag_agents.py index 4928a59cc..181eb48ee 100644 --- a/src/agentscope/agents/rag_agents.py +++ b/src/agentscope/agents/rag_agents.py @@ -6,13 +6,12 @@ Notice, this is a Beta version of RAG agent. """ -from abc import ABC, abstractmethod from typing import Optional, Any from loguru import logger from agentscope.agents.agent import AgentBase from agentscope.message import Msg -from agentscope.rag import KnowledgeBank +from agentscope.rag import Knowledge CHECKING_PROMPT = """ @@ -23,151 +22,7 @@ """ -class RAGAgentBase(AgentBase, ABC): - """ - Base class for RAG agents - """ - - def __init__( - self, - name: str, - sys_prompt: str, - model_config_name: str, - memory_config: Optional[dict] = None, - rag_config: Optional[dict] = None, - ) -> None: - """ - Initialize the RAG base agent - Args: - name (str): - the name for the agent. - sys_prompt (str): - system prompt for the RAG agent. - model_config_name (str): - language model for the agent. - memory_config (dict): - memory configuration. - rag_config (dict): - config for RAG. It contains most of the - important parameters for RAG modules. If not provided, - the default setting will be used. - Examples can refer to children classes. - """ - super().__init__( - name=name, - sys_prompt=sys_prompt, - model_config_name=model_config_name, - use_memory=True, - memory_config=memory_config, - ) - - # setup RAG configurations - self.rag_config = rag_config or {} - - # rag module to be initialized later - self.rag = None - - @abstractmethod - def retrieve( - self, - query: Any, - to_list_strs: bool = False, - ) -> list[Any]: - """ - retrieve list of content from database (vector stored index) to memory - Args: - query (Any): query to retrieve - to_list_strs (bool): whether return a list of str - - Returns: - return a list with retrieved documents (in strings) - """ - - def reply( - self, - x: dict = None, - ) -> dict: - """ - Reply function of the RAG agent. - Processes the input data, - 1) use the input data to retrieve with RAG function; - 2) generates a prompt using the current memory and system - prompt; - 3) invokes the language model to produce a response. The - response is then formatted and added to the dialogue memory. - - Args: - x (`dict`, defaults to `None`): - A dictionary representing the user's input to the agent. This - input is added to the memory if provided. Defaults to - None. - Returns: - A dictionary representing the message generated by the agent in - response to the user's input. - """ - retrieved_docs_to_string = "" - # record the input if needed - if self.memory: - self.memory.add(x) - # in case no input is provided (e.g., in msghub), - # use the memory as query - history = self.memory.get_memory( - recent_n=self.rag_config.get("recent_n_mem", 1), - ) - query = ( - "/n".join( - [msg["content"] for msg in history], - ) - if isinstance(history, list) - else str(history) - ) - elif x is not None: - query = x["content"] - else: - query = "" - - if len(query) > 0: - # when content has information, do retrieval - retrieved_docs = self.rag.retrieve(query, to_list_strs=True) - for content in retrieved_docs: - retrieved_docs_to_string += "\n>>>> " + content - - if self.rag_config["log_retrieval"]: - self.speak("[retrieved]:" + retrieved_docs_to_string) - - # prepare prompt - prompt = self.model.format( - Msg( - name="system", - role="system", - content=self.sys_prompt, - ), - # {"role": "system", "content": retrieved_docs_to_string}, - self.memory.get_memory( - recent_n=self.rag_config.get("recent_n_mem", 1), - ), - Msg( - name="user", - role="user", - content="Context: " + retrieved_docs_to_string, - ), - ) - - # call llm and generate response - response = self.model(prompt).text - msg = Msg(self.name, response) - - # Print/speak the message in this agent's voice - self.speak(msg) - - if self.memory: - # Record the message in memory - self.memory.add(msg) - - return msg - - -class LlamaIndexAgent(RAGAgentBase): +class LlamaIndexAgent(AgentBase): """ A LlamaIndex agent build on LlamaIndex. """ @@ -177,7 +32,7 @@ def __init__( name: str, sys_prompt: str, model_config_name: str, - knowledge_bank: Optional[KnowledgeBank], + knowledge_list: list[Knowledge] = None, memory_config: Optional[dict] = None, rag_config: Optional[dict] = None, **kwargs: Any, @@ -211,46 +66,11 @@ def __init__( sys_prompt=sys_prompt, model_config_name=model_config_name, memory_config=memory_config, - rag_config=rag_config, ) + self.knowledge_list = knowledge_list or [] self.retriever_list = [] - self.knowledge_bank = knowledge_bank self.description = kwargs.get("description", "") - self._init_rag() - - def _init_rag(self) -> None: - for knowledge_id in self.rag_config.get("knowledge_id", None): - rag = self.knowledge_bank.get_rag(knowledge_id) - self.retriever_list.append(rag.retriever) - logger.info(f"retrievers for {self.name} are ready.\n") - if len(self.retriever_list) == 0: - raise ValueError("retrievers are empty!") - - def retrieve(self, query: str, to_list_strs: bool = False) -> list[Any]: - """ - This is a basic retrieve function for RAG agent. - - Args: - query (str): - query is expected to be a question in string - to_list_strs (book): - whether returns the list of strings; - if False, return NodeWithScore - Return: - list[Any]: list of str or NodeWithScore - - More advanced query processing can refer to - https://docs.llamaindex.ai/en/stable/examples/query_transformations/query_transform_cookbook.html - """ - results = [] - retrieved_list = [] - for retriever in self.retriever_list: - retrieved = retriever.retrieve(str(query)) - retrieved_list += retrieved - if to_list_strs: - for node in retrieved: - results.append(node.get_text()) - return results if to_list_strs else retrieved_list + self.rag_config = rag_config or {} def reply(self, x: dict = None) -> dict: """ @@ -294,16 +114,19 @@ def reply(self, x: dict = None) -> dict: if len(query) > 0: # when content has information, do retrieval - retrieved_docs = self.retrieve(query) scores = [] - for content in retrieved_docs: - scores.append(content.score) - retrieved_docs_to_string += ( - "\n>>>> score:" - + str(content.score) - + "\n>>>> content:" - + content.get_content() - ) + for retriever in self.retriever_list: + retrieved_nodes = retriever.retrieve(str(query)) + for node in retrieved_nodes: + scores.append(node.score) + retrieved_docs_to_string += ( + "\n>>>> score:" + + str(node.score) + + "\n>>>> source:" + + str(node.node.get_metadata_str()) + + "\n>>>> content:" + + node.get_content() + ) if self.rag_config["log_retrieval"]: self.speak("[retrieved]:" + retrieved_docs_to_string) diff --git a/src/agentscope/rag/__init__.py b/src/agentscope/rag/__init__.py index 90a7c1240..362f1de14 100644 --- a/src/agentscope/rag/__init__.py +++ b/src/agentscope/rag/__init__.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- """ Import all pipeline related modules in the package. """ -from .rag import RAGBase -from .llama_index_rag import LlamaIndexRAG +from .knowledge import Knowledge +from .llama_index_knowledge import LlamaIndexKnowledge from .knowledge_bank import KnowledgeBank __all__ = [ - "RAGBase", - "LlamaIndexRAG", + "Knowledge", + "LlamaIndexKnowledge", "KnowledgeBank", ] diff --git a/src/agentscope/rag/rag.py b/src/agentscope/rag/knowledge.py similarity index 88% rename from src/agentscope/rag/rag.py rename to src/agentscope/rag/knowledge.py index 3ca0c99c7..285459cdc 100644 --- a/src/agentscope/rag/rag.py +++ b/src/agentscope/rag/knowledge.py @@ -23,24 +23,34 @@ DEFAULT_TOP_K = 5 -class RAGBase(ABC): +class Knowledge(ABC): """ Base class for RAG, CANNOT be instantiated directly """ def __init__( self, - model: Optional[ModelWrapperBase] = None, + knowledge_id: str, emb_model: Any = None, - index_config: Optional[dict] = None, - rag_config: Optional[dict] = None, + knowledge_config: Optional[dict] = None, + model: Optional[ModelWrapperBase] = None, **kwargs: Any, ) -> None: # pylint: disable=unused-argument - self.postprocessing_model = model + """ + initialize the knowledge component + Args: + knowledge_id (str): + The id of the knowledge unit. + emb_model (ModelWrapperBase): + The embedding model used for generate embeddings + knowledge_config (dict): + The configuration to generate or load the index. + """ + self.knowledge_id = knowledge_id self.emb_model = emb_model - self.index_config = index_config or {} - self.rag_config = rag_config or {} + self.knowledge_config = knowledge_config or {} + self.postprocessing_model = model @abstractmethod def _init_rag( @@ -68,7 +78,7 @@ def retrieve( """ @abstractmethod - def _set_retriever(self, **kwargs: Any) -> None: + def set_retriever(self, **kwargs: Any) -> None: """update retriever of RAG module""" def post_processing( diff --git a/src/agentscope/rag/knowledge_bank.py b/src/agentscope/rag/knowledge_bank.py index aae9e4279..3a5a30ff0 100644 --- a/src/agentscope/rag/knowledge_bank.py +++ b/src/agentscope/rag/knowledge_bank.py @@ -6,7 +6,9 @@ from typing import Optional from loguru import logger from agentscope.models import load_model_by_config_name -from .llama_index_rag import LlamaIndexRAG +from agentscope.agents import AgentBase +from .llama_index_knowledge import LlamaIndexKnowledge + DEFAULT_INDEX_CONFIG = { "knowledge_id": "", @@ -42,26 +44,27 @@ def __init__( ) -> None: """initialize the knowledge bank""" self.configs = configs - self.stored_knowledge: dict[str, LlamaIndexRAG] = {} + self.stored_knowledge: dict[str, LlamaIndexKnowledge] = {} self._init_knowledge() def _init_knowledge(self) -> None: """initialize the knowledge bank""" for config in self.configs: - self.add_data_for_rag( + print("bank", config) + self.add_data_as_knowledge( knowledge_id=config["knowledge_id"], emb_model_name=config["emb_model_config_name"], - index_config=config, + knowledge_config=config, ) logger.info("knowledge bank initialization completed.\n ") - def add_data_for_rag( + def add_data_as_knowledge( self, knowledge_id: str, emb_model_name: str, data_dirs_and_types: dict[str, list[str]] = None, model_name: Optional[str] = None, - index_config: Optional[dict] = None, + knowledge_config: Optional[dict] = None, ) -> None: """ Transform data in a directory to be ready to work with RAG. @@ -76,7 +79,7 @@ def add_data_for_rag( dictionary of data paths (keys) to the data types (file extensions) for knowledgebase (e.g., [".md", ".py", ".html"]) - index_config (optional[dict]): + knowledge_config (optional[dict]): complete indexing configuration, used for more advanced applications. Users can customize - loader, @@ -86,7 +89,7 @@ def add_data_for_rag( a simple example of importing data to RAG: '' - knowledge_bank.add_data_for_rag( + knowledge_bank.add_data_as_knowledge( knowledge_id="agentscope_tutorial_rag", emb_model_name="qwen_emb_config", data_dirs_and_types={ @@ -99,33 +102,33 @@ def add_data_for_rag( if knowledge_id in self.stored_knowledge: raise ValueError(f"knowledge_id {knowledge_id} already exists.") - assert data_dirs_and_types is not None or index_config is not None + assert data_dirs_and_types is not None or knowledge_config is not None - if index_config is None: - index_config = copy.deepcopy(DEFAULT_INDEX_CONFIG) + if knowledge_config is None: + knowledge_config = copy.deepcopy(DEFAULT_INDEX_CONFIG) for data_dir, types in data_dirs_and_types.items(): loader_config = copy.deepcopy(DEFAULT_LOADER_CONFIG) loader_init = copy.deepcopy(DEFAULT_INIT_CONFIG) loader_init["input_dir"] = data_dir loader_init["required_exts"] = types loader_config["load_data"]["loader"]["init_args"] = loader_init - index_config["data_processing"].append(loader_config) + knowledge_config["data_processing"].append(loader_config) - self.stored_knowledge[knowledge_id] = LlamaIndexRAG( + self.stored_knowledge[knowledge_id] = LlamaIndexKnowledge( knowledge_id=knowledge_id, emb_model=load_model_by_config_name(emb_model_name), + knowledge_config=knowledge_config, model=load_model_by_config_name(model_name) if model_name else None, - index_config=index_config, ) logger.info(f"data loaded for knowledge_id = {knowledge_id}.") - def get_rag( + def get_knowledge( self, knowledge_id: str, duplicate: bool = False, - ) -> LlamaIndexRAG: + ) -> LlamaIndexKnowledge: """ Get a RAG from the knowledge bank. Args: @@ -146,3 +149,25 @@ def get_rag( rag = copy.deepcopy(rag) logger.info(f"knowledge bank loaded: {knowledge_id}.") return rag + + def equip(self, agent: AgentBase, duplicate: bool = False) -> None: + """ + Equip the agent with the knowledge it requests + Args: + agent (AgentBase): the agent to be equipped with knowledge + if it has "rag_config" + duplicate (bool): whether to deepcopy the knowledge object + """ + if hasattr(agent, "rag_config") and "knowledge_id" in agent.rag_config: + if not hasattr(agent, "knowledge_list"): + agent.knowledge_list = [] + if not hasattr(agent, "retriever_list"): + agent.retriever_list = [] + for rid in agent.rag_config["knowledge_id"]: + knowledge = self.get_knowledge( + knowledge_id=rid, + duplicate=duplicate, + ) + knowledge.set_retriever(agent.rag_config) + agent.knowledge_list.append(knowledge) + agent.retriever_list.append(knowledge.retriever) diff --git a/src/agentscope/rag/llama_index_rag.py b/src/agentscope/rag/llama_index_knowledge.py similarity index 92% rename from src/agentscope/rag/llama_index_rag.py rename to src/agentscope/rag/llama_index_knowledge.py index 583e0671f..49439321f 100644 --- a/src/agentscope/rag/llama_index_rag.py +++ b/src/agentscope/rag/llama_index_knowledge.py @@ -37,13 +37,14 @@ PrivateAttr = None Document, TransformComponent = None, None -from agentscope.rag import RAGBase -from agentscope.rag.rag import ( +from agentscope.file_manager import file_manager +from agentscope.models import ModelWrapperBase +from .knowledge import ( DEFAULT_TOP_K, DEFAULT_CHUNK_SIZE, DEFAULT_CHUNK_OVERLAP, + Knowledge, ) -from agentscope.models import ModelWrapperBase try: @@ -134,7 +135,7 @@ def __init__(self, emb_model: ModelWrapperBase): self._emb_model_wrapper = emb_model -class LlamaIndexRAG(RAGBase): +class LlamaIndexKnowledge(Knowledge): """ This class is a wrapper with the llama index RAG. """ @@ -142,16 +143,16 @@ class LlamaIndexRAG(RAGBase): def __init__( self, knowledge_id: str, - persist_root: str = "./rag_storage/", - model: Optional[ModelWrapperBase] = None, emb_model: Union[ModelWrapperBase, BaseEmbedding, None] = None, - index_config: dict = None, + knowledge_config: Optional[dict] = None, + model: Optional[ModelWrapperBase] = None, + persist_root: Optional[str] = None, overwrite_index: Optional[bool] = False, showprogress: Optional[bool] = True, **kwargs: Any, ) -> None: """ - initialize the RAG component based on the + initialize the knowledge component based on the llama-index framework: https://github.com/run-llama/llama_index Notes: @@ -168,23 +169,30 @@ def __init__( Args: knowledge_id (str): The id of the RAG knowledge unit. - persist_root (str): - The root directory for index persisting - model (ModelWrapperBase): - The language model used for final synthesis emb_model (ModelWrapperBase): The embedding model used for generate embeddings - index_config (dict): + knowledge_config (dict): The configuration for llama-index to generate or load the index. + model (ModelWrapperBase): + The language model used for final synthesis + persist_root (str): + The root directory for index persisting overwrite_index (Optional[bool]): Whether to overwrite the index while refreshing showprogress (Optional[bool]): Whether to show the indexing progress """ - super().__init__(model, emb_model, index_config, **kwargs) - self.knowledge_id = knowledge_id - self.persist_dir = persist_root + knowledge_id + super().__init__( + knowledge_id=knowledge_id, + emb_model=emb_model, + knowledge_config=knowledge_config, + model=model, + **kwargs, + ) + if persist_root is None: + persist_root = file_manager.dir + self.persist_dir = os.path.join(persist_root, knowledge_id) self.emb_model = emb_model self.overwrite_index = overwrite_index self.showprogress = showprogress @@ -200,9 +208,10 @@ def __init__( f"Embedding model does not support {type(self.emb_model)}.", ) # then we can initialize the RAG + print("init", self.knowledge_config) self._init_rag() - def _init_rag(self) -> None: + def _init_rag(self, **kwargs: Any) -> None: """ Initialize the RAG. This includes: * if the persist_dir exists, load the persisted index @@ -222,7 +231,7 @@ def _init_rag(self) -> None: # self.refresh_index() else: self._data_to_index() - self._set_retriever() + self.set_retriever() logger.info( f"RAG with knowledge ids: {self.knowledge_id} " f"initialization completed!\n", @@ -253,12 +262,12 @@ def _data_to_index(self) -> None: Notes: As each selected file type may need to use a different loader - and transformations, index_config is a list of configs. + and transformations, knowledge_config is a list of configs. """ nodes = [] # load data to documents and set transformations - # using information in index_config - for config in self.index_config.get("data_processing"): + # using information in knowledge_config + for config in self.knowledge_config.get("data_processing"): documents = self._data_to_docs(config=config) transformations = self._set_transformations(config=config).get( "transformations", @@ -390,11 +399,11 @@ def _set_transformations(self, config: dict) -> Any: else: transformations = [ SentenceSplitter( - chunk_size=self.index_config.get( + chunk_size=self.knowledge_config.get( "chunk_size", DEFAULT_CHUNK_SIZE, ), - chunk_overlap=self.index_config.get( + chunk_overlap=self.knowledge_config.get( "chunk_overlap", DEFAULT_CHUNK_OVERLAP, ), @@ -408,8 +417,9 @@ def _set_transformations(self, config: dict) -> Any: transformations = {"transformations": transformations} return transformations - def _set_retriever( + def set_retriever( self, + rag_config: Optional[dict] = None, retriever: Optional[BaseRetriever] = None, **kwargs: Any, ) -> None: @@ -418,17 +428,19 @@ def _set_retriever( Args: retriever (Optional[BaseRetriever]): passing a retriever in llama + rag_config (dict): rag configuration, including similarity top k index. """ # set the retriever + rag_config = rag_config or {} if retriever is None: logger.info( f"similarity_top_k" - f'={self.rag_config.get("similarity_top_k", DEFAULT_TOP_K)}', + f'={rag_config.get("similarity_top_k", DEFAULT_TOP_K)}', ) self.retriever = self.index.as_retriever( embed_model=self.emb_model, - similarity_top_k=self.rag_config.get( + similarity_top_k=rag_config.get( "similarity_top_k", DEFAULT_TOP_K, ), @@ -466,7 +478,7 @@ def refresh_index(self) -> None: """ Refresh the index when needed. """ - for config in self.index_config.get("data_processing"): + for config in self.knowledge_config.get("data_processing"): documents = self._data_to_docs(config=config) # store and indexing for each file type transformations = self._set_transformations(config=config).get(