⚠️ Alpha内测版本警告:此为早期内部构建版本,尚不完整且可能存在错误,欢迎大家提Issue反馈问题或建议。
Skip to content

扩展:Agent 框架深度

在线 Notebook

对应的交互式版本可在 Google Colab 打开,统一使用方式见 第0章说明

所属章节: 第6章:LLM应用
前置阅读: 6.4 Agent 框架


概览

6.4 节介绍了 Agent 的基本概念和 ReAct 模式。本节聚焦工程可靠性:如何让工具调用更稳定、多步推理更可控、复杂任务更可靠。


工具定义规范

标准格式

工具定义的质量直接决定 LLM 能否正确调用。关键是 description 要精确:

python
tools = [
    {
        "name": "search_web",
        "description": "搜索互联网获取最新信息。适用于:需要实时数据、近期事件、具体数字。不适用于:通用知识、历史事实(模型已知)。",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "搜索关键词,建议使用英文以获得更好结果"
                },
                "num_results": {
                    "type": "integer",
                    "description": "返回结果数量,默认 5,最大 10",
                    "default": 5
                }
            },
            "required": ["query"]
        }
    }
]

工具描述的三要素:

  1. 做什么:工具的功能
  2. 什么时候用:适用场景
  3. 什么时候不用:避免误调用

工具调用可靠性

LLM 可能调用错误的工具或传入无效参数。防御策略:

LLM 生成工具调用


[参数验证](JSON Schema 校验)

    ├─ 校验失败 → 返回错误信息给 LLM,要求重试


[工具执行]

    ├─ 执行失败 → 返回错误信息给 LLM,最多重试 N 次


工具结果 → 返回给 LLM

参数类型错误(如 LLM 把数字传成字符串)是最常见的失败原因,可以在校验层自动修正:

python
def validate_and_fix_params(params: dict, schema: dict) -> dict:
    """尝试自动修正类型错误,无法修正时抛出异常让 LLM 重试。"""
    fixed = {}
    for key, prop in schema.get("properties", {}).items():
        val = params.get(key)
        if val is None:
            if key in schema.get("required", []):
                raise ValueError(f"Missing required parameter: {key}")
            continue
        expected_type = prop.get("type")
        if expected_type == "integer" and isinstance(val, str):
            fixed[key] = int(val)   # "5" → 5
        elif expected_type == "number" and isinstance(val, str):
            fixed[key] = float(val)
        else:
            fixed[key] = val
    return fixed

工具调用重试建议使用指数退避(exponential backoff),避免在工具服务故障时频繁重试:

python
import time

def call_tool_with_retry(tool_fn, params, max_retries=3):
    for attempt in range(max_retries):
        try:
            return tool_fn(**params)
        except Exception as e:
            if attempt == max_retries - 1:
                raise
            time.sleep(2 ** attempt)   # 1s, 2s, 4s

ReAct 模式详解

ReAct(Reasoning + Acting)是目前最主流的 Agent 范式:

用户:2024年诺贝尔物理学奖得主是谁?他们的主要贡献是什么?

Thought: 我需要查找2024年诺贝尔物理学奖的信息
Action: search_web(query="2024 Nobel Prize Physics winner")
Observation: 搜索结果显示获奖者是 John Hopfield 和 Geoffrey Hinton...

Thought: 我已经知道获奖者,现在需要了解他们的具体贡献
Action: search_web(query="Hopfield Hinton Nobel Prize contributions neural networks")
Observation: 他们因在人工神经网络领域的基础性发现而获奖...

Thought: 我现在有足够的信息来回答问题了
Final Answer: 2024年诺贝尔物理学奖授予 John Hopfield 和 Geoffrey Hinton,
表彰他们在人工神经网络领域的基础性发现...

关键设计: Thought 步骤让 LLM 显式推理"为什么"调用工具,而不是盲目调用,显著提升可靠性。

错误恢复案例: 当 Thought 推理出错时,将错误反馈给 LLM 让其重新规划:

Thought: 我需要查询用户 ID 为 abc123 的订单
Action: query_orders(user_id="abc123")
Observation: Error: user_id must be integer, got string "abc123"

Thought: 参数类型错误,user_id 应该是整数。但我没有整数 ID,
         需要先通过用户名查询 ID
Action: get_user_id(username="abc123")
Observation: {"user_id": 42}

Thought: 获取到整数 ID,现在可以查询订单了
Action: query_orders(user_id=42)

多步推理控制

循环终止条件

Agent 循环必须有明确的终止条件,否则可能无限循环:

python
MAX_STEPS = 10   # 最大步数限制

for step in range(MAX_STEPS):
    response = llm.call(messages)
    
    if response.is_final_answer:
        return response.content
    
    tool_result = execute_tool(response.tool_call)
    messages.append(tool_result)

# 超过最大步数,强制返回
return "任务超过最大步数限制,当前进度:..."

错误恢复

工具调用失败时,让 LLM 自主决策如何恢复:

工具调用失败


将错误信息返回给 LLM:
"工具 search_web 调用失败:网络超时。
请选择:1) 重试 2) 使用其他工具 3) 基于已有信息回答"


LLM 决策下一步

并行工具调用

当多个工具调用相互独立时,并行执行可大幅降低延迟:

python
# 串行:总时间 = t1 + t2 + t3
result1 = tool_a(...)
result2 = tool_b(...)
result3 = tool_c(...)

# 并行:总时间 = max(t1, t2, t3)
import asyncio
results = await asyncio.gather(
    tool_a(...),
    tool_b(...),
    tool_c(...)
)

现代 LLM API(GPT-4、Claude)支持在单次响应中返回多个并行工具调用。


记忆系统

Agent 的记忆分为四类:

类型存储位置生命周期用途
工作记忆上下文窗口单次对话当前任务的中间结果
对话历史数据库跨对话记住用户偏好和历史
知识库向量数据库持久领域知识(RAG)
程序记忆代码/工具持久固定的操作流程

上下文窗口管理: 长对话需要压缩历史,常见策略:

  • 保留最近 N 轮
  • 用 LLM 总结早期对话
  • 只保留关键事实(实体、决策)

对话历史持久化示例:

python
import sqlite3, json

def save_turn(session_id: str, role: str, content: str):
    conn = sqlite3.connect("agent_history.db")
    conn.execute(
        "INSERT INTO turns (session_id, role, content, ts) VALUES (?,?,?,datetime('now'))",
        (session_id, role, content)
    )
    conn.commit()

def load_recent_turns(session_id: str, n: int = 20) -> list[dict]:
    conn = sqlite3.connect("agent_history.db")
    rows = conn.execute(
        "SELECT role, content FROM turns WHERE session_id=? ORDER BY ts DESC LIMIT ?",
        (session_id, n)
    ).fetchall()
    return [{"role": r, "content": c} for r, c in reversed(rows)]

RAG 与 Agent 集成: 将向量检索封装为一个工具,Agent 按需调用:

python
tools = [
    {
        "name": "search_knowledge_base",
        "description": "在内部知识库中检索相关文档。适用于:产品文档、政策、FAQ。",
        "parameters": {"query": {"type": "string"}, "top_k": {"type": "integer", "default": 3}}
    }
]
# Agent 调用时触发向量检索,结果作为 Observation 返回

主流 Agent 框架

框架定位特点局限
LangChain Agents通用工具生态丰富抽象层多,学习曲线陡峭,调试困难
LlamaIndex AgentsRAG + Agent与知识库集成好非 RAG 场景功能较弱
AutoGen多 Agent多个 Agent 协作对话对话可能无限循环,必须设计终止条件
CrewAI多 Agent角色分工,适合复杂任务配置繁琐,调试多 Agent 交互困难
Semantic Kernel企业级微软出品,.NET/Python国内用户较少,英文资料为主

选择建议:

场景推荐不推荐理由
快速原型验证原生 function callingLangChain减少抽象层,调试简单
复杂工具链LangChain原生 API内置工具、解析器丰富
多 Agent 协作AutoGenLangChainAutoGen 原生支持对话管理
受限网络环境原生 API + 自建LangChain避免外网依赖

成本与延迟控制

Agent 的主要成本来源是多轮 LLM 调用:

单次 Agent 任务成本 ≈ 平均步数 × 每步 token 数 × token 单价

示例(GPT-4o,平均 5 步,每步 2000 tokens):
  5 × 2000 × $0.005/1K = $0.05/次
  日均 1000 次 → $50/天

成本优化策略:

  • 用小模型处理简单步骤(工具选择),大模型处理复杂推理
  • 缓存工具调用结果(相同参数的重复调用)
  • 设置合理的最大步数限制

推荐论文

  • Yao et al. (2022) — "ReAct: Synergizing Reasoning and Acting in Language Models"(ReAct 框架)
  • Schick et al. (2023) — "Toolformer: Language Models Can Teach Themselves to Use Tools"
  • Wang et al. (2023) — "Voyager: An Open-Ended Embodied Agent with Large Language Models"
  • Wu et al. (2023) — "AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation"

常见坑与解决方案

常见问题解决方案
LLM 无限循环调用同一个工具在 Prompt 中限制:"同一工具连续调用不超过 3 次";代码层面记录调用历史并强制终止
工具调用参数总是不对优化 description,加上正例和反例;对高频错误参数做自动类型修正(见上方代码)
多步推理中"遗忘"早期信息每步将关键信息提取到"工作记忆"摘要,附加到下一步的 Prompt 中
工具返回结果太长撑爆上下文对工具结果做截断(保留前 N 字符)或摘要(用小模型压缩)
AutoGen 多 Agent 对话无限循环设计明确的终止条件(如 TERMINATE 关键词);设置最大对话轮数
Agent 成本失控监控每次任务的步数和 token 消耗;设置单任务 token 上限并告警

Agent 质量评估

如何衡量 Agent 做得好不好:

指标说明测量方法
任务成功率端到端完成任务的比例人工标注测试集,判断最终答案是否正确
平均步数完成任务所需的工具调用次数自动统计,步数越少效率越高
工具调用准确率调用正确工具、参数正确的比例对比预期工具调用序列
错误恢复率遇到工具失败后成功恢复的比例注入故障测试
人工评估回答质量、推理过程合理性领域专家评分(1-5分),至少抽样 50 条

最小可行评估方案: 构建 20-50 条有标准答案的测试用例,每次迭代后跑一遍,监控任务成功率的变化趋势。


返回: 第6章:LLM应用

本教程采用 CC BY-NC-SA 4.0 许可协议