LangGraph

一句话定位

LangGraph 不是一个像 Claude Code / opencode 那样的单体 CLI agent harness,而是一个通用的图编排 + 持久化执行引擎(内部代号 “Pregel”,BSP/bulk-synchronous-parallel 模型),create_react_agent 只是搭在这套引擎之上的一个”预制件”(prebuilt),且在这个 commit 里已带 legacy 色彩——LangChain 官方更推荐的新入口是另一个包 langchain.agents.create_agent

核心架构总览

Monorepo,独立版本化的子库(libs/),本次分析针对 commit be999ad38a8443a2a64d468e33c1228ca5aede4f

  • libs/langgraph/(核心引擎,langgraph 包 = 1.2.7)——状态图编译器、Pregel 执行循环、channels(状态归约)、checkpoint 挂接、streaming。
  • libs/prebuilt/langgraph-prebuilt = 1.1.0)——create_react_agent(ReAct 风格工具调用循环)、ToolNode(工具派发)、ValidationNode
  • libs/checkpoint/langgraph-checkpoint)——抽象 BaseCheckpointSaver(短期/线程持久化)、BaseStore(长期/跨线程记忆)、BaseCache(节点级 memoization)。仓库内只带内存参考实现。
  • libs/checkpoint-sqlite/libs/checkpoint-postgres/——具体 checkpointer/store 后端。Redis/MongoDB/Oracle 版本是独立 pip 包(如 langgraph-checkpoint-redis),不在本仓库内(据官方 memory 文档确认)。
  • libs/cli/langgraph-cli)——开发服务器/部署工具:把一张图构建成 Docker 镜像跑成 HTTP 服务(LangGraph Platform/Server)。这是本仓库里最接近”沙箱”的东西——是部署容器,不是逐工具调用的执行沙箱。
  • libs/sdk-py/libs/sdk-js/——面向已部署 LangGraph Server 的客户端 SDK,其中包含服务端 Auth 类(认证/鉴权 hook)——“安全/权限”维度具体落地的地方。

关键范围事实:这个 commit 里大量”agent 形状”的功能(AgentState/AgentStatePydantic TypedDict、HumanInterrupt/HumanInterruptConfig/ActionRequest 这套 HITL 审批类型)都带 @deprecated(...) 装饰器,指向 langchain.agents / langchain.agents.interrupt(另一个更新的包)。langgraph.prebuilt.create_react_agent 仍可用但偏 legacy。多 agent supervisor/swarm 模式不在本仓库内,官方放在独立仓库 langchain-ai/langgraph-supervisor-py(经搜索确认存在,本轮未克隆读取)。仓库内 docs/ 目录已只剩一个重定向文件 docs/llms.txt,官方文档实际托管在 docs.langchain.com——本次分析对该站点做了两次活取(memory、observability 两页)。

Agent Loop(主循环 / 何时继续何时停)

两层结构:

  • 通用引擎层:Pregel 的 BSP “superstep” 循环,libs/langgraph/langgraph/pregel/_loop.py(1988 行)。PregelLoop.tick() 计算下一批可执行任务 → 检查 interrupt_before → 执行任务 → after_tick() 应用写入、打 checkpoint、检查 interrupt_after。循环终止条件:任务队列为空(status="done"),或 step > stopstop = step + recursion_limit + 1pregel/_loop.py:1701,1961),触发 GraphRecursionError(抛出点在 pregel/main.py:3017-3026,另一处校验在 pregel/main.py:2578)。这是硬性递归上限,与具体 agent 逻辑无关。
  • ReAct agent 特定的”继续/停止”libs/prebuilt/langgraph/prebuilt/chat_agent_executor.py::should_continue(第 831 行)——若最后一条 AIMessage 没有 tool_calls 则停(跳转 END 或 post-hook/structured-response 节点);否则为每个 tool call 派发一个 Send("tools", ...)(并行执行)。另有一个软性早停 _are_more_steps_needed(第 620 行):remaining_steps(用户可配置的 per-state 计数器,独立于 recursion_limit)低于 1-2 时强制提前返回”步数不够”的回复,专门为了给”直接返回工具结果”的收尾留出余量。

