LangChain1.0智能体开发:上下文工程

众所周知,上下文工程是构建企业级可靠的智能体的关键。阅读本文您将获得:

  • LangChain上下文工程概述
  • LangChain模型上下文详解
  • LangChain工具上下文详解
  • LangChain生命周期上下文详解
  • 上下文工程最佳实践

1、概述

构建智能体(或任何大模型应用)的难点在于如何让它们具备足够的可靠性。这类应用或许能在原型阶段正常运行,但在实际应用场景中却常常出现故障。

1.1 智能体为何会出现故障?

智能体发生故障,通常是因为其内部的大模型调用执行了错误操作,或是未按照预期完成任务。而大模型出现问题,主要源于以下两种原因之一:

  • 基础大模型的能力不足
  • 未向大模型传递 "正确" 的上下文

事实上,多数情况下,智能体可靠性不足的根源是上述第二种原因。 上下文工程(Context Engineering)指的是:以恰当的格式为大模型提供所需的正确信息与工具,使其能够完成特定任务。这是人工智能工程师的核心工作之一。"正确" 上下文的缺失,是阻碍智能体实现更高可靠性的首要因素;而LangChain的智能体抽象层经过独特设计,能够为上下文工程的实施提供便利。

1.2 智能体循环(Agent Loop)

一个典型的智能体循环包含两个主要步骤:

  • 模型调用(Model call):向大模型传入提示词和可用工具,返回结果要么是一个响应,要么是执行工具的请求。
  • 工具执行(Tool execution):执行大模型所请求的工具,返回工具执行结果。

该循环会持续进行,直至大模型判定任务完成。

1.3 可控制的内容

要构建可靠的智能体,你需要控制智能体循环每个步骤中发生的事情,以及步骤之间发生的事情。

上下文类型(Context Type) 可控制的内容(What You Control) 临时或持久(Transient or Persistent)
模型上下文(Model Context) 传入模型调用的内容(指令、消息历史、工具、响应格式) 临时(Transient)
工具上下文(Tool Context) 工具可访问和生成的内容(对状态、存储、运行时上下文的读写操作) 持久(Persistent)
生命周期上下文(Life-cycle Context) 模型调用与工具调用之间发生的事情(总结、安全护栏、日志记录等) 持久(Persistent)
  • 临时上下文(Transient Context) 指大模型单次调用所能获取的信息。你可以修改消息、工具或提示词,且无需改变状态(state)中已保存的内容。
  • 持久上下文(Persistent Context) 指在多轮交互(turns)过程中会保存在状态(state)中的信息。生命周期钩子(life-cycle hooks)和工具写入操作会对其进行永久性修改。

1.4 数据源(Data sources)

在整个流程中,智能体会访问(读取 / 写入)不同的数据源:

数据源(Data Source) 其他名称(Also Known As) 作用范围(Scope) 示例(Examples)
运行时上下文(Runtime Context) 静态配置(Static configuration) 对话级(Conversation-scoped) 用户 ID、API 密钥、数据库连接、权限、环境设置
状态(State) 短期记忆(Short-term memory) 对话级(Conversation-scoped) 当前消息、上传文件、认证状态、工具执行结果
存储(Store) 长期记忆(Long-term memory) 跨对话级(Cross-conversation) 用户偏好、提取的洞察、记忆数据、历史数据

1.5 工作原理

LangChain中间件(middleware)是底层核心机制,它让使用LangChain的开发者能够切实落地上下文工程(context engineering)。 通过中间件,你可以接入智能体生命周期(agent lifecycle)的任意步骤,并实现以下操作:

  • 更新上下文(Update context)
  • 跳转到智能体生命周期的其他步骤

使用中间件是实现上下文工程的重要手段。

2、模型上下文(Model Context)

控制传入每次模型调用的内容,包括指令、可用工具、待使用的模型以及输出格式。这些决策会直接影响智能体的可靠性与成本。

  • 系统提示词(System Prompt):开发者向大语言模型(LLM)提供的基础指令。
  • 消息(Messages):发送给大语言模型(LLM)的完整消息列表(即对话历史)。
  • 工具(Tools):智能体可访问并用于执行操作的实用工具。
  • 模型(Model):待调用的实际模型(包含配置信息)。
  • 响应格式(Response Format):用于规范大语言模型(LLM)最终输出内容的模式说明。

