自主AI Agent开发完全教程(记忆/规划/工具使用)

教程简介

本教程系统讲解自主AI Agent的核心架构与开发技术,涵盖Agent记忆系统(短期/长期/工作记忆)、规划能力(ReAct/Plan-and-Execute/Reflexion)、Function Calling与工具使用、环境感知与状态管理、错误恢复与自纠正、Agent评估方法、主流框架对比(LangGraph/AutoGen/CrewAI/OpenAI Agents SDK)、安全机制,并通过构建自主研究Agent的完整实战案例帮助开发者掌握Agent开发。

自主AI Agent开发完全教程(记忆/规划/工具使用)

一、概述

人工智能正在从"被动响应"走向"主动行动"。传统的AI模型接收输入、产生输出,是一个无状态的函数映射。而AI Agent(智能体) 则是一种能够自主感知环境、制定计划、使用工具、执行行动并从反馈中学习的智能系统。

2024年以来,AI Agent已成为人工智能领域最活跃的研究和工程方向之一。从自动化编程助手到自主研究系统,从智能客服到数据分析Agent,Agent技术正在重塑人机交互的方式。

本教程将系统讲解AI Agent的核心架构、关键技术与工程实践,帮助开发者从零构建具有记忆、规划和工具使用能力的自主Agent系统。

目标读者:有Python基础和LLM使用经验的开发者。

你将学到

  • AI Agent的核心架构与设计模式
  • 短期记忆、长期记忆和工作记忆的实现
  • 多种规划策略(ReAct、Plan-and-Execute、Reflexion)
  • Function Calling与工具集成
  • 环境感知与状态管理
  • 错误恢复与自纠正机制
  • Agent评估方法
  • 主流Agent框架的对比与使用
  • Agent安全与人类监督机制
  • 从零构建一个自主研究Agent

二、AI Agent概述与架构

2.1 什么是AI Agent

AI Agent是一个具有以下核心能力的系统:

  1. 感知(Perception):从环境获取信息(用户输入、API返回、传感器数据等)
  2. 推理(Reasoning):基于感知信息和内部知识进行分析和决策
  3. 行动(Action):执行具体操作(调用工具、生成内容、发送请求等)
  4. 记忆(Memory):保持上下文、积累经验、学习改进

用一个简单的公式表示:

Agent = LLM + 记忆 + 规划 + 工具使用 + 行动循环

2.2 Agent核心架构

一个典型的Agent系统架构包含以下组件:

┌─────────────────────────────────────────────┐
│                   用户输入                    │
└─────────────────┬───────────────────────────┘
                  │
┌─────────────────▼───────────────────────────┐
│              感知层 (Perception)              │
│  解析输入、提取意图、环境状态获取              │
└─────────────────┬───────────────────────────┘
                  │
┌─────────────────▼───────────────────────────┐
│              推理层 (Reasoning)               │
│  基于LLM的思考、规划、决策                    │
│  ┌─────────┐  ┌──────────┐  ┌──────────┐   │
│  │ 短期记忆 │  │ 长期记忆  │  │ 工作记忆  │   │
│  └─────────┘  └──────────┘  └──────────┘   │
└─────────────────┬───────────────────────────┘
                  │
┌─────────────────▼───────────────────────────┐
│              行动层 (Action)                  │
│  工具调用、API请求、代码执行                   │
└─────────────────┬───────────────────────────┘
                  │
┌─────────────────▼───────────────────────────┐
│              反馈层 (Feedback)                │
│  结果评估、错误处理、经验积累                  │
└─────────────────────────────────────────────┘

2.3 Agent循环(Agent Loop)

Agent的核心运行模式是一个感知-思考-行动循环:

class SimpleAgent:
    """最简单的Agent循环实现"""
    
    def __init__(self, llm, tools, memory):
        self.llm = llm
        self.tools = tools
        self.memory = memory
    
    def run(self, task: str, max_iterations: int = 10) -> str:
        """执行任务的主循环"""
        self.memory.add("user", task)
        
        for i in range(max_iterations):
            # 感知:获取当前上下文
            context = self.memory.get_context()
            
            # 思考:LLM决定下一步行动
            thought = self.think(context)
            
            # 检查是否完成
            if thought.get("type") == "final_answer":
                answer = thought["content"]
                self.memory.add("assistant", answer)
                return answer
            
            # 行动:执行工具调用
            if thought.get("type") == "action":
                result = self.execute_action(thought["action"], thought["input"])
                self.memory.add("system", f"工具 {thought['action']} 返回: {result}")
        
        return "达到最大迭代次数,任务未能完成。"
    
    def think(self, context: str) -> dict:
        """LLM推理"""
        prompt = f"""基于当前上下文,决定下一步行动。
        
上下文:
{context}

你可以:
1. 调用工具: {{"type": "action", "action": "工具名", "input": "参数"}}
2. 给出最终答案: {{"type": "final_answer", "content": "答案内容"}}

请以JSON格式回复:"""
        
        response = self.llm.generate(prompt)
        return parse_json(response)
    
    def execute_action(self, action: str, input_data: str) -> str:
        """执行工具调用"""
        if action in self.tools:
            return self.tools[action].execute(input_data)
        return f"错误:未知工具 {action}"

三、Agent记忆系统

3.1 记忆的三种类型

人类记忆系统为Agent设计提供了重要启发:

短期记忆(Short-term Memory):当前对话的上下文,通常通过LLM的上下文窗口实现。容量有限,会话结束即消失。

长期记忆(Long-term Memory):持久化存储的知识和经验,通常使用向量数据库。跨会话保留,支持检索。

工作记忆(Working Memory):当前任务的中间状态和临时信息,类似人类的"心智工作台"。

3.2 短期记忆实现

from typing import List, Dict
from collections import deque

class ShortTermMemory:
    """短期记忆:基于滑动窗口的对话历史"""
    
    def __init__(self, max_tokens: int = 4000):
        self.messages: List[Dict] = []
        self.max_tokens = max_tokens
    
    def add(self, role: str, content: str):
        self.messages.append({"role": role, "content": content})
        self._trim()
    
    def get_context(self) -> str:
        """获取当前上下文"""
        return "\n".join(
            f"[{m['role']}]: {m['content']}" for m in self.messages
        )
    
    def get_messages(self) -> List[Dict]:
        return self.messages.copy()
    
    def _trim(self):
        """保持在token限制内"""
        total = sum(len(m["content"]) for m in self.messages)
        while total > self.max_tokens and len(self.messages) > 1:
            removed = self.messages.pop(0)
            total -= len(removed["content"])
    
    def clear(self):
        self.messages.clear()

3.3 长期记忆实现

import json
import numpy as np
from datetime import datetime
from typing import List, Dict, Optional

