Skip to content

中间件系统

中间件是 Yuxi 扩展智能体运行行为的主要机制。它工作在 LangGraph Agent 的模型调用、工具调用、状态更新和文件系统访问路径上,用来把知识库、Skills、附件、子智能体、上下文压缩和运行观测接入同一条执行链路。

内置 ChatbotAgentSubAgentBackend 都会在 get_graph() 中构建中间件列表。运行前的资源过滤不再依赖旧版运行时配置中间件,而是在创建 Graph 前由 prepare_agent_runtime_context 完成。

运行时准备

运行时准备不是中间件,但它决定后续中间件能看到什么资源。内置 Agent 创建 Graph 前会先执行以下步骤:

  • prepare_agent_runtime_context:按当前用户权限过滤工具、知识库、MCP、Skills 和子智能体,并派生 _visible_knowledge_bases_prompt_skills_readable_skills
  • build_prompt_with_context:基于 Context 生成系统提示词
  • load_chat_model(context.model):加载主模型
  • resolve_configured_runtime_tools(context):加载已配置的内置工具和 MCP 工具

这意味着中间件不负责重新判断“用户是否能访问某个资源”。它们消费的是已经归一化后的 runtime context。

内置中间件链路

当前内置 ChatbotAgent 的中间件顺序如下:

中间件作用
create_agent_filesystem_middleware接入沙盒文件系统、用户工作区、线程 uploads/outputs 与只读 Skills 路由,并在工具结果过大时把内容写入 outputs/large_tool_results
save_attachments_to_fs / AttachmentMiddleware从 LangGraph state 的 uploads 读取附件路径,把可读路径注入系统提示,提示模型按需使用 read_file
SkillsMiddleware注入可见 Skill 的提示段,监听读取 SKILL.md 后的 Skill 激活,并按依赖追加工具和 MCP 工具;知识库工具由内置 knowledge-base Skill 按需加载
YuxiSubAgentMiddleware仅主 Agent 在存在可见子智能体时挂载,提供 task 工具调用真实子 Agent graph
YuxiSummarizationMiddleware基于 DeepAgents SummarizationMiddleware 做长上下文压缩,并清洗被摘要历史里的工具结果
TodoListMiddleware提供待办状态,让前端状态面板可展示 Agent 运行进度
PatchToolCallsMiddleware修正部分工具调用消息形态,提升工具调用兼容性
ModelRetryMiddleware在模型调用失败时按配置重试
TokenUsageMiddleware在 LangGraph state 写入本轮 token 使用快照,供前端状态面板查看

SubAgentBackend 使用同一组核心能力,但不会挂载 YuxiSubAgentMiddleware,并额外过滤 present_artifactsask_user_questioninstall_skill 等不适合子智能体直接使用的工具。

知识库工具

知识库访问能力沉淀为内置 knowledge-base Skill。Agent 读取 /home/gem/skills/knowledge-base/SKILL.md 激活该 Skill 后,SkillsMiddleware 会按依赖追加 list_kbsquery_kbfind_kb_documentopen_kb_documentget_mindmap 等知识库工具。

实际可见知识库仍由 prepare_agent_runtime_context 根据当前用户和 Agent 配置写入 _visible_knowledge_bases,工具执行时只会在这批知识库中检索。context.knowledges 是资源范围,不是 Skill 本身。

系统不会把知识库文件树挂进沙盒。Agent 访问知识库内容应使用 query_kbfind_kb_documentopen_kb_document,而不是遍历 /home/gem/kbs 这类旧路径。

Skills 注入与激活

SkillsMiddleware 分两步工作:

  1. 模型调用前读取 _prompt_skills,把可见 Skill 的名称、描述和 SKILL.md 路径追加到系统提示。
  2. 工具调用后检查模型是否读取了 /home/gem/skills/<slug>/SKILL.md。如果该 Skill 在 _readable_skills 范围内,就把它写入 activated_skills,并在后续模型调用中追加它声明的工具和 MCP 依赖。

