Agent 开发实战:幻觉和工具选择错误的 5 个解决方案

0. 痛点:Agent 开始"胡说八道"了

你有没有遇到过这种情况:

用户:帮我查一下腾讯的股价
Agent:好的,让我查询...
[调用 get_stock_price("腾讯")]
[API 返回:{"error": "Invalid symbol"}]
Agent:腾讯的股价是 123.45 元
[幻觉!因为工具调用失败,Agent 瞎编了一个数字]

用户:今天北京天气怎么样?
Agent:好的,让我查询...
[调用 get_weather("北京")]
Agent:北京今天晴天,温度 25°C
[实际是雨天,Agent 没有调用工具就直接回答了]

或者更糟:

用户:帮我查一下苹果公司的市值
Agent:好的,让我查询...
[调用 get_weather("苹果")]
[工具选择错误!应该是 get_company_info("苹果")]

这就是幻觉(Hallucination)和工具选择错误(Tool Selection Error)


1. 问题根源:为什么 Agent 会幻觉和选错工具?

原因 1:工具描述不清晰

# 工具定义(描述不清晰)
tools = [
    {
        "name": "get_weather",
        "description": "获取天气",  # 太简略!
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string"}
            }
        }
    }
]

# 问题:Agent 不知道这个工具能查哪些城市、返回什么格式
# 容易选错工具或误解返回结果

原因 2:Few-shot 示例不足

# System Prompt(缺少示例)
prompt = """
你是一个助手,可以调用以下工具:
- get_weather(city): 获取天气
- get_stock_price(symbol): 获取股价

用户问题:
"""

# 问题:没有示例,Agent 不知道如何正确调用工具
# 容易选错工具或传错参数

原因 3:输出格式约束不够严格

# 工具定义(输出格式不严格)
tools = [
    {
        "name": "get_weather",
        "description": "获取天气",
        "parameters": {...},
        "returns": "天气信息"  # 太模糊!
    }
]

# 问题:Agent 不知道返回格式,容易自由发挥(幻觉)

解决方案 1:优化工具描述(Tool Description Optimization)

原理

给工具写清晰、详细的描述,让 Agent 准确理解工具的用途和限制。

# ❌ 错误示例(描述太简略)
{
    "name": "get_weather",
    "description": "获取天气",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {"type": "string"}
        }
    }
}

# ✅ 正确示例(描述详细)
{
    "name": "get_weather",
    "description": """
获取指定城市的当前天气信息。

支持的城市:北京、上海、广州、深圳、杭州、成都(其他城市返回错误)
返回格式:{"weather": "晴天/多云/雨天/雪天", "temperature": 温度(摄氏度)}
注意事项:如果城市不支持,返回 {"error": "City not supported"}
""",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {
                "type": "string",
                "description": "城市名称(中文,例如:北京、上海)"
            }
        },
        "required": ["city"]
    },
    "returns": {
        "type": "object",
        "properties": {
            "weather": {"type": "string", "description": "天气状况"},
            "temperature": {"type": "number", "description": "温度(摄氏度)"}
        }
    }
}

自动化工具描述优化

from typing import Dict, Any


def optimize_tool_description(tool_def: Dict[str, Any]) -> Dict[str, Any]:
    """
    自动优化工具描述
    
    优化策略:
    1. 描述要包含:功能、支持范围、返回格式、注意事项
    2. 参数要包含:类型、描述、示例值
    3. 返回值要包含:类型、描述、示例
    """
    optimized = tool_def.copy()
    
    # 1. 优化描述
    if "description" in optimized:
        desc = optimized["description"]
        
        # 如果描述太短,提示需要补充
        if len(desc) < 50:
            print(f"⚠️  工具 {optimized['name']} 的描述太短,建议补充:功能、支持范围、返回格式、注意事项")
    
    # 2. 优化参数描述
    if "parameters" in optimized:
        for param_name, param_def in optimized["parameters"].get("properties", {}).items():
            if "description" not in param_def:
                print(f"⚠️  参数 {param_name} 缺少描述,建议补充")
                param_def["description"] = f"{param_name} 参数"  # 默认描述
    
    # 3. 添加返回值描述(如果缺失)
    if "returns" not in optimized:
        print(f"⚠️  工具 {optimized['name']} 缺少返回值描述,建议补充")
        optimized["returns"] = {"description": "返回值格式待补充"}
    
    return optimized