class LongTermMemory:
    """长期记忆:基于向量数据库的持久化记忆"""
    
    def __init__(self, embedding_model, vector_store):
        self.embedding_model = embedding_model
        self.vector_store = vector_store
    
    def store(self, content: str, memory_type: str = "general",
              metadata: Dict = None):
        """存储一条记忆"""
        embedding = self.embedding_model.encode(content)
        
        memory_entry = {
            "id": f"mem_{datetime.now().timestamp()}",
            "content": content,
            "embedding": embedding,
            "type": memory_type,
            "timestamp": datetime.now().isoformat(),
            "metadata": metadata or {}
        }
        
        self.vector_store.add(memory_entry)
    
    def recall(self, query: str, top_k: int = 5, 
               memory_type: Optional[str] = None) -> List[Dict]:
        """检索相关记忆"""
        query_embedding = self.embedding_model.encode(query)
        
        filters = {}
        if memory_type:
            filters["type"] = memory_type
        
        results = self.vector_store.search(
            query_embedding, top_k=top_k, filters=filters
        )
        
        return results
    
    def forget(self, memory_id: str):
        """删除特定记忆"""
        self.vector_store.delete(memory_id)
    
    def consolidate(self):
        """记忆整合:合并相似记忆,去除冗余"""
        all_memories = self.vector_store.get_all()
        
        # 聚类相似记忆
        clusters = self._cluster_memories(all_memories)
        
        # 对每个聚类进行摘要
        for cluster in clusters:
            if len(cluster) > 1:
                summary = self._summarize_cluster(cluster)
                # 删除原始记忆,存储摘要
                for mem in cluster:
                    self.vector_store.delete(mem["id"])
                self.store(summary, memory_type="consolidated")

3.4 工作记忆实现

class WorkingMemory:
    """工作记忆:当前任务的临时状态"""
    
    def __init__(self):
        self.scratchpad: Dict = {}  # 临时变量
        self.plan: List[str] = []   # 当前计划
        self.step_results: Dict = {} # 每步结果
        self.constraints: List[str] = []  # 约束条件
        self.goals: List[str] = []  # 目标
    
    def set_goal(self, goal: str):
        self.goals.append(goal)
    
    def set_plan(self, steps: List[str]):
        self.plan = steps
        self.step_results = {i: None for i in range(len(steps))}
    
    def update_step(self, step_index: int, result: str):
        self.step_results[step_index] = result
    
    def get_progress(self) -> Dict:
        completed = sum(1 for v in self.step_results.values() if v is not None)
        return {
            "total_steps": len(self.plan),
            "completed": completed,
            "current_step": self._get_current_step(),
            "progress_pct": completed / len(self.plan) * 100 if self.plan else 0
        }
    
    def _get_current_step(self) -> Optional[str]:
        for i, result in self.step_results.items():
            if result is None:
                return self.plan[i]
        return None
    
    def set_scratchpad(self, key: str, value):
        self.scratchpad[key] = value
    
    def get_scratchpad(self, key: str, default=None):
        return self.scratchpad.get(key, default)
    
    def clear(self):
        self.scratchpad.clear()
        self.plan.clear()
        self.step_results.clear()
        self.constraints.clear()
        self.goals.clear()

3.5 统一记忆管理

class AgentMemory:
    """统一的Agent记忆管理"""
    
    def __init__(self, embedding_model, vector_store, max_context_tokens=4000):
        self.short_term = ShortTermMemory(max_tokens=max_context_tokens)
        self.long_term = LongTermMemory(embedding_model, vector_store)
        self.working = WorkingMemory()
    
    def add_conversation(self, role: str, content: str):
        """添加对话到短期记忆"""
        self.short_term.add(role, content)
    
    def remember(self, content: str, memory_type: str = "general"):
        """存储到长期记忆"""
        self.long_term.store(content, memory_type)
    
    def recall(self, query: str, top_k: int = 5) -> List[Dict]:
        """从长期记忆中检索"""
        return self.long_term.recall(query, top_k)
    
    def get_context(self, include_long_term: bool = True, 
                    query: str = None) -> str:
        """获取完整的记忆上下文"""
        context_parts = []
        
        # 短期记忆
        context_parts.append("=== 当前对话 ===")
        context_parts.append(self.short_term.get_context())
        
        # 相关的长期记忆
        if include_long_term and query:
            memories = self.recall(query, top_k=3)
            if memories:
                context_parts.append("\n=== 相关记忆 ===")
                for mem in memories:
                    context_parts.append(f"- {mem['content']}")
        
        # 工作记忆状态
        if self.working.plan:
            progress = self.working.get_progress()
            context_parts.append(f"\n=== 任务进度 ===")
            context_parts.append(f"当前步骤: {progress['current_step']}")
            context_parts.append(f"完成度: {progress['progress_pct']:.0f}%")
        
        return "\n".join(context_parts)

四、规划能力

4.1 ReAct(Reasoning + Acting)

ReAct是最经典的Agent规划模式,将推理和行动交替进行:

思考(Thought) → 行动(Action) → 观察(Observation) → 思考 → ...
class ReActAgent:
    """基于ReAct模式的Agent"""
    
    def __init__(self, llm, tools, memory):
        self.llm = llm
        self.tools = tools
        self.memory = memory
    
    def run(self, task: str, max_steps: int = 10) -> str:
        self.memory.add_conversation("user", task)
        
        for step in range(max_steps):
            # 构建提示
            prompt = self._build_react_prompt(task)
            
            # 获取LLM响应
            response = self.llm.generate(prompt)
            
            # 解析响应
            parsed = self._parse_react_response(response)
            
            # 记录思考过程
            self.memory.add_conversation("assistant", response)
            
            # 如果是最终答案
            if parsed["type"] == "finish":
                return parsed["answer"]
            
            # 执行行动
            if parsed["type"] == "action":
                observation = self._execute_tool(
                    parsed["tool"], 
                    parsed["input"]
                )
                self.memory.add_conversation("system", 
                    f"Observation: {observation}")
        
        return "达到最大步骤数限制"
    
    def _build_react_prompt(self, task: str) -> str:
        tools_desc = "\n".join(
            f"- {name}: {tool.description}" 
            for name, tool in self.tools.items()
        )
        
        return f"""你是一个智能助手。请用以下格式回答问题:

Question: 用户的问题
Thought: 分析当前情况,决定下一步
Action: 工具名称
Action Input: 工具输入
Observation: 工具返回结果
... (可以重复多次)
Thought: 我现在知道答案了
Final Answer: 最终答案

可用工具:
{tools_desc}

对话历史:
{self.memory.short_term.get_context()}

请继续:"""
    
    def _parse_react_response(self, response: str) -> dict:
        """解析ReAct格式的响应"""
        lines = response.strip().split("\n")
        
        for line in lines:
            if line.startswith("Final Answer:"):
                return {
                    "type": "finish",
                    "answer": line[len("Final Answer:"):].strip()
                }
            if line.startswith("Action:"):
                tool_name = line[len("Action:"):].strip()
                # 查找对应的Action Input
                for sub_line in lines:
                    if sub_line.startswith("Action Input:"):
                        tool_input = sub_line[len("Action Input:"):].strip()
                        return {
                            "type": "action",
                            "tool": tool_name,
                            "input": tool_input
                        }
        
        return {"type": "thought", "content": response}
    
    def _execute_tool(self, tool_name: str, tool_input: str) -> str:
        if tool_name in self.tools:
            try:
                return self.tools[tool_name].execute(tool_input)
            except Exception as e:
                return f"工具执行错误: {str(e)}"
        return f"未知工具: {tool_name}"

4.2 Plan-and-Execute

Plan-and-Execute模式将规划和执行分离:先制定完整计划,然后逐步执行。

