从原理到实践构建自主AI代理

前言

AI Agent(智能体)是能够自主感知环境、做出决策并执行行动的AI系统。与简单的问答不同,Agent能够分解任务、使用工具、迭代执行,直到完成复杂目标。本文深入介绍Agent的原理与实现。


Agent概述

什么是AI Agent

特性 说明
自主性 能够独立做出决策
目标导向 围绕目标规划行动
环境交互 通过工具与外界交互
学习适应 从反馈中调整策略

Agent vs 传统LLM应用

传统LLM应用:
  用户输入 → LLM处理 → 直接输出
  
Agent:
  用户目标 → 任务规划 → [观察→思考→行动]循环 → 最终结果
                              ↑__________|

Agent核心组件

┌─────────────────────────────────────────────┐
│                  AI Agent                    │
├─────────────────────────────────────────────┤
│                                             │
│    ┌─────────┐    ┌─────────┐              │
│    │  Brain  │    │ Memory  │              │
│    │  (LLM)  │◄──►│ 记忆系统 │              │
│    └────┬────┘    └─────────┘              │
│         │                                   │
│    ┌────▼────┐                             │
│    │Planning │   规划与推理                 │
│    └────┬────┘                             │
│         │                                   │
│    ┌────▼────┐    ┌─────────┐              │
│    │ Action  │───►│  Tools  │              │
│    │ 执行器  │    │  工具集  │              │
│    └─────────┘    └─────────┘              │
│                                             │
└─────────────────────────────────────────────┘

ReAct框架

ReAct原理

ReAct (Reasoning + Acting) 将推理与行动交织:

用户问题:北京今天的温度是多少摄氏度?

Thought: 我需要获取北京的天气信息
Action: search_weather
Action Input: {"city": "北京"}
Observation: 北京今天晴,温度8-15°C

Thought: 我已经得到了北京的温度信息
Final Answer: 北京今天的温度是8-15摄氏度。

ReAct实现

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.tools import tool
import json
import re

# 定义工具
@tool
def search_weather(city: str) -> str:
    """查询城市天气信息"""
    weather_data = {
        "北京": "晴,温度8-15°C,空气质量良好",
        "上海": "多云,温度12-18°C,湿度80%",
        "深圳": "阴,温度20-25°C,有阵雨"
    }
    return weather_data.get(city, f"未找到{city}的天气信息")

@tool  
def calculate(expression: str) -> str:
    """计算数学表达式"""
    try:
        return str(eval(expression))
    except:
        return "计算错误"

@tool
def search_web(query: str) -> str:
    """搜索网络信息"""
    return f"关于'{query}'的搜索结果:这是一个模拟的搜索结果。"

class SimpleReActAgent:
    def __init__(self, tools: list):
        self.llm = ChatOpenAI(model="gpt-4o", temperature=0)
        self.tools = {t.name: t for t in tools}
        self.tools_description = "\n".join(
            f"- {t.name}: {t.description}"
            for t in tools
        )
        
        self.prompt = ChatPromptTemplate.from_template("""
你是一个能够使用工具的AI助手。请使用ReAct格式回答问题。

可用工具:
{tools}

使用格式:
Thought: 思考当前需要做什么
Action: 工具名称
Action Input: 工具输入(JSON格式)
Observation: 工具返回结果(由系统填充)
... (可以重复多次)
Thought: 得出最终结论
Final Answer: 最终答案

问题:{question}

{agent_scratchpad}
""")
    
    def run(self, question: str, max_iterations: int = 5) -> str:
        """运行Agent"""
        scratchpad = ""
        
        for i in range(max_iterations):
            # 构建提示
            prompt_value = self.prompt.format(
                tools=self.tools_description,
                question=question,
                agent_scratchpad=scratchpad
            )
            
            # 获取LLM响应
            response = self.llm.invoke(prompt_value).content
            
            # 检查是否得出最终答案
            if "Final Answer:" in response:
                final_answer = response.split("Final Answer:")[-1].strip()
                return final_answer
            
            # 解析并执行Action
            action_match = re.search(
                r'Action:\s*(\w+)\s*\nAction Input:\s*(.+?)(?=\n|$)',
                response, re.DOTALL
            )
            
            if action_match:
                action_name = action_match.group(1)
                action_input = action_match.group(2).strip()
                
                # 执行工具
                if action_name in self.tools:
                    try:
                        # 解析JSON输入
                        if action_input.startswith('{'):
                            input_dict = json.loads(action_input)
                            result = self.tools[action_name].invoke(input_dict)
                        else:
                            result = self.tools[action_name].invoke(action_input)
                    except Exception as e:
                        result = f"工具执行错误: {e}"
                else:
                    result = f"未找到工具: {action_name}"
                
                # 更新scratchpad
                scratchpad += f"{response}\nObservation: {result}\n"
            else:
                scratchpad += response + "\n"
        
        return "达到最大迭代次数,未能得出答案"