# 使用示例
tool_def = {
    "name": "get_weather",
    "description": "获取天气",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {"type": "string"}
        }
    }
}

optimized_tool = optimize_tool_description(tool_def)
print(json.dumps(optimized_tool, indent=2, ensure_ascii=False))

优点:提高工具选择准确率,减少幻觉
缺点:需要人工编写高质量描述(AI 辅助)


解决方案 2:Few-shot 示例(Few-shot Examples)

原理

在 System Prompt 中提供几个正确调用的示例,让 Agent 学习如何正确调用工具。

# System Prompt 模板(带 Few-shot 示例)
FEW_SHOT_PROMPT = """
你是一个助手,可以调用以下工具:
- get_weather(city): 获取指定城市的天气
- get_stock_price(symbol): 获取指定股票的股价

【重要】调用工具时,必须严格按照以下格式:
```json
{
  "tool": "工具名",
  "parameters": {
    "参数名": "参数值"
  }
}

【示例 1】
用户:北京今天天气怎么样?
你的思考:需要调用 get_weather 工具,参数是 city=“北京”
你的回答:

{
  "tool": "get_weather",
  "parameters": {
    "city": "北京"
  }
}

【示例 2】
用户:腾讯的股价是多少?
你的思考:需要调用 get_stock_price 工具,参数是 symbol=“0700.HK”(腾讯港股代码)
你的回答:

{
  "tool": "get_stock_price",
  "parameters": {
    "symbol": "0700.HK"
  }
}

【示例 3】
用户:今天天气真好啊
你的思考:这是闲聊,不需要调用工具
你的回答:是的,今天天气确实不错!

现在,请处理用户的问题:
用户问题:{user_query}
“”"


**代码示例:动态生成 Few-shot 示例**

```python
from typing import List, Dict


class FewShotGenerator:
    """
    Few-shot 示例生成器
    """
    def __init__(self):
        self.examples: List[Dict] = []
    
    def add_example(self, user_query: str, tool_name: str, parameters: Dict, reasoning: str):
        """添加一个示例"""
        self.examples.append({
            "user_query": user_query,
            "tool_name": tool_name,
            "parameters": parameters,
            "reasoning": reasoning
        })
    
    def generate_prompt(self, user_query: str) -> str:
        """生成带 Few-shot 的 Prompt"""
        prompt = """
你是一个助手,可以调用以下工具:
- get_weather(city): 获取指定城市的天气
- get_stock_price(symbol): 获取指定股票的股价

【示例】
"""

        # 添加所有示例
        for i, example in enumerate(self.examples, 1):
            prompt += f"""
【示例 {i}】
用户:{example['user_query']}
你的思考:{example['reasoning']}
你的回答:
```json
{{
  "tool": "{example['tool_name']}",
  "parameters": {json.dumps(example['parameters'], ensure_ascii=False)}
}}

“”"

    # 添加当前用户问题
    prompt += f"""

现在,请处理用户的问题:
用户问题:{user_query}
“”"

    return prompt

使用示例

generator = FewShotGenerator()

添加示例

generator.add_example(
user_query=“北京今天天气怎么样?”,
tool_name=“get_weather”,
parameters={“city”: “北京”},
reasoning=“需要调用 get_weather 工具,参数是 city=北京”
)

generator.add_example(
user_query=“腾讯的股价是多少?”,
tool_name=“get_stock_price”,
parameters={“symbol”: “0700.HK”},
reasoning=“需要调用 get_stock_price 工具,参数是 symbol=0700.HK”
)

生成 Prompt

user_query = “上海明天会下雨吗?”
prompt = generator.generate_prompt(user_query)
print(prompt)


**优点**:显著提高工具选择准确率  
**缺点**:占用 Token(示例越多,Token 消耗越大)

---

## 解决方案 3:输出格式约束(Output Format Constraints)

### 原理

强制 Agent 按照严格格式输出,减少自由发挥(幻觉)。

```python
from typing import Dict, Any
import json
import re


