工具路由
本章讲 NLWeb「不止搜索」的那一面:怎么把「问菜谱配料」「对比两部电影」这类不同意图,路由到不同的处理器。机制是「XML 声明工具 + LLM 给工具打分 + 动态加载处理器」。
路径基准提示:本章
core/...、methods/...等.py路径相对仓库的AskAgent/python/;而config/tools.xml、config/config_nlweb.yaml相对仓库根(config/在根目录,不在AskAgent/python/下)。
3.1 为什么要工具,而不只是搜索
「找 20 分钟能做的意面」是搜索;但「鸡肉意面里放了什么」是问某个具体条目的细节,「A 和 B 哪个评分高」是对比。 这些都不该走「检索一堆候选再排序」,而该有专门处理逻辑。
NLWeb 把这些处理逻辑抽象成工具(Tool),让一个 ToolSelector 先判断「这句话该用哪个工具」。
3.2 工具是 XML 声明的
工具不写死在代码里,而是声明在 config/tools.xml(相对仓库根)。每个工具带:名字、示例、一段给 LLM 的判定 prompt、返回结构、以及处理器类路径。
看真实的 search 工具声明(config/tools.xml,default 站的 Item 类型下):它的 prompt 教 LLM「搜索工具适合按属性找东西,不适合问某个具体条目的细节」,返回结构是 {score, search_query}。而 details 工具的 prompt 则教「用户点名某条目要细节时打 80-100,想搜索时打 0-30」,并配了 handler 标签指向 methods.item_details.ItemDetailsHandler。
加载逻辑在 _load_tools_from_file(router.py:52):用 xml.etree 解析,按 <Site id=...> 找站点(找不到回退到 default,router.py:75),再遍历每个 schema 类型下的 <Tool>,解析出 Tool dataclass(router.py:26)。
Tool 的字段(router.py:26):name、prompt、return_structure、handler_class 等。handler_class 是字符串形式的模块路径——这是后面动态加载的关键。