# 使用示例
agent = SimpleReActAgent([search_weather, calculate, search_web])
answer = agent.run("北京今天天气怎么样?如果温度是15度,加上5度是多少?")
print(answer)

规划能力

任务分解

class TaskPlanner:
    def __init__(self):
        self.llm = ChatOpenAI(model="gpt-4o", temperature=0)
        
        self.plan_prompt = ChatPromptTemplate.from_template("""
你是一个任务规划专家。请将用户的复杂目标分解为具体的执行步骤。

目标:{goal}

请以JSON格式输出任务分解:
goal_summary
    ],
    "success_criteria": "成功标准"
}}

请确保步骤之间的依赖关系正确,步骤要具体可执行。
""")
    
    def plan(self, goal: str) -> dict:
        """生成执行计划"""
        prompt = self.plan_prompt.format(goal=goal)
        response = self.llm.invoke(prompt).content
        
        # 提取JSON
        import json
        json_match = re.search(r'\{[\s\S]*\}', response)
        if json_match:
            return json.loads(json_match.group())
        return {"error": "无法解析计划"}

# 使用示例
planner = TaskPlanner()
plan = planner.plan("帮我调研Python Web框架,比较Flask、FastAPI和Django,并给出选型建议")
print(json.dumps(plan, ensure_ascii=False, indent=2))

Plan-and-Execute模式

from typing import List, Dict, Any

class PlanAndExecuteAgent:
    def __init__(self, tools: list):
        self.planner = TaskPlanner()
        self.executor = SimpleReActAgent(tools)
        self.llm = ChatOpenAI(model="gpt-4o")
    
    def run(self, goal: str) -> str:
        """规划并执行"""
        # 1. 生成计划
        print("📋 正在规划任务...")
        plan = self.planner.plan(goal)
        
        if "error" in plan:
            return f"规划失败: {plan['error']}"
        
        print(f"✅ 计划包含 {len(plan['steps'])} 个步骤")
        
        # 2. 按顺序执行步骤
        results = []
        for step in plan['steps']:
            print(f"\n🔄 执行步骤 {step['id']}: {step['description']}")
            
            # 执行单个步骤
            step_result = self.executor.run(step['description'])
            results.append({
                "step_id": step['id'],
                "description": step['description'],
                "result": step_result
            })
            
            print(f"✅ 步骤完成")
        
        # 3. 汇总结果
        summary = self._summarize_results(goal, results)
        return summary
    
    def _summarize_results(self, goal: str, results: List[Dict]) -> str:
        """汇总执行结果"""
        results_text = "\n".join(
            f"步骤{r['step_id']}: {r['description']}\n结果: {r['result']}"
            for r in results
        )
        
        summary_prompt = f"""
原始目标:{goal}

执行结果:
{results_text}

请根据以上执行结果,给出最终的综合回答。
"""
        
        response = self.llm.invoke(summary_prompt)
        return response.content

记忆系统

短期记忆

from collections import deque
from dataclasses import dataclass
from datetime import datetime
from typing import Optional

