从 Claude Code 到 DeerFlow:深入理解 LangGraph 在 AI Agent 架构中的核心价值

1 阅读15分钟

📋 摘要

Claude Code 采用极简的 Agent Loop 架构,适合单用户 CLI 场景,追求简单高效;DeerFlow 选用 LangGraph 构建企业级多用户 Web 应用,解决状态管理、并发、可观测性等复杂问题。架构选型的核心是场景匹配:简单场景用简单方案,复杂场景需要系统化框架。

📑 目录

前言

在 AI 应用开发领域,一个永恒的话题是:如何在简单性和扩展性之间找到平衡?

Claude Code 作为 Anthropic 官方的 CLI 编程助手,以其简洁优雅的实现赢得了开发者的青睐。然而,当我们面对更复杂的生产级应用场景时,是否还能延续这种简单?DeerFlow 项目给出了答案——它选择了 LangGraph 作为 AI Agent 运行时的核心引擎。

本文将从架构演进的视角,深入剖析为什么 Claude Code 不需要 LangGraph,而 DeerFlow 却离不开它。通过核心源码的分析,帮助你理解 LangGraph 的设计哲学,以及在实际项目中如何做出正确的架构选型。

一、AI Agent 开发的核心挑战

在深入架构对比之前,让我们先明确 AI Agent 开发面临的核心挑战:

1.1 状态管理的困境

传统的 LLM 应用是无状态的——每次调用都是独立的,模型不会记住你上一句说了什么。这对于简单的问答场景或许足够,但对于需要多轮对话、任务分解、工具调用的 Agent 应用来说,状态管理是绕不开的难题。

状态管理需要解决的核心问题:

  • 对话历史:如何高效存储和检索历史消息?
  • 上下文维护:如何在对话过程中保持必要的上下文信息?
  • 断点恢复:如果服务重启或网络中断,如何从上次中断的地方继续?
  • 并发隔离:多用户场景下,如何确保每个用户的对话互不干扰?

1.2 工具调用的复杂性

现代 AI Agent 的核心能力之一是工具调用——模型能够自主决定何时调用工具、调用哪个工具、如何处理工具返回的结果。

一个典型的工具调用流程:

用户输入 → 模型推理 → 决定调用工具 → 执行工具 → 返回结果 → 模型继续推理 → ...

这个循环可能执行多次,直到模型认为任务完成。在这个过程中,需要处理:

  • 工具调用的编排与调度
  • 工具执行的超时与错误处理
  • 工具结果的格式化与注入

1.3 可观测性与调试

生产环境中的 AI Agent 需要具备可观测性——开发者需要知道:

  • Agent 的决策过程是什么?
  • 调用了哪些工具?参数是什么?
  • 为什么会出现某个错误?
  • Token 消耗情况如何?

二、Claude Code 的极简哲学

2.1 架构概览

Claude Code 是 Anthropic 官方推出的命令行 AI 编程助手。作为一个 CLI 工具,它采用了极简的架构设计——Agent Loop 模式

┌─────────────────────────────────────────────────────────────┐
│                    Claude Code 架构                          │
├─────────────────────────────────────────────────────────────┤
│  CLI 层                                                      │
│  ├── 用户输入处理                                            │
│  ├── 输出渲染 (Markdown、语法高亮)                           │
│  └── 交互式确认                                              │
├─────────────────────────────────────────────────────────────┤
│  Agent Loop (核心循环)                                       │
│  while True:                                                 │
│    1. 构建消息 (system + history + user input)              │
│    2. 调用 Anthropic API                                     │
│    3. 解析响应:                                              │
│       - text → 输出给用户                                    │
│       - tool_use → 执行工具 → 添加 tool_result → 继续       │
│    4. 持久化到本地文件                                       │
├─────────────────────────────────────────────────────────────┤
│  工具层                                                      │
│  ├── Read/Write/Edit 文件操作                               │
│  ├── Bash 命令执行                                          │
│  └── Glob/Grep 文件搜索                                     │
├─────────────────────────────────────────────────────────────┤
│  持久化层                                                    │
│  ~/.claude/projects/{project}/                              │
│  ├── memory.md     # 项目记忆                               │
│  └── history.json  # 对话历史                               │
└─────────────────────────────────────────────────────────────┘

