☰
Pi Agent工具提示词瘦身91%:从说明书到索引卡
2026/10/8 3:58:55 网站建设 项目流程

1. 为什么你的 Pi Agent 工具提示词该“瘦身”了

如果你正在用 Pi Agent 做自动化任务编排,或者正在给 Pi Agent 写扩展工具,大概率遇到过这样的场景:一开始只是想让 Agent 帮忙查个天气、读个文件,结果工具描述越写越长,系统提示词越堆越厚,最后发现光是工具定义就吃掉了几千甚至上万 token。更麻烦的是,工具一多,Agent 反而变“笨”了——该调用的不调用,不该调用的乱调用,参数还经常填错。

这个问题的根源,往往不在模型本身,而在工具提示词的设计方式。我见过太多扩展作者把工具描述写成了产品说明书:每个参数都配一段解释,每个返回值都列三行示例,再加上一堆“注意事项”“使用场景”“限制条件”。单看每个工具都很完整,但放到一起,Agent 的上下文就被稀释了。

所谓“省掉 91% 的工具提示词”,核心思路其实很朴素:把工具提示词从“说明书”变成“索引卡”。Agent 不需要在提示词里学会怎么用工具,它只需要知道“有这个工具、大概干什么、关键参数是什么”。真正的使用细节,应该交给工具本身的参数校验、错误返回和 Agent 的推理能力去处理。

这篇文章面向两类人:一是正在使用 Pi Agent 做任务自动化的用户,二是给 Pi Agent 写扩展工具的开发者。我会把“提示词瘦身”的完整思路拆开讲清楚——哪些内容必须留、哪些可以砍、砍完之后怎么保证 Agent 不掉链子。所有操作都可以直接照着改,不需要你重新设计整个工具架构。

先给一个直观的对比。假设你有一个“查询订单状态”的工具,传统写法可能是这样:

{ "name": "query_order_status", "description": "查询订单的当前状态。该工具接受订单ID作为输入,返回订单的详细状态信息,包括订单创建时间、支付状态、发货状态、物流信息等。注意:订单ID必须是有效的字符串格式,如果订单不存在会返回错误。使用场景:当用户询问订单进度、物流情况、是否发货等问题时调用此工具。", "parameters": { "order_id": { "type": "string", "description": "订单的唯一标识符,通常是一串数字或字母数字组合,例如 'ORD20240101001'。请确保传入正确的订单ID,否则查询会失败。" } } }

瘦身之后:

{ "name": "query_order_status", "description": "按订单ID查询状态", "parameters": { "order_id": { "type": "string", "description": "订单ID" } } }

功能完全一样,但 token 消耗可能只有原来的十分之一。你可能会担心:这么简略,Agent 能理解吗?实测下来,对于主流的大模型来说,完全够用。因为“query_order_status”这个函数名本身已经表达了意图,“order_id”这个参数名也足够清晰。那些“使用场景”“注意事项”更多是写给人类开发者看的,Agent 并不需要。

2. 工具提示词里到底哪些内容可以砍

2.1 先搞清楚 token 都花在哪了

在动手砍之前,得先知道工具提示词的 token 构成。一个典型的工具定义包含这几部分:

组成部分典型内容是否必要
工具名称query_order_status必须保留
工具描述一段自然语言说明可大幅精简
参数名order_id必须保留
参数类型string / number / boolean必须保留
参数描述对参数的详细解释可精简
枚举值可选值的列表按需保留
必填标记required必须保留
示例调用示例通常可砍
注意事项使用限制、边界条件大部分可砍

我统计过自己项目里的工具定义,发现参数描述和工具描述这两块占了总 token 的 70% 以上。而这两块恰恰是最容易写“膨胀”的。比如一个“发送邮件”的工具,参数描述写成“收件人的电子邮件地址,格式必须符合 RFC 5322 标准,多个收件人用逗号分隔”,其实只需要写“收件人邮箱,多个用逗号分隔”就够了。

2.2 必须保留的三类信息

砍归砍,有三类信息绝对不能丢,否则 Agent 会直接“抓瞎”。

第一类是工具名称。名称要能自解释,最好用“动词+名词”的结构,比如search_web、read_file、send_email。避免用tool_1、helper这种无意义的名字。如果工具功能相近,名称要能区分开,比如search_web和search_local,而不是search和search2。

第二类是参数名和类型。参数名同样要自解释,user_id比uid好,max_results比n好。类型必须准确,该是 integer 就别写 string,否则 Agent 可能传错格式。必填参数一定要标记required,可选参数给个默认值。

第三类是枚举值。如果某个参数只能取固定几个值,一定要在 schema 里列出来。比如sort_order只能是asc或desc,那就明确写出来。这比在描述里写“排序方式,可选升序或降序”要有效得多,因为 Agent 能直接看到合法值。

2.3 可以大胆砍掉的内容

