思考: LLM 自己“不知道”某个事实性问题的答案,但仍然能“知道”去调用工具获取正确答案,这听起来确实有点像个悖论
该内容触及了大型语言模型(LLM)的核心局限性以及(Agents)的智能所在。
实际上,LLM 并不是真的“知道”某个特定事实是否正确,而是通过模式识别和指令遵循来运作的。
LLM 如何“知道”去调用工具?
LLM 知道去调用工具,并不是因为它在调用前就**“知道”工具能提供正确**答案,而是因为它被训练成了能够理解:
-
它自己的知识边界: 大模型在训练时接触了大量的文本数据。对于某些特定、不常见的或时效性强的问题(比如“奥巴马的生日”,虽然是常识但具体日期可能不在模型的精确记忆中),它可能没有被明确地训练过这些信息,或者它对这些信息的置信度很低。在代理的上下文中,当它面对一个它内部知识无法直接、高置信度地回答的问题时,它会倾向于寻求外部帮助。
-
工具的描述和用途: 这是最关键的一点。当我们将工具(比如
duckduckgo_search
)提供给代理时,我们同时提供了该工具的名称和详细描述。例如:@tool def duckduckgo_search(query: str) -> str:"""这个工具可以用于搜索互联网上的信息。当你需要获取实时信息、特定事实、事件日期、人物履历等,且这些信息可能不在你的内部知识库中时,请使用此工具。输入应该是一个清晰的搜索查询字符串。"""
大模型在“思考”阶段,会:
- 分析用户问题: “奥巴马生日是哪天?”这是一个明显需要事实性查询的问题。
- 匹配工具描述: 它会将其对用户问题的理解与它所拥有的所有工具的描述进行匹配。当它看到
duckduckgo_search
工具的描述提到“获取实时信息、特定事实、事件日期、人物履历”时,它会识别到这个工具与当前的任务高度相关。 - 遵循指令: 代理的 ReAct 提示模板(我们从
hub.pull("hwchase17/react")
拉取的那个)会明确指示 LLM 按照“思考-行动-观察”的模式进行。如果 LLM 认为某个工具是解决当前问题的最佳方式,它就会按照 ReAct 提示的结构,生成Action: duckduckgo_search[奥巴马生日]
这样的指令。
-
预测下一个词(Next Token Prediction): LLM 的底层机制始终是预测下一个最可能出现的词。在代理的提示语境中,如果它判断当前问题无法直接回答,并且有一个工具的描述与问题匹配,那么生成“
Thought: I need to find the birthday of Obama. Action: duckduckgo_search[Barack Obama birthday]
”这样的文本序列,就成了当前语境下概率最高的“下一个词”序列。
为什么它不会乱给一个答案(比如 1 月 1 日)?
在代理的场景下,LLM 之所以不会随意编造一个错误答案(比如“奥巴马生日是 1 月 1 日”),有几个原因:
- 明确的提示指导: ReAct 提示模板明确地引导 LLM 进行推理,并说明在无法直接回答时应该使用工具。提示中通常包含这样的指令:“如果你需要外部信息,请使用工具。一旦你有了答案,就用
Final Answer:
格式回答。” - 避免“幻觉”的倾向(在代理语境下): 虽然 LLM 本身可能产生幻觉,但在代理这种结构化的应用中,当它被明确赋予了“使用工具”的选择时,它会倾向于选择这一条路径来获取更可靠的信息,而不是“编造”一个。代理的训练和提示工程旨在最大化其决策能力,最小化其不负责任的生成。
- 没有足够高的置信度: 对于像“奥巴马生日”这样的具体事实,如果 LLM 在其内部参数中没有存储这个精确信息,或者对其存储的置信度不高,它就不会选择直接生成一个答案。相反,它会识别出这是一个“外部知识”类型的问题,并转向工具。
总结
大模型在代理中的行为,不是因为它“知道”某个答案是错误的,而是因为它在训练中学会了:
- 识别不同类型的问题(可以理解问题)
- 评估自己内部知识的确定性(可以知道自己的知识边界)
- 根据工具的描述和当前任务,判断何时以及如何调用工具来获取信息(可以知道外部信息,比如工具)
- 遵循明确的指令(如 ReAct 模式),在需要外部信息时,优先采取行动调用工具,而不是直接生成不确定的答案(优先跟随指令,选择可靠信息)
因此,代理的核心在于为 LLM 提供了一个决策框架和一套执行能力。LLM 就像一个聪明的学生,当遇到不会的问题时,它会根据老师(提示)的指导和手头的资源(工具),去查阅资料(调用工具)而不是胡编乱造。工具的详细描述就是它“查阅资料”的指南。