Agents 与 Memory

面试官:「Agent 和 Chain 的区别是什么?」

你:「Chain 是预设好的执行流程,Agent 是让 LLM 自己决定下一步做什么...」

面试官:「那 Tool Calling 呢?」

你:「就是给 Agent 调用外部工具的能力,比如搜索、计算、API...」

面试官:「对话多了上下文会爆炸,怎么处理?」

🤔 Memory 就是答案!这一章让你彻底搞懂 Agent 的决策逻辑和记忆机制。

3.1 什么是 Agent

Agent(代理)是 LangChain 中让模型能够自主决策调用工具的核心组件。与普通的 Chain 不同,Agent 可以根据输入动态决定下一步操作。

🤖 一句话理解:Agent = 模型(大脑)+ 工具(手脚)+ 循环(思考→行动→观察)

🔄 Chain vs Agent

特性 Chain Agent
执行方式 固定顺序 动态决策
下一步 预先定义 模型决定
工具调用 不支持 支持
循环 单次执行 多轮循环
适用场景 固定流程 复杂任务
图 3-1:Agent 核心架构
🤖 LLM 模型 决策中心 · 思考引擎 ReAct 循环 🧠 Think 思考下一步行动 ⚡ Action 执行工具 👁️ Observe 观察结果 循环直到完成任务 可用工具: 🔍 搜索 🧮 计算 🌐 API 📄 文件 ...

3.1.1 Agent 的工作流程

Agent 通过一个循环来处理任务:

  1. 接收输入:获取用户的请求
  2. 思考(Think):模型分析当前情况,决定是否需要调用工具
  3. 行动(Action):调用选定的工具
  4. 观察(Observe):获取工具返回的结果
  5. 判断:如果任务完成,返回结果;否则继续循环

3.2 ReAct 思考模式

ReAct(Reasoning + Acting)是一种让模型同时进行推理行动的方法。它结合了链式思考(Chain-of-Thought)的推理能力和工具调用的行动能力。

图 3-2:ReAct 执行流程详解
用户:北京今天天气怎么样? 🤔 Thought 1: 我需要先搜索北京的天气 🔧 Action 1: search_weather(北京) 👁️ Observation: 北京今天晴,温度15-25°C,空气质量良好 🤔 Thought 2: 我已获取天气信息,现在可以回答用户了 ✅ Final Answer: 北京今天天气晴朗,气温15-25°C,适合出行。 循环 直到 完成
💡 ReAct 的优势

相比纯推理(Chain-of-Thought),ReAct 的优势在于:模型可以与外部世界交互,获取实时信息;相比纯行动(Action-only),ReAct 的优势在于:模型有明确的思考过程,决策更透明、更可解释。

3.3 Agent 类型详解

LangChain 提供了多种预置的 Agent 类型,适用于不同的场景。

Agent 类型 特点 适用场景
OpenAI Functions 使用 OpenAI 的 function calling 功能 OpenAI 模型首选
ReAct 标准的 ReAct 循环 通用场景
Self-Ask 包含自我追问 复杂推理
Conversational 对话式,带记忆 聊天机器人

3.3.1 使用 OpenAI Functions Agent

python openai_functions_agent.py
from langchain_openai import ChatOpenAI
from langchain.agents import create_openai_functions_agent
from langchain.tools.render import format_tool_to_openai_function
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder

# 初始化模型
llm = ChatOpenAI(model="gpt-4o", temperature=0)

# 定义工具
from langchain_community.tools import WikipediaQueryRun, DuckDuckGoSearchRun

search = DuckDuckGoSearchRun()
wikipedia = WikipediaQueryRun()

tools = [search, wikipedia]

# 创建 Agent
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个有帮助的助手,擅长搜索信息并回答问题。"),
    MessagesPlaceholder("chat_history", optional=True),
    ("human", "{input}"),
    MessagesPlaceholder("agent_scratchpad"),  # Agent 的中间思考过程
])

agent = create_openai_functions_agent(llm, tools, prompt)

# 运行 Agent
from langchain.agents import AgentExecutor

agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

result = agent_executor.invoke({"input": "特斯拉的 CEO 是谁?"})
print(result["output"])

3.3.2 使用 ReAct Agent

python react_agent.py
from langchain_openai import ChatOpenAI
from langchain.agents import create_react_agent
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder

# 初始化模型
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

# 创建 ReAct Agent
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个有帮助的助手。"),
    ("human", "{input}"),
    MessagesPlaceholder("agent_scratchpad"),
])

# 工具列表
tools = [search, wikipedia]  # 复用上面的工具

agent = create_react_agent(llm, tools, prompt)

agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    verbose=True,  # 打印思考过程
    max_iterations=5  # 最大迭代次数
)

