3.3 工具调用:给 AI 接上订单查询
知识库能回答产品问题,但用户最常问的另一类是:我的订单到哪了。这种信息不在文档里,在业务系统里,靠检索永远检索不到——你不可能把订单实时状态写进知识库,那是分秒都在变的数据。解决办法是给智能体接上工具调用(Function Calling),让它能去业务后端查真实数据。这是整个项目里智能体第一次真正地动了业务系统,也是技术含量最高的一节。
这一节的活涉及两侧:智能体平台上配工具节点,业务后端提供订单查询接口。我们的订单服务跑在 CVM 上,对接口部署和报错排查不熟的,先看服务器常见问题热热身。这节按照原理、设计、兜底、联调、安全的顺序展开,内容对任何带参数查询的工具都通用,订单查询只是最好上手的例子。
工具调用的四个步骤
理解工具调用,关键是分清谁决定、谁执行:
第一步,用户说话,大模型读完消息,判断需不需要调工具。用户问我的订单到哪了,模型知道要查订单;问退货政策,则不调工具、走知识库检索。这个判断完全由模型完成,不需要写关键词匹配规则。能力边界来自你给工具写的描述:描述清楚,模型就知道什么时候该调、什么时候不该碰。
这里最重要的一步是第二步:如果模型决定调工具,它会以结构化形式给出工具名和参数,而不是像聊天那样输出一句话。这个结构化输出是工具调用能落地的关键,机器读得懂、业务侧解析得了,错误率远低于自己写正则提取。
第二步,模型给出要调用的工具名和从消息里提取的参数,比如订单号。注意参数是模型从自然语言里提取的,不是用户填的表单——这是工具调用最容易出问题的地方,用户随口说的话,格式千奇百怪。
第三步,业务侧拿到工具名和参数,真正执行查询,把结果返回给智能体。
第四步,模型拿到真实结果,组织语言回答用户:您的订单已发货,预计明天送达。
整个过程中模型只做两件事:决定调什么工具、把返回结果说清楚。真正的查询动作发生在业务侧,模型从不直接碰数据库——这一点既是原理,也是安全边界。
和规则系统的区别
有同事问:判断要不要查订单,写成关键词匹配不就行了,干嘛让模型来决定?我做了个对比实验:同一批历史会话,关键词规则和模型判断各跑一遍。
规则路线的问题是太脆。用户写帮我看看那个东西发出来没有,规则匹配不到任何关键词,不会触发查询;用户写查一下我的快递吧,匹配到快递却触发不了真正的订单工具,因为它只认订单两个字。规则只能覆盖你想到的说法,用户说法的分布是无限的。
模型判断则宽容得多:它理解帮我看看那个东西的意图是查物流,即使一个关键词都没命中。代价是偶发误判——把闲聊当成工具调用,比如用户说帮我看看这事怎么办,它可能真的去查了订单。误调可以通过工具描述写细致来抑制,而规则的脆弱只能靠不断加规则,规则越加越多,最后没人敢动。
结论:高频意图用规则兜底省成本,模糊意图交给模型。我们最后只留了一条规则(用户消息里包含完整订单号格式时直接调查询,省掉一次模型推理),其余全交给模型判断。这个混合方案跑了一个月,误调率稳定在百分之一以内,比纯规则路线的漏检低了一个量级。规则和模型不是非此即彼,怎么搭配顺手得看自己的数据分布。
订单查询工具设计
工具设计其实是接口设计,先和后端同事把表定清楚,再上画布配置:
| 设计项 | 内容 | 说明 |
|---|---|---|
| 工具名称 | 查询订单 | 名称要让模型一看就懂用途,描述写清何时调用 |
| 入参一 | 订单号 | 优先从消息提取,需做长度与格式校验 |
| 入参二 | 手机号后四位 | 订单号缺失时作为辅助匹配条件 |
| 返回字段 | 订单状态、物流单号、下单时间 | 只返回回答所必需的字段 |
| 成功码 | 零 | 业务双方约定的成功标记 |
| 错误码一 | 订单不存在 | 引导用户提供正确订单号 |
| 错误码二 | 信息不匹配 | 手机号后四位对不上,提示重新确认 |
| 错误码三 | 查询超时 | 走兜底,建议稍后重试或转人工 |
返回字段刻意压到最少,不返回金额、收货地址这类敏感信息,原因见后面的安全段。工具描述写详细一点很值:模型靠这段描述决定什么情况下调它,描述含糊,误调率就高。我的写法是描述里包含用途、适用场景和不适用的反例三部分,上线后误调确实少了许多。参数定义里最好注明取值范围和格式样例,模型提取时照着样例走,格式比没有样例时规整不少。
参数提取失败怎么办
真实环境里用户很少规规矩矩报订单号。一半以上的情况是:我想查下我的订单,一个数字都没有。这时候链路里要有一个条件判断分支:参数缺失或校验不过,不调接口、不报错,直接让智能体反问用户。
反问也有讲究。第一轮问:请提供订单号,它通常显示在订单完成页或确认短信里。后者是关键提示——绝大多数用户不知道订单号长什么样,告诉他哪里能找到,比单纯催他要号有效得多。用户回还是找不到,第二轮改为问手机号后四位作为辅助匹配。如果有了后四位仍然查不到,就不再纠缠,直接进入转人工流程,让客服在后台查。连环追问是最差的体验,等于把接口报错转嫁给了用户,每多问一轮都在消耗耐心。
参数校验也要做:订单号位数不对、明显是随手打的字符串,不要真发去后端查。校验在链路侧做掉,能挡掉一半无效调用,省的是后端资源和用户的时间。
还有一种情况值得单独处理:用户把订单号和别的话混在一起,比如我的订单是 SO20260901 发了吗。模型提取时可能连中文一起带出来,校验规则要把无关字符剥掉再比对。这类情况在真实会话里占比不低,我在测试集里专门留了两条样本。
与业务后端联调
联调那天我印象最深的是一个低级问题:第一版订单接口返回了十四个字段,包括下单人、收货人、备注、优惠明细这些。结果回答冗长到没法看——模型拿到这么多素材,恨不得把订单详情单全文复述一遍,用户其实只想知道一句话:发货了没有。
收窄返回字段是联调的核心动作。把十四个字段砍到三个:订单状态、物流单号、下单时间。回答立刻清爽:您的订单已于十月一日发货,物流单号已附上。这次教训让我定了个规矩:接口字段按回答必需返回,宁可缺,不可多。每多一个字段,就多一段模型发挥的空间,也多一分敏感数据外泄的风险。
其一,超时控制。大模型侧的等待耐心往往比业务接口的响应时间更长,我在工具节点配置了超时阈值,超过就按错误码三走兜底,不至于让用户干等半分钟。阈值参考订单接口压测的 p99 耗时定的,留了一倍余量。超时返回兜底时千万别说系统故障,说查询仍在处理中可能更准确——但从用户体感出发,标准说法是正在为您核实,稍后可再次查询或直接转人工。
其二,错误信息对齐。最初业务侧直接把技术报错文本返回来,模型把它原样转述给用户,什么数据库连接超时之类的内部细节都漏出去了,既难看也不安全。后来统一成上表的错误码结构,模型只说人话:查不到、信息不对、稍后再试。
其三,联调用例要齐全。我准备了四类:正常查询、缺参反问、错参提示、接口超时,每一类都跑通才算联调完成。这些用例我一直留着,后来归入 5.2 的迭代测试集,每次改链路回归一遍。用例脚本我让 AI 辅助起草再人工校验,效率比从头写高,做法见Claude Code 指南。
上线后的观察
工具调用上线一周,我盯着三类数据看:触发率(多少会话调了工具)、成功率(调用里返回成功码的占比)、平均耗时。触发率比预期低——不少用户明明问了订单却没触发,翻会话发现是工具描述写得太窄,模型只在出现订单两个字时才敢调。把描述改成包含物流、到哪了等说法之后,触发率回到预期。
成功率头两天九成出头,掉的量主要是订单不存在和信息不匹配两类。这不是 bug,是真实分布:用户记错单号、用错手机号本就常见。这两类错误码占比如此稳定,我们干脆在兜底话术里直接写明最常见原因,用户自己就能核对。
平均耗时稳定在两秒内,超时率低于千分之五,阈值余量留得还算合理。这些数字怎么长期跟踪、出问题怎么告警,在 5.3 监控告警一节展开。
安全:两条红线
工具调用把智能体接到了真实业务系统上,权限和数据都要收住。
一是鉴权。智能体调业务接口必须带访问令牌或密钥,密钥只配在平台侧的节点配置里,绝不写进提示词、不进前端代码、不进任何会被用户看到的回复。密钥还要定期轮换,别配完就忘。上线时这部分会经过 API 网关集中收口,鉴权与限流在 4.1 展开。
二是最小数据返回。接口只返回回答用户问题所必需的字段。收货地址、完整手机号、支付凭证这些一律不返回,既减少泄露面,也避免模型把敏感信息复述出去。客服组起初想顺手返回订单金额,理由是用户经常问,被我用这条理由挡了回去——问金额的需求另外走一个脱敏接口,而不是在查询工具里全量带出。
延伸一句:脱敏接口和查询接口分开,不是多此一举。查询接口频率高、参数杂,泄露面天然大;金额接口频率低但敏感,单独走更严格的鉴权。两个接口的风险等级不同,混在一起只图省事,出问题时分不清是哪一侧漏的。
其三,调用日志要脱敏。工具调用的日志里天然带着参数和返回结果,订单号、手机号尾号会一起落盘。我对日志做了脱敏处理:只保留工具名、调用时间、成功与否和错误码,参数值和返回体在落盘前替换掉,只在不成立时才临时打开完整日志排查。日志权限也收紧在技术组内部,客服侧看不到。这条不做,等于把用户数据明文存在服务器上送给下一次故障当陪葬。
工具调用的链路长、节点多,排查问题时优先看三处:工具节点是否被触发、参数提取是否正确、接口返回是什么。这三步定位九成问题:没触发多半是工具描述没写好;参数错多半是校验和提取的问题;返回错就翻业务后端的日志。对接口环境本身不熟的,腾讯云五件套实战里有 CVM 服务部署的完整说明。
延伸阅读
- 服务器常见问题:业务接口部署后的常见报错排查。
- Claude Code 指南:用 AI 辅助编写联调脚本与回归测试用例。