这种设计让 Skill 可以先作为说明可见,只有模型真正读取并激活后才扩展工具集,避免一开始就把所有依赖工具塞进上下文。

附件与文件系统

附件上传后会先落盘到线程文件系统,并在 LangGraph state 中记录 uploadsAttachmentMiddleware 只把文件名和可读路径注入提示词,不会把文件内容整体塞进模型上下文。模型需要查看附件时,应通过 read_file 读取对应路径。

文件系统中间件负责把 sandbox backend、线程 uploads/outputs、用户工作区和只读 Skills 组合成 Agent 可访问的虚拟文件系统。普通 Agent 默认使用当前 thread_id 作为文件作用域;子智能体使用 child thread_id 做 checkpoint,同时沿用父线程的 uploads/outputs,并使用子 Agent 自己的 Skills 作用域。

子智能体任务

主 Agent 如果配置了可见子智能体,会挂载 YuxiSubAgentMiddleware 并获得 task 工具。这个工具不会调用旧版独立 SubAgents 表,而是查找 agents.is_subagent=true 且后端为 SubAgentBackend 的真实 Agent 配置,然后启动对应子 Agent graph。

子智能体执行时会获得独立 child thread、独立 checkpoint 和 agent_runs(run_type=subagent) 记录;工具结果会返回 child thread ID,后续可以把该 ID 传回 task 继续同一个子任务。子智能体自身不会再挂载下一层 task 中间件,避免形成嵌套子智能体链路。

Summary 上下文压缩

长对话压缩由 Yuxi 封装的 YuxiSummarizationMiddleware 负责。它基于 DeepAgents 的 SummarizationMiddleware,但针对 Yuxi 的知识库检索和工具调用结果做了额外处理。

触发条件来自 Agent Context:

字段说明
summary_threshold上下文超过该 K token 阈值后触发摘要
summary_keep_messages摘要后保留最近消息数
summary_prompt摘要模型使用的提示词
summary_tool_result_token_limit被摘要历史中工具结果的预览 token 上限

触发判断使用 Yuxi 自己的近似 token 计算结果,不使用模型返回的 usage_metadata.total_tokens 作为触发依据,避免 provider 的计费口径、累计口径或异常上报导致短对话过早压缩。

触发后,中间件会把较早的消息压缩成一条 summary message,并保留最近窗口内的原始消息。对被摘要掉的历史工具结果,它不会把完整 ToolMessage.content 直接送进 summary prompt,而是先写入当前 Agent 可见的 outputs/large_tool_results,再用工具名、近似 token 数、完整结果路径和有限预览替换工具结果内容。

这对知识库检索尤其重要:query_kbopen_kb_documentfind_kb_document 等工具可能返回较长的片段、引用和文档内容。Summary 阶段保留“查过什么、结果在哪里、关键预览是什么”,同时避免把大量检索原文反复卷入摘要,减少上下文污染和 token 压力。

未触发 summary 的常规模型调用不会额外清洗最近窗口内的工具结果;常规工具结果预算主要由文件系统中间件在工具返回阶段处理。

自定义中间件

新增中间件时,将实现放入 backend/package/yuxi/agents/middlewares,再在具体 Agent 的 get_graph() 中加入 middleware 列表。新增前先确认它属于哪一种职责:

  • 资源过滤、权限收敛和默认资源选择应放在 prepare_agent_runtime_context 一类的 Graph 创建前逻辑中。
  • 模型提示注入、工具动态追加、工具结果处理和 state 更新适合做成 LangChain Agent middleware。
  • 文件读写、工具结果卸载和 artifacts 展示应优先复用 create_agent_filesystem_middleware 与沙盒 backend。

仓库中仍保留 DynamicToolMiddleware,但当前内置 Agent 的工具和 MCP 加载已经由 resolve_configured_runtime_tools(context)SkillsMiddleware 承担。新增功能时不要默认复用旧的动态工具中间件,除非确实需要“预注册后按请求筛选”的模式。

本项目基于 MIT License 开源,欢迎使用和贡献。