@dataclass
class MemoryItem:
    content: str
    type: str  # observation, thought, action, result
    timestamp: datetime
    importance: float = 1.0

class ShortTermMemory:
    def __init__(self, capacity: int = 20):
        self.memory = deque(maxlen=capacity)
    
    def add(self, content: str, type: str, importance: float = 1.0):
        """添加记忆"""
        item = MemoryItem(
            content=content,
            type=type,
            timestamp=datetime.now(),
            importance=importance
        )
        self.memory.append(item)
    
    def get_recent(self, n: int = 5) -> List[MemoryItem]:
        """获取最近n条记忆"""
        return list(self.memory)[-n:]
    
    def get_by_type(self, type: str) -> List[MemoryItem]:
        """按类型获取记忆"""
        return [m for m in self.memory if m.type == type]
    
    def to_context(self) -> str:
        """转换为上下文字符串"""
        return "\n".join(
            f"[{m.type}] {m.content}"
            for m in self.memory
        )

长期记忆(向量存储)

from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_core.documents import Document

class LongTermMemory:
    def __init__(self, persist_dir: str = "./agent_memory"):
        self.embeddings = OpenAIEmbeddings()
        self.vectorstore = Chroma(
            collection_name="agent_memory",
            embedding_function=self.embeddings,
            persist_directory=persist_dir
        )
    
    def add(self, content: str, metadata: dict = None):
        """存储记忆"""
        doc = Document(
            page_content=content,
            metadata=metadata or {}
        )
        self.vectorstore.add_documents([doc])
    
    def search(self, query: str, k: int = 5) -> List[Document]:
        """检索相关记忆"""
        return self.vectorstore.similarity_search(query, k=k)
    
    def get_relevant_context(self, query: str, k: int = 3) -> str:
        """获取相关上下文"""
        docs = self.search(query, k=k)
        return "\n".join(doc.page_content for doc in docs)

反思机制

class ReflectionMemory:
    def __init__(self):
        self.llm = ChatOpenAI(model="gpt-4o")
        self.experiences = []
    
    def add_experience(self, task: str, actions: list, outcome: str, success: bool):
        """记录经验"""
        self.experiences.append({
            "task": task,
            "actions": actions,
            "outcome": outcome,
            "success": success,
            "timestamp": datetime.now()
        })
    
    def reflect(self) -> str:
        """反思近期经验"""
        if not self.experiences:
            return "暂无经验可供反思"
        
        recent = self.experiences[-5:]
        experiences_text = "\n".join(
            f"任务: {e['task']}\n行动: {e['actions']}\n结果: {e['outcome']}\n成功: {e['success']}"
            for e in recent
        )
        
        prompt = f"""
请分析以下执行经验,总结规律和教训:

{experiences_text}

请给出:
1. 成功模式:哪些做法有效
2. 失败原因:哪些情况导致失败
3. 改进建议:如何提高成功率
"""
        
        response = self.llm.invoke(prompt)
        return response.content

多Agent系统

Agent协作架构

                    ┌─────────────┐
                    │ Coordinator │
                    │   协调者     │
                    └──────┬──────┘
                           │
         ┌─────────────────┼─────────────────┐
         ▼                 ▼                 ▼
  ┌────────────┐   ┌────────────┐   ┌────────────┐
  │ Researcher │   │   Coder    │   │  Reviewer  │
  │  研究者     │   │   编码者    │   │   审查者    │
  └────────────┘   └────────────┘   └────────────┘

多Agent实现

from typing import Callable
from enum import Enum

class AgentRole(Enum):
    COORDINATOR = "coordinator"
    RESEARCHER = "researcher"
    CODER = "coder"
    REVIEWER = "reviewer"