2.2 核心实现:Agent Loop

Claude Code 的核心是一个简洁的循环结构:

# Claude Code 核心循环 (概念简化版,实际使用流式响应)

class ClaudeCode:
    def __init__(self):
        self.messages = []  # 对话历史(内存中)
        self.tools = [
            {"name": "read_file", "description": "...", "input_schema": {...}},
            {"name": "write_file", "description": "...", "input_schema": {...}},
            {"name": "bash", "description": "...", "input_schema": {...}},
            # ... 工具定义需包含完整的 JSON Schema
        ]
    
    def run(self, user_input: str):
        # 1. 添加用户消息到历史
        self.messages.append({
            "role": "user", 
            "content": user_input
        })
        
        # 2. Agent 主循环(实际使用 stream=True 流式处理)
        while True:
            # 调用 Anthropic Messages API
            with anthropic.messages.stream(
                model="claude-sonnet-4",
                system=self.build_system_prompt(),
                messages=self.messages,
                tools=self.tools,
                max_tokens=8192,
            ) as stream:
                response = stream.get_final_message()
            
            # 添加助手响应到历史
            self.messages.append({
                "role": "assistant", 
                "content": response.content
            })
            
            # 检查是否有工具调用
            tool_calls = [
                block for block in response.content 
                if block.type == "tool_use"
            ]
            
            if not tool_calls:
                # 没有工具调用,直接输出文本并结束
                self.render_output(response.content)
                break
            
            # 执行工具并收集结果
            tool_results = []
            for tool_call in tool_calls:
                result = self.execute_tool(tool_call)
                tool_results.append({
                    "type": "tool_result",
                    "tool_use_id": tool_call.id,
                    "content": result,
                })
            
            # 将工具结果添加到消息历史
            self.messages.append({
                "role": "user",
                "content": tool_results
            })
        
        # 3. 持久化到本地文件
        self.save_history()
    
    def build_system_prompt(self) -> str:
        """构建系统提示,包含工作目录、项目记忆等上下文"""
        return f"""
        You are Claude Code, an AI programming assistant.
        
        # 当前环境
        Working directory: {os.getcwd()}
        
        # 项目记忆
        {self.load_memory()}
        
        # 可用工具说明
        {self.format_tools_description()}
        """
    
    def save_history(self):
        """保存对话历史到本地 JSON 文件"""
        history_path = Path.home() / ".claude" / "projects" / self.project_name / "history.json"
        with open(history_path, "w") as f:
            json.dump(self.messages, f)

注意:实际 Claude Code 使用 stream=True 流式响应,而非同步阻塞调用,以提供实时反馈。工具定义需要完整的 JSON Schema 格式。

2.3 为什么 Claude Code 不需要 LangGraph?

Claude Code 选择极简架构的原因在于它的场景特点

特点说明对架构的影响
单用户 CLI一次只有一个用户使用无需并发处理、无需会话隔离
同步阻塞交互用户等待 AI 响应无需复杂的异步架构
本地持久化数据保存在用户机器上JSON 文件足够,无需数据库
直接 API 调用只用 Anthropic API原生支持工具调用、流式响应
功能固定不需要扩展插件无需可插拔架构

这种极简设计带来的优势:

  • 易于理解:整个核心逻辑一目了然
  • 易于调试:没有复杂的抽象层,问题定位直接
  • 启动快速:无需初始化复杂的运行时环境
  • 资源占用低:没有额外的中间件开销

三、DeerFlow 的企业级架构

3.1 场景差异

DeerFlow 是一个多用户 Web 应用,其场景与 Claude Code 有着本质区别:

