主题
概述
构建智能体(或任何 LLM 应用程序)的难点在于使其足够可靠。虽然它们可能在原型阶段有效,但在实际使用案例中常常失败。
智能体为何失败?
当智能体失败时,通常是因为智能体内部的 LLM 调用采取了错误的行动/没有达到我们的预期。LLM 失败的原因通常有以下两种:
- 底层 LLM 能力不足
- 没有将“正确的”上下文传递给 LLM
大多数情况下,实际上是第二个原因导致智能体不可靠。
上下文工程 是指以正确的格式提供正确的信息和工具,以便 LLM 能够完成任务。这是 AI 工程师的首要工作。缺乏“正确的”上下文是构建更可靠智能体的首要障碍,而 LangChain 的智能体抽象设计独特,旨在促进上下文工程。
不熟悉上下文工程?请从 概念概述 开始,了解不同类型的上下文及其使用时机。
智能体循环
典型的智能体循环包含两个主要步骤:
- 模型调用 - 使用提示词和可用工具调用 LLM,返回响应或执行工具的请求
- 工具执行 - 执行 LLM 请求的工具,返回工具结果

此循环持续进行,直到 LLM 决定结束。
您可以控制的内容
为了构建可靠的智能体,您需要控制智能体循环每个步骤中发生的事情,以及步骤之间发生的事情。
| 上下文类型 | 您控制的内容 | 瞬态或持久 |
|---|---|---|
| 模型上下文 | 模型调用的输入内容(指令、消息历史、工具、响应格式) | 瞬态 |
| 工具上下文 | 工具可以访问和产生的内容(对状态、存储、运行时上下文的读写) | 持久 |
| 生命周期上下文 | 模型调用和工具调用之间发生的事情(摘要、护栏、日志记录等) | 持久 |
数据源
在整个过程中,您的智能体会访问(读取/写入)不同的数据源:
| 数据源 | 亦称 | 作用域 | 示例 |
|---|---|---|---|
| 运行时上下文 | 静态配置 | 会话作用域 | 用户 ID、API 密钥、数据库连接、权限、环境设置 |
| 状态 | 短期记忆 | 会话作用域 | 当前消息、上传的文件、认证状态、工具结果 |
| 存储 | 长期记忆 | 跨会话 | 用户偏好、提取的见解、记忆、历史数据 |
工作原理
LangChain 的 中间件 是底层机制,使得使用 LangChain 的开发者能够实际进行上下文工程。
中间件允许您钩入智能体生命周期的任何步骤,并:
- 更新上下文
- 跳转到智能体生命周期中的不同步骤
在本指南中,您将频繁看到使用中间件 API 作为实现上下文工程目标的手段。
模型上下文
控制每次模型调用的输入内容——指令、可用工具、使用哪个模型以及输出格式。这些决策直接影响可靠性和成本。
所有这些类型的模型上下文都可以从 状态(短期记忆)、存储(长期记忆)或 运行时上下文(静态配置)中获取。
系统提示词
系统提示词设定了 LLM 的行为和能力。不同的用户、上下文或对话阶段需要不同的指令。成功的智能体会利用记忆、偏好和配置,为对话的当前状态提供正确的指令。
状态
存储
运行时上下文
从状态访问消息计数或对话上下文:
python
from langchain.agents import create_agent
from langchain.agents.middleware import dynamic_prompt, ModelRequest
@dynamic_prompt
def state_aware_prompt(request: ModelRequest) -> str:
# request.messages is a shortcut for request.state["messages"]
message_count = len(request.messages)
base = "You are a helpful assistant."
if message_count > 10:
base += "\nThis is a long conversation - be extra concise."
return base
agent = create_agent(
model="gpt-4o",
tools=[...],
middleware=[state_aware_prompt]
)消息
消息构成了发送给 LLM 的提示词。 管理消息内容至关重要,以确保 LLM 拥有正确的信息来做出良好响应。
状态
存储
运行时上下文
当与当前查询相关时,从状态注入上传的文件上下文:
python
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from typing import Callable
@wrap_model_call
def inject_file_context(
request: ModelRequest,
handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
"""Inject context about files user has uploaded this session."""
# Read from State: get uploaded files metadata
uploaded_files = request.state.get("uploaded_files", [])
if uploaded_files:
# Build context about available files
file_descriptions = []
for file in uploaded_files:
file_descriptions.append(
f"- {file['name']} ({file['type']}): {file['summary']}"
)
file_context = f"""Files you have access to in this conversation:
{chr(10).join(file_descriptions)}
Reference these files when answering questions."""
# Inject file context before recent messages
messages = [
*request.messages,
{"role": "user", "content": file_context},
]
request = request.override(messages=messages)
return handler(request)
agent = create_agent(
model="gpt-4o",
tools=[...],
middleware=[inject_file_context]
)工具
工具让模型能够与数据库、API 和外部系统交互。您定义和选择工具的方式直接影响模型是否能有效完成任务。
定义工具
每个工具都需要清晰的名称、描述、参数名称和参数描述。这些不仅仅是元数据——它们指导模型关于何时以及如何使用该工具的推理。
python
from langchain.tools import tool
@tool(parse_docstring=True)
def search_orders(
user_id: str,
status: str,
limit: int = 10
) -> str:
"""Search for user orders by status.
Use this when the user asks about order history or wants to check
order status. Always filter by the provided status.
Args:
user_id: Unique identifier for the user
status: Order status: 'pending', 'shipped', or 'delivered'
limit: Maximum number of results to return
"""
# Implementation here
pass选择工具
并非每个工具都适用于所有情况。工具过多可能会使模型不堪重负(上下文过载)并增加错误;工具过少则会限制能力。动态工具选择基于认证状态、用户权限、功能标志或对话阶段来调整可用工具集。
状态
存储
运行时上下文
仅在达到特定对话里程碑后启用高级工具:
python
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from typing import Callable
@wrap_model_call
def state_based_tools(
request: ModelRequest,
handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
"""Filter tools based on conversation State."""
# Read from State: check if user has authenticated
state = request.state
is_authenticated = state.get("authenticated", False)
message_count = len(state["messages"])
# Only enable sensitive tools after authentication
if not is_authenticated:
tools = [t for t in request.tools if t.name.startswith("public_")]
request = request.override(tools=tools)
elif message_count < 5:
# Limit tools early in conversation
tools = [t for t in request.tools if t.name != "advanced_search"]
request = request.override(tools=tools)
return handler(request)
agent = create_agent(
model="gpt-4o",
tools=[public_search, private_search, advanced_search],
middleware=[state_based_tools]
)更多示例请参见 动态选择工具。
模型
不同的模型有不同的优势、成本和上下文窗口。为当前任务选择合适的模型,这在智能体运行期间可能会发生变化。
状态
存储
运行时上下文
根据状态中的对话长度使用不同的模型:
python
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from langchain.chat_models import init_chat_model
from typing import Callable
# Initialize models once outside the middleware
large_model = init_chat_model("claude-sonnet-4-5-20250929")
standard_model = init_chat_model("gpt-4o")
efficient_model = init_chat_model("gpt-4o-mini")
@wrap_model_call
def state_based_model(
request: ModelRequest,
handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
"""Select model based on State conversation length."""
# request.messages is a shortcut for request.state["messages"]
message_count = len(request.messages)
if message_count > 20:
# Long conversation - use model with larger context window
model = large_model
elif message_count > 10:
# Medium conversation
model = standard_model
else:
# Short conversation - use efficient model
model = efficient_model
request = request.override(model=model)
return handler(request)
agent = create_agent(
model="gpt-4o-mini",
tools=[...],
middleware=[state_based_model]
)更多示例请参见 动态模型。
响应格式
结构化输出将非结构化文本转换为经过验证的结构化数据。当提取特定字段或为下游系统返回数据时,自由格式的文本是不够的。
工作原理: 当您提供一个模式作为响应格式时,模型的最终响应保证符合该模式。智能体运行模型/工具调用循环,直到模型完成工具调用,然后将最终响应强制转换为提供的格式。
定义格式
模式定义指导模型。字段名称、类型和描述精确指定了输出应遵循的格式。
python
from pydantic import BaseModel, Field
class CustomerSupportTicket(BaseModel):
"""Structured ticket information extracted from customer message."""
category: str = Field(
description="Issue category: 'billing', 'technical', 'account', or 'product'"
)
priority: str = Field(
description="Urgency level: 'low', 'medium', 'high', or 'critical'"
)
summary: str = Field(
description="One-sentence summary of the customer's issue"
)
customer_sentiment: str = Field(
description="Customer's emotional tone: 'frustrated', 'neutral', or 'satisfied'"
)选择格式
动态响应格式选择根据用户偏好、对话阶段或角色调整模式——早期返回简单格式,随着复杂性增加返回详细格式。
状态
存储
运行时上下文
根据对话状态配置结构化输出:
python
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from pydantic import BaseModel, Field
from typing import Callable
class SimpleResponse(BaseModel):
"""Simple response for early conversation."""
answer: str = Field(description="A brief answer")
class DetailedResponse(BaseModel):
"""Detailed response for established conversation."""
answer: str = Field(description="A detailed answer")
reasoning: str = Field(description="Explanation of reasoning")
confidence: float = Field(description="Confidence score 0-1")
@wrap_model_call
def state_based_output(
request: ModelRequest,
handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
"""Select output format based on State."""
# request.messages is a shortcut for request.state["messages"]
message_count = len(request.messages)
if message_count < 3:
# Early conversation - use simple format
request = request.override(response_format=SimpleResponse)
else:
# Established conversation - use detailed format
request = request.override(response_format=DetailedResponse)
return handler(request)
agent = create_agent(
model="gpt-4o",
tools=[...],
middleware=[state_based_output]
)工具上下文
工具的特殊之处在于它们既读取也写入上下文。
在最基本的情况下,当工具执行时,它接收 LLM 的请求参数并返回一个工具消息。工具完成其工作并产生结果。
工具还可以为模型获取重要信息,使其能够执行和完成任务。
读取
大多数现实世界的工具需要的不仅仅是 LLM 的参数。它们需要用户 ID 进行数据库查询、API 密钥访问外部服务,或者当前会话状态来做决策。工具从状态、存储和运行时上下文中读取以访问这些信息。
状态
存储
运行时上下文
从状态读取以检查当前会话信息:
python
from langchain.tools import tool, ToolRuntime
from langchain.agents import create_agent
@tool
def check_authentication(
runtime: ToolRuntime
) -> str:
"""Check if user is authenticated."""
# Read from State: check current auth status
current_state = runtime.state
is_authenticated = current_state.get("authenticated", False)
if is_authenticated:
return "User is authenticated"
else:
return "User is not authenticated"
agent = create_agent(
model="gpt-4o",
tools=[check_authentication]
)写入
工具结果可用于帮助智能体完成给定任务。工具既可以直接将结果返回给模型,也可以更新智能体的记忆,使重要的上下文在后续步骤中可用。
状态
存储
使用 Command 写入状态以跟踪会话特定信息:
python
from langchain.tools import tool, ToolRuntime
from langchain.agents import create_agent
from langgraph.types import Command
@tool
def authenticate_user(
password: str,
runtime: ToolRuntime
) -> Command:
"""Authenticate user and update State."""
# Perform authentication (simplified)
if password == "correct":
# Write to State: mark as authenticated using Command
return Command(
update={"authenticated": True},
)
else:
return Command(update={"authenticated": False})
agent = create_agent(
model="gpt-4o",
tools=[authenticate_user]
)有关在工具中访问状态、存储和运行时上下文的全面示例,请参见 工具。
生命周期上下文
控制 核心智能体步骤之间 发生的事情——拦截数据流以实现横切关注点,如摘要、护栏和日志记录。
正如您在 模型上下文 和 工具上下文 中所见,中间件 是使上下文工程变得可行的机制。中间件允许您钩入智能体生命周期的任何步骤,并:
- 更新上下文 - 修改状态和存储以持久化更改、更新对话历史或保存见解
- 在生命周期中跳转 - 根据上下文移动到智能体循环中的不同步骤(例如,如果满足条件则跳过工具执行,使用修改后的上下文重复模型调用)

示例:摘要
最常见的生命周期模式之一是在对话历史过长时自动压缩。与 模型上下文 中展示的瞬态消息修剪不同,摘要 持久地更新状态——永久地用摘要替换旧消息,该摘要将保存供未来所有轮次使用。
LangChain 为此提供了内置中间件:
python
from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
agent = create_agent(
model="gpt-4o",
tools=[...],
middleware=[
SummarizationMiddleware(
model="gpt-4o-mini",
trigger={"tokens": 4000},
keep={"messages": 20},
),
],
)当对话超过令牌限制时,SummarizationMiddleware 会自动:
- 使用单独的 LLM 调用总结较早的消息
- 在状态中用摘要消息替换它们(永久地)
- 保留最近的消息以保持上下文
摘要后的对话历史被永久更新——未来的轮次将看到摘要而不是原始消息。
有关内置中间件的完整列表、可用钩子以及如何创建自定义中间件,请参阅 中间件文档。
最佳实践
- 从简单开始 - 先使用静态提示词和工具,仅在必要时添加动态元素
- 逐步测试 - 每次只添加一个上下文工程功能
- 监控性能 - 跟踪模型调用、令牌使用情况和延迟
- 使用内置中间件 - 利用
SummarizationMiddleware、LLMToolSelectorMiddleware等 - 记录上下文策略 - 明确说明传递了哪些上下文及其原因
- 理解临时性与持久性:模型上下文更改是临时的(每次调用),而生命周期上下文更改会持久保存到状态中