class OutputFormatter:
    """
    输出格式约束器
    """
    def __init__(self, schema: Dict[str, Any]):
        """
        Args:
            schema: 输出格式 Schema
            例如:
            {
                "type": "object",
                "properties": {
                    "tool": {"type": "string", "enum": ["get_weather", "get_stock_price", "none"]},
                    "parameters": {"type": "object"}
                },
                "required": ["tool"]
            }
        """
        self.schema = schema
    
    def format(self, output: str) -> Dict[str, Any]:
        """
        格式化输出(解析 + 验证)
        
        Returns:
            解析后的字典
            
        Raises:
            ValueError: 输出格式不符合 Schema
        """
        # 1. 尝试解析 JSON
        try:
            parsed = json.loads(output)
        except json.JSONDecodeError:
            # 2. 如果解析失败,尝试从文本中提取 JSON
            parsed = self._extract_json(output)
        
        # 3. 验证格式
        self._validate(parsed)
        
        return parsed
    
    def _extract_json(self, text: str) -> Dict[str, Any]:
        """从文本中提取 JSON"""
        # 匹配 ```json ... ```代码块
        match = re.search(r"```json\s*(\{.*?\})\s*```", text, re.DOTALL)
        if match:
            return json.loads(match.group(1))
        
        # 匹配 { ... }(简单匹配)
        match = re.search(r"\{.*\}", text, re.DOTALL)
        if match:
            return json.loads(match.group(0))
        
        raise ValueError("无法从输出中提取 JSON")
    
    def _validate(self, parsed: Dict[str, Any]):
        """验证格式是否符合 Schema"""
        # 检查必需字段
        for field in self.schema.get("required", []):
            if field not in parsed:
                raise ValueError(f"缺少必需字段:{field}")
        
        # 检查字段类型
        properties = self.schema.get("properties", {})
        for field, field_schema in properties.items():
            if field in parsed:
                expected_type = field_schema.get("type")
                if expected_type == "string" and not isinstance(parsed[field], str):
                    raise ValueError(f"字段 {field} 应该是字符串,实际类型:{type(parsed[field])}")
                elif expected_type == "object" and not isinstance(parsed[field], dict):
                    raise ValueError(f"字段 {field} 应该是对象,实际类型:{type(parsed[field])}")
        
        # 检查枚举值
        for field, field_schema in properties.items():
            if field in parsed and "enum" in field_schema:
                if parsed[field] not in field_schema["enum"]:
                    raise ValueError(f"字段 {field} 的值应该是 {field_schema['enum']} 之一,实际值:{parsed[field]}")


# 使用示例
schema = {
    "type": "object",
    "properties": {
        "tool": {
            "type": "string",
            "enum": ["get_weather", "get_stock_price", "none"]
        },
        "parameters": {"type": "object"}
    },
    "required": ["tool"]
}

formatter = OutputFormatter(schema)

# 测试 1:正确格式
output1 = '{"tool": "get_weather", "parameters": {"city": "北京"}}'
parsed1 = formatter.format(output1)
print(f"解析结果 1:{parsed1}")

# 测试 2:从文本中提取 JSON
output2 = "好的,让我查询一下:\n```json\n{"tool": "get_weather", "parameters": {"city": "北京"}}\n```"
parsed2 = formatter.format(output2)
print(f"解析结果 2:{parsed2}")

# 测试 3:错误格式(缺少必需字段)
output3 = '{"parameters": {"city": "北京"}}'
try:
    parsed3 = formatter.format(output3)
except ValueError as e:
    print(f"格式验证失败:{e}")

# 测试 4:错误格式(字段类型错误)
output4 = '{"tool": 123, "parameters": {"city": "北京"}}'
try:
    parsed4 = formatter.format(output4)
except ValueError as e:
    print(f"格式验证失败:{e}")

集成到 Agent