记忆与上下文管理(压缩、长期记忆、会话持久化)

  • 短期(线程作用域)BaseCheckpointSaver + 具体后端(InMemorySaverSqliteSaverPostgresSaver;Redis/Mongo/Oracle 为独立包)——按 thread_id 持久化完整图状态快照,支撑多轮对话与可恢复执行。
  • 长期(跨线程)BaseStorelibs/checkpoint/langgraph/store/base/__init__.py)——分层命名空间(namespace: tuple[str,...])的 KV 存储,可选接语义搜索索引(InMemoryStore(index={"embed":..., "dims":...}),官方 memory 文档确认)。节点/工具内通过 runtime.store.get/put/search 访问。
  • 上下文窗口管理(原生、非学习型):trim_messages(基于 token 预算的滑窗,来自 langchain_core)与 RemoveMessage/REMOVE_ALL_MESSAGES(通过 add_messages reducer 永久删除,libs/langgraph/langgraph/graph/message.py)。摘要压缩不是 langgraph core 原生能力——官方文档示例里的 SummarizationNode/RunningSummary 是从独立的 langmem 包导入的;langgraph 只提供机制(用户自写 summarize_conversation 节点 + RemoveMessage 裁剪),不内置摘要器。
  • pre_model_hook/post_model_hookchat_agent_executor.py)是 prebuilt ReAct agent 里每次模型调用前后的既定插入点,用于裁剪/摘要/护栏。

工具体系(定义/调用协议/注册/权限)

  • 工具是普通 Python callable 或 BaseTool(langchain-core)实例;ToolNodelibs/prebuilt/langgraph/prebuilt/tool_node.py:622,全文件 2030 行)把一组工具包装成图节点。
  • 派发:模型最后一条 AIMessagetool_calls 一一映射为工具执行,通过 get_executor_for_config 并行执行(concurrent.futures/asyncio)。
  • 注册/schema:标准 langchain @tool 装饰函数自动生成 JSON schema,模型侧通过 .bind_tools(tools) 绑定(chat_agent_executor.py:586)。
  • 特殊注入注解Annotated[T, InjectedState] / Annotated[T, InjectedStore]——让工具接收图状态或 store 对象作为参数,但对模型的工具 schema 隐藏这些参数(tool_node.py 约 1753、1829 行)。
  • 类权限原语:工具可以返回 Command 对象而非普通值,直接修改图状态或触发 goto——这是工具自行实现审批/路由逻辑的组合点;langgraph core 没有独立的声明式工具权限清单(对比 opencode 的通配符权限引擎)。
  • 错误处理:handle_tool_errors 参数支持 bool/str/异常类型/tuple/callable;默认策略(_default_handle_tool_errors,第 383 行)捕获参数校验类错误并包装为 ToolMessage,但真正的执行错误会继续向上抛出。

Prompt 设计(系统提示结构、动态组装)

create_react_agentprompt 参数(Prompt 类型别名,第 121 行)接受:None(裸消息)、str(包装成单条 SystemMessage 前置)、SystemMessage、callable (state) -> LanguageModelInput(完全动态,可读 state/context)、或完整 Runnable_get_prompt_runnable(第 137 行)据此构建 RunnableCallable

没有固定的多段式系统提示模板(不像 Claude Code/opencode 那样内置”environment/skills/reminders”结构)——prompt 组装完全交给用户;langgraph 只提供注入点 + Runtime[ContextT].context)支持按次调用动态取值(如按调用切换模型家族,见 libs/cli/examples/graphs/agent.py)。

Router / 编排(任务分解、多 agent、子 agent)

  • 核心原语均在 libs/langgraph/langgraph/types.pySend(node, arg)——向同一/不同节点派发自定义 per-branch 状态(并行 map-reduce、并行工具调用);Command(update=..., resume=..., goto=..., graph=Command.PARENT)——更新状态 + 跳转节点,可选跳到父图(这是子图/子 agent 能够操纵调用方图状态的机制基础,即多 agent”handoff”的底层实现)。
  • 子图组合:一个编译好的 StateGraphCompiledStateGraph)可以作为节点加入另一张图(满足 node/Runnable 协议)——这是层级化多 agent 系统的组合机制,在 graph/state.py 中有结构性确认(子图 checkpointer 继承相关注释,约 283、1187 行)。
  • 本仓库内没有内置的 supervisor/swarm/planner。官方 supervisor 模式在独立仓库 langchain-ai/langgraph-supervisor-py(经搜索确认,本轮未克隆,超出本 dossier 范围,留作交叉引用)。通用条件路由通过 add_conditional_edges(node, routing_fn, path_map)graph/state.py:969)实现,should_continueroute_tool_responsespost_model_hook_router(均在 chat_agent_executor.py)都是这个机制的实例。

Skill / 插件体系

未找到 / 不适用。libs/langgraphlibs/prebuilt 里没有找到 skill 文件加载、插件 manifest 发现机制,没有类似 Claude Code 的 SKILL.md 或 opencode 插件 Hooks 接口的等价物。LangGraph 的可扩展性模型是”写一个 Python 节点/工具/子图,接进图里”——组合发生在代码层面,不是运行时发现插件。