class SpecializedAgent:
    def __init__(self, role: AgentRole, tools: list = None):
        self.role = role
        self.llm = ChatOpenAI(model="gpt-4o")
        self.tools = tools or []
        
        self.system_prompts = {
            AgentRole.COORDINATOR: """
你是团队协调者,负责:
1. 理解任务需求
2. 分配任务给合适的团队成员
3. 整合各方结果
4. 做出最终决策
""",
            AgentRole.RESEARCHER: """
你是研究专家,负责:
1. 收集和分析信息
2. 调研最佳实践
3. 评估技术方案
4. 提供研究报告
""",
            AgentRole.CODER: """
你是编程专家,负责:
1. 编写高质量代码
2. 实现技术方案
3. 处理技术细节
4. 确保代码可运行
""",
            AgentRole.REVIEWER: """
你是审查专家,负责:
1. 审查代码质量
2. 发现潜在问题
3. 提供改进建议
4. 确保符合标准
"""
        }
    
    def process(self, task: str, context: str = "") -> str:
        """处理任务"""
        prompt = f"""
{self.system_prompts[self.role]}

当前上下文:
{context}

任务:
{task}

请完成任务并给出详细结果。
"""
        response = self.llm.invoke(prompt)
        return response.content

class MultiAgentSystem:
    def __init__(self):
        self.agents = {
            AgentRole.COORDINATOR: SpecializedAgent(AgentRole.COORDINATOR),
            AgentRole.RESEARCHER: SpecializedAgent(AgentRole.RESEARCHER),
            AgentRole.CODER: SpecializedAgent(AgentRole.CODER),
            AgentRole.REVIEWER: SpecializedAgent(AgentRole.REVIEWER),
        }
        self.conversation_history = []
    
    def run(self, goal: str) -> str:
        """运行多Agent协作"""
        context = ""
        
        # 1. 协调者分析任务
        print("🎯 协调者分析任务...")
        coordinator_analysis = self.agents[AgentRole.COORDINATOR].process(
            f"分析以下任务,确定需要哪些专家参与,以及执行顺序:\n{goal}"
        )
        context += f"协调者分析:\n{coordinator_analysis}\n\n"
        
        # 2. 研究者调研
        print("🔍 研究者调研...")
        research_result = self.agents[AgentRole.RESEARCHER].process(
            goal, context
        )
        context += f"研究结果:\n{research_result}\n\n"
        
        # 3. 编码者实现
        print("💻 编码者实现...")
        code_result = self.agents[AgentRole.CODER].process(
            goal, context
        )
        context += f"代码实现:\n{code_result}\n\n"
        
        # 4. 审查者审查
        print("🔎 审查者审查...")
        review_result = self.agents[AgentRole.REVIEWER].process(
            f"审查以下实现:\n{code_result}", context
        )
        context += f"审查结果:\n{review_result}\n\n"
        
        # 5. 协调者汇总
        print("📋 协调者汇总...")
        final_result = self.agents[AgentRole.COORDINATOR].process(
            f"汇总团队工作结果,给出最终交付物:\n目标:{goal}",
            context
        )
        
        return final_result

# 使用示例
mas = MultiAgentSystem()
result = mas.run("实现一个Python函数,用于解析CSV文件并计算每列的统计信息")
print(result)

工具使用进阶

动态工具选择

class DynamicToolSelector:
    def __init__(self, tools: list):
        self.tools = {t.name: t for t in tools}
        self.llm = ChatOpenAI(model="gpt-4o")
    
    def select_tools(self, task: str) -> list:
        """根据任务动态选择工具"""
        tools_info = "\n".join(
            f"- {name}: {tool.description}"
            for name, tool in self.tools.items()
        )
        
        prompt = f"""
任务:{task}

可用工具:
{tools_info}

请选择完成此任务所需的工具(返回工具名列表,JSON格式):
"""
        
        response = self.llm.invoke(prompt).content
        selected = json.loads(response)
        
        return [self.tools[name] for name in selected if name in self.tools]

工具链组合