class PlanAndExecuteAgent:
    """Plan-and-Execute模式Agent"""
    
    def __init__(self, llm, tools, memory):
        self.llm = llm
        self.tools = tools
        self.memory = memory
        self.planner = Planner(llm)
        self.executor = Executor(llm, tools)
    
    def run(self, task: str) -> str:
        # 阶段1: 制定计划
        plan = self.planner.create_plan(task)
        self.memory.working.set_plan(plan)
        
        print(f"制定计划: {plan}")
        
        # 阶段2: 逐步执行
        for i, step in enumerate(plan):
            print(f"\n执行步骤 {i+1}: {step}")
            
            # 获取之前步骤的结果
            context = self._get_execution_context()
            
            # 执行当前步骤
            result = self.executor.execute_step(step, context)
            
            # 记录结果
            self.memory.working.update_step(i, result)
            print(f"结果: {result}")
            
            # 检查是否需要重新规划
            if self._should_replan(task, i):
                remaining = plan[i+1:]
                new_plan = self.planner.replan(task, remaining, 
                                                self.memory.working.step_results)
                plan = plan[:i+1] + new_plan
                self.memory.working.set_plan(plan)
                print(f"重新规划: {new_plan}")
        
        # 阶段3: 综合结果
        final_answer = self._synthesize_results(task)
        return final_answer
    
    def _get_execution_context(self) -> str:
        """获取执行上下文"""
        context_parts = []
        for i, result in self.memory.working.step_results.items():
            if result is not None:
                context_parts.append(
                    f"步骤{i+1} ({self.memory.working.plan[i]}): {result}"
                )
        return "\n".join(context_parts)
    
    def _should_replan(self, task: str, current_step: int) -> bool:
        """判断是否需要重新规划"""
        # 简单策略:如果当前步骤失败,需要重新规划
        current_result = self.memory.working.step_results[current_step]
        if current_result and "错误" in current_result:
            return True
        return False
    
    def _synthesize_results(self, task: str) -> str:
        """综合所有步骤结果生成最终答案"""
        context = self._get_execution_context()
        prompt = f"""基于以下执行结果,回答原始问题。

原始问题: {task}

执行结果:
{context}

请给出完整的最终答案:"""
        
        return self.llm.generate(prompt)


class Planner:
    """计划生成器"""
    
    def __init__(self, llm):
        self.llm = llm
    
    def create_plan(self, task: str) -> List[str]:
        prompt = f"""请为以下任务制定一个详细的执行计划,将任务分解为具体的步骤。

任务: {task}

要求:
1. 每个步骤应该是具体、可执行的
2. 步骤之间有清晰的逻辑顺序
3. 步骤数量控制在3-7个

请以如下格式输出:
步骤1: xxx
步骤2: xxx
..."""
        
        response = self.llm.generate(prompt)
        return self._parse_plan(response)
    
    def replan(self, task: str, remaining_steps: List[str], 
               completed_results: Dict) -> List[str]:
        prompt = f"""原始任务: {task}
        
已完成的结果:
{json.dumps(completed_results, ensure_ascii=False, indent=2)}

剩余计划: {remaining_steps}

请根据已完成的结果,重新制定剩余步骤的计划。"""
        
        response = self.llm.generate(prompt)
        return self._parse_plan(response)
    
    def _parse_plan(self, response: str) -> List[str]:
        steps = []
        for line in response.strip().split("\n"):
            line = line.strip()
            if line.startswith("步骤"):
                # 提取步骤内容
                parts = line.split(":", 1)
                if len(parts) > 1:
                    steps.append(parts[1].strip())
        return steps


class Executor:
    """步骤执行器"""
    
    def __init__(self, llm, tools):
        self.llm = llm
        self.tools = tools
    
    def execute_step(self, step: str, context: str) -> str:
        prompt = f"""请执行以下步骤:

步骤: {step}

之前的执行结果:
{context}

你可以使用以下工具:
{self._format_tools()}

如果需要使用工具,请以如下格式输出:
Action: 工具名称
Action Input: 工具输入

如果不需要工具,请直接输出结果。

输出:"""
        
        response = self.llm.generate(prompt)
        
        # 检查是否需要调用工具
        if "Action:" in response:
            return self._handle_tool_call(response)
        
        return response
    
    def _format_tools(self) -> str:
        return "\n".join(
            f"- {name}: {tool.description}" 
            for name, tool in self.tools.items()
        )
    
    def _handle_tool_call(self, response: str) -> str:
        """处理工具调用"""
        lines = response.split("\n")
        tool_name = None
        tool_input = None
        
        for line in lines:
            if line.startswith("Action:"):
                tool_name = line[len("Action:"):].strip()
            elif line.startswith("Action Input:"):
                tool_input = line[len("Action Input:"):].strip()
        
        if tool_name and tool_name in self.tools:
            return self.tools[tool_name].execute(tool_input or "")
        
        return f"工具调用失败: {tool_name}"

4.3 Reflexion(反思式规划)

Reflexion模式让Agent能够从失败中学习,通过反思改进策略:

class ReflexionAgent:
    """基于Reflexion的自我反思Agent"""
    
    def __init__(self, llm, tools, memory, max_retries=3):
        self.llm = llm
        self.tools = tools
        self.memory = memory
        self.max_retries = max_retries
        self.reflections: List[str] = []
    
    def run(self, task: str) -> str:
        for attempt in range(self.max_retries):
            # 尝试执行任务
            result, success = self._attempt(task)
            
            if success:
                return result
            
            # 反思失败原因
            reflection = self._reflect(task, result)
            self.reflections.append(reflection)
            self.memory.remember(reflection, memory_type="reflection")
            
            print(f"尝试 {attempt + 1} 失败,反思: {reflection}")
        
        return f"经过 {self.max_retries} 次尝试后未能完成任务"
    
    def _attempt(self, task: str) -> tuple:
        """尝试执行任务"""
        # 构建包含反思的提示
        reflections_text = ""
        if self.reflections:
            reflections_text = "\n之前的反思(请避免重复这些错误):\n"
            for i, r in enumerate(self.reflections, 1):
                reflections_text += f"{i}. {r}\n"
        
        prompt = f"""任务: {task}
{reflections_text}

请完成任务。如果遇到问题,请明确说明。"""
        
        # 使用ReAct执行
        agent = ReActAgent(self.llm, self.tools, ShortTermMemory())
        result = agent.run(prompt)
        
        # 判断是否成功
        success = self._evaluate_success(task, result)
        
        return result, success
    
    def _reflect(self, task: str, failed_result: str) -> str:
        """反思失败原因"""
        prompt = f"""你尝试完成以下任务但失败了。

任务: {task}
你的回答: {failed_result}

请反思:
1. 为什么这个回答不正确或不完整?
2. 你犯了什么错误?
3. 下次应该如何改进?

反思:"""
        
        return self.llm.generate(prompt)
    
    def _evaluate_success(self, task: str, result: str) -> bool:
        """评估任务是否成功完成"""
        prompt = f"""请评估以下回答是否正确完成了任务。

任务: {task}
回答: {result}

回答是否正确且完整?请只回答 "是" 或 "否"。"""
        
        evaluation = self.llm.generate(prompt).strip()
        return "是" in evaluation

五、工具使用(Function Calling / Tool Use)

5.1 工具定义与注册

from typing import Callable, Dict, Any
from dataclasses import dataclass
import inspect

@dataclass
class Tool:
    """工具定义"""
    name: str
    description: str
    function: Callable
    parameters: Dict[str, Any]
    
    def execute(self, **kwargs) -> str:
        try:
            result = self.function(**kwargs)
            return str(result)
        except Exception as e:
            return f"执行错误: {str(e)}"