┌─────────────────────────────────────────────────────────────┐
│                 DeerFlow 的场景挑战                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 多用户并发                                               │
│     └── 需要同时处理多个用户的对话请求                        │
│                                                             │
│  2. 服务化架构                                               │
│     └── 前后端分离、HTTP API、SSE 流式响应                   │
│                                                             │
│  3. 复杂状态管理                                             │
│     ├── ThreadState 包含 messages、sandbox、artifacts...    │
│     └── 每个线程有独立的工作空间、上传文件、生成文件          │
│                                                             │
│  4. 可扩展中间件                                             │
│     ├── 14 个中间件处理不同关注点                            │
│     └── 需要支持自定义中间件注入                             │
│                                                             │
│  5. 多模型支持                                               │
│     ├── OpenAI、Anthropic、DeepSeek、Google 等              │
│     └── 需要统一的模型抽象层                                 │
│                                                             │
│  6. 子 Agent 系统                                            │
│     └── 并发执行多个子任务,需要线程池和状态追踪              │
│                                                             │
│  7. 可观测性                                                 │
│     └── 集成 LangSmith/Langfuse 进行追踪                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

3.2 LangGraph 的核心价值

面对上述挑战,LangGraph 提供了系统性的解决方案:

┌─────────────────────────────────────────────────────────────┐
│                  LangGraph 提供的能力                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ✅ 有状态管理                                               │
│     ThreadState 自动维护对话上下文、沙箱状态、artifacts 等   │
│                                                             │
│  ✅ 持久化引擎                                               │
│     Checkpointer 自动保存状态,支持 SQLite、Redis 等后端     │
│                                                             │
│  ✅ 工具编排                                                 │
│     自动处理 tool_calls → tool_messages 循环                │
│                                                             │
│  ✅ 中间件系统                                               │
│     可插拔的中间件链处理跨切面逻辑                           │
│                                                             │
│  ✅ 流式响应                                                 │
│     原生支持 SSE,提供实时反馈                               │
│                                                             │
│  ✅ 断线重连                                                 │
│     支持从任意检查点恢复执行                                 │
│                                                             │
│  ✅ 可观测性                                                 │
│     集成 LangSmith/Langfuse 进行全链路追踪                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

四、核心源码剖析

4.1 LangGraph 服务配置

DeerFlow 通过 langgraph.json 配置 LangGraph Server:

{
  "$schema": "https://langgra.ph/schema.json",
  "python_version": "3.12",
  "dependencies": ["."],
  "env": ".env",
  "graphs": {
    "lead_agent": "deerflow.agents:make_lead_agent"
  },
  "checkpointer": {
    "path": "./packages/harness/deerflow/agents/checkpointer/async_provider.py:make_checkpointer"
  }
}

注意dependencies 是字符串数组格式,支持指定多个依赖路径。

关键配置解析:

配置项说明
graphs.lead_agent定义 Agent 入口点,指向 make_lead_agent 工厂函数
checkpointer状态持久化后端,用于保存和恢复对话状态

4.2 Agent 工厂函数

当 LangGraph Server 接收到请求时,会调用 make_lead_agent 创建 Agent 实例:

def make_lead_agent(config: RunnableConfig):
    """
    LangGraph Server 调用此函数创建 Agent 实例
    
    参数:
        config: 运行时配置,包含 model_name、thinking_enabled 等
    
    返回:
        CompiledStateGraph: 编译后的 Agent 图
    """
    cfg = config.get("configurable", {})

    # 解析运行时配置
    thinking_enabled = cfg.get("thinking_enabled", True)
    reasoning_effort = cfg.get("reasoning_effort", None)
    requested_model_name = cfg.get("model_name") or cfg.get("model")
    is_plan_mode = cfg.get("is_plan_mode", False)
    subagent_enabled = cfg.get("subagent_enabled", False)
    max_concurrent_subagents = cfg.get("max_concurrent_subagents", 3)
    is_bootstrap = cfg.get("is_bootstrap", False)  # 特殊模式:创建自定义 Agent
    agent_name = cfg.get("agent_name")

    # 解析模型名称(支持自定义 Agent 配置)
    agent_config = load_agent_config(agent_name) if not is_bootstrap else None
    agent_model_name = agent_config.model if agent_config and agent_config.model else _resolve_model_name()
    model_name = requested_model_name or agent_model_name

    # 验证模型能力
    app_config = get_app_config()
    model_config = app_config.get_model_config(model_name) if model_name else None
    
    if thinking_enabled and not model_config.supports_thinking:
        logger.warning(f"Thinking mode enabled but model '{model_name}' does not support it")
        thinking_enabled = False

    # 注入运行元数据(用于 LangSmith 追踪)
    if "metadata" not in config:
        config["metadata"] = {}
    config["metadata"].update({
        "agent_name": agent_name or "default",
        "model_name": model_name or "default",
        "thinking_enabled": thinking_enabled,
        "is_plan_mode": is_plan_mode,
        "subagent_enabled": subagent_enabled,
    })

    # Bootstrap 模式:特殊 Agent 用于初始自定义 Agent 创建流程
    if is_bootstrap:
        return create_agent(
            model=create_chat_model(name=model_name, thinking_enabled=thinking_enabled),
            tools=get_available_tools(model_name=model_name, subagent_enabled=subagent_enabled) + [setup_agent],
            middleware=_build_middlewares(config, model_name=model_name),
            system_prompt=apply_prompt_template(subagent_enabled=subagent_enabled, max_concurrent_subagents=max_concurrent_subagents, available_skills=set(["bootstrap"])),
            state_schema=ThreadState,
        )

    # 默认 Lead Agent
    return create_agent(
        model=create_chat_model(
            name=model_name, 
            thinking_enabled=thinking_enabled, 
            reasoning_effort=reasoning_effort
        ),
        tools=get_available_tools(
            model_name=model_name, 
            groups=agent_config.tool_groups if agent_config else None, 
            subagent_enabled=subagent_enabled
        ),
        middleware=_build_middlewares(config, model_name=model_name, agent_name=agent_name),
        system_prompt=apply_prompt_template(
            subagent_enabled=subagent_enabled, 
            max_concurrent_subagents=max_concurrent_subagents, 
            agent_name=agent_name, 
            available_skills=set(agent_config.skills) if agent_config and agent_config.skills is not None else None
        ),
        state_schema=ThreadState,
    )

4.3 线程状态定义

LangGraph 的核心概念之一是状态。DeerFlow 定义了 ThreadState 来承载对话过程中的所有状态信息:

from typing import Annotated, NotRequired, TypedDict
from langchain.agents import AgentState


class SandboxState(TypedDict):
    """沙箱状态"""
    sandbox_id: NotRequired[str | None]


class ThreadDataState(TypedDict):
    """线程数据路径状态"""
    workspace_path: NotRequired[str | None]
    uploads_path: NotRequired[str | None]
    outputs_path: NotRequired[str | None]


class ViewedImageData(TypedDict):
    """已查看图片的数据"""
    base64: str
    mime_type: str


def merge_artifacts(existing: list[str] | None, new: list[str] | None) -> list[str]:
    """Artifacts 合并函数 - 去重并保持顺序"""
    if existing is None:
        return new or []
    if new is None:
        return existing
    return list(dict.fromkeys(existing + new))


def merge_viewed_images(
    existing: dict[str, ViewedImageData] | None, 
    new: dict[str, ViewedImageData] | None
) -> dict[str, ViewedImageData]:
    """已查看图片合并函数"""
    if existing is None:
        return new or {}
    if new is None:
        return existing
    if len(new) == 0:  # 空字典表示清空
        return {}
    return {**existing, **new}


class ThreadState(AgentState):
    """
    DeerFlow 线程状态
    
    继承自 LangChain 的 AgentState,扩展了以下字段:
    - sandbox: 沙箱环境信息
    - thread_data: 线程相关路径
    - title: 对话标题
    - artifacts: 生成的文件路径列表
    - todos: 任务列表 (plan mode)
    - uploaded_files: 上传的文件信息
    - viewed_images: 已查看的图片数据 (键为 image_path)
    """
    sandbox: NotRequired[SandboxState | None]
    thread_data: NotRequired[ThreadDataState | None]
    title: NotRequired[str | None]
    artifacts: Annotated[list[str], merge_artifacts]  # 自定义合并函数
    todos: NotRequired[list | None]
    uploaded_files: NotRequired[list[dict] | None]
    viewed_images: Annotated[dict[str, ViewedImageData], merge_viewed_images]  # image_path -> {base64, mime_type}