自进化能力(自我改进 / 学习型记忆 / eval 驱动纠错)

langgraph core 内未找到 / 不适用。libs/langgraphlibs/prebuilt 全库搜索未发现反思循环、自我改进机制或 eval 门控的自动纠错(唯一相关命中是 tool_node.py:572 一处无关的注释用语 “injection without repeated reflection”,并非功能)。BaseCache(节点 memoization)与 checkpoint “time travel”(get_state_history/update_statepregel/main.py:1479,2530)支持人工调试/回溯与分叉过去状态,不是自动化自我纠错。这个维度确实未实现——LangGraph 是编排基座,任何自我改进循环都要由用户以普通图节点的形式自行搭建。

可观测性(日志 / trace 格式)

  • 原生/本地stream_mode="debug" 发出结构化的 TaskPayload/CheckpointPayload 事件(libs/langgraph/langgraph/pregel/debug.py::map_debug_tasksmap_debug_checkpoint)——含 task id/name/input/触发条件、过滤后的 config tags、checkpoint 元数据。除这套 streaming 事件 schema 和 checkpointer 持久化的内容外,没有专有的落盘日志/trace 文件格式。
  • 一等观测产品是 LangSmith(独立 SaaS,不在本仓库内):通过 LANGSMITH_TRACING=true + LANGSMITH_API_KEY 启用;langsmith.tracing_context() 上下文管理器支持选择性/动态 tracing 及每次调用的 project/tags/metadata;LangChainTracer 回调可配 anonymizer=create_anonymizer([...]),在数据进入 LangSmith 前做脱敏(如遮蔽 SSN)。此结论来自对 https://docs.langchain.com/oss/python/langgraph/observability 的活取确认,已存档于 key-files/official-doc-observability.md

安全与权限(审批门、密钥管理)

  • libs/langgraph core 内没有节点/工具级别的权限引擎(对比某些 harness 的逐工具通配符审批规则)。
  • 服务端鉴权/授权确实存在,位于 libs/sdk-py/langgraph_sdk/auth/__init__.py(875 行):Auth 类——@auth.authenticate handler 校验 bearer token 返回 MinimalUserDict{identity, permissions}@auth.on / @auth.on.threads.create/.read/.search / @auth.on.store 等——针对每种资源(runs|threads|crons|assistants|store,类型定义见 auth/types.pyAuthContext)、每种动作的细粒度授权回调,可返回布尔值允许/拒绝,或返回 FilterType 字典做行级作用域过滤(如 {"owner": ctx.user.identity})。通过部署配置 langgraph.json"auth": {"path": "./auth.py:my_auth"} 接入,由 LangGraph Server 强制执行,而非开源图执行库本身。
  • 工具调用的人机审批门通过通用的 interrupt() 原语实现(types.py:811,抛出 GraphInterrupt,要求有 checkpointer,通过 Command(resume=...) 恢复),配合(本 commit 已弃用、迁往 langchain.agents.interrupt)的 HumanInterrupt/HumanInterruptConfig 形状——allow_ignore/allow_respond/allow_edit/allow_accept 四个标志位描述待处理动作的可交互方式(libs/prebuilt/langgraph/prebuilt/interrupt.py)。

沙箱与执行隔离

在图执行层面未实现。 节点就是普通的 in-process Python callable(同步或异步),没有针对节点/工具执行的 OS 级沙箱、seccomp、容器或虚拟机隔离。libs/langgraph/langgraph/_internal/_timeout.py 明确写明同步节点”无法在进程内安全取消”,即超时是尽力而为/仅异步生效,不是靠进程隔离强制执行。本仓库内唯一的容器/隔离边界在部署层libs/cli/langgraph_cli/docker.py 构建 Docker 镜像(默认带 Postgres 服务)把整张图跑成 HTTP 服务——隔离的是部署的服务,不是单次运行内的逐工具调用。

与模型的协同设计

  • Runtime[ContextT] + StateGraph/create_react_agent 上的 context_schema,让节点/prompt 构建函数可以按每次调用的任意上下文分支(例如 libs/cli/examples/graphs/agent.pyAgentContext{model: Literal["anthropic","openai"]}ChatAnthropic/ChatOpenAI 实例间切换)。
  • create_react_agentmodel 参数既可以是静态 BaseChatModel,也可以是动态 callable (state, runtime) -> LanguageModelLike,按次调用解析(_resolve_model/_aresolve_model,第 599-618 行)——支持依据 state 在对话中途换模型。
  • 结构化输出(response_format 参数,接受”(system_prompt, schema)“元组或裸 schema)通过 .with_structured_output() 实现,作为独立图节点加入(generate_structured_response),而非揉进主循环——这是刻意把”工具调用轮次”和”结构化输出轮次”分离的设计选择。
  • langgraph core 本身不内置任何模型专属 prompt 模板或模型家族分支逻辑(不像 opencode 那样按模型家族维护独立 .txt prompt 文件)——这类逻辑留给用户的 prompt callable/Runtime 自行处理。

