用户只说了一句话,工具需要的参数从哪来
开篇引言
上一篇走完了 MCP 工具调用的完整链路——意图分流 → 注册表查找 → 参数提取 → 远程执行 → 结果格式化 → 汇入主流水线。但链路中有一步被当黑盒跳过了:参数提取。
executeSingleMcpTool() 里有这样一行代码:
Map<String, Object> params = mcpParameterExtractor.extractParameters(
question, tool, customParamPrompt
);
传入的是用户说的一句大白话,返回的是工具需要的结构化参数 Map。就拿上一篇用的 sales_query 工具来说,它定义了 6 个参数(region、period、product、salesPerson、queryType、limit),用户说的是“华东区本月的 销售额是多少”。6 个参数里用户只明确提到了 2 个——华东和本月,queryType 需要从问句语义推断出来(问销售额 → summary),剩下 3 个用户压根没提。
这中间的转换怎么做?写一堆正则和关键词匹配?光本月的表达方式就有这个月、当月、本月份、这月到现在等好几种变体,再加上上个季度、最近三十天、Q3 这些更复杂的时间表达,规则根本写不完。
所以 Ragent 选了另一条路——用 LLM 来做参数提取。把工具的参数定义和用户问题一起丢给大模型,让它从自然语言中抽出结构化参数。本篇就来拆这个参数提取器的内部实现。
为什么用 LLM 而不是规则匹配
1. 自然语言表达的多样性
同一个参数值,用户可以有很多种说法。拿 sales_query 工具的几个参数来感受一下:
| 参数 | 规范值 | 用户可能的表达 |
|---|---|---|
region | 华东 | 华东、华东区、华东地区、东部 |
period | 上季度 | 上季度、上个季度、前一个季度、Q2(如果当前是 Q3) |
queryType | ranking | 排名、排行、排行榜、谁卖得最多、TOP 几 |
limit | 5 | 前五、前 5 名、top 5、五个 |
如果用规则匹配,每个参数的每种说法都要写正则或关键词列表。工具有 6 个参数,每个参数平均 5 种说法,就是 30 条规则。再来一个新工具,又是 30 条。工具数量一上去,规则的维护成本比写工具本身还高。
2. LLM 的天然优势
LLM 天生理解同义表达、口语化表述、省略和推断。你不需要告诉它“前五”等于 5,它自己就能推断出来。一套 Prompt 搞定所有工具的参数提取——不管工具有 3 个参数还是 30 个参数,不管参数是地区名还是日期范围,LLM 都能处理。
当然,用 LLM 也有代价——多一次 LLM 调用,多几十到几百毫秒的延迟。但和规则匹配的维护成本相比,这个代价值得。
参数提取器接口
McpParameterExtractor 定义了参数提取的契约:
public interface McpParameterExtractor {
Map<String, Object> extractParameters(String userQuestion, Tool tool);
default Map<String, Object> extractParameters(String userQuestion, Tool tool,
String customPromptTemplate) {
return extractParameters(userQuestion, tool);
}
}