简介:AI Agent 总是选错工具、传错参数、返回无用信息?问题多半不在模型,而在工具定义本身。本文围绕命名、默认值、Schema 校验、宽松解析、报错导航、按需加载六个技巧,系统讲解如何提升 Agent 调用准确率与自纠错能力,让你的智能体真正“听话”。
让 AI 帮你干活,它却频繁选错工具、拼错参数、返回一堆用不上的信息——遇到这种情况,很多团队的第一反应是“换个更强的模型”。但大量工程实践表明,症结往往不在模型能力,而在你暴露给 Agent 的那份“工具说明书”。
模型对工具的全部认知,只来自四个信息源:工具名称、参数定义、返回结构、错误信息。它看不到你的源代码,也不了解接口背后的业务约定。说明书写得含糊,再强的模型也只能靠猜;而每猜错一次,都会消耗一轮对话、一次调用,甚至动摇用户对整个 Agent 的信任。
输入设计的核心目标可以概括为一句话:让 Agent 更容易传对参数,更难传错参数。围绕这个目标,本文整理六个技巧,覆盖命名、默认值、输入校验、宽松解析、报错设计与工具数量治理。无论你基于原生函数调用(Function Calling)构建 Agent,还是在百度智能云等平台上搭建智能体应用,这些原则同样适用。
请记住一个前提:你不是在写接口,而是在教 AI 怎么跟世界打交道。
工具名是模型决定“调用哪个工具”时权重最高的信号。人类读接口文档时会结合上下文与经验推断,模型却只能依赖字面信息,因此命名必须做到“零推理成本”。四条原则如下:
search_issues、create_ticket、delete_record 一眼可懂;而 issue_service、handle_data 这类名字无法判断工具到底做什么、会不会改动数据。repo_search_code 与 docs_search_page。同一动作在不同业务域里语义差异很大,前缀能显著降低误选率。get_usr_cfg 省了几个字符,却让模型多猜一层;内部代号对模型而言更是纯噪声。一个对比例子:
❌ name: querydesc: 查询接口✅ name: search_issuesdesc: 按关键词搜索项目 Issue 工单,支持状态过滤与排序;适用于“查缺陷、找需求、看任务”类意图。
默认值是降低传错概率的第一道防线。理想状态是:Agent 只提供一个必填参数,就能拿到“够用”的结果。以一个 Issue 搜索工具为例:
def search_issues(query: str, # 必填:搜索关键词repo: str = None, # 可选:默认搜索全部有权限的仓库state: str = "open", # 可选:默认只看 open 状态sort: str = "relevance", # 可选:默认按相关性排序limit: int = 20 # 可选:默认返回 20 条) -> str:"""搜索项目 Issue 工单。参数:- query: 搜索关键词(必填)- repo: 限定仓库,格式 owner/repo(可选,默认搜索所有可访问仓库)- state: 状态过滤,取值 'open'|'closed'|'all'(可选,默认 'open')- sort: 排序方式,取值 'relevance'|'created'|'updated'(可选,默认 'relevance')- limit: 返回条数上限(可选,默认 20,最大 100)"""
三条关键纪律:
描述写得再好也只是“建议”,JSON Schema 的约束条件才是硬边界。三类约束尤其值得善用:
枚举收敛取值空间。凡取值可穷举的参数都应声明枚举,把“开放生成题”变成“选择题”:
{"state": {"type": "string","enum": ["open", "closed", "all"],"default": "open","description": "Issue 状态过滤"}}
模式锁定格式。对固定格式的参数,用正则提前卡住非法输入:
{"repo": {"type": "string","pattern": "^[a-zA-Z0-9_-]+/[a-zA-Z0-9_.-]+$","description": "仓库名,格式为 owner/repo"}}
边界限定范围。数值型参数(数量、页码、超时)必须限定上下界,防止模型给出把后端打挂的极端值:
{"limit": {"type": "integer","minimum": 1,"maximum": 100,"default": 20,"description": "返回结果数量上限"}}
两点常被忽视:其一,description 应写“业务含义 + 单位 + 约束”,而不是只写一个名词;其二,校验应前置到框架层,让非法参数在进入业务逻辑前就被拒绝,并把违反的具体约束项回传给模型——这与技巧五直接联动。
Schema 拦截“明显错误”,但模型输出天然有抖动:大小写不一、多余空格、越界数值。若一律硬性报错,Agent 会在重试循环里空转。更优的策略是入口做归一化,出口做截断:
"OPEN"、" open " 先做去空格与小写归一再匹配枚举;limit = 250 不必报错,直接钳制到上限 100,并在结果中注明“已按上限截断”;需要强调:宽松不等于迁就。可以纠正“形式噪声”,不能猜测“语义错误”。无法确定指向的输入宁可报错并要求澄清,也不要猜一个结果返回——猜错的代价远高于多一轮对话。
工具失败时返回的信息,决定了 Agent 是“原地打转”还是“一步纠错”。合格的报错必须回答三个问题:错在哪里、为什么错、下一步怎么改。
❌ {"error": "参数错误"}✅ {"error": {"code": "INVALID_PARAM","field": "repo","message": "repo 需符合 owner/repo 格式(如 'team/web-app'),收到 'web-app'。若想搜索所有仓库,可省略该参数。"}}
好的报错具备三个特征:可定位(指明字段与违反的约束)、可行动(给出修正建议或正确示例,模型读完即可构造下一次调用)、有退路(提供替代路径,让 Agent 知道如何降级完成目标)。把报错做成结构化数据(错误码 + 字段 + 建议),它就从“日志”升级为“给模型的即时指令”。
工具数量膨胀有两重代价:一是决策质量下降,可选项越多误选率越高,模型甚至可能凭空调用不存在的工具;二是上下文膨胀,每个工具的名称、参数与描述都占据窗口,几十上百个工具会把系统提示塞满,挤压真正的工作内容。
治理思路是让工具按场景分批上架(按需加载):
初始上下文:仅挂载 list_skills(占用极少 token)任务 = "整理本周缺陷"→ Agent 调用 list_skills,发现 "issue-analysis" 技能→ load_skill("issue-analysis")→ 此后上下文中才出现 search_issues、summarize 等具体工具
这样既保住能力覆盖面,又把单次决策的选项控制在模型能可靠选择的规模上。实践经验表明,同时暴露的工具数量一旦达到几十个以上,误选率会明显上升。
六个技巧本质上是同一条设计观的分层落地:输入层面(命名、默认值、校验、宽松解析)降低模型犯错的概率;反馈层面(报错导航)降低错误发生后的纠错成本;规模层面(按需加载)让能力扩展不以决策质量为代价。
写传统接口时,你的用户是另一个程序员,他会读文档、会调试、会来提问;而设计 Agent 工具时,你的“用户”是一个只能靠文字理解世界、且不会主动追问的模型。把工具当产品来设计,把工具描述当产品文档来反复打磨,Agent 的“听话”程度自然随之提升。