Part B · 横切深挖 · B02

Tool and MCP interface designTool / MCP 接口设计

口述 2 min 追问 6 层 适合 垂直 Agent 研发, FDE, Solutions
Prompt 题面

先想清楚再开口

你要把公司内部的订单、退款、工单系统接给客服 Agent。后端同事说:「我们已经有 40 个 REST 接口,自动生成一个 MCP server 全部暴露出去就行,模型自己会挑。」你怎么设计这层工具接口?怎么防止它选错工具、越权读别人的订单、重复退款?

题面为本书自拟的训练题,通常是在 A01 / A03 / A04 / A05 之后被追问出来的;它不代表任何公司的真实面试题或真实系统。

约束

约束取值(练习设定)
现有接口40 个 REST 接口,含查询、改地址、退款、建工单,也含几个运维用的管理接口
调用者终端用户通过客服 Agent 使用;Agent 在服务端运行
副作用退款、改地址、建工单都有副作用;退款接口超时后结果未知的情况时有发生
权限用户只能看、只能操作自己名下的订单
模型通用 LLM,会选错工具、会填错参数、会在出错后反复重试
协议工具通过 MCP 暴露给 Agent;规范细节以 MCP 规范 2026-07-28 版为准
答到一半再点开:面试官补了一句

「物流跟踪要接一家第三方公司提供的远程 MCP server,它的工具名、描述和 schema 都由对方维护,随时可能更新。」

Answer 参考回答

先口答,再展开

展开参考回答

该先问的问题

  1. Agent 以谁的身份调用工具?是用户本人的会话凭证,还是一个服务账号?这决定鉴权放在哪里。
  2. 40 个接口里,哪些有副作用、哪些能撤销?下游支持按操作 ID 去重和查询吗?这决定写工具要不要带幂等键、结果未知时怎么办。
  3. 客服这个任务真正需要哪几个动作?管理接口有没有任何理由暴露?这决定暴露面有多大。
  4. 哪些工具是自己团队维护的,哪些来自第三方?描述和 schema 变更谁来审?这决定对工具定义本身信任到什么程度。
  5. 出错时模型能不能自己改参数重试,还是必须停下来交给人?这决定错误信息要写给谁看、怎么写。

一句话框架

工具是给模型用的产品接口,不是后端 API 的镜像:按任务收窄、读写分开、关键参数用 ID 和枚举约束;模型只提议,执行端按用户权限和业务规则校验,并用稳定的 operation_id 保证副作用只发生一次;工具的描述和返回内容也都是不可信输入。

设计取舍表

设计点采用否决的备选什么证据会让我改
粒度按任务包装的窄工具:查我的订单、申请退款、建工单,每个只做一件事,内部可以组合多个后端接口40 个接口一对一自动生成,全量暴露评测显示某个任务需要的两三步组合调用反复出错,就把它们合成一个任务级工具;反过来,某个工具经常被用在不该用的场景,就拆开或改名
名字、描述与 schema名字用「动词 + 对象」;描述写清什么时候用、什么时候不用、参数格式和单位;关键参数用 ID、枚举和取值范围约束,不用自由文本承载;返回用结构化字段沿用后端字段名和接口文档原文评测里选错工具的样本集中在某两个工具之间,先改描述、再考虑合并
暴露面只暴露任务需要的工具,读写分开;会话读过不可信内容之后,写工具改为必须确认;管理接口永不暴露给面向用户的 Agent一个 manage_order(action=…) 大工具,靠参数区分读写不改管理接口的结论;其余按任务评测结果增减
权限工具以用户本人身份执行,服务端对每次调用鉴权;模型传来的订单号、句柄只是候选值,服务端每次校验它是否属于这个用户服务账号调用,在 prompt 里告诉模型「当前用户是谁」不改;让模型记住用户身份不是权限控制
副作用用户确认一个具体动作时生成稳定的 operation_id,写工具必须带上;执行端按它去重,额度和次数与提交一起原子校验;结果未知先按 operation_id 查询,查不清就对账或转人工在描述里叮嘱模型「不要重复调用」只有三种情况才自动重试:下游在有效期内按同一业务交易 ID 去重;唯一约束和业务写入在同一事务里;或者查询明确证明这笔操作的终态是未生效或失败。查询结果是阴性但不是终态,就过了对账窗口再查,或者转人工;网关单独加一张账本不够(下游已退款、网关没来得及记结果就崩溃时,本地唯一键既确认不了成功,也不能安全重发)。都做不到,就把结果未知交给人,不自动重试
错误回传模型能自己纠正的错误(格式、取值范围、业务规则)作为工具结果返回,说清哪个参数错、合法值是什么;遇到权限和策略拒绝,对模型标「不可重试」并给出下一步,但给用户看的说法不暴露资源是否存在;完整拒绝原因只留在服务端审计里;不回传堆栈和内部细节直接抛 500 或返回一句「invalid」同一个错误被模型用相同参数反复重试,说明错误信息不可操作,改写它
工具定义与返回的信任工具返回的内容按不可信数据处理,进入模型前按输出 schema 校验;第三方 server 的描述和 annotations 不作为放行依据;工具名加服务前缀;我方客户端固定已审核的定义,变更审核后才生效;第三方工具只授予最小权限、只读,出站受监控看 annotations 里标了只读,就跳过确认不改;描述和 annotations 由 server 自己声明,只有可信的 server 才值得参考
Two-minute English 口述

