第 10 章:MCP、Skills 与延迟发现 —— 能力多,但上下文不必重
MCP 解决“如何连接外部工具”,Skills 解决“如何告诉 Agent 正确地使用能力”。DeerFlow 把二者分开治理,又在运行时让它们互相约束。
MCP 配置与缓存
MCP server 定义位于 extensions_config.json,而主应用配置在 config.yaml。分开是因为 MCP/技能启用状态可通过 Gateway 在线编辑,需要独立重载;Agent 每次组装工具时重新读取 extensions config,再从缓存取已初始化工具。
支持的 transport 由 MCP adapter 处理,build_server_params() 将声明式配置转换为 client 参数。应用启动时初始化会话池与工具缓存,Agent 构建不应在请求热路径重新握手所有 server。
MCP 工具的路径翻译
本地 stdio MCP 可能返回宿主文件 URI,也可能在当前工作目录生成文件。mcp/tools.py 在调用前后做 workspace snapshot,并将可识别的本地路径改写为 Agent 虚拟路径;裸文件名只有在唯一匹配时才改写。
这是一个经常被忽略的边界:外部工具和沙箱若使用不同路径空间,模型会得到一个自己无法再次读取的路径。DeerFlow 通过转换层让 MCP 输出重新进入统一 workspace 语义。
Session Pool 的意义
MCP 工具包装器不为每次 call 新建 client,而是从 session pool 借用连接。并发、超时、OAuth 与 server 重启都集中在这一层。工具对象只暴露 LangChain BaseTool 接口,不把连接生命周期泄露给 Agent。
Skills 的三类存储
Skills 大致来自:
skills/public:仓库内置、只读;skills/custom或用户目录:用户可写;- 集成安装的 provider skill packs:全局安装、按用户启用与凭据隔离。
Loader 解析 SKILL.md frontmatter、描述和 allowed-tools,并通过 storage 抽象合并。Custom agent 还能配置自己的 skills allowlist;子代理得到父子 allowlist 的交集。
发现不等于激活
这条边界必须记牢:
模型在 prompt 里看见某技能,只说明它可发现。只有完整技能内容被可信地加载,相关工具策略才生效。否则一个恶意技能仅凭 metadata 就能扩大能力或隐藏原工具。
Slash 激活的确定性
用户以 /skill-name 开始一轮时,SkillActivationMiddleware 确定性加载对应 SKILL.md。它用 owner token 标记激活来源,让 SkillToolPolicy 确认这是本中间件产生的可信状态,而不是客户端伪造的消息字段。
模型自主发现则通过 describe_skill 和文件读取发生。读取路径要落在允许的技能投影中;DurableContext 观察真实读取结果并记录 reference。
延迟 MCP 工具搜索
tool_search.enabled 和 skills.deferred_discovery 是两套独立开关:
- 前者控制 MCP/tool schema 是否延迟;
- 后者控制技能内容是否只按需描述/加载。
延迟工具目录保存名称、描述、参数摘要和 routing metadata。搜索支持正则/关键词评分;MCP routing middleware 可根据当前请求提示自动晋升 top-k,然后 DeferredToolFilter 才决定本轮向模型隐藏哪些 schema。
顺序必须是 routing → filter。反过来,路由器连候选目录都看不到。
Skill 安全审查
内置 review_skill_package 是只读分析工具。它对本地包、压缩包或 inline 内容生成结构化审查,模型可见部分经过长度限制和标签中和,完整 raw payload 只放 tool artifacts。审查本身不会安装或激活技能,保持“评估”和“变更能力”分离。
skill_scan 则是确定性安全扫描配置,可在安装/启用路径阻止危险包。LLM review 提供语义判断,扫描器提供可重复门禁,两者互补。
为什么 MCP 与 Skills 不合并
MCP tool 是可执行接口,Skill 是操作说明与策略包。同一 MCP server 可被多个技能以不同工作流使用;一个 Skill 也可能组合内置、MCP 和 CLI 工具。把二者一一绑定会降低复用,还会混淆“发现工具”与“授权行为”。
源码锚点
下一章回到用户眼前:多种事件、历史和乐观状态如何折叠成一条稳定对话。