上述所有类型的模型上下文(model context),均可从状态(state,即短期记忆)、存储(store,即长期记忆)或运行时上下文(runtime context,即静态配置)中获取数据。

2.1 系统提示词(System Prompt)

系统提示词用于设定大模型的行为模式与能力范围。不同用户、不同上下文或对话的不同阶段,均需对应不同的指令。一个高效的智能体会结合记忆数据、用户偏好及配置信息,为当前对话状态提供适配的指令。

python 复制代码
from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.agents.middleware import dynamic_prompt, ModelRequest

@dataclass
class Context:
    user_role: str
    deployment_env: str

@dynamic_prompt
def context_aware_prompt(request: ModelRequest) -> str:
    # Read from Runtime Context: user role and environment
    user_role = request.runtime.context.user_role
    env = request.runtime.context.deployment_env

    base = "You are a helpful assistant."

    if user_role == "admin":
        base += "\nYou have admin access. You can perform all operations."
    elif user_role == "viewer":
        base += "\nYou have read-only access. Guide users to read operations only."

    if env == "production":
        base += "\nBe extra careful with any data modifications."

    return base

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[context_aware_prompt],
    context_schema=Context
)

2.2 消息(Messages)

消息构成了发送给大模型的提示词(prompt)。管理消息内容至关重要,这能确保大模型获得足够的正确信息,从而生成优质响应。

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]
)

2.3 工具(Tools)

工具能让大模型与数据库、API及外部系统进行交互。工具的定义与选择方式,会直接影响大模型能否高效完成任务。

2.3.1 工具定义(Defining tools)

每个工具都需要包含清晰的名称(name)、描述(description)、参数名称(argument names)及参数描述(argument descriptions)。这些并非单纯的元数据(metadata)------ 它们会引导大模型思考 "何时使用该工具" 以及 "如何使用该工具"。

2.3.2 工具选择(Selecting tools)

并非所有工具都适用于所有场景。工具过多可能会让大模型难以应对(造成上下文过载),进而增加出错概率;工具过少则会限制其能力。动态工具选择(Dynamic tool selection)会根据认证状态、用户权限、功能标志(feature flags)或对话阶段,调整可用的工具集合。

python 复制代码
from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from typing import Callable

@dataclass
class Context:
    user_role: str