两分钟,先结论后展开

展开 2 分钟英文口述稿

I'd design tools as a product interface for the model, not a mirror of the backend.

First, shape. Instead of exposing forty endpoints, I'd expose a few task-level tools — look up my order, request a refund, open a ticket — with verb-object names, descriptions that say when to use and when not to use them, and parameters constrained by IDs, enums and ranges. Admin endpoints are never exposed to a customer-facing agent.

Second, the model only proposes. Every call runs with the user's own credentials and is authorized on the server. An order ID from the model is a candidate; the server checks it belongs to this user on every call.

Third, side effects happen once. When the user confirms a specific refund, the system creates a stable operation ID. Retries reuse it, the executor deduplicates on it, and limits are checked atomically with the commit. If a call times out, we look the operation up before retrying.

Fourth, errors are written for the model. Fixable errors say which parameter is wrong and what's valid; permission and policy denials are marked not retryable.

Finally, tool output is untrusted input, and so are third-party tool descriptions. I pin their versions, review changes, and don't let their own annotations decide what needs confirmation.

Follow-ups 追问

一层一层往下问

  1. 为何不用备选为什么不把 40 个接口全暴露出去?模型够聪明,会自己挑。
    先口答,再展开要点
    • 工具越多、彼此越相似,选错工具和填错参数的机会就越多;这不靠直觉判断,用同一评测集比较「全量暴露」和「任务级工具」两种设计的选择准确率和任务完成率。
    • 暴露面就是攻击面:管理接口一旦出现在工具列表里,一次注入或一次选错就可能调用它。
    • 工具定义每轮都在上下文里,数量越多,每轮的 token 越多;定义稳定、顺序固定,才不会打乱前缀缓存(B03)。
    • 什么证据会让我放宽:某些高级用户确实需要更多工具时,按角色分组暴露,而不是一次全给。规范也允许 server 按调用者的授权返回不同的工具列表。
  2. 需求变化物流跟踪要接一家第三方的远程 MCP server,工具定义由对方维护。
    先口答,再展开要点
    • 对方的描述和 annotations 只是声明:规范要求客户端在 server 不可信时把 annotations 当作不可信信息(MCP 规范 · Tools,2026-07-28 版)。是否需要确认,由我方的策略决定。
    • 客户端把对方 tools/list 返回的描述交给模型,所以恶意或被攻破的 server 可以在描述里藏指令。对方改了定义,要等客户端重新获取并接受新列表才会影响模型:规范允许工具列表随时间变化,声明了 listChanged 且客户端订阅时会收到变更通知,列表还可能被缓存,旧会话未必立刻看到新描述。
    • 「固定已审核的版本、记录定义哈希、哈希一变就暂停该工具、审核后再启用」是我方客户端的策略,不是 MCP 自动提供的保证。
    • 哈希只覆盖定义:定义不变,对方服务器的代码和返回内容照样可以变。所以还要给第三方工具最小授权(只读、只拿运单号)、监控它的出站和返回,并定期跑行为回归,而不是只盯哈希。
    • 它返回的物流信息也是不可信数据:只作为数据放进上下文,不能触发写工具。
    • 只发给它完成任务所需的最少字段(运单号),不发用户手机号和地址全文;工具名加服务前缀,避免和自家工具重名。
  3. 失败反证用户在对话里念了一个别人的订单号,模型照着调用了「查询订单」。
    先口答,再展开要点
    • 这正是「模型传的 ID 只是候选值」要挡的情况:服务端按用户凭证鉴权,订单不属于他就返回「未找到」,不区分「不存在」和「无权访问」,避免泄露订单是否存在。
    • 句柄同理:服务端返回给模型的购物车号、会话号是名字,不是权限;每次带着它调用,都要重新校验调用者是否有权操作它。
    • 发现:审计日志统计「归属不符」的拒绝次数,按用户和会话告警;把这类样本放进评测集,按「是否发生了越权读取」计分。
  4. 副作用退款工具超时了,模型决定再调一次。
    先口答,再展开要点
    • 超时不等于失败:退款可能已经完成。写工具带着用户确认时生成的 operation_id,执行端按它去重,所以重试不会退两次。
    • 模型的正确动作是先调用「查询操作结果」,而不是直接重试;查不清就进对账,或者转人工,并如实告诉用户「处理中」。
    • 额度和次数的校验与提交在账本里原子完成,否则两个并发会话会同时通过(与 A03 的口径一致)。
    • 能不能自动重试要看下游:只有三种情况才自动重试:下游在有效期内按同一业务交易 ID 去重;唯一约束和业务写入在同一事务里;或者查询明确证明这笔操作的终态是未生效或失败。查询结果是阴性但不是终态,就过了对账窗口再查,或者转人工。三样都做不到时,结果未知就停下交人,不自动重试(与 B08 一致)。
  5. 错误设计模型收到一句「invalid request」,用同样的参数连续重试了 10 次。
    先口答,再展开要点
    • 错误信息要写给模型看:哪个参数错、合法格式或取值范围是什么、能不能重试。规范也把输入校验错误和业务逻辑错误归为工具执行错误,放在工具结果里返回,供模型自我纠正。
    • 权限和策略拒绝要明确标「不可重试」,并给出下一步(例如转人工),否则模型会换着参数试探边界。
    • 编排层兜底:同一工具、同一错误连续出现 N 次就停止,交给人或降级,不能只靠模型自己察觉在打转。
  6. 评估你怎么知道这套工具接口设计得好不好?
    先口答,再展开要点
    • 固定任务集,分项计分:工具选择正确率、参数有效率、每个任务的调用次数、越权尝试被服务端拒绝的次数、同一错误的重复次数、副作用是否只发生一次。
    • 改描述、改粒度都当作版本,在同一任务集上对比;描述的一句话改动就可能改变选择行为,所以要回归。
    • 故障注入:模拟超时、重复响应、结果未知,检查是否出现重复副作用;这一项按「最终系统状态」计分,不按模型说了什么计分。