class ToolRegistry:
    """工具注册中心"""
    
    def __init__(self):
        self.tools: Dict[str, Tool] = {}
    
    def register(self, name: str, description: str, 
                 parameters: Dict = None):
        """装饰器方式注册工具"""
        def decorator(func: Callable):
            self.tools[name] = Tool(
                name=name,
                description=description,
                function=func,
                parameters=parameters or {}
            )
            return func
        return decorator
    
    def get_tool(self, name: str) -> Tool:
        return self.tools.get(name)
    
    def list_tools(self) -> str:
        """列出所有工具"""
        descriptions = []
        for name, tool in self.tools.items():
            params = ", ".join(tool.parameters.keys())
            descriptions.append(f"- {name}({params}): {tool.description}")
        return "\n".join(descriptions)
    
    def call(self, name: str, **kwargs) -> str:
        """调用工具"""
        tool = self.tools.get(name)
        if not tool:
            return f"未知工具: {name}"
        return tool.execute(**kwargs)


# 使用示例
registry = ToolRegistry()

@registry.register(
    name="search_web",
    description="搜索互联网获取信息",
    parameters={"query": {"type": "string", "description": "搜索关键词"}}
)
def search_web(query: str) -> str:
    # 实际实现会调用搜索API
    return f"搜索 '{query}' 的结果: ..."


@registry.register(
    name="calculate",
    description="执行数学计算",
    parameters={"expression": {"type": "string", "description": "数学表达式"}}
)
def calculate(expression: str) -> str:
    try:
        result = eval(expression)
        return str(result)
    except Exception as e:
        return f"计算错误: {str(e)}"


@registry.register(
    name="read_file",
    description="读取文件内容",
    parameters={"file_path": {"type": "string", "description": "文件路径"}}
)
def read_file(file_path: str) -> str:
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            return f.read()
    except Exception as e:
        return f"读取错误: {str(e)}"

5.2 Function Calling实现

class FunctionCallingAgent:
    """基于Function Calling的Agent"""
    
    def __init__(self, llm_client, tool_registry: ToolRegistry):
        self.client = llm_client
        self.tools = tool_registry
    
    def run(self, task: str, max_iterations: int = 5) -> str:
        messages = [{"role": "user", "content": task}]
        
        for _ in range(max_iterations):
            # 调用LLM(带工具定义)
            response = self.client.chat.completions.create(
                model="gpt-4o-mini",
                messages=messages,
                tools=self._get_tool_definitions(),
                tool_choice="auto"
            )
            
            message = response.choices[0].message
            messages.append(message)
            
            # 如果没有工具调用,返回结果
            if not message.tool_calls:
                return message.content
            
            # 处理工具调用
            for tool_call in message.tool_calls:
                function_name = tool_call.function.name
                function_args = json.loads(tool_call.function.arguments)
                
                # 执行工具
                result = self.tools.call(function_name, **function_args)
                
                # 添加工具结果到消息
                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "content": result
                })
        
        return "达到最大迭代次数"
    
    def _get_tool_definitions(self) -> list:
        """转换为OpenAI工具格式"""
        tools = []
        for name, tool in self.tools.tools.items():
            tools.append({
                "type": "function",
                "function": {
                    "name": name,
                    "description": tool.description,
                    "parameters": {
                        "type": "object",
                        "properties": {
                            param_name: {
                                "type": param_info.get("type", "string"),
                                "description": param_info.get("description", "")
                            }
                            for param_name, param_info in tool.parameters.items()
                        },
                        "required": list(tool.parameters.keys())
                    }
                }
            })
        return tools

5.3 工具使用最佳实践

工具描述要清晰:LLM根据描述决定何时使用工具,描述不清会导致误用。

参数验证:在工具内部验证输入参数,防止错误输入。

错误处理:工具应该返回友好的错误信息,而不是抛出异常。

超时控制:对外部API调用设置超时。

import functools
import signal

def timeout_handler(signum, frame):
    raise TimeoutError("工具执行超时")

def with_timeout(seconds=30):
    """工具超时装饰器"""
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            old_handler = signal.signal(signal.SIGALRM, timeout_handler)
            signal.alarm(seconds)
            try:
                result = func(*args, **kwargs)
            finally:
                signal.alarm(0)
                signal.signal(signal.SIGALRM, old_handler)
            return result
        return wrapper
    return decorator


@registry.register(
    name="fetch_url",
    description="获取网页内容",
    parameters={"url": {"type": "string", "description": "网页URL"}}
)
@with_timeout(seconds=10)
def fetch_url(url: str) -> str:
    import urllib.request
    response = urllib.request.urlopen(url)
    return response.read().decode('utf-8')[:5000]  # 限制返回长度

六、环境感知与状态管理

6.1 环境接口设计

from abc import ABC, abstractmethod
from typing import Any, Dict

class Environment(ABC):
    """Agent环境接口"""
    
    @abstractmethod
    def get_state(self) -> Dict[str, Any]:
        """获取当前环境状态"""
        pass
    
    @abstractmethod
    def execute_action(self, action: str, params: Dict) -> Any:
        """在环境中执行动作"""
        pass
    
    @abstractmethod
    def observe(self) -> str:
        """观察环境变化"""
        pass


class WebEnvironment(Environment):
    """Web环境实现"""
    
    def __init__(self):
        self.current_url = None
        self.page_content = None
        self.history = []
    
    def get_state(self) -> Dict[str, Any]:
        return {
            "current_url": self.current_url,
            "has_content": self.page_content is not None,
            "history_length": len(self.history)
        }
    
    def execute_action(self, action: str, params: Dict) -> Any:
        if action == "navigate":
            self.current_url = params["url"]
            # 实际会获取网页内容
            self.page_content = f"页面内容: {params['url']}"
            self.history.append(params["url"])
            return f"已导航到 {params['url']}"
        
        elif action == "extract":
            # 提取页面信息
            return f"从 {self.current_url} 提取的信息..."
        
        return f"未知动作: {action}"
    
    def observe(self) -> str:
        state = self.get_state()
        return f"当前URL: {state['current_url']}, 浏览历史: {state['history_length']}页"


class FileSystemEnvironment(Environment):
    """文件系统环境"""
    
    def __init__(self, base_dir: str = "."):
        self.base_dir = base_dir
        self.current_dir = base_dir
    
    def get_state(self) -> Dict[str, Any]:
        import os
        files = os.listdir(self.current_dir)
        return {
            "current_dir": self.current_dir,
            "files": files[:20],  # 限制返回数量
            "file_count": len(files)
        }
    
    def execute_action(self, action: str, params: Dict) -> Any:
        import os
        
        if action == "read_file":
            path = os.path.join(self.current_dir, params["path"])
            with open(path, 'r', encoding='utf-8') as f:
                return f.read()
        
        elif action == "list_dir":
            path = os.path.join(self.current_dir, params.get("path", "."))
            return os.listdir(path)
        
        elif action == "change_dir":
            self.current_dir = os.path.join(self.current_dir, params["path"])
            return f"当前目录: {self.current_dir}"
        
        return f"未知动作: {action}"
    
    def observe(self) -> str:
        state = self.get_state()
        return f"目录: {state['current_dir']}, 文件数: {state['file_count']}"

6.2 状态机管理

class AgentStateMachine:
    """Agent状态机"""
    
    STATES = ["idle", "planning", "executing", "waiting", "error", "completed"]
    
    def __init__(self):
        self.current_state = "idle"
        self.state_data = {}
        self.transitions = {
            "idle": ["planning"],
            "planning": ["executing", "idle"],
            "executing": ["waiting", "completed", "error"],
            "waiting": ["executing", "error"],
            "error": ["planning", "idle"],
            "completed": ["idle"]
        }
    
    def transition(self, new_state: str, data: Dict = None) -> bool:
        """状态转换"""
        if new_state in self.transitions.get(self.current_state, []):
            self.current_state = new_state
            if data:
                self.state_data.update(data)
            return True
        return False
    
    def get_state(self) -> Dict:
        return {
            "state": self.current_state,
            "data": self.state_data
        }

