Skip to content

02 · 工具、MCP 与 Skills ​

本课交付:工具契约与四种拒绝场景。前置:01 的执行轨迹;课后完成 L2:让契约阻止一次越权,用实际输出证明执行层边界。

视频辅助阅读:今天不coding 视频导读,包含工具调用时间定位,以及 MCP 本地连接、会话和授权的边界校正。

一、场景:这一步要解决什么问题 ​

上一章的助手已经会提出“读取一篇笔记”。现在给它一个合法文档 ID,却发现文档属于另一位用户:如果只检查参数类型,这次请求仍会通过。

本章把工具当作业务接口设计。我们要解决的不只是模型会不会调用,还包括它最多能读什么、空结果意味着什么、失败后能否重试。

二、目标与方案设计 ​

本章目标:设计一个模型能正确选择、运行时能验证、出错后能恢复的工具,并区分协议、规程与权限。资料核对:2026-09-06;下文协议字段示例以 MCP 2025-11-25 工具规范为明确版本参考。

工具契约比工具数量重要 ​

工具是模型与程序之间的接口。名称说明动作,参数描述输入,返回值给出可被后续使用的结果。不要让调用方猜测时间单位、路径基准或空结果的含义。

下面是本专题研究助手的教学契约:

json
{
  "name": "search_notes",
  "description": "搜索当前用户有权读取的笔记,返回摘要与稳定文档 ID;不返回全文",
  "inputSchema": {
    "type": "object",
    "properties": {
      "query": { "type": "string", "minLength": 1 },
      "limit": { "type": "integer", "minimum": 1, "maximum": 5 }
    },
    "required": ["query", "limit"],
    "additionalProperties": false
  }
}

这是契约示意,不能直接当作所有模型 API 的请求体;不同提供方支持的 Schema 范围可能不同。

建议返回 doc_id、title、snippet、source、revision。读取全文再用另一个 read_note 工具,避免每次搜索都塞入大量正文。用户身份由服务端可信会话传入,不能让模型通过参数指定另一个用户来扩大读取范围。

如何判断一个工具粒度合适 ​

工具过细,模型需要多次调用才能获得一次决策所需的信息;工具过宽,则参数复杂、返回过多,也容易隐藏副作用。Anthropic 的工程文章建议围绕实际任务设计工具、明确命名边界,并控制返回信息量。工具设计经验。

以本案例为例:

设计问题调整建议
execute(action, payload)名称与参数无法表达具体边界暴露明确的搜索和读取动作
list_all_notes()一次把整个库送回上下文支持查询、分页与返回上限
search_and_publish()读取与外部写入混在一起搜索与发布分别授权、验收
read_note(id, revision)目标与版本清楚返回稳定来源和截断信息

不要把“拆得越多”作为优化目标。先用真实任务观察错误选择率、无效参数率和多余调用量,再调整接口。

MCP 负责连接能力 ​

MCP 描述应用与能力服务之间的通信。常见服务端能力有:Tools 提供可执行操作,Resources 提供上下文数据,Prompts 提供可复用提示模板。工具可被发现,并通过协议请求调用。官方架构说明。

text
Agent 应用 → MCP 客户端 → MCP 服务端 → 笔记库 / 业务 API

模型工具调用是“模型输出动作请求”的机制;MCP 是应用接入外部能力的一种协议。接入 MCP 后,应用仍需实现任务循环、权限判断、错误处理和验收。

Skills 负责操作规程 ​

Agent Skills 用 SKILL.md 和可选脚本、参考资料、模板描述某类任务的做法。常见加载方式是先读取名称和描述,匹配任务后再读取完整说明及必要资源。格式与加载方式。

例如,本知识库可以把“总结一篇技术文章”的步骤写成技能:标注来源、区分事实与建议、生成复习题、检查站内链接。它描述怎么做,搜索工具提供执行能力;两者可以配合。此处是设计示例,尚未创建技能包。

三、实现拆解 ​

完整工具调用链:六个检查点 ​

  1. 发现能力:应用把允许使用的工具说明交给模型。工具清单应与当前用户、任务范围相匹配。
  2. 生成请求:模型输出工具名称、参数和调用标识;这只是候选动作。
  3. 验证结构:检查类型、必填字段、长度与枚举,不把“JSON 可解析”当成业务有效。
  4. 验证权限:将可信会话身份与目标资源绑定,再执行访问控制。
  5. 执行并记录:保留开始、结束、失败或结果未知状态。
  6. 回传观察:结果关联原调用 ID,让后续决策知道是哪个动作产生了它。

以上是本研究助手的运行时设计。MCP 的 tools/list、tools/call 和工具 Schema 则是协议层定义的能力。MCP 工具规范。

返回值也需要契约 ​

以下为本案例自定义结果格式,不是 MCP 原生响应的完整格式:

json
{
  "ok": true,
  "items": [{
    "doc_id": "note-17",
    "revision": "r3",
    "title": "延时任务",
    "snippet": "用于展示的短摘要",
    "source": "/notes/delayed-tasks"
  }],
  "truncated": false,
  "next_cursor": null
}

