什么是 Agent 的“幻觉”(Hallucination)?特别是在调用 API 时产生的参数幻觉如何解决?
这是一个非常专业且实际的问题。在构建 AI Agent(智能体)时,幻觉是最大的挑战之一,尤其是在涉及精确操作(如调用 API)时。
以下是关于 Agent 幻觉的定义,以及针对 API 参数幻觉 的深度解析和解决方案。
一、 什么是 Agent 的“幻觉”(Hallucination)?
在 AI Agent 的语境下,幻觉不仅仅是“胡说八道”,它指的是 LLM(大语言模型)生成了看似合理但实际上错误、不存在或不忠实于上下文的指令、计划或数据。
对于 Agent 而言,幻觉通常分为三类:
- 事实性幻觉 (Fact Hallucination):
- Agent 回答了错误的事实(例如:“埃隆·马斯克发明了相对论”)。
- 指令遵循幻觉 (Instruction Following Hallucination):
- Agent 忽略了系统提示词(System Prompt)中的安全限制或业务规则。
- 工具/API 幻觉 (Tool/API Hallucination):
- 调用不存在的工具:Agent 试图调用一个你没给它定义的函数(例如
search_google_images,但你只给了search_text)。 - 参数幻觉 (Parameter Hallucination):这是你最关心的部分。Agent 决定调用正确的工具,但编造了错误的参数值、格式或键名。
- 调用不存在的工具:Agent 试图调用一个你没给它定义的函数(例如
二、 什么是“API 参数幻觉”?
当 Agent 决定调用一个函数(Function Calling)时,它必须从对话历史中提取信息来填充函数的参数。参数幻觉通常表现为以下几种形式:
- 无中生有(Invented Parameters):
- API 定义:
get_weather(city) - 幻觉调用:
get_weather(city="Beijing", date="tomorrow") - 问题:API 根本不支持
date参数,但这会导致代码报错。
- API 定义:
- 瞎猜数值(Guessing Values):
- 用户说:“帮我查下订单。”
- API 定义:
query_order(order_id) - 幻觉调用:
query_order(order_id="123456") - 问题:用户没提供 ID,Agent 为了完成任务自己编了一个。
- 格式错误(Format Mismatch):
- API 定义:
set_alarm(time: string)(要求 ISO 8601 格式) - 幻觉调用:
set_alarm(time="下午三点") - 问题:参数存在,但数据类型或格式不符合后端要求。
- API 定义:
三、 如何解决 API 调用时的参数幻觉?
解决这个问题不能只靠“模型变强”,需要从 提示工程(Prompting)、架构设计(Architecture) 和 验证机制(Validation) 三个层面入手。
1. 提示工程层面 (Prompt Engineering)
- 提供极其详尽的工具定义 (Rich Schema Definitions):
不要只给函数名。LLM 依赖描述来理解参数。- 差的定义:
calculate_loan(amount, rate, time) - 好的定义:使用 JSON Schema,并添加描述。json
{ "name": "calculate_loan", "description": "计算贷款利息", "parameters": { "type": "object", "properties": { "rate": { "type": "number", "description": "年利率,必须是小数形式,例如 0.05 代表 5%" } }, "required": ["rate"] } }
- 差的定义:
- Few-Shot Prompting (少样本提示):
在 System Prompt 中直接给出“正确”和“错误”的调用示例。示例:
"当你调用search_user时,如果用户没有提供user_id,不要编造一个,请反问用户。
错误示例:用户说'查用户' -> 调用search_user(id=1)
正确示例:用户说'查用户' -> 回复 '请提供用户ID'"
2. 架构与流程层面 (Architecture & Workflow)
- 强制类型约束 (Constrained Decoding / Grammars):
如果你使用的是开源模型(如 Llama.cpp 或 vLLM),或者 OpenAI 的JSON Mode/Structured Outputs,可以强制模型的输出必须符合特定的 JSON Schema。这从底层生成概率上切断了生成非法参数的可能性。 - 参数槽位检查 (Slot Filling Strategy):
设计一个中间层,在调用 API 之前,检查所有Required参数是否真的从用户的话语中提取到了。- 如果参数缺失,不要让 LLM 猜,而是强制 Agent 进入“追问模式”(Ask for clarification)。
- 逻辑:
if parameter is None or Guess -> return "Ask User"
3. 验证与自愈机制 (Validation & Self-Correction Loop) —— 最有效的方法
这是目前构建高可靠 Agent 的标准做法。不要盲目信任 LLM 的输出,而是建立一个 "LLM -> 代码验证 -> 错误反馈 -> LLM 重试" 的闭环。
具体步骤:
- LLM 生成调用:Agent 输出
call_api(date="next tuesday")。 - 代码层拦截验证:使用 Pydantic (Python) 或 Zod (JS) 等库验证参数。
- 代码发现错误:
date字段必须是YYYY-MM-DD格式。
- 代码发现错误:
- 构造错误反馈:不要直接把 Python 的 Traceback 扔给 LLM,而是构造一个易读的错误提示。
- System Message to LLM:
"你尝试调用
call_api,但参数date的值 'next tuesday' 无效。该字段要求格式为 'YYYY-MM-DD'。请根据今天的日期(2023-10-27)修正参数并重新调用。"
- System Message to LLM:
- LLM 自我修正:LLM 接收到错误反馈后,会利用其推理能力修正输出:
- Agent 新输出:
call_api(date="2023-10-31")。
- Agent 新输出:
4. 代码示例 (基于 Pydantic 的验证思路)
python
from pydantic import BaseModel, ValidationError, Field
# 1. 定义严格的参数结构
class WeatherParams(BaseModel):
city: str = Field(..., description="城市名称")
date: str = Field(..., pattern=r"^\d{4}-\d{2}-\d{2}$", description="日期,格式必须是 YYYY-MM-DD")
# 2. 模拟 Agent 执行流程
def execute_agent_action(llm_output_json):
try:
# 尝试验证 LLM 的输出
params = WeatherParams(llm_output_json)
return f"调用成功: {params}"
except ValidationError as e:
# 3. 捕捉幻觉导致的格式错误
error_msg = f"参数验证失败: {e.errors()}"
# 4. 【关键】将错误返回给 LLM 让其重试 (伪代码)
# return call_llm_again(history + [error_msg])
return f"系统提示 Agent: 你的参数格式错了,请修正。错误详情: {error_msg}"
# 假设 LLM 幻觉了,输出了错误的日期格式
llm_hallucination = {"city": "Shanghai", "date": "明天"}
print(execute_agent_action(llm_hallucination))
# 结果会包含具体的错误信息,Agent 看到这个信息就能修正为 "2023-10-xx"
总结
解决 API 参数幻觉的核心心法是:不要信任模型,要信任校验。
- 事前:用详细的 Schema 和 Few-Shot 提示教它怎么做。
- 事中:用 Pydantic/JSON Schema 强校验它的输出。
- 事后:构建“错误-修正”闭环,让 Agent 有机会自己改错。