☰
第七章、LangChain-上下文工程(Context Engineering)
2026/11/3 10:38:12 网站建设 项目流程

一、概述

构建代理(或任何大型语言模型应用)最难的是让它们足够可靠。
虽然它们可能适合原型,但在实际应用中常常失败。

为什么代理会失败?

代理失败通常是因为代理内部的 LLM 调用做错了操作,或者没有按预期执行。LLM 失败的原因有两个:

  1. 底层的 LLM 能力不足
  2. "正确"的上下文没有传递给 LLM

大多数情况下——实际上是第二个原因导致代理不可靠。

什么是上下文工程

上下文工程是以合适的格式提供正确的信息和工具,使 LLM 能够完成任务。

  • 这是人工智能工程师的首要任务
  • 缺乏"正确"上下文是更可靠代理的头号障碍
  • LangChain 的代理抽象设计独特地促进了上下文工程

刚接触上下文工程?先从「概念概述」理解不同类型的语境以及何时使用它们。


二、智能体循环(Agent Loop)

典型的代理环路主要包括两个步骤:

  1. 模型调用—— 调用 LLM 并提供提示词和可用工具,返回响应或执行工具的请求
  2. 工具执行—— 执行 LLM 请求的工具,返回工具结果
┌──────────────────────────────────────┐ │ │ ▼ │ ┌─────────┐ 工具调用请求 ┌──────────────┴───┐ │ Model ├─────────────────►│ Tool Execution │ │ Call │◄─────────────────┤ (工具执行) │ └────┬────┘ 工具结果 └──────────────────┘ │ │ 无工具调用 → 完成 ▼ END

这个循环会持续,直到 LLM 决定完成。


三、你能控制什么

要构建可靠的代理,你需要控制代理循环的每一步发生的事情,以及步骤之间发生的事情。

三类上下文

上下文类型你能控制什么瞬态还是持久
模型上下文(Model context)模型调用包含了哪些内容(指令、消息历史、工具、响应格式)瞬态
工具上下文(Tool context)哪些工具可以访问和生成(读写状态、存储、运行时上下文)持久
生命周期上下文(Life-cycle context)模型调用和工具调用之间会发生什么(总结、护栏、日志记录等)持久

瞬态 vs 持久

类型含义
瞬态上下文(Transient)LLM 对单次通话的感知。你可以修改消息、工具或提示,而不改变保存在状态中的内容
持久上下文(Persistent)在各回合中被保存在状态内的内容。生命周期钩子和工具写入会永久修改这一点

四、数据来源

在整个过程中,你的代理访问(读写)不同的数据源:

数据来源也被称为范围示例
运行时上下文(Runtime Context)静态配置对话范围用户 ID、API 密钥、数据库连接、权限、环境设置
状态(State)短期记忆对话范围当前消息、上传文件、认证状态、工具结果
存储(Store)长期记忆跨对话用户偏好、提取的洞察、记忆、历史数据

五、工作原理

LangChain 中间件(middleware)是让上下文工程对开发者切实可行的底层机制。

Middleware 允许你钩入代理生命周期的任何步骤并:

  1. 更新上下文(Update context)
  2. 跳转到生命周期中的不同步骤(Jump)

本指南中会频繁使用 middleware API 作为达成上下文工程的手段。


六、模型上下文(Model context)

控制每次模型调用包含什么—— 指令、可用工具、使用哪个模型、输出格式。
这些决策直接影响可靠性和成本。

类型说明
System Prompt开发者给 LLM 的基础指令
Messages发送给 LLM 的完整消息列表(会话历史)
Tools代理可用于采取行动的工具
Model实际要调用的模型(含配置)
Response Format模型最终响应的 schema 规范

所有这些类型的模型上下文都可以取自 state(短期记忆)、store(长期记忆)或 runtime context(静态配置)。


6.1 System Prompt

系统提示词设定 LLM 的行为和能力。
不同的用户、上下文或对话阶段需要不同的指令。

成功的代理会借助记忆、偏好和配置,为当前对话状态提供正确的指令。

从 State 读取(访问消息数或对话上下文):

fromlangchain.agentsimportcreate_agentfromlangchain.agents.middlewareimportdynamic_prompt,ModelRequest@dynamic_promptdefstate_aware_prompt(request:ModelRequest)->str:# request.messages 是 request.state["messages"] 的快捷方式message_count=len(request.messages)base="You are a helpful assistant."ifmessage_count>10:base+="\nThis is a long conversation - be extra concise."returnbase agent=create_agent(model="gpt-5.5",tools=[...],middleware=[state_aware_prompt])