以下几类内容,我建议直接删掉或者大幅压缩:

  • 使用场景说明:比如“当用户询问X时调用此工具”。Agent 根据工具名和当前对话上下文就能判断,不需要你教。
  • 返回值详细描述:除非返回值结构特别复杂,否则不用写。Agent 调用完自然能看到返回结果。
  • 调用示例:大部分情况下不需要。如果参数结构特别复杂,可以用 schema 的examples字段,而不是写在描述里。
  • 注意事项和限制:比如“请确保参数正确”。这种话写了等于没写,Agent 不会因为这句话就变得更小心。
  • 重复解释:工具描述里说一遍,参数描述里又说一遍,纯属浪费。

注意:如果你的工具涉及敏感操作(如删除数据、发送消息),可以在描述里用极简的方式标注风险等级,比如[危险]前缀。但不要写一整段警告文字。

2.4 一个真实的瘦身案例

我拿自己项目里的一个“文件搜索”工具做过对比测试。原始版本的工具定义有 380 个 token,瘦身后只有 34 个 token,压缩了 91%。具体对比如下:

原始版本:

{ "name": "search_files", "description": "在指定目录下搜索文件。该工具会根据文件名模式进行匹配,支持通配符。搜索是递归的,会遍历所有子目录。注意:搜索大目录时可能较慢,建议指定更精确的路径。返回匹配的文件路径列表。", "parameters": { "directory": { "type": "string", "description": "要搜索的目录路径,必须是绝对路径,例如 '/home/user/documents'。如果路径不存在会返回错误。" }, "pattern": { "type": "string", "description": "文件名匹配模式,支持 * 和 ? 通配符。例如 '*.txt' 匹配所有文本文件,'report_?.pdf' 匹配 report_1.pdf 等。" }, "max_results": { "type": "integer", "description": "最大返回结果数量,默认为 100。设置过大会导致响应变慢。", "default": 100 } } }

瘦身版本:

{ "name": "search_files", "description": "递归搜索文件", "parameters": { "directory": { "type": "string", "description": "目录绝对路径" }, "pattern": { "type": "string", "description": "文件名模式,支持 * ?" }, "max_results": { "type": "integer", "description": "最大结果数", "default": 100 } } }

实测下来,Agent 在两个版本下的调用成功率没有明显差异,但瘦身版本节省下来的 token 可以多放好几个工具定义。对于工具数量多的场景,这个收益是复利式的。

3. 给扩展作者的实操改造流程

3.1 第一步:盘点现有工具定义

别急着动手改,先把所有工具定义导出来,做个“体检”。我通常会把工具定义整理成一张表,列出每个工具的 token 数、参数个数、描述字数。这样一眼就能看出哪些工具是“重灾区”。

具体操作上,如果你用的是 JSON schema 定义工具,可以写个小脚本统计每个字段的字符数。粗略估算 token 的方法是:英文字符数除以 4,中文字符数除以 1.5。比如一个工具定义有 800 个英文字符和 200 个中文字符,大约就是 200 + 133 = 333 个 token。

盘点的时候重点关注三类工具:参数特别多的、描述特别长的、使用频率特别低的。参数多的工具往往是瘦身重点,因为每个参数描述都在消耗 token。使用频率低的工具可以考虑合并或者干脆去掉。

3.2 第二步:按“最小可用信息”原则重写

重写工具定义时,我遵循一个原则:假设 Agent 是一个聪明但没耐心的新同事。你只需要告诉它“这个工具叫什么、干什么、需要什么参数”,剩下的它自己能推理出来。

具体写法上,工具描述控制在一句话以内,最好不超过 10 个字。参数描述控制在 5 个字以内,能用一个词就不用一句话。比如:

  • description: "查询订单状态"而不是description: "该工具用于根据订单ID查询订单的当前状态信息"
  • description: "订单ID"而不是description: "订单的唯一标识符,例如 ORD20240101001"

如果某个参数确实需要额外说明,优先用 schema 的enum、default、minimum、maximum等字段来表达,而不是写在描述里。比如“排序方式,可选升序或降序”应该写成enum: ["asc", "desc"],描述里只写“排序方式”。

3.3 第三步:用 AGENTS.md 统一管理工具约定

这里要提一下AGENTS.md这个文件。在 Pi Agent 的生态里,AGENTS.md通常用来存放 Agent 的全局行为约定。你可以把工具使用的通用规则写在这里,而不是重复写在每个工具定义里。

比如,你可以在AGENTS.md里写:

## 工具使用约定 - 所有文件路径使用绝对路径 - 搜索类工具默认返回 100 条结果 - 涉及写操作的工具调用前需确认

这样每个工具定义里就不用再重复“请使用绝对路径”“默认返回100条”这些内容了。AGENTS.md的内容只在系统提示词里出现一次,而工具定义里的重复内容会随着工具数量线性增长。把通用约定抽到AGENTS.md,是省 token 的另一个关键操作。

3.4 第四步:验证瘦身效果

改完之后不能直接上线,得验证 Agent 还能不能正常调用。我的验证方法是准备一组测试用例,覆盖每个工具的典型调用场景,然后对比瘦身前后的调用成功率。