class AgentWithOutputFormatting:
    """带输出格式约束的 Agent"""
    def __init__(self, llm, output_schema: Dict):
        self.llm = llm
        self.formatter = OutputFormatter(output_schema)
    
    def run(self, user_query: str) -> Dict[str, Any]:
        """运行 Agent(带输出格式验证)"""
        # 1. 生成 Prompt
        prompt = self._build_prompt(user_query)
        
        # 2. 调用 LLM
        output = self.llm.call(prompt)
        
        # 3. 格式化输出(解析 + 验证)
        try:
            formatted = self.formatter.format(output)
            return formatted
        except ValueError as e:
            print(f"输出格式错误:{e}")
            # 返回错误标记
            return {"tool": "error", "error": str(e)}
    
    def _build_prompt(self, user_query: str) -> str:
        """构建 Prompt(包含输出格式要求)"""
        return f"""
你是一个助手,可以调用以下工具:
- get_weather(city): 获取指定城市的天气
- get_stock_price(symbol): 获取指定股票的股价

【输出格式要求】
你必须严格按照以下 JSON 格式输出:
```json
{{
  "tool": "工具名(必须是 get_weather、get_stock_price 或 none 之一)",
  "parameters": {{"参数名": "参数值"}}
}}

【示例】
用户:北京今天天气怎么样?
输出:

{{"tool": "get_weather", "parameters": {{"city": "北京"}}}}

现在,请处理用户的问题:
用户问题:{user_query}
“”"

使用示例

class MockLLM:
def call(self, prompt: str) -> str:
# 模拟 LLM 输出(可能格式不正确)
return “好的,让我查询一下北京天气…\njson\n{"tool": "get_weather", "parameters": {"city": "北京"}}\n

llm = MockLLM()
schema = {
“type”: “object”,
“properties”: {
“tool”: {“type”: “string”, “enum”: [“get_weather”, “get_stock_price”, “none”]},
“parameters”: {“type”: “object”}
},
“required”: [“tool”]
}

agent = AgentWithOutputFormatting(llm, schema)
result = agent.run(“北京今天天气怎么样?”)
print(f"Agent 输出:{result}")


**优点**:强制格式,减少幻觉  
**缺点**:LLM 可能不遵守格式(需要多次重试)

---

## 解决方案 4:工具选择验证(Tool Selection Validation)

### 原理

在调用工具之前,验证 Agent 选择的工具是否合理。

```python
from typing import Dict, Any, List
import difflib


class ToolSelectionValidator:
    """
    工具选择验证器
    """
    def __init__(self, tools: List[Dict[str, Any]]):
        self.tools = tools
        self.tool_names = [t["name"] for t in tools]
    
    def validate(self, user_query: str, selected_tool: str, parameters: Dict) -> Dict[str, Any]:
        """
        验证工具选择是否合理
        
        Returns:
            {"valid": True} 或 {"valid": False, "reason": "..."}
        """
        # 1. 检查工具是否存在
        if selected_tool not in self.tool_names:
            # 尝试模糊匹配
            suggestion = self._suggest_tool(selected_tool)
            return {
                "valid": False,
                "reason": f"工具 {selected_tool} 不存在",
                "suggestion": suggestion
            }
        
        # 2. 检查参数是否匹配
        tool_def = next(t for t in self.tools if t["name"] == selected_tool)
        required_params = tool_def.get("parameters", {}).get("required", [])
        
        for param in required_params:
            if param not in parameters:
                return {
                    "valid": False,
                    "reason": f"缺少必需参数:{param}"
                }
        
        # 3. 检查工具是否适合用户问题(简化:关键词匹配)
        relevance = self._check_relevance(user_query, selected_tool)
        if relevance < 0.5:
            return {
                "valid": False,
                "reason": f"工具 {selected_tool} 可能不适合用户问题(相关度:{relevance:.2f})",
                "suggestion": self._suggest_tool_for_query(user_query)
            }
        
        return {"valid": True}
    
    def _suggest_tool(self, wrong_name: str) -> str:
        """模糊匹配建议工具名"""
        matches = difflib.get_close_matches(wrong_name, self.tool_names, n=1)
        return matches[0] if matches else "(无建议)"
    
    def _check_relevance(self, user_query: str, tool_name: str) -> float:
        """检查工具和用户问题的相关度(简化:关键词匹配)"""
        keywords_map = {
            "get_weather": ["天气", "气温", "下雨", "晴天"],
            "get_stock_price": ["股价", "股票", "市值", "涨"]
        }
        
        keywords = keywords_map.get(tool_name, [])
        if not keywords:
            return 1.0
        
        # 计算关键词匹配率
        matched = sum(1 for kw in keywords if kw in user_query)
        return matched / len(keywords)
    
    def _suggest_tool_for_query(self, user_query: str) -> str:
        """根据用户问题建议工具"""
        for tool_name, keywords in {
            "get_weather": ["天气", "气温", "下雨", "晴天"],
            "get_stock_price": ["股价", "股票", "市值", "涨"]
        }.items():
            if any(kw in user_query for kw in keywords):
                return tool_name
        return "(无建议)"


# 使用示例
tools = [
    {
        "name": "get_weather",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string"}
            },
            "required": ["city"]
        }
    },
    {
        "name": "get_stock_price",
        "parameters": {
            "type": "object",
            "properties": {
                "symbol": {"type": "string"}
            },
            "required": ["symbol"]
        }
    }
]

validator = ToolSelectionValidator(tools)

# 测试 1:工具不存在
result1 = validator.validate("北京天气怎么样?", "get_wether", {"city": "北京"})
print(f"验证结果 1:{result1}")

# 测试 2:缺少必需参数
result2 = validator.validate("北京天气怎么样?", "get_weather", {})
print(f"验证结果 2:{result2}")

# 测试 3:工具不适合用户问题
result3 = validator.validate("腾讯股价是多少?", "get_weather", {"city": "深圳"})
print(f"验证结果 3:{result3}")

# 测试 4:验证通过
result4 = validator.validate("北京天气怎么样?", "get_weather", {"city": "北京"})
print(f"验证结果 4:{result4}")

集成到 Agent

class AgentWithToolValidation:
    """带工具选择验证的 Agent"""
    def __init__(self, llm, tools: List[Dict]):
        self.llm = llm
        self.tools = tools
        self.validator = ToolSelectionValidator(tools)
    
    def run(self, user_query: str) -> Dict[str, Any]:
        """运行 Agent(带工具选择验证)"""
        # 1. LLM 选择工具
        selected_tool, parameters = self._llm_select_tool(user_query)
        
        # 2. 验证工具选择
        validation = self.validator.validate(user_query, selected_tool, parameters)
        
        if not validation["valid"]:
            print(f"⚠️  工具选择验证失败:{validation['reason']}")
            print(f"建议工具:{validation.get('suggestion', '(无建议)')}")
            
            # 返回验证失败标记
            return {
                "tool": "validation_failed",
                "error": validation["reason"],
                "suggestion": validation.get("suggestion")
            }
        
        # 3. 调用工具
        result = self._call_tool(selected_tool, parameters)
        return result
    
    def _llm_select_tool(self, user_query: str) -> tuple[str, Dict]:
        """LLM 选择工具(简化:模拟)"""
        # 实际应该调用 LLM
        if "天气" in user_query:
            return "get_weather", {"city": "北京"}
        elif "股价" in user_query:
            return "get_stock_price", {"symbol": "0700.HK"}
        else:
            return "none", {}
    
    def _call_tool(self, tool_name: str, parameters: Dict) -> Any:
        """调用工具(简化:模拟)"""
        print(f"调用工具:{tool_name},参数:{parameters}")
        return {"result": "工具调用成功"}


# 使用示例
agent = AgentWithToolValidation(MockLLM(), tools)

# 测试
result = agent.run("北京天气怎么样?")
print(f"Agent 输出:{result}")

优点:提前发现工具选择错误,减少无效调用
缺点:增加延迟(需要验证步骤)


解决方案 5:幻觉检测(Hallucination Detection)

原理

在 Agent 输出后,检测是否包含幻觉(编造的信息)。

from typing import Dict, Any, List
import re


class HallucinationDetector:
    """
    幻觉检测器
    """
    def __init__(self, knowledge_base: Dict[str, Any] = None):
        """
        Args:
            knowledge_base: 知识库(用于验证事实性)
            例如:{"腾讯股价": 123.45, "北京天气": "晴天"}
        """
        self.knowledge_base = knowledge_base or {}
    
    def detect(self, user_query: str, agent_output: str, tool_results: List[Dict] = None) -> Dict[str, Any]:
        """
        检测幻觉
        
        Returns:
            {"hallucination": False} 或 {"hallucination": True, "reason": "..."}
        """
        # 1. 检查是否包含工具未返回的信息
        if tool_results:
            for result in tool_results:
                if not self._is_info_from_tool(agent_output, result):
                    return {
                        "hallucination": True,
                        "reason": "输出包含工具未返回的信息(可能幻觉)"
                    }
        
        # 2. 检查是否包含与知识库矛盾的信息
        if self.knowledge_base:
            contradiction = self._check_contradiction(agent_output)
            if contradiction:
                return {
                    "hallucination": True,
                    "reason": f"输出与知识库矛盾:{contradiction}"
                }
        
        # 3. 检查是否包含不确定的表述(可能幻觉)
        uncertain_patterns = ["可能", "大概", "也许", "应该", "估计"]
        for pattern in uncertain_patterns:
            if pattern in agent_output:
                return {
                    "hallucination": True,
                    "reason": f"输出包含不确定的表述:{pattern}"
                }
        
        return {"hallucination": False}
    
    def _is_info_from_tool(self, agent_output: str, tool_result: Dict) -> bool:
        """检查输出信息是否来自工具返回结果"""
        # 简化:检查输出是否包含工具返回的关键信息
        for value in tool_result.values():
            if str(value) in agent_output:
                return True
        return False
    
    def _check_contradiction(self, agent_output: str) -> str:
        """检查输出是否与知识库矛盾"""
        for key, value in self.knowledge_base.items():
            if key in agent_output and str(value) not in agent_output:
                return f"{key} 应该是 {value},但输出说是别的"
        return ""


# 使用示例
knowledge_base = {
    "腾讯股价": 123.45,
    "北京天气": "晴天"
}

detector = HallucinationDetector(knowledge_base)

# 测试 1:正常输出(无幻觉)
output1 = "腾讯的股价是 123.45 元"
tool_results1 = [{"price": 123.45}]
result1 = detector.detect("腾讯股价是多少?", output1, tool_results1)
print(f"检测结果 1:{result1}")

# 测试 2:幻觉(工具未返回的信息)
output2 = "腾讯的股价是 123.45 元,市盈率是 18.5"
tool_results2 = [{"price": 123.45}]  # 没有返回市盈率
result2 = detector.detect("腾讯股价是多少?", output2, tool_results2)
print(f"检测结果 2:{result2}")

# 测试 3:幻觉(与知识库矛盾)
output3 = "腾讯的股价是 999.99 元"
tool_results3 = [{"price": 123.45}]
result3 = detector.detect("腾讯股价是多少?", output3, tool_results3)
print(f"检测结果 3:{result3}")

# 测试 4:幻觉(不确定的表述)
output4 = "腾讯的股价大概是 123 元左右"
tool_results4 = [{"price": 123.45}]
result4 = detector.detect("腾讯股价是多少?", output4, tool_results4)
print(f"检测结果 4:{result4}")

更先进的幻觉检测:用 LLM 做 Judge

class LLMAsJudgeHallucinationDetector:
    """用 LLM 做 Judge 检测幻觉"""
    def __init__(self, judge_llm):
        self.judge_llm = judge_llm
    
    def detect(self, user_query: str, agent_output: str, tool_results: List[Dict] = None) -> Dict[str, Any]:
        """用 LLM 判断输出是否包含幻觉"""
        # 构建 Judge Prompt
        judge_prompt = f"""
