nlweb — 本课题摘录
读了哪几篇: 03-tool-routing(工具路由)。
其余四篇(一次请求的主线、排序与抢跑、检索抽象、协议面)本轮没读——属 RAG 与界面课题。
这一家在本课题里只贡献一条,但这一条是"怎么认出模型要调工具"的第三种答案:不认,改成让模型给每个工具打分。
它对本课题回答了什么
决定二:让模型给每个工具打分,而不是让它返回一个调用
主流做法是:把工具清单给模型,模型返回"我要调 X,参数是 Y"。
它的做法是反过来的:每个工具自带一段"判定说明",并发地拿每一段去问模型"这个工具对这句话合不合适,打个分",谁分高用谁。 (依据:协议库 · NLWeb · 工具路由 —— 每个工具带自己的判定 prompt,并发问 LLM「这工具对这句话合不合适,打分」,谁分高用谁)
工具的判定说明写得很具体,比如详情工具的说明是:"用户点名某条目要细节时打 80-100,想搜索时打 0-30"。
这条为什么值得记: 主流做法要求模型同时做两件事——判断该用哪个工具、生成合法参数。 打分法把这两件事拆开了:先只判断"该不该用",判完了再单独生成参数。 代价是每个工具一次模型调用(可并发);好处是不挑模型——只要模型会输出一个数字就行。
三个配套机制,缺一不可
| 机制 | 做什么 | 为什么 |
|---|---|---|
| 早停 | 边完成边看,一旦某个工具分数达到高阈值(90),立刻取消其余调用直接返回 | 常见意图往往有一个工具明显高分,早停省下其余调用 |
| 单工具短路 | 如果只有一个工具可选,直接给满分,跳过模型 | 省一次调用 |
| 及格线 + 兜底 | 低于及格线(70)的工具被滤掉;全都没过线就回退到搜索工具 | 保证"再不济也能搜一下" |
(依据:协议库 · NLWeb · 工具路由 —— 三个配套机制是早停(分数≥90 立刻 cancel 其余 task)、单工具短路(只有一个工具时直接 100 分跳过 LLM)、及格线 70 加兜底(全没过线回退到 search 工具))
"全都没过线怎么办"这一问是主流做法回避掉的。 主流做法里,模型不调工具就是"它说完了";这里明确定义了"没有一个工具合适"这种情况,并给了兜底。 我们的循环也该想清楚:模型既不给答案也不调工具时,该怎么办。
决定一:工具是声明式配置,不写死在代码里
工具声明在一个配置文件里,每个工具带:名字、示例、给模型的判定说明、返回结构、以及处理器的类路径。 (依据:协议库 · NLWeb · 工具路由 —— 工具声明在 config/tools.xml 而非写死在代码里,每个工具带名字、示例、给 LLM 的判定 prompt、返回结构、处理器类路径,处理器按字符串路径动态加载)
处理器是按字符串路径动态加载的。 这意味着加一个工具 = 加一段配置,不改代码。
决定一补充:工具集按类型继承
站点问的是菜谱还是商品,决定了可用的工具集。先收通用工具,再用具体类型的工具覆盖同名的。 (依据:协议库 · NLWeb · 工具路由 —— 工具集按 schema 类型继承——先收通用类型的工具,再用具体类型的工具覆盖同名的,所以具体站点既有通用搜索又有专属详情)
"覆盖同名"这个语义值得记。 我们如果要做"不同场景给不同工具",这是一种很轻的做法: 一份基础工具集 + 按场景覆盖几个,而不是每个场景各配一份完整清单。
一处联动:选中的不是默认工具时,要叫停抢跑
它有一条"边检索边赌"的优化(默认假设用户在搜索,提前开跑)。如果打分结果表明该用的不是搜索工具,就发信号叫停那条抢跑。
反过来,如果请求里显式指定了工具,就整个跳过模型选择。
这两条合起来是一个通用模式:猜测性优化必须配一个"猜错了怎么撤"的信号,以及一个"别猜了"的旁路。