简要结论
从名称、Schema、规范结果、错误语义和幂等性设计可靠工具。
Tool 是模型与真实世界之间的函数接口。描述模糊、参数宽松或错误不透明,都会让模型在错误输入上反复试探。可靠 Tool 需要同时照顾模型选择、运行时校验、持久结果和人工审计。
最小工具插件
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'issue-reader'
export const inject = ['tools']
export function apply(ctx: Context) {
ctx.tools.register(defineTool({
name: 'get_issue',
description: 'Read one issue by numeric id. This tool never updates it.',
parameters: {
id: { type: 'number', required: true, description: 'Positive issue id' },
},
output: {
schema: { type: 'string' },
render: (_args, value) => [{ type: 'text', text: value }],
},
async execute(args) {
return `Issue #${args.id}`
},
}))
}
inject: ['tools'] 让插件等待工具注册表;defineTool 把参数转换成模型可见 Schema,并在 execute 前校验。规范返回值由 output.schema 描述,render 再生成进入会话的内容。
名称和描述
- 名称使用稳定动词,如
get_issue、update_issue,不要用issue_magic。 - 描述说明做什么,也说明不做什么。
- 读写操作分成两个 Tool,便于审批和最小权限。
- 参数描述写业务语义,不重复类型名称。
Schema 应拒绝含糊输入
能用枚举就不要自由文本,能用结构化对象就不要让模型拼接 Shell。时间、路径、ID 和分页都要写清边界。无效输入应在执行副作用前失败。
配置同样应有 Schema。不同部署需要改变的超时、端点和重试次数不要硬编码;无效配置应在插件加载时响亮失败。
输出分两层
规范值服务于代码和测试,渲染内容服务于模型与会话。避免把整个远程响应原样塞进上下文:
- 保留状态、稳定 ID 和关键字段;
- 对超长列表分页或摘要;
- 秘密和认证 Header 永不进入 render;
- 错误返回可恢复信息,不返回内部堆栈与凭据。
副作用工具的保护
对于 update_issue:
- 支持
dryRun或 preview; - 要求明确目标 ID 与期望旧状态;
- 使用幂等键避免重试重复写入;
- 返回变更前后摘要与远端操作 ID;
- 响应取消信号,设置合理超时;
- 将批准策略放在调用边界,而不是藏在实现内部。
测试矩阵
| 用例 | 预期 |
|---|---|
| 合法最小参数 | 返回符合 output schema 的值 |
| 缺必填字段 | execute 前拒绝 |
| 不存在的目标 | 可解释、可分类错误 |
| 重复相同请求 | 不产生重复副作用 |
| 中途取消 | 停止并保留一致状态 |
| 超长响应 | 有界渲染,不淹没上下文 |
还应监听 tools/result 或检查 Session Event,确认持久结果和调用方看到的内容一致。
下一篇学习子智能体编排。