轨迹利用(session/trajectory 是否反哺训练/评测)

本仓库内未实现。 LangGraph 通过 checkpoint 持久化完整状态历史(get_state_historyupdate_state/fork,pregel/main.py:1479,2530),支持”time travel”式回放/调试和从任意历史 checkpoint 分叉,但这是人工的开发者调试工具,不是自动把轨迹回灌进模型训练或 eval harness 的流水线。LangSmith(外部产品)捕获的 trace 数据理论上可以通过 LangSmith 自身产品面转成 eval 数据集,但这个机制在本仓库之外,本次会话未验证(超出范围,记为”在 langgraph/langgraph 仓库内未找到”)。

与同类 harness 的关键差异(1-3 条,概述)

  • 定位不同:LangGraph 是通用图编排/持久化执行引擎,不是单体 agent CLI——create_react_agent 只是众多可能的图拓扑之一,且在本 commit 中已偏 legacy(官方新入口 langchain.agents.create_agent 是另一个包)。这与 Claude Code/opencode 等”agent 循环即产品本体”的 harness 形成结构性差异。
  • 安全模型分层:工具执行层没有权限引擎/沙箱,安全边界完全推到部署层(Docker 容器)和服务层(LangGraph Server 的 Auth 类),核心库本身对”允许这个工具跑吗”没有意见。
  • 可观测性外包给独立 SaaS:原生只有 stream_mode="debug" 这一种事件流,没有专有本地 trace 文件格式;生产级可观测性依赖外部产品 LangSmith,这点与自带完整本地日志/trace 系统的 harness不同。
  • 跨 harness 系统对比留待 synthesis 阶段。

原始源码定位

  • repo: https://github.com/langchain-ai/langgraph
  • commit/version analyzed: be999ad38a8443a2a64d468e33c1228ca5aede4flanggraph core = 1.2.7,langgraph-prebuilt = 1.1.0)
  • 关键文件列表(相对仓库根目录):
    • libs/langgraph/langgraph/pregel/_loop.py
    • libs/langgraph/langgraph/pregel/_algo.py
    • libs/langgraph/langgraph/pregel/main.py
    • libs/langgraph/langgraph/pregel/debug.py
    • libs/langgraph/langgraph/types.py
    • libs/langgraph/langgraph/runtime.py
    • libs/langgraph/langgraph/graph/message.py
    • libs/langgraph/langgraph/errors.py
    • libs/langgraph/langgraph/_internal/_retry.py
    • libs/langgraph/langgraph/_internal/_timeout.py
    • libs/langgraph/langgraph/channels/*.py
    • libs/prebuilt/langgraph/prebuilt/chat_agent_executor.py
    • libs/prebuilt/langgraph/prebuilt/tool_node.py
    • libs/prebuilt/langgraph/prebuilt/interrupt.py
    • libs/checkpoint/langgraph/checkpoint/base/__init__.py
    • libs/checkpoint/langgraph/store/base/__init__.py
    • libs/checkpoint/langgraph/cache/base/__init__.py
    • libs/sdk-py/langgraph_sdk/auth/__init__.py
    • libs/sdk-py/langgraph_sdk/auth/types.py
    • libs/cli/langgraph_cli/docker.py
    • libs/cli/langgraph_cli/cli.py
    • libs/cli/examples/graphs/agent.py

一手源存档(sources/)

/Users/zhao/projects/self-wiki/ai-research/sources/harness/langgraph/ 下:

  • NOTES.md —— Stage 1 完整调研笔记(本页写作的直接依据)
  • key-files/pregel/_loop.py_algo.pymain.pyerrors.pyruntime.pytypes.pygraph_message.py
  • key-files/prebuilt/chat_agent_executor.pytool_node.pyinterrupt.py
  • key-files/checkpoint/checkpoint_base.pystore_base.pycache_base.py
  • key-files/sdk-auth/auth_init.pyauth_types.py
  • key-files/examples/simple_agent_example.py
  • key-files/official-doc-add-memory.md(活取自 docs.langchain.com)
  • key-files/official-doc-observability.md(活取自 docs.langchain.com)