杨轲Blueeon
26-05-08 11:33 微博认证:科技博主

# 给 AI Agent 设计工具的最佳实践
AI Agent 之所以能力比直接使用 LLM 更强,来自于环境和运行在环境中精心设计的工具。直接将已有API粗暴的转化为Agent工具,虽然能用,但是往往伴随着额外的工具组合调用的成本,甚至引入更多的不确定性。AI Agent 的核心工具需要精心设计。

目前业内并没有四海皆准的唯一正确答案,这篇文章将基于 Anthropic、OpenAI、Block(60+ MCP 服务器)、GitHub、Phil Schmid、arXiv 论文等多个来源的建议和经验,加上我们自己在开发 [LinklyAI](http://t.cn/AXIRlLp9) 的 Agent 工具的实践经验撰写,试图整理出一份当下对 Agent 工具的设计 “共识”。

## 核心原则
1. **为结果设计,不是为接口设计。** 好的 AI 工具不是 REST API 的薄封装,而是把一个完整的用户工作流打包成尽量少的调用。让 Agent 少做编排,多拿结果。
2. **工具越少越好,描述越清楚越好。** 实践中收敛到每个 Server 5-15 个工具。一项对 856 个 MCP 工具的研究发现,97.1% 的工具描述存在质量问题,56% 连基本用途都没说清。准确简洁的描述,就能提升任务成功率 5-15 个百分点。
3. **每个 token 都是成本。** 返回高信噪比、分页、截断的输出;减少类似UUID之类编码,而用name之类的有意义的字符串替代;参数尽量扁平化;错误信息要教 Agent 下一步怎么修复。

## 十大设计原则
> 按出现频率排序

### 1. 面向结果设计,而不是面向接口

不要把每个 API 端点都暴露成一个工具。把多个内部调用合并成一个面向任务的工具。

**反面**:`get_user` → `list_orders` → `get_shipment`(Agent 需要调三次)
**正面**:`track_order(email)`(一次搞定)

Block 的 Linear MCP 从 30+ 工具精简到 2 个;GitHub Copilot 从 40 个砍到 13 个,任务成功率提升 2-5 个百分点,延迟降低 400ms。

### 2. 控制工具数量(5-15 个/Server)

默认工具绝对不是越多越好,超过 20 个工具,模型的工具选择准确率急剧下降,切勿过渡依赖模型挑选工具的能力。5 个 MCP Server 可能在用户还没说话之前就消耗 55K token。

做法:一个 Server 只做一件事,删掉没人用的工具,不常用的工具用动态发现(Tool Search)延迟加载。

### 3. 工具描述就是 Prompt,要像写 Prompt 一样写

一个好的描述应该包含六个要素:

- **用途**:这个工具做什么(一句话)
- **何时使用**:在什么场景下应该调用
- **何时不使用**:什么情况下不该调用
- **参数说明**:格式、单位、默认值、允许值
- **限制**:边界、副作用
- **示例**:至少一个具体的调用示例

把它当作给新员工写入职文档——把隐含的上下文全部显式化。

### 4. 命名清晰,带命名空间

格式:`{服务}_{动词}_{名词}`,snake_case。

**反面**:`get_data`、`process_request`、`create_issue`
**正面**:`slack_send_message`、`linear_list_issues`、`sentry_get_error_details`

多个 MCP Server 同时存在时,不带前缀的 `create_issue` 会让模型搞不清该调哪个。

### 5. 参数扁平化,用枚举约束

- 参数放在顶层,不要嵌套对象(模型容易在嵌套结构里编造键名)
- 有限选项用 `enum`,不要在描述里写"可选值为 foo/bar/baz"
- 用 JSON Schema 的 `minimum`、`maximum`、`pattern` 做约束
- 尽量提供合理默认值,减少模型的决策负担
- 先做参数校验,返回结构化的校验错误让 Agent 自我修正

### 6. 输出要精简,为 token 效率优化

Anthropic Claude Code 默认截断工具输出到 25,000 token。Block 对超过 400KB 的文件直接报错并建议用 `sed`/`head`。

- **分页**:返回 `limit`、`offset`、`has_more`、`total_count`
- **在源头过滤**:不要把全部数据丢给模型去筛
- **去掉低价值字段**:UUID、MIME type、内部 ID——除非后续调用需要
- **提供详略开关**:`response_format: concise | detailed`,让 Agent 自己选
- Markdown/XML 格式通常比原始 JSON 更省 token、模型也更容易解析

### 7. 用语义标识符,不用 UUID

把 UUID一类的ID,解析成人类可读的名称再返回。Anthropic 的实测显示这能显著减少后续调用中的幻觉。

### 8. 错误信息要教 Agent 怎么修复

**反面**:返回 Python 堆栈跟踪
**正面**:`"未找到用户。请尝试用邮箱搜索。示例:search_user(email='jane@acme.com')"`

好的错误信息包含四个部分:出了什么问题、期望是什么、一个正确输入的示例、1-2 个具体的修复建议。

### 9. 用评估驱动迭代

Anthropic 最强的元建议:**把工具设计当作非确定性工程,用 eval 驱动。**

- 生成几十个真实的多步骤测试任务
- 跑 Agent 循环,记录每次工具调用、错误和 token 消耗
- 让模型自己分析对话记录,找出描述不清、上下文缺失、冗余调用的地方
- 关注"模型没做什么"——沉默的遗漏比显式的错误更重要

### 10. 读写分离

一个工具要么只读,要么只写,不要混在一起。这样用户/Agent 可以安全地批量授权只读工具,而对写入工具逐个确认。MCP 规范里的 `readOnlyHint`、`destructiveHint` 注解就是为此设计的。

---

## 12 个常见反模式

1. **API 一对一映射**:每个端点一个工具
2. **通用命名**:`get_data`、`process_request`
3. **模糊描述**:`"获取数据"`
4. **嵌套参数**:dict 套 dict,模型编造键名
5. **返回所有字段**:原样透传 API 响应,context 爆炸
6. **到处是 UUID**:后续调用全靠幻觉
7. **读写混合**:一个工具既查又改
8. **无分页无截断**:context 溢出,模型放弃
9. **原始异常堆栈**:浪费轮次,无法恢复
10. **工具过多**:选择准确率随数量对数下降
11. **工具太"聪明"**:MCP Server 不应该自己做推理,让模型推理,Server 提供结构化上下文
12. **状态塞进返回值**:大块 JSON blob 让客户端来回传递

---

## 参考

- Anthropic: *Writing effective tools for agents — with agents*
- Block Engineering: *Block's Playbook for Designing MCP Servers*(60+ 内部 MCP 服务器经验)
- Phil Schmid: *MCP is Not the Problem, It's your Server*
- OpenAI: *o3/o4-mini Function Calling Guide*
- GitHub: MCP Server 工具精简实践(40→13)
- arXiv 2602.14878: *MCP Tool Descriptions Are Smelly!*(856 工具实证研究)
- 阿里云开发者社区、知乎 Tool Learning 综述等中文来源

发布于 湖北