工具 Runtime 工程
提出问题
工具契约定义“能调用什么、参数和返回长什么样”。工具 runtime 负责“这次调用能不能执行、怎么执行、失败怎么办、谁负责”。
很多线上事故不是因为工具没有 schema,而是因为运行时缺位:
- 模型传了合法订单号,但订单不属于当前用户。
- 写入工具超时后被重试两次,产生重复记录。
- 高风险动作没有确认,模型直接提交。
- 工具失败只在模型回复里出现,系统日志没有 trace。
- 多个客户端各自调用同一工具,权限和审计规则不一致。
工具 runtime 的目标不是增加一层复杂架构,而是把权限、确认、timeout、retry、审计和复用治理放到稳定位置。
场景
在客服后台里,用户请求:
发票如果已经开好了,就帮我重发到这个邮箱 finance@example.com。
这句话看起来只是一个小动作,但 runtime 要回答很多问题:
- 当前客服是否有权查看这个订单?
- 用户是否有权接收这张发票?
- 邮箱是不是当前客户组织里的邮箱?
- 工具是先生成邮件预览,还是直接发送?
- 如果发票系统 8 秒没有响应,要不要重试?
- 如果发送工具超时,如何确认邮件是否已经发出?
- 同一个请求刷新页面后会不会重复发送?
- 日志里应该记录完整邮箱,还是脱敏邮箱?
模型可以判断“用户想重发发票”,但这些执行问题必须由 runtime 处理。
分析问题
问题类型
工具 runtime 主要处理执行类问题。
模型适合提出候选动作、解释工具结果、在错误可恢复时追问用户。runtime 应该负责执行边界和系统可靠性。
收益和成本判断
工具 runtime 的收益包括:
- 防止越权访问和越权执行。
- 降低重复写入和不可逆错误。
- 让高风险动作进入确认和审批。
- 让失败能被重试、降级或转人工。
- 让工具调用可以审计、回放和评估。
- 让同一组工具被多个客户端安全复用。
成本包括:
- 需要统一封装工具执行入口。
- 需要接入权限、确认 UI、日志和监控。
- 需要设计 timeout、retry、幂等和错误分类。
- 需要处理异步任务和人工队列。
- MCP 化还需要协议、部署、版本和客户端兼容管理。
如果工具只做低风险查询,并且调用方固定,runtime 可以轻量。只要工具会写入、影响权益、跨客户端复用或被 agent 自主选择,就需要更完整的运行时治理。
权限
权限不是 prompt 规则,也不是工具 description。权限必须在工具执行前由 runtime 和业务系统共同检查。
权限至少分四层:
常见原则:
- 不让模型传
tenantId、role、isAdmin等权限字段。 - 权限过滤发生在工具执行前,而不是回复生成后。
- 查询工具也要鉴权,尤其是客户数据、文件和历史记录。
- 工具返回值按权限裁剪和脱敏。
- 权限拒绝要返回结构化错误,而不是让模型猜。
确认
确认用于处理“模型可以建议,但不能单独执行”的动作。
需要确认的典型动作:
- 发送邮件、短信、通知。
- 写入 CRM、工单、知识库或代码仓库。
- 发起退款、改套餐、改权限。
- 对外承诺 SLA、价格、合同条款。
- 删除、覆盖、发布或部署。
确认界面应该展示:
- 将要调用的工具和动作。
- 关键参数和影响范围。
- 模型调用理由。
- 数据来源或工具依据。
- 可取消、可编辑或转人工的入口。
确认不是让用户看一段“AI 将执行操作”的空话,而是让人能判断这个动作是否应该发生。
确认还要区分“用户确认”和“业务审批”。用户确认适合收件人、邮件内容、备注文本这类即时动作;业务审批适合退款、改套餐、改权限、发布和删除。前者通常在当前交互里完成,后者应该进入工作流,并记录审批人、审批依据和审批结果。
Timeout
工具调用不能无限等待。不同工具应该有不同 timeout:
timeout 不是单纯技术参数,它会影响用户体验和成本。核心链路里,宁可明确失败并降级,也不要让模型和用户一起等待不确定结果。
Retry
重试可以提升成功率,也可能制造事故。runtime 必须知道哪些错误可重试、哪些不能重试。
可重试:
- 临时网络错误。
- 上游限流后可退避。
- 只读查询超时。
- 幂等写入的临时失败。
不可重试:
- 参数校验失败。
- 无权限。
- 对象不存在。
- 业务规则不允许。
- 非幂等写入且无法确认执行状态。
写入类工具必须设计幂等键。例如重发发票邮件可以使用 requestId 或 ticketId + invoiceId + recipientEmail 作为幂等维度,避免刷新、重试或模型重复调用导致多次发送。
幂等设计要回答三个问题:
- 同一个业务动作如何识别为“同一次”请求。
- 上一次执行状态未知时,如何查询它是否已经生效。
- 重复请求到来时,返回上次结果、拒绝执行,还是创建新动作。
不要把“模型不会重复调用”当作幂等策略。模型可能因为工具超时、上下文压缩、页面刷新或恢复执行而再次发起相同动作。runtime 要能用动作日志和外部系统状态判断是否安全继续。
状态不确定
工具最危险的失败不是明确失败,而是状态不确定。例如发送邮件工具超时,可能是邮件没发出,也可能是发出了但响应丢失。此时让模型自由决定“再试一次”会制造重复副作用。
状态不确定时,runtime 应该优先选择:
- 调用查询状态工具确认动作是否生效。
- 使用幂等键再次提交,让业务系统返回已有结果。
- 将任务标记为
unknown,转人工处理。 - 在最终回复里明确“操作状态未确认”,而不是让模型猜测成功或失败。
写入工具的 error schema 应该区分 FAILED 和 UNKNOWN_EXECUTION_STATE。前者可以按错误类型重试或降级,后者必须先查状态或转人工。
审计
审计日志要能回答六个问题:
- 谁触发了工具调用。
- 模型为什么选择这个工具。
- 调用了哪个工具版本。
- 参数是什么,哪些字段被脱敏。
- 运行时做了哪些权限和确认检查。
- 工具返回了什么,失败时错误类型是什么。
建议记录:
日志要服务复盘,不应该成为新的泄露源。敏感字段需要脱敏或摘要化。
MCP 化
MCP 化适合把工具作为标准能力暴露给多个模型客户端。它的价值在于统一工具发现、调用协议和能力边界,而不是让每个函数都“显得更高级”。
适合 MCP 化的场景:
- 同一组工具要被 IDE、桌面端、后台任务和 agent 复用。
- 工具需要统一鉴权、审计和版本管理。
- 团队希望把能力和客户端解耦。
- 工具集合属于一个清晰领域,例如工单、订单、文档、代码仓库。
不适合 MCP 化的场景:
- 只有一个应用内部使用。
- 工具仍在频繁变化,契约不稳定。
- 权限和审计还没有想清楚。
- 只是为了 demo,把本地函数包装成协议服务。
MCP Server 也不能替代 runtime。它可以承载工具暴露方式,但权限、确认、timeout、retry 和审计仍然要设计。
列举方案
方案阶梯
第一层是直接函数调用,适合内部低风险流程。
第二层是统一执行入口,把所有工具调用经过同一个 runtime。
第三层加入权限和参数校验,防止合法 schema 下的越权对象访问。
第四层加入确认和风险分级,处理写入、高风险和模糊意图。
第五层加入 timeout、retry 和幂等,提升可靠性并避免重复副作用。
第六层加入审计和 trace,让线上问题可以复盘。
第七层把复杂动作放入异步工作流和人工队列。
第八层在确实需要跨客户端复用时 MCP 化。
第九层上线后持续做评估和运营监控。
什么时候简单函数足够
以下情况可以保持轻量:
- 工具只读低敏信息。
- 调用方固定,模型不自主选择。
- 参数来自可信后端状态。
- 失败可以简单重试或重新加载页面。
- 不需要跨客户端复用。
- 普通应用日志已经足够定位问题。
例如“读取当前用户主题配置”或“根据当前页面 ID 查询公开帮助文档”通常不需要完整 runtime。
什么时候需要工程封装
以下情况应该建设工具 runtime:
- 模型自主选择工具或组合多个工具。
- 参数来自自然语言抽取。
- 工具涉及租户数据、客户数据、文件、权限或财务。
- 工具会写入、发送、发布、删除或修改状态。
- 工具调用需要用户确认或人工审批。
- 失败后需要重试、降级、补偿或回滚。
- 工具要被多个客户端或 agent 复用。
- 线上必须满足审计、合规或事故复盘要求。
runtime 的复杂度应该跟风险匹配,不必一步到位,但权限和日志通常不应该拖到最后。
决策判断
方案选型表
反模式
第一种反模式:把权限写在 prompt 里。
“只能查询当前用户数据”必须由系统执行。模型可以遵守,也可能误用上下文或被注入诱导。
第二种反模式:所有工具使用同一个确认策略。
查询公开信息不需要确认;退款、发邮件、删数据必须确认。确认策略应该按风险等级和影响范围设计。
第三种反模式:写入工具没有幂等。
一旦 timeout、重试或用户刷新发生,就可能重复发送、重复创建、重复扣款。写入动作必须先考虑幂等。
第四种反模式:失败后让模型自由解释。
工具失败应该返回结构化错误,由 runtime 决定重试、追问、转人工或降级。模型可以解释,但不能猜测执行状态。
第五种反模式:审计日志记录了太多敏感数据。
审计要可复盘,但不应把密码、完整 token、完整身份证、完整银行卡或敏感文档内容写入日志。
第六种反模式:为了 MCP 化而 MCP 化。
如果只有单应用内部使用,且工具契约和权限还不稳定,先做好本地 runtime 往往更重要。
工程清单
- 执行入口:所有模型工具调用是否经过统一 runtime。
- 权限:是否做用户、租户、角色和对象级鉴权。
- 参数来源:是否区分模型抽取参数和可信系统参数。
- 风险分级:工具是否标注查询、写入、高风险。
- 确认:写入和高风险动作是否有预览、依据、确认和取消。
- Timeout:每类工具是否有合理超时和用户反馈。
- Retry:是否区分可重试和不可重试错误,是否有次数上限和退避。
- 幂等:写入类工具是否有幂等键和执行状态查询。
- 审计:是否记录 traceId、工具版本、调用理由、参数、结果、确认和错误。
- 脱敏:日志和工具返回值是否处理敏感字段。
- 降级:权限拒绝、上游失败、超时和确认取消时是否有明确路径。
- MCP 化:是否真的需要跨客户端复用,是否已有稳定契约和权限策略。
- Eval:是否评估工具选择、参数正确率、权限拦截率和高风险确认命中率。
结论收束
工具 runtime 是工具封装从 demo 走向生产的关键层。契约让工具“说得清”,runtime 让工具“跑得稳、管得住、查得到”。
低风险、内部、确定性调用可以保持简单函数。模型参与选择、参数来自自然语言、工具会写入或影响权益时,就需要权限、确认、timeout、retry、幂等和审计。MCP 化适合跨客户端复用,但它不是治理的替代品;真正的治理仍然来自清晰契约和可靠 runtime。