result = agent_executor.invoke({"input": "LangChain 是什么时候发布的?"})
print(result["output"])

3.4 Tools 工具系统

Tools(工具)是 Agent 与外部世界交互的桥梁。通过工具,Agent 可以搜索网络、执行计算、读写文件、调用 API 等。

3.4.1 内置工具

LangChain 内置了大量常用工具:

工具 功能 安装
DuckDuckGoSearch 网络搜索 langchain-community
Wikipedia 维基百科查询 wikipedia
WolframAlpha 计算引擎 wolframalpha
Python REPL 执行 Python 代码 内置
SerpAPI Google 搜索 google-search-results

3.4.2 自定义工具

你可以创建自己的工具:

python custom_tool.py
from langchain_core.tools import tool
from datetime import datetime

# 方式一:使用 @tool 装饰器
@tool
def get_current_time() -> str:
    """获取当前的日期和时间"""
    return datetime.now().strftime("%Y年%m月%d日 %H:%M:%S")

@tool
def calculate(expression: str) -> str:
    """执行数学计算

    Args:
        expression: 数学表达式,如 "2 + 2" 或 "sqrt(16)"
    """
    try:
        import math
        # 安全评估简单表达式
        result = eval(expression, {"__builtins__": {}, "sqrt": math.sqrt, "pi": math.pi}, {})
        return str(result)
    except Exception as e:
        return f"计算错误:{str(e)}"

# 使用
print(get_current_time.invoke({}))
# 2026年04月21日 09:20:30

print(calculate.invoke({"expression": "2 + 2 * 3"}))
# 8

3.4.3 工具的完整示例

图 3-3:自定义工具在 Agent 中的使用
① 定义工具 @tool + docstring ② 绑定 Agent tools=[...] 注入 ③ 用户提问 触发 Agent 执行 Agent 核心循环(ReAct) 🤔 思考 🔧 调用工具 👁️ 观察 不够?继续循环 ✅ 信息足够 → 生成回复 Agent 返回最终答案给用户 够了
python complete_agent.py
from langchain_openai import ChatOpenAI
from langchain.agents import create_openai_functions_agent, AgentExecutor
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder

llm = ChatOpenAI(model="gpt-4o", temperature=0)

# 定义自定义工具
@tool
def get_weather(city: str) -> str:
    """获取指定城市的天气信息

    Args:
        city: 城市名称,如"北京"、"上海"
    """
    # 实际应用中这里会调用天气 API
    weather_data = {
        "北京": "晴,15-25°C",
        "上海": "多云,18-28°C",
        "广州": "雨,22-30°C",
    }
    return weather_data.get(city, "未知城市")

@tool
def get_time() -> str:
    """获取当前时间"""
    from datetime import datetime
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

# 创建 Agent
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个天气助手,可以查询城市天气和时间。"),
    MessagesPlaceholder("chat_history", optional=True),
    ("human", "{input}"),
    MessagesPlaceholder("agent_scratchpad"),
])

tools = [get_weather, get_time]
agent = create_openai_functions_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# 测试
result = agent_executor.invoke({
    "input": "北京今天天气怎么样?现在几点了?"
})
print(result["output"])

3.5 Memory 记忆系统

Memory(记忆)让 Agent 能够记住之前的对话内容和中间结果。这是构建多轮对话应用的基础。

3.5.1 Memory 的类型

类型 描述 适用场景
BufferMemory 保存所有对话历史 简单场景
SummaryMemory 总结对话内容 长对话
EntityMemory 提取实体信息 用户画像
ConversationBufferWindowMemory 只保留最近 N 轮 限制上下文长度

3.5.2 使用 BufferMemory

python buffer_memory.py
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.agents import create_openai_functions_agent, AgentExecutor
from langchain_core.chat_history import InMemoryChatMessageHistory

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

# 创建带记忆的 Agent
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个乐于助人的助手。"),
    MessagesPlaceholder("chat_history", optional=True),
    ("human", "{input}"),
    MessagesPlaceholder("agent_scratchpad"),
])

agent = create_openai_functions_agent(llm, tools=[], prompt=prompt)

# 创建记忆管理
chat_history = InMemoryChatMessageHistory()

agent_executor = AgentExecutor(agent=agent, tools=[], memory=chat_history)

# 多轮对话
response1 = agent_executor.invoke({"input": "我叫张三"})
print(response1["output"])  # 很高兴认识你,张三!

response2 = agent_executor.invoke({"input": "我叫什么名字?"})
print(response2["output"])  # 你叫张三!

# 查看记忆内容
print(chat_history.messages)
# [HumanMessage(content='我叫张三'), AIMessage(content='很高兴认识你,张三!'),
#  HumanMessage(content='我叫什么名字?'), AIMessage(content='你叫张三!')]

