fix(middleware): 修复 RuntimeConfigMiddleware 的工具override 导致的其余中间件失效的问题(还需要进一步排查 subagents 的 model 是否有问题)

This commit is contained in:
Wenjie Zhang 2026-01-29 22:48:48 +08:00
parent 812bb95f8d
commit 4480c20f81
3 changed files with 33 additions and 53 deletions

View File

@ -114,6 +114,16 @@ class ReporterContext(BaseContext):
中间件位于 `src/agents/common/middlewares`,包含上下文感知提示词、模型选择、动态工具加载以及附件注入等实现。如果需要编写新的中间件,请遵循 LangChain 官方文档中对 `AgentMiddleware`、`ModelRequest`、`ModelResponse` 等接口的定义,完成后在该目录的 `__init__.py` 暴露入口,主智能体即可在 `middleware` 列表中引用。
#### RuntimeConfigMiddleware
`RuntimeConfigMiddleware`[runtime_config_middleware.py](https://github.com/xerrors/Yuxi-Know/blob/main/src/agents/common/middlewares/runtime_config_middleware.py))是系统默认的核心中间件之一,负责在每次模型调用前自动注入运行时配置:
1. **自动注入当前时间**:在 system prompt 开头追加当前时间,格式为 `当前时间YYYY-MM-DD HH:MM:SS`,确保 LLM 能获取准确的时间上下文。
2. **动态加载工具**:根据 `context.tools`、`context.knowledges`、`context.mcps` 自动组装可用工具列表。
3. **模型选择**:根据 `context.model` 加载对应模型配置。
如需自定义时间注入逻辑或禁用该行为,可继承该中间件并覆盖 `awrap_model_call` 方法。
#### 文件上传中间件
文件上传功能通过 `inject_attachment_context` 中间件实现(位于 `src/agents/common/middlewares/attachment_middleware.py`)。该中间件基于 LangChain 1.0 的 `AgentMiddleware` 标准实现,具有以下特点:

View File

@ -4,29 +4,15 @@ from collections.abc import Callable
from typing import Any
from langchain.agents.middleware import AgentMiddleware, ModelRequest, ModelResponse
from langchain_core.messages import SystemMessage
from src.agents.common import load_chat_model
from src.agents.common.tools import get_kb_based_tools, get_buildin_tools
from src.agents.common.tools import get_buildin_tools, get_kb_based_tools
from src.services.mcp_service import get_enabled_mcp_tools
from src.utils.datetime_utils import shanghai_now
from src.utils.logging_config import logger
def _is_system_message(msg: Any) -> bool:
if isinstance(msg, dict):
role = msg.get("role") or msg.get("type")
return role == "system"
msg_type = getattr(msg, "type", None) or getattr(msg, "role", None)
return msg_type == "system"
def _get_message_content(msg: Any) -> str | None:
if isinstance(msg, dict):
content = msg.get("content")
return str(content) if content is not None else None
content = getattr(msg, "content", None)
return str(content) if content is not None else None
class RuntimeConfigMiddleware(AgentMiddleware):
"""运行时配置中间件 - 应用模型/工具/知识库/MCP/提示词配置
@ -41,7 +27,7 @@ class RuntimeConfigMiddleware(AgentMiddleware):
extra_tools: 额外工具列表 create_agent tools 参数传入
"""
super().__init__()
# 这里的工具只是提供给 langchain 调用,并不是真正的绑定在模型上
# 这里的工具只是提供给 langchain 调用,并不是真正的绑定在模型上(后续会过滤)
self.kb_tools = get_kb_based_tools()
self.buildin_tools = get_buildin_tools()
self.tools = self.kb_tools + self.buildin_tools + (extra_tools or [])
@ -54,35 +40,29 @@ class RuntimeConfigMiddleware(AgentMiddleware):
model = load_chat_model(getattr(runtime_context, "model", None))
enabled_tools = await self.get_tools_from_context(runtime_context)
system_prompt = getattr(runtime_context, "system_prompt", None)
logger.debug(f"RuntimeConfigMiddleware: model={model}, "
f"tools={[t.name for t in enabled_tools]}. ")
existing_tools = list(request.tools or [])
existing_systems: list[Any] = []
remaining: list[Any] = []
in_prefix = True
for msg in request.messages:
if in_prefix and _is_system_message(msg):
existing_systems.append(msg)
else:
in_prefix = False
remaining.append(msg)
# 合并之前中间件设置的 tools避免覆盖
merged_tools = []
for t_bind in existing_tools:
if t_bind in enabled_tools or t_bind not in self.tools:
merged_tools.append(t_bind)
existing_contents = [_get_message_content(m) for m in existing_systems]
# 动态生成 system message添加当前时间
cur_datetime = f"当前时间:{shanghai_now().strftime('%Y-%m-%d %H:%M:%S')} UTC"
system_prompt = getattr(runtime_context, "system_prompt", "") or ""
new_content = list(request.system_message.content_blocks) + [
{"type": "text", "text": f"{cur_datetime}\n\n{system_prompt}"}
]
new_system_message = SystemMessage(content=new_content)
new_systems: list[Any] = []
if system_prompt:
try:
idx = existing_contents.index(system_prompt)
except ValueError:
new_systems.append({"role": "system", "content": system_prompt})
else:
new_systems.append(existing_systems.pop(idx))
existing_contents.pop(idx)
logger.debug(f"RuntimeConfigMiddleware: model={model}, tools={[t.name for t in merged_tools]}. ")
messages = [*new_systems, *existing_systems, *remaining]
request = request.override(model=model, tools=enabled_tools, messages=messages)
request = request.override(
model=model,
tools=merged_tools,
system_message=new_system_message
)
return await handler(request)
async def get_tools_from_context(self, context) -> list:

View File

@ -5,10 +5,8 @@ from deepagents.middleware.patch_tool_calls import PatchToolCallsMiddleware
from deepagents.middleware.subagents import SubAgentMiddleware
from langchain.agents import create_agent
from langchain.agents.middleware import (
ModelRequest,
SummarizationMiddleware,
TodoListMiddleware,
dynamic_prompt,
)
from src.agents.common import BaseAgent, load_chat_model
@ -17,7 +15,6 @@ from src.agents.common.tools import get_tavily_search
from src.services.mcp_service import get_tools_from_all_servers
from .context import DeepContext
from .prompts import DEEP_PROMPT
def _get_research_sub_agent(search_tools: list) -> dict:
@ -57,12 +54,6 @@ critique_sub_agent = {
}
@dynamic_prompt
def context_aware_prompt(request: ModelRequest) -> str:
"""从 runtime context 动态生成系统提示词"""
return DEEP_PROMPT + "\n\n\n" + request.runtime.context.system_prompt
class DeepAgent(BaseAgent):
name = "深度分析智能体"
description = "具备规划、深度分析和子智能体协作能力的智能体,可以处理复杂的多步骤任务"
@ -111,7 +102,6 @@ class DeepAgent(BaseAgent):
model=model,
system_prompt=context.system_prompt,
middleware=[
context_aware_prompt, # 动态系统提示词
inject_attachment_context, # 附件上下文注入
RuntimeConfigMiddleware(extra_tools=all_mcp_tools),
TodoListMiddleware(),