
LangGraph + 多Agent系统实战:上下文工程才是智能协作的核心基建 原创
随着大语言模型(LLMs)和多智能体系统(Multi-Agent Systems, MAS)的快速发展,我们不再满足于单个“聪明”的AI,而是追求多个AI代理(Agent)之间的高效协作、动态推理与上下文感知。而这一切的核心,正是我们今天要探讨的主题 —— Multi-Agent。 Context Engineering(多智能体上下文工程)
什么是 Multi-Agent Context Engineering?
Context Engineering(上下文工程) 是指通过设计、管理和优化上下文信息,使AI系统能够更准确地理解当前任务、环境与用户意图,从而做出更合理、更连贯的响应。
而在多智能体系统中,每个Agent都有自己的目标、记忆、工具和推理能力。Multi-Agent Context Engineering 就是:
在多个Agent之间,动态构建、共享、演化和优化上下文信息,以支持协同决策、任务分解、角色分配与冲突解决。
简单来说:让每个Agent都知道“现在在干嘛、谁在干、为什么干、怎么干”,并能根据全局上下文动态调整自己的行为。
为什么需要 Multi-Agent Context Engineering?
想象一个由3个Agent组成的团队:
- Planner Agent:负责拆解任务
- Researcher Agent:负责搜索信息
- Writer Agent:负责撰写报告
如果没有良好的上下文工程:
- Researcher 不知道 Planner 最关心哪部分数据
- Writer 拿到的信息可能是过时的或与目标无关
- Planner 无法评估任务是否真正完成
结果:效率低下、重复劳动、输出不一致。
而通过 Context Engineering:
- 每个Agent的输入输出都携带结构化上下文
- 上下文随任务推进动态更新
- Agent 之间共享“情境记忆”与“意图图谱”
- 系统具备“情境感知”能力,能自动协调冲突或填补信息缺口
核心组件与设计模式
全局上下文存储(Global Context Store)
类似一个“黑板系统”(Blackboard Architecture),所有Agent都可以读写一个共享的上下文空间。这个空间可以是:
- 一个结构化的 JSON 对象
- 一个向量数据库(用于语义检索)
- 一个图数据库(用于关系建模)
# state.py
from typing import TypedDict, List, Dict, Optional, Any, Annotated
from langgraph.graph.message import add_messages
from datetime import datetime
class AgentState(TypedDict):
agent_id: str
role: str
last_action: str
last_updated: str
status: str # "idle", "working", "blocked", "done"
output: Optional[Any]
class SharedContext(TypedDict):
# 任务元信息
session_id: str
task_id: str
task_goal: str
task_constraints: List[str]
current_phase: str
phase_history: List[Dict[str, Any]]
# 共享数据区
shared_memory: Dict[str, Any]
# Agent 状态池
agent_states: Dict[str, AgentState]
# 上下文控制
context_version: Annotated[int, lambda x, y: x + 1] # 自动递增版本号
event_queue: Annotated[List[Dict], add_messages] # 事件队列(LangGraph 原生支持)
# 时间戳
created_at: str
updated_at: str
Annotated[int, lambda x, y: x + 1]:每次状态更新自动递增版本号 Annotated[List, add_messages]:利用 LangGraph 内置的 add_messages 实现事件队列累加
上下文协议(Context Protocol)
定义Agent之间交换上下文的格式与语义。例如:
- 使用自定义 Schema 描述上下文字段
- 定义“上下文变更事件”(Context Update Event)的发布/订阅机制
- 支持增量更新(Delta Update)而非全量覆盖
当 Researcher 找到新数据时,它发布一个
context.update
事件,附带 data_snippet
和 confidence_score
,Writer 订阅该事件并决定是否采纳。
[Researcher Agent]
│
▼
[更新 state.event_queue] → LangGraph 内部流转(Writer 下一步消费)
│
▼
[发布到 Redis "agent_events"] → 外部系统实时响应
│
├→ [前端仪表盘] 实时显示“研究员已获取数据”
├→ [日志服务] 写入结构化日志
└→ [告警服务] 检测异常事件(如 confidence < 0.5)
# agents/researcher.py
from event_bus.redis_adapter import RedisEventBus
# 全局 EventBus 实例(生产环境建议用依赖注入或 Singleton)
redis_bus = RedisEventBus()
def researcher_agent(state: SharedContext) -> Dict[str, Any]:
data_snippet = "AI市场规模2025年预计达$3000亿"
confidence_score = 0.92
# 写入 LangGraph 内部 event_queue(用于状态机流转)
internal_event = {
"event_id": str(uuid.uuid4()),
"event_type": "context.update",
"source": "researcher",
"target": "writer",
"payload": {
"key": "market_data",
"value": data_snippet,
"confidence": confidence_score
}
}
# 同时发布到 Redis(用于外部系统监听)
redis_bus.publish("agent_events", {
"event_type": "researcher.data_fetched",
"source_agent": "researcher",
"payload": {
"data_snippet": data_snippet,
"confidence": confidence_score,
"task_id": state["task_id"]
},
"context_version": state["context_version"]
})
return {
"shared_memory": {**state["shared_memory"], "latest_data": data_snippet},
"event_queue": [internal_event], # 供 LangGraph 内部消费
"agent_states": { ... }
}
# monitor/realtime_logger.py
import json
from event_bus.redis_adapter import RedisEventBus
def on_agent_event(message):
data = json.loads(message['data'])
event_type = data["event_type"]
if event_type == "researcher.data_fetched":
print(f" 实时监控: 研究员获取数据: {data['payload']['data_snippet']}")
elif event_type == "report.draft_ready":
print(f" 报告已生成,长度: {data['payload']['length']} 字符")
# 启动监听
bus = RedisEventBus()
bus.subscribe("agent_events", on_agent_event)
我们也可以在状态更新时自动发布快照事件。
# checkpoint/event_trigger.py
from langgraph.checkpoint.base import BaseCheckpointSaver
class EventEmittingCheckpointer(BaseCheckpointSaver):
def put(self, config, checkpoint, metadata):
# 先调用原生保存逻辑
super().put(config, checkpoint, metadata)
# 发布“状态已保存”事件到 EventBus
redis_bus.publish("system_events", {
"event_type": "checkpoint.saved",
"thread_id": config["configurable"]["thread_id"],
"version": checkpoint["channel_versions"]["__root__"],
"timestamp": metadata["write_timestamp"]
})
注意:LangGraph 的 BaseCheckpointSaver
是底层接口,自定义要谨慎。更推荐在节点返回后手动发布。
角色感知上下文(Role-Aware Context)
不同角色的Agent关注的上下文维度不同:
- Planner 关注任务结构与依赖关系
- Researcher 关注查询意图与数据新鲜度
因此,上下文引擎应支持:
- 视图隔离(每个Agent看到自己需要的上下文子集)
- 权限控制(某些上下文字段只读/可写)
- 个性化摘要(自动为每个Agent生成“上下文简报”)
我们在节点内实现“视图生成器”:
def get_role_view(state: SharedContext, role: str) -> Dict[str, Any]:
view_templates = {
"planner": ["task_goal", "current_phase", "agent_states"],
"researcher": ["task_goal", "shared_memory.queries", "task_constraints"],
"writer": ["shared_memory.latest_data", "task_goal"]
}
view = {}
for key in view_templates.get(role, []):
if '.' in key:
parts = key.split('.')
val = state
for part in parts:
val = val.get(part, {}) if isinstance(val, dict) else {}
view[key] = val
else:
view[key] = state.get(key)
return view
# 在 researcher_agent 中调用
view = get_role_view(state, "researcher")
print(f"[Researcher View] {view}")
上下文演化与版本控制
上下文不是静态的 —— 它随时间推移、任务推进、外部输入而演化。我们需要:
- 记录上下文变更历史(类似 Git)
- 支持“上下文快照”用于回滚或对比
- 检测上下文漂移(Context Drift)并触发重校准
例如:当用户中途修改了报告目标,系统应自动通知所有Agent,并触发 Planner 重新规划。
LangGraph 的 Checkpointer
是天然解决方案。
# graph_builder.py
from langgraph.graph import StateGraph
from langgraph.checkpoint.sqlite import SqliteSaver
from .state import SharedContext
from .agents import planner_agent, researcher_agent, writer_agent
# 初始化检查点(持久化 + 版本历史)
memory = SqliteSaver.from_conn_string("checkpoints.db")
def build_graph():
workflow = StateGraph(SharedContext)
workflow.add_node("planner", planner_agent)
workflow.add_node("researcher", researcher_agent)
workflow.add_node("writer", writer_agent)
workflow.set_entry_point("planner")
workflow.add_edge("planner", "researcher")
workflow.add_edge("researcher", "writer")
# 编译时绑定检查点
return workflow.compile(checkpointer=memory)
手动触发快照(当关键字段变更时)
# agents/planner.py
def planner_agent(state: SharedContext) -> Dict[str, Any]:
new_phase = "data_collection"
# 当 phase 改变时,强制创建快照(用于回滚)
if state["current_phase"] != new_phase:
# 在返回值中不直接支持“创建快照”,但可通过外部机制或自定义 reducer 实现
# 这里我们通过 event 通知外部系统创建快照
snapshot_event = {
"event_id": str(uuid.uuid4()),
"event_type": "snapshot.request",
"reason": f"phase_changed: {state['current_phase']} → {new_phase}",
"manual_trigger": True
}
return {
"current_phase": new_phase,
"event_queue": [snapshot_event],
# ... 其他字段
}
回滚到历史版本(外部调用)
# rollback_manager.py
from .graph_builder import app
def rollback_to_version(thread_id: str, target_version: int):
"""回滚到指定版本"""
# 获取所有历史状态
history = list(app.get_state_history({"configurable": {"thread_id": thread_id}}))
for snapshot in reversed(history):
if snapshot.values["context_version"] == target_version:
# 执行回滚
app.update_state(
{"configurable": {"thread_id": thread_id}},
snapshot.values, # 完整状态覆盖
as_node="system_rollback" # 虚拟节点名
)
print(f"已回滚到版本 {target_version}")
return True
return False
检测上下文漂移(例如用户修改目标)
def detect_context_drift(current_state: SharedContext, baseline: Dict) -> bool:
"""检测关键字段是否被外部修改"""
drift_fields = ["task_goal", "task_constraints"]
for field in drift_fields:
if current_state.get(field) != baseline.get(field):
return True
return False
if detect_context_drift(latest_state, original_baseline):
# 触发 Planner 重新规划
app.update_state(
{"configurable": {"thread_id": thread_id}},
{"event_queue": [{
"event_id": "drift_detected",
"event_type": "system.reset",
"payload": {"reason": "task_goal_modified"}
}]},
as_node="planner" # 强制在 planner 上下文中处理
)
最佳实践
上下文压缩与摘要
当上下文过长时(如超过 LLM 的上下文窗口),使用:
- Map-Reduce 摘要
- 关键信息提取(Key-Value Extraction)
- 向量化 + 相似度检索(只注入最相关的上下文)
上下文反思(Context Reflection)
定期让一个“Meta-Agent”或“Critic Agent”审查当前上下文:
- 是否偏离原始目标?
- 是否存在矛盾信息?
- 是否需要人类介入?
外部上下文注入
从外部系统(数据库、API、用户反馈)动态注入上下文
context["user_feedback"] = get_latest_feedback()
context["market_data"] = fetch_real_time_data()
最近建了langgraph & langgraph 智能体开发交流群,感兴趣的朋友可以点赞关注后入群交流
本文转载自AI 博物院 作者:longyunfeigu