你是一个事实核查员。请判断 Agent 的输出是否包含幻觉(编造的信息)。

用户问题:{user_query}

Agent 输出:
{agent_output}

工具返回结果:
{json.dumps(tool_results, ensure_ascii=False) if tool_results else "(无工具调用)"}

请判断 Agent 输出是否包含幻觉(即:输出包含工具未返回的信息,或与已知事实矛盾)。

输出格式(JSON):
```json
{{
  "hallucination": true/false,
  "reason": "判断理由"
}}

“”"

    # 调用 Judge LLM
    judge_output = self.judge_llm.call(judge_prompt)
    
    # 解析 Judge 输出
    try:
        result = json.loads(judge_output)
        return result
    except json.JSONDecodeError:
        # 解析失败,返回未知
        return {"hallucination": "unknown", "reason": "Judge LLM 输出格式错误"}


# 使用示例
class MockJudgeLLM:
    def call(self, prompt: str) -> str:
        # 模拟 Judge LLM 输出
        return '{"hallucination": false, "reason": "输出与工具返回结果一致"}'


judge_llm = MockJudgeLLM()
detector = LLMAsJudgeHallucinationDetector(judge_llm)

# 测试
output = "腾讯的股价是 123.45 元"
tool_results = [{"price": 123.45}]
result = detector.detect("腾讯股价是多少?", output, tool_results)
print(f"Judge 检测结果:{result}")

优点:准确检测幻觉,提高输出可信度
缺点:增加延迟和成本(需要调用 Judge LLM)


效果对比

方案 幻觉减少 工具选择准确率提升 实现难度 适用场景
优化工具描述 ⭐⭐ ⭐⭐⭐⭐ ⭐⭐ 所有场景(基础)
Few-shot 示例 ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐ 工具选择复杂
输出格式约束 ⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐ 输出格式固定
工具选择验证 N/A ⭐⭐⭐⭐⭐ ⭐⭐⭐ 工具数量多
幻觉检测 ⭐⭐⭐⭐⭐ N/A ⭐⭐⭐⭐ 高可信度要求

避坑指南

1. 工具描述不是越详细越好

错误做法

# 描述太长(占用大量 Token)
"description": "获取天气。这个函数可以查询全球任意城市的天气,包括温度、湿度、风速、风向、气压、能见度、云量、紫外线指数、空气质量指数、..."

正确做法

# 描述简洁但完整(控制在 200 字以内)
"description": "获取指定城市的当前天气(温度、天气状况)。支持城市:北京、上海、广州、深圳、杭州、成都。"

2. Few-shot 示例不是越多越好

错误做法

# 10 个示例(占用大量 Token)
examples = [示例1, 示例2, ..., 示例10]

正确做法

# 3-5 个精选示例(覆盖常见场景)
examples = [示例1, 示例2, 示例3]  # 3 个就够了

3. 幻觉检测不是万能的

错误做法

# 对所有输出都做幻觉检测(成本高)
if True:  # 无条件检测
    detector.detect(...)

正确做法

# 只对高风险输出做检测(成本高,谨慎使用)
if risk_level == "high":  # 例如:金融、医疗场景
    detector.detect(...)

延伸思考

1. 如何自动优化工具描述?

方案:用 LLM 生成工具描述,人工审核后使用。

def auto_generate_tool_description(tool_code: str) -> str:
    """用 LLM 自动生成工具描述"""
    prompt = f"""
请根据以下工具代码,生成清晰、详细的工具描述(包含:功能、参数、返回值、注意事项)。

工具代码:
{tool_code}

输出格式(JSON):
```json
{{
  "name": "工具名",
  "description": "工具描述",
  "parameters": {{"参数名": "参数描述"}},
  "returns": "返回值描述"
}}

