
全网最全AI智能体框架终极指南:从CoT到Plan-and-Execute,附LangGraph完整代码 原创
随着大语言模型(LLM)的快速发展,如何让AI系统更智能地解决复杂问题成为了研究热点。从简单的问答到复杂的多步骤任务执行,LLM Agent思考框架正在重塑我们对AI能力的认知。本文将深入探讨几种主流的Agent思考框架,包括Chain of Thought(CoT)、ReAct、以及Plan-and-Execute等,并提供基于LangChain和LangGraph的具体实现代码,帮助您理解这些框架的原理、优势和实际应用场景。
无论您是想快速上手Agent开发,还是希望深入理解不同框架的设计理念,本文都将为您提供理论知识和实战代码的完整指南。
一、Agent思考框架概述
环境准备
在开始之前,请确保安装必要的依赖:
# 基础依赖
pip install langchain langchain-openai langchain-community
# LangGraph(用于高级Agent功能)
pip install langgraph
# 工具依赖
pip install tavily-python # 搜索工具
pip install arxiv # 学术论文搜索
pip install wikipedia-api # Wikipedia查询
# 可选:监控和调试
pip install langsmith
设置API密钥:
import os
os.environ["OPENAI_API_KEY"] = "your-api-key"
os.environ["TAVILY_API_KEY"] = "your-tavily-key" # 获取地址:https://tavily.com
什么是Agent思考框架?
Agent思考框架是指导LLM如何系统化地分解问题、推理和执行任务的结构化方法。这些框架让LLM不再是简单的"问答机器",而是能够像人类一样思考、规划和行动的智能体。
通过规划,LLM agents能够推理、将复杂任务分解为更小、更可管理的部分,并为每个部分制定具体计划。随着任务的发展,agents还可以反思和调整他们的计划,确保它们与现实世界的情况保持相关。
核心组件
一个完整的Agent框架通常包含以下核心组件:
- 思维(Thought):Agent的推理过程,用于分析问题和制定策略
- 行动(Action):Agent可以执行的具体操作,如调用API、查询数据库等
- 观察(Observation):从环境中获取的反馈信息
- 记忆(Memory):存储历史信息和上下文
- 规划(Planning):制定执行步骤和策略
二、Chain of Thought(CoT)
2.1 CoT的起源与原理
Chain of Thought prompting是一种让模型分解多步骤问题为中间步骤的方法。通过chain of thought prompting,足够规模的语言模型(约100B参数)可以解决使用标准提示方法无法解决的复杂推理问题。
CoT的核心思想是引导LLM像人类一样,通过一系列逻辑步骤来解决问题,而不是直接跳到答案。这种方法在2022年由Google Brain团队首次提出,迅速成为提升LLM推理能力的标准技术。
2.2 CoT的实现方式
Zero-Shot CoT
最简单的实现方式是在提示词中加入"Let's think step by step"(让我们一步步思考):
prompt = """
问题:如果一个班级有28个学生,其中女生比男生多4人,请问男生有多少人?
让我们一步步思考:
"""
Few-Shot CoT
通过提供示例来引导模型的推理过程:
prompt = """
问题:Roger有5个网球。他又买了2罐网球,每罐有3个球。他现在有多少个网球?
思考过程:Roger开始有5个球。2罐,每罐3个球,就是2×3=6个球。5+6=11个球。
答案:11个球
问题:食堂有23个苹果。如果他们用了20个做午餐,又买了6个,他们有多少个苹果?
思考过程:[模型生成]
"""
2.3 CoT的优势与局限
优势:
- 提高复杂推理任务的准确性
- 使推理过程透明可解释
- 适用于各种推理任务(数学、常识、符号推理等)
局限:
- 对较小的模型效果不佳。研究表明,CoT只在约100B参数的模型上产生性能提升。较小的模型会写出不合逻辑的思维链,导致准确性比标准提示更差。
- 仍然依赖模型内部知识,无法获取外部实时信息
三、ReAct
3.1 ReAct框架的创新
ReAct使语言模型能够以交错的方式生成语言推理轨迹和文本动作。虽然动作会从外部环境获得观察反馈,但推理轨迹不会影响外部环境。相反,它们通过对上下文进行推理并用有用的信息更新它来影响模型的内部状态。
ReAct框架解决了CoT的一个关键限制:无法与外部世界交互。它将推理(Reasoning)和行动(Acting)结合起来,让Agent能够:
- 通过推理分解任务
- 执行动作获取新信息
- 基于观察调整策略
- 迭代直到解决问题
3.2 ReAct的工作流程
典型的ReAct循环如下:
Thought 1: 我需要搜索最新的人口数据
Action 1: Search("中国人口 2024")
Observation 1: 根据最新统计,中国人口约为14.1亿
Thought 2: 现在我需要计算两倍的值
Action 2: Calculate(14.1 * 2)
Observation 2: 28.2
Thought 3: 我现在知道答案了
Final Answer: 中国人口的两倍是28.2亿
3.3 LangChain实现ReAct Agent
基础实现
使用LangChain创建ReAct agent的基础实现非常简单:
from langchain import hub
from langchain.agents import AgentExecutor, create_react_agent
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_openai import ChatOpenAI
# 初始化LLM
llm = ChatOpenAI(model="gpt-4", temperature=0)
# 定义工具
tools = [
TavilySearchResults(max_results=3, description="搜索互联网获取最新信息")
]
# 使用预定义的ReAct提示词模板
prompt = hub.pull("hwchase17/react")
# 创建ReAct agent
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# 执行查询
result = agent_executor.invoke({
"input": "2024年诺贝尔物理学奖获得者是谁?他们的主要贡献是什么?"
})
自定义ReAct提示词
您可以自定义ReAct提示词模板来控制agent的行为:
from langchain_core.prompts import PromptTemplate
template = '''Answer the following questions as best you can.
You have access to the following tools:
{tools}
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
Begin!
Question: {input}
Thought: {agent_scratchpad}'''
prompt = PromptTemplate.from_template(template)
# 使用自定义提示词创建agent
agent = create_react_agent(llm, tools, prompt)
3.4 LangGraph实现ReAct Agent
LangGraph提供了更现代化和功能丰富的ReAct实现:
from langchain.chat_models import init_chat_model
from langchain_tavily import TavilySearch
from langgraph.checkpoint.memory import MemorySaver
from langgraph.prebuilt import create_react_agent
# 创建带有记忆功能的ReAct agent
memory = MemorySaver()
model = init_chat_model("anthropic:claude-3-5-sonnet-latest")
search = TavilySearch(max_results=2)
tools = [search]
# 创建支持多轮对话的agent
agent_executor = create_react_agent(
model,
tools,
checkpointer=memory # 启用对话记忆
)
# 使用配置管理对话线程
config = {"configurable": {"thread_id": "abc123"}}
# 第一轮对话
response1 = agent_executor.invoke(
{"messages": [{"role": "user", "content": "我叫张三,住在北京"}]},
config
)
# 第二轮对话(agent会记住之前的信息)
response2 = agent_executor.invoke(
{"messages": [{"role": "user", "content": "我住在哪里?"}]},
config
)
自定义工具函数
您可以定义自定义工具来扩展agent的能力:
from langchain_core.tools import tool
@tool
def get_weather(location: str) -> str:
"""获取指定城市的天气信息"""
# 这里可以调用真实的天气API
if"北京"in location:
return"北京今天晴天,温度23°C,空气质量良好"
returnf"无法获取{location}的天气信息"
@tool
def calculate(expression: str) -> str:
"""计算数学表达式"""
try:
result = eval(expression)
returnf"计算结果:{result}"
except:
return"计算错误,请检查表达式"
# 使用自定义工具创建agent
tools = [get_weather, calculate, search]
agent = create_react_agent(model, tools, checkpointer=memory)
3.5 ReAct的实际应用
ReAct框架受到人类如何使用自然语言进行复杂任务的逐步规划和执行的启发。ReAct agents不是实施基于规则或预定义的工作流程,而是依靠其LLM的推理能力,根据新信息或先前步骤的结果动态调整其方法。
ReAct在以下场景表现出色:
- 问答系统:结合Wikipedia API等外部知识源
- 事实验证:通过多次搜索验证信息
- 任务自动化:在复杂环境中执行多步骤任务
- 交互式决策:在游戏或模拟环境中做出决策
四、Plan-and-Execute
4.1 架构设计理念
Plan-and-Execute架构由两个基本组件组成:一个规划器(Planner),它提示LLM生成完成大型任务的多步骤计划;执行器(Executors),它们接受用户查询和计划中的一个步骤,并调用一个或多个工具来完成该任务。
这种架构的核心创新在于将规划和执行分离,带来了以下优势:
- 更快的执行速度:不需要在每个动作后都咨询大型LLM
- 成本优化:可以使用较小的模型执行具体任务
- 更好的性能:强制规划器明确思考所有步骤
4.2 Plan-and-Execute vs ReAct
特性 | ReAct | Plan-and-Execute |
规划方式 | 逐步规划 | 预先制定完整计划 |
LLM调用频率 | 每步都需要 | 主要在规划阶段 |
灵活性 | 高度灵活 | 按计划执行 |
执行速度 | 较慢 | 更快 |
成本 | 较高 | 较低 |
适用场景 | 探索性任务 | 结构化任务 |
4.3 LangGraph实现Plan-and-Execute
方式一:使用LangChain Experimental
LangChain在experimental包中提供了Plan-and-Execute的实现:
# 安装experimental包
# pip install langchain-experimental
from langchain.chains import LLMMathChain
from langchain_community.utilities import DuckDuckGoSearchAPIWrapper
from langchain_core.tools import Tool
from langchain_experimental.plan_and_execute import (
PlanAndExecute,
load_agent_executor,
load_chat_planner,
)
from langchain_openai import ChatOpenAI
# 初始化LLM
llm = ChatOpenAI(model="gpt-4", temperature=0)
# 定义工具
search = DuckDuckGoSearchAPIWrapper()
llm_math_chain = LLMMathChain.from_llm(llm=llm)
tools = [
Tool(
name="Search",
func=search.run,
description="用于搜索当前事件和信息"
),
Tool(
name="Calculator",
func=llm_math_chain.run,
description="用于数学计算"
),
]
# 创建planner和executor
planner = load_chat_planner(llm)
executor = load_agent_executor(llm, tools, verbose=True)
# 创建Plan-and-Execute agent
agent = PlanAndExecute(planner=planner, executor=executor, verbose=True)
# 使用agent
result = agent.run("研究2024年诺贝尔物理学奖获得者并计算他们的平均年龄")
方式二:使用LangGraph自定义实现
包含错误处理和动态重新规划:
from typing import Union, List, Tuple, Optional
from pydantic import BaseModel, Field
from enum import Enum
class ExecutionStatus(Enum):
"""执行状态枚举"""
SUCCESS = "success"
FAILURE = "failure"
PARTIAL = "partial"
NEEDS_RETRY = "needs_retry"
class PlanEvaluation(BaseModel):
"""计划评估结果"""
needs_replan: bool = Field(description="是否需要重新规划")
reason: Optional[str] = Field(description="需要重新规划的原因")
new_plan: Optional[List[str]] = Field(description="新的执行计划")
continue_execution: bool = Field(description="是否继续执行")
class SmartPlanExecute(TypedDict):
"""增强的状态定义"""
input: str
original_plan: List[str] # 保存原始计划
plan: List[str] # 当前待执行的计划
past_steps: List[Tuple[str, str, ExecutionStatus]] # 包含状态
response: Optional[str]
replan_count: int # 重新规划次数
max_replans: int # 最大重新规划次数
asyncdef smart_execute_step(state: SmartPlanExecute):
"""智能执行步骤,包含错误处理"""
ifnot state["plan"]:
return {}
task = state["plan"][0]
max_retries = 3
for attempt in range(max_retries):
try:
# 执行任务
result = await agent_executor.ainvoke({
"messages": [{"role": "user", "content": task}]
})
# 评估执行结果
status = await evaluate_execution_result(task, result)
# 记录执行结果
return {
"past_steps": [(task, result["messages"][-1].content, status)],
"plan": state["plan"][1:] # 移除已执行的步骤
}
except Exception as e:
if attempt < max_retries - 1:
await asyncio.sleep(2 ** attempt) # 指数退避
continue
else:
# 记录失败
return {
"past_steps": [(task, f"执行失败: {str(e)}", ExecutionStatus.FAILURE)],
"plan": state["plan"][1:]
}
asyncdef evaluate_execution_result(task: str, result: dict) -> ExecutionStatus:
"""评估任务执行结果"""
evaluation_prompt = """
评估以下任务执行结果:
任务:{task}
结果:{result}
请判断执行状态:
- SUCCESS: 完全成功
- PARTIAL: 部分成功,可能需要补充
- FAILURE: 执行失败
- NEEDS_RETRY: 需要重试
只返回状态值。
"""
response = await llm.ainvoke(
evaluation_prompt.format(
task=task,
result=result["messages"][-1].content
)
)
# 解析状态
status_text = response.content.strip().upper()
for status in ExecutionStatus:
if status.value.upper() in status_text or status.name in status_text:
return status
return ExecutionStatus.SUCCESS # 默认为成功
asyncdef intelligent_replan_step(state: SmartPlanExecute):
"""智能重新规划,考虑多种因素"""
# 检查是否超过最大重新规划次数
if state["replan_count"] >= state.get("max_replans", 3):
return {
"response": "达到最大重新规划次数,使用当前结果生成报告。\n" +
await generate_best_effort_report(state)
}
# 分析执行历史
analysis = await analyze_execution_history(state)
if analysis.needs_replan:
# 生成新计划
new_plan = await generate_adaptive_plan(
state["input"],
state["past_steps"],
state["plan"],
analysis.reason
)
return {
"plan": new_plan,
"replan_count": state["replan_count"] + 1
}
elif len(state["plan"]) == 0:
# 所有步骤完成,生成最终报告
return {"response": await generate_intelligent_report(state)}
else:
# 继续执行
return {}
asyncdef analyze_execution_history(state: SmartPlanExecute) -> PlanEvaluation:
"""深度分析执行历史"""
# 统计执行状态
status_counts = {}
for _, _, status in state["past_steps"]:
status_counts[status] = status_counts.get(status, 0) + 1
# 获取最近的执行结果
recent_failures = [
(task, result) for task, result, status in state["past_steps"][-3:]
if status in [ExecutionStatus.FAILURE, ExecutionStatus.NEEDS_RETRY]
]
# 构建分析提示
analysis_prompt = """
分析任务执行情况并决定是否需要重新规划:
原始目标:{input}
执行统计:{status_counts}
最近失败:{recent_failures}
剩余任务:{remaining_tasks}
考虑因素:
1. 失败率是否过高?
2. 是否发现了原计划未考虑的情况?
3. 剩余任务是否仍然适用?
4. 是否需要新的方法或工具?
返回JSON格式:
{{
"needs_replan": true/false,
"reason": "重新规划的原因",
"suggestions": ["建议1", "建议2"]
}}
"""
response = await llm.ainvoke(
analysis_prompt.format(
input=state["input"],
status_counts=status_counts,
recent_failures=recent_failures,
remaining_tasks=state["plan"]
)
)
# 解析响应
import json
try:
analysis_data = json.loads(response.content)
return PlanEvaluation(
needs_replan=analysis_data.get("needs_replan", False),
reason=analysis_data.get("reason"),
continue_execution=not analysis_data.get("needs_replan", False)
)
except:
# 如果解析失败,默认继续执行
return PlanEvaluation(
needs_replan=False,
continue_execution=True
)
asyncdef generate_adaptive_plan(
original_goal: str,
past_steps: List[Tuple],
remaining_tasks: List[str],
replan_reason: str
) -> List[str]:
"""生成自适应的新计划"""
adaptive_prompt = """
基于执行历史生成新的计划:
原始目标:{goal}
已执行步骤:{past}
原剩余任务:{remaining}
重新规划原因:{reason}
请生成新的执行计划,要求:
1. 避免重复已成功的步骤
2. 解决发现的问题
3. 使用替代方法处理失败的任务
4. 保持计划简洁高效
每行一个步骤:
"""
response = await llm.ainvoke(
adaptive_prompt.format(
goal=original_goal,
past=past_steps,
remaining=remaining_tasks,
reason=replan_reason
)
)
return parse_new_plan(response.content)
# 构建增强的工作流
def build_smart_plan_execute_workflow():
workflow = StateGraph(SmartPlanExecute)
# 添加节点
workflow.add_node("planner", initial_plan_step)
workflow.add_node("executor", smart_execute_step)
workflow.add_node("analyzer", intelligent_replan_step)
# 设置流程
workflow.set_entry_point("planner")
workflow.add_edge("planner", "executor")
workflow.add_edge("executor", "analyzer")
# 条件边:根据分析结果决定下一步
def route_after_analysis(state: SmartPlanExecute):
if"response"in state and state["response"]:
return"end"
elif state["plan"]:
return"executor"
else:
return"end"
workflow.add_conditional_edges(
"analyzer",
route_after_analysis,
{
"executor": "executor",
"end": END
}
)
return workflow.compile()
# 使用示例
smart_agent = build_smart_plan_execute_workflow()
result = await smart_agent.ainvoke({
"input": "分析竞争对手的产品策略并提出改进建议",
"replan_count": 0,
"max_replans": 3
})
五、框架实战最佳实践
5.1 混合使用策略
在实际项目中,可以根据不同阶段使用不同框架:
class HybridAgent:
def __init__(self):
self.cot_llm = ChatOpenAI(model="gpt-3.5-turbo")
self.react_agent = create_react_agent(...)
self.plan_execute_agent = create_plan_and_execute_agent(...)
def analyze_complexity(self, query: str) -> ComplexityAnalysis:
"""
分析查询的复杂度,考虑以下因素:
- 任务是否需要多步骤推理
- 是否需要外部信息
- 任务的结构化程度
- 是否有明确的执行路径
"""
pass
def process(self, query):
complexity = self.analyze_complexity(query)
if complexity == "simple":
# 简单问题直接用CoT
return self.cot_llm.invoke(f"{query}\n让我们一步步思考:")
elif complexity == "exploratory":
# 探索性问题用ReAct
return self.react_agent.invoke({"input": query})
else:
# 复杂结构化任务用Plan-and-Execute
return self.plan_execute_agent.invoke({"input": query})
5.2 性能优化技巧
- 缓存策略
from langchain.cache import InMemoryCache
import langchain
# 启用缓存减少重复调用
langchain.llm_cache = InMemoryCache()
- 异步处理
import asyncio
async def parallel_agent_execution(queries):
agents = [create_react_agent(llm, tools) for _ in queries]
tasks = [agent.ainvoke({"input": q}) for agent, q in zip(agents, queries)]
return await asyncio.gather(*tasks)
- 模型选择策略
def select_model(task_type):
model_map = {
"reasoning": "gpt-4", # 复杂推理用大模型
"extraction": "gpt-3.5-turbo", # 信息提取用快速模型
"classification": "gpt-3.5-turbo", # 分类任务用快速模型
"creative": "claude-3-opus" # 创意任务用Claude
}
return model_map.get(task_type, "gpt-3.5-turbo")
5.3 错误处理和回退机制
from tenacity import retry, stop_after_attempt, wait_exponential
class RobustAgent:
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
asyncdef execute_with_retry(self, task):
try:
result = await self.agent.ainvoke(task)
return result
except Exception as e:
# 记录错误
logger.error(f"Agent execution failed: {e}")
# 回退到更简单的方法
if hasattr(self, 'fallback_agent'):
returnawait self.fallback_agent.ainvoke(task)
raise
六、最佳实践与选择指南
6.1 框架选择决策树
任务类型判断:
├── 纯推理任务(不需要外部信息)
│ └── 使用 CoT
├── 需要实时信息或工具调用
│ ├── 探索性/动态任务
│ │ └── 使用 ReAct
│ └── 结构化/可预测任务
│ └── 使用 Plan-and-Execute
6.2 性能优化建议
- 模型选择:
- CoT需要大模型(>100B参数)才能发挥效果
- ReAct和Plan-and-Execute可以混合使用大小模型
- 成本控制:
- 对于高频任务,优先考虑Plan-and-Execute
- 使用缓存机制减少重复调用
- 错误处理:
- 实现重试机制和fallback策略
- 在ReAct中加入自我反思机制
6.3 实施建议
从简单开始:先用CoT验证基本推理能力
# 开始时使用简单的Zero-Shot CoT
prompt = "问题:{question}\n让我们一步步思考:"
逐步升级:根据需求添加工具调用(ReAct)
# 添加基础工具
tools = [search_tool]
agent = create_react_agent(llm, tools)
优化迭代:对于成熟流程,迁移到Plan-and-Execute
# 当流程稳定后,使用Plan-and-Execute提升效率
planner_agent = create_plan_and_execute_agent(
planner_llm=expensive_model, # 只在规划时使用大模型
executor_llm=cheap_model, # 执行时使用小模型
tools=tools
)
监控评估:持续监控性能和成本指标
# 使用LangSmith进行追踪
from langsmith import Client
client = Client()
# 启用追踪来监控agent性能
6.4 框架选择快速参考
场景 | 推荐框架 | 代码示例 |
简单问答 | CoT | |
实时信息查询 | ReAct | |
复杂报告生成 | Plan-and-Execute | |
并行任务处理 | LLMCompiler | |
多轮对话 | ReAct + Memory | |
总结
作为开发者和技术决策者,深入理解这些框架不仅能帮助我们构建更好的AI系统。无论是选择简单直接的CoT,还是构建复杂的多Agent系统,关键在于理解业务需求,选择合适的工具,并持续优化迭代。
最近一些读者想加
langchain&langgraph
的群,打算等对这部分感兴趣的朋友达到一定数量再拉群,想加这个群的朋友可以关注之后加我备注 langgraph 即可
参考资料:
- LangChain ReAct Agent Documentation[1]
- LangGraph Plan-and-Execute Tutorial[2]
- LangGraph Prebuilt Agents[3]
- LangChain Hub - Prompt Templates[4]
- LangSmith - Monitoring and Debugging[5]
参考资料
[1] LangChain ReAct Agent Documentation: https://python.langchain.com/docs/modules/agents/agent_types/react/
[2] LangGraph Plan-and-Execute Tutorial: https://langchain-ai.github.io/langgraph/tutorials/plan-and-execute/
[3] LangGraph Prebuilt Agents: https://langchain-ai.github.io/langgraph/reference/prebuilt/
[4] LangChain Hub - Prompt Templates: https://smith.langchain.com/hub
[5] LangSmith - Monitoring and Debugging: https://docs.smith.langchain.com/
本文转载自AI 博物院 作者:longyunfeigu