七、错误恢复与自纠正

7.1 错误处理策略

class ErrorRecoveryStrategy:
    """错误恢复策略"""
    
    def __init__(self, llm):
        self.llm = llm
        self.error_history = []
    
    def handle_error(self, error: Exception, context: Dict) -> str:
        """处理错误并返回恢复策略"""
        error_info = {
            "type": type(error).__name__,
            "message": str(error),
            "context": context
        }
        self.error_history.append(error_info)
        
        # 分析错误类型
        if isinstance(error, ToolExecutionError):
            return self._handle_tool_error(error, context)
        elif isinstance(error, PlanningError):
            return self._handle_planning_error(error, context)
        else:
            return self._handle_general_error(error, context)
    
    def _handle_tool_error(self, error, context) -> str:
        """处理工具执行错误"""
        prompt = f"""工具执行失败:
工具: {context.get('tool_name')}
输入: {context.get('tool_input')}
错误: {str(error)}

请分析原因并建议恢复策略:
1. 是否应该重试?
2. 是否应该使用不同的工具?
3. 是否应该修改输入参数?

建议:"""
        
        return self.llm.generate(prompt)
    
    def _handle_planning_error(self, error, context) -> str:
        """处理规划错误"""
        return "replan"
    
    def _handle_general_error(self, error, context) -> str:
        """处理一般错误"""
        prompt = f"""遇到错误: {str(error)}
当前状态: {context}

请建议恢复策略。"""
        
        return self.llm.generate(prompt)


class ResilientAgent:
    """具有错误恢复能力的Agent"""
    
    def __init__(self, llm, tools, memory):
        self.llm = llm
        self.tools = tools
        self.memory = memory
        self.error_handler = ErrorRecoveryStrategy(llm)
        self.max_retries = 3
    
    def run(self, task: str) -> str:
        retry_count = 0
        
        while retry_count < self.max_retries:
            try:
                result = self._execute(task)
                return result
            except Exception as e:
                retry_count += 1
                print(f"错误 (尝试 {retry_count}): {str(e)}")
                
                # 获取恢复策略
                context = {
                    "task": task,
                    "attempt": retry_count,
                    "memory": self.memory.get_context()
                }
                
                recovery = self.error_handler.handle_error(e, context)
                print(f"恢复策略: {recovery}")
                
                # 根据恢复策略调整
                if "重试" in recovery:
                    continue
                elif "修改" in recovery:
                    task = self._modify_task(task, recovery)
                else:
                    break
        
        return f"任务执行失败,已尝试 {retry_count} 次"
    
    def _execute(self, task: str) -> str:
        """执行任务"""
        agent = ReActAgent(self.llm, self.tools, self.memory.short_term)
        return agent.run(task)
    
    def _modify_task(self, task: str, recovery: str) -> str:
        """根据恢复策略修改任务"""
        prompt = f"""原始任务: {task}
恢复建议: {recovery}

请根据建议,重新表述任务:"""
        
        return self.llm.generate(prompt)

7.2 自我验证

class SelfVerifyingAgent:
    """具有自我验证能力的Agent"""
    
    def __init__(self, llm, tools):
        self.llm = llm
        self.tools = tools
    
    def run(self, task: str) -> str:
        # 执行任务
        result = self._execute(task)
        
        # 自我验证
        is_valid, feedback = self._verify(task, result)
        
        if is_valid:
            return result
        
        # 如果验证失败,尝试修正
        corrected = self._correct(task, result, feedback)
        return corrected
    
    def _execute(self, task: str) -> str:
        agent = ReActAgent(self.llm, self.tools, ShortTermMemory())
        return agent.run(task)
    
    def _verify(self, task: str, result: str) -> tuple:
        """验证结果"""
        prompt = f"""请验证以下回答是否正确完成了任务。

任务: {task}
回答: {result}

检查清单:
1. 回答是否完整?
2. 信息是否准确?
3. 是否回答了问题的所有部分?

如果验证通过,回答 "VALID"。
如果验证失败,说明具体问题。

验证结果:"""
        
        verification = self.llm.generate(prompt)
        
        if "VALID" in verification:
            return True, ""
        
        return False, verification
    
    def _correct(self, task: str, result: str, feedback: str) -> str:
        """修正结果"""
        prompt = f"""任务: {task}
之前的回答: {result}
验证反馈: {feedback}

请根据反馈修正回答:"""
        
        return self.llm.generate(prompt)

八、Agent评估与基准测试

8.1 评估维度

Agent的评估需要考虑多个维度:

任务完成率:Agent能否成功完成指定任务。

效率:完成任务所需的步骤数、时间、API调用次数。

准确性:结果的正确性和精确度。

鲁棒性:面对错误和异常情况的处理能力。

安全性:是否遵守安全约束。

8.2 评估框架

from dataclasses import dataclass
from typing import List, Callable
import time
import json

@dataclass
class TestCase:
    """测试用例"""
    task: str
    expected_output: str = None
    evaluation_fn: Callable = None
    max_steps: int = 10
    timeout: int = 60


@dataclass
class EvalResult:
    """评估结果"""
    test_case: str
    success: bool
    output: str
    steps_taken: int
    time_taken: float
    error: str = None


class AgentEvaluator:
    """Agent评估器"""
    
    def __init__(self, agent):
        self.agent = agent
        self.results: List[EvalResult] = []
    
    def evaluate(self, test_cases: List[TestCase]) -> Dict:
        """运行评估"""
        for test_case in test_cases:
            result = self._run_test(test_case)
            self.results.append(result)
        
        return self._compute_metrics()
    
    def _run_test(self, test_case: TestCase) -> EvalResult:
        """运行单个测试"""
        start_time = time.time()
        
        try:
            output = self.agent.run(test_case.task)
            time_taken = time.time() - start_time
            
            # 评估成功性
            success = True
            if test_case.evaluation_fn:
                success = test_case.evaluation_fn(output)
            elif test_case.expected_output:
                success = self._check_output(output, test_case.expected_output)
            
            return EvalResult(
                test_case=test_case.task,
                success=success,
                output=output,
                steps_taken=getattr(self.agent, 'step_count', 0),
                time_taken=time_taken
            )
        
        except Exception as e:
            return EvalResult(
                test_case=test_case.task,
                success=False,
                output="",
                steps_taken=0,
                time_taken=time.time() - start_time,
                error=str(e)
            )
    
    def _check_output(self, output: str, expected: str) -> bool:
        """简单输出匹配"""
        return expected.lower() in output.lower()
    
    def _compute_metrics(self) -> Dict:
        """计算评估指标"""
        total = len(self.results)
        successes = sum(1 for r in self.results if r.success)
        
        return {
            "total_tests": total,
            "successes": successes,
            "success_rate": successes / total if total > 0 else 0,
            "avg_time": sum(r.time_taken for r in self.results) / total,
            "avg_steps": sum(r.steps_taken for r in self.results) / total,
            "errors": [r for r in self.results if r.error]
        }
    
    def generate_report(self) -> str:
        """生成评估报告"""
        metrics = self._compute_metrics()
        
        report = f"""Agent评估报告
================

总测试数: {metrics['total_tests']}
成功数: {metrics['successes']}
成功率: {metrics['success_rate']:.2%}
平均耗时: {metrics['avg_time']:.2f}秒
平均步骤数: {metrics['avg_steps']:.1f}

详细结果:
"""
        for result in self.results:
            status = "✓" if result.success else "✗"
            report += f"\n{status} [{result.time_taken:.1f}s] {result.test_case[:50]}..."
            if result.error:
                report += f"\n  错误: {result.error}"
        
        return report


