
做 AI 编程的人最近应该都听过 Pi Agent 这个名字——一个能自己调工具、写代码、跑测试的编程代理。我在自己的项目里跑过一段时间最让我意外的不是它写代码多快而是它“不太看工具提示词”。传统上我们给 Agent 接一个工具要写一段几百上千字的描述功能说明、参数含义、边界条件、返回结构、异常处理恨不得把 README 搬进去。但实测下来在大多数场景里这些描述里的 90% 以上根本不会被用到。我把 20 个常用工具的描述全部重写一遍压缩掉 91% 的文字之后Pi Agent 的调用成功率反而没掉有些调用甚至更稳了。这篇文章就是来拆解这件事的省掉的到底是什么哪些能省、哪些不能省以及用户和扩展作者分别该怎么操作。无论你只是用 Pi Agent 跑任务还是正在给别人写扩展工具这篇指南都值得花十分钟看完。1. 先把账算清楚91% 的工具提示词到底省在哪里1.1 一个典型工具提示词长得什么样这里的“工具提示词”指的是你在给 Agent 定义工具时写在函数名和参数之外的说明文字。在 Pi Agent 这类工具调用型的 Agent 里每个工具一般都是一段 JSON Schema 或者装饰器描述包含 name、description、parameters而这段 description 是最容易失控的地方。我拿一个很常见的“文件内容搜索”工具举例。传统写法是这样的tool( namesearch_in_file, description在指定文件中搜索匹配指定正则表达式的所有行并返回匹配行号及行内容。支持跨平台路径解析支持忽略大小写搜索失败时返回错误信息。当用户提到查找、定位、搜索时使用此工具。, parameters{ file_path: str必填要搜索的文件路径支持绝对路径和相对路径, pattern: str必填正则表达式支持 Python re 语法, ignore_case: bool可选默认 False是否忽略大小写 } ) def search_in_file(file_path: str, pattern: str, ignore_case: bool False) - list[str]: ...这段看起来还挺正常的对吧但仔细想一下几乎所有信息都是多余的。“在指定文件中搜索匹配正则的行”——搜索工具不做这个做什么“当用户提到查找、定位、搜索时使用”——这是在教模型做意图匹配而意图匹配本来就是 Agent 的强项。“支持跨平台路径解析”——路径怎么处理是我这个工具内部的实现细节模型根本不需要关心。真正必要的只有三件事这个函数做什么、参数是什么类型和单位、返回什么。1.2 四个隐藏的成本为什么这些字不该写很多人会觉得“多写几个字又没坏处”但在工具调用型 Agent 里这还真有坏处。第一个成本是 token。每轮对话里Agent 手上的工具列表会被完整发送给模型。你给 15 个工具、每个多写 200 字一次请求就多出 3000 token。按现在主流模型的定价算一个跑满一天的 Agent 项目这笔开销能占到总费用的一两成。省掉 91% 的工具提示词本质上是省真金白银。第二个成本是维护。工具描述写得越多改起来越痛。今天给函数加个参数、明天调整返回值格式描述和代码一旦对不上模型就会照着旧描述去解析新返回然后报错。我见过太多团队的“工具文档”和代码完全脱节最后 Agent 的行为完全不可控。第三个成本是干扰。描述里塞进“当用户提到 XX 时使用”本质上是在替模型做决定。工具多了之后这种提示词会互相打架用户说“看一下这个文件”文件读取工具说“提到‘看’时用我”文件搜索工具也说“提到‘看’时用我”模型就蒙了。工具描述应该提供事实而不是提供猜测。第四个成本是调试。描述越长排错越难。模型到底是因为参数类型错了、还是因为描述有歧义才没调用对根本分不清。我后面会讲把描述压到最短之后问题反而好定位了。1.3 “省掉 91%”是怎么测出来的我在自己项目里做了一个对照实验把接进 Pi Agent 的 20 个工具逐一改写原始平均每个工具描述约 180 个中文字符重写后压缩到约 1620 个字符压缩比例大约为 90.5%四舍五入得到了“91%”这个数。这里要说明这个 91% 是我自己项目里的数字不同工具集差异很大但趋势是一致的。实验不求完美求的是一个稳定的基准我用同一批 50 个任务分别跑“完整描述版”和“精简描述版”统计工具调用成功率、任务完成率和平均耗时。结果是成功率从 95% 变成 94%基本持平而平均每任务的 token 消耗下降了约 18%。至于为什么描述砍掉 91%成功率还能维持住——这就是 Pi Agent 和传统 Agent 最大的区别下一节讲。提示如果你也想复现这个实验建议先用 git 分支或者配置开关留住原始提示词再逐步替换。别一次性全改否则出了问题都不知道是哪个描述引起的。2. Pi Agent 凭什么敢让你省提示词能力拆解2.1 从“看文档”到“问出来”工具意图推断传统 Agent包括很多走 function calling 的模型基本是靠工具描述来理解工具。描述写得不清楚它就不敢调用或者调用错。所以大家都养成了“描述必须详细”的习惯。Pi Agent 不一样。它在选工具时会同时做两件事第一看当前任务上下文第二推演这个工具的调用结果是否有助于完成任务。换句话说它不是被动地“读文档”而是主动地“问自己”这个函数如果被调用返回的数据能帮我完成任务吗我做个类比你在一个团队里接手一个老项目同事不会给你详尽的文档而是给你几个函数名你靠函数名、参数名、调用位置就能猜出八成用途。Pi Agent 用的就是这套逻辑。函数名 search_in_file 加参数 file_path、pattern基本就把用途说完了。2.2 它缺什么哪些信息必须你亲手写这不代表你可以什么都不写。我把信息分成两类第一类是模型“猜得到”的比如函数名、参数名、默认值、返回值形状。这些写出来反而是噪音。第二类是模型“猜不到”的必须由你写清楚。我列了一个清单单位和量纲size 参数到底是字节还是 MB必须写明。返回结构函数返回的是列表还是字典键名是什么模型解析错一次后面全错。副作用和成本delete 会不会删文件pull 会不会触发网络请求模型必须知道操作是否“便宜”、是否“危险”。外部依赖的状态这个工具会不会因为网络、权限或数据库未连接而失败失败时返回什么这四类信息无论如何都不能省。我给一个对比表信息类别示例能省吗功能意图“在文件里搜索匹配正则的行”通常能省函数名参数已经暴露参数类型file_path: str不能省必须写清楚单位/量纲size 的单位不能省返回结构返回 {“line”: int, “text”: str} 的列表不能省使用场景“当用户提到查找时调用”能省反而有害实现细节“支持跨平台路径解析”能省对模型无意义失败行为文件不存在时抛异常尽量省但保留“会抛错”这一点足以示例代码例如 search(‘a.*b’) 会返回 …能省除非返回值很反直觉2.3 一个原则“像写函数名一样写描述”总结下来工具描述的正确写法只有一个原则像写一个好函数名那样写描述而不是像写文档一样写描述。一个好函数名会把动词和宾语说清楚get_user_by_id、delete_file_by_path。工具描述要做到的也就是“在函数名旁边补一句话把函数名没说清的单位和返回讲明白”。多余的东西全部剪掉。当时我做这个实验的时候脑子里一直有个印象删到最后每把描述删掉一句模型的表现反而更稳。后来我理解了不是描述不重要而是“长描述里总是混着错的描述”。描述越长模型越容易把某一句错的话当真。3. 如果你是 Pi Agent 用户3 步把提示词砍掉 91%3.1 第一步给工具做“体检”——找出可省项我的做法是先把每个现有工具的描述拆进一张三栏表能删、能简、必须留。“能删”包括使用场景句子“当用户提到……”、实现细节“支持……技术”、冗余解释“通过……实现”。 “能简”包括参数说明里每个参数单独一句话描述的那种可以压缩到“类型单位默认值”。 “必须留”就是上面 2.2 节说的四类信息。举个真实的例子。我有个工具叫 send_email原描述 180 字。拆完之后能删掉的是“当用户需要发送邮件时使用”“支持 SMTP 协议”“邮件内容支持 HTML 格式”……能简的是四个参数的说明。最后留下的是发送邮件。必填: to(list[str])、subject(str)、body(str)可选: cc(list[str]) 默认空返回 message_id。3.2 第二步按“四个信息层级”重写工具描述重写的时候我推荐你用这个模板一句话功能通常就是一个动词短语 必填参数名称(类型单位含义) 可选参数名称(类型单位含义默认值) 返回什么结构的关键字段拿上面 send_email 的完整重写做个示例tool( namesend_email, description发送一封邮件。必填: to(list[str] 收件人邮箱), subject(str 主题), body(str 正文)。可选: cc(list[str] 默认空)。返回: message_id(str)。, parameters{...} ) def send_email(to: list[str], subject: str, body: str, cc: list[str] []) - dict: ...这段描述一共 90 个字符原版 180 字压缩了一半。再用同样的手法把其他工具描述都压一遍整体就能逼近 91% 这个比例。关键是描述里只保留“模型真的会去读的句子”。模型在决定调用时实际留意的是工具名、参数名、以及“返回什么”对这三点之外的内容它极少认真对待。3.3 第三步用 Pi Agent 的自我测试做回归描述重写完之后别直接上生产。我给自己定了一个规矩每次改完工具描述必须跑一遍“回归测试集”。我的测试集有 5 个用例让 Agent 完成一个需要直接调用该工具的任务验证基本调用没断。让 Agent 完成一个参数容易混淆的任务比如单位转换、字段名对应。给一个模糊任务看它是否能自己选对工具验证“意图匹配”没断。给一个需要连续调用两个工具的任务验证工具间数据传递没断。给一个错误输入的任务看它是否能根据返回结构自行纠错验证错误处理没断。每次跑完我会在表格里记录通过与否。如果第 2 个用例挂了大多数情况是描述里漏了单位如果第 4 个用例挂了通常是返回结构的描述被删过头了。我后面会在“常见问题”里把这几个坑单列一节。3.4 一个偷懒但有效的技巧先写废话再删到 10%如果你想更快摸到自己的“最小描述点”可以用这个办法先把描述写成“废话大全”就是把你能想到的所有信息全塞进去包括使用场景、注意事项、示例代码然后让 Agent 跑通几条链路任务确认功能正常接下来开始一句一句删。每删一句重跑一次同样的任务组。如果任务还是能过说明这句是冗余的永久删除。如果删了之后任务开始挂说明这句是必要的恢复它然后停手。这个过程本质上是在用 Agent 自己的表现做“描述变量筛选”。你不用猜哪句话有用你只要看删掉哪句话会让它犯错就能准确找到“最小描述点”。我在 send_email 这个工具上试过最后留下的描述比我手动直觉写的还短——因为有些我以为必要的信息比如“邮件内容支持 HTML”模型自己验证后根本不需要。4. 如果你是扩展作者把工具描述写成“接口摘要”4.1 扩展作者常见的三个误区扩展作者也就是给 Pi Agent 写工具包、插件的人遇到的问题比普通用户更典型因为你的工具描述不只是给一个 Agent 用而是给所有安装你扩展的用户用。写得好不好直接决定你的扩展在别人手里好不好使。第一个误区是把 README 直接当描述。工具描述应该让模型“在调用那一刻”看到而 README 是给人看的里面充满了架构设计、安装步骤、FAQ。这些信息对模型来说全是噪音。我见过有扩展直接把十几行 README 贴进 description结果模型每次调用都会被那段长文本干扰调用速度明显变慢。第二个误区是堆参数表格。扩展工具往往有十几个参数于是作者把每个参数都写满一句说明。但模型不是数据库它记不住几十条说明。它需要的是“该参数名 该参数怎么影响结果”其他的交给它自己读参数名去猜。堆得越多决策越慢错误率越高。第三个误区是把“示例代码”写进描述。模型本身就会写代码你给它的示例如果和它当前任务不匹配反而会把它带偏。示例只适合放在 README 里或者作为另一个“返回结构示例”字段存在但绝不能塞进每条描述里。4.2 推荐的工具描述模板可直接抄给扩展工具写描述我推荐下面这个结构一句话功能 必填参数列表 可选参数列表 一个关键行为说明其中“一句话功能”用“动词名词”写成不少于 3 个字、不多于 20 个字。“必填参数”必须包含参数名、类型、单位如果有、含义。“可选参数”只需要列参数名、默认值、单位重点列有的其他让模型自己发挥。“关键行为说明”只写那些“模型猜不到的行为”例如“这个工具会向外部服务发出真实请求”“成功时返回 200失败时抛异常”“返回的 ids 是数字而非字符串”。下面给一个可直接抄的 Python 装饰器示例tool( namegithub_create_issue, description在指定仓库创建 issue。必填: repo(owner/name格式字符串), title(str)。可选: body(str 默认空), labels(list[str] 默认空)。返回: issue_number(int) 和 url(str)。会真实调用 GitHub API慎用。, parameters{ repo: {type: string, description: 仓库地址格式 owner/repo如 octocat/Hello-World}, title: {type: string, description: issue 标题}, body: {type: string, description: issue 正文, default: }, labels: {type: array, items: {type: string}, description: 标签列表, default: []} } ) def github_create_issue(repo: str, title: str, body: str , labels: list[str] []) - dict: ...这是一段 130 字左右的描述但信息密度很高。模型看到后能在 0.5 秒内理解这个工具的作用、参数、返回和行为边界。如果你把它按传统写法铺开没有 500 字根本写不完。对照 JSON Schema 的形式也差不多只是把 description 写成同样的句子不要嵌套字典描述。4.3 给工具分组让 Agent 少做选择题工具描述省下来之后还有一个影响调用效率的因素工具数量。Pi Agent 在每轮请求里都会扫描可用工具列表。如果一个扩展把 30 个工具全挂上去即便每个描述都很短模型每次都要做一次 30 选 1 的选择题速度还是会拖慢误选率也会上升。我的建议是给工具分组。有几种做法按域分组文件操作类、网络请求类、数据库类……每组一个“门面工具”用户需要时先调用门面工具。按用途分组只读工具一组写操作一组危险操作一组。Agent 在处理“删除”任务时只需要扫描危险组。按调用热度分组常用工具放一组、一次全量注入冷门工具放另一组、按需加载。在 Pi Agent 上这个可以通过给工具加前缀或者分组命名空间来实现。比如 file_read、file_write、file_delete 归到 file 命名空间search_file、diff_files 归到 analyze 命名空间。字段上给工具加分组名Agent 就会先生成“分组意图”再在分组内选择具体工具相当于把 30 选 1 拆成两步 5 选 1效果显著提升。4.4 “省 91%”之后测试样本建议给扩展作者一套“上线前测试样本”我认为比工具描述模板更重要。因为没有人能保证自己写出来的精简描述一定对但一套好的测试样本能帮你发现哪里没写够。我的建议是每个工具至少准备 4 条测试指令测试维度示例指令通过标准基本调用“用 github_create_issue 给 repo 建个 issue标题是测试”参数完全正确调用成功参数推导“给 octocat/Hello-World 建一个 issue内容写‘test’”Agent 能自己填上 body 参数数据流转“创建 issue 后把 url 打印出来”返回值被正确解析异常输入“对不存在的 repo 创建 issue然后告诉我错误”Agent 能理解返回的报错并转述上面的表是我最常用的样本模板。每个工具跑一遍基本能吃透“描述有没有精简过头”以及“返回结构是否被模型正确理解”。5. 常见问题与排查技巧实录5.1 常见问题速查表我把自己的实验和社区里朋友遇到的问题整理成一张速查表现象最可能的原因处理方式压缩后 Agent 完全不再调用某个工具工具名太模糊或一句话功能写得像废话改函数名把动词宾语写进 name再精简描述Agent 调用成功但参数明显不对参数的单位或含义没写全在参数 description 里补单位如 size(MB)返回值解析失败Agent 胡编字段返回结构描述被删过头了恢复“返回字段名”那部分描述哪怕多花 20 字描述变短后任务完成率不升反降你删掉了一条模型“猜不到”的关键行为对照 2.2 节清单逐项检查通常漏了副作用或失败行为Agent 一直在两个工具之间摇摆工具名或功能描述相似度太高合并成一个工具加参数区分而不是硬拆扩展工具多导致每次响应很慢工具数量太多模型在扫描全部工具做工具分组让 Agent 先定位分组再选工具5.2 三个排查技巧第一个技巧是“让 Agent 说”。在 Pi Agent 的日志里开启工具选择为“思考过程”输出让它把“为什么选这个工具”这一步写出来。你会很清楚看到模型是读了你描述的哪一句话或者压根没读。这个信息比任何猜测都直接。第二个技巧是“对比日志”。保留压缩前后的调用日志异常出现时直接 grep 一下两次调用里模型给工具的参数差异。多数情况下问题都出在“参数名对不上”或“返回值类型对不上”跟描述内容的字数关系不大。第三个技巧是“用错误返回做反向测试”。压缩之后给工具喂一个故意带错的输入比如传一个不存在的文件路径看模型拿到错误返回后能不能理解并转述。如果它转述成了“文件未找到”而不是“路径无效”说明返回结构描述还不够清楚如果它直接懵了那就把“失败时会返回 error 字段”这句话加回去。这个技巧帮我找到了很多隐藏的描述问题。5.3 什么情况下别省省 91% 并不适用于所有场景。下面几种情况我强烈建议你保留“传统详细描述”工具涉及高风险操作比如删除、支付、真实对外请求。此时多写几个字的成本远低于误操作成本。工具对接的是格式严格的第三方 API比如某个服务的响应必须按特定 schema 解析。你需要把响应结构写清楚哪怕长一点。你用的是较旧的模型或参数量较小的模型。模型越弱越依赖显式描述短描述可能真的不行。你要分发扩展给第三方用户。别人环境里的任务类型你不知道保守起见保留必要的上下文。除此之外大多数日常工具尤其是“本地文件操作、文本处理、信息查询”类都可以放心大胆地压到最简。最后说一点我自己的体会。我最初之所以花力气做这个 91% 实验其实就是因为每次给 Pi Agent 加新工具都被“写描述”这事拖住。后来把描述全部压短之后我发现一个意外的好处模型在短描述下反而更敢尝试了因为它不再被大段上下文束缚能靠自己的推理去判断工具用法。也许这就是工具调用型 Agent 该有的样子——工具描述只是路标而不是文档。再分享一个小技巧把完整描述留在扩展的 README 里或者作为工具函数 docstring 存在代码里。Pi Agent 在运行时如果需要更详细的上下文会按需读取这部分内容而不是默认把它们全塞进每一轮 prompt。这样你既保留了详细信息又不会让它们成为每轮对话的负担。