feat: 使用 create_agent 接口替换老版本的 create_react_agent

This commit is contained in:
Wenjie Zhang 2025-10-25 20:01:23 +08:00
parent fdc4f174a9
commit a8491c5beb
6 changed files with 54 additions and 42 deletions

View File

@ -11,16 +11,13 @@
## Next ## Next
- [ ] 修改现有的智能体Demo并尽量将默认助手的特性兼容到 LangGraph 的 [`create_agent`](https://docs.langchain.com/oss/python/langchain/agents) 中 - [x] 修改现有的智能体Demo并尽量将默认助手的特性兼容到 LangGraph 的 [`create_agent`](https://docs.langchain.com/oss/python/langchain/agents) 中
- [ ] 基于 create_agent 创建 SQL Viewer 智能体 <Badge type="info" text="0.3.5" /> - [ ] 基于 create_agent 创建 SQL Viewer 智能体 <Badge type="info" text="0.3.5" />
- [ ] 优化 MCP 逻辑,支持 common + special 创建方式 <Badge type="info" text="0.3.5" /> - [ ] 优化 MCP 逻辑,支持 common + special 创建方式 <Badge type="info" text="0.3.5" />
- [ ] 添加对于上传文件的支持 - [ ] 添加对于上传文件的支持
- [ ] 统一图谱数据结构,优化可视化方式 [#298](https://github.com/xerrors/Yuxi-Know/issues/298) <Badge type="info" text="0.4" /> - [ ] 统一图谱数据结构,优化可视化方式 [#298](https://github.com/xerrors/Yuxi-Know/issues/298) <Badge type="info" text="0.4" />
- [ ] 集成智能体评估,首先使用命令行来实现,然后考虑放在 UI 里面展示 - [ ] 集成智能体评估,首先使用命令行来实现,然后考虑放在 UI 里面展示
- [ ] 开发与生产环境隔离,构建生产镜像 <Badge type="info" text="0.4" /> - [ ] 开发与生产环境隔离,构建生产镜像 <Badge type="info" text="0.4" />
- [x] 支持 MinerU 2.5 的解析方法 <Badge type="info" text="0.3.5" />
- [x] 文件管理1文件选择的时候会跨数据库2文件校验会算上失败的文件
- [x] Tasker 中获取历史任务的时候,仅获取 top100 个 task。
## Later ## Later
@ -37,3 +34,6 @@
- [x] 优化对文档信息的检索展示(检索结果页、详情页) - [x] 优化对文档信息的检索展示(检索结果页、详情页)
- [x] 当前 ReAct 智能体有消息顺序错乱的 bug且不会默认调用工具 - [x] 当前 ReAct 智能体有消息顺序错乱的 bug且不会默认调用工具
- [x] 优化全局配置的管理模型,优化配置管理 - [x] 优化全局配置的管理模型,优化配置管理
- [x] 支持 MinerU 2.5 的解析方法 <Badge type="info" text="0.3.5" />
- [x] 文件管理1文件选择的时候会跨数据库2文件校验会算上失败的文件
- [x] Tasker 中获取历史任务的时候,仅获取 top100 个 task。

View File

@ -10,11 +10,6 @@ from .tools import get_tools
@dataclass(kw_only=True) @dataclass(kw_only=True)
class Context(BaseContext): class Context(BaseContext):
model: Annotated[str, {"__template_metadata__": {"kind": "llm"}}] = field(
default="siliconflow/Qwen/Qwen3-235B-A22B-Instruct-2507",
metadata={"name": "智能体模型", "options": [], "description": "智能体的驱动模型"},
)
tools: Annotated[list[dict], {"__template_metadata__": {"kind": "tools"}}] = field( tools: Annotated[list[dict], {"__template_metadata__": {"kind": "tools"}}] = field(
default_factory=list, default_factory=list,
metadata={ metadata={

View File

@ -1,12 +1,10 @@
"""Define the configurable parameters for the agent.""" """Define the configurable parameters for the agent."""
from __future__ import annotations
import os import os
import uuid import uuid
from dataclasses import MISSING, dataclass, field, fields from dataclasses import MISSING, dataclass, field, fields
from pathlib import Path from pathlib import Path
from typing import get_args, get_origin from typing import Annotated, get_args, get_origin
import yaml import yaml
@ -46,8 +44,13 @@ class BaseContext:
metadata={"name": "系统提示词", "description": "用来描述智能体的角色和行为"}, metadata={"name": "系统提示词", "description": "用来描述智能体的角色和行为"},
) )
model: Annotated[str, {"__template_metadata__": {"kind": "llm"}}] = field(
default="siliconflow/Qwen/Qwen3-235B-A22B-Instruct-2507",
metadata={"name": "智能体模型", "options": [], "description": "智能体的驱动模型"},
)
@classmethod @classmethod
def from_file(cls, module_name: str, input_context: dict = None) -> BaseContext: def from_file(cls, module_name: str, input_context: dict = None) -> "BaseContext":
"""Load configuration from a YAML file. 用于持久化配置""" """Load configuration from a YAML file. 用于持久化配置"""
# 从文件加载配置 # 从文件加载配置

View File

@ -1,12 +1,10 @@
from pathlib import Path from pathlib import Path
from langchain.messages import AnyMessage, SystemMessage from langchain.agents import create_agent
from langgraph.prebuilt import create_react_agent from langchain.agents.middleware import ModelRequest, ModelResponse, dynamic_prompt, wrap_model_call
from langgraph.runtime import get_runtime
from src import config as sys_config from src import config as sys_config
from src.agents.common.base import BaseAgent from src.agents.common.base import BaseAgent
from src.agents.common.context import BaseContext
from src.agents.common.models import load_chat_model from src.agents.common.models import load_chat_model
from src.agents.common.tools import get_buildin_tools from src.agents.common.tools import get_buildin_tools
from src.utils import logger from src.utils import logger
@ -14,14 +12,24 @@ from src.utils import logger
model = load_chat_model("siliconflow/Qwen/Qwen3-235B-A22B-Instruct-2507") model = load_chat_model("siliconflow/Qwen/Qwen3-235B-A22B-Instruct-2507")
def prompt(state) -> list[AnyMessage]: @dynamic_prompt
runtime = get_runtime(BaseContext) def context_aware_prompt(request: ModelRequest) -> str:
system_msg = SystemMessage(content=runtime.context.system_prompt) runtime = request.runtime
return [system_msg] + state["messages"] return runtime.context.system_prompt
@wrap_model_call
async def context_based_model(request: ModelRequest, handler) -> ModelResponse:
# 从 runtime context 读取配置
model_spec = request.runtime.context.model
model = load_chat_model(model_spec)
request = request.override(model=model)
return await handler(request)
class ReActAgent(BaseAgent): class ReActAgent(BaseAgent):
name = "ReAct (all tools)" name = "智能体 Demo"
description = "A react agent that can answer questions and help with tasks." description = "A react agent that can answer questions and help with tasks."
def __init__(self, **kwargs): def __init__(self, **kwargs):
@ -30,15 +38,21 @@ class ReActAgent(BaseAgent):
self.workdir = Path(sys_config.save_dir) / "agents" / self.module_name self.workdir = Path(sys_config.save_dir) / "agents" / self.module_name
self.workdir.mkdir(parents=True, exist_ok=True) self.workdir.mkdir(parents=True, exist_ok=True)
def get_tools(self):
return get_buildin_tools()
async def get_graph(self, **kwargs): async def get_graph(self, **kwargs):
if self.graph: if self.graph:
return self.graph return self.graph
available_tools = get_buildin_tools()
self.checkpointer = await self._get_checkpointer()
# 创建 ReActAgent # 创建 ReActAgent
graph = create_react_agent(model, tools=available_tools, prompt=prompt, checkpointer=self.checkpointer) graph = create_agent(
model=model,
tools=self.get_tools(),
middleware=[context_aware_prompt, context_based_model],
checkpointer=await self._get_checkpointer(),
)
self.graph = graph self.graph = graph
logger.info("ReActAgent 使用内存 checkpointer 构建成功") logger.info("ReActAgent 使用内存 checkpointer 构建成功")
return graph return graph

View File

@ -46,21 +46,21 @@ class KnowledgeBaseManager:
logger.info("KnowledgeBaseManager initialized") logger.info("KnowledgeBaseManager initialized")
# 在后台运行数据一致性检测(不阻塞初始化) # 在后台运行数据一致性检测(不阻塞初始化)
try: # try:
# 尝试获取当前事件循环,如果没有则创建新的 # # 尝试获取当前事件循环,如果没有则创建新的
try: # try:
loop = asyncio.get_event_loop() # loop = asyncio.get_event_loop()
if loop.is_running(): # if loop.is_running():
# 如果已经在事件循环中,创建任务 # # 如果已经在事件循环中,创建任务
asyncio.create_task(self.detect_data_inconsistencies()) # asyncio.create_task(self.detect_data_inconsistencies())
else: # else:
# 如果事件循环未运行,直接运行 # # 如果事件循环未运行,直接运行
loop.run_until_complete(self.detect_data_inconsistencies()) # loop.run_until_complete(self.detect_data_inconsistencies())
except RuntimeError: # except RuntimeError:
# 没有事件循环,创建一个来运行检测 # # 没有事件循环,创建一个来运行检测
asyncio.run(self.detect_data_inconsistencies()) # asyncio.run(self.detect_data_inconsistencies())
except Exception as e: # except Exception as e:
logger.warning(f"初始化时运行数据一致性检测失败: {e}") # logger.warning(f"初始化时运行数据一致性检测失败: {e}")
def _load_global_metadata(self): def _load_global_metadata(self):
"""加载全局元数据""" """加载全局元数据"""

View File

@ -18,7 +18,7 @@
<!-- 侧边栏内容 --> <!-- 侧边栏内容 -->
<div class="sidebar-content"> <div class="sidebar-content">
<div class="agent-info" v-if="selectedAgent"> <div class="agent-info" v-if="selectedAgent">
<div class="agent-basic-info"> <div class="agent-basic-info" @click="console.log(configurableItems)">
<p class="agent-description">{{ selectedAgent.description }}</p> <p class="agent-description">{{ selectedAgent.description }}</p>
</div> </div>