工具
工具的分类
| 工具类型 | 调用方向 | 作用对象 |
|---|---|---|
| 感知工具 | Agent 主动调用 | 获取信息 |
| 执行工具 | Agent 主动调用 | 改变世界 |
| 协作工具 | Agent 主动调用 | 驱动其他 Agent 或人类 |
| 用户沟通工具 | Agent 主动调用 | 向用户传递信息 |
| 事件触发工具 | Agent 注册、外部触发 | 驱动 Agent 开始执行 |
工具的设计的通用原则
工具的表现形式
- 专用代码工具:结构化的函数调用,确定性高、可测试,但每个工具会占据数百个 token,且数量膨胀会破坏 KV Cache。
- skill+通用工具:用自然语言编写的 Skill 文档来描述操作流程,Agent 通过终端或代码解释器来执行,只需少量的通用工具就能覆盖大量场景
怎么选择专用代码工具还是 skill+通用工具?
- 参数复杂度:涉及嵌套对象、多字段联合校验、复杂类型约束
- 工具变更频率:
- 模型能力:
工具的粒度:分离还是整合
粒度过细会导致工具数量激增,增加 LLM 的选择负担;粒度过粗又会使单个工具过于复杂。当工具数量过多时(比如超过 100 个),即使是最先进的大语言模型也容易在工具选择上出错。
判断标准:功能相似性以及场景重叠度
当功能虽然相似但参数集差异很大、或者某个功能的使用频率极高时,保持独立反而更合理。
工具描述
- 什么时候用比用来做什么更重要。use when
- 添加一些反例,Do not use when
- 参数描述应该用具体的例子代替抽象的规范
- 返回值也可以用json schema来描述,或者用示例来说明.对于耗时较长的工具,注明执行代价有助于 LLM 合理规划调用顺序
- 为每个工具附带 1-5 个真实的调用示例
工具的通用性设计
一般来说,通用工具要优于专用工具,给agent一个代码解释器,要比设计加减乘除的专用工具更有价值。前者可以搭配数学计算库完成更多样的计算任务,有时候通用工具的设计也能覆盖到考虑不足的地方
但是对于有特殊权限、复杂配置或有安全风险的操作,封装良好的专用工具仍然是必要的。
参数传递保真性
模型感知到的世界和工具操作的世界是有差异的,要谨防静默参数注入和静默参数转换
如果必须要进行参数的规范化,一定要在工具的文档中明确说明,并且在工具调用前后进行参数的验证和转换,确保传递给工具的参数与模型预期的一致。
感知工具
感知工具设计的核心问题之一,是控制返回信息量,让 Agent 按需获取信息,而不是一次性把所有内容塞进上下文。
当返回结果过长时,可以采用三种方式控制:
- 压缩:超过一定阈值时,根据 Agent 当前任务对内容做上下文感知压缩,保留与问题最相关的信息。
- 分页 / limit:搜索工具只返回前若干条候选结果,read 工具通过 offset/limit 只读取文件的一部分,由 Agent 决定是否继续。
- 显式截断:如果内容被截断,必须明确告诉 Agent“当前展示了多少、还剩多少、如何继续读取”,避免 Agent 误以为已经获得完整信息。
另一个重要设计就是工具的粒度权衡
执行工具
执行工具会真实修改外部环境,因此相比感知工具需要重点保证安全性和可靠性。
执行前检查 → 执行时隔离/审查 → 执行后验证 → 出现异常时安全恢复
执行前检查
- 输入校验
- 权限控制
- 提议者-审核者:事前审批与事后验证
执行时隔离/审查
- Sidecar 机制:与主思考并行的安全校验。只看这个工具调用是否安全,是一个分类型问题,因此可以用小模型
1 | 主模型生成: |
Reviewer:
“这个操作从任务角度应不应该做?”
Sidecar:
“这一次具体的 Tool Call 安不安全?”
- 执行环境的隔离与沙盒:进程级隔离:对低风险的 Agent,可以直接在本地环境中执行代码,例如 Claude Code、Codex、OpenClaw 等都是直接在本地环境中执行代码的。Agent 生成的代码和命令与本地用户拥有相同的权限,因此可以访问、修改或删除用户的任意文件。
容器隔离:Docker 等容器提供独立的文件系统和网络栈,隔离更完整,但与宿主机共享内核,内核漏洞仍可能被利用来逃逸。
microVM/虚拟机:Firecracker 等 microVM 提供带独立内核的硬件级隔离,是运行完全不可信代码的最强层级。
执行后验证
如果操作结果可以被验证,就应该自动验证
“执行-验证-反馈”的闭环
还要考虑操作的幂等性,多次操作和单次操作的结果是否一致,避免重复执行带来的副作用。
协作工具
协作工具三大原语:创建/取消、消息传递、Agent 发现
子 Agent 的 Prompt 怎么设计:
角色是谁
↓
拿到了哪些上下文
↓
任务边界是什么
↓
输出格式是什么
人工介入的艺术:
- 超时和降级策略。
- 反馈循环的建立。
事件触发工具
定时器(set_timer)处理依赖物理时间的事件。
后台任务监控(monitor_shell)处理来自异步执行的工具或命令行任务的事件。
外部事件通道(connect_channel)
关键在于触发条件的过滤和事件载荷的设计,让世界能够主动唤醒 Agent
用户沟通工具
用户沟通工具用于 Agent 主动向用户传递信息,
主要解决异步 Agent 中“如何触达用户”的问题。
典型工具:
- reply_to_user
- send_card_to_user
- send_user_notification
核心设计
-
异步消息模式
用户不需要一直停留在当前 session,
Agent 可以在任务完成或事件发生后主动联系用户。 -
多渠道选择
渠道包括 App 消息、Push、短信、邮件、电话等。
根据:
- 消息紧急程度
- 用户状态
- 内容性质
- 用户偏好
选择合适渠道,并避免重复打扰。
-
用户召回
长任务完成、事件发生或周期任务完成后,
通过通知重新获取用户注意力。 -
消息形态
除文本外,还可以支持图片、文件、结构化卡片和 Generative UI。
如何从成百上千的工具中选择合适的工具
模型原生工具发现方法(主动发现)
主动声明—语义匹配—动态注入
在系统提示词中仅保留少数几个常用的工具,外加一个工具搜索工具,agent用自然语言描述需求即可检索并加载
两个工程细节
- 高效工具搜索需要工具组织的层次化

