提示词工程(prompt engineering)已死,上下文工程(context engineering)当立——这是 2026 年智能体领域最确定的范式转移。当一个 agent 在推理回路里跑得越久,它自己生产的工具返回、子任务草稿、中间推理就在把上下文窗口一点一点塞满,直到触发截断、失忆、幻觉乃至崩溃。本文以 Anthropic 提出的 write / select / compress / isolate 四策略为标尺,实测 LangGraph、OpenAI Agents SDK、CrewAI、AutoGen、Claude Agent SDK、Letta 六大主流栈在上下文治理上的真实手法与代价。核心结论:上下文是有限的预算而非无限的容器,谁把"每一 token 该不该进窗口"想清楚,谁就掌握了长程自主体的命门。
| 维度 | LangGraph | OpenAI Agents SDK | CrewAI | AutoGen | Claude Agent SDK | Letta (MemGPT) |
|---|---|---|---|---|---|---|
| 核心范式 | 显式 State 图 + 检查点 | 依赖注入 + Handoff | 角色作用域任务上下文 | 对话历史压缩 | 压缩 + 隔离子上下文 | 虚拟内存分页 |
| 写(write) | TypedDict State 显式声明 | RunContextWrapper 注入 |
Role+Backstory | Message list | CLAUDE.md 持久化 | system memory block |
| 选(select) | 节点内 RAG 注入 | Handoff 转交前剪枝 | Task 共享黑白名单 | condense 摘要 |
动态 select 工具 | memory retrieval |
| 压(compress) | trim_messages + 摘要节点 |
由模型/手写处理 | 弱(依赖底层 LLM) | 内建 condense_messages |
自动 compaction | 主动驱逐 + 摘要 |
| 隔(isolate) | 多 thread_id 隔离 | subagent 独立窗口 | Crew 内 agent 分治 | 多 agent 独立对话 | isolated subcontexts | 分层 memory tiers |
| 上手难度 | 高(要懂图论) | 中(类 FastAPI 体验) | 低(声明式) | 中 | 中(约束即设计) | 中高(要懂分页) |
| 变现/训练营 | 强(企业编排刚需) | 强(原厂背书) | 中(小项目演示) | 中(学术/研究) | 强(原厂最佳实践) | 中(差异化卖点) |
| 适用场景 | 复杂可控工作流 | OpenAI 栈产品 | 快速 PoC | 多智能体研究 | 长程 coding/办公 | 超长对话伴侣 |
架构原理:LangGraph 的核心赌注是——上下文不该是 LLM 凭感觉拼出来的字符串,而应当是被 TypedDict 显式声明的、有 reducer 的状态对象。每一步节点(node)接收 state、返回对 state 的增量修改,由检查点器(checkpointer,如 MemorySaver / PostgresSaver)落盘。这意味着上下文的写是结构化的、选是在节点内部用 RAG 主动注入的、压是用 trim_messages 或摘要节点完成的、隔是用 thread_id 天然实现的。
关键代码:
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph.message import add_messages
from typing import Annotated, TypedDict
from langchain_core.messages import SystemMessage, trim_messages
class State(TypedDict):
messages: Annotated[list, add_messages]
summary: str # 压缩产物独立存放
def call_model(state: State):
# compress 策略:每次只喂精挑后的窗口
trimmed = trim_messages(
state["messages"], strategy="last",
max_tokens=4000, include_system=True, start_on="human",
)
msgs = [SystemMessage(state["summary"])] + trimmed if state["summary"] else trimmed
return {"messages": [llm.invoke(msgs)]}
def summarize(state: State):
s = llm.invoke([SystemMessage("摘要以下历史:")] + state["messages"][:-2])
return {"summary": s.content, "messages": state["messages"][-2:]}
builder = StateGraph(State)
builder.add_node("model", call_model)
builder.add_node("summarize", summarize)
builder.add_conditional_edges("model",
lambda s: "summarize" if len(s["messages"]) > 10 else END)
builder.add_edge("summarize", "model")
graph = builder.compile(checkpointer=MemorySaver())
优缺点:最大优点是可观测、可回放、可分叉——你能用 LangSmith 看到每一步上下文里到底有什么,这是企业生产环境的硬需求。代价是心智负担重,初学者常被"reducer 为什么是 add_messages 不是 add"绊倒。
变现评估:企业级编排的刚需栈,适合做"复杂工作流训练营"高客单课。PostgresSaver + Store API 的组合是 To B 故事的核心。
架构原理:OpenAI 的设计哲学是上下文是依赖注入工具,而非数据搬运工。它把上下文劈成两类——本地上下文(local context,给工具函数、lifecycle hook 用的 RunContextWrapper)与 LLM 可见上下文(模型实际看到的消息)。核心理念是 Handoff:当 agent A 把控制权交给 agent B 时,前者的推理历史被显式裁剪,只把"该带走的摘要"传给后者——这就是 isolate 的官方实现。
关键代码:
from agents import Agent, Runner, RunContextWrapper
from dataclasses import dataclass
@dataclass
class UserCtx: # 本地上下文:依赖注入,LLM 看不到
user_id: str
db_pool: object
async def fetch_orders(ctx: RunContextWrapper[UserCtx], query: str):
# 工具内可直接拿到 db_pool,无需塞进 prompt
return await ctx.context.db_pool.fetch(query)
triage = Agent(name="分诊", tools=[fetch_orders],
handoffs=[billing_agent])
result = await Runner.run(trage, "查我上个月账单", context=UserCtx("u1", pool))
优缺点:手写"上下文装配"的代码量陡降,类 FastAPI 的体验极讨好开发者;Handoff 模型天然隔离上下文,避免了"一锅炖"的污染。缺点是压缩能力几乎全交给模型或手写——SDK 本身不像 LangGraph 那样提供 trim_messages 这种开箱即用的原语,长对话场景要自己补课。
变现评估:原厂背书是最大卖点,适合"OpenAI 官方栈"定位的训练营;但要注意它对压缩的"裸奔"状态需要配额外方案才能讲完整故事。
架构原理:CrewAI 不和你谈 state graph,它谈角色(role)、目标(goal)、背景故事(backstory)。每个 agent 是一个有边界的人设,上下文天然被角色作用域约束——研究员 agent 看到的和写作 agent 看到的,默认是不同切片。任务(task)之间通过显式 context=[...] 声明要消费哪些前置任务的输出,这是它对 select 的朴素实现。
关键代码:
from crewai import Agent, Task, Crew
researcher = Agent(role="研究员",
backstory="资深行业分析师,只信一手数据",
goal="产出 3 条带出处的洞察")
writer = Agent(role="撰稿人",
backstory="把数据翻译成高管能 30 秒读完的摘要",
goal="输出 200 字结论")
t1 = Task(description="调研{topic}最新进展", agent=researcher,
expected_output="3 条洞察")
t2 = Task(description="将洞察改写为摘要", agent=writer,
expected_output="200 字", context=[t1]) # select:只喂 t1 的产物
crew = Crew(agents=[researcher, writer], tasks=[t1, t2])
优缺点:上手门槛全场最低,10 行代码出第一个多智能体,演示效果惊艳。但它的压缩能力弱——基本依赖底层 LLM 的窗口,长程任务容易在 task 之间累积臃肿上下文;isolate 是"分工式"的粗粒度隔离,不如 LangGraph 精确。
变现评估:理想的"入门爆款课"载体,故事好讲、demo 漂亮;但别指望它扛企业级长程任务。
架构原理:AutoGen 的基因是对话式多智能体,所以它的上下文治理天然围绕"对话历史"展开。v0.4+ 引入的 Condenser 抽象是关键——它能在消息列表膨胀到阈值时,调用 LLM 把旧消息压缩成一段摘要再继续。这本质上是用 token 换 token:花一次推理的代价,把 N 条历史炼成 1 条。
关键代码:
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.conditions import TextMentionTermination
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_core.models import ChatCompletionClient
# 压缩器:对话超过阈值自动 condense
from autogen_agentchat.condensers import LLMSummaryCondenser
model = ChatCompletionClient(model="gpt-4o")
condenser = LLMSummaryCondenser(
model_client=model, max_messages=20, # 超过 20 条触发摘要
trigger_messages=15)
agent = AssistantAgent("analyst", model_client=model,
system_message="你是严谨的分析师",)
team = RoundRobinGroupChat([agent],
termination_condition=TextMentionTermination("TERMINATE"))
优缺点:对话压缩是开箱即用的,省心;多 agent 各自独立对话历史也实现了轻量 isolate。缺点是摘要有损——关键的数字、代码片段可能在 condense 中被改写或丢失,金融、法律等高保真场景要慎用,且每次摘要本身就是一笔推理成本。
变现评估:学术与多智能体研究场景的金标准,适合做"多智能体协议"主题的进阶课。
架构原理:Anthropic 的策略最接近"上下文工程"的教科书定义,两点最锋利。其一,自动压缩(compaction)——当上下文逼近窗口上限时,系统自动把旧轮次摘要化,Claude Code 的长会话不掉链子靠的就是它。其二,隔离子上下文(isolated subcontexts)——子智能体在自己的独立窗口里完成任务,只把简洁结果回传给编排者,父上下文干净如初。这把 compress 和 isolate 两个最贵的策略做到了产品级。
关键代码(Claude Agent SDK 风格):
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
options = ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Task"], # select:限定可见工具
# compaction 由 SDK 在阈值自动触发,无需手写
mcp_servers={ # 外置 context(MCP)
"db": {"command": "uvx", "args": ["db-mcp"]}},
setting_sources=["project", "local"], # 写:CLAUDE.md 持久指令
)
async for msg in query(prompt="重构 src/auth", options=options):
print(msg)
anyio.run(main)
优缺点:长程任务的稳定性全场最佳,子上下文隔离让"分工不污染"成为默认;CLAUDE.md 把项目级持久指令做成一等公民,写策略极其优雅。缺点是强绑定 Anthropic 生态,跨厂商迁移成本高。
变现评估:原厂最佳实践天然适合做"专家级 agent 训练营",CLAUDE.md + compaction + subagent 三件套是讲故事的核心抓手。
架构原理:Letta 的赌注最大胆——把操作系统的虚拟内存搬进 LLM。它把上下文分成核心记忆(core memory,常驻窗口)、召回记忆(recall,历史对话)、归档记忆(archival,外置向量库),并让 agent 自己用 core_memory_append、archival_memory_search 这类自我编辑工具来管理上下文的换入换出。这相当于把 select / compress 的决策权从框架交还给了 agent 自己。
关键代码:
from letta_client import Letta
client = Letta(base_url="http://localhost:8283")
agent = client.agents.create(
name="长记忆伴侣",
memory_blocks=[
{"label": "human", "value": "用户偏好:简洁、爱用数据说话"},
{"label": "persona", "value": "我是严谨的助理"},
],
model="anthropic/claude-sonnet-4-6",
# archival memory 自动分页,超长对话不爆窗口
)
# agent 运行中可自主调用 archival_memory_search 取回旧信息
response = client.agents.messages.create(
agent_id=agent.id,
messages=[{"role": "user", "content": "我们三个月前聊过的那个方案"}])
优缺点:理论天花板最高——理论上可承载无限长对话,是真正解决"塞满即崩"的根治派。代价是复杂度和不确定性:agent 自己决定换页,意味着它可能"忘记"该记的或"翻错"该取的,调试链路长。
变现评估:差异化最强的卖点,"无限记忆伴侣"故事性十足,适合做面向 C 端陪伴类产品的训练营。
flowchart TB
subgraph 四策略["上下文工程四策略 (Anthropic)"]
W["✍️ Write 写入<br/>该进窗口的持久化"]
S["🔍 Select 选取<br/>每步按需召回"]
C["🗜️ Compress 压缩<br/>摘要/裁剪历史"]
I["🧱 Isolate 隔离<br/>子上下文分治"]
end
subgraph 六栈["六栈实现手法"]
LG["LangGraph<br/>State+检查点+trim"]
OA["OpenAI SDK<br/>DI+Handoff"]
CR["CrewAI<br/>角色作用域"]
AT["AutoGen<br/>Condenser摘要"]
CA["Claude SDK<br/>compaction+子上下文"]
LE["Letta<br/>虚拟内存分页"]
end
W --> LG & CA & LE
S --> OA & CR & LE
C --> LG & AT & CA
I --> LG & OA & CR & CA
classDef strat fill:#e8f4fd,stroke:#2563eb,stroke-width:2px
classDef stack fill:#fef3c7,stroke:#d97706,stroke-width:1px
class W,S,C,I strat
class LG,OA,CR,AT,CA,LE stack
sequenceDiagram
participant U as 用户
participant Orch as 编排Agent
participant Sub as 子Agent
participant Mem as 外部记忆
U->>Orch: 长任务请求
Note over Orch: ✍️ Write: CLAUDE.md/State 持久指令
Orch->>Mem: 🔍 Select: 按需召回相关片段
Mem-->>Orch: 注入精选上下文
Orch->>Sub: 🧱 Isolate: 派发+裁剪上下文
Note over Sub: 子上下文独立工作
Sub-->>Orch: 只回传摘要结果
Note over Orch: 🗜️ Compress: 超阈值自动摘要旧轮次
Orch-->>U: 持续输出,窗口不爆
真相一:压缩永远是有损的。 AutoGen 的 condense 和 Claude 的 compaction 本质都是"用一次推理换 token 预算",但这意味着精确数字、代码、引用在压缩中必然面临改写风险。生产实践中,金融、医疗、法律场景对"压缩后是否还能找到原始出处"有强需求——这也是为什么 RAG(select 策略)往往比 compress 更可靠:它不丢信息,只在需要时召回。判断该压还是该选,看你的任务对"逐字保真"的敏感度。
真相二:隔离比压缩更省。 Claude Agent SDK 和 OpenAI Handoff 都押注"隔离"——与其让一个 agent 在膨胀的窗口里苦苦摘要,不如让子 agent 在干净窗口里干完、只回传结论。隔离是 O(1) 的上下文成本,而压缩是 O(n) 之后的清理。当任务可分解时,优先隔离,压缩兜底是更优的算力分配。
真相三:上下文是预算而非容器。 这是 Anthropic 那篇奠基文章的核心隐喻。把上下文当作"能塞多少塞多少"的容器,迟早撞墙;把它当作"每个 token 都有成本"的预算,才会主动 write 精炼指令、select 恰好够用的知识、compress 旧历史、isolate 子任务。LangGraph 把这做成类型系统、Letta 做成虚拟内存、CrewAI 做成角色边界——殊途同归,都是对"上下文稀缺性"的承认。
| 场景 | 首选栈 | 理由 |
|---|---|---|
| 企业级复杂可控工作流 | LangGraph | State 显式 + 检查点回放 + LangSmith 可观测,可审计、可分叉 |
| OpenAI 栈快速上产品 | OpenAI Agents SDK | 原厂 DI + Handoff,开发体验最佳,迁移成本最低 |
| 多智能体研究/教学 PoC | CrewAI + AutoGen | CrewAI 演示惊艳,AutoGen 对话压缩适合研究复现 |
| 长程 coding/办公 agent | Claude Agent SDK | compaction + 子上下文隔离,长任务稳定性天花板 |
| 超长对话/陪伴类 C 端 | Letta | 虚拟内存分页,理论无限记忆,差异化最强 |
| 高保真领域(金融/法律) | LangGraph + RAG(select) | 慎用有损 compress,select 召回保逐字出处 |
一句话总结给所有选型者:没有最好的上下文栈,只有最匹配你"对信息丢失容忍度"的那一栈。 先想清楚你的 agent 跑完 100 步后,哪些信息必须原样还在,哪些可以变成一句话——答案决定了你该 write、select、compress 还是 isolate。
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
