跳转至

第 8 章:MCP、工具与 RAG —— 能力如何进入模型上下文

8.1 三类工具来源

MCP tools        ← 外部 MCP server(stdio / SSE / streamable HTTP)
RAG tools        ← 附件解析 + embedding + vector DB
Built-in tools   ← web_search / web_fetch / 本地产品工具

它们在 Web 层最终都被规整成模型可接受的 function tool schema,再由 CustomChatTransport 统一执行/审批。

8.2 MCP 的 Rust 状态模型

AppState 中与 MCP 相关的字段非常多,说明 MCP 不是一个静态列表:

状态 用途
mcp_servers 已建立的 RunningService 连接
mcp_active_servers 当前配置中应保持 active 的 server
mcp_server_pids stdio 子进程 PID,便于清理
mcp_monitoring_tasks 健康检查/自动重连任务
mcp_starting 防止同一个 server 并发 serve()
mcp_last_known_tools 短暂断线时保留稳定 schema
tool_call_cancellations 取消正在运行的 tool call
mcp_reconnect_notify 立即唤醒 monitor,而不必等待 30 秒

这些字段共同形成一个小型连接管理器。

8.3 启动与重连流程

stateDiagram-v2
  [*] --> Configured
  Configured --> Starting: active + start task
  Starting --> Connected: initialize / list tools OK
  Starting --> Disconnected: timeout / transport error
  Connected --> Connected: health check every 30s
  Connected --> Reconnecting: list_tools failed
  Reconnecting --> Connected: backoff + start success
  Reconnecting --> Reconnecting: failure count grows
  Connected --> Stopped: deactivate / app exit
  Reconnecting --> Stopped: shutdown flag

helpers.rs::monitor_mcp_server_handle 每 30 秒或收到 notify 后检查 list_all_tools;失败时删除旧 service、清理 PID、发出状态事件,按 base_restart_delay_ms * multiplier^n 做 capped exponential backoff,然后确认 server 仍 active 再重连。

最值得注意的是幂等保护:boot startup 和前端 activation 可能同时请求同一 server,如果没有 mcp_starting,两个 serve() 会发重复 initialize,streamable HTTP server 可能以 400 拒绝第二个连接。

8.4 工具 schema 是上下文成本

工具不是“白送给模型”的。每个工具的 name、description、inputSchema 都会占用 prompt tokens。Jan 的 mcp-orchestrator 通过 intent classifier、server summaries 和 model filter 选择工具集合,目标是只把当前任务需要的工具给模型。

全部 MCP tools
  → 服务器摘要 / intent 分类
  → selected server names
  → getToolsForServers
  → 规范化 JSON Schema
  → 当前 chat request

这和 RAG 的检索思想相似:不是把所有知识塞进上下文,而是按需选择可用能力。

8.5 Tool approval 的位置

Web 层的 ToolApprovaluseToolApprovaluseToolApprovalRequests 管理用户可见的审批。批准之前,tool call 可能已经作为 assistant 的“待处理意图”出现在 UI;批准之后才真正执行,并把 result 送回模型。

但通过本地 API proxy 开启 server-side tool execution 时,审批边界会改变。文档和配置必须明确指出:UI 中的审批不自动覆盖外部 API 调用。

8.6 RAG 的两条管线

RAG extension 负责产品语义,两个 Tauri plugin 负责系统能力:

附件
  → tauri-plugin-rag:PDF / DOCX / CSV / HTML / XML / 文本解析
  → chunking
  → embedding model(可由 llama.cpp 提供)
  → tauri-plugin-vector-db
  → sqlite-vec 或线性 fallback
  → search tool
  → message context / citations

Vector DB plugin 的 API 包括 create collection、create file、insert chunks、search、list attachments、delete collection 和 chunk text。删除 thread 时,useThreads 也会清理 attachments_<threadId> collection,避免业务数据已删但向量残留。

8.7 为什么工具系统必须读失败路径

  • MCP server 初始化失败不阻塞其他 server。
  • 短暂断线不让工具 schema 反复消失,减少上下文漂移。
  • tool call 可取消,避免应用退出时后台子进程继续跑。
  • JSON Schema 需要适配 llama.cpp GBNF 限制。
  • RAG plugin 不可用时,产品仍应允许普通聊天。

Jan 的工具架构本质上是“可失效能力”:工具是增强项,不应让聊天核心变成全有或全无。