关键设计点:

  1. TypedDict 类型安全:所有字段都有明确的类型注解,便于 IDE 提示和静态检查。

  2. Annotated 自定义合并artifactsviewed_images 使用自定义合并函数,确保状态更新时的正确行为。

  3. NotRequired 可选字段:大部分字段是可选的,适应不同场景的需求。

4.4 中间件链构建

DeerFlow 的中间件系统是其架构的核心亮点之一。通过中间件链,可以将不同关注点的逻辑解耦:

def _build_middlewares(
    config: RunnableConfig, 
    model_name: str | None, 
    agent_name: str | None = None, 
    custom_middlewares: list[AgentMiddleware] | None = None
):
    """
    构建中间件链(动态组合,数量取决于配置)
    
    基础中间件(build_lead_runtime_middlewares 提供):
    1. ThreadDataMiddleware → 线程数据路径管理
    2. UploadsMiddleware → 文件上传处理
    3. SandboxMiddleware → 沙箱环境隔离
    4. DanglingToolCallMiddleware → 修复缺失的 ToolMessage
    5. LLMErrorHandlingMiddleware → LLM 错误处理
    6. GuardrailMiddleware → 工具调用守卫(可选,需配置 guardrails.enabled)
    7. SandboxAuditMiddleware → 沙箱审计
    8. ToolErrorHandlingMiddleware → 工具异常处理
    
    动态添加的中间件:
    - SummarizationMiddleware(启用压缩时)
    - TodoMiddleware(plan mode 时)
    - TokenUsageMiddleware(启用 token 统计时)
    - TitleMiddleware(始终)
    - MemoryMiddleware(始终)
    - ViewImageMiddleware(模型支持视觉时)
    - DeferredToolFilterMiddleware(启用 tool_search 时)
    - SubagentLimitMiddleware(启用子 Agent 时)
    - LoopDetectionMiddleware(始终)
    - ClarificationMiddleware(必须最后)
    """
    middlewares = build_lead_runtime_middlewares(lazy_init=True)

    # 添加 SummarizationMiddleware(如果启用)
    summarization_middleware = _create_summarization_middleware()
    if summarization_middleware is not None:
        middlewares.append(summarization_middleware)

    # 添加 TodoMiddleware(如果启用 plan mode)
    is_plan_mode = config.get("configurable", {}).get("is_plan_mode", False)
    todo_list_middleware = _create_todo_list_middleware(is_plan_mode)
    if todo_list_middleware is not None:
        middlewares.append(todo_list_middleware)

    # 添加 TokenUsageMiddleware(如果启用)
    if get_app_config().token_usage.enabled:
        middlewares.append(TokenUsageMiddleware())

    # 添加 TitleMiddleware
    middlewares.append(TitleMiddleware())

    # 添加 MemoryMiddleware(在 TitleMiddleware 之后)
    middlewares.append(MemoryMiddleware(agent_name=agent_name))

    # 添加 ViewImageMiddleware(如果模型支持视觉)
    app_config = get_app_config()
    model_config = app_config.get_model_config(model_name) if model_name else None
    if model_config is not None and model_config.supports_vision:
        middlewares.append(ViewImageMiddleware())

    # 添加 DeferredToolFilterMiddleware(如果启用 tool_search)
    if app_config.tool_search.enabled:
        from deerflow.agents.middlewares.deferred_tool_filter_middleware import DeferredToolFilterMiddleware
        middlewares.append(DeferredToolFilterMiddleware())

    # 添加 SubagentLimitMiddleware(如果启用子 Agent)
    subagent_enabled = config.get("configurable", {}).get("subagent_enabled", False)
    if subagent_enabled:
        max_concurrent_subagents = config.get("configurable", {}).get("max_concurrent_subagents", 3)
        middlewares.append(SubagentLimitMiddleware(max_concurrent=max_concurrent_subagents))

    # 添加 LoopDetectionMiddleware
    middlewares.append(LoopDetectionMiddleware())

    # 注入自定义中间件
    if custom_middlewares:
        middlewares.extend(custom_middlewares)

    # ClarificationMiddleware 必须是最后一个
    middlewares.append(ClarificationMiddleware())
    
    return middlewares

4.5 前端触发流程