class ToolChain:
    def __init__(self, tools: list):
        self.tools = {t.name: t for t in tools}
    
    def execute_chain(self, chain: List[Dict]) -> List[Dict]:
        """执行工具链
        
        chain格式:
        [
            {"tool": "search", "input": "query", "output_var": "search_result"},
            {"tool": "summarize", "input": "${search_result}", "output_var": "summary"}
        ]
        """
        variables = {}
        results = []
        
        for step in chain:
            tool_name = step["tool"]
            input_val = step["input"]
            
            # 替换变量引用
            if input_val.startswith("${") and input_val.endswith("}"):
                var_name = input_val[2:-1]
                input_val = variables.get(var_name, input_val)
            
            # 执行工具
            if tool_name in self.tools:
                output = self.tools[tool_name].invoke(input_val)
                variables[step["output_var"]] = output
                results.append({
                    "step": step,
                    "output": output
                })
            else:
                results.append({
                    "step": step,
                    "error": f"Tool {tool_name} not found"
                })
        
        return results

工具错误处理

class RobustToolExecutor:
    def __init__(self, tools: list, max_retries: int = 3):
        self.tools = {t.name: t for t in tools}
        self.max_retries = max_retries
        self.llm = ChatOpenAI(model="gpt-4o")
    
    def execute(self, tool_name: str, input_data: Any) -> Dict:
        """带重试的工具执行"""
        errors = []
        
        for attempt in range(self.max_retries):
            try:
                if tool_name not in self.tools:
                    # 尝试找到相似工具
                    suggested = self._suggest_tool(tool_name)
                    if suggested:
                        tool_name = suggested
                    else:
                        return {"error": f"工具 {tool_name} 不存在"}
                
                result = self.tools[tool_name].invoke(input_data)
                return {"success": True, "result": result}
                
            except Exception as e:
                errors.append(str(e))
                
                # 尝试修复输入
                if attempt < self.max_retries - 1:
                    input_data = self._fix_input(tool_name, input_data, str(e))
        
        return {
            "error": "执行失败",
            "attempts": errors
        }
    
    def _suggest_tool(self, tool_name: str) -> Optional[str]:
        """建议相似工具"""
        from difflib import get_close_matches
        matches = get_close_matches(
            tool_name, 
            self.tools.keys(), 
            n=1, 
            cutoff=0.6
        )
        return matches[0] if matches else None
    
    def _fix_input(self, tool_name: str, input_data: Any, error: str) -> Any:
        """尝试修复输入"""
        prompt = f"""
工具 {tool_name} 执行失败。
输入: {input_data}
错误: {error}

请修正输入格式(只返回修正后的输入):
"""
        response = self.llm.invoke(prompt)
        return response.content.strip()

实战:构建研究助手Agent

from langchain_openai import ChatOpenAI
from langchain_community.tools import DuckDuckGoSearchResults
from langchain_core.tools import tool
import json

# 定义工具
@tool
def web_search(query: str) -> str:
    """搜索互联网获取信息"""
    search = DuckDuckGoSearchResults()
    return search.run(query)

@tool
def take_notes(content: str) -> str:
    """记录研究笔记"""
    # 实际应用中可以保存到文件或数据库
    return f"已记录笔记: {content[:100]}..."

@tool
def write_report(topic: str, notes: str) -> str:
    """根据笔记生成研究报告"""
    llm = ChatOpenAI(model="gpt-4o")
    prompt = f"""
基于以下研究笔记,为主题"{topic}"生成一份结构化的研究报告。

研究笔记:
{notes}

报告应包含:
1. 摘要
2. 背景介绍
3. 主要发现
4. 结论与建议
"""
    response = llm.invoke(prompt)
    return response.content