@wrap_model_call
def context_based_tools(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    """Filter tools based on Runtime Context permissions."""
    # Read from Runtime Context: get user role
    user_role = request.runtime.context.user_role

    if user_role == "admin":
        # Admins get all tools
        pass
    elif user_role == "editor":
        # Editors can't delete
        tools = [t for t in request.tools if t.name != "delete_data"]
        request = request.override(tools=tools)
    else:
        # Viewers get read-only tools
        tools = [t for t in request.tools if t.name.startswith("read_")]
        request = request.override(tools=tools)

    return handler(request)

agent = create_agent(
    model="gpt-4o",
    tools=[read_data, write_data, delete_data],
    middleware=[context_based_tools],
    context_schema=Context
)

2.4 模型(Model)

不同的模型具备不同的优势、成本及上下文窗口(context window)。需为当前待处理的任务选择合适的模型,而在智能体(agent)运行过程中,所选模型也可能发生变化。

python 复制代码
from dataclasses import dataclass
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

@dataclass
class Context:
    cost_tier: str
    environment: str

# Initialize models once outside the middleware
premium_model = init_chat_model("claude-sonnet-4-5-20250929")
standard_model = init_chat_model("gpt-4o")
budget_model = init_chat_model("gpt-4o-mini")

@wrap_model_call
def context_based_model(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    """Select model based on Runtime Context."""
    # Read from Runtime Context: cost tier and environment
    cost_tier = request.runtime.context.cost_tier
    environment = request.runtime.context.environment

    if environment == "production" and cost_tier == "premium":
        # Production premium users get best model
        model = premium_model
    elif cost_tier == "budget":
        # Budget tier gets efficient model
        model = budget_model
    else:
        # Standard tier
        model = standard_model

    request = request.override(model=model)

    return handler(request)

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[context_based_model],
    context_schema=Context
)

2.5 响应格式(Response Format)

结构化输出(Structured output)能将非结构化文本转换为经过验证的结构化数据。在提取特定字段或向下游系统返回数据时,自由格式文本往往无法满足需求。 其工作原理如下:当你将一个模式(schema)指定为响应格式时,大模型的最终响应将确保符合该模式。智能体会运行 "模型调用 / 工具调用" 循环,直至模型完成工具调用流程,随后最终响应会被强制转换为指定的格式。

2.5.1 格式定义(Defining formats)

模式定义(Schema definitions)对模型具有指导作用。字段名称(field names)、字段类型(types)和字段描述(descriptions)会精确规定输出应遵循的格式。

2.5.2 格式选择(Selecting formats)

动态响应格式选择(Dynamic response format selection)会根据用户偏好、对话阶段或角色调整模式(schema)------ 在对话初期返回简单格式,随着复杂度提升则返回详细格式。

python 复制代码
from dataclasses import dataclass
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

@dataclass
class Context:
    user_role: str
    environment: str

class AdminResponse(BaseModel):
    """Response with technical details for admins."""
    answer: str = Field(description="Answer")
    debug_info: dict = Field(description="Debug information")
    system_status: str = Field(description="System status")

class UserResponse(BaseModel):
    """Simple response for regular users."""
    answer: str = Field(description="Answer")

@wrap_model_call
def context_based_output(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    """Select output format based on Runtime Context."""
    # Read from Runtime Context: user role and environment
    user_role = request.runtime.context.user_role
    environment = request.runtime.context.environment

    if user_role == "admin" and environment == "production":
        # Admins in production get detailed output
        request = request.override(response_format=AdminResponse)
    else:
        # Regular users get simple output
        request = request.override(response_format=UserResponse)

    return handler(request)

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[context_based_output],
    context_schema=Context
)

3、工具上下文(Tool Context)

工具的特殊性在于,它们既能读取上下文,也能写入上下文。 在最基础的场景中,工具执行时会接收大模型的请求参数,并返回一条工具消息。随后工具完成其既定任务并生成结果。 工具还能为大模型获取关键信息,这些信息可帮助模型执行并完成任务。

3.1 读取操作

现实场景中,大多数工具所需的信息远不止大模型的参数。它们可能需要用户ID来执行数据库查询、需要API密钥来调用外部服务,或需要当前会话状态来辅助决策。工具会通过读取状态(state)、存储(store)和运行时上下文(runtime context)来获取这些信息。

python 复制代码
from dataclasses import dataclass
from langchain.tools import tool, ToolRuntime
from langchain.agents import create_agent

@dataclass
class Context:
    user_id: str
    api_key: str
    db_connection: str

@tool
def fetch_user_data(
    query: str,
    runtime: ToolRuntime[Context]
) -> str:
    """Fetch data using Runtime Context configuration."""
    # Read from Runtime Context: get API key and DB connection
    user_id = runtime.context.user_id
    api_key = runtime.context.api_key
    db_connection = runtime.context.db_connection

    # Use configuration to fetch data
    results = perform_database_query(db_connection, query, api_key)

    return f"Found {len(results)} results for user {user_id}"

agent = create_agent(
    model="gpt-4o",
    tools=[fetch_user_data],
    context_schema=Context
)

# Invoke with runtime context
result = agent.invoke(
    {"messages": [{"role": "user", "content": "Get my data"}]},
    context=Context(
        user_id="user_123",
        api_key="sk-...",
        db_connection="postgresql://..."
    )
)

3.2 写入操作

工具结果可用于帮助智能体完成指定任务。工具既能将结果直接返回给大模型,也能更新智能体的记忆(memory),从而为后续步骤提供可用的关键上下文。

python 复制代码
from dataclasses import dataclass
from langchain.tools import tool, ToolRuntime
from langchain.agents import create_agent
from langgraph.store.memory import InMemoryStore

@dataclass
class Context:
    user_id: str

@tool
def save_preference(
    preference_key: str,
    preference_value: str,
    runtime: ToolRuntime[Context]
) -> str:
    """Save user preference to Store."""
    user_id = runtime.context.user_id

    # Read existing preferences
    store = runtime.store
    existing_prefs = store.get(("preferences",), user_id)

    # Merge with new preference
    prefs = existing_prefs.value if existing_prefs else {}
    prefs[preference_key] = preference_value

    # Write to Store: save updated preferences
    store.put(("preferences",), user_id, prefs)

    return f"Saved preference: {preference_key} = {preference_value}"

agent = create_agent(
    model="gpt-4o",
    tools=[save_preference],
    context_schema=Context,
    store=InMemoryStore()
)

4、生命周期上下文(Life-cycle Context)

控制智能体核心步骤之间发生的操作 ------ 通过拦截数据流,实现总结、安全护栏(guardrails)、日志记录等横切关注点功能。 正如在 "模型上下文(Model Context)" 和 "工具上下文(Tool Context)" 中所见,中间件(middleware)是让上下文工程(context engineering)切实落地的核心机制。通过中间件,可以接入智能体生命周期的任意步骤,并执行以下任一操作:

  • 更新上下文(Update context):修改状态(state)和存储(store)以持久化变更、更新对话历史,或保存关键洞察(insights)
  • 跳转生命周期步骤(Jump in the lifecycle):根据上下文切换至智能体循环(agent cycle)的不同步骤(例如,若满足特定条件则跳过工具执行,或使用修改后的上下文重复调用模型) 示例:总结(Summarization)

生命周期模式中最常见的场景之一,是当对话历史过长时自动压缩其内容。与 "模型上下文(Model Context)" 中介绍的临时消息裁剪(transient message trimming)不同,总结(summarization)会持久化更新状态(state)------ 即用总结内容永久替换旧消息,且该总结会为后续所有对话轮次保存。 LangChain为此提供了内置中间件:SummarizationMiddleware

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",
            max_tokens_before_summary=4000,  # Trigger summarization at 4000 tokens
            messages_to_keep=20,  # Keep last 20 messages after summary
        ),
    ],
)