三种数据来源:State / Store / Runtime Context均可用于动态系统提示词。


6.2 Messages

消息构成发送给 LLM 的提示词。
管理消息内容至关重要,以确保 LLM 拥有正确信息来做出好的响应。

从 State 注入已上传文件的上下文(当与当前查询相关时):

fromlangchain.agentsimportcreate_agentfromlangchain.agents.middlewareimportwrap_model_call,ModelRequest,ModelResponsefromtypingimportCallable@wrap_model_calldefinject_file_context(request:ModelRequest,handler:Callable[[ModelRequest],ModelResponse])->ModelResponse:"""Inject context about files user has uploaded this session."""# 从 State 读取:获取上传文件的元数据uploaded_files=request.state.get("uploaded_files",[])ifuploaded_files:# 构建关于可用文件的上下文file_descriptions=[]forfileinuploaded_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."""# 在最近的消息之前注入文件上下文messages=[*request.messages,{"role":"user","content":file_context},]request=request.override(messages=messages)returnhandler(request)agent=create_agent(model="gpt-5.5",tools=[...],middleware=[inject_file_context])
⭐ 瞬态 vs 持久的消息更新

上面的例子使用wrap_model_call进行瞬态更新——
修改单次调用发送给模型的消息,不改变 state 中保存的内容。

对于修改 state 的持久更新,你可以:

  1. 从wrap_model_call返回带有Command的ExtendedModelResponse,从模型调用层注入 state 更新
  2. 使用生命周期钩子,如before_model、after_model或wrap_tool_call(用于工具返回)来更新对话历史

详见 middleware 文档与 State updates。


6.3 Tools

工具让模型与数据库、API 和外部系统交互。
你如何定义和选择工具直接影响模型能否有效完成任务。

定义工具

每个工具需要清晰的名称、描述、参数名和参数描述。

这些不只是元数据——它们指导模型关于何时以及如何使用该工具的推理。

fromlangchain.toolsimporttool@tool(parse_docstring=True)defsearch_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 herepass

@tool(parse_docstring=True)可解析 Google 风格的 docstring,自动填充参数描述。

选择工具

并非每个工具都适合每种情况:

  • 工具太多可能压垮模型(上下文过载)并增加错误
  • 工具太少限制能力

动态工具选择使工具集能根据认证状态、用户权限、功能标志或对话阶段进行适配。

fromlangchain.agentsimportcreate_agentfromlangchain.agents.middlewareimportwrap_model_call,ModelRequest,ModelResponsefromtypingimportCallable@wrap_model_calldefstate_based_tools(request:ModelRequest,handler:Callable[[ModelRequest],ModelResponse])->ModelResponse:"""Filter tools based on conversation State."""# 从 State 读取:检查用户是否已认证state=request.state is_authenticated=state.get("authenticated",False)message_count=len(state["messages"])# 仅在认证后启用敏感工具ifnotis_authenticated:tools=[tfortinrequest.toolsift.name.startswith("public_")]request=request.override(tools=tools)elifmessage_count<5:# 对话早期限制工具tools=[tfortinrequest.toolsift.name!="advanced_search"]request=request.override(tools=tools)returnhandler(request)agent=create_agent(model="gpt-5.5",tools=[public_search,private_search,advanced_search],middleware=[state_based_tools])

参见 Dynamic tools 了解过滤预注册工具和运行时注册工具(例如从 MCP 服务器)。


6.4 Model

不同模型有不同的优势、成本和上下文窗口。为当前任务选择合适的模型,这在代理运行期间可能会变化。

fromlangchain.agentsimportcreate_agentfromlangchain.agents.middlewareimportwrap_model_call,ModelRequest,ModelResponsefromlangchain.chat_modelsimportinit_chat_modelfromtypingimportCallable# 在中间件外部一次性初始化模型large_model=init_chat_model("claude-sonnet-4-6")standard_model=init_chat_model("gpt-5.5")efficient_model=init_chat_model("gpt-5.4-mini")@wrap_model_calldefstate_based_model(request:ModelRequest,handler:Callable[[ModelRequest],ModelResponse])->ModelResponse:"""Select model based on State conversation length."""# request.messages 是 request.state["messages"] 的快捷方式message_count=len(request.messages)ifmessage_count>20:# 长对话 - 使用上下文窗口更大的模型model=large_modelelifmessage_count>10:# 中等对话model=standard_modelelse:# 短对话 - 使用高效模型model=efficient_model request=request.override(model=model)returnhandler(request)agent=create_agent(model="gpt-5.4-mini",tools=[...],middleware=[state_based_model])