class ResearchAssistant:
    def __init__(self):
        self.llm = ChatOpenAI(model="gpt-4o", temperature=0)
        self.tools = [web_search, take_notes, write_report]
        self.notes = []
        
        self.system_prompt = """
你是一个专业的研究助手Agent。你的任务是帮助用户进行深入研究。

工作流程:
1. 理解研究主题和目标
2. 制定研究计划
3. 使用搜索工具收集信息
4. 整理和记录重要发现
5. 生成研究报告

可用工具:
- web_search: 搜索互联网信息
- take_notes: 记录研究笔记
- write_report: 生成研究报告

请根据用户需求,逐步完成研究任务。
"""
    
    def research(self, topic: str) -> str:
        """执行研究任务"""
        print(f"🔬 开始研究: {topic}\n")
        
        # 1. 制定研究计划
        plan_prompt = f"""
研究主题: {topic}

请制定一个详细的研究计划,包括:
1. 需要搜索的关键问题(3-5个)
2. 预期的研究产出
"""
        plan = self.llm.invoke(plan_prompt).content
        print(f"📋 研究计划:\n{plan}\n")
        
        # 2. 执行搜索
        search_queries = self._extract_queries(plan)
        all_findings = []
        
        for query in search_queries:
            print(f"🔍 搜索: {query}")
            results = web_search.invoke(query)
            all_findings.append(f"查询: {query}\n结果: {results}")
        
        # 3. 整理笔记
        notes_content = "\n\n".join(all_findings)
        take_notes.invoke(notes_content)
        
        # 4. 生成报告
        print("\n📝 生成研究报告...")
        report = write_report.invoke({"topic": topic, "notes": notes_content})
        
        return report
    
    def _extract_queries(self, plan: str) -> List[str]:
        """从计划中提取搜索查询"""
        prompt = f"""
从以下研究计划中提取关键搜索查询,返回JSON列表:

{plan}

返回格式:["查询1", "查询2", ...]
"""
        response = self.llm.invoke(prompt).content
        try:
            queries = json.loads(response)
            return queries[:5]  # 限制最多5个查询
        except:
            return [plan.split('\n')[0]]  # 回退到主题

# 使用示例
assistant = ResearchAssistant()
report = assistant.research("2024年大语言模型的最新发展趋势")
print(report)

工业级进阶:Agentic Workflows

吴恩达 (Andrew Ng) 曾指出,Agentic Workflows (智能体工作流) 往往比单纯追求更强大的模型更能提升应用效果。以下是四种核心模式:

1. 反思 (Reflection)

让模型检查自己的工作。

  • 模式:生成 -> 检查 -> 修正。
  • 价值:显著降低逻辑错误和幻觉。

2. 工具使用 (Tool Use)

赋予模型行动能力。

  • 模式:思考 -> 选择工具 -> 执行 -> 观察结果。
  • 价值:扩展了 LLM 的能力边界(如实时搜索、代码执行)。

3. 规划 (Planning)

将复杂目标拆解为子任务。

  • 模式:目标 -> 任务列表 -> 逐一执行 -> 动态调整。
  • 价值:处理长程、复杂任务的关键。

4. 多智能体协作 (Multi-agent Collaboration)

让多个角色各司其职。

  • 模式:辩论、分工、评审。
  • 价值:模拟人类团队,提高专业领域的输出质量。

主流 Agent 框架对比

框架 核心理念 适用场景
CrewAI 角色扮演与流程驱动 结构化的团队协作任务
AutoGen 对话驱动的多智能体 复杂的交互式任务、代码生成
LangGraph 状态机与图结构 需要精细控制状态和循环的场景
PydanticAI 类型安全与生产级 追求严谨、可测试的生产环境

总结

AI Agent是LLM应用的高级形态,核心要点:

要素 说明
规划能力 分解任务、制定策略
工具使用 与外界环境交互
记忆系统 保持上下文、积累经验
反馈循环 观察结果、调整行动

构建可靠的Agent需要关注:

  • 明确的任务边界
  • 合理的工具设计
  • 完善的错误处理
  • 适当的人工干预

参考资源

版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。

(采用 CC BY-NC-SA 4.0 许可协议进行授权)

本文标题:《 LLM应用开发——Agent智能体 》

本文链接:http://localhost:3015/ai/Agent%E6%99%BA%E8%83%BD%E4%BD%93.html

本文最后一次更新为 天前,文章中的某些内容可能已过时!