From 2fab455fa0576fbc039e72a4ed4d97e1ff6cd077 Mon Sep 17 00:00:00 2001 From: weizjajj Date: Mon, 17 Jun 2024 12:58:56 +0800 Subject: [PATCH 1/7] add tool doc --- ...20\347\232\204\345\267\245\345\205\267.md" | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 "docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md" diff --git "a/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md" "b/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md" new file mode 100644 index 00000000..4fb390b2 --- /dev/null +++ "b/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md" @@ -0,0 +1,140 @@ +# 支持的工具 + +当前au的 sample工程当中,集成了以下工具: + +## 1. 搜索工具 + +### 1.1 谷歌搜索 +[工具地址](../../../sample_standard_app/app/core/tool/google_search_tool.yaml) +详细配置信息: + +```yaml +name: 'google_search_tool' +description: | + 该工具可以用来进行谷歌搜索,工具的输入是你想搜索的内容。 + 工具输入示例: + 示例1: 你想要搜索上海的天气时,工具的输入应该是:上海今天的天气 + 示例2: 你想要搜索日本的天气时,工具的输入应该是:日本的天气 +tool_type: 'api' +input_keys: ['input'] +metadata: + type: 'TOOL' + module: 'sample_standard_app.app.core.tool.google_search_tool' + class: 'GoogleSearchTool' +``` +为了使用该api,你必须申请(https://serper.dev)BING_SUBSCRIPTION_KEY,并配置在环境变量当中。 +配置方法: +1. 通过python代码配置 +必须配置:SERPER_API_KEY +```python +import os +os.environ['SERPER_API_KEY'] = 'xxxx' +``` +2. 通过配置文件配置 +在项目的config目录下的custom_key.toml当中,添加配置: +```toml +SERPER_API_KEY="xxxx" +``` + + +### 1.2 Bing(必应)搜索 +当前集成了Bing官方的搜索 +[工具地址](../../../sample_standard_app/app/core/tool/bing_search_tool.yaml) +工具配置: +```yaml +name: 'bing_search_tool' +description: 'demo bing search tool' +tool_type: 'api' +input_keys: ['input'] +metadata: + type: 'TOOL' + module: 'sample_standard_app.app.core.tool.bing_search_tool' + class: 'BingSearchTool' +``` +为了使用该api,你必须申请BING_SUBSCRIPTION_KEY,并配置在环境变量当中。 +配置方法: +1. 通过python代码配置 +必须配置:BING_SUBSCRIPTION_KEY +```python +import os +os.environ['BING_SUBSCRIPTION_KEY'] = 'xxxx' +``` +2. 通过配置文件配置 +在项目的config目录下的custom_key.toml当中,添加配置: +```toml +BING_SUBSCRIPTION_KEY="xxxx" +``` + + + +### 1.3 Search API +支持多种搜索工具,例如: +- [百度搜索](../../../sample_standard_app/app/core/tool/search_api_baidu_tool.yaml) +- [Bing搜索](../../../sample_standard_app/app/core/tool/search_api_bing_tool.yaml) +其他搜索引擎还包括: 谷歌搜索、亚马逊搜索、YouTube搜索等,详细信息可以参考:https://www.searchapi.io/ +工具配置: +```yaml +name: 'search_api_baidu_tool' +description: '百度(必应)搜索工具,输入为一个要搜索内容的字符串,例如:input=黄金价格是多少' +tool_type: 'api' +input_keys: ['input'] +engine: 'baidu' +search_type: 'json' +search_params: + num: 10 +metadata: + type: 'TOOL' + module: 'sample_standard_app.app.core.tool.search_api_tool' + class: 'SearchAPITool' +``` +参数说明: +search_type: 代表你期望返回的搜索结果的格式,json代表你期望为json格式,common代表你期望为string字符串格式。 +search_params: 代表你需要额外的传递给搜索引擎的参数,比如在百度搜索中,num代表了返回的搜索结果条数,详细参数需要参考https://www.searchapi.io/ 。 +engine: 你期望使用的搜索引擎,baidu、google、bing、amazon、youtube... +为了使用该api,你必须从[官网](https://www.searchapi.io/)申请SEARCH_API_KEY,并配置在环境变量当中。 +配置方法: +1. 通过python代码配置 +必须配置:SEARCH_API_KEY +```python +import os +os.environ['SEARCHAPI_API_KEY'] = 'xxxxxx' +``` +2. 通过配置文件配置 +在项目的config目录下的custom_key.toml当中,添加配置: +```toml +SEARCHAPI_API_KEY="xxxxxx" +``` + + +## 2. 代码工具 + +### 2.1 PythonRepl +[工具地址](../../../sample_standard_app/app/core/tool/python_repl_tool.yaml) +该工具可以执行一段Python代码,工具的配置信息: +```yaml +name: 'python_runner' +description: '使用该工具可以执行python代码,可以在pycharm中直接运行的代码.工具的输入必须时一段有效的python代码. 如何你想要查看工具的执行结果, 必须在python代码中使用print(...)打印你想查看的内容。 + 工具输入示例: + 你想要计算1+3等于多少时,工具的输入应该是: + ```py + print(1+3) + ``` + 你想要获取百度页面的信息时,工具的输入应该是: + ```py + import requests + resp=requests.get("https://www.baidu.com") + print(resp.content) + ```' +tool_type: 'api' +input_keys: ['input'] +metadata: + type: 'TOOL' + module: 'sample_standard_app.app.core.tool.python_repl' + class: 'PythonREPLTool' +``` + +该工具可以直接使用,无需任何key,但是为了系统安全,请不要在生产环境使用该工具 + + + + From f450c79a77957e0377ebc176abe4e58254319006 Mon Sep 17 00:00:00 2001 From: weizjajj Date: Mon, 17 Jun 2024 13:16:46 +0800 Subject: [PATCH 2/7] add en doc --- docs/guidebook/en/2_2_3_Integrated_Tools.md | 138 ++++++++++++++++++ ...20\347\232\204\345\267\245\345\205\267.md" | 2 +- 2 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 docs/guidebook/en/2_2_3_Integrated_Tools.md diff --git a/docs/guidebook/en/2_2_3_Integrated_Tools.md b/docs/guidebook/en/2_2_3_Integrated_Tools.md new file mode 100644 index 00000000..6f7e977e --- /dev/null +++ b/docs/guidebook/en/2_2_3_Integrated_Tools.md @@ -0,0 +1,138 @@ +# Integrated Tools + +In the current au's sample project, the following tools are integrated. + +## 1. Search Tools + +### 1.1 Google Search +[工具地址](../../../sample_standard_app/app/core/tool/google_search_tool.yaml) +Detailed Configuration Information: + +```yaml +name: 'google_search_tool' +description: | + This tool can be used to perform Google searches. The tool's input is the content you want to search for. + Example inputs for the tool: + Example 1: If you want to search for the weather in Shanghai, the tool's input should be: "Shanghai weather today" + Example 2: If you want to search for the weather in Japan, the tool's input should be: "Japan weather" +tool_type: 'api' +input_keys: ['input'] +metadata: + type: 'TOOL' + module: 'sample_standard_app.app.core.tool.google_search_tool' + class: 'GoogleSearchTool' +``` +To use this API, you must apply for a BING_SUBSCRIPTION_KEY at https://serper.dev and configure it in your environment variables. +Configuration method: +1. Configure via Python code You must configure: SERPER_API_KEY +```python +import os +os.environ['SERPER_API_KEY'] = 'xxxx' +``` +2. Configure via configuration file In the custom_key.toml file located in the config directory of the project, add the configuration: +```toml +SERPER_API_KEY="xxxx" +``` + + +### 1.2 Bing Search +Currently, it integrates with the official Bing search. +[工具地址](../../../sample_standard_app/app/core/tool/bing_search_tool.yaml) +Tool configuration: +```yaml +name: 'bing_search_tool' +description: 'demo bing search tool' +tool_type: 'api' +input_keys: ['input'] +metadata: + type: 'TOOL' + module: 'sample_standard_app.app.core.tool.bing_search_tool' + class: 'BingSearchTool' +``` +To use this API, you must apply for BING_SUBSCRIPTION_KEY and configure it in environment variables. +Configuration method: +1. Configure through Python code +Mandatory configuration: BING_SUBSCRIPTION_KEY +```python +import os +os.environ['BING_SUBSCRIPTION_KEY'] = 'xxxx' +``` +2. Configure through configuration file +In custom_key.toml under config directory of the project, add configuration: +```toml +BING_SUBSCRIPTION_KEY="xxxx" +``` + + + +### 1.3 Search API +Supports multiple search tools, such as: +- [Baidu search](../../../sample_standard_app/app/core/tool/search_api_baidu_tool.yaml) +- [Bing search](../../../sample_standard_app/app/core/tool/search_api_bing_tool.yaml) +Other search engines also include: Google search, Amazon search, YouTube search, etc. For more information, please refer to: https://www.searchapi.io/ +Tool configuration: +```yaml +name: 'search_api_baidu_tool' +description: 'Baidu (Bing) search tool, input is a string of content to be searched, e.g.: input="What is the price of gold?"' +tool_type: 'api' +input_keys: ['input'] +engine: 'baidu' +search_type: 'json' +search_params: + num: 10 +metadata: + type: 'TOOL' + module: 'sample_standard_app.app.core.tool.search_api_tool' + class: 'SearchAPITool' +``` +Parameter description: + +search_type: Represents the format of the expected search results, where json represents the expectation for JSON format and common represents the expectation for string string format. +search_params: Represents additional parameters that need to be passed to the search engine, such as in Baidu search, num represents the number of returned search results, detailed parameters need to be referenced at [https://www.searchapi.io/]. +engine: The search engine you expect to use, including baidu, google, bing, amazon, youtube, ... To use this API, you must apply for SEARCH_API_KEY from the official website ([https://www.searchapi.io/]) and configure it in environment variables. +Configuration method: +You must configure:SEARCHAPI_API_KEY +1. Configure via Python code : +```python +import os +os.environ['SEARCHAPI_API_KEY'] = 'xxxxxx' +``` +2. Configure through configuration file +Add configuration in custom_key.toml under the config directory of the project: +```toml +SEARCHAPI_API_KEY="xxxxxx" +``` + + +## 2. 代码工具 + +### 2.1 PythonRepl +[Tool address](../../../sample_standard_app/app/core/tool/python_repl_tool.yaml) +This tool can execute a piece of Python code, the configuration information of the tool: +```yaml +name: 'python_runner' +description: 'The tool can execute Python code, which can be directly run in PyCharm. The input to the tool must be valid Python code. If you want to view the execution result of the tool, you must use print(...) to print the content you want to view in the Python code. + Example of tool input: + When you want to calculate what 1 + 3 equals, the input to the tool should be: + ```py + print(1+3) + ``` + When you want to get information about the Baidu page, the input to the tool should be: + ```py + import requests + resp=requests.get("https://www.baidu.com") + print(resp.content) + ```' +tool_type: 'api' +input_keys: ['input'] +metadata: + type: 'TOOL' + module: 'sample_standard_app.app.core.tool.python_repl' + class: 'PythonREPLTool' +``` + +This tool can be used directly without any key, but for system security, please do not use this tool in production environments. + + + + diff --git "a/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md" "b/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md" index 4fb390b2..12057d5d 100644 --- "a/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md" +++ "b/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md" @@ -1,4 +1,4 @@ -# 支持的工具 +# 集成的工具 当前au的 sample工程当中,集成了以下工具: From 81c3a759e57e8c9e76ecb2152cf05cfca04c9849 Mon Sep 17 00:00:00 2001 From: weizjajj Date: Mon, 17 Jun 2024 14:47:52 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E6=9A=82=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../agent/action/knowledge/knowledge.py | 37 +++++++++++++++++++ agentuniverse/agent/agent.py | 36 ++++++++++++++++++ .../app/test/test_rag_agent.py | 10 +++-- 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/agentuniverse/agent/action/knowledge/knowledge.py b/agentuniverse/agent/action/knowledge/knowledge.py index f8e631a7..f8bc3bb7 100644 --- a/agentuniverse/agent/action/knowledge/knowledge.py +++ b/agentuniverse/agent/action/knowledge/knowledge.py @@ -7,6 +7,9 @@ # @FileName: knowledge.py from typing import Optional, Dict, List, Any +from langchain_core.utils.json import parse_json_markdown +from langchain.tools import Tool as LangchainTool + from agentuniverse.agent.action.knowledge.reader.reader import Reader from agentuniverse.agent.action.knowledge.store.document import Document from agentuniverse.agent.action.knowledge.store.query import Query @@ -77,3 +80,37 @@ def initialize_by_component_configer(self, component_configer: KnowledgeConfiger if component_configer.ext_info: self.ext_info = component_configer.ext_info return self + + def langchain_query(self, query: str) -> str: + """Query the knowledge using LangChain. + + Query documents from the store and return the results. + """ + parse_query = parse_json_markdown(query) + query = Query(**parse_query) + knowledge = self.store.query(query) + res = ['This is Query Result'] + for doc in knowledge: + res.append(doc.text) + return "\n=========================================\n".join(res) + + def as_langchain_tool(self) -> Any: + """Convert the Knowledge object to a LangChain tool. + + Returns: + Any: the LangChain tool object + """ + args_description = """ + This is a knowledge base tool, which stores the content you may need. To use this tool, you need to give a json string with the following format: + ```json + { + "query_str": "", + "top_k": , + } + ``` + """ + return LangchainTool( + name=self.name, + description=self.description + args_description, + func=self.langchain_query, + ) diff --git a/agentuniverse/agent/agent.py b/agentuniverse/agent/agent.py index 2f4099fc..40f34354 100644 --- a/agentuniverse/agent/agent.py +++ b/agentuniverse/agent/agent.py @@ -6,10 +6,13 @@ # @Email : lc299034@antgroup.com # @FileName: agent.py """The definition of agent paradigm.""" +import json from abc import abstractmethod from datetime import datetime from typing import Optional +from langchain_core.utils.json import parse_json_markdown + from agentuniverse.agent.agent_model import AgentModel from agentuniverse.agent.input_object import InputObject from agentuniverse.agent.output_object import OutputObject @@ -21,6 +24,7 @@ import ApplicationConfigManager from agentuniverse.base.config.component_configer.configers.agent_configer \ import AgentConfiger +from agentuniverse.base.util.logging.logging_util import LOGGER from agentuniverse.llm.llm import LLM @@ -156,3 +160,35 @@ def initialize_by_component_configer(self, component_configer: AgentConfiger) -> plan=plan, memory=memory, action=action) self.agent_model = agent_model return self + + def langchain_run(self, input: str, callbacks=None, **kwargs): + """Run the agent model using LangChain.""" + try: + parse_result = parse_json_markdown(input) + except Exception as e: + LOGGER.error(f"langchain run parse_json_markdown error,input(parse_result) error({str(e)})") + return "Error , Your Action Input is not a valid JSON string" + output_object = self.run(**parse_result, callbacks=callbacks, **kwargs) + result_dict = {} + for key in self.output_keys(): + result_dict[key] = output_object.get_data(key) + return result_dict + + def as_langchain_tool(self): + """Convert to LangChain tool.""" + from langchain.agents.tools import Tool + format_dict = {} + for key in self.input_keys(): + format_dict.setdefault(key, "input val") + format_str = json.dumps(format_dict) + + args_description = f""" + to use this tool,your input must be a json string,must contain all keys of {self.input_keys()}, + and the value of the key must be a json string,the format of the json string is as follows: + ```{format_str}``` + """ + return Tool( + name=self.agent_model.info.get("name"), + func=self.langchain_run, + description=self.agent_model.info.get("description") + args_description + ) diff --git a/sample_standard_app/app/test/test_rag_agent.py b/sample_standard_app/app/test/test_rag_agent.py index 06c3d9b8..2b7178d5 100644 --- a/sample_standard_app/app/test/test_rag_agent.py +++ b/sample_standard_app/app/test/test_rag_agent.py @@ -24,10 +24,12 @@ def setUp(self) -> None: def test_rag_agent(self): """Test demo rag agent.""" instance: Agent = AgentManager().get_instance_obj('demo_rag_agent') - output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因') - res_info = f"\nRag agent execution result is :\n" - res_info += output_object.get_data('output') - print(res_info) + # output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因') + # res_info = f"\nRag agent execution result is :\n" + # res_info += output_object.get_data('output') + # print(res_info) + tool = instance.as_langchain_tool() + print(tool.description) if __name__ == '__main__': From c1f8bfb7ca2705d6aaac98212b8a6e78e29e9ee7 Mon Sep 17 00:00:00 2001 From: weizjajj Date: Mon, 17 Jun 2024 16:06:47 +0800 Subject: [PATCH 4/7] add knowlege --- .../agent/action/knowledge/knowledge.py | 4 ++-- .../plan/planner/react_planner/react_planner.py | 12 ++++++++++++ sample_standard_app/app/test/test_rag_agent.py | 17 ++++++++++------- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/agentuniverse/agent/action/knowledge/knowledge.py b/agentuniverse/agent/action/knowledge/knowledge.py index f8bc3bb7..d6fc4920 100644 --- a/agentuniverse/agent/action/knowledge/knowledge.py +++ b/agentuniverse/agent/action/knowledge/knowledge.py @@ -5,7 +5,7 @@ # @Author : wangchongshi # @Email : wangchongshi.wcs@antgroup.com # @FileName: knowledge.py -from typing import Optional, Dict, List, Any +from typing import Optional, Dict, List from langchain_core.utils.json import parse_json_markdown from langchain.tools import Tool as LangchainTool @@ -94,7 +94,7 @@ def langchain_query(self, query: str) -> str: res.append(doc.text) return "\n=========================================\n".join(res) - def as_langchain_tool(self) -> Any: + def as_langchain_tool(self) -> LangchainTool: """Convert the Knowledge object to a LangChain tool. Returns: diff --git a/agentuniverse/agent/plan/planner/react_planner/react_planner.py b/agentuniverse/agent/plan/planner/react_planner/react_planner.py index ef1f76f9..77e2b0f2 100644 --- a/agentuniverse/agent/plan/planner/react_planner/react_planner.py +++ b/agentuniverse/agent/plan/planner/react_planner/react_planner.py @@ -11,8 +11,11 @@ from langchain.tools import Tool as LangchainTool from langchain_core.runnables import RunnableConfig +from agentuniverse.agent.action.knowledge.knowledge import Knowledge +from agentuniverse.agent.action.knowledge.knowledge_manager import KnowledgeManager from agentuniverse.agent.action.tool.tool import Tool from agentuniverse.agent.action.tool.tool_manager import ToolManager +from agentuniverse.agent.agent import Agent from agentuniverse.agent.agent_model import AgentModel from agentuniverse.agent.input_object import InputObject from agentuniverse.agent.memory.chat_memory import ChatMemory @@ -78,6 +81,15 @@ def acquire_tools(action) -> list[LangchainTool]: for tool_name in tool_names: tool: Tool = ToolManager().get_instance_obj(tool_name) lc_tools.append(tool.as_langchain()) + knowledge: list = action.get('knowledge') or list() + for knowledge_name in knowledge: + knowledge_tool: Knowledge = KnowledgeManager().get_instance_obj(knowledge_name) + lc_tools.append(knowledge_tool.as_langchain_tool()) + + agents: list = action.get('agent') or list() + for agent_name in agents: + agent_tool: Agent = AgentModel.load_by_name(agent_name) + lc_tools.append(agent_tool.as_langchain_tool()) return lc_tools def handle_prompt(self, agent_model: AgentModel, planner_input: dict) -> Prompt: diff --git a/sample_standard_app/app/test/test_rag_agent.py b/sample_standard_app/app/test/test_rag_agent.py index 2b7178d5..1d97de49 100644 --- a/sample_standard_app/app/test/test_rag_agent.py +++ b/sample_standard_app/app/test/test_rag_agent.py @@ -7,6 +7,8 @@ # @FileName: test_rag_agent.py import unittest +from agentuniverse.agent.action.knowledge.knowledge import Knowledge +from agentuniverse.agent.action.knowledge.knowledge_manager import KnowledgeManager from agentuniverse.agent.agent import Agent from agentuniverse.agent.agent_manager import AgentManager from agentuniverse.agent.output_object import OutputObject @@ -23,13 +25,14 @@ def setUp(self) -> None: def test_rag_agent(self): """Test demo rag agent.""" - instance: Agent = AgentManager().get_instance_obj('demo_rag_agent') - # output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因') - # res_info = f"\nRag agent execution result is :\n" - # res_info += output_object.get_data('output') - # print(res_info) - tool = instance.as_langchain_tool() - print(tool.description) + # instance: Agent = AgentManager().get_instance_obj('demo_rag_agent') + # # output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因') + # # res_info = f"\nRag agent execution result is :\n" + # # res_info += output_object.get_data('output') + # # print(res_info) + # tool = instance.as_langchain_tool() + knowledge: Knowledge = KnowledgeManager().get_instance_obj('demo_knowledge') + print(knowledge.as_langchain_tool().description) if __name__ == '__main__': From 76f2621345a790fc259c3fe597d2f299a3db6dc1 Mon Sep 17 00:00:00 2001 From: weizjajj Date: Mon, 17 Jun 2024 16:07:50 +0800 Subject: [PATCH 5/7] fix output --- sample_standard_app/app/test/test_rag_agent.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sample_standard_app/app/test/test_rag_agent.py b/sample_standard_app/app/test/test_rag_agent.py index 1d97de49..3c678aa1 100644 --- a/sample_standard_app/app/test/test_rag_agent.py +++ b/sample_standard_app/app/test/test_rag_agent.py @@ -23,16 +23,13 @@ class RagAgentTest(unittest.TestCase): def setUp(self) -> None: AgentUniverse().start(config_path='../../config/config.toml') - def test_rag_agent(self): + def test_rag_fgent(self): """Test demo rag agent.""" - # instance: Agent = AgentManager().get_instance_obj('demo_rag_agent') - # # output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因') - # # res_info = f"\nRag agent execution result is :\n" - # # res_info += output_object.get_data('output') - # # print(res_info) - # tool = instance.as_langchain_tool() - knowledge: Knowledge = KnowledgeManager().get_instance_obj('demo_knowledge') - print(knowledge.as_langchain_tool().description) + instance: Agent = AgentManager().get_instance_obj('demo_rag_agent') + output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因') + res_info = f"\nRag agent execution result is :\n" + res_info += output_object.get_data('output') + print(res_info) if __name__ == '__main__': From 521295a33d1901a7f70bfdd7238d400bd1635e41 Mon Sep 17 00:00:00 2001 From: weizjajj Date: Mon, 17 Jun 2024 16:08:42 +0800 Subject: [PATCH 6/7] remove unused import --- sample_standard_app/app/test/test_rag_agent.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sample_standard_app/app/test/test_rag_agent.py b/sample_standard_app/app/test/test_rag_agent.py index 3c678aa1..14ba678f 100644 --- a/sample_standard_app/app/test/test_rag_agent.py +++ b/sample_standard_app/app/test/test_rag_agent.py @@ -7,8 +7,6 @@ # @FileName: test_rag_agent.py import unittest -from agentuniverse.agent.action.knowledge.knowledge import Knowledge -from agentuniverse.agent.action.knowledge.knowledge_manager import KnowledgeManager from agentuniverse.agent.agent import Agent from agentuniverse.agent.agent_manager import AgentManager from agentuniverse.agent.output_object import OutputObject From 4ff65593214677e89006920a009d6e04eaa07223 Mon Sep 17 00:00:00 2001 From: weizjajj Date: Wed, 19 Jun 2024 17:53:42 +0800 Subject: [PATCH 7/7] add deepseek support --- .../planner/react_planner/react_planner.py | 3 +- .../llm/default/deep_seek_openai_style_llm.py | 70 +++++++++++++++++++ .../default/deep_seek_openai_style_llm.yaml | 8 +++ agentuniverse/llm/llm.py | 2 + agentuniverse/llm/openai_style_llm.py | 19 +++++ ...20\347\232\204\345\267\245\345\205\267.md" | 2 +- .../rag_agent_case/demo_multillm_agent.yaml | 6 +- .../agent/rag_agent_case/law_rag_agent.yaml | 2 +- .../react_agent_case/demo_react_agent.yaml | 6 ++ .../core/knowledge/civil_law_knowledge.yaml | 2 +- .../knowledge/criminal_law_knowledge.yaml | 2 +- .../app/core/llm/deep_seek_opneai_llm.yaml | 11 +++ .../app/test/test_deep_seek_llm.py | 56 +++++++++++++++ 13 files changed, 182 insertions(+), 7 deletions(-) create mode 100644 agentuniverse/llm/default/deep_seek_openai_style_llm.py create mode 100644 agentuniverse/llm/default/deep_seek_openai_style_llm.yaml create mode 100644 sample_standard_app/app/core/llm/deep_seek_opneai_llm.yaml create mode 100644 sample_standard_app/app/test/test_deep_seek_llm.py diff --git a/agentuniverse/agent/plan/planner/react_planner/react_planner.py b/agentuniverse/agent/plan/planner/react_planner/react_planner.py index 77e2b0f2..b3f20211 100644 --- a/agentuniverse/agent/plan/planner/react_planner/react_planner.py +++ b/agentuniverse/agent/plan/planner/react_planner/react_planner.py @@ -16,6 +16,7 @@ from agentuniverse.agent.action.tool.tool import Tool from agentuniverse.agent.action.tool.tool_manager import ToolManager from agentuniverse.agent.agent import Agent +from agentuniverse.agent.agent_manager import AgentManager from agentuniverse.agent.agent_model import AgentModel from agentuniverse.agent.input_object import InputObject from agentuniverse.agent.memory.chat_memory import ChatMemory @@ -88,7 +89,7 @@ def acquire_tools(action) -> list[LangchainTool]: agents: list = action.get('agent') or list() for agent_name in agents: - agent_tool: Agent = AgentModel.load_by_name(agent_name) + agent_tool: Agent = AgentManager().get_instance_obj(agent_name) lc_tools.append(agent_tool.as_langchain_tool()) return lc_tools diff --git a/agentuniverse/llm/default/deep_seek_openai_style_llm.py b/agentuniverse/llm/default/deep_seek_openai_style_llm.py new file mode 100644 index 00000000..485ec685 --- /dev/null +++ b/agentuniverse/llm/default/deep_seek_openai_style_llm.py @@ -0,0 +1,70 @@ +# !/usr/bin/env python3 +# -*- coding:utf-8 -*- + +# @Time : 2024/5/21 17:49 +# @Author : weizjajj +# @Email : weizhongjie.wzj@antgroup.com +# @FileName: claude_llm.py + +from typing import Optional, Any, Union, Iterator, AsyncIterator + +from pydantic import Field + +from agentuniverse.base.annotation.trace import trace_llm +from agentuniverse.base.util.env_util import get_from_env +from agentuniverse.llm.llm_output import LLMOutput +from agentuniverse.llm.openai_style_llm import OpenAIStyleLLM + +DEEpSEEkMAXCONTETNLENGTH = { + "deepseek-chat": 32000, + "deepseek-coder": 32000, + "claude-3-haiku-20240307": 200000, + "claude-2.1": 200000, + "claude-2.0": 100000, + "claude-instant-1.2": 100000 +} + + +class DefaultDeepSeekLLM(OpenAIStyleLLM): + """The agentUniverse default openai llm module. + + LLM parameters, such as name/description/model_name/max_tokens, + are injected into this class by the default_openai_llm.yaml configuration. + """ + + api_key: Optional[str] = Field(default_factory=lambda: get_from_env("DEEPSEEK_API_KEY")) + organization: Optional[str] = Field(default_factory=lambda: get_from_env("DEEPSEEK_ORGANIZATION")) + api_base: Optional[str] = Field(default_factory=lambda: get_from_env("DEEPSEEK_API_BASE")) + proxy: Optional[str] = Field(default_factory=lambda: get_from_env("DEEPSEEK_PROXY")) + + @trace_llm + def call(self, messages: list, **kwargs: Any) -> Union[LLMOutput, Iterator[LLMOutput]]: + """ The call method of the LLM. + + Users can customize how the model interacts by overriding call method of the LLM class. + + Args: + messages (list): The messages to send to the LLM. + **kwargs: Arbitrary keyword arguments. + """ + return super().call(messages, **kwargs) + + @trace_llm + async def acall(self, messages: list, **kwargs: Any) -> Union[LLMOutput, AsyncIterator[LLMOutput]]: + """ The async call method of the LLM. + + Users can customize how the model interacts by overriding acall method of the LLM class. + + Args: + messages (list): The messages to send to the LLM. + **kwargs: Arbitrary keyword arguments. + """ + return await super().acall(messages, **kwargs) + + def max_context_length(self) -> int: + """Max context length. + + The total length of input tokens and generated tokens is limited by the openai model's context length. + """ + return DEEpSEEkMAXCONTETNLENGTH.get(self.model_name, 4096) + diff --git a/agentuniverse/llm/default/deep_seek_openai_style_llm.yaml b/agentuniverse/llm/default/deep_seek_openai_style_llm.yaml new file mode 100644 index 00000000..3921577a --- /dev/null +++ b/agentuniverse/llm/default/deep_seek_openai_style_llm.yaml @@ -0,0 +1,8 @@ +name: 'default_deepseek_llm' +description: 'default default_deepseek_llm llm with spi' +model_name: 'deepseek-chat' +max_tokens: 1000 +metadata: + type: 'LLM' + module: 'agentuniverse.llm.default.deep_seek_openai_style_llm' + class: 'DefaultDeepSeekLLM' \ No newline at end of file diff --git a/agentuniverse/llm/llm.py b/agentuniverse/llm/llm.py index 53c4fd67..4d33c629 100644 --- a/agentuniverse/llm/llm.py +++ b/agentuniverse/llm/llm.py @@ -103,6 +103,8 @@ def initialize_by_component_configer(self, component_configer: LLMConfiger) -> ' if component_configer.ext_info: self.ext_info = component_configer.ext_info self.tracing = component_configer.tracing + if 'max_context_length' in component_configer.configer.value: + self._max_context_length = component_configer.configer.value['max_context_length'] return self def set_by_agent_model(self, **kwargs) -> None: diff --git a/agentuniverse/llm/openai_style_llm.py b/agentuniverse/llm/openai_style_llm.py index 2d5a3ea0..0981e47a 100644 --- a/agentuniverse/llm/openai_style_llm.py +++ b/agentuniverse/llm/openai_style_llm.py @@ -14,6 +14,8 @@ from langchain_core.language_models.base import BaseLanguageModel from openai import OpenAI, AsyncOpenAI +from agentuniverse.base.config.component_configer.configers.llm_configer import LLMConfiger +from agentuniverse.base.util.env_util import get_from_env from agentuniverse.llm.llm import LLM, LLMOutput from agentuniverse.llm.openai_style_langchain_instance import LangchainOpenAIStyleInstance @@ -161,6 +163,17 @@ async def agenerate_stream_result(self, stream: AsyncIterator) -> AsyncIterator[ await self.aclose() + def initialize_by_component_configer(self, component_configer: LLMConfiger) -> 'LLM': + if 'api_base' in component_configer.configer.value: + self.api_base = component_configer.configer.value.get('api_base') + elif 'api_base_env' in component_configer.configer.value: + self.api_base = get_from_env(component_configer.configer.value.get('api_base_env')) + if 'api_key' in component_configer .configer.value: + self.api_key = component_configer.configer.value.get('api_key') + elif 'api_key_env' in component_configer.configer.value: + self.api_key = get_from_env(component_configer.configer.value.get('api_key_env')) + return super().initialize_by_component_configer(component_configer) + def get_num_tokens(self, text: str) -> int: """Get the number of tokens present in the text. @@ -187,3 +200,9 @@ async def aclose(self): """Async close the client.""" if hasattr(self, 'async_client') and self.async_client: await self.async_client.close() + + def max_context_length(self) -> int: + """Return the maximum length of the context.""" + if super().max_context_length(): + return super().max_context_length() + return 4000 diff --git "a/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md" "b/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md" index 12057d5d..ceba884c 100644 --- "a/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md" +++ "b/docs/guidebook/zh/2_2_3_\351\233\206\346\210\220\347\232\204\345\267\245\345\205\267.md" @@ -22,7 +22,7 @@ metadata: module: 'sample_standard_app.app.core.tool.google_search_tool' class: 'GoogleSearchTool' ``` -为了使用该api,你必须申请(https://serper.dev)BING_SUBSCRIPTION_KEY,并配置在环境变量当中。 +为了使用该api,你必须申请(https://serper.dev)SERPER_API_KEY并配置在环境变量当中。 配置方法: 1. 通过python代码配置 必须配置:SERPER_API_KEY diff --git a/sample_standard_app/app/core/agent/rag_agent_case/demo_multillm_agent.yaml b/sample_standard_app/app/core/agent/rag_agent_case/demo_multillm_agent.yaml index 2fd13785..8732f8a1 100644 --- a/sample_standard_app/app/core/agent/rag_agent_case/demo_multillm_agent.yaml +++ b/sample_standard_app/app/core/agent/rag_agent_case/demo_multillm_agent.yaml @@ -15,8 +15,10 @@ profile: # model_name: 'Baichuan2-Turbo' # name: 'qwen_llm' # model_name: 'qwen-turbo' - name: 'wenxin_llm' - model_name: 'ERNIE-3.5-8K' +# name: 'wenxin_llm' +# model_name: 'ERNIE-3.5-8K' +# name: 'deep_seek_llm' + name: 'default_deepseek_llm' plan: planner: name: 'rag_planner' diff --git a/sample_standard_app/app/core/agent/rag_agent_case/law_rag_agent.yaml b/sample_standard_app/app/core/agent/rag_agent_case/law_rag_agent.yaml index bf917fcd..03ced866 100644 --- a/sample_standard_app/app/core/agent/rag_agent_case/law_rag_agent.yaml +++ b/sample_standard_app/app/core/agent/rag_agent_case/law_rag_agent.yaml @@ -1,6 +1,6 @@ info: name: 'law_rag_agent' - description: 'law rag agent' + description: '一个法律顾问,可以根据给出的事件,以及提供的背景知识做出客观的司法判断。' profile: introduction: 你是一位精通信息分析的ai法律顾问。 target: 你的目标是根据给出的事件,以及提供的背景知识做出客观的司法判断。 diff --git a/sample_standard_app/app/core/agent/react_agent_case/demo_react_agent.yaml b/sample_standard_app/app/core/agent/react_agent_case/demo_react_agent.yaml index 8a38838d..b9a4e02a 100644 --- a/sample_standard_app/app/core/agent/react_agent_case/demo_react_agent.yaml +++ b/sample_standard_app/app/core/agent/react_agent_case/demo_react_agent.yaml @@ -5,11 +5,17 @@ profile: prompt_version: qwen_react_agent.cn llm_model: name: 'default_qwen_llm' + model_name: 'qwen-max' temperature: 0 action: tool: - 'google_search_tool' - 'python_runner' + knowledge: + - 'civil_law_knowledge' + - 'criminal_law_knowledge' + agent: + - 'law_rag_agent' plan: planner: name: 'react_planner' diff --git a/sample_standard_app/app/core/knowledge/civil_law_knowledge.yaml b/sample_standard_app/app/core/knowledge/civil_law_knowledge.yaml index 86ddd6b0..3cf789e9 100644 --- a/sample_standard_app/app/core/knowledge/civil_law_knowledge.yaml +++ b/sample_standard_app/app/core/knowledge/civil_law_knowledge.yaml @@ -1,5 +1,5 @@ name: 'civil_law_knowledge' -description: 'civil law knowledge' +description: 民法知识库,可以查询民法典法律相关内容' metadata: type: 'KNOWLEDGE' module: 'sample_standard_app.app.core.knowledge.civil_law_knowledge' diff --git a/sample_standard_app/app/core/knowledge/criminal_law_knowledge.yaml b/sample_standard_app/app/core/knowledge/criminal_law_knowledge.yaml index 5a1b2a8c..184b16f9 100644 --- a/sample_standard_app/app/core/knowledge/criminal_law_knowledge.yaml +++ b/sample_standard_app/app/core/knowledge/criminal_law_knowledge.yaml @@ -1,5 +1,5 @@ name: 'criminal_law_knowledge' -description: 'criminal law knowledge' +description: '刑法知识库,可以查询与刑法相关的内容' metadata: type: 'KNOWLEDGE' module: 'sample_standard_app.app.core.knowledge.criminal_law_knowledge' diff --git a/sample_standard_app/app/core/llm/deep_seek_opneai_llm.yaml b/sample_standard_app/app/core/llm/deep_seek_opneai_llm.yaml new file mode 100644 index 00000000..a4aebb15 --- /dev/null +++ b/sample_standard_app/app/core/llm/deep_seek_opneai_llm.yaml @@ -0,0 +1,11 @@ +name: 'deep_seek_llm' +description: 'demo deep_seek llm with spi' +model_name: 'deepseek-chat' +max_tokens: 4000 +max_context_length: 32000 +api_key_env: 'DEEPSEEK_API_KEY' +api_base_env: 'DEEPSEEK_API_BASE' +metadata: + type: 'LLM' + module: 'agentuniverse.llm.openai_style_llm' + class: 'OpenAIStyleLLM' \ No newline at end of file diff --git a/sample_standard_app/app/test/test_deep_seek_llm.py b/sample_standard_app/app/test/test_deep_seek_llm.py new file mode 100644 index 00000000..8afb55c8 --- /dev/null +++ b/sample_standard_app/app/test/test_deep_seek_llm.py @@ -0,0 +1,56 @@ +# !/usr/bin/env python3 +# -*- coding:utf-8 -*- + +# @Time : 2024/5/22 16:25 +# @Author : weizjajj +# @Email : weizhongjie.wzj@antgroup.com +# @FileName: test_wenxin_llm.py + + +import asyncio +import time +import unittest + +from agentuniverse.base.agentuniverse import AgentUniverse +from agentuniverse.llm.default.wenxin_llm import WenXinLLM +from agentuniverse.llm.llm_manager import LLMManager + + +class DeepSeekLLMTest(unittest.TestCase): + """Test cases for the reviewing agent""" + + def setUp(self) -> None: + AgentUniverse().start(config_path='../../config/config.toml') + + def test_reviewing_agent(self): + llm: WenXinLLM = LLMManager().get_instance_obj("deep_seek_llm") + res = llm.call( + messages=[{"role": "user", "content": "你好"}], + streaming=True + ) + print(res) + for item in res: + print(item) + + langchain_llm = llm.as_langchain() + print(langchain_llm.invoke(input="你好")) + time.sleep(1) + asyncio.run(self.call_stream()) + + async def call_stream(self): + llm: WenXinLLM = LLMManager().get_instance_obj("deep_seek_llm") + res = await llm.acall( + messages=[{"role": "user", "content": "你好"}], + streaming=True + ) + print(res) + async for item in res: + print(item) + + langchain_llm = llm.as_langchain() + res = await langchain_llm.ainvoke(input="你好") + print(res) + + +if __name__ == '__main__': + unittest.main()