# 使用示例
test_cases = [
    TestCase(
        task="计算 15 * 23 + 47 的结果",
        expected_output="392"
    ),
    TestCase(
        task="搜索Python最新版本号",
        evaluation_fn=lambda x: "3." in x  # 包含版本号
    ),
    TestCase(
        task="列出当前目录下的Python文件",
        evaluation_fn=lambda x: ".py" in x
    ),
]

evaluator = AgentEvaluator(my_agent)
report = evaluator.evaluate(test_cases)
print(evaluator.generate_report())

九、主流Agent框架对比

9.1 LangGraph

LangGraph是LangChain团队推出的图状态Agent框架,支持复杂的有状态工作流。

# LangGraph核心概念示意
from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, END

# 定义状态
class AgentState(TypedDict):
    task: str
    plan: list
    results: dict
    current_step: int

# 定义节点函数
def plan_node(state: AgentState) -> AgentState:
    """规划节点"""
    plan = create_plan(state["task"])
    return {"plan": plan, "current_step": 0}

def execute_node(state: AgentState) -> AgentState:
    """执行节点"""
    step = state["plan"][state["current_step"]]
    result = execute_step(step)
    state["results"][state["current_step"]] = result
    return {"current_step": state["current_step"] + 1, "results": state["results"]}

def should_continue(state: AgentState) -> str:
    """条件边:决定是否继续"""
    if state["current_step"] >= len(state["plan"]):
        return "end"
    return "continue"

# 构建图
workflow = StateGraph(AgentState)
workflow.add_node("planner", plan_node)
workflow.add_node("executor", execute_node)

# 添加边
workflow.set_entry_point("planner")
workflow.add_edge("planner", "executor")
workflow.add_conditional_edges(
    "executor",
    should_continue,
    {"continue": "executor", "end": END}
)

# 编译运行
app = workflow.compile()
result = app.invoke({"task": "分析销售数据", "plan": [], "results": {}, "current_step": 0})

优点:状态管理清晰、支持复杂流程、可视化调试 缺点:学习曲线较陡、概念较多

9.2 AutoGen

微软的多Agent对话框架,强调Agent之间的协作。

# AutoGen核心概念示意
from autogen import AssistantAgent, UserProxyAgent

# 创建助手Agent
assistant = AssistantAgent(
    name="researcher",
    system_message="你是一个研究助手,擅长分析数据和撰写报告。",
    llm_config={"model": "gpt-4o-mini"}
)

# 创建用户代理(可执行代码)
user_proxy = UserProxyAgent(
    name="user",
    human_input_mode="NEVER",  # 不需要人工输入
    max_consecutive_auto_reply=10,
    code_execution_config={"work_dir": "workspace"}
)

# 启动对话
user_proxy.initiate_chat(
    assistant,
    message="请分析当前目录下的sales.csv数据,并生成一份月度报告。"
)

优点:多Agent协作、代码执行、人机交互 缺点:对话管理复杂、调试困难

9.3 CrewAI

专注于角色扮演的多Agent框架,定义角色、目标和工具。

# CrewAI核心概念示意
from crewai import Agent, Task, Crew

# 定义Agent角色
researcher = Agent(
    role="研究员",
    goal="深入研究指定主题,收集全面信息",
    backstory="你是一位资深研究员,擅长信息收集和分析。",
    tools=[search_tool, read_tool],
    verbose=True
)

writer = Agent(
    role="技术作家",
    goal="将研究结果转化为高质量的技术文档",
    backstory="你是一位技术写作专家,擅长将复杂概念通俗化。",
    tools=[write_tool],
    verbose=True
)

# 定义任务
research_task = Task(
    description="研究AI Agent的最新进展",
    expected_output="一份详细的研究报告",
    agent=researcher
)

writing_task = Task(
    description="基于研究结果撰写技术教程",
    expected_output="一篇完整的技术教程",
    agent=writer,
    context=[research_task]  # 依赖研究任务的结果
)

# 组建团队并执行
crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, writing_task],
    verbose=True
)

result = crew.kickoff()

优点:角色定义直观、协作模式清晰 缺点:灵活性有限、调试工具不足

9.4 OpenAI Agents SDK

OpenAI官方的轻量Agent框架。

# OpenAI Agents SDK核心概念示意
from openai import OpenAI
from agents import Agent, Runner, function_tool

# 定义工具
@function_tool
def get_weather(city: str) -> str:
    """获取指定城市的天气信息"""
    return f"{city}今天晴朗,温度25°C"

@function_tool  
def search_knowledge(query: str) -> str:
    """搜索知识库"""
    return f"关于'{query}'的信息..."

# 定义Agent
agent = Agent(
    name="助手",
    instructions="你是一个有用的助手,可以查询天气和搜索知识。",
    tools=[get_weather, search_knowledge],
    model="gpt-4o-mini"
)

# 运行
result = Runner.run_sync(agent, "北京今天天气怎么样?")
print(result.final_output)

优点:简洁API、官方支持、与其他OpenAI服务集成 缺点:功能相对简单、依赖OpenAI生态

9.5 框架选型建议

场景 推荐框架
复杂有状态工作流 LangGraph
多Agent协作/代码执行 AutoGen
角色扮演/团队协作 CrewAI
快速原型/OpenAI生态 OpenAI Agents SDK
需要最大灵活性 自定义实现

十、Agent安全与人类监督

10.1 安全风险

Agent系统的安全风险包括:

工具滥用:Agent可能以不安全的方式使用工具(如删除文件、发送不当请求)。

权限提升:Agent可能尝试获取超出授权的权限。

信息泄露:Agent可能在不适当的场合泄露敏感信息。

幻觉与误导:Agent基于错误信息做出决策。

10.2 安全机制实现

from enum import Enum
from typing import List, Set

