Skip to content

Commit 5adff04

Browse files
committed
feat: 添加深度分析智能体模块及相关上下文和工具
- 在 `src/agents/deep_agent` 中新增深度分析智能体模块,包含任务规划、深度知识搜索和分析能力。 - 引入 `deepagents` 库,创建深度智能体并实现复杂任务处理。 - 更新 `pyproject.toml` 以添加 `deepagents` 依赖。 - 修改 `context.py` 和 `graph.py`,为深度智能体提供专用上下文和工具支持。 - 更新文档以反映新功能和模块的集成。
1 parent cab57e7 commit 5adff04

File tree

8 files changed

+291
-9
lines changed

8 files changed

+291
-9
lines changed

docs/latest/changelog/roadmap.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
- 集成智能体评估,首先使用命令行来实现,然后考虑放在 UI 里面展示
1212
- 开发与生产环境隔离,构建生产镜像 <Badge type="info" text="0.4" />
1313
- 集成 LangFuse (观望) 添加用户日志与用户反馈模块,可以在 AgentView 中查看信息
14+
- 集成 neo4j mcp (或者自己构建工具)
15+
- 工具组件重构以支持 todo,files 等渲染。
1416

1517
### Bugs
1618
- 部分异常状态下,智能体的模型名称出现重叠[#279](https://github.com/xerrors/Yuxi-Know/issues/279)

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ dependencies = [
6060
"tomli-w",
6161
"aiofiles>=24.1.0",
6262
"aiohttp>=3.9.0",
63+
"deepagents>=0.2.5",
6364
]
6465
[tool.ruff]
6566
line-length = 120 # 代码最大行宽

server/routers/system_router.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
from fastapi import APIRouter, Body, Depends, HTTPException
77

88
from src.storage.db.models import User
9-
from server.utils.auth_middleware import get_admin_user, get_superadmin_user
10-
from src import config, graph_base
9+
from server.utils.auth_middleware import get_admin_user
10+
from src import config
1111
from src.models.chat import test_chat_model_status, test_all_chat_models_status
1212
from src.utils.logging_config import logger
1313

src/agents/common/context.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ def update(self, data: dict):
3131

3232
thread_id: str = field(
3333
default_factory=lambda: str(uuid.uuid4()),
34-
metadata={"name": "线程ID", "configurable": False, "description": "用来描述智能体的角色和行为"},
34+
metadata={"name": "线程ID", "configurable": False, "description": "用来唯一标识一个对话线程"},
3535
)
3636

3737
user_id: str = field(
3838
default_factory=lambda: str(uuid.uuid4()),
39-
metadata={"name": "用户ID", "configurable": False, "description": "用来描述智能体的角色和行为"},
39+
metadata={"name": "用户ID", "configurable": False, "description": "用来唯一标识一个用户"},
4040
)
4141

4242
system_prompt: str = field(
@@ -45,7 +45,7 @@ def update(self, data: dict):
4545
)
4646

4747
model: Annotated[str, {"__template_metadata__": {"kind": "llm"}}] = field(
48-
default="siliconflow/Qwen/Qwen3-235B-A22B-Instruct-2507",
48+
default=sys_config.default_model,
4949
metadata={"name": "智能体模型", "options": [], "description": "智能体的驱动模型"},
5050
)
5151

src/agents/common/tools.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
from src.utils import logger
1313

1414

15+
search = TavilySearch(max_results=10)
16+
search.metadata = {"name": "Tavily 网页搜索"}
17+
1518
@tool(name_or_callable="计算器", description="可以对给定的2个数字选择进行 add, subtract, multiply, divide 运算")
1619
def calculator(a: float, b: float, operation: str) -> float:
1720
try:
@@ -69,9 +72,15 @@ def get_approved_user_goal(
6972

7073
return result
7174

72-
@tool(name_or_callable="查询知识图谱", description="使用这个工具可以查询知识图谱中包含的三元组信息。")
75+
76+
KG_QUERY_DESCRIPTION = """
77+
使用这个工具可以查询知识图谱中包含的三元组信息。
78+
关键词(query),使用可能帮助回答这个问题的关键词进行查询,不要直接使用用户的原始输入去查询。
79+
"""
80+
81+
@tool(name_or_callable="查询知识图谱", description=KG_QUERY_DESCRIPTION)
7382
def query_knowledge_graph(query: Annotated[str, "The keyword to query knowledge graph."]) -> Any:
74-
"""Use this to query knowledge graph, which include some food domain knowledge."""
83+
"""使用这个工具可以查询知识图谱中包含的三元组信息。关键词(query),使用可能帮助回答这个问题的关键词进行查询,不要直接使用用户的原始输入去查询。"""
7584
try:
7685
logger.debug(f"Querying knowledge graph with: {query}")
7786
result = graph_base.query_node(query, hops=2, return_format="triples")
@@ -91,8 +100,6 @@ def get_static_tools() -> list:
91100

92101
# 检查是否启用网页搜索
93102
if config.enable_web_search:
94-
search = TavilySearch(max_results=10)
95-
search.metadata = {"name": "Tavily 网页搜索"}
96103
static_tools.append(search)
97104

98105
return static_tools

src/agents/deep_agent/__init__.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""Deep Agent - 深度分析智能体模块
2+
3+
基于 deepagents 库构建的深度分析智能体,具备以下特性:
4+
- 任务规划和分解能力
5+
- 深度知识搜索和分析
6+
- 子智能体协作
7+
- 文件系统和长期记忆
8+
- 综合分析和报告生成
9+
"""
10+
11+
from .context import DeepContext
12+
from .graph import DeepAgent
13+
14+
__all__ = [
15+
"DeepAgent",
16+
"DeepContext",
17+
]
18+
19+
# 模块元数据
20+
__version__ = "1.0.0"
21+
__author__ = "Yuxi-Know Team"
22+
__description__ = "基于 create_deep_agent 的深度分析智能体"

src/agents/deep_agent/context.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""Deep Agent Context - 基于BaseContext的深度分析上下文配置"""
2+
3+
from dataclasses import field
4+
5+
from src.agents.common.context import BaseContext
6+
7+
8+
DEEP_PROMPT = """你是一个能够处理复杂、多步骤任务的深度分析代理。
9+
10+
你拥有以下资源:
11+
- 用于分解复杂任务的规划工具
12+
- 用于存储上下文和长期记忆的文件系统
13+
- 用于委派专业工作的子代理
14+
- 知识图谱查询与分析工具
15+
16+
你的工作方式:
17+
1. 仔细分析用户的请求
18+
2. 如果任务复杂,则制定计划
19+
3. 使用合适的工具和子代理
20+
4. 提供全面且有充分推理的回应
21+
5. 存储重要信息以备将来参考
22+
23+
在分析中注重深度、准确性和全面性。"""
24+
25+
26+
class DeepContext(BaseContext):
27+
"""
28+
Deep Agent 的上下文配置,继承自 BaseContext
29+
专门用于深度分析任务的配置管理
30+
"""
31+
32+
# 深度分析专用的系统提示词
33+
system_prompt: str = field(
34+
default=DEEP_PROMPT,
35+
metadata={"name": "系统提示词", "description": "Deep智能体的角色和行为指导"},
36+
)

src/agents/deep_agent/graph.py

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
"""Deep Agent - 基于create_deep_agent的深度分析智能体"""
2+
import os
3+
from typing import Literal
4+
from deepagents import create_deep_agent
5+
6+
from src.agents.common import BaseAgent, load_chat_model
7+
from src.agents.common.tools import search
8+
from src.agents.common.middlewares import (
9+
context_aware_prompt,
10+
context_based_model,
11+
inject_attachment_context,
12+
)
13+
from .context import DeepContext
14+
from tavily import TavilyClient
15+
16+
# 最佳实践是初始化客户端一次并复用它。
17+
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
18+
19+
20+
# 用于进行研究的搜索工具
21+
def internet_search(
22+
query: str,
23+
max_results: int = 5,
24+
topic: Literal["general", "news", "finance"] = "general",
25+
include_raw_content: bool = False,
26+
):
27+
"""运行网络搜索"""
28+
search_docs = tavily_client.search(
29+
query,
30+
max_results=max_results,
31+
include_raw_content=include_raw_content,
32+
topic=topic,
33+
)
34+
return search_docs
35+
36+
37+
sub_research_prompt = """你是一位专注的研究员。你的工作是根据用户的问题进行研究。
38+
39+
进行彻底的研究,然后用详细的答案回复用户的问题
40+
41+
只有你的最终答案会被传递给用户。除了你的最终信息,他们不会知道任何其他事情,所以你的最终报告应该就是你的最终信息!"""
42+
43+
research_sub_agent = {
44+
"name": "research-agent",
45+
"description": (
46+
"用于研究更深入的问题。一次只给这个研究员一个主题。不要向这个研究员传递多个子问题。"
47+
"相反,你应该将一个大主题分解成必要的组成部分,然后并行调用多个研究代理,每个子问题一个。"
48+
),
49+
"system_prompt": sub_research_prompt,
50+
"tools": [internet_search],
51+
}
52+
53+
sub_critique_prompt = """你是一位专注的编辑。你的任务是评论一份报告。
54+
55+
你可以在 `final_report.md` 找到这份报告。
56+
57+
你可以在 `question.txt` 找到这份报告的问题/主题。
58+
59+
用户可能会要求评论报告的特定方面。请用详细的评论回复用户,指出报告中可以改进的地方。
60+
61+
如果有助于你评论报告,你可以使用搜索工具来搜索信息
62+
63+
不要自己写入 `final_report.md`。
64+
65+
需要检查的事项:
66+
- 检查每个部分的标题是否恰当
67+
- 检查报告的写法是否像论文或教科书——它应该是以文本为主,不要只是一个项目符号列表!
68+
- 检查报告是否全面。如果任何段落或部分过短,或缺少重要细节,请指出来。
69+
- 检查文章是否涵盖了行业的关键领域,确保了整体理解,并且没有遗漏重要部分。
70+
- 检查文章是否深入分析了原因、影响和趋势,提供了有价值的见解
71+
- 检查文章是否紧扣研究主题并直接回答问题
72+
- 检查文章是否结构清晰、语言流畅、易于理解。
73+
"""
74+
75+
critique_sub_agent = {
76+
"name": "critique-agent",
77+
"description": "用于评论最终报告。给这个代理一些关于你希望它如何评论报告的信息。",
78+
"system_prompt": sub_critique_prompt,
79+
}
80+
81+
82+
# 用于引导代理成为专家级研究员的提示前缀
83+
research_instructions = """你是一位专家级研究员。你的工作是进行彻底的研究,然后撰写一份精美的报告。
84+
85+
你应该做的第一件事是把原始的用户问题写入 `question.txt`,以便你有一个记录。
86+
87+
使用 research-agent 进行深入研究。它会用详细的答案回应你的问题/主题。
88+
89+
当你认为有足够的信息来撰写最终报告时,就把它写入 `final_report.md`
90+
91+
你可以调用 critique-agent 来获取对最终报告的评论。之后(如果需要)你可以做更多的研究并编辑 `final_report.md`
92+
你可以根据需要重复这个过程,直到你对结果满意为止。
93+
94+
一次只编辑一个文件(如果你并行调用这个工具,可能会有冲突)。
95+
96+
以下是撰写最终报告的说明:
97+
98+
<report_instructions>
99+
100+
关键:确保答案的语言与人类信息的语言相同!如果你制定了一个待办事项计划,你应该在计划中注明报告应该使用什么语言。
101+
注意:报告应该使用的语言是问题所在的语言,而不是问题所涉及的国家/地区的语言。
102+
103+
请根据整体研究简报创建一个详细的答案,该答案应:
104+
1. 组织良好,有恰当的标题(# 用于标题,## 用于章节,### 用于子章节)
105+
2. 包含研究中的具体事实和见解
106+
3. 使用 [标题](URL) 格式引用相关来源
107+
4. 提供平衡、透彻的分析。尽可能全面,并包含与整体研究问题相关的所有信息。使用你进行深入研究,并期望得到详细、全面的答案
108+
5. 在末尾包含一个“来源”部分,列出所有引用的链接
109+
110+
你可以用多种不同的方式来组织你的报告。以下是一些例子:
111+
112+
要回答一个要求你比较两件事物的问题,你可以这样组织你的报告:
113+
1/ 引言
114+
2/ 主题A概述
115+
3/ 主题B概述
116+
4/ A与B的比较
117+
5/ 结论
118+
119+
要回答一个要求你返回一个事物列表的问题,你可能只需要一个部分,即整个列表。
120+
1/ 事物列表或表格
121+
或者,你可以选择将列表中的每一项都作为报告中的一个独立部分。当被要求提供列表时,你不需要引言或结论。
122+
1/ 项目1
123+
2/ 项目2
124+
3/ 项目3
125+
126+
要回答一个要求你总结一个主题、给出一份报告或概述的问题,你可以这样组织你的报告:
127+
1/ 主题概述
128+
2/ 概念1
129+
3/ 概念2
130+
4/ 概念3
131+
5/ 结论
132+
133+
如果你认为你可以用一个部分来回答问题,你也可以这样做!
134+
1/ 答案
135+
136+
请记住:章节是一个非常灵活和松散的概念。你可以按照你认为最好的方式来组织你的报告,包括上面没有列出的方式!
137+
确保你的各个部分是连贯的,并且对读者来说是有意义的。
138+
139+
对于报告的每个部分,请执行以下操作:
140+
- 使用简单、清晰的语言
141+
- 对报告的每个部分使用 ## 作为章节标题(Markdown 格式)
142+
- 绝不要将自己称为报告的作者。这应该是一份专业的报告,不含任何自我指涉的语言。
143+
- 不要在报告中说你正在做什么。只需撰写报告,不要添加任何你自己的评论。
144+
- 每个部分的长度应足以用你收集到的信息。预计各部分会长且详尽。你正在撰写一份深入的研究报告,用户会期望得到透彻的答案。
145+
- 在适当的时候使用项目符号来列出信息,但默认情况下,请以段落形式撰写。
146+
147+
请记住:
148+
简报和研究可能是英文的,但在撰写最终答案时,你需要将这些信息翻译成正确的语言。
149+
确保最终答案报告的语言与消息历史中的人类信息语言相同。
150+
151+
用清晰的 markdown 格式化报告,结构合理,并在适当的地方包含来源引用。
152+
153+
<引用规则>
154+
- 在你的文本中为每个唯一的 URL 分配一个引文编号
155+
- 以 ### 来源 结尾,列出每个来源及其对应的编号
156+
- 重要提示:无论你选择哪些来源,最终列表中的来源编号都应连续无间断(1,2,3,4...)
157+
- 每个来源都应该是列表中的一个独立行项目,这样在 markdown 中它会被渲染成一个列表。
158+
- 示例格式:
159+
[1] 来源标题: URL
160+
[2] 来源标题: URL
161+
- 引用非常重要。请确保包含这些内容,并特别注意确保其正确性。用户通常会使用这些引文来查找更多信息。
162+
</引用规则>
163+
</report_instructions>
164+
165+
你可以使用一些工具。
166+
167+
## `internet_search`
168+
169+
使用此工具对给定的查询进行网络搜索。你可以指定结果数量、主题以及是否包含原始内容。
170+
"""
171+
172+
class DeepAgent(BaseAgent):
173+
174+
name = "深度分析智能体"
175+
description = "具备规划、深度分析和子智能体协作能力的智能体,可以处理复杂的多步骤任务"
176+
context_schema = DeepContext
177+
capabilities = [
178+
"file_upload",
179+
]
180+
181+
def __init__(self, **kwargs):
182+
super().__init__(**kwargs)
183+
self.graph = None
184+
self.checkpointer = None
185+
186+
def get_tools(self):
187+
"""返回 Deep Agent 的专用工具"""
188+
tools = [search]
189+
return tools
190+
191+
async def get_graph(self, **kwargs):
192+
"""构建 Deep Agent 的图"""
193+
if self.graph:
194+
return self.graph
195+
196+
# 获取上下文配置
197+
context = self.context_schema.from_file(module_name=self.name)
198+
199+
# 使用 create_deep_agent 创建深度智能体
200+
graph = create_deep_agent(
201+
model=load_chat_model(context.model),
202+
system_prompt=context.system_prompt,
203+
tools=self.get_tools(),
204+
subagents=[critique_sub_agent, research_sub_agent],
205+
middleware=[
206+
context_based_model, # 动态模型选择
207+
context_aware_prompt, # 动态系统提示词
208+
inject_attachment_context, # 附件上下文注入
209+
],
210+
checkpointer=await self._get_checkpointer(),
211+
)
212+
213+
self.graph = graph
214+
return graph

0 commit comments

Comments
 (0)