- 注意KV Cache的使用
这种方式的缺点就是工程上还是很繁琐的,要支持离线的增量更新索引,要考虑KV Cache的使用,弱模型要进行专门的训练
Skills:把工具发现变成“按需查阅”
不再需要那套 “嵌入索引 + 语义匹配” 的基础设施。
Agent 启动时只看到一份薄薄的目录——每个 skill 的 name 与 description(合计数百 token)。当当前上下文真的需要某种能力时,模型才去读取对应的 sub-skill,并顺着其中的引用再往下一层,读取具体的脚本或子文档。“发现” 由模型在上下文里的实际需要驱动,而不是在任务开始时对初始查询做一次性预匹配。
| 主动工具发现 | Skills | |
|---|---|---|
| 核心 | Agent 主动声明能力缺口 | Agent 主动读取 Skill |
| 发现方式 | 语义检索 | 目录 + 文件阅读 |
| 是否需要 Embedding | 通常需要 | 不需要 |
| 是否需要 Tool Index | 需要 | 不需要 |
| 工具定义 | JSON Schema | 自然语言 |
| 灵活性 | 较强 | 很强 |
| 模型要求 | 较低 | 较高 |
| 人类维护 | 相对复杂 | 简单 |
缺点就是,模型需要有较强的阅读理解能力和推理能力,才能在目录和文档中找到所需的工具,并正确理解其使用方法。
Skill 对模型提出了更高的要求,在参数复杂的情况下也更容易出错。
这里将主动工具发现和skill并列并不是说它们是互斥的,而是说它们在工具发现的方式上有本质区别。主动工具发现是通过语义检索来找到工具,而 skill 是通过阅读文档来找到工具。通常架构上Skill告诉 Agent:这个任务应该怎么完成。然后调用多个 Tool得到结果,Skill 指导 Agent 如何组织结果