truncated 防止模型把被截断的输出理解成全部内容;revision 使后续读取与引用能够绑定同一版本;next_cursor 用来明确继续获取数据的方式。排序分数如果暴露,也应说明它只是检索排序信号,不是结论正确的概率。

协议错误与业务执行错误要分开。MCP 2025-11-25 中,JSON-RPC 请求层问题与工具结果中的 isError: true 是不同通道;调用方应查看结果内容,不能只凭传输成功判断工具成功。错误处理规范。

把错误设计进接口 ​

返回情况应用处理建议
空结果视为成功搜索但没有匹配,允许修改查询
参数无效返回字段级错误,不原样重复调用
临时限流在总预算内按服务提示退避
无权限返回明确拒绝,不尝试换身份
写入超时先查操作状态,再判断能否重试

对于发送、创建和扣款等写操作,超时不等于未发生。工程上可使用业务幂等键和操作状态查询,让重复请求不会重复产生业务效果。

MCP 不会替你完成业务安全 ​

工具标记为只读或幂等,不代表应用可以放弃验证;从不可信服务收到的描述和提示仍然需要按信任边界处理。身份认证回答“谁在调用”,资源授权回答“能访问什么”,模型选择回答“这次想做什么”。这三层不应混为一谈。

OWASP 将过多功能、过大权限和过强自主性列为 Excessive Agency 的主要成因。落实到本研究助手,就是只给查询所需能力,用会话身份检查每次资源访问,并为新增写操作建立独立边界。OWASP LLM06:2025。

Skills:把稳定流程做成可维护材料 ​

Agent Skills 规范要求 SKILL.md 包含名称与描述等元数据,正文描述步骤;可以附带脚本和参考材料。描述应说明何时适用,而不只是写“一个很有用的技能”。allowed-tools 是实验字段,其支持方式取决于具体宿主,不能据此假定实际执行权限。Skills 规范。

本案例可设计如下资料包,这里只展示结构:

text
research-note/
  SKILL.md              适用条件、来源要求、写作和验收步骤
  references/style.md   引文与结论的写作约定
  assets/template.md    问题、证据、边界、复习题模板

规程与工具的变化周期也不同:工具接口变化需要适配代码与 Schema;研究方法变化可能只需调整规程和回归用例。把两者解耦,可以避免每次改写作流程都重做连接层。

推演一次参数正确但权限不足的请求 ​

研究助手以 alice 的可信身份运行,收到 read_note(id='private', revision='1')。字段格式正确,只能说明通过了参数检查;它不能证明 Alice 有权读取该资源。

在离线源码中,读取必须同时匹配文档 ID 与 owner。查不到授权资源时返回 not_found_or_not_allowed,不暴露他人的正文,也不透露资源究竟不存在还是无权限。搜索接口先过滤所有者,而读取接口仍然独立检查,避免调用方绕开搜索直接猜 ID。

这里的 user 参数由测试程序传入,是模拟可信身份,不是真实登录认证。上线时必须从已验证的服务端会话获得身份。示例用手工校验实现这两个工具的必填字段、类型、取值边界及额外字段拒绝;它不是通用 JSON Schema 校验器,也没有实现 MCP 服务端。

四、验证与练习 ​

工程加深:结构化返回与模型结构化输出不是一回事 ​

MCP 的 structuredContent 是工具服务返回的数据;模型的结构化输出是模型生成受约束的数据。前者仍需核对服务来源、字段与业务含义,后者即使格式正确也可能请求错误资源。MCP 2025-11-25 允许定义 outputSchema;声明后,服务端结果必须符合结构,客户端也应验证。输出结构规范

本案例将响应处理分成:传输成功 → 协议有效 → 业务成功 → 输出符合契约 → 可作为当前任务证据。任意一层失败,都不能直接标记“研究完成”。

工具清单也要控制成本和权限 ​

工具很多时,先根据任务筛选候选能力,再让模型选择具体工具;但“没有展示某工具”不是安全控制,执行入口仍需白名单与资源授权。工具目录自身可能过期,所以应记录所用契约版本并拒绝不兼容参数,不能静默改变单位或副作用。

建议对搜索工具做一个小型对照实验:只改名称和描述、只改返回字段、只改默认返回量,每次固定其他条件,观察误选工具、无效参数、重复读取和端到端结果。不要把减少 token 当成唯一胜负标准;删掉版本或适用条件可能让输出更短、答案却更错。这个实验方案受官方工具工程经验启发,本站未报告实测收益。

自测与参考答案 ​

让另一个开发者只看契约,不看实现:他能解释空结果、最大返回量和权限范围吗?若不能,先改契约。

再问:工具返回 HTTP 成功但包含业务错误,是否可以标记完成?不可以。把任意用户 ID 作为模型可填参数是否安全?仅有 Schema 不够,资源授权必须使用可信身份判断。

五、本章小结 ​

模型选择动作,工具契约定义边界,运行时负责执行边界。MCP 连接能力,Skills 组织规程,它们都不替代资源授权。下一章处理另一半问题:即使读到合法资料,也要判断哪些内容应进入当前上下文。

六、参考资料 ​

返回 Agent 专题目录。本文场景与推演为原创教学设计,参考写法及资料边界见专题目录。