从前端视角看,触发 LangGraph 的入口是 useThreadStream Hook:

export function useThreadStream({
  threadId,
  context,
  isMock,
  onStart,
  onFinish,
  onToolEnd,
}: ThreadStreamOptions) {
  // 使用 LangGraph SDK 的 useStream Hook
  const thread = useStream<AgentThreadState>({
    client: getAPIClient(isMock),      // LangGraph Client
    assistantId: "lead_agent",         // Agent ID
    threadId: onStreamThreadId,        // 线程 ID
    reconnectOnMount: runMetadataStorageRef.current  // 断线重连支持
      ? () => runMetadataStorageRef.current!
      : false,
    fetchStateHistory: { limit: 1 },   // 获取历史状态
    
    // 事件回调
    onCreated(meta) {
      handleStreamStart(meta.thread_id);
      setOnStreamThreadId(meta.thread_id);
    },
    onLangChainEvent(event) {
      if (event.event === "on_tool_end") {
        onToolEnd?.({ name: event.name, data: event.data });
      }
    },
    onUpdateEvent(data) {
      // 处理标题更新等
    },
    onCustomEvent(event) {
      // 处理子任务状态、LLM 重试等
    },
    onError(error) {
      setOptimisticMessages([]);  // 清除乐观消息
      toast.error(getStreamErrorMessage(error));
    },
    onFinish(state) {
      onFinish?.(state.values);
      queryClient.invalidateQueries({ queryKey: ["threads", "search"] });
    },
  });

  // 乐观消息:立即显示用户输入,不等服务器响应
  const [optimisticMessages, setOptimisticMessages] = useState<Message[]>([]);
  const [isUploading, setIsUploading] = useState(false);
  const sendInFlightRef = useRef(false);  // 防止重复提交

  // 发送消息函数
  const sendMessage = async (threadId, message, extraContext, options) => {
    if (sendInFlightRef.current) return;  // 防止重复提交
    sendInFlightRef.current = true;

    try {
      // 1. 上传文件(如有)
      if (message.files?.length > 0) {
        setIsUploading(true);
        uploadedFileInfo = await uploadFiles(threadId, files);
      }
      
      // 2. 提交到 LangGraph
      await thread.submit({
        messages: [{
          type: "human",
          content: [{ type: "text", text }],
          additional_kwargs: { files: filesForSubmit },
        }],
        context: {
          thinking_enabled: context.mode !== "flash",
          is_plan_mode: context.mode === "pro" || context.mode === "ultra",
          subagent_enabled: context.mode === "ultra",
          reasoning_effort: ...,
          thread_id: threadId,
        },
      }, {
        streamSubgraphs: true,   // 流式子图
        streamResumable: true,   // 可恢复流
      });
    } finally {
      sendInFlightRef.current = false;
    }
  };

  // 合并乐观消息与实际消息
  const mergedThread = optimisticMessages.length > 0
    ? { ...thread, messages: [...thread.messages, ...optimisticMessages] }
    : thread;

  return [mergedThread, sendMessage, isUploading] as const;
}

关键实现细节

  • 乐观消息:用户发送后立即显示,不等服务器响应,提升体验
  • 防重复提交sendInFlightRef 防止用户快速点击导致的重复请求
  • 断线重连reconnectOnMount 配合 runMetadataStorage 实现会话恢复
  • 文件上传状态:独立 isUploading 状态,上传期间显示进度

五、架构选型指南

5.1 决策树

                        你的应用是什么类型?
                              │
              ┌───────────────┴───────────────┐
              ▼                               ▼
        CLI / 桌面应用                    Web / SaaS 应用
              │                               │
              ▼                               ▼
    ┌─────────────────┐              ┌─────────────────┐
    │  单用户?        │              │  多用户?        │
    │  同步交互?      │              │  并发请求?      │
    │  本地持久化?    │              │  服务化部署?    │
    └────────┬────────┘              └────────┬────────┘
             │                                │
             ▼                                ▼
    ┌─────────────────┐              ┌─────────────────┐
    │  Agent Loop     │              │  LangGraph      │
    │  极简架构       │              │  企业级架构     │
    └─────────────────┘              └─────────────────┘