class RiskLevel(Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"


class SecurityPolicy:
    """安全策略管理"""
    
    def __init__(self):
        self.tool_risk_levels: Dict[str, RiskLevel] = {}
        self.forbidden_actions: Set[str] = set()
        self.require_approval: Set[str] = set()
        self.max_consecutive_actions: int = 20
    
    def set_tool_risk(self, tool_name: str, level: RiskLevel):
        self.tool_risk_levels[tool_name] = level
    
    def add_forbidden_action(self, action: str):
        self.forbidden_actions.add(action)
    
    def require_human_approval(self, action: str):
        self.require_approval.add(action)
    
    def check_action(self, action: str, params: Dict) -> tuple:
        """检查动作是否安全"""
        # 检查是否禁止
        if action in self.forbidden_actions:
            return False, "此操作已被禁止"
        
        # 检查风险级别
        risk = self.tool_risk_levels.get(action, RiskLevel.LOW)
        
        if risk in (RiskLevel.HIGH, RiskLevel.CRITICAL):
            if action in self.require_approval:
                return None, f"需要人工审批 (风险级别: {risk.value})"
        
        return True, "通过"


class HumanOversight:
    """人类监督机制"""
    
    def __init__(self, security_policy: SecurityPolicy):
        self.policy = security_policy
        self.approval_log: List[Dict] = []
    
    def request_approval(self, action: str, params: Dict, 
                         reason: str) -> bool:
        """请求人工审批"""
        print(f"\n{'='*50}")
        print(f"⚠️  需要人工审批")
        print(f"动作: {action}")
        print(f"参数: {params}")
        print(f"原因: {reason}")
        print(f"{'='*50}")
        
        # 在实际系统中,这里会发送审批请求
        response = input("是否批准?(y/n): ")
        approved = response.lower() == 'y'
        
        self.approval_log.append({
            "action": action,
            "params": params,
            "approved": approved
        })
        
        return approved


class SafeAgent:
    """具有安全机制的Agent"""
    
    def __init__(self, base_agent, security_policy: SecurityPolicy,
                 human_oversight: HumanOversight):
        self.agent = base_agent
        self.policy = security_policy
        self.oversight = human_oversight
        self.action_count = 0
    
    def run(self, task: str) -> str:
        # 任务安全检查
        if not self._check_task_safety(task):
            return "任务被安全策略拒绝"
        
        # 包装工具调用
        self._wrap_tools_with_security()
        
        # 执行
        return self.agent.run(task)
    
    def _check_task_safety(self, task: str) -> bool:
        """检查任务本身是否安全"""
        # 检查任务是否包含敏感操作
        dangerous_keywords = ["删除所有", "格式化", "rm -rf", "drop table"]
        for keyword in dangerous_keywords:
            if keyword in task.lower():
                return False
        return True
    
    def _wrap_tools_with_security(self):
        """包装工具添加安全检查"""
        original_tools = self.agent.tools.copy()
        
        for name, tool in original_tools.items():
            original_execute = tool.execute
            
            def make_safe_executor(tool_name, orig_exec):
                def safe_execute(**kwargs):
                    self.action_count += 1
                    
                    # 检查连续操作数
                    if self.action_count > self.policy.max_consecutive_actions:
                        return "超过最大连续操作数限制"
                    
                    # 安全检查
                    allowed, message = self.policy.check_action(
                        tool_name, kwargs
                    )
                    
                    if allowed is None:
                        # 需要人工审批
                        approved = self.oversight.request_approval(
                            tool_name, kwargs, message
                        )
                        if not approved:
                            return "操作被人工拒绝"
                    
                    elif not allowed:
                        return f"安全拒绝: {message}"
                    
                    return orig_exec(**kwargs)
                
                return safe_execute
            
            tool.execute = make_safe_executor(name, original_execute)

10.3 沙箱执行环境

class SandboxExecutor:
    """沙箱执行器:限制Agent的操作范围"""
    
    def __init__(self, allowed_dirs: List[str] = None,
                 allowed_commands: List[str] = None,
                 network_access: bool = False):
        self.allowed_dirs = allowed_dirs or []
        self.allowed_commands = allowed_commands or []
        self.network_access = network_access
    
    def execute_code(self, code: str) -> str:
        """在沙箱中执行代码"""
        import subprocess
        import tempfile
        
        # 写入临时文件
        with tempfile.NamedTemporaryFile(mode='w', suffix='.py', 
                                          delete=False) as f:
            f.write(code)
            temp_path = f.name
        
        # 构建受限执行命令
        cmd = [
            "python", temp_path
        ]
        
        # 设置环境变量限制
        env = {
            "PYTHONPATH": "",
            "SANDBOX_MODE": "1"
        }
        
        if not self.network_access:
            env["NO_NETWORK"] = "1"
        
        try:
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=30,
                env=env
            )
            return result.stdout if result.returncode == 0 else result.stderr
        except subprocess.TimeoutExpired:
            return "执行超时"
        finally:
            import os
            os.unlink(temp_path)

十一、实战案例:构建自主研究Agent

11.1 项目概述

我们将构建一个自主研究Agent,它能够:

  1. 理解研究问题
  2. 制定研究计划
  3. 搜索和收集信息
  4. 分析和综合信息
  5. 生成研究报告

11.2 完整实现

# research_agent.py
import json
from typing import List, Dict, Optional
from dataclasses import dataclass, field

@dataclass
class ResearchSource:
    """研究来源"""
    title: str
    content: str
    url: str = ""
    relevance_score: float = 0.0

@dataclass
class ResearchState:
    """研究状态"""
    question: str
    plan: List[str] = field(default_factory=list)
    sources: List[ResearchSource] = field(default_factory=list)
    findings: Dict[str, str] = field(default_factory=dict)
    current_step: int = 0
    status: str = "initialized"  # initialized, planning, researching, analyzing, completed


class ResearchAgent:
    """自主研究Agent"""
    
    def __init__(self, llm, search_tool, memory):
        self.llm = llm
        self.search_tool = search_tool
        self.memory = memory
        self.state: Optional[ResearchState] = None
    
    def research(self, question: str) -> str:
        """执行研究任务"""
        self.state = ResearchState(question=question)
        
        print(f"开始研究: {question}\n")
        
        # 阶段1: 制定研究计划
        self._create_plan()
        
        # 阶段2: 收集信息
        self._gather_information()
        
        # 阶段3: 分析和综合
        analysis = self._analyze_findings()
        
        # 阶段4: 生成报告
        report = self._generate_report()
        
        self.state.status = "completed"
        return report
    
    def _create_plan(self):
        """制定研究计划"""
        self.state.status = "planning"
        print("📋 制定研究计划...")
        
        prompt = f"""研究问题: {self.state.question}

请制定一个详细的研究计划,包括:
1. 需要搜索的关键主题
2. 需要回答的子问题
3. 信息收集的优先顺序

输出格式:
主题1: xxx
主题2: xxx
..."""
        
        response = self.llm.generate(prompt)
        
        # 解析计划
        self.state.plan = []
        for line in response.strip().split("\n"):
            if line.strip().startswith("主题"):
                parts = line.split(":", 1)
                if len(parts) > 1:
                    self.state.plan.append(parts[1].strip())
        
        print(f"研究计划: {self.state.plan}\n")
    
    def _gather_information(self):
        """收集信息"""
        self.state.status = "researching"
        print("🔍 收集信息...\n")
        
        for i, topic in enumerate(self.state.plan):
            print(f"  搜索主题 {i+1}: {topic}")
            
            # 生成搜索查询
            queries = self._generate_search_queries(topic)
            
            # 执行搜索
            for query in queries:
                results = self.search_tool.execute(query=query)
                
                # 处理搜索结果
                sources = self._process_search_results(query, results)
                self.state.sources.extend(sources)
                
                print(f"    查询 '{query}' 找到 {len(sources)} 个相关来源")
            
            # 提取关键发现
            finding = self._extract_findings(topic)
            self.state.findings[topic] = finding
            self.state.current_step = i + 1
            
            print(f"    关键发现: {finding[:100]}...\n")
    
    def _generate_search_queries(self, topic: str) -> List[str]:
        """为给定主题生成搜索查询"""
        prompt = f"""研究主题: {topic}
相关问题: {self.state.question}

请生成2-3个不同的搜索查询,从不同角度搜索信息。
每行一个查询:"""
        
        response = self.llm.generate(prompt)
        queries = [q.strip() for q in response.strip().split("\n") if q.strip()]
        return queries[:3]
    
    def _process_search_results(self, query: str, results: str) -> List[ResearchSource]:
        """处理搜索结果"""
        # 简化处理:将结果拆分为来源
        sources = []
        sections = results.split("\n\n")
        
        for i, section in enumerate(sections[:3]):
            if len(section.strip()) > 50:
                source = ResearchSource(
                    title=f"来源_{query}_{i}",
                    content=section.strip(),
                    relevance_score=1.0 - (i * 0.2)
                )
                sources.append(source)
        
        return sources
    
    def _extract_findings(self, topic: str) -> str:
        """从收集的来源中提取关键发现"""
        # 获取与当前主题相关的来源
        relevant_sources = [
            s.content for s in self.state.sources 
            if topic.lower() in s.content.lower()
        ][:5]
        
        if not relevant_sources:
            return "未找到相关信息"
        
        sources_text = "\n---\n".join(relevant_sources)
        
        prompt = f"""研究主题: {topic}
研究问题: {self.state.question}

基于以下来源信息,提取关键发现和要点:

{sources_text}

请总结3-5个关键发现:"""
        
        return self.llm.generate(prompt)
    
    def _analyze_findings(self) -> str:
        """分析和综合所有发现"""
        self.state.status = "analyzing"
        print("📊 分析研究发现...\n")
        
        findings_text = "\n\n".join(
            f"## {topic}\n{finding}" 
            for topic, finding in self.state.findings.items()
        )
        
        prompt = f"""研究问题: {self.state.question}

研究发现:
{findings_text}

请进行深入分析:
1. 这些发现之间有什么关联?
2. 是否存在矛盾或不一致?
3. 最重要的结论是什么?
4. 还有哪些未解答的问题?

分析结果:"""
        
        return self.llm.generate(prompt)
    
    def _generate_report(self) -> str:
        """生成最终研究报告"""
        print("📝 生成研究报告...\n")
        
        analysis = self._analyze_findings()
        
        prompt = f"""请基于以下研究内容,生成一份完整的研究报告。

研究问题: {self.state.question}

研究发现:
{json.dumps(self.state.findings, ensure_ascii=False, indent=2)}

分析:
{analysis}

请按照以下结构生成报告:
1. 摘要
2. 背景
3. 主要发现
4. 分析与讨论
5. 结论
6. 参考来源

报告:"""
        
        report = self.llm.generate(prompt)
        
        # 保存到长期记忆
        self.memory.remember(
            f"研究报告: {self.state.question}\n{report[:500]}",
            memory_type="research"
        )
        
        return report


