前两个阶段,AgentHub 已经能通过模型选择工具,并记录模型和工具的调用过程。接下来,我想让它处理一个更接近业务的问题:根据商店提供的资料回答售后咨询。

这件事把几个问题放到了一起:回答依据从哪里来,每轮请求到底带了多少内容,以及模型给出的工具参数应该怎样检查。

这篇记录的是截至 2026 年 10 月 9 日完成的知识检索、模型用量统计和独立图片参数校验。这里的演示商店政策都是练习用的虚构资料。

先做一条能跟清楚的检索链路

我先把演示商店的退货、保修和运费政策写进 Markdown 文档,用二级标题划分片段,再增加 knowledge_search 工具。

工具接受空格分隔的关键词,比如:

1
耳机 拆封 退货

当前执行过程是:

  1. 检查上下文是否已取消,拒绝空关键词输入。
  2. 读取知识文档,按二级标题拆分片段。
  3. 将关键词和片段转换为小写,做子串匹配。
  4. 一个片段只要命中任意关键词,就加入结果。
  5. 返回片段内容,并附上来源文件名。

因此,工具返回给模型的是资料片段,模型再根据这些片段生成回答。

返回格式会包含这样的来源标识:

1
2
来源:after_sales.md
## 七天退货

把来源一起回传,可以帮助回答保留依据。不过,模型最终是否引用正确、是否严格遵守资料,仍然需要检查;工具提供资料不能自动保证答案正确。

无资料,也应该是一个明确结果

检索工具里有两类需要分开的情况。

如果文件读取失败、文档没有预期的二级标题,或者输入关键词为空,那是执行或输入错误,会返回 error。

如果文档正常读取,只是没有片段命中,则返回:

未找到相关资料。当前知识库无法提供这个问题的答案。

工具描述也要求模型在资料不足时说明信息不足。这样,模型下一轮能知道发生的是“正常检索但没有结果”,而不是把它误当成工具运行失败。

这只能提供明确反馈,不能保证模型每次都遵守。后续仍需要用固定问题检查有资料、无资料和资料冲突时的回答表现。

关键词匹配的不足已经能看见

当前规则是“任意关键词命中就返回片段”。它简单,但也容易带回过多内容。

例如,耳机 拆封 退货 这组词,在当前演示文档里会命中七天退货、耳机保修和退货运费三个片段。模型要处理的资料比直接回答拆封退货问题所需的更多。

接下来可以考虑统计关键词命中数、排序并只返回前 K 个片段。但这一版还没有评分、排序和 Top-K,也没有接入向量检索。

先保留这条简单链路,可以把“用户问题 → 检索参数 → 资料片段 → 最终回答”逐步检查清楚,再决定检索能力应该怎样升级。

用量信息要表达“有没有取得”

随着循环继续,历史消息和工具结果会被送进下一轮模型请求。为了观察这一过程,我把模型客户端的返回值从正文字符串改成了 Response:

1
2
3
4
5
6
7
8
9
10
type Response struct {
Content string
Usage *Usage
}

type Usage struct {
PromptTokens int
CompletionTokens int
TotalTokens int
}

Usage 使用指针,是为了区分接口返回了用量数据,还是根本没有返回。

没有取得用量时,控制台会显示“未取得”。如果只得到部分调用的用量,任务结束时会说明累计数字只包含已取得的部分。

这样可以避免把缺失数据打印成零,让一个看起来很精确的数字造成误解。

目前还分别记录模型调用次数和取得用量的调用次数,并通过延迟执行的结束回调汇总。因此提前返回或循环耗尽时,也会输出本次运行已经收集到的统计。

字符数、Token 和费用分别看

模型调用前,程序会记录消息条数和消息正文的 rune 数;调用后,如果接口提供了 usage,再记录输入、输出和总 Token 数。

正文字符数可以帮助观察输入是否不断增长,但它不等于 Token 数,也不包含模型接口所有潜在的协议开销。Token 应以接口实际返回的数据为准。

同样,用量统计还不等于费用统计。这一版没有接入价格表、预算控制或自动压缩。我现在能够观察的是每轮输入变化、调用耗时,以及已取得的 Token 用量。

这些数据会帮助后续判断:检索结果是否太多,是否反复带入了不必要的历史,以及一次任务大概经历了多少次模型调用。

独立参数校验先把规则写清楚

这一阶段还增加了 internal/tool/validation 包,用 JSON Schema 校验图片缩放参数。

输入样例是:

1
{"path": "picture/window.jpg", "width": 256}

当前规则要求根值为对象,必须包含字符串 path 和整数 width,宽度范围为 10 到 4096。

对应测试覆盖了边界值、缺失字段、类型错误和 JSON 格式错误。例如:

输入情况当前结果
宽度为 10 或 4096通过
宽度为 9 或 4097规则校验失败
宽度为字符串 "128"规则校验失败
宽度为 128.0通过,数值没有小数部分
宽度为 128.5规则校验失败
缺少必需字段规则校验失败
空路径或额外字段当前规则允许
JSON 损坏或连续包含两个值JSON 解析失败

“空路径允许”和“额外字段允许”也是现有规则的真实行为。测试把它们明确记录下来,方便以后决定是否收紧规则。

这个校验器不会检查路径对应的文件是否存在、是否允许访问,也不会执行图片处理。数据满足 schema,只说明它满足当前定义的结构和取值规则。

当前校验尚未进入工具执行链路

这一点需要单独说清楚:独立校验器已经有实现和测试,但还没有接入 ImageScaling.Execute 或 Agent 循环。

当前图片工具仍然接收“路径 宽度”的文本参数,并在自己的 Execute 里做原有检查。Agent 循环也仍然直接调用工具,没有完成执行前的权限判断。

因此,目前还不能说“所有工具已经统一使用 JSON 参数”或“Agent 已有完整权限系统”。把当前的接口和测试单独做好,是后续接入执行链路的准备。

这一阶段完成的内容

到这里,AgentHub 有了三个工具:Echo、图片缩放和知识检索。模型与工具调用有轨迹,模型返回值能携带可选用量,图片参数也有独立的规则校验。