“”"
return llm.call(prompt)


### 2. 如何让 Agent 自我纠正工具选择错误?

**方案**:让 Agent 在调用工具前,先"思考"一下。

```python
# Agent Prompt 模板(带思考步骤)
prompt = f"""
用户问题:{user_query}

请按以下步骤思考:
1. 用户想要什么信息?
2. 我有哪些工具可以用?
3. 哪个工具最适合?为什么?
4. 需要哪些参数?从哪里获取?

然后,输出工具调用 JSON。
"""

3. 如何衡量幻觉减少的效果?

方案:用标注数据集评测。

def evaluate_hallucination_reduction(agent, test_dataset: List[Dict]) -> Dict:
    """
    评测幻觉减少效果
    
    test_dataset: [
        {"user_query": "...", "expected_output": "...", "tool_results": [...]},
        ...
    ]
    """
    results = {"hallucination": 0, "total": len(test_dataset)}
    
    for item in test_dataset:
        agent_output = agent.run(item["user_query"])
        
        # 检测幻觉
        detection = detector.detect(item["user_query"], agent_output, item["tool_results"])
        
        if detection["hallucination"]:
            results["hallucination"] += 1
    
    results["hallucination_rate"] = results["hallucination"] / results["total"]
    return results

总结

幻觉和工具选择错误是 Agent 开发的核心痛点,需要组合多种方案

基础方案(必做) → 优化工具描述 + Few-shot 示例
进阶方案(推荐) → 输出格式约束 + 工具选择验证
高级方案(可选) → 幻觉检测(成本高,高风险场景用)

关键原则

  1. 工具描述要清晰、详细(但不要太长)
  2. Few-shot 示例要精选(3-5 个足够)
  3. 输出格式要约束(减少自由发挥)
  4. 工具选择要验证(提前发现问题)
  5. 高风险场景要检测幻觉(提高可信度)

下一篇预告:《Agent 开发实战:多 Agent 死循环的 5 个解决方案》

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