⭐最佳实践:模型实例在中间件外部一次性初始化,避免每次调用重复创建。


6.5 Response Format

结构化输出将非结构化文本转换为经过验证的结构化数据。
当提取特定字段或为下游系统返回数据时,自由文本是不够的。

工作原理:当你提供 schema 作为响应格式时,模型的最终响应保证符合该 schema。
代理运行模型/工具调用循环直到模型完成工具调用,然后将最终响应强制转换为提供的格式。

定义格式

Schema 定义指导模型。字段名、类型和描述明确指定了输出应遵循的格式。

frompydanticimportBaseModel,FieldclassCustomerSupportTicket(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'")
选择格式

动态响应格式选择使 schema 能根据用户偏好、对话阶段或角色进行调整——
早期返回简单格式,随着复杂度增加返回详细格式。

fromlangchain.agentsimportcreate_agentfromlangchain.agents.middlewareimportwrap_model_call,ModelRequest,ModelResponsefrompydanticimportBaseModel,FieldfromtypingimportCallableclassSimpleResponse(BaseModel):"""Simple response for early conversation."""answer:str=Field(description="A brief answer")classDetailedResponse(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_calldefstate_based_output(request:ModelRequest,handler:Callable[[ModelRequest],ModelResponse])->ModelResponse:"""Select output format based on State."""# request.messages 是 request.state["messages"] 的快捷方式message_count=len(request.messages)ifmessage_count<3:# 对话早期 - 使用简单格式request=request.override(response_format=SimpleResponse)else:# 已建立的对话 - 使用详细格式request=request.override(response_format=DetailedResponse)returnhandler(request)agent=create_agent(model="gpt-5.5",tools=[...],middleware=[state_based_output])

七、工具上下文(Tool context)

工具的特殊之处在于它们既读又写上下文。

在最基本的情况下,工具执行时接收 LLM 的请求参数并返回一个工具消息。工具完成工作并产生结果。

工具还可以为模型获取重要信息,使其能够执行和完成任务。

Reads(读)

大多数现实世界的工具需要的不只是 LLM 的参数:
数据库查询需要用户 ID、外部服务需要 API 密钥、决策需要当前会话状态。

工具从state、store 和 runtime context读取这些信息。

fromlangchain.toolsimporttool,ToolRuntimefromlangchain.agentsimportcreate_agent@tooldefcheck_authentication(runtime:ToolRuntime)->str:"""Check if user is authenticated."""# 从 State 读取:检查当前认证状态current_state=runtime.state is_authenticated=current_state.get("authenticated",False)ifis_authenticated:return"User is authenticated"else:return"User is not authenticated"agent=create_agent(model="gpt-5.5",tools=[check_authentication])

Writes(写)

工具结果可用于帮助代理完成给定任务。
工具可以既直接向模型返回结果,又更新代理的记忆,使重要上下文对未来的步骤可用。

fromlangchain.toolsimporttool,ToolRuntimefromlangchain.agentsimportcreate_agentfromlanggraph.typesimportCommand@tooldefauthenticate_user(password:str,runtime:ToolRuntime)->Command:"""Authenticate user and update State."""# 执行认证(简化)ifpassword=="correct":# 写入 State:使用 Command 标记为已认证returnCommand(update={"authenticated":True},)else:returnCommand(update={"authenticated":False})agent=create_agent(model="gpt-5.5",tools=[authenticate_user])

参见 Tools 获取在工具中访问 state、store 和 runtime context 的全面示例。


八、生命周期上下文(Life-cycle context)

控制核心代理步骤之间发生的事情—— 拦截数据流以实现横切关注点,
如摘要(summarization)、护栏(guardrails)和日志记录(logging)。

中间件是让上下文工程切实可行的机制。Middleware 允许你钩入代理生命周期的任何步骤并:

  1. 更新上下文—— 修改 state 和 store 以持久化更改、更新对话历史或保存洞察
  2. 在生命周期中跳转—— 根据上下文移动到代理循环中的不同步骤
    (例如,满足条件时跳过工具执行、使用修改后的上下文重复模型调用)

代理循环中的中间件钩子

┌─────────────────────────────────────────────────────────┐ │ 代理循环 │ │ │ │ before_model ┌───────────┐ after_model │ │ ───────────────────► │ Model │ ───────────────────► │ │ │ Call │ │ │ └─────┬─────┘ │ │ │ 工具调用请求 │ │ ▼ │ │ ┌──────────────────┐ │ │ wrap_tool_call │ Tool Execution │ │ │ ─────────────────►│ (工具执行) │ │ │ └────────┬─────────┘ │ │ │ 工具结果 │ │ └──────► 回到模型调用 │ └─────────────────────────────────────────────────────────┘ wrap_model_call ──► 包裹整个模型调用(可重写 request / 跳转到别的步骤) dynamic_prompt ──► 动态生成 system prompt

常用钩子:

钩子时机典型用途
@before_model模型调用前裁剪消息、注入上下文
@after_model模型调用后校验/删除敏感内容
@wrap_model_call包裹模型调用换模型、过滤工具、注入消息、改 response_format
@wrap_tool_call包裹工具调用工具错误兜底、改写工具返回
@dynamic_prompt生成提示词时基于 state/context 动态 system prompt

示例:摘要(Summarization)

最常见的生命周期模式之一是当对话记录过长时自动压缩。

⭐ 与「模型上下文」中所示的瞬态消息修剪不同,摘要会持久更新状态——
永久替换旧消息,用保存到未来所有回合的摘要。

LangChain 提供了内置的中间件来实现这一点:

fromlangchain.agentsimportcreate_agentfromlangchain.agents.middlewareimportSummarizationMiddleware agent=create_agent(model="gpt-5.5",tools=[...],middleware=[SummarizationMiddleware(model="gpt-5.4-mini",trigger={"tokens":4000},keep=("messages",20),),],)

九、速查表

request.override()可覆盖的维度

参数效果上下文类型
messages=改发送给模型的消息瞬态
tools=过滤/替换工具集瞬态
model=切换模型瞬态
response_format=切换输出 schema瞬态

⭐ 这四个都通过request.override(...)实现,是模型上下文工程的核心手段。

中间件钩子速查

fromlangchain.agents.middlewareimport(before_model,# 模型调用前:持久更新 stateafter_model,# 模型调用后:持久更新 statewrap_model_call,# 包裹模型调用:瞬态重写 requestwrap_tool_call,# 包裹工具调用:处理工具错误/结果dynamic_prompt,# 动态 system promptSummarizationMiddleware,# 内置:自动摘要)

三大数据源访问方式

场景访问方式
中间件中读 Staterequest.state/request.state["messages"]/request.messages
工具中读 Stateruntime.state
工具中读 Storeruntime.store
工具中读 Contextruntime.context
工具中写 State返回Command(update={...})

十、要点小结

  1. 代理失败多数不是模型能力问题,而是"正确的上下文没有传给 LLM"——上下文工程是 AI 工程师的首要任务。
  2. 代理循环 =模型调用+工具执行,循环持续到 LLM 决定完成。
  3. 三类上下文:模型上下文(瞬态)、工具上下文(持久)、生命周期上下文(持久)。
  4. 三大数据源:Runtime Context(静态配置)、State(短期记忆)、Store(长期记忆/跨对话)。
  5. Middleware 是上下文工程的落地机制:更新上下文 + 在生命周期中跳转。
  6. ⭐瞬态 vs 持久:wrap_model_call+override()只影响本次调用;
    要持久修改需用before_model/after_model或返回Command的ExtendedModelResponse。
  7. 工具的名/描述/参数描述不是元数据,而是引导模型推理的指令;parse_docstring=True可自动解析 Google 风格 docstring。
  8. 工具是唯一既能读又能写上下文的组件:靠ToolRuntime读写 State/Store/Context。
  9. 动态化的四个维度都可用request.override():
    工具集(按权限过滤)、模型(按对话长度/成本)、消息(注入文件上下文)、输出格式(按对话阶段)。
  10. ⭐摘要 vs 修剪:修剪是瞬态的(只影响本次调用);摘要是持久的(永久改写 state,影响未来所有回合)。
  11. 模型实例应在中间件外部一次性初始化,避免重复开销。
  12. 响应格式在代理完成所有工具调用后,才把最终响应强制转换为指定 schema。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询