3.5.3 对话摘要记忆

对于很长的对话,我们可以使用摘要记忆来压缩历史:

python summary_memory.py
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain.memory.summary import GeneratedSummary

# 创建摘要记忆
summary_memory = GeneratedSummary(
    chat_memory=InMemoryChatMessageHistory(),
    llm=llm,  # 用于生成摘要的模型
)

# 或者使用内置的 ConversationSummaryMemory
from langchain.memory import ConversationSummaryMemory

memory = ConversationSummaryMemory(llm=llm, return_messages=True)

# 添加对话
memory.save_context({"input": "我叫李四"}, {"output": "你好李四!"})
memory.save_context({"input": "我喜欢编程"}, {"output": "编程是一项很棒的技能!"})

# 获取记忆
print(memory.load_memory_variables({})["history"])
# "用户叫李四,喜欢编程。助手已友好地回应。"
图 3-4:对话记忆流程
原始对话历史 Human: 我叫张三 AI: 你好张三! Human: 从事什么工作? AI: 我是AI助手... 200+ tokens 压缩 摘要记忆 用户张三在询问AI的工作 性质,助手进行了自我介绍。 Token: 30 (vs 原始: 200+) ✅ 使用摘要进行下一轮对话 System: 你是乐于助人的助手。已知信息:用户叫张三... Human: 你还记得我叫什么吗? → AI: 你叫张三!

3.6 对话历史管理

3.6.1 RunnableWithMessageHistory

使用 RunnableWithMessageHistory 可以轻松实现多会话管理:

python multi_session.py
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_core.chat_history import InMemoryChatMessageHistory

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个乐于助人的助手。"),
    MessagesPlaceholder("history"),
    ("human", "{message}"),
])

chain = prompt | llm

# 创建带对话历史的链
chat_history_store = {}  # 存储不同会话的历史

def get_history(session_id: str):
    """获取或创建指定会话的历史"""
    if session_id not in chat_history_store:
        chat_history_store[session_id] = InMemoryChatMessageHistory()
    return chat_history_store[session_id]

chain_with_history = RunnableWithMessageHistory(
    chain,
    get_history,
    input_messages_key="message",
    history_messages_key="history",
)

# 用户 1 的对话
print(chain_with_history.invoke(
    {"message": "我叫王五"},
    config={"configurable": {"session_id": "user_001"}}
).content)
# 很高兴认识你,王五!

# 用户 2 的对话(独立会话)
print(chain_with_history.invoke(
    {"message": "我叫赵六"},
    config={"configurable": {"session_id": "user_002"}}
).content)
# 你好赵六!

# 用户 1 继续对话
print(chain_with_history.invoke(
    {"message": "我叫什么名字?"},
    config={"configurable": {"session_id": "user_001"}}
).content)
# 你叫王五!

3.6.2 滑动窗口记忆

只保留最近 N 轮对话,避免超出模型的上下文限制:

python sliding_window.py
from langchain.memory import ConversationBufferWindowMemory
from langchain.agents import create_openai_functions_agent

# 只保留最近 3 轮对话
window_size = 3

memory = ConversationBufferWindowMemory(
    k=window_size,
    return_messages=True,
    llm=llm,
)

# 每次对话后更新记忆
memory.save_context({"input": "第1轮问题"}, {"output": "第1轮回答"})
memory.save_context({"input": "第2轮问题"}, {"output": "第2轮回答"})
memory.save_context({"input": "第3轮问题"}, {"output": "第3轮回答"})
memory.save_context({"input": "第4轮问题"}, {"output": "第4轮回答"})

# 查看记忆 - 只有最近的3轮
print(memory.load_memory_variables({})["history"])
# 第2轮、第3轮、第4轮的对话(不包含第1轮)

3.7 本章小结

📝 关键概念回顾

概念 说明
Agent 让模型自主决策并调用工具
ReAct 推理 + 行动的思考循环
Tools Agent 与外部世界交互的桥梁
Memory 管理对话历史和上下文
RunnableWithMessageHistory 多会话管理
  • Agent:相比 Chain,可以动态决定下一步操作,支持工具调用
  • ReAct:Think → Action → Observe 的循环,让模型既会思考又会行动
  • Tools:使用 @tool 装饰器创建自定义工具
  • Memory:BufferMemory、SummaryMemory、EntityMemory 等多种类型
  • 对话历史:使用 RunnableWithMessageHistory 管理多会话
🚀 接下来学什么?

在下一章中,我们将学习 模型 I/O 与 Tools,深入了解如何与不同类型的模型交互,以及如何构建更复杂的工具系统。