最初只需要一个订单函数,直接写在请求处理器里很方便。后来增加退款、库存、物流和几个 MCP Server,每个 Agent 都各自实现校验、超时和日志,行为开始不一致。
生产中可以把这些重复职责整理为工具运行时。它可以先是应用内模块,不必立刻成为独立平台服务。重点是所有调用都经过明确的契约、策略和执行路径。
调用请求进入模块时包含什么
模型给出工具名和参数,应用再补可信主体、任务 ID、调用 ID、截止时间和允许能力范围。涉及写操作时,还需要关联业务操作身份与匹配审批。
工具运行时输出实际执行状态、可回填模型的结果、来源信息和受控诊断记录。结果未知必须单独表达,不能与确定失败混成一个布尔值。
这些字段不全部暴露给模型。模型需要理解发生了什么和下一步缺什么;运行记录需要关联版本与执行轨迹;凭据只留在执行环境。
注册表保存能力身份与契约
一个注册项可以包含逻辑名称、工具版本、输入输出 Schema、来源 Server、只读声明、并发约束和实现入口。名称应在当前暴露范围唯一,例如 orders.get 与 inventory.get 不能意外映射到同一个别名。
模型接口可能限制工具名格式,因此 Host 可以生成合法别名,再保存别名到真实工具身份的映射。只做字符串替换却不保存映射,后续日志和审批就难以解释到底调用了哪一项。
注册不等于授权。目录中存在的工具未必适合当前任务,也未必允许当前用户执行。动态 MCP 工具变更时,注册表更新与策略生效要有明确版本。
策略模块判断本次是否允许
策略同时考虑主体、业务对象、当前任务、参数和环境。比如查询本人订单可以直接执行,提交退款需要当前有效批准,生产环境导出客户数据则可能完全不提供给该 Agent。
Prompt 写“不要越权”帮助模型理解意图,但策略是程序实际执行的判断。后端服务也要授权,不能信任“请求来自工具运行时,所以全部放行”。
审批决定应绑定工具契约版本。升级后参数含义改变,即使 JSON 形状相同,旧审批也可能不再适用。策略更新过程中无法判断兼容性时,应保守停止未完成写操作并重新准备可审阅动作。
执行器控制资源与结果
执行器负责分发、截止时间、并发、取消以及错误分类。重试不是所有函数统一加装饰器,而是根据工具契约和后端语义选择。
配套 runtime_registry.py下载 展示只读工具注册、显式允许列表、调用次数和并发上限,并返回 trace。它没有模拟完整生产网关,更不提供真实写工具的幂等保障。
多个工具共享一个下游服务时,除了每工具并发,还要考虑共同的服务配额。排队等待同样消耗用户任务时间,不能把超时只从获得执行槽之后才开始计算。
结果需要经过类型与大小检查再回填。执行器不负责把所有内容写进下一轮 Prompt;它把结构化结果交给上下文模块选择与组织。
操作账本记录真实写入意图
查询通常可以无状态完成,退款等写操作需要稳定身份。操作账本保存意图、参数绑定、批准关联、提交状态和回执,承担重试与恢复的依据。
业务服务的原子更新与下游幂等需要配合。工具平台可以统一要求提供 operation_id,却不能仅通过这个字段保证下游没有重复效果。执行未知时保留 unknown,驱动查询和对账。
审批、执行结果与聊天历史各自记录。用户看到“申请已提交”的答案可以由真实回执生成,但聊天中的这句话不能反过来成为证明执行成功的唯一记录。
MCP 连接管理关注生命周期与隔离
连接模块选择传输、管理 Client 生命周期、发现能力、处理协议兼容与目录刷新。本地 Server 的进程数量需要控制,远程连接和凭据按身份范围组织。
一个共享 Client 的缓存如果没有正确主体隔离,可能让用户甲发现用户乙可用的资源。切换凭据、租户或授权范围时,应按 SDK 语义建立正确的隔离边界,而不是把一个可变全局 Authorization Header 到处复用。
目录刷新应保留当前任务使用的契约快照,或在变更后明确重新校验。Server 重连成功只是传输恢复,不意味着它暴露的工具集合没有变化。
和上下文工程怎样衔接
上下文模块决定当前模型看哪些工具定义和资料;工具运行时校验并执行模型提出的调用;执行结果带来源和状态返回上下文模块,形成下一轮输入。
两边都需要预算,但对象不同。上下文预算控制 Token 与信息选择,执行预算控制次数、时间、并发和费用。只缩短工具描述无法防止无限调用,只限制调用次数也无法避免一个结果占满窗口。
可以为一次调用记录从候选工具、选中工具、执行决定、结果摘要到最终回填的链路。这样模型选错工具与工具执行正确但回填丢字段,可以被分开定位。
正常与失败流程放在一起看
A1042 咨询进入后,策略只开放订单与政策读取。运行时完成两次查询,模型给出条件性答复。用户转入申请流程后,应用创建草稿,展示具体金额;批准通过后才调用执行服务。
若政策 Server 超时,应用说明无法完成当前判断,可以保留已取得的订单事实,但不能猜测政策。若批准过期,重新确认动作;若提交超时,查询操作结果;若权限服务不可用,不默认放行。
这些降级方式由任务语义决定。统一返回空对象让模型“自行发挥”,看似提高可用性,却隐藏了关键缺口。
观测应能区分哪一层慢或错
记录模型等待时间、工具排队时间、执行时间和回填大小。工具总成功率高,但模型频繁选错工具,说明需要改进描述或可见工具集合;模型选择正确而参数持续不合法,需要看 Schema 与参数来源。
写操作重点观察未知结果、重复请求命中、参数冲突和审批失效。只看 HTTP 200 会漏掉工具层错误和业务拒绝。
日志关联 request_id、call_id、MCP 请求及业务 operation_id,敏感参数按用途限制保留。供应商连接错误不应把带凭据 URL 或请求头写进模型可见错误。
怎样演进这套模块
先统一一两个工具的契约和执行路径,再逐步集中策略与连接管理。只有多个应用确实需要共同发布、隔离或运维时,再考虑拆成独立服务。
升级工具时保留版本与变更说明,比较固定任务轨迹中的选择、参数与结果。回滚代码不能撤销已提交业务动作,操作账本和补偿机制仍然必要。
这一设计把模型的灵活选择放进可观察的运行边界。最后一篇会使用实际文件把本地函数、审批模拟和 MCP 连接串起来,读者可以沿源码看到各层职责,而不是只记住组件名字。
继续阅读
上一篇:接入工具以后,系统多了哪些风险:MCP 与工具安全边界。
下一篇:从头接通一个工具系统:Python 实战与 MCP 源码导读。
下载文件、依赖与运行边界见配套指南下载。