5.2 详细对比

维度Agent Loop (Claude Code 风格)LangGraph (DeerFlow 风格)
适用场景CLI 工具、桌面应用、原型验证Web 应用、SaaS、企业级服务
用户模型单用户多用户并发
状态管理内存 + 本地文件Checkpointer (数据库)
持久化手动 JSON 序列化自动事务性持久化
中间件硬编码在循环中可插拔中间件链
工具编排手动处理 tool_calls 循环自动工具调用循环
断线恢复需手动实现原生支持
可观测性自定义日志LangSmith/Langfuse 集成
学习曲线中高
开发效率快速启动初期投入大,长期收益高
维护成本功能简单时低,复杂时高架构清晰,长期维护成本低

5.3 何时选择 LangGraph?

推荐使用 LangGraph 的场景:

  1. 多用户 Web 应用:需要并发处理、会话隔离
  2. 复杂状态管理:对话历史只是冰山一角,还有沙箱、artifacts、todos 等
  3. 需要断线恢复:用户可能中途离开,需要从断点继续
  4. 可扩展架构:需要通过中间件扩展功能
  5. 生产级可观测性:需要集成追踪系统
  6. 多模型支持:需要统一的模型抽象层

可以不用 LangGraph 的场景:

  1. CLI 工具:如 Claude Code
  2. 原型验证:快速迭代,架构简单
  3. 单用户场景:无需并发处理
  4. 功能简单:不需要复杂的状态管理

5.4 实战场景示例

场景一:内部开发助手 CLI 工具

  • 需求:为开发团队提供一个命令行工具,辅助代码审查、调试脚本。
  • 用户量:单用户,每次运行独立。
  • 状态管理:只需保存当前对话历史,无多轮复杂状态。
  • 架构选择Agent Loop 足够。
  • 实现要点
    • 使用 Claude Code 风格的简单循环。
    • 历史记录保存为本地 JSON 文件。
    • 工具集限于文件读写、Shell 命令。

场景二:多租户 AI 客服 SaaS 平台

  • 需求:为多个企业客户提供 AI 客服,每个客户有独立的对话历史和知识库。
  • 用户量:多用户并发,每秒处理数十个请求。
  • 状态管理:每个会话需保存对话历史、用户信息、工单状态、上传文件等。
  • 架构选择LangGraph 必需。
  • 实现要点
    • 使用 ThreadState 管理每个会话的完整状态。
    • 配置 Redis Checkpointer 实现状态持久化和断线恢复。
    • 中间件处理鉴权、审计、限流。
    • 集成 LangSmith 监控每个会话的 Token 消耗和延迟。

六、总结

Claude Code 和 DeerFlow 代表了两种不同的架构选择,没有绝对的对错,关键在于场景匹配

Claude Code 的极简主义告诉我们:不要过度设计。对于 CLI 工具,Agent Loop 足够优雅且高效。

DeerFlow 的企业级架构则展示了:复杂场景需要系统性解决方案。LangGraph 提供的状态管理、持久化、中间件系统、可观测性,是构建生产级 AI Agent 应用的坚实基石。

架构选型的核心原则:以终为始,量体裁衣。理解你的场景需求,选择合适的工具,而不是盲目追求技术潮流。

术语表

  • Agent Loop: 一种简单的循环结构,依次处理用户输入、模型调用、工具执行和状态更新,适用于单用户 CLI 场景。
  • LangGraph: LangChain 提供的框架,用于构建有状态的、多步骤的 AI Agent 应用,支持复杂的状态管理和可观测性。
  • ThreadState: DeerFlow 中定义的状态类型,包含对话历史、沙箱环境、生成文件等所有运行时信息。
  • Checkpointer: LangGraph 的持久化组件,支持将状态保存到数据库(如 SQLite、Redis),实现断点恢复。
  • 中间件 (Middleware): 在 Agent 执行流程中插入的可插拔组件,用于处理横切关注点,如错误处理、审计、压缩等。
  • 可观测性 (Observability): 通过日志、追踪、指标等手段监控 Agent 的运行情况,LangSmith/Langfuse 是常用工具。

参考资料