diff --git a/CHANGELOG.md b/CHANGELOG.md index bbbcdee3..ac7f8b7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,15 @@ Security - Patches and security improvements. *************************************************** # Version Update History +## [0.0.4] - 2024-04-26 +### Added +- Add version management capability to the prompt. + +### Fixed +- Fixed compatibility issues on Windows + * Due to compatibility issues of Gunicorn with Windows systems, automatically identify the kernel version to select the web startup method. + * Specified YAML reading as UTF-8 encoding method. + ## [0.0.3] - 2024-04-19 ### Init - The official release version of AgentUniverse has been initialized. Enjoy using it! diff --git a/CHANGELOG_zh.md b/CHANGELOG_zh.md index 193110ea..7e6f0a74 100644 --- a/CHANGELOG_zh.md +++ b/CHANGELOG_zh.md @@ -23,6 +23,15 @@ Security - 补丁与安全改进。 *************************************************** # 版本更新记录 +## [0.0.4] - 2024-04-26 +### Added +- 新增prompt版本管理能力 + +### Fixed +- Windows版本下的兼容问题修复 + * 由于Gunicore对于windows系统的兼容问题,自动识别内核版本自动选择web启动方式 + * yaml读取指定为utf-8 encode方式 + ## [0.0.3] - 2024-04-19 ### Init - agentUniverse正式外发版本初始化,祝您使用愉快! diff --git a/README.md b/README.md index e42783d1..e3c5326b 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ Language version: [English](./README.md) | [中文](./README_zh.md) ![](https://img.shields.io/badge/framework-agentUniverse-pink) ![](https://img.shields.io/badge/python-3.10%2B-blue?logo=Python) [![](https://img.shields.io/badge/%20license-Apache--2.0-yellow)](LICENSE) -[![Static Badge](https://img.shields.io/badge/pypi-v0.0.3-blue?logo=pypi)](https://pypi.org/project/agentUniverse/) +[![Static Badge](https://img.shields.io/badge/pypi-v0.0.4-blue?logo=pypi)](https://pypi.org/project/agentUniverse/) -![](https://github.com/alipay/agentUniverse/blob/master/docs/guidebook/_picture/logo_bar.png) +![](docs/guidebook/_picture/logo_bar.jpg) **************************************** ## Overview @@ -24,10 +24,10 @@ This pattern consists of three agents: Data-fining agent, which is designed to s More patterns are coming soon... -![](https://github.com/alipay/agentUniverse/blob/master/docs/guidebook/_picture/agent_universe_framework_resize.jpg) +![](docs/guidebook/_picture/agent_universe_framework_resize.jpg) ## agentUniverseSample Project -[agentUniverse Sample Project](https://github.com/alipay/agentUniverse/blob/master/sample_standard_app/README.md) +[agentUniverse Sample Project](sample_standard_app/README.md) ## Quick Installation Using pip: @@ -42,7 +42,20 @@ We will show you how to: * Use pattern components to complete multi-agent collaboration * Test and optimize the performance of the agent * Quickly serve the agent -For details, please read [Quick Start](https://github.com/alipay/agentUniverse/blob/master/docs/guidebook/en/1_3_Quick_Start.md). +For details, please read [Quick Start](docs/guidebook/en/1_3_Quick_Start.md). ## Guidebook -For more detailed information, please refer to the [Guidebook](https://github.com/alipay/agentUniverse/blob/master/docs/guidebook/en/0_index.md). +For more detailed information, please refer to the [Guidebook](docs/guidebook/en/0_index.md). + +## API Reference +[readthedocs](https://agentuniverse.readthedocs.io/en/latest/) + +## More Ways to Contact Us +* github: https://github.com/alipay/agentUniverse +* gitee: https://gitee.com/agentUniverse/agentUniverse +* gitcode: https://gitcode.com/agentUniverse +* Stack Overflow: https://stackoverflowteams.com/c/agentuniverse/questions +* Discord: https://discord.gg/VfhEvJzQ +* WeChat Official Account: agentUniverse智多星 +* DingTalk Group: +![](./docs/guidebook/_picture/dingtalk_util20250429.png) \ No newline at end of file diff --git a/README_zh.md b/README_zh.md index 776acc6b..2ec569ca 100644 --- a/README_zh.md +++ b/README_zh.md @@ -5,9 +5,9 @@ ![](https://img.shields.io/badge/framework-agentUniverse-pink) ![](https://img.shields.io/badge/python-3.10%2B-blue?logo=Python) [![](https://img.shields.io/badge/%20license-Apache--2.0-yellow)](LICENSE) -[![Static Badge](https://img.shields.io/badge/pypi-v0.0.3-blue?logo=pypi)](https://pypi.org/project/agentUniverse/) +[![Static Badge](https://img.shields.io/badge/pypi-v0.0.4-blue?logo=pypi)](https://pypi.org/project/agentUniverse/) -![](https://github.com/alipay/agentUniverse/blob/master/docs/guidebook/_picture/logo_bar.png) +![](docs/guidebook/_picture/logo_bar.jpg) **************************************** ## 项目介绍 @@ -25,11 +25,11 @@ 更多模式组件持续推出中... -![](https://github.com/alipay/agentUniverse/blob/master/docs/guidebook/_picture/agent_universe_framework_resize.jpg) +![](docs/guidebook/_picture/agent_universe_framework_resize.jpg) ## agentUniverse 示例项目 -[agentUniverse 示例项目](https://github.com/alipay/agentUniverse/tree/master/sample_standard_app) +[agentUniverse 示例项目](sample_standard_app/README_zh.md) ## 快速安装 使用pip: @@ -45,7 +45,20 @@ pip install agentUniverse * 对agent执行效果进行测试调优 * 对agent进行快速服务化 -详情请阅读[快速开始](https://github.com/alipay/agentUniverse/blob/master/docs/guidebook/zh/1_3_%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B.md) 。 +详情请阅读[快速开始](docs/guidebook/zh/1_3_%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B.md) 。 ## 用户指南 -更多详细信息,请参阅[指南](https://github.com/alipay/agentUniverse/blob/master/docs/guidebook/zh/0_%E7%9B%AE%E5%BD%95.md) 。 +更多详细信息,请参阅[指南](docs/guidebook/zh/0_%E7%9B%AE%E5%BD%95.md) 。 + +## API 参考 +[readthedocs](https://agentuniverse.readthedocs.io/en/latest/) + +## 更多方式联系我们 +* github: https://github.com/alipay/agentUniverse +* gitee: https://gitee.com/agentUniverse/agentUniverse +* gitcode: https://gitcode.com/agentUniverse +* Stack Overflow: https://stackoverflowteams.com/c/agentuniverse/questions +* Discord: https://discord.gg/VfhEvJzQ +* 微信公众号: agentUniverse智多星 +* 钉钉答疑群: +![](./docs/guidebook/_picture/dingtalk_util20250429.png) \ No newline at end of file diff --git a/agentuniverse/agent/action/knowledge/embedding/openai_embedding.py b/agentuniverse/agent/action/knowledge/embedding/openai_embedding.py index b521577f..fa9bba8c 100644 --- a/agentuniverse/agent/action/knowledge/embedding/openai_embedding.py +++ b/agentuniverse/agent/action/knowledge/embedding/openai_embedding.py @@ -24,14 +24,6 @@ class OpenAIEmbedding(Embedding): async_client: Any = None dimensions: Optional[int] = None - def __init__(self, **kwargs): - """Initialize the openai embedding class.""" - super().__init__(**kwargs) - if self.client is None: - self.client = OpenAI(api_key=self.openai_api_key, **self.openai_client_args or {}) - if self.async_client is None: - self.async_client = AsyncOpenAI(api_key=self.openai_api_key, **self.openai_client_args or {}) - def get_embeddings(self, texts: List[str]) -> List[List[float]]: """Get the OpenAI embeddings. @@ -48,7 +40,7 @@ def get_embeddings(self, texts: List[str]) -> List[List[float]]: Raises: ValueError: If texts exceed the embedding model token limit or missing some required parameters. """ - + self.client = OpenAI(api_key=self.openai_api_key, **self.openai_client_args or {}) if self.embedding_model_name is None: raise ValueError("Must provide `embedding_model_name`") try: @@ -81,7 +73,7 @@ async def async_get_embeddings(self, texts: List[str]) -> List[List[float]]: Raises: ValueError: If texts exceed the embedding model token limit or missing some required parameters. """ - + self.async_client = AsyncOpenAI(api_key=self.openai_api_key, **self.openai_client_args or {}) if self.embedding_model_name is None: raise ValueError("Must provide `embedding_model_name`") try: diff --git a/agentuniverse/agent/action/knowledge/store/chroma_store.py b/agentuniverse/agent/action/knowledge/store/chroma_store.py index cda4405a..7da8f8ad 100644 --- a/agentuniverse/agent/action/knowledge/store/chroma_store.py +++ b/agentuniverse/agent/action/knowledge/store/chroma_store.py @@ -99,6 +99,32 @@ def insert_documents(self, documents: List[Document], **kwargs: Any): ids=[document.id] ) + def upsert_document(self, documents: List[Document], **kwargs): + """Upsert document into the store.""" + for document in documents: + embedding = document.embedding + if self.embedding_model is not None and len(embedding) == 0: + embedding = self.embedding_model.get_embeddings([document.text])[0] + self.collection.upsert( + documents=[document.text], + metadatas=[document.metadata], + embeddings=[embedding] if embedding is not None else None, + ids=[document.id] + ) + + def update_document(self, documents: List[Document], **kwargs): + """Update document into the store.""" + for document in documents: + embedding = document.embedding + if self.embedding_model is not None and len(embedding) == 0: + embedding = self.embedding_model.get_embeddings([document.text])[0] + self.collection.update( + documents=[document.text], + metadatas=[document.metadata], + embeddings=[embedding] if embedding is not None else None, + ids=[document.id] + ) + @staticmethod def to_documents(query_result: QueryResult) -> List[Document]: """Convert the query results of ChromaDB to the AgentUniverse(AU) document format.""" diff --git a/agentuniverse/agent/action/knowledge/store/document.py b/agentuniverse/agent/action/knowledge/store/document.py index 46ef5896..3f999b54 100644 --- a/agentuniverse/agent/action/knowledge/store/document.py +++ b/agentuniverse/agent/action/knowledge/store/document.py @@ -8,7 +8,7 @@ from typing import Dict, Any, Optional, List from langchain_core.documents.base import Document as LCDocument -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, model_validator class Document(BaseModel): @@ -21,11 +21,18 @@ class Document(BaseModel): embedding (List[float]): Embedding data associated with the document """ - id: str = Field(default_factory=lambda: str(uuid.uuid4())) + id: str = None text: Optional[str] = "" metadata: Optional[Dict[str, Any]] = None embedding: List[float] = Field(default_factory=list) + @model_validator(mode='before') + def create_id(cls, values): + text: str = values.get('text', '') + if not values.get('id'): + values['id'] = str(uuid.uuid5(uuid.NAMESPACE_URL, text)) + return values + def as_langchain(self) -> LCDocument: """Convert to LangChain document format.""" metadata = self.metadata or {} diff --git a/agentuniverse/agent/action/knowledge/store/store.py b/agentuniverse/agent/action/knowledge/store/store.py index 8be62a52..c37ec73b 100644 --- a/agentuniverse/agent/action/knowledge/store/store.py +++ b/agentuniverse/agent/action/knowledge/store/store.py @@ -87,3 +87,19 @@ def delete_document(self, document_id: str, **kwargs): async def async_delete_document(self, document_id: str, **kwargs): """Asynchronously delete the specific document by the document id.""" raise NotImplementedError + + def upsert_document(self, documents: List[Document], **kwargs): + """Upsert document into the store.""" + raise NotImplementedError + + async def async_upsert_document(self, documents: List[Document], **kwargs): + """Asynchronously upsert documents into the store.""" + raise NotImplementedError + + def update_document(self, documents: List[Document], **kwargs): + """Update document into the store.""" + raise NotImplementedError + + async def async_update_document(self, documents: List[Document], **kwargs): + """Asynchronously update documents into the store.""" + raise NotImplementedError diff --git a/agentuniverse/agent/default/peer_agent.py b/agentuniverse/agent/default/peer_agent.py new file mode 100644 index 00000000..5c003ff4 --- /dev/null +++ b/agentuniverse/agent/default/peer_agent.py @@ -0,0 +1,43 @@ +# !/usr/bin/env python3 +# -*- coding:utf-8 -*- + +# @Time : 2024/4/29 16:00 +# @Author : wangchongshi +# @Email : wangchongshi.wcs@antgroup.com +# @FileName: peer_agent.py +from agentuniverse.agent.agent import Agent +from agentuniverse.agent.input_object import InputObject + + +class PeerAgent(Agent): + """Peer Agent class.""" + + def input_keys(self) -> list[str]: + """Return the input keys of the Agent.""" + return ['input'] + + def output_keys(self) -> list[str]: + """Return the output keys of the Agent.""" + return ['output'] + + def parse_input(self, input_object: InputObject, planner_input: dict) -> dict: + """Planner parameter parsing. + + Args: + input_object(InputObject): agent parameter object + planner_input(dict): Planner input + Returns: + dict: Planner input + """ + planner_input['input'] = input_object.get_data('input') + return planner_input + + def parse_result(self, planner_result: dict) -> dict: + """Planner result parser. + + Args: + planner_result(dict): Planner result + Returns: + dict: Agent result object. + """ + return {"output": planner_result.get('result')[0].get('expressing_result').get_data('output')} diff --git a/agentuniverse/agent/default/peer_agent.yaml b/agentuniverse/agent/default/peer_agent.yaml new file mode 100644 index 00000000..75e16fd6 --- /dev/null +++ b/agentuniverse/agent/default/peer_agent.yaml @@ -0,0 +1,16 @@ +info: + name: 'PeerAgent' + description: 'peer agent' +plan: + planner: + name: 'peer_planner' + eval_threshold: 60 + retry_count: 2 + planning: 'PlanningAgent' + executing: 'ExecutingAgent' + expressing: 'ExpressingAgent' + reviewing: 'ReviewingAgent' +metadata: + type: 'AGENT' + module: 'agentuniverse.agent.default.peer_agent' + class: 'PeerAgent' \ No newline at end of file diff --git a/agentuniverse/agent/plan/planner/executing_planner/executing_planner.py b/agentuniverse/agent/plan/planner/executing_planner/executing_planner.py index 9fc1084f..b35ea313 100644 --- a/agentuniverse/agent/plan/planner/executing_planner/executing_planner.py +++ b/agentuniverse/agent/plan/planner/executing_planner/executing_planner.py @@ -6,9 +6,10 @@ # @FileName: executing_planner.py """Execution planner module.""" import asyncio + from langchain.chains import LLMChain from langchain_core.memory import BaseMemory -from langchain_core.prompts import PromptTemplate + from agentuniverse.agent.agent_model import AgentModel from agentuniverse.agent.input_object import InputObject from agentuniverse.agent.plan.planner.planner import Planner @@ -39,21 +40,21 @@ def invoke(self, agent_model: AgentModel, planner_input: dict, input_object: Inp llm: LLM = self.handle_llm(agent_model) - self.handle_prompt(agent_model, planner_input) + prompt: Prompt = self.handle_prompt(agent_model, planner_input) llm_chain = LLMChain(llm=llm.as_langchain(), - prompt=self.prompt.as_langchain(), + prompt=prompt.as_langchain(), output_key=self.output_key, memory=memory) return asyncio.run(llm_chain.acall(inputs=planner_input)) - def handle_prompt(self, agent_model: AgentModel, planner_input: dict): + def handle_prompt(self, agent_model: AgentModel, planner_input: dict) -> Prompt: """Prompt module processing. Args: agent_model (AgentModel): Agent model object. planner_input (dict): Planner input object. Returns: - PromptTemplate: The prompt template. + Prompt: The prompt instance. """ expert_framework = planner_input.pop('expert_framework', '') or '' @@ -74,6 +75,7 @@ def handle_prompt(self, agent_model: AgentModel, planner_input: dict): target=prompt.target, instruction=expert_framework + prompt.instruction) - self.prompt.build_prompt(user_prompt_model, system_prompt_model, - self.prompt_assemble_order) - process_llm_token(self.prompt.as_langchain(), profile, planner_input) + prompt: Prompt = Prompt().build_prompt(user_prompt_model, system_prompt_model, + self.prompt_assemble_order) + process_llm_token(prompt.as_langchain(), profile, planner_input) + return prompt diff --git a/agentuniverse/agent/plan/planner/expressing_planner/expressing_planner.py b/agentuniverse/agent/plan/planner/expressing_planner/expressing_planner.py index 8611d4d4..eb2ffc44 100644 --- a/agentuniverse/agent/plan/planner/expressing_planner/expressing_planner.py +++ b/agentuniverse/agent/plan/planner/expressing_planner/expressing_planner.py @@ -9,7 +9,6 @@ from langchain.chains import LLMChain from langchain_core.memory import BaseMemory -from langchain_core.prompts import PromptTemplate from agentuniverse.agent.agent_model import AgentModel from agentuniverse.agent.input_object import InputObject @@ -38,22 +37,22 @@ def invoke(self, agent_model: AgentModel, planner_input: dict, input_object: Inp llm: LLM = self.handle_llm(agent_model) - self.handle_prompt(agent_model, planner_input) + prompt: Prompt = self.handle_prompt(agent_model, planner_input) llm_chain = LLMChain(llm=llm.as_langchain(), - prompt=self.prompt.as_langchain(), + prompt=prompt.as_langchain(), output_key=self.output_key, memory=memory) return asyncio.run(llm_chain.acall(inputs=planner_input)) - def handle_prompt(self, agent_model: AgentModel, planner_input: dict): + def handle_prompt(self, agent_model: AgentModel, planner_input: dict) -> Prompt: """Prompt module processing. Args: agent_model (AgentModel): Agent model object. planner_input (dict): Planner input object. Returns: - PromptTemplate: The prompt template. + Prompt: The prompt instance. """ expert_framework = planner_input.pop('expert_framework', '') or '' @@ -74,6 +73,7 @@ def handle_prompt(self, agent_model: AgentModel, planner_input: dict): target=prompt.target, instruction=expert_framework + prompt.instruction) - self.prompt.build_prompt(user_prompt_model, system_prompt_model, - self.prompt_assemble_order) - process_llm_token(self.prompt.as_langchain(), profile, planner_input) + prompt: Prompt = Prompt().build_prompt(user_prompt_model, system_prompt_model, + self.prompt_assemble_order) + process_llm_token(prompt.as_langchain(), profile, planner_input) + return prompt diff --git a/agentuniverse/agent/plan/planner/peer_planner/peer_planner.py b/agentuniverse/agent/plan/planner/peer_planner/peer_planner.py index ffeaad15..47f9c001 100644 --- a/agentuniverse/agent/plan/planner/peer_planner/peer_planner.py +++ b/agentuniverse/agent/plan/planner/peer_planner/peer_planner.py @@ -170,7 +170,7 @@ def agents_run(self, agents: dict, planner_config: dict, agent_input: dict, inpu # add reviewing agent log info logger_info = f"\nReviewing agent execution result is :\n" reviewing_info_str = f"review suggestion: {reviewing_result.get_data('suggestion')} \n" - reviewing_info_str += f"useful: {reviewing_result.get_data('is_useful')} \n" + reviewing_info_str += f"review score: {reviewing_result.get_data('score')} \n" LOGGER.info(logger_info + reviewing_info_str) if reviewing_result.get_data('score') and reviewing_result.get_data('score') >= eval_threshold: diff --git a/agentuniverse/agent/plan/planner/planner.py b/agentuniverse/agent/plan/planner/planner.py index 2f1784c1..62fe1ad8 100644 --- a/agentuniverse/agent/plan/planner/planner.py +++ b/agentuniverse/agent/plan/planner/planner.py @@ -5,12 +5,11 @@ # @Email : lc299034@antgroup.com # @FileName: planner.py """Base class for Planner.""" -import json +import copy from abc import abstractmethod from typing import Optional, List from langchain_core.memory import BaseMemory -from langchain_core.prompts import PromptTemplate from agentuniverse.agent.action.knowledge.knowledge import Knowledge from agentuniverse.agent.action.knowledge.knowledge_manager import KnowledgeManager @@ -42,7 +41,6 @@ class Planner(ComponentBase): output_key: str = 'output' input_key: str = 'input' prompt_assemble_order: list = ['introduction', 'target', 'instruction'] - prompt: Prompt = Prompt() def __init__(self): """Initialize the ComponentBase.""" @@ -87,8 +85,9 @@ def handle_memory(self, agent_model: AgentModel, planner_input: dict) -> BaseMem memory: Memory = MemoryManager().get_instance_obj(memory_name) if memory is None: return None - memory.set_by_agent_model(**params) - langchain_memory: BaseMemory = memory.as_langchain() + copied_memory = copy.deepcopy(memory) + copied_memory.set_by_agent_model(**params) + langchain_memory: BaseMemory = copied_memory.as_langchain() planner_input['chat_history'] = langchain_memory.load_memory_str return langchain_memory @@ -125,14 +124,14 @@ def handle_action(self, agent_model: AgentModel, planner_input: dict, input_obje planner_input['background'] = planner_input['background'] or '' + "\n".join(action_result) - def handle_prompt(self, agent_model: AgentModel, planner_input: dict): + def handle_prompt(self, agent_model: AgentModel, planner_input: dict) -> Prompt: """Prompt module processing. Args: agent_model (AgentModel): Agent model object. planner_input (dict): Planner input object. Returns: - PromptTemplate: The prompt template. + Prompt: The prompt instance. """ pass @@ -146,8 +145,9 @@ def handle_llm(self, agent_model: AgentModel) -> LLM: """ llm_name = agent_model.profile.get('llm_model').get('name') llm: LLM = LLMManager().get_instance_obj(llm_name) - llm.set_by_agent_model(**agent_model.profile.get('llm_model')) - return llm + copied_llm = copy.deepcopy(llm) + copied_llm.set_by_agent_model(**agent_model.profile.get('llm_model')) + return copied_llm def initialize_by_component_configer(self, component_configer: PlannerConfiger) -> 'Planner': """Initialize the planner by the PlannerConfiger object. diff --git a/agentuniverse/agent/plan/planner/planning_planner/planning_planner.py b/agentuniverse/agent/plan/planner/planning_planner/planning_planner.py index 220a1403..82f224bb 100644 --- a/agentuniverse/agent/plan/planner/planning_planner/planning_planner.py +++ b/agentuniverse/agent/plan/planner/planning_planner/planning_planner.py @@ -6,6 +6,7 @@ # @FileName: planning_planner.py """Planning planner module.""" import asyncio + from langchain.chains import LLMChain from langchain_core.memory import BaseMemory @@ -37,22 +38,22 @@ def invoke(self, agent_model: AgentModel, planner_input: dict, llm: LLM = self.handle_llm(agent_model) - self.handle_prompt(agent_model, planner_input) + prompt: Prompt = self.handle_prompt(agent_model, planner_input) llm_chain = LLMChain(llm=llm.as_langchain(), - prompt=self.prompt.as_langchain(), + prompt=prompt.as_langchain(), output_key=self.output_key, memory=memory) return asyncio.run(llm_chain.acall(planner_input)) - def handle_prompt(self, agent_model: AgentModel, planner_input: dict): + def handle_prompt(self, agent_model: AgentModel, planner_input: dict) -> Prompt: """Prompt module processing. Args: agent_model (AgentModel): Agent model object. planner_input (dict): Planner input object. Returns: - PromptTemplate: The prompt template. + Prompt: The prompt instance. """ expert_framework = planner_input.pop('expert_framework', '') or '' @@ -72,6 +73,7 @@ def handle_prompt(self, agent_model: AgentModel, planner_input: dict): system_prompt_model: AgentPromptModel = AgentPromptModel(introduction=prompt.introduction, target=prompt.target, instruction=expert_framework + prompt.instruction) - self.prompt.build_prompt(user_prompt_model, system_prompt_model, - self.prompt_assemble_order) - process_llm_token(self.prompt.as_langchain(), profile, planner_input) + prompt = Prompt().build_prompt(user_prompt_model, system_prompt_model, + self.prompt_assemble_order) + process_llm_token(prompt.as_langchain(), profile, planner_input) + return prompt diff --git a/agentuniverse/agent/plan/planner/rag_planner/rag_planner.py b/agentuniverse/agent/plan/planner/rag_planner/rag_planner.py index 3b5bdf2b..90032f55 100644 --- a/agentuniverse/agent/plan/planner/rag_planner/rag_planner.py +++ b/agentuniverse/agent/plan/planner/rag_planner/rag_planner.py @@ -6,8 +6,10 @@ # @FileName: rag_planner.py """Rag planner module.""" import asyncio + from langchain.chains import LLMChain from langchain_core.memory import BaseMemory + from agentuniverse.agent.agent_model import AgentModel from agentuniverse.agent.input_object import InputObject from agentuniverse.agent.plan.planner.planner import Planner @@ -38,21 +40,21 @@ def invoke(self, agent_model: AgentModel, planner_input: dict, llm: LLM = self.handle_llm(agent_model) - self.handle_prompt(agent_model, planner_input) + prompt: Prompt = self.handle_prompt(agent_model, planner_input) llm_chain = LLMChain(llm=llm.as_langchain(), - prompt=self.prompt.as_langchain(), + prompt=prompt.as_langchain(), output_key=self.output_key, memory=memory) return asyncio.run(llm_chain.acall(inputs=planner_input)) - def handle_prompt(self, agent_model: AgentModel, planner_input: dict): + def handle_prompt(self, agent_model: AgentModel, planner_input: dict) -> Prompt: """Prompt module processing. Args: agent_model (AgentModel): Agent model object. planner_input (dict): Planner input object. Returns: - PromptTemplate: The prompt template. + Prompt: The prompt instance. """ profile: dict = agent_model.profile @@ -68,6 +70,7 @@ def handle_prompt(self, agent_model: AgentModel, planner_input: dict): target=prompt.target, instruction=prompt.instruction) - self.prompt.build_prompt(user_prompt_model, system_prompt_model, - self.prompt_assemble_order) - process_llm_token(self.prompt.as_langchain(), profile, planner_input) + prompt = Prompt().build_prompt(user_prompt_model, system_prompt_model, + self.prompt_assemble_order) + process_llm_token(prompt.as_langchain(), profile, planner_input) + return prompt diff --git a/agentuniverse/agent/plan/planner/reviewing_planner/reviewing_planner.py b/agentuniverse/agent/plan/planner/reviewing_planner/reviewing_planner.py index c16bb617..c470b04d 100644 --- a/agentuniverse/agent/plan/planner/reviewing_planner/reviewing_planner.py +++ b/agentuniverse/agent/plan/planner/reviewing_planner/reviewing_planner.py @@ -6,9 +6,10 @@ # @FileName: reviewing_planner.py """Reviewing planner module.""" import asyncio + from langchain.chains import LLMChain from langchain_core.memory import BaseMemory -from langchain_core.prompts import PromptTemplate + from agentuniverse.agent.agent_model import AgentModel from agentuniverse.agent.input_object import InputObject from agentuniverse.agent.plan.planner.planner import Planner @@ -36,22 +37,22 @@ def invoke(self, agent_model: AgentModel, planner_input: dict, input_object: Inp llm: LLM = self.handle_llm(agent_model) - self.handle_prompt(agent_model, planner_input) + prompt: Prompt = self.handle_prompt(agent_model, planner_input) llm_chain = LLMChain(llm=llm.as_langchain(), - prompt=self.prompt.as_langchain(), + prompt=prompt.as_langchain(), output_key=self.output_key, memory=memory) return asyncio.run(llm_chain.acall(inputs=planner_input)) - def handle_prompt(self, agent_model: AgentModel, planner_input: dict): + def handle_prompt(self, agent_model: AgentModel, planner_input: dict) -> Prompt: """Generate prompt template for the planner. Args: agent_model (AgentModel): The agent model. planner_input (dict): The agent input. Returns: - PromptTemplate: The prompt template. + Prompt: The prompt instance. """ expert_framework = planner_input.pop('expert_framework', '') or '' @@ -72,6 +73,7 @@ def handle_prompt(self, agent_model: AgentModel, planner_input: dict): target=prompt.target, instruction=expert_framework + prompt.instruction) - self.prompt.build_prompt(user_prompt_model, system_prompt_model, - self.prompt_assemble_order) - process_llm_token(self.prompt.as_langchain(), profile, planner_input) + prompt: Prompt = Prompt().build_prompt(user_prompt_model, system_prompt_model, + self.prompt_assemble_order) + process_llm_token(prompt.as_langchain(), profile, planner_input) + return prompt diff --git a/agentuniverse/base/agentuniverse.py b/agentuniverse/base/agentuniverse.py index d12fe935..99177916 100644 --- a/agentuniverse/base/agentuniverse.py +++ b/agentuniverse/base/agentuniverse.py @@ -33,7 +33,11 @@ class AgentUniverse(object): def __init__(self): self.__application_container = ApplicationComponentManager() self.__config_container: ApplicationConfigManager = ApplicationConfigManager() - self.__system_default_package = ['agentuniverse'] + self.__system_default_agent_package = ['agentuniverse.agent.default'] + self.__system_default_llm_package = ['agentuniverse.llm.default'] + self.__system_default_planner_package = ['agentuniverse.agent.plan.planner'] + self.__system_default_memory_package = ['agentuniverse.agent.memory.default'] + self.__system_default_prompt_package = ['agentuniverse.agent', 'agentuniverse.base.prompt'] def start(self, config_path: str = None): """Start the agentUniverse framework.""" @@ -92,14 +96,19 @@ def __scan_and_register(self, app_configer: AppConfiger): Args: app_configer(AppConfiger): the AppConfiger object """ - core_agent_package_list = app_configer.core_agent_package_list or app_configer.core_default_package_list + self.__system_default_package - core_knowledge_package_list = app_configer.core_knowledge_package_list or app_configer.core_default_package_list + self.__system_default_package - core_llm_package_list = app_configer.core_llm_package_list or app_configer.core_default_package_list + self.__system_default_package - core_planner_package_list = app_configer.core_planner_package_list or app_configer.core_default_package_list + self.__system_default_package - core_tool_package_list = app_configer.core_tool_package_list or app_configer.core_default_package_list + self.__system_default_package - core_service_package_list = app_configer.core_service_package_list or app_configer.core_default_package_list + self.__system_default_package - core_memory_package_list = app_configer.core_memory_package_list or app_configer.core_default_package_list + self.__system_default_package - core_prompt_package_list = app_configer.core_prompt_package_list or app_configer.core_default_package_list + self.__system_default_package + core_agent_package_list = ((app_configer.core_agent_package_list or app_configer.core_default_package_list) + + self.__system_default_agent_package) + core_knowledge_package_list = app_configer.core_knowledge_package_list or app_configer.core_default_package_list + core_llm_package_list = ((app_configer.core_llm_package_list or app_configer.core_default_package_list) + + self.__system_default_llm_package) + core_planner_package_list = ((app_configer.core_planner_package_list or app_configer.core_default_package_list) + + self.__system_default_planner_package) + core_tool_package_list = app_configer.core_tool_package_list or app_configer.core_default_package_list + core_service_package_list = app_configer.core_service_package_list or app_configer.core_default_package_list + core_memory_package_list = ((app_configer.core_memory_package_list or app_configer.core_default_package_list) + + self.__system_default_memory_package) + core_prompt_package_list = ((app_configer.core_prompt_package_list or app_configer.core_default_package_list) + + self.__system_default_prompt_package) component_package_map = { ComponentEnum.AGENT: core_agent_package_list, diff --git a/agentuniverse/base/config/configer.py b/agentuniverse/base/config/configer.py index ed567c62..aef07b18 100644 --- a/agentuniverse/base/config/configer.py +++ b/agentuniverse/base/config/configer.py @@ -158,6 +158,6 @@ def __load_yaml_file(path: str) -> dict: Returns: dict: the value of the yaml file """ - with open(path, 'r') as stream: + with open(path, 'r', encoding='utf-8') as stream: config_data = yaml.safe_load(stream) return config_data diff --git a/agentuniverse/base/util/prompt_util.py b/agentuniverse/base/util/prompt_util.py index 26bad6b0..90a3e836 100644 --- a/agentuniverse/base/util/prompt_util.py +++ b/agentuniverse/base/util/prompt_util.py @@ -62,6 +62,9 @@ def split_text_on_tokens(text: str, text_token, chunk_size=800, chunk_overlap=10 result.append(chunk) current_position += chunk_char_size - chunk_char_overlap + if len(result) == 0: + result.append(text[current_position:]) + return result diff --git a/agentuniverse/llm/langchain_instance.py b/agentuniverse/llm/langchain_instance.py index a8f83901..736af0c4 100644 --- a/agentuniverse/llm/langchain_instance.py +++ b/agentuniverse/llm/langchain_instance.py @@ -29,13 +29,13 @@ def __init__(self, llm: LLM): llm (LLM): the AgentUniverse(AU) LLM instance. """ init_params = dict() - init_params['model_name'] = llm.model_name if llm.model_name is not None else 'gpt-3.5-turbo' - init_params['temperature'] = llm.temperature if llm.temperature is not None else 0.7 + init_params['model_name'] = llm.model_name if llm.model_name else 'gpt-3.5-turbo' + init_params['temperature'] = llm.temperature if llm.temperature else 0.7 init_params['request_timeout'] = llm.request_timeout init_params['max_tokens'] = llm.max_tokens - init_params['max_retries'] = llm.max_retries if llm.max_retries is not None else 2 - init_params['streaming'] = llm.streaming if llm.streaming is not None else False - init_params['openai_api_key'] = llm.openai_api_key + init_params['max_retries'] = llm.max_retries if llm.max_retries else 2 + init_params['streaming'] = llm.streaming if llm.streaming else False + init_params['openai_api_key'] = llm.openai_api_key if llm.openai_api_key else 'blank' init_params['openai_organization'] = llm.openai_organization init_params['openai_api_base'] = llm.openai_api_base init_params['openai_proxy'] = llm.openai_proxy diff --git a/agentuniverse/llm/openai_llm.py b/agentuniverse/llm/openai_llm.py index 719e4439..8c420548 100644 --- a/agentuniverse/llm/openai_llm.py +++ b/agentuniverse/llm/openai_llm.py @@ -26,12 +26,14 @@ "gpt-35-turbo": 4096, "gpt-35-turbo-16k": 16384, "gpt-3.5-turbo-1106": 16384, + "gpt-3.5-turbo-0125": 16384, "gpt-4-0314": 8192, "gpt-4": 8192, "gpt-4-32k": 32768, - "gpt-4-32k-0314": 32768, + "gpt-4-32k-0613": 32768, "gpt-4-0613": 8192, "gpt-4-1106-preview": 128000, + "gpt-4-turbo": 128000, } diff --git a/agentuniverse/prompt/prompt.py b/agentuniverse/prompt/prompt.py index 104dd03b..aa387284 100644 --- a/agentuniverse/prompt/prompt.py +++ b/agentuniverse/prompt/prompt.py @@ -37,7 +37,7 @@ def as_langchain(self) -> PromptTemplate: input_variables=self.input_variables) def build_prompt(self, user_agent_prompt_model: AgentPromptModel, system_agent_prompt_model: AgentPromptModel, - prompt_assemble_order: list[str]): + prompt_assemble_order: list[str]) -> 'Prompt': """Build the prompt class. Args: @@ -51,6 +51,7 @@ def build_prompt(self, user_agent_prompt_model: AgentPromptModel, system_agent_p agent_prompt_model = user_agent_prompt_model + system_agent_prompt_model self.prompt_template = generate_template(agent_prompt_model, prompt_assemble_order) self.input_variables = re.findall(r'\{(.*?)}', self.prompt_template) + return self def get_instance_code(self) -> str: """Return the prompt version of the current prompt.""" diff --git a/docs/guidebook/_picture/dingtalk_util20250429.png b/docs/guidebook/_picture/dingtalk_util20250429.png new file mode 100644 index 00000000..ff8f4b18 Binary files /dev/null and b/docs/guidebook/_picture/dingtalk_util20250429.png differ diff --git a/docs/guidebook/_picture/logo_bar.jpg b/docs/guidebook/_picture/logo_bar.jpg new file mode 100644 index 00000000..c1fd7028 Binary files /dev/null and b/docs/guidebook/_picture/logo_bar.jpg differ diff --git a/docs/guidebook/_picture/logo_bar.png b/docs/guidebook/_picture/logo_bar.png deleted file mode 100644 index 3d43b9d7..00000000 Binary files a/docs/guidebook/_picture/logo_bar.png and /dev/null differ diff --git a/docs/guidebook/en/0_index.md b/docs/guidebook/en/0_index.md index 0016f4fd..f053e534 100644 --- a/docs/guidebook/en/0_index.md +++ b/docs/guidebook/en/0_index.md @@ -6,12 +6,13 @@ * 1.1 [Introduction](1_1_Introduction.md) * 1.2 [Installation](1_2_Installation.md) * 1.3 [Quick Start](1_3_Quick_Start.md) +* 1.4 [ApplicationStructure](1_4_Application_Engineering_Structure_Explanation.md) **2. Principle Introduction** **3. Component Reference Manual** -**4. API Reference Manual** +**[4. API Reference Manual](4_1_API_Reference.md)** **5. Best Practices** @@ -19,4 +20,4 @@ **7. Frequently Asked Questions (FAQ)** -**8. Contact Us** +**[8. Contact Us](8_1_Contact_Us.md)** diff --git a/docs/guidebook/en/1_1_Introduction.md b/docs/guidebook/en/1_1_Introduction.md index 22d0715c..9943e90b 100644 --- a/docs/guidebook/en/1_1_Introduction.md +++ b/docs/guidebook/en/1_1_Introduction.md @@ -11,4 +11,15 @@ This pattern utilizes four distinct agent roles: Plan, Execute, Express, and Rev - DOE pattern: This pattern consists of three agents: Data-fining agent, which is designed to solve data-intensive and high-computational-precision task; Opinion-inject agent, which combines the data results from first agent and the expert opinions which are pre-collected and structured; the third agent, Express agent generates the final result base on given document type and language style. -More patterns are coming soon... \ No newline at end of file +More patterns are coming soon... + +![](../_picture/agent_universe_framework_resize.jpg) + +In addition to rich collaboration modes, agentUniverse also includes the following main features: + +* **Fast and Simple Development Experience**: Through configuration and simple interfaces, you can quickly complete single-agent construction, multi-agent collaboration process definition, and service-based applications with this framework. +* **Rich Components and Custom Extensions**: The framework provides a wide variety of common domain components (LLM, knowledge, tools, memory, collaboration patterns, etc.) and technical components (DB, RPC, Message, etc.) with default implementations. It offers extension standards for all types of components, allowing you to customize any part to enhance your agent capabilities. +* **Prompt-Friendly and Management**: The framework has built-in a complete set of prompt management mechanisms. You can manage prompts in multiple versions, switch between them, and specialize them based on expert domain knowledge. + +## Acknowledgments +This project is partially based on open-source projects like langchain, pydantic, gunicorn, flask, SQLAlchemy, chromadb, etc. (A detailed dependency list can be found in requirements.txt). Special thanks to the related projects and associated parties. \ No newline at end of file diff --git a/docs/guidebook/en/1_4_Application_Engineering_Structure_Explanation.md b/docs/guidebook/en/1_4_Application_Engineering_Structure_Explanation.md new file mode 100644 index 00000000..6c1884d1 --- /dev/null +++ b/docs/guidebook/en/1_4_Application_Engineering_Structure_Explanation.md @@ -0,0 +1,99 @@ +# Application Engineering Structure and Explanation +As you can see, `agentUniverse` is designed with lightness and integrative capabilities in mind, allowing you to incorporate `agentUniverse` into any of your projects for seamless operation. + +## Recommended Project Directory Structure and Explanation +The directory structure provided below is only a suggestion, and you are free to adjust it according to your preferences and actual situation. We will explain this in more detail later in the document. + +``` +/ +├── app/ +│ ├── biz/ +│ ├── bootstarp/ +│ │ └── server_application.py +│ ├── core/ +│ │ ├── agent +│ │ ├── knowledge +│ │ ├── llm +│ │ ├── memory +│ │ ├── planner +│ │ ├── service +│ │ └── tool +│ ├── test/ +│ └── web/ +├── config +├── pyproject.toml +└── other project files... +``` + +The specific meanings of each package directory level are as follows: +* app - The main application program code + * biz - Your business code, where you can organize the next level of the directory structure as you wish + * bootstrap - The entry layer for starting the web server, for starting details refer to server_application.py + * core - The core layer of LLM agent application components + * agent - Place the agents you build + * knowledge - The knowledge you customize and use + * llm - The LLM (Language Model) you customize and use + * memory - The memory you customize and use + * planner - The collaborative mode you customize and use + * service - Service registration directory + * tool - The tools you customize and use + * test - Directory for tests + * web - The upper web layer, currently left blank +* config - Application configuration code + +## Using Any Project Directory Structure +You can adjust the project directory structure according to your preferences and actual circumstances, but please be sure to follow the rules below. + +### Bootstrap Startup Directory {#bootstrap-startup-directory} +Regardless of the location of your project's startup script, except for testing, please ensure that the application service is started with the following statement: + +```python +from agentuniverse.agent_serve.web.web_booster import start_web_server +from agentuniverse.base.agentuniverse import AgentUniverse + + +class ServerApplication: + """ + Server application. + """ + + @classmethod + def start(cls): + AgentUniverse().start() + start_web_server() + +ServerApplication.start() + +``` +`ServerApplication.start()` is the server startup method for this framework, which accepts a configuration path `config_path` as an input parameter. The default `config_path` is a file located at `project_root_dir/config/config.toml` under the config directory in the project root path. Please ensure that the config file path is correct. If you've further changed the directory of the config file, please adjust the `config_path` accordingly. + +### Config Directory +As mentioned in the [Bootstrap Startup Directory](#bootstrap-startup-directory), the default config path for the project is `project_root_dir/config/config.toml`. If you have made any adjustments to this, please ensure that the correct config file path is passed to the startup method when the application server is launched. + +### Core Directory +As demonstrated by the recommended directory structure for the project, the project directory within the core directory is mainly used for placing custom domain components such as agents, knowledge, LLM, and others. You are free to position all core components wherever you like and not limited to the same main package. You only need to define it in the `[CORE_PACKAGE]` section of the main configuration file `config/config.toml` of the project, as follows: + +```toml +[CORE_PACKAGE] +# Perform a full component scan and registration for all the paths under this list. +default = ['sample_standard_app.app.core'] +# Scan and register agent components for all paths under this list, with priority over the default. +agent = ['sample_standard_app.app.core.agent'] +# Scan and register agent components for all paths under this list, with priority over the default. +knowledge = ['sample_standard_app.app.core.knowledge'] +# Scan and register knowledge components for all paths under this list, with priority over the default. +llm = ['sample_standard_app.app.core.llm'] +# Scan and register llm components for all paths under this list, with priority over the default. +planner = ['sample_standard_app.app.core.planner'] +# Scan and register planner components for all paths under this list, with priority over the default. +tool = ['sample_standard_app.app.core.tool'] +# Scan and register memory components for all paths under this list, with priority over the default. +memory = ['sample_standard_app.app.core.memory'] +# Scan and register service components for all paths under this list, with priority over the default. +service = ['sample_standard_app.app.core.service'] +# Scan and register prompt components for all paths under this list, with priority over the default. +prompt = [] +``` +The format for defining packages follows the standard Python package path format. The framework will register, scan, and manage all types of component packages uniformly based on the defined package paths during startup. + +**Tips**: The package path starts one level below your project's root directory. For example, in the sample_standard_app example, since the package path is under the agentUniverse level, it starts with sample_standard_app. If you are using sample_standard_app as a project template, then the path should start with app.xxx. \ No newline at end of file diff --git a/docs/guidebook/en/4_1_API_Reference.md b/docs/guidebook/en/4_1_API_Reference.md new file mode 100644 index 00000000..21279e6c --- /dev/null +++ b/docs/guidebook/en/4_1_API_Reference.md @@ -0,0 +1,2 @@ +# API Reference +[readthedocs](https://agentuniverse.readthedocs.io/en/latest/) diff --git a/docs/guidebook/en/8_1_Contact_Us.md b/docs/guidebook/en/8_1_Contact_Us.md new file mode 100644 index 00000000..c5a3cf33 --- /dev/null +++ b/docs/guidebook/en/8_1_Contact_Us.md @@ -0,0 +1,9 @@ +# Contact Us +* github: https://github.com/alipay/agentUniverse +* gitee: https://gitee.com/agentUniverse/agentUniverse +* gitcode: https://gitcode.com/agentUniverse +* Stack Overflow: https://stackoverflowteams.com/c/agentuniverse/questions +* Discord: https://discord.gg/VfhEvJzQ +* WeChat Official Account: agentUniverse智多星 +* DingTalk Group: +![](../_picture/dingtalk_util20250429.png) \ No newline at end of file diff --git "a/docs/guidebook/zh/0_\347\233\256\345\275\225.md" "b/docs/guidebook/zh/0_\347\233\256\345\275\225.md" index f6a41fe9..33523c3c 100644 --- "a/docs/guidebook/zh/0_\347\233\256\345\275\225.md" +++ "b/docs/guidebook/zh/0_\347\233\256\345\275\225.md" @@ -10,11 +10,13 @@ * 1.3 [快速开始](1_3_快速开始.md) +* 1.4 [应用结构说明](1_4_应用工程结构及说明.md) + **2.原理介绍** **3.组件参考手册** -**4.API参考手册** +**[4.API参考手册](4_1_API参考.md)** **5.最佳实践** @@ -22,4 +24,4 @@ **7.常见问题FAQ** -**8.联系我们** +**[8.联系我们](8_1_联系我们.md)** diff --git "a/docs/guidebook/zh/1_1_\347\256\200\344\273\213.md" "b/docs/guidebook/zh/1_1_\347\256\200\344\273\213.md" index 740d9af6..c8bc66ee 100644 --- "a/docs/guidebook/zh/1_1_\347\256\200\344\273\213.md" +++ "b/docs/guidebook/zh/1_1_\347\256\200\344\273\213.md" @@ -11,4 +11,15 @@ - DOE 模式组件: 该pattern通过数据精制(Data-fining)、观点注入(Opinion-inject)、表达(Express)三个智能体,实现对数据密集、高计算精度、融合专家观点的生成任务的效果提升。典型适用场景:财报生成 -更多模式组件持续推出中... \ No newline at end of file +更多模式组件持续推出中... + +![](../_picture/agent_universe_framework_resize.jpg) + +除了丰富的协作模式外agentUniverse还包含如下主要特性: + +* **快速简单的研发体验**: 通过配置化与简单的接口实现,您可以基于本框架快速完成单智能体搭建、多智能体协同过程定义与服务化; +* **丰富的组件与扩展定制**: 框架提供了大量常见的领域组件(LLM、知识、工具、记忆、协同模式等组件)与技术组件(DB、RPC、Message等组件)的默认实现;提供了基于所有组件类型的扩展标准,您可以对任何部分进行定制并用来强化您的agent能力; +* **prompt友好与管理**:框架内置了一整套prompt管理机制,您可以对于prompt进行多版本管理、切换与专家经验领域prompt化。 + +## 鸣谢 +本项目部分基于langchain、pydantic、gunicorn、flask、SQLAlchemy、chromadb等开源项目(详细依赖列表可见requirements.txt)实现,在此特别感想相关项目与关联方。 \ No newline at end of file diff --git "a/docs/guidebook/zh/1_3_\345\277\253\351\200\237\345\274\200\345\247\213.md" "b/docs/guidebook/zh/1_3_\345\277\253\351\200\237\345\274\200\345\247\213.md" index 8a342de6..c77191c0 100644 --- "a/docs/guidebook/zh/1_3_\345\277\253\351\200\237\345\274\200\345\247\213.md" +++ "b/docs/guidebook/zh/1_3_\345\277\253\351\200\237\345\274\200\345\247\213.md" @@ -1,5 +1,5 @@ # 快速开始 -我们将向您展示如何: +在本部分我们将向您展示如何: * 进行环境与应用工程准备 * 构建一个简单的agent * 使用模式组件完成多agent协同 @@ -48,7 +48,7 @@ custom_key_path = './custom_key.toml' #### 私有配置文件 -在使用过程中,您可能需要一些私有配置,比如密钥等。我们建议您将这些私有配置保存在一个独立的文件中,比如`custom_key.toml`。您可以在`config.toml`的`custom_key_path`中配置这个文件的路径,`custom_key_path`路径中的私有配置文件会自动注册到系统的环境变量中,您可以在后续代码中通过`Config`操作器或通过系统变量来读取这些私有配置。 +在使用过程中,您可能需要一些私有配置,比如密钥等。我们建议您将这些私有配置保存在一个独立的文件中,比如`custom_key.toml`。您可以在`config.toml`的`custom_key_path`中配置这个文件的路径,`custom_key_path`路径中的私有配置文件会自动注册到系统的环境变量中,您可以在后续代码中通过`Config`操作器或通过系统变量来读取这些私有配置。 下面是一个`custom_key.toml`的示例: ```toml @@ -112,7 +112,7 @@ class DemoRagAgent(Agent): 更多的agent开发细节请参考后续的agent开发章节。 ## 使用模式组件完成多agent协同 -planner决定了agent在协作模式中的作用。在`xx_agent_case_a.yaml`中,我们定义了一个`rag_planner`的配置, 其决定了`XXagent`会采用RAG的方式进行工作; 在复杂的工作场景中,我们往往需要多个agent协同工作。我们可以通过配置多个agent来实现这一目的。 +planner决定了agent在协作模式中的作用。在`xx_agent_case_a.yaml`中,我们定义了一个`rag_planner`的配置,其决定了`XXagent`会采用RAG的方式进行工作;在复杂的工作场景中,我们往往需要多个agent协同工作。我们可以通过配置多个agent来实现这一目的。 例如PEER模式就是一个典型的协同模式,它可以让多个agent同时工作,互相协作,共同完成一个任务,接下来我们将创建一个PEER模式的agent配置。 @@ -139,7 +139,7 @@ metadata: 在`xx_agent_case_b.yaml`中,我们定义了一个`DemoPeerAgent`的配置。`info`部分是agent的基本信息设置,`plan`部分包含了agent的行为规划设置(决定了agent的工作模式),`metadata`部分包含了agent对象的元数据设置。 -其中`plan`部分的`planner`字段定义了一个`peer_planner`的配置,其中`planning`、`executing`、`expressing`和`reviewing`字段分别定义了PEER的四个环节的agent配置。您可以继续创建每个环节对应的子agent,每个子agent的配置又可以采用不同的agent pattern模式。 +其中`plan`部分的`planner`字段定义了一个`peer_planner`的配置,其中`planning`、`executing`、`expressing`和`reviewing`字段分别定义了PEER的四个环节的agent配置。您可以继续创建每个环节对应的子agent,每个子agent的配置又可以采用不同的agent pattern模式。 ### 更多细节 更多的agent pattern开发细节请参考后续的agent pattern章节。 @@ -226,4 +226,4 @@ curl http://127.0.0.1:8000/service_run -X POST --header "Content-Type: applicati 进一步运用框架提供端到端方案与产品; 进一步阅读框架在当前在各个产业场景的最佳实践。 -让我们共同探索, 共同进步! \ No newline at end of file +让我们共同探索,共同进步! \ No newline at end of file diff --git "a/docs/guidebook/zh/1_4_\345\272\224\347\224\250\345\267\245\347\250\213\347\273\223\346\236\204\345\217\212\350\257\264\346\230\216.md" "b/docs/guidebook/zh/1_4_\345\272\224\347\224\250\345\267\245\347\250\213\347\273\223\346\236\204\345\217\212\350\257\264\346\230\216.md" new file mode 100644 index 00000000..106ce0f0 --- /dev/null +++ "b/docs/guidebook/zh/1_4_\345\272\224\347\224\250\345\267\245\347\250\213\347\273\223\346\236\204\345\217\212\350\257\264\346\230\216.md" @@ -0,0 +1,98 @@ +# 应用工程结构及说明 +如你所见,`agentUniverse`在设计时具备轻量与融合能力,您可以通过引入`agentUniverse`至您的任何工程中进行工作。 + +## 推荐工程目录结构及说明 +下列目录结构仅作为推荐结构,您可以根据您的喜好与实际情况进行调整我们将在后文中说明。 + +``` +/ +├── app/ +│ ├── biz/ +│ ├── bootstarp/ +│ │ └── server_application.py +│ ├── core/ +│ │ ├── agent +│ │ ├── knowledge +│ │ ├── llm +│ │ ├── memory +│ │ ├── planner +│ │ ├── service +│ │ └── tool +│ ├── test/ +│ └── web/ +├── config +├── pyproject.toml +└── other project files... +``` + +每个层级包目录具体含义如下: +* app - 应用主要程序代码 + * biz - 您的业务代码,您可以任意组织下一级的目录结构 + * bootstarp - webserve启动入口曾,启动详情可参考server_application.py + * core - 核心的LLM agent应用组件层 + * agent - 放置您搭建的agent + * knowledge - 您自定义使用的knowledge + * llm - 您自定义使用的llm + * memory - 您自定义使用的memory + * planner - 您自定义使用的协作模式 + * service - 服务注册目录 + * tool - 您自定义使用的tool + * test - 测试目录 + * web - 更上层的web层,当前留白 +* config - 应用配置代码 + +## 使用任意工程目录结构 +您可以将工程目录按照根据您的喜好与实际情况进行调整,但请务必遵循以下的规则。 + +### bootstarp启动目录 {#bootstarp启动目录} +无论您的项目启动脚本在何位置,除测试外请保证应用服务使用如下语句进行服务启动: + +```python +from agentuniverse.agent_serve.web.web_booster import start_web_server +from agentuniverse.base.agentuniverse import AgentUniverse + + +class ServerApplication: + """ + Server application. + """ + + @classmethod + def start(cls): + AgentUniverse().start() + start_web_server() + +ServerApplication.start() + +``` +`ServerApplication.start()`为本框架的serve启动方法,其会接收项目配置路径`config_path`作为入参,`config_path`默认路径为项目根路径下的config目录中的文件 `project_root_dir/config/config.toml`,请确保config文件路径正确,如果您进一步变更了config文件的目录,请将`config_path`作为调整; + +### config目录 +如 [bootstarp启动目录](#bootstarp启动目录)部分所述,项目的默认config路径为`project_root_dir/config/config.toml`,若您对其进行了调整,请确保在应用serve启动时将正确的config文件路径传入启动方法。 + +### core目录 +如推荐目录结构工程所示,core目录中的工程目录主要用于放置agent、knowledge、LLM等自定义的领域组件,您可以随意所有核心组件的位置并且不局限于同一主包下,只需要在项目工程的主配置文件`config/config.toml`中的`[CORE_PACKAGE]`部分进行定义即可,如下: +```toml +[CORE_PACKAGE] +# Perform a full component scan and registration for all the paths under this list. +default = ['sample_standard_app.app.core'] +# Scan and register agent components for all paths under this list, with priority over the default. +agent = ['sample_standard_app.app.core.agent'] +# Scan and register agent components for all paths under this list, with priority over the default. +knowledge = ['sample_standard_app.app.core.knowledge'] +# Scan and register knowledge components for all paths under this list, with priority over the default. +llm = ['sample_standard_app.app.core.llm'] +# Scan and register llm components for all paths under this list, with priority over the default. +planner = ['sample_standard_app.app.core.planner'] +# Scan and register planner components for all paths under this list, with priority over the default. +tool = ['sample_standard_app.app.core.tool'] +# Scan and register memory components for all paths under this list, with priority over the default. +memory = ['sample_standard_app.app.core.memory'] +# Scan and register service components for all paths under this list, with priority over the default. +service = ['sample_standard_app.app.core.service'] +# Scan and register prompt components for all paths under this list, with priority over the default. +prompt = [] +``` +包定义的格式遵从标准的python包路径格式,框架在启动时会根据定义的各类组件package路径进行注册扫描与统一管理。 + +**Tips**: package路径以您的项目根目录下一级开始,如sample_standard_app示例中的package路径由于在agentUniverse层级下,所以由sample_standard_app开始, 若您以sample_standard_app为项目模版则路径应以app.xxx 开头。 \ No newline at end of file diff --git "a/docs/guidebook/zh/4_1_API\345\217\202\350\200\203.md" "b/docs/guidebook/zh/4_1_API\345\217\202\350\200\203.md" new file mode 100644 index 00000000..1e8be0f6 --- /dev/null +++ "b/docs/guidebook/zh/4_1_API\345\217\202\350\200\203.md" @@ -0,0 +1,2 @@ +# API参考 +[readthedocs](https://agentuniverse.readthedocs.io/en/latest/) \ No newline at end of file diff --git "a/docs/guidebook/zh/8_1_\350\201\224\347\263\273\346\210\221\344\273\254.md" "b/docs/guidebook/zh/8_1_\350\201\224\347\263\273\346\210\221\344\273\254.md" new file mode 100644 index 00000000..86c11e9d --- /dev/null +++ "b/docs/guidebook/zh/8_1_\350\201\224\347\263\273\346\210\221\344\273\254.md" @@ -0,0 +1,9 @@ +# 联系我们 +* github: https://github.com/alipay/agentUniverse +* gitee: https://gitee.com/agentUniverse/agentUniverse +* gitcode: https://gitcode.com/agentUniverse +* Stack Overflow: https://stackoverflowteams.com/c/agentuniverse/questions +* Discord: https://discord.gg/VfhEvJzQ +* 微信公众号: agentUniverse智多星 +* 钉钉交流群: +![](../_picture/dingtalk_util20250429.png) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index dc9bc36b..161be8ef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "agentUniverse" -version = "0.0.3" +version = "0.0.4" description = "agentUniverse is a framework for developing applications powered by multi-agent base on large language model." authors = ["AntGroup "] readme = "README.md" diff --git a/sample_standard_app/app/core/agent/peer_agent_case/demo_executing_agent.yaml b/sample_standard_app/app/core/agent/peer_agent_case/demo_executing_agent.yaml index 5d74b052..46185a5f 100644 --- a/sample_standard_app/app/core/agent/peer_agent_case/demo_executing_agent.yaml +++ b/sample_standard_app/app/core/agent/peer_agent_case/demo_executing_agent.yaml @@ -2,37 +2,35 @@ info: name: 'demo_executing_agent' description: 'demo executing agent' profile: - instruction: ' -你需要根据我提供的背景知识结合你自己拥有的知识,来回答我的问题。 -你的回答需要尽可能的详细、全面,包含足够多的数据信息。 --------------------------------------------------------------- -需要遵守下面的规则: -1.去除重复的信息。 -2.去除对回答问题没有帮助的信息。 -3.去除错误的信息。 -4.只可以使用这些信息来回答问题。 -5.简明扼要,重点突出,不过多花哨词藻。 -6.不在多处讲到同一个细节点,一个点只出现一次。 -7.尽量多的使用数值类信息。 -8.不可以出现XXX、ABC等不明确的词语。 - -之前的对话: -{chat_history} - -背景信息是: -{background} - -开始! -我的问题是: {input} - --------------------------------------------------------------- -必须使用中文进行详细的回答。你需要聚焦在我的问题上,不要延伸这个问题。 -让我们一步一步来。 -' + prompt_version: executing_planner.default_cn + instruction: | + 结合提供的背景信息和你所拥有的知识回答用户问题,确保回答详细、全面并包含足够的数据信息。针对用户的问题,进行深入分析并提供详尽的解答。 + -------------------------------------------------------------- + 需要遵守下面的规则: + 1.去除重复的信息。 + 2.去除对回答问题没有帮助的信息。 + 3.去除错误的信息。 + 4.详尽回答问题,重点突出,不过多花哨词藻。 + 5.不在多处讲到同一个细节点,一个点只出现一次。 + 6.尽量多的使用数值类信息。 + 7.需要高度注意信息的时效性 + 8.不可以出现XXX、ABC等不明确的词语。 + + 之前的对话: + {chat_history} + + 背景信息是: + {background} + + 开始! + 我的问题是: {input} + + -------------------------------------------------------------- + 必须使用中文进行详细的回答。你需要聚焦在我的问题上,不要延伸这个问题,让我们一步一步来。 llm_model: name: 'demo_llm' - model_name: 'gpt-4' - temperature: 0.5 + model_name: 'gpt-4-turbo' + temperature: 0.4 plan: planner: name: 'executing_planner' @@ -40,9 +38,9 @@ memory: name: '' action: knowledge: - - 'demo_knowledge' + - '' tool: - - 'demo_tool' + - 'google_search_tool' metadata: type: 'AGENT' module: 'agentuniverse.agent.default.executing_agent' diff --git a/sample_standard_app/app/core/agent/peer_agent_case/demo_expressing_agent.yaml b/sample_standard_app/app/core/agent/peer_agent_case/demo_expressing_agent.yaml index 7f382143..701292c8 100644 --- a/sample_standard_app/app/core/agent/peer_agent_case/demo_expressing_agent.yaml +++ b/sample_standard_app/app/core/agent/peer_agent_case/demo_expressing_agent.yaml @@ -2,32 +2,31 @@ info: name: 'demo_expressing_agent' description: 'demo expressing agent' profile: - instruction: ' -从不同角度、有条理的回答用户的问题。 -使用提供的知识结合你自己拥有的知识,专业、详细的回答用户的问题。 - -回答问题需要遵守下面的规则: -- 回答必须是分-总结构,第一段分论点,进行专业、有结构性、通顺流畅的阐述论点。基于上述几个维度,基于能够获取到的客观信息展开详细论述,同时内容上要避免重复,同时更加强调时效性,表达的内容语义连贯。第二段总论点,总结陈述,这里需要提炼要点,做到重点突出,专业、有结构性、通顺流畅的阐述总论点,直接了当回答问题。 -- 可以使用知识中的数值和数据,作为分论点的论据支撑。 -- 不描述重复的信息、不做对问题没有帮助的回答、不说模糊的推测、不可以出现XXX、ABC等不明确的词语。 -- 整体回答结果没有重复信息,必要时可以通过空行提升阅读体验。 -- 回答的答案需要详细 - -之前的对话: -{chat_history} - -背景信息是: -{background} - -开始! -需要回答的问题是: {input} --------------------------------------------------------------- -请根据规则要求做出回答。 -' + prompt_version: expressing_planner.default_cn + target: 你的任务是根据背景信息提供的q&a信息结合你自身的知识,对用户提出的具体问题,生成一个完整的结构化问题答案。 + instruction: | + 回答问题需要遵守下面的规则: + - 理解和分析背景信息中的q&a信息,结合你自身的知识,确保提供完整、结构化的答案,答案准确、清晰、易于理解。 + - 回答问题内容详细,同时避免重复语句、需要高度注意信息的时效性。 + - 结构化答案生成:回答分为两大段,必须是总-分结构。 + - 第一大段总结陈述,这里需要提炼要点,做到重点突出,专业、有结构性、通顺流畅的阐述总论点,直接了当回答问题。 + - 第二大段详细的论点阐述。基于背景信息中的q&a信息,结合你自身的知识,展开详细论述,表达的内容语义连贯。可以使用知识中的数值和数据,作为分论点的论据支撑,必要时通过空行提升阅读体验。 + - 不做对问题没有帮助的回答、不可以出现XXX、ABC等不明确的词语。 + - 整体回答结果没有重复信息,必要时可以通过空行提升阅读体验。 + + 背景信息是: + {background} + + 开始! + 需要回答的问题是: {input} + -------------------------------------------------------------- + 请根据规则要求做出回答。 llm_model: - name: 'demo_llm' - model_name: 'gpt-4' - temperature: 0.5 + name: demo_llm + model_name: gpt-4-turbo + temperature: 0.2 + prompt_processor: + type: stuff plan: planner: name: 'expressing_planner' diff --git a/sample_standard_app/app/core/agent/peer_agent_case/demo_peer_agent.py b/sample_standard_app/app/core/agent/peer_agent_case/demo_peer_agent.py deleted file mode 100644 index 5b471a0c..00000000 --- a/sample_standard_app/app/core/agent/peer_agent_case/demo_peer_agent.py +++ /dev/null @@ -1,25 +0,0 @@ -# !/usr/bin/env python3 -# -*- coding:utf-8 -*- -# @Time : 2024/3/20 10:54 -# @Author : heji -# @Email : lc299034@antgroup.com -# @FileName: demo_peer_agent.py -from datetime import datetime - -from agentuniverse.agent.agent import Agent -from agentuniverse.agent.input_object import InputObject - - -class DemoPeerAgent(Agent): - def input_keys(self) -> list[str]: - return ['input'] - - def output_keys(self) -> list[str]: - return ['output'] - - def parse_input(self, input_object: InputObject, planner_input: dict) -> dict: - planner_input['input'] = input_object.get_data('input') - return planner_input - - def parse_result(self, planner_result: dict) -> dict: - return {"output": planner_result.get('result')[0].get('expressing_result').get_data('output')} diff --git a/sample_standard_app/app/core/agent/peer_agent_case/demo_peer_agent.yaml b/sample_standard_app/app/core/agent/peer_agent_case/demo_peer_agent.yaml index d2cd32c9..71c94677 100644 --- a/sample_standard_app/app/core/agent/peer_agent_case/demo_peer_agent.yaml +++ b/sample_standard_app/app/core/agent/peer_agent_case/demo_peer_agent.yaml @@ -12,5 +12,5 @@ plan: reviewing: 'demo_reviewing_agent' metadata: type: 'AGENT' - module: 'sample_standard_app.app.core.agent.peer_agent_case.demo_peer_agent' - class: 'DemoPeerAgent' \ No newline at end of file + module: 'agentuniverse.agent.default.peer_agent' + class: 'PeerAgent' \ No newline at end of file diff --git a/sample_standard_app/app/core/agent/peer_agent_case/demo_planning_agent.yaml b/sample_standard_app/app/core/agent/peer_agent_case/demo_planning_agent.yaml index 79177191..86446dd2 100644 --- a/sample_standard_app/app/core/agent/peer_agent_case/demo_planning_agent.yaml +++ b/sample_standard_app/app/core/agent/peer_agent_case/demo_planning_agent.yaml @@ -2,11 +2,36 @@ info: name: 'demo_planning_agent' description: 'demo planning agent' profile: - target: '你的目标是对需要回答的问题进行拆解,生成5-10个子问题,要求每个子问题独立可被解答,包含完整的主体、客体信息。' + prompt_version: planning_planner.default_cn + target: | + 你的目标是针对用户提出的问题,进行拆解并生成3-5个子问题。 + instruction: | + 根据需要回答的问题,给出一个逻辑递进的思考链路,帮助用户逐渐掌握知识并最终回答问题。 + 思考链路以子问题的形式体现,每个子问题都是一个完整的句子,能够独立通过比如google搜索信息并做出解答。 + + 要求如下: + 1. 思考链路必须严格遵循需要回答的问题,不可以延伸问题,也不可以直接回答问题。 + 2. 这个思考链路的每一步必须是简单、单一的。 + 3. 每一步的问题必须是有答案的,不能是开放性的问题。 + 4. 每一步的问题必须是完整的句子,不能有任何歧义。 + 5. 子问题不要出现英文标点符号或中文标点符号 + + 开始! + 注意:生成的子问题避免使用模糊的主语,比如拆解后的子问题为"这份报告有哪些要点?",根本不清楚这份报告到底是什么。每个子问题应包含明确的主体和客体信息,以便通过搜索引擎搜索出关键信息并作出回答。 + + 输出必须是按照以下格式化的Json代码片段,thought字段代表拆解问题的思考过程,framework字段代表拆解后的子问题列表。 + {{ + "thought": string, + "framework": list + }} + + 必须使用中文回答用户提出的问题。 + + 需要回答的问题是: {input} llm_model: name: 'demo_llm' - model_name: 'gpt-4' - temperature: 0.7 + model_name: 'gpt-4-turbo' + temperature: 0.5 plan: planner: name: 'planning_planner' diff --git a/sample_standard_app/app/core/agent/peer_agent_case/demo_reviewing_agent.yaml b/sample_standard_app/app/core/agent/peer_agent_case/demo_reviewing_agent.yaml index b55a78a0..0daff7a7 100644 --- a/sample_standard_app/app/core/agent/peer_agent_case/demo_reviewing_agent.yaml +++ b/sample_standard_app/app/core/agent/peer_agent_case/demo_reviewing_agent.yaml @@ -4,7 +4,7 @@ info: profile: llm_model: name: 'demo_llm' - model_name: 'gpt-3.5-turbo' + model_name: 'gpt-3.5-turbo-0125' temperature: 0.5 plan: planner: diff --git a/sample_standard_app/app/core/agent/rag_agent_case/demo_rag_agent.yaml b/sample_standard_app/app/core/agent/rag_agent_case/demo_rag_agent.yaml index 2d15a9fc..64b332ea 100644 --- a/sample_standard_app/app/core/agent/rag_agent_case/demo_rag_agent.yaml +++ b/sample_standard_app/app/core/agent/rag_agent_case/demo_rag_agent.yaml @@ -2,15 +2,31 @@ info: name: 'demo_rag_agent' description: 'demo rag agent' profile: + prompt_version: 'rag_planner.default_cn' + instruction: | + 你需要遵守的规则是: + 1. 必须使用中文结合查询的背景信息结合你所拥有的知识回答用户提出的问题。 + 2. 不采用背景信息中的错误信息。 + 3. 要考虑答案和问题的相关性,不做对问题没有帮助的回答。 + 4. 详尽回答问题,重点突出,不过多花哨词藻。 + 5. 不说模糊的推测。 + 6. 尽量多的使用数值类信息。 + + 背景信息是: + {background} + + 开始! + + 需要回答的问题是: {input} llm_model: - name: 'default_openai_llm' - model_name: 'gpt-4' + name: 'demo_llm' + model_name: 'gpt-4-turbo' plan: planner: name: 'rag_planner' action: tool: - - 'demo_tool' + - 'google_search_tool' metadata: type: 'AGENT' module: 'sample_standard_app.app.core.agent.rag_agent_case.demo_rag_agent' diff --git a/sample_standard_app/app/core/knowledge/demo_knowledge.py b/sample_standard_app/app/core/knowledge/demo_knowledge.py index a48a1f3e..592b9ec1 100644 --- a/sample_standard_app/app/core/knowledge/demo_knowledge.py +++ b/sample_standard_app/app/core/knowledge/demo_knowledge.py @@ -43,7 +43,7 @@ def __init__(self, **kwargs): embedding_model_name='text-embedding-3-small'), dimensions=1056) self.reader = WebPdfReader() # initialize the knowledge - self.insert_knowledge() + # self.insert_knowledge() def insert_knowledge(self, **kwargs) -> None: """Insert the knowledge into the knowledge store. diff --git a/sample_standard_app/app/core/llm/demo_llm.yaml b/sample_standard_app/app/core/llm/demo_llm.yaml index 52a936c7..919ccb1f 100644 --- a/sample_standard_app/app/core/llm/demo_llm.yaml +++ b/sample_standard_app/app/core/llm/demo_llm.yaml @@ -1,7 +1,7 @@ name: 'demo_llm' description: 'demo openai' model_name: 'gpt-3.5-turbo' -max_tokens: 3000 +max_tokens: 1000 max_retries: 2 metadata: type: 'LLM' diff --git a/sample_standard_app/app/core/tool/demo_tool.py b/sample_standard_app/app/core/tool/demo_tool.py deleted file mode 100644 index 4cace8b3..00000000 --- a/sample_standard_app/app/core/tool/demo_tool.py +++ /dev/null @@ -1,25 +0,0 @@ -# !/usr/bin/env python3 -# -*- coding:utf-8 -*- - -# @Time : 2024/3/31 11:00 -# @Author : wangchongshi -# @Email : wangchongshi.wcs@antgroup.com -# @FileName: demo_tool.py -from langchain_community.utilities.google_serper import GoogleSerperAPIWrapper -from agentuniverse.agent.action.tool.tool import Tool, ToolInput - - -class DemoTool(Tool): - """The demo tool. - - Implement the execute method of demo tool, using the `GoogleSerperAPIWrapper` to implement a simple Google search. - - Note: - You need to sign up for a free account at https://serper.dev and get the serpher api key (2500 free queries). - """ - - def execute(self, tool_input: ToolInput): - query = tool_input.get_data("input") - # get top3 results from Google search. - search = GoogleSerperAPIWrapper(k=3, type="search") - return search.run(query=query) diff --git a/sample_standard_app/app/core/tool/demo_tool.yaml b/sample_standard_app/app/core/tool/demo_tool.yaml deleted file mode 100644 index 691db39e..00000000 --- a/sample_standard_app/app/core/tool/demo_tool.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: 'demo_tool' -description: 'demo tool' -tool_type: 'api' -input_keys: ['input'] -metadata: - type: 'TOOL' - module: 'sample_standard_app.app.core.tool.demo_tool' - class: 'DemoTool' \ No newline at end of file diff --git a/sample_standard_app/app/core/tool/google_search_tool.py b/sample_standard_app/app/core/tool/google_search_tool.py new file mode 100644 index 00000000..50b14d7e --- /dev/null +++ b/sample_standard_app/app/core/tool/google_search_tool.py @@ -0,0 +1,34 @@ +# !/usr/bin/env python3 +# -*- coding:utf-8 -*- +# @Time : 2024/3/31 11:00 +# @Author : wangchongshi +# @Email : wangchongshi.wcs@antgroup.com +# @FileName: google_search_tool.py +from typing import Optional + +from pydantic import Field +from langchain_community.utilities.google_serper import GoogleSerperAPIWrapper +from agentuniverse.agent.action.tool.tool import Tool, ToolInput +from agentuniverse.base.util.env_util import get_from_env + +from sample_standard_app.app.core.tool.mock_search_tool import MockSearchTool + + +class GoogleSearchTool(Tool): + """The demo google search tool. + + Implement the execute method of demo google search tool, using the `GoogleSerperAPIWrapper` to implement a simple Google search. + + Note: + You need to sign up for a free account at https://serper.dev and get the serpher api key (2500 free queries). + """ + + serper_api_key: Optional[str] = Field(default_factory=lambda: get_from_env("SERPER_API_KEY")) + + def execute(self, tool_input: ToolInput): + if self.serper_api_key is None: + return MockSearchTool().execute(tool_input) + query = tool_input.get_data("input") + # get top10 results from Google search. + search = GoogleSerperAPIWrapper(serper_api_key=self.serper_api_key, k=10, gl="us", hl="en", type="search") + return search.run(query=query) diff --git a/sample_standard_app/app/core/tool/google_search_tool.yaml b/sample_standard_app/app/core/tool/google_search_tool.yaml new file mode 100644 index 00000000..93ca5659 --- /dev/null +++ b/sample_standard_app/app/core/tool/google_search_tool.yaml @@ -0,0 +1,8 @@ +name: 'google_search_tool' +description: 'demo google search tool' +tool_type: 'api' +input_keys: ['input'] +metadata: + type: 'TOOL' + module: 'sample_standard_app.app.core.tool.google_search_tool' + class: 'GoogleSearchTool' \ No newline at end of file diff --git a/sample_standard_app/app/core/tool/mock_search_tool.py b/sample_standard_app/app/core/tool/mock_search_tool.py new file mode 100644 index 00000000..ebd78516 --- /dev/null +++ b/sample_standard_app/app/core/tool/mock_search_tool.py @@ -0,0 +1,45 @@ +# !/usr/bin/env python3 +# -*- coding:utf-8 -*- +# @Time : 2024/4/15 13:50 +# @Author : wangchongshi +# @Email : wangchongshi.wcs@antgroup.com +# @FileName: mock_search_tool.py +from agentuniverse.agent.action.tool.tool import Tool, ToolInput + +MOCK_SEARCH_RESULT = """ +巴菲特旗下的伯克希尔·哈撒韦公司自2022年8月24日首次减持比亚迪股票以来,已经披露了13次减持行为,包括2022年9月1日、11月1日、11月8日、11月17日、12月8日、2023年1月3日、1月27日、2月9日、3月31日、5月2日等时间点。 +最近的一次减持是在2023年10月25日,当时伯克希尔·哈撒韦公司出售82.05万比亚迪H股,使其持股比例降至7.98%。 +这次减持的平均价格为每股245.86港元,但整体来看,比亚迪的股价并未受到太大影响。 + +巴菲特的投资策略包括: +1. 长期投资:巴菲特主张买入并持有优质股票,而非短期交易。他的投资策略往往以做多绩优股为主,不排除出现长期慢牛的可能。 +2. 价值投资:巴菲特注重企业的内在价值,而不是短期的股价波动。他会深入研究公司的基本面,包括其盈利能力、市场地位、管理层质量等。 +3. 能力圈原则:巴菲特建议投资者只投资于自己理解的领域,即自己的“能力圈”内。这样可以更好地评估企业的真实价值和未来前景。 +巴菲特的减持并不会改变比亚迪公司优质的基本面,比亚迪依然是中国新能源汽车行业的龙头。 + +放眼中国新能源产业版图,比亚迪绝对是举足轻重的一员。比亚迪在新能源汽车领域形成了上中下游全产业链的完整布局,从电池原材料到新能源汽车三电系统,再到动力电池回收利用,各板块协同效应显著: +1. 在中游零部件领域,公司自产自研汽车核心零部件以及三电系统,在动力电池、发动机、变速箱等关键部件上均实现自主生产,2020年3月成立的弗迪公司,进一步加快了新能源汽车核心零部件的对外销售; +2. 在下游整车领域,公司具备完成的整车制造及研发体系,在不同价格区间陆续推出多款不同车型,丰富的产品类型拉动终端需求,销量在国内自主品牌中常年稳居首位。 + +巴菲特最近的一次减持是在2023年10月25日,10月30日晚,比亚迪披露了一份亮眼的三季报。三季报显示比亚迪前三季度实现营业收入4222.75亿元,同比增长58%,实现净利润213.67亿元,同比增长130%,业绩保持高速增长态势;其中,第三季度营收1621.51亿元,同比增长38.49%;净利润104.13亿元,平均每天挣1.13亿元。 +截至10月31日,比亚迪H股报收237.4港元/股,A股报收238.54元/股,合计总市值约6568亿元。 + +尽管减持比亚迪股票,巴菲特与搭档查理芒格在2023年对比亚迪仍有极高评价,芒格2023年演讲也提及比亚迪是至今最爱的股票,且相较于美国特斯拉 (TSLA-US) 更看好比亚迪发展。巴菲特对比亚迪这家公司,对王传福这个创业者始终表现出了充分的尊重。2008年以后每年的股东大会上,巴菲特一直都为比亚迪站台。 +早在2008年9月,巴菲特就发现了新能源汽车的市场潜力,并与比亚迪签署协议,以每股港元8元的价格认购2.25亿股比亚迪的股份,约占其配售后10%的股份比例,总金额约为18亿港元,就此开启了“股神”长达14年的持股之旅。 +时至今日,比亚迪的股价早已今非昔比,按照8月30日比亚迪收盘的263港元/股计,即便不算分红,巴菲特所持比亚迪股票总体增值约31倍,价值近600亿港币,这一投资收益已足够令所有人称赞和羡慕。 +""" + + +class MockSearchTool(Tool): + """The mock search tool. + + In this tool, we mocked the search engine's answers to search for information about BYD and Warren Buffett. + + Note: + The tool is only suitable for users searching for Buffett or BYD related queries. + We recommend that you configure your `SERPER_API_KEY` and use google_search_tool to get information. + """ + + def execute(self, tool_input: ToolInput): + """Demonstrates the execute method of the Tool class.""" + return MOCK_SEARCH_RESULT diff --git a/sample_standard_app/app/core/tool/mock_search_tool.yaml b/sample_standard_app/app/core/tool/mock_search_tool.yaml new file mode 100644 index 00000000..8b0f4a9b --- /dev/null +++ b/sample_standard_app/app/core/tool/mock_search_tool.yaml @@ -0,0 +1,8 @@ +name: 'mock_search_tool' +description: 'mock search tool' +tool_type: 'api' +input_keys: ['input'] +metadata: + type: 'TOOL' + module: 'sample_standard_app.app.core.tool.mock_search_tool' + class: 'MockSearchTool' \ No newline at end of file diff --git a/sample_standard_app/app/test/test_executing_agent.py b/sample_standard_app/app/test/test_executing_agent.py new file mode 100644 index 00000000..11fa01af --- /dev/null +++ b/sample_standard_app/app/test/test_executing_agent.py @@ -0,0 +1,56 @@ +# !/usr/bin/env python3 +# -*- coding:utf-8 -*- +# @Time : 2024/4/15 11:02 +# @Author : wangchongshi +# @Email : wangchongshi.wcs@antgroup.com +# @FileName: test_executing_agent.py +import unittest + +from agentuniverse.agent.agent import Agent +from agentuniverse.agent.agent_manager import AgentManager +from agentuniverse.agent.input_object import InputObject +from agentuniverse.agent.output_object import OutputObject +from agentuniverse.base.agentuniverse import AgentUniverse + + +class ExecutingAgentTest(unittest.TestCase): + """Test cases for the executing agent""" + + def setUp(self) -> None: + AgentUniverse().start(config_path='../../config/config.toml') + + def test_executing_agent(self): + """Test demo executing agent. + + In the normal process, we need to generate the framework through the planning agent. + After that, the information is collected through the executing agent. + In the current demo test method, we mock the framework result generated by the planning Agent. + + Note: + This agent uses `google_search_tool`, which is a simple Google search. + You need to sign up for a free account at https://serper.dev + and get the serpher api key (2500 free queries). + """ + + instance: Agent = AgentManager().get_instance_obj('demo_executing_agent') + + # mock the planning agent result, which is a framework of mind solving the final problem. + framework = ["巴菲特减持比亚迪的具体情况是什么?包括减持的时间和数量。", + "巴菲特减持比亚迪前后的市场环境是怎么样的?", + "巴菲特的投资策略是什么?是否可能影响其决定减持比亚迪?", + "比亚迪在巴菲特减持前后的业绩表现如何?", + "巴菲特减持比亚迪对比亚迪的影响有哪些?比如可能的股价变动、投资者信心等。"] + planning_result = InputObject({'framework': framework}) + + output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因', + planning_result=planning_result) + executing_result = output_object.get_data('executing_result') + res_info = f"\nExecuting agent execution result is :\n" + for index, one_exec_res in enumerate(executing_result): + res_info += f"[{index + 1}] input: {one_exec_res.get('input')}\n" + res_info += f"[{index + 1}] output: {one_exec_res.get('output')}\n" + print(res_info) + + +if __name__ == '__main__': + unittest.main() diff --git a/sample_standard_app/app/test/test_expressing_agent.py b/sample_standard_app/app/test/test_expressing_agent.py new file mode 100644 index 00000000..f5f4d69a --- /dev/null +++ b/sample_standard_app/app/test/test_expressing_agent.py @@ -0,0 +1,94 @@ +# !/usr/bin/env python3 +# -*- coding:utf-8 -*- + +# @Time : 2024/4/16 20:30 +# @Author : wangchongshi +# @Email : wangchongshi.wcs@antgroup.com +# @FileName: test_expressing_agent.py +import unittest + +from agentuniverse.agent.agent import Agent +from agentuniverse.agent.agent_manager import AgentManager +from agentuniverse.agent.input_object import InputObject +from agentuniverse.agent.output_object import OutputObject +from agentuniverse.base.agentuniverse import AgentUniverse + + +class ExpressingAgentTest(unittest.TestCase): + """Test cases for the expressing agent""" + + def setUp(self) -> None: + AgentUniverse().start(config_path='../../config/config.toml') + + def test_expressing_agent(self): + """Test demo expressing agent. + + In the normal process, we need to generate answers to the framework questions through the executing agent. + After that, aggregate information through the expressing agent to generate a complete answer. + In the current demo test method, we mock answers generated by the executing Agent. + """ + + instance: Agent = AgentManager().get_instance_obj('demo_expressing_agent') + + output1 = """ + 巴菲特通过其公司伯克希尔·哈撒韦自2022年开始减持比亚迪股份,具体情况如下: + + 1. 2022年8月24日:伯克希尔·哈撒韦减持了133.10万股比亚迪H股,减持的均价为277.10港元,此次减持后,持股数量降至2.18719亿股。 + + 2. 2023年3月31日:伯克希尔·哈撒韦再次减持,此次为248.05万股比亚迪H股,减持的均价为217.67港元。 + + 这两次减持是巴菲特对比亚迪股份的主要减持行动,显示了他在持有比亚迪14年后开始逐步减少持股的策略。尽管巴菲特的减持行为引起市场关注,但似乎并未对比亚迪的股价产生长期负面影响。 + """ + + output2 = """ + 巴菲特减持比亚迪的市场环境可以从以下几个方面进行详细分析: + + 1. 全球新能源汽车市场的增长:在巴菲特减持比亚迪的背景下,全球新能源汽车市场持续增长。新能源汽车因其环保特性在全球范围内受到推崇,尤其是在中国,政府对新能源汽车的支持政策不断,市场需求强劲。 + + 2. 中国数字经济的发展:2022年,中国数字经济规模达到50.2万亿元,占国内生产总值的比重提升至41.5%。数字经济的快速发展为新能源汽车行业,包括比亚迪在内的企业提供了强大的技术支持和市场环境。 + + 3. 比亚迪的股价和市场表现:尽管巴菲特的减持行为引发了市场的关注和短期波动,比亚迪的股价在7月12日确实出现了下跌,但从长期来看, + 比亚迪的股价并未因此受到严重影响。事实上,巴菲特此次减持的均价是近7次披露中的最高价格,显示出其对比亚迪长期价值的认可。 + + 4. 巴菲特减持的原因及其影响:巴菲特减持比亚迪的主要原因是为了更好的资金配置,而非对比亚迪前景的不看好。 + 伯克希尔首席执行官沃伦·巴菲特明确表示,比亚迪是一家“卓越的公司”,并且在减持后,巴菲特依然保留了近10%的仓位在比亚迪。 + + 综上所述,巴菲特减持比亚迪的市场环境是在全球新能源汽车市场的持续增长、中国数字经济的快速发展背景下进行的。 + 尽管市场对此有短暂的反应,但从长远看,比亚迪的市场表现和公司前景依然被看好。巴菲特的减持更多是基于资金配置的考虑,而非对比亚迪业务的负面评价。 + """ + + output3 = """ + 沃伦·巴菲特的投资策略以价值投资为核心,这种策略强调寻找那些价格低于其内在价值的股票,并持有这些股票直到市场价格反映出其真实价值。巴菲特在选择投资标的时,会重点考虑公司的财务健康状况、长期增长潜力、管理层质量以及市场定位等因素。他倾向于投资那些具有清晰业务模式和持续盈利能力的公司。 + + 关于巴菲特减持比亚迪的股份,这一行为可能受到多种因素的影响,其中包括但不限于比亚迪的市场估值、公司的业务发展以及整体市场环境的变化。巴菲特始终强调投资决策应基于公司的基本面分析,而非市场短期波动。因此,如果他认为比亚迪的市场估值超过了其内在价值,或者相比其他投资机会,比亚迪的吸引力减弱,这可能促使他减持持股。 + + 综合来看,巴菲特的价值投资策略和对投资标的持续评估是影响其决定是否减持比亚迪股份的重要因素。 + """ + + output4 = """ + 巴菲特减持比亚迪的行为对比亚迪有以下几方面的影响: + + 1. 股价变动:巴菲特的减持行为可能短期内对比亚迪的股价造成压力。由于巴菲特被视为价值投资的典范,他的投资决策往往被市场解读为对被投资公司价值的一种评估。 + 因此,他减持比亚迪的行为可能被市场解读为对比亚迪未来增长潜力的质疑,从而引发股价短期内的下跌。然而,具体的股价走势还需要结合公司的基本面和市场整体状况来综合判断。 + + 2. 投资者信心:巴菲特的减持可能会影响到部分投资者对比亚迪的信心。尤其是那些高度依赖于知名投资者行为的跟风投资者,他们可能会因为担心比亚迪的长期增长潜力而选择跟随减持。 + 然而,对于那些更加关注公司基本面的投资者而言,只要比亚迪能够持续展现出良好的业绩和增长前景,他们的信心可能不会因此受到太大影响。 + + 综上所述,巴菲特减持比亚迪的行为对比亚迪股价和投资者信心都有一定影响,具体影响的程度和持续时间还需要根据市场的反应和比亚迪的业绩表现来进一步观察。 + """ + + # mock the executing agent results + executing_list = [{'input': '巴菲特减持比亚迪的具体情况是什么?包括减持的时间和数量。', 'output': output1}, + {'input': '巴菲特减持比亚迪前后的市场环境是怎么样的?', 'output': output2}, + {'input': '巴菲特的投资策略是什么?是否可能影响其决定减持比亚迪?', 'output': output3}, + {'input': '巴菲特减持比亚迪对比亚迪的影响有哪些?比如可能的股价变动、投资者信心等。', 'output': output4}] + executing_result = InputObject({'executing_result': executing_list}) + output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因', + executing_result=executing_result) + res_info = f"\nExpressing agent execution result is :\n" + res_info += f"{output_object.get_data('output')}" + print(res_info) + + +if __name__ == '__main__': + unittest.main() diff --git a/sample_standard_app/app/test/test_peer_agent.py b/sample_standard_app/app/test/test_peer_agent.py new file mode 100644 index 00000000..2d9e2923 --- /dev/null +++ b/sample_standard_app/app/test/test_peer_agent.py @@ -0,0 +1,31 @@ +# !/usr/bin/env python3 +# -*- coding:utf-8 -*- +# @Time : 2024/4/15 11:19 +# @Author : wangchongshi +# @Email : wangchongshi.wcs@antgroup.com +# @FileName: test_peer_agent.py +import unittest + +from agentuniverse.agent.agent import Agent +from agentuniverse.agent.agent_manager import AgentManager +from agentuniverse.base.agentuniverse import AgentUniverse + + +class PeerAgentTest(unittest.TestCase): + """Test cases for the peer agent""" + + def setUp(self) -> None: + AgentUniverse().start(config_path='../../config/config.toml') + + def test_peer_agent(self): + """Test demo peer agent. + + The overall process of peer agents (demo_planning_agent/demo_executing_agent/demo_expressing_agent/demo_reviewing_agent). + """ + + instance: Agent = AgentManager().get_instance_obj('demo_peer_agent') + instance.run(input='请帮我分析下2023年巴菲特减持比亚迪的原因') + + +if __name__ == '__main__': + unittest.main() diff --git a/sample_standard_app/app/test/test_peer_agents.py b/sample_standard_app/app/test/test_peer_agents.py deleted file mode 100644 index 62ad4ac8..00000000 --- a/sample_standard_app/app/test/test_peer_agents.py +++ /dev/null @@ -1,112 +0,0 @@ -# !/usr/bin/env python3 -# -*- coding:utf-8 -*- - -# @Time : 2024/3/28 17:44 -# @Author : wangchongshi -# @Email : wangchongshi.wcs@antgroup.com -# @FileName: test_peer_agent.py -import unittest - -from agentuniverse.agent.agent import Agent -from agentuniverse.agent.agent_manager import AgentManager -from agentuniverse.agent.input_object import InputObject -from agentuniverse.agent.output_object import OutputObject -from agentuniverse.base.agentuniverse import AgentUniverse - - -class PeerAgentTest(unittest.TestCase): - """ - Test cases for the overall process of peer agents - """ - - def setUp(self) -> None: - AgentUniverse().start(config_path='../../config/config.toml') - - def test_planning_agent(self): - """Test demo planning agent.""" - instance: Agent = AgentManager().get_instance_obj('demo_planning_agent') - output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因') - print(output_object.get_data('output')) - - def test_executing_agent(self): - """Test demo executing agent. - - Note: - This agent uses `demo_tool`, which is a simple Google search. - You need to sign up for a free account at https://serper.dev - and get the serpher api key (2500 free queries). - """ - instance: Agent = AgentManager().get_instance_obj('demo_executing_agent') - # demo planning agent result, which is a framework of mind solving the final problem. - framework = ["巴菲特减持比亚迪的具体情况是什么?包括减持的时间和数量。", - "巴菲特减持比亚迪前后的市场环境是怎么样的?", - "巴菲特的投资策略是什么?是否可能影响其决定减持比亚迪?", - "比亚迪在巴菲特减持前后的业绩表现如何?", - "当时的市场走势是怎样的?是否可能影响巴菲特的决定?", - "巴菲特减持比亚迪对比亚迪的影响有哪些?比如可能的股价变动、投资者信心等。", - "巴菲特减持比亚迪对相关市场有哪些影响?"] - planning_result = InputObject({'framework': framework}) - output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因', - planning_result=planning_result) - print(output_object.get_data('executing_result')) - - def test_expressing_agent(self): - """Test demo expressing agent.""" - instance: Agent = AgentManager().get_instance_obj('demo_expressing_agent') - - # demo executing agent result - executing_list = [{'input': '巴菲特减持比亚迪的具体情况是什么?包括减持的时间和数量。', - 'output': '巴菲特通过其旗下的伯克希尔·哈撒韦公司,自2022年8月24日开始,对比亚迪H股进行了多次减持。具体来说,这是他们第12次披露减持比亚迪的消息。在最近一次的减持中,伯克希尔·哈撒韦的持股比例从9.21%降至8.98%,平均减持价格为每股266.85港元,总共套现约6.76亿港元。尽管巴菲特的减持速度和力度都有加快的趋势,但整体来看,比亚迪的股价并未受到太大影响。实际上,这一次披露的减持均价,是近7次披露中的最高价格。'}, - {'input': '巴菲特减持比亚迪前后的市场环境是怎么样的?', - 'output': '巴菲特减持比亚迪的市场环境主要可以从以下几个方面来分析:\n\n首先,巴菲特减持比亚迪的消息在资本市场上引起了广泛的关注,这一事件被视为新能源赛道的重要风向标。如果市场能够澄清相关的传闻,那么这无疑将对新能源赛道的持续看好产生积极影响。反之,如果确认巴菲特大举减持,可能会对新能源赛道的前景产生一定的影响。\n\n其次,巴菲特的投资策略一直是市场关注的焦点。他的投资策略主要是基于公司的运营结果,而非短期的股市波动。因此,巴菲特减持比亚迪可能是他对比亚迪的运营状况或者新能源行业的前景产生了新的认识。\n\n再次,巴菲特减持比亚迪的消息发布之后,可能会引发市场的情绪波动。根据巴菲特的"市场先生"寓言,市场的短期走势往往受到投资者情绪的影响,而长期价值则取决于公司的经济进步。因此,巴菲特减持比亚迪可能会引发市场的短期情绪波动,但长期来看,比亚迪的股价还是会回归其经济价值。\n\n最后,巴菲特减持比亚迪的行为可能会影响其他投资者的决策。因为巴菲特的投资决策往往会被市场视为重要的参考,他的减持行为可能会引发其他投资者的跟风行为,从而影响比亚迪的股价。\n\n总结来说,巴菲特减持比亚迪的市场环境是复杂的,它受到市场对新能源赛道的看好、巴菲特的投资策略、市场情绪波动以及其他投资者行为的影响。'}, - {'input': '巴菲特的投资策略是什么?是否可能影响其决定减持比亚迪?', - 'output': '巴菲特的投资策略主要是价值投资,以长期持有为主,并且他非常注重企业的内在价值和市场价格。他会对他感兴趣并且理解的企业进行深入研究,变成该领域的专家,并且他会和企业管理层进行合作,而不是对抗。他的投资策略主要包含以下几个方面:\n\n1. 不跟随股市的日常波动。他认为市场只是为了方便买卖,而不是设定价值。\n2. 不尝试分析或担忧整体经济。如果你不能预测股市的日常波动,那么你如何可靠地预测经济的命运?\n3. 购买一家企业,而不仅仅是它的股票。他会把购买股票当作是购买整个企业,他会根据以下几个方面来评估企业:企业是否简单并且从投资者的角度来看是否可理解?企业是否有一致的运营历史?企业是否有良好的长期前景?管理层是否理性?管理层是否对股东坦诚?关注企业的回报率,而不是每股收益。寻找利润率高的公司。对于每一美元的留存收益,公司是否创造了至少一美元的额外市场价值?\n4. 管理一组企业。聪明的投资意味着具有商业所有者的优先级(专注于长期价值)而不是股票交易员(专注于短期的收益和损失)。\n\n对于巴菲特是否会继续减持比亚迪股份,我们可以结合他的投资策略来分析。首先,巴菲特是一个长期投资者,他不会因为短期的市场波动而轻易改变他的持股策略。其次,他非常注重企业的内在价值,如果他认为比亚迪的内在价值依然存在,那么他可能会继续持有。但是,如果他认为比亚迪的内在价值已经不再,或者市场价格已经远超过了他认为的合理价值,那么他可能会选择减持。'}, - {'input': '比亚迪在巴菲特减持前后的业绩表现如何?', - 'output': '比亚迪在巴菲特减持前后的业绩表现均表现出色。在巴菲特减持的同时,比亚迪的业绩表现仍然非常突出。在新能源汽车领域,比亚迪已经明显领先于对手。其前三季度的营业收入达到了2676.88亿元,同比增长了84.37%,这主要是因为新能源汽车业务的增长。\n\n此外,比亚迪在10月30日晚公布的三季报中显示,其前三季度实现营业收入4222.75亿元,同比增长58%,实现净利润213.67亿元,同比增长130%,业绩保持高速增长态势。这些数据显示,即使在巴菲特减持的情况下,比亚迪的业绩仍然在稳步增长,这也是多个证券机构对比亚迪持续保持买入评级的重要原因。'}, - {'input': '当时的市场走势是怎样的?是否可能影响巴菲特的决定?', - 'output': '根据提供的信息,没有直接描述当时的市场走势是怎样的,也没有明确指出市场走势是否影响了巴菲特的决定。但从巴菲特的投资策略来看,他的决策更多地是基于对公司的长期价值评估,而不是短期的市场波动。他的投资哲学是,长期来看,股票的价值最终将反映出公司的经济表现,而不是日常市场波动。\n\n巴菲特的策略是,即使股票价值下跌50%或更多,也要保持冷静,因为这是增加投资组合份额的好机会,只要投资的公司基本面健康,管理良好,价格合理,市场最终会认可其成功。\n\n因此,从这个角度看,即使市场走势对巴菲特的决策有影响,也只是在他评估公司价值的基础上,作为买入或持有股票的时机考虑,而不会改变他的基本投资策略。'}, - {'input': '巴菲特减持比亚迪对比亚迪的影响有哪些?比如可能的股价变动、投资者信心等。', - 'output': '巴菲特减持比亚迪的行为可能对比亚迪产生以下几方面的影响:\n\n1. 股价变动:巴菲特减持比亚迪可能会引发市场对比亚迪股价的质疑,导致股价下跌。因为巴菲特的投资决策通常被市场视为信号,他的减持行为可能被解读为对比亚迪未来盈利能力的不确定性。\n\n2. 投资者信心:巴菲特减持比亚迪可能会影响投资者对比亚迪的信心。巴菲特是一位著名的价值投资者,他的投资决策通常会影响其他投资者的决策。如果他减持比亚迪,可能会引发其他投资者对比亚迪未来的担忧,进而影响他们的投资决策。\n\n3. 公司声誉:巴菲特减持比亚迪可能会对比亚迪的声誉造成一定影响。因为巴菲特是一位世界级的投资大师,他的投资决策通常会被媒体广泛报道,这可能会引起公众对比亚迪的关注,进而影响比亚迪的声誉。\n\n4. 公司经营:巴菲特减持比亚迪可能会对比亚迪的经营产生影响。如果市场对比亚迪的信心下降,可能会影响比亚迪的融资能力,进而影响其经营。\n\n总的来说,巴菲特减持比亚迪可能会对比亚迪的股价、投资者信心、公司声誉和经营产生影响。然而,这些影响的具体程度会受到许多因素的影响,包括巴菲特减持的比例、市场对比亚迪的其他信息的反应等。'}, - {'input': '巴菲特减持比亚迪对相关市场有哪些影响?', - 'output': '巴菲特减持比亚迪的决定对相关市场可能产生以下影响:\n\n1. 投资者心理影响:巴菲特是世界知名的投资大师,他的投资决策往往会对市场产生影响。他首次减持比亚迪,可能会在持有新能源汽车股票的投资者心理上产生影响,引发部分投资者对新能源汽车市场的担忧和不确定性。\n\n2. 股价波动:巴菲特减持比亚迪的消息可能会导致比亚迪的股价出现波动。一方面,这可能是因为市场对比亚迪的前景产生了疑虑;另一方面,可能是因为一些投资者在跟风巴菲特的决策,选择减持比亚迪股票。\n\n3. 市场信心下滑:由于比亚迪是新能源汽车市场的重要参与者,因此巴菲特减持比亚迪可能会导致市场对新能源汽车市场的信心下滑,影响新能源汽车市场的整体发展。\n\n4. 投资主线调整:巴菲特减持比亚迪可能会引发投资者对新能源汽车投资主线的重新思考。投资者可能会重新评估新能源汽车市场的前景,并据此调整自己的投资策略。\n\n需要注意的是,这些影响可能会受到许多因素的影响,包括比亚迪的业绩、市场环境、投资者心理等。因此,投资者需要根据自己的判断和风险承受能力来做出投资决策。'}] - - executing_result = InputObject({'executing_result': executing_list}) - - output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因', - executing_result=executing_result) - print(output_object.get_data('output')) - - def test_reviewing_agent(self): - """Test demo reviewing agent.""" - instance: Agent = AgentManager().get_instance_obj('demo_reviewing_agent') - - # demo expressing agent result - expressing_output = """ - 分析巴菲特减持比亚迪的原因,我们可以从以下几个角度进行解读: - - 首先,从投资策略的角度来看,巴菲特一直以来的投资原则是“买入并持有”,而非频繁交易。他的投资决策通常基于对公司运营状况的长期观察和判断。因此,巴菲特减持比亚迪可能是他对比亚迪的未来发展或者新能源行业的前景有了新的认识。这可能是由于比亚迪的业务表现、市场竞争环境、政策风险等因素的变化,使得巴菲特对比亚迪的价值预期发生了调整。 - - 其次,从资本运作的角度来看,巴菲特减持比亚迪也可能是出于资本运作的需要。巴菲特的伯克希尔·哈撒韦公司是一个多元化的投资集团,需要对各个投资项目进行合理的资金配置。因此,巴菲特可能是在进行资产配置的调整,以适应市场环境的变化,或者获取更高的投资回报。 - - 再次,从市场环境的角度来看,近年来,新能源汽车行业的竞争日益激烈,各大汽车厂商纷纷投入新能源汽车的研发和生产。在这种情况下,巴菲特可能认为比亚迪在未来的市场竞争中面临的压力和挑战增大,因此选择了减持。 - - 总的来说,巴菲特减持比亚迪的原因可能是多方面的,包括他对比亚迪及新能源行业未来发展的认识变化,资本运作的需要,以及市场环境的变化等。这些因素的综合作用可能导致了巴菲特对比亚迪的投资策略进行了调整。 - """ - expressing_result = InputObject({'output': expressing_output}) - - output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因', - expressing_result=expressing_result) - print(output_object.get_data('output')) - - def test_peer_agent(self): - """Test demo peer agent. - - The overall process of peer agents (demo_planning_agent/demo_executing_agent/demo_expressing_agent/demo_reviewing_agent). - """ - instance: Agent = AgentManager().get_instance_obj('demo_peer_agent') - output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因') - print(output_object.get_data('output')) - - -if __name__ == '__main__': - pass diff --git a/sample_standard_app/app/test/test_planning_agent.py b/sample_standard_app/app/test/test_planning_agent.py new file mode 100644 index 00000000..8fbcc73f --- /dev/null +++ b/sample_standard_app/app/test/test_planning_agent.py @@ -0,0 +1,33 @@ +# !/usr/bin/env python3 +# -*- coding:utf-8 -*- +# @Time : 2024/4/15 11:01 +# @Author : wangchongshi +# @Email : wangchongshi.wcs@antgroup.com +# @FileName: test_planning_agent.py +import unittest + +from agentuniverse.agent.agent import Agent +from agentuniverse.agent.agent_manager import AgentManager +from agentuniverse.agent.output_object import OutputObject +from agentuniverse.base.agentuniverse import AgentUniverse + + +class PlanningAgentTest(unittest.TestCase): + """Test cases for the planning agent""" + + def setUp(self) -> None: + AgentUniverse().start(config_path='../../config/config.toml') + + def test_planning_agent(self): + """Test demo planning agent.""" + + instance: Agent = AgentManager().get_instance_obj('demo_planning_agent') + output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因') + res_info = f"\nPlanning agent execution result is :\n" + for index, one_framework in enumerate(output_object.get_data('framework')): + res_info += f"[{index + 1}] {one_framework} \n" + print(res_info) + + +if __name__ == '__main__': + unittest.main() diff --git a/sample_standard_app/app/test/test_rag_agent.py b/sample_standard_app/app/test/test_rag_agent.py index afa2da0d..217c23c0 100644 --- a/sample_standard_app/app/test/test_rag_agent.py +++ b/sample_standard_app/app/test/test_rag_agent.py @@ -24,8 +24,10 @@ 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='英伟达股票大涨原因是什么?') - print(output_object.get_data('output')) + 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__': diff --git a/sample_standard_app/app/test/test_reviewing_agent.py b/sample_standard_app/app/test/test_reviewing_agent.py new file mode 100644 index 00000000..cdb244e9 --- /dev/null +++ b/sample_standard_app/app/test/test_reviewing_agent.py @@ -0,0 +1,51 @@ +# !/usr/bin/env python3 +# -*- coding:utf-8 -*- +# @Time : 2024/4/15 11:14 +# @Author : wangchongshi +# @Email : wangchongshi.wcs@antgroup.com +# @FileName: test_reviewing_agent.py +import unittest + +from agentuniverse.agent.agent import Agent +from agentuniverse.agent.agent_manager import AgentManager +from agentuniverse.agent.input_object import InputObject +from agentuniverse.agent.output_object import OutputObject +from agentuniverse.base.agentuniverse import AgentUniverse + + +class ReviewingAgentTest(unittest.TestCase): + """Test cases for the reviewing agent""" + + def setUp(self) -> None: + AgentUniverse().start(config_path='../../config/config.toml') + + def test_reviewing_agent(self): + """Test demo reviewing agent. + + In the normal process, we need to aggregate information through the expressing agent to generate a complete answer. + After that, the reviewing agent is used to evaluate whether the question answered by the expressing agent is valid. + In the current demo test method, we mock the expressing result generated by the expressing Agent. + """ + + instance: Agent = AgentManager().get_instance_obj('demo_reviewing_agent') + + # mock the expressing agent result + expressing_output = """ + 分析巴菲特减持比亚迪的原因,我们可以从以下几个角度进行解读: + 首先,从投资策略的角度来看,巴菲特一直以来的投资原则是“买入并持有”,而非频繁交易。他的投资决策通常基于对公司运营状况的长期观察和判断。因此,巴菲特减持比亚迪可能是他对比亚迪的未来发展或者新能源行业的前景有了新的认识。这可能是由于比亚迪的业务表现、市场竞争环境、政策风险等因素的变化,使得巴菲特对比亚迪的价值预期发生了调整。 + 其次,从资本运作的角度来看,巴菲特减持比亚迪也可能是出于资本运作的需要。巴菲特的伯克希尔·哈撒韦公司是一个多元化的投资集团,需要对各个投资项目进行合理的资金配置。因此,巴菲特可能是在进行资产配置的调整,以适应市场环境的变化,或者获取更高的投资回报。 + 再次,从市场环境的角度来看,近年来,新能源汽车行业的竞争日益激烈,各大汽车厂商纷纷投入新能源汽车的研发和生产。在这种情况下,巴菲特可能认为比亚迪在未来的市场竞争中面临的压力和挑战增大,因此选择了减持。 + 总的来说,巴菲特减持比亚迪的原因可能是多方面的,包括他对比亚迪及新能源行业未来发展的认识变化,资本运作的需要,以及市场环境的变化等。这些因素的综合作用可能导致了巴菲特对比亚迪的投资策略进行了调整。 + """ + expressing_result = InputObject({'output': expressing_output}) + + output_object: OutputObject = instance.run(input='分析下巴菲特减持比亚迪的原因', + expressing_result=expressing_result) + res_info = f"\nReviewing agent execution result is :\n" + res_info += f"review suggestion: {output_object.get_data('suggestion')} \n" + res_info += f"review score: {output_object.get_data('score')} \n" + print(res_info) + + +if __name__ == '__main__': + unittest.main() diff --git a/sample_standard_app/config/config.toml b/sample_standard_app/config/config.toml index 7ac7a1a7..fe4a5eeb 100644 --- a/sample_standard_app/config/config.toml +++ b/sample_standard_app/config/config.toml @@ -6,19 +6,21 @@ appname = 'demo_app' # Perform a full component scan and registration for all the paths under this list. default = ['sample_standard_app.app.core'] # Scan and register agent components for all paths under this list, with priority over the default. -agent = ['sample_standard_app.app.core.agent', 'agentuniverse.agent.default'] +agent = ['sample_standard_app.app.core.agent'] # Scan and register agent components for all paths under this list, with priority over the default. knowledge = ['sample_standard_app.app.core.knowledge'] # Scan and register knowledge components for all paths under this list, with priority over the default. -llm = ['sample_standard_app.app.core.llm', 'agentuniverse.llm.default'] +llm = ['sample_standard_app.app.core.llm'] # Scan and register llm components for all paths under this list, with priority over the default. -planner = ['sample_standard_app.app.core.planner', 'agentuniverse.agent.plan.planner'] +planner = ['sample_standard_app.app.core.planner'] # Scan and register planner components for all paths under this list, with priority over the default. tool = ['sample_standard_app.app.core.tool'] # Scan and register memory components for all paths under this list, with priority over the default. memory = ['sample_standard_app.app.core.memory'] # Scan and register service components for all paths under this list, with priority over the default. service = ['sample_standard_app.app.core.service'] +# Scan and register prompt components for all paths under this list, with priority over the default. +prompt = [] [SUB_CONFIG_PATH] # Log config file path, an absolute path or a relative path based on the dir where the current config file is located. diff --git a/setup.py b/setup.py index c6ec97e5..611d37f9 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ def read_requirements(): setuptools.setup( name="agentUniverse", - version="0.0.3", + version="0.0.4", author="AntGroup", author_email="jerry.zzw@antgroup.com", description="agentUniverse is a framework for developing applications powered " diff --git a/tests/test_agentuniverse/unit/agent/action/knowledge/test_knowledge.py b/tests/test_agentuniverse/unit/agent/action/knowledge/test_knowledge.py index 09516779..24813adf 100644 --- a/tests/test_agentuniverse/unit/agent/action/knowledge/test_knowledge.py +++ b/tests/test_agentuniverse/unit/agent/action/knowledge/test_knowledge.py @@ -27,6 +27,16 @@ def setUp(self) -> None: embedding_model_name='text-embedding-ada-002')) self.knowledge = Knowledge(**init_params) + def test_store_update_documents(self) -> None: + store = self.knowledge.store + store.update_document([Document(text='This is an iPhone', metadata={'type': 'Electronic products'}), + Document(text='This is a Tesla.', metadata={'type': 'Industrial products'})]) + + def test_store_upsert_documents(self) -> None: + store = self.knowledge.store + store.upsert_document([Document(text='This is an iPhone', metadata={'type': 'Cell phone'}), + Document(text='This is a Tesla.', metadata={'type': 'Car'})]) + def test_store_insert_documents(self) -> None: store = self.knowledge.store store.insert_documents([Document(text='This is a document about engineer'), @@ -34,7 +44,7 @@ def test_store_insert_documents(self) -> None: def test_query(self) -> None: store = self.knowledge.store - query = Query(query_str='Which stock is the best?', similarity_top_k=1) + query = Query(query_str='Which one is a cell phone?', similarity_top_k=1) res = store.query(query) print(res) diff --git a/tests/test_agentuniverse/unit/agent/test_rag_agent.py b/tests/test_agentuniverse/unit/agent/test_rag_agent.py deleted file mode 100644 index eedc6fa4..00000000 --- a/tests/test_agentuniverse/unit/agent/test_rag_agent.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding:utf-8 -*- - -# @Time : 2024/4/23 14:58 -# @Author : wangchongshi -# @Email : wangchongshi.wcs@antgroup.com -# @FileName: test_rag_agent.py -import unittest - -from agentuniverse.agent.agent import Agent -from agentuniverse.agent.agent_manager import AgentManager -from agentuniverse.agent.output_object import OutputObject -from agentuniverse.base.agentuniverse import AgentUniverse - - -class TestAgent(unittest.TestCase): - - def setUp(self) -> None: - AgentUniverse().start(config_path='./config.toml') - - def test_rag_agent(self): - instance: Agent = AgentManager().get_instance_obj('rag_agent') - output_object: OutputObject = instance.run(input='分析下先锋领航退出中国的原因') - print(output_object.get_data('output'))