Failure Modes 失败模式

这些地方最容易栽

把后端 API 原样镜像成工具
  • 症状:模型经常在两三个相似接口之间选错,填的参数用的是后端的内部字段名;每轮的 token 很高。
  • 根因:工具按后端的组织方式暴露,而不是按任务;描述写给开发者看,没有说什么时候该用、什么时候不该用。
  • 防线:按任务包装窄工具,描述写使用边界,参数用 ID 和枚举约束;用选择准确率评测每次描述改动。
把模型给的 ID 当成授权
  • 症状:用户能查到别人的订单,或者通过猜句柄操作别人的购物车。
  • 根因:工具信任了模型传来的参数,服务端只校验格式,不校验归属;或者用了服务账号,所有调用都有全量权限。
  • 防线:以用户身份调用,服务端每次校验资源归属;句柄是名字不是权限;越权拒绝进审计和评测。
超时重试造成重复副作用
  • 症状:同一笔退款执行了两次,或者同一个问题建了两张工单。
  • 根因:写工具没有稳定的操作 ID,超时后模型或编排层直接重试;下游不去重。
  • 防线:用户确认时生成 operation_id,重试复用;执行端按它去重,额度与提交原子完成;结果未知先查询,查不清就对账或转人工。下游既不能在有效期内按同一 ID 去重、也没有同事务唯一约束、查询又证明不了终态时,不开放自动重试;查询阴性但非终态,过对账窗口再查或转人工。
第三方工具定义被悄悄改了
  • 症状:某个第三方工具上线后行为变了,模型开始在调用它之后做一些用户没要求的事。
  • 根因:客户端重新获取了变更后的定义,没有审核就交给了模型;客户端还按对方声明的 annotations 放宽了确认。另一种情况是定义没变,对方服务器的代码行为变了。
  • 防线:我方客户端固定已审核的定义并记录哈希,变更暂停、审核后启用;不按第三方 annotations 放行;第三方工具最小授权、出站监控、定期行为回归;返回内容按不可信数据处理。
Cross-references 回链

原理去哪里补

  • AI 4.1 Tool Use 基础:function calling 的本质,schema 设计对成功率的影响 · AI 系统工程手册
  • AI 6.6 提交点、稳定 operation_id 与幂等重试 · AI 系统工程手册
  • DV ch12 工具实现与 MCP 服务器开发 · CCDV 备考手册
  • AR ch11 工具接口设计 · CCAR 备考手册
  • AR ch12 MCP 集成 · CCAR 备考手册
  • A01 改代码的 Agent:文件与命令类工具的权限边界
  • A03 客服 Agent:退款的 operation_id 与账本原子提交
  • A04 受监管文档审查 Agent:模型没有写入或发送工具
  • A05 浏览器 Agent:不可逆动作前停下
  • B07 注入、权限与人工放行点
  • B08 错误分类、重试、幂等与补偿
Your Turn 本人填写

只写真实经历

只写真实经历,没有就空着,不编。公开版只有空表;填好的版本存在自己的私用练习记录里。

场景当时发生了什么我亲自做了什么(团队 / AI 做了什么)怎么发现的,结果和证据之后怎么防
模型选错工具或填错参数
工具调用产生了重复或越权的副作用

练习记录

日期口述用时脱稿?答不上的追问下一轮修正(≤2)