当对话超出令牌(token)限制时,总结中间件(SummarizationMiddleware)会自动执行以下操作:

  • 通过单独调用大模型,对较早的消息进行总结
  • 在状态(State)中用总结消息永久替换这些较早的消息
  • 保留近期消息的完整内容,以提供上下文支持

总结后的对话历史会被永久更新 ------ 在后续的对话轮次(turns)中,系统将显示总结内容,而非原始消息。

5、最佳实践

  • 从简入手:先使用静态提示词和工具,仅在需要时再添加动态功能
  • 增量测试:每次只添加一项上下文工程功能
  • 监控性能:跟踪模型调用、令牌(token)使用量和延迟情况
  • 使用内置中间件:充分利用总结中间件(SummarizationMiddleware)、大模型工具选择器中间件(LLMToolSelectorMiddleware)等
  • 记录上下文策略:清晰记录当前传递的上下文内容及其原因
  • 理解临时与持久的区别:模型上下文的变更为临时变更(按调用次数生效),而生命周期上下文(Life-cycle Context)的变更会持久化到状态(state)中。
相关推荐
Data_Adventure2 小时前
从 TypeScript 到 Java(2):从脚本执行到 main 方法 —— 理解 Java 的程序入口
前端·后端
暹罗软件开发2 小时前
告别分布式事务烦恼,Seata AT模式实战入门指南
后端·掘金·金石计划
武子康2 小时前
大数据-149 Apache Druid 实时 OLAP 架构与选型要点
大数据·后端·nosql
John_Rey2 小时前
Rust底层深度探究:自定义分配器(Allocators)——控制内存分配的精妙艺术
开发语言·后端·rust
isyuah2 小时前
Rust Miko 框架系列(二):快速上手与基础示例
后端·rust
Moe4882 小时前
JDK动态代理和CGLIB动态代理源码解析
java·后端
用户68545375977692 小时前
布隆过滤器删不掉数据?布谷鸟过滤器:让我来!🐦
后端
isyuah2 小时前
Rust Miko 框架系列(四):深入路由系统
后端·rust
虎子_layor2 小时前
号段模式(分布式ID)上手指南:从原理到实战
java·后端