# 使用示例
class MockLLM:
    """模拟LLM(用于演示)"""
    def generate(self, prompt: str) -> str:
        # 实际使用时替换为真实LLM调用
        return "这是LLM的模拟响应..."


class MockSearchTool:
    """模拟搜索工具"""
    def execute(self, query: str) -> str:
        return f"搜索 '{query}' 的结果...\n相关内容片段1...\n相关内容片段2..."


# 运行研究Agent
if __name__ == "__main__":
    llm = MockLLM()
    search_tool = MockSearchTool()
    memory = AgentMemory(None, None)  # 简化示意
    
    agent = ResearchAgent(llm, search_tool, memory)
    report = agent.research("2024年AI Agent技术的发展趋势是什么?")
    print(report)

11.3 增强功能

class EnhancedResearchAgent(ResearchAgent):
    """增强版研究Agent"""
    
    def __init__(self, llm, tools, memory):
        super().__init__(llm, tools.get("search"), memory)
        self.tools = tools
        self.verifier = SelfVerifyingAgent(llm, tools)
    
    def research(self, question: str) -> str:
        """增强的研究流程"""
        # 初始研究
        initial_report = super().research(question)
        
        # 自我验证
        is_valid, feedback = self.verifier._verify(question, initial_report)
        
        if not is_valid:
            print(f"\n验证反馈: {feedback}")
            print("进行补充研究...")
            
            # 补充研究
            additional_findings = self._supplemental_research(feedback)
            
            # 修正报告
            final_report = self._revise_report(
                question, initial_report, additional_findings
            )
            return final_report
        
        return initial_report
    
    def _supplemental_research(self, feedback: str) -> str:
        """基于反馈进行补充研究"""
        prompt = f"""基于以下反馈,确定需要补充研究的内容:

{feedback}

请列出需要进一步研究的问题:"""
        
        additional_questions = self.llm.generate(prompt)
        
        # 执行补充搜索
        findings = []
        for question in additional_questions.split("\n"):
            if question.strip():
                result = self.search_tool.execute(query=question.strip())
                findings.append(result)
        
        return "\n".join(findings)
    
    def _revise_report(self, question: str, original: str, 
                       additional: str) -> str:
        """修正报告"""
        prompt = f"""原始报告:
{original}

补充研究结果:
{additional}

请修正和完善报告,确保回答完整、准确。"""
        
        return self.llm.generate(prompt)

十二、最佳实践

12.1 设计原则

  1. 单一职责:每个Agent只负责一个明确的任务
  2. 可组合性:Agent可以组合使用,形成更强大的系统
  3. 可观察性:Agent的每一步都应该可追踪、可调试
  4. 优雅降级:当工具或外部服务不可用时,有合理的回退方案

12.2 开发建议

  1. 从小开始:先实现核心功能,再逐步增加复杂性
  2. 充分测试:建立完善的评估数据集和测试流程
  3. 日志记录:记录Agent的每一步决策和行动
  4. 人工验证:关键决策点加入人工审核

12.3 性能优化

  1. 缓存:缓存重复的工具调用结果
  2. 并发:独立的子任务可以并发执行
  3. 提前终止:当结果已经足够好时,提前结束
  4. 工具选择:根据任务特点选择最合适的工具

十三、常见问题

Q1: Agent总是无限循环怎么办?

设置明确的终止条件:

  • 最大迭代次数
  • 重复检测(如果连续N次行动相同则终止)
  • 进度检查(如果长时间没有进展则终止)
  • 成本限制(API调用次数/金额上限)

Q2: 如何处理LLM的幻觉?

  • 要求Agent引用来源
  • 实施自我验证机制
  • 使用工具验证关键信息
  • 设置置信度阈值

Q3: 如何降低Agent的成本?

  • 使用更小的模型处理简单任务
  • 缓存重复查询
  • 减少不必要的工具调用
  • 优化Prompt减少Token使用

Q4: 多Agent系统如何处理冲突?

  • 定义清晰的职责边界
  • 实施仲裁机制
  • 使用优先级系统
  • 引入人类监督

Q5: 如何评估Agent的安全性?

  • 建立安全测试用例集
  • 红队测试(尝试让Agent做不安全的事)
  • 监控异常行为模式
  • 定期审计Agent的决策日志

十四、总结

AI Agent代表了人工智能从"工具"到"助手"再到"自主体"的演进方向。构建高质量的Agent系统需要综合考虑:

  1. 记忆系统:短期记忆保持对话连贯,长期记忆积累经验,工作记忆管理当前任务
  2. 规划能力:ReAct适合简单任务,Plan-and-Execute适合复杂任务,Reflexion适合需要迭代改进的任务
  3. 工具使用:清晰的工具定义、可靠的错误处理、安全的执行环境
  4. 安全机制:权限控制、人类监督、沙箱执行

技术栈推荐

  • 快速原型:OpenAI Agents SDK + Function Calling
  • 复杂工作流:LangGraph
  • 多Agent协作:AutoGen 或 CrewAI
  • 生产环境:自定义实现 + 安全框架

未来的发展方向包括:

  • 更强的自主规划能力
  • 更好的多模态理解
  • 更安全的Agent行为
  • Agent之间的标准化协作协议

掌握本教程的核心技术和工程实践,你将能够构建出强大、可靠、安全的AI Agent系统,为用户提供真正有价值的智能服务。

内容声明

本文内容为AI技术学习教程,仅供学习参考。如涉及技术问题,欢迎通过 xurj005@163.com 与我们交流。

目录