测试用例要包括:正常调用、参数缺失、参数格式错误、边界值。比如对于search_files工具,测试用例可以是“搜索 /tmp 下的所有 .log 文件”“搜索不存在的目录”“max_results 设为 0”。跑一遍下来,如果调用成功率和瘦身前持平,说明瘦身没有引入问题。

如果发现某个工具瘦身后调用成功率下降,优先检查是不是参数名或枚举值被砍得太狠了。参数名和枚举值是 Agent 理解工具用法的关键线索,这两块要保守一些。

4. 工具提示词瘦身后的常见问题与排查

4.1 Agent 不调用工具了怎么办

这是瘦身后最常见的问题。原因通常是工具描述太简略,Agent 无法判断什么时候该用这个工具。排查思路是:先看工具名是否足够自解释,再看工具描述是否丢失了关键的动作词。

比如你把工具描述从“查询订单状态”砍成了“订单”,Agent 就不知道这个工具是“查”还是“改”。这时候要把动词加回来。工具描述里至少要有一个动词,说明这个工具是做什么操作的。

另一个原因是工具之间的区分度不够。如果你有两个工具get_user和fetch_user,描述都写“获取用户”,Agent 就不知道该用哪个。这时候要么合并工具,要么在描述里加上区分词,比如“按ID获取用户”和“按邮箱获取用户”。

4.2 参数传错格式怎么处理

瘦身后参数描述变短,Agent 可能对参数格式的理解变模糊。比如date参数,原来描述写“日期,格式为 YYYY-MM-DD”,瘦身后只写“日期”,Agent 可能传“2024年1月1日”这种格式。

解决办法不是把描述写回去,而是在工具实现里做参数校验和容错。Agent 传了“2024年1月1日”,你的工具代码应该能解析成标准日期,或者返回一个清晰的错误信息告诉 Agent 正确格式。Agent 看到错误信息后会自行纠正。

这其实是一个设计理念的转变:把提示词里的“预防性说明”转移到工具实现里的“容错处理”。提示词是软约束,工具实现是硬约束。硬约束更可靠,而且不消耗 token。

4.3 工具数量多时怎么组织

当工具有几十个的时候,即使每个都瘦身了,总量还是不小。这时候可以考虑分层组织:把常用工具放在主工具列表里,不常用的工具放到“扩展工具”里,通过一个list_extensions工具按需加载。

另一种做法是按领域分组,比如“文件操作”“网络请求”“数据处理”各一组,每组用一个统一的入口工具,通过action参数区分具体操作。这样可以把多个工具合并成一个,大幅减少工具定义数量。

不过要注意,合并工具会增加单个工具的复杂度,Agent 可能搞混action的取值。所以合并要适度,一般 3 到 5 个操作合并成一个工具比较合适。

4.4 常见问题速查表

问题现象可能原因排查方法解决方式
Agent 不调用工具描述缺动词或区分度低检查工具名和描述补动词、加区分词
参数格式错误描述太简略查看错误日志工具实现加容错
调用频率下降工具被“淹没”统计各工具调用次数精简工具列表
返回结果被忽略返回值结构复杂检查返回格式简化返回结构
工具间互相干扰功能重叠对比工具定义合并或明确分工

提示:瘦身不是一次性的工作。每次新增工具或修改工具后,都建议重新跑一遍验证用例。工具定义会随着项目迭代慢慢“膨胀”,定期做一次“体检”很有必要。

5. 我踩过的坑和几条实用建议

先说一个我踩过的坑。有一次我把一个“发送通知”的工具描述从“向指定用户发送通知消息,支持邮件和短信两种渠道”砍成了“发送通知”,结果 Agent 在需要发邮件的时候调用了这个工具,但没传channel参数,导致工具报错。后来我在参数 schema 里把channel设为必填并加了枚举值,问题就解决了。该保留的枚举值和必填标记,一个都不能省。

另一个坑是过度合并工具。我曾经把“读文件”“写文件”“删文件”合并成一个file_operation工具,用action参数区分。结果 Agent 经常把action传成read但参数里带了content,或者传成write但没带content。后来拆回三个独立工具,反而更稳定。合并工具的前提是操作之间参数结构相似,否则不如分开。

还有一点关于AGENTS.md的使用。我一开始把所有通用约定都塞进AGENTS.md,结果这个文件越来越长,最后比工具定义还占 token。后来我定了个规矩:AGENTS.md只放真正跨工具通用的约定,而且每条不超过一行。工具特有的约定,还是放在工具定义里,但用最简的方式表达。

最后分享一个实用技巧:用工具名代替工具描述。如果你的工具名足够清晰,比如search_web、read_file、send_email,那么工具描述甚至可以留空或者只写一个词。Agent 看到工具名就能理解意图。这招在工具数量多的时候特别管用,能把工具定义的 token 压到极限。

瘦身这件事,本质上是在“信息量”和“token 成本”之间找平衡。我的经验是,宁可让 Agent 多试错一次,也不要在提示词里写一堆它可能永远用不上的说明。试错的成本是一次工具调用,而冗余提示词的成本是每一次对话都在消耗。这笔账算清楚了,工具提示词的设计思路自然就清晰了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询