Skip to content
OpenInfoHub
Go back

LangGraph 项目开发与部署实战指南

在前两篇文章中,我们介绍了 LangGraph 的基础概念和核心特性。本文将聚焦于实际开发流程,包括项目结构、测试策略和部署方案。

目录

应用结构

一个 LangGraph 应用由一个或多个图、配置文件(langgraph.json)、依赖文件和可选的环境变量文件组成。

典型的项目结构

my-app/
├── my_agent/              # 所有项目代码
│   ├── utils/             # 图的工具函数
│   │   ├── __init__.py
│   │   ├── tools.py       # 图的工具
│   │   ├── nodes.py       # 图的节点函数
│   │   └── state.py       # 图的状态定义
│   ├── __init__.py
│   └── agent.py           # 构建图的代码
├── .env                   # 环境变量
├── requirements.txt       # 包依赖
└── langgraph.json         # LangGraph 配置文件

配置文件(langgraph.json)

langgraph.json 是一个 JSON 文件,指定部署 LangGraph 应用所需的依赖、图、环境变量和其他设置。

基本示例

{
  "dependencies": ["langchain_openai", "./your_package"],
  "graphs": {
    "my_agent": "./your_package/your_file.py:agent"
  },
  "env": "./.env"
}

这个配置表示:

依赖管理

LangGraph 应用可能依赖其他 Python 包。需要指定以下信息:

  1. 依赖文件requirements.txtpyproject.toml
  2. 配置文件中的依赖键:指定运行应用所需的依赖
  3. 额外的二进制文件或系统库:使用 dockerfile_lines 键指定

requirements.txt 示例

langgraph
langchain-openai
langchain-anthropic

pyproject.toml 示例

[project]
name = "my-agent"
version = "0.1.0"
dependencies = [
    "langgraph>=0.2.0",
    "langchain-openai>=0.1.0",
]

图配置

使用配置文件中的 graphs 键指定部署的 LangGraph 应用中可用的图。可以指定一个或多个图,每个图由名称(应该是唯一的)和路径标识。

{
  "graphs": {
    "customer_support": "./agents/customer_support.py:graph",
    "data_analyst": "./agents/data_analyst.py:graph"
  }
}

环境变量

对于本地开发,可以在配置文件的 env 键中配置环境变量:

{
  "env": "./.env"
}

.env 文件示例

OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
DATABASE_URL=postgresql://localhost:5432/mydb

对于生产部署,通常在部署环境中配置环境变量。

测试策略

在原型化 LangGraph Agent 后,添加测试是自然的下一步。本节介绍编写单元测试时的一些有用模式。

安装 pytest

pip install pytest

基本测试模式

由于许多 LangGraph Agent 依赖于状态,一个有用的模式是在每个测试之前创建图,然后在测试中使用新的检查点实例编译它。

import pytest
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver

def create_graph() -> StateGraph:
    class MyState(TypedDict):
        my_key: str

    graph = StateGraph(MyState)
    graph.add_node("node1", lambda state: {"my_key": "hello from node1"})
    graph.add_node("node2", lambda state: {"my_key": "hello from node2"})
    graph.add_edge(START, "node1")
    graph.add_edge("node1", "node2")
    graph.add_edge("node2", END)
    return graph

def test_basic_agent_execution() -> None:
    checkpointer = MemorySaver()
    graph = create_graph()
    compiled_graph = graph.compile(checkpointer=checkpointer)
    
    result = compiled_graph.invoke(
        {"my_key": "initial_value"},
        config={"configurable": {"thread_id": "1"}}
    )
    
    assert result["my_key"] == "hello from node2"

测试单个节点

编译的 LangGraph Agent 通过 graph.nodes 暴露对每个单独节点的引用。可以利用这一点来测试 Agent 中的单个节点。

def test_individual_node_execution() -> None:
    checkpointer = MemorySaver()
    graph = create_graph()
    compiled_graph = graph.compile(checkpointer=checkpointer)
    
    # 只调用 node1
    result = compiled_graph.nodes["node1"].invoke(
        {"my_key": "initial_value"},
    )
    
    assert result["my_key"] == "hello from node1"

注意:这将绕过编译图时传递的任何检查点。

部分执行测试

对于由较大图组成的 Agent,可能希望测试 Agent 中的部分执行路径,而不是整个端到端流程。可以使用 LangGraph 的持久化机制来模拟 Agent 在所需部分开始之前暂停的状态。

步骤如下:

  1. 使用检查点编译 Agent(内存检查点 MemorySaver 足以用于测试)
  2. 调用 Agent 的 update_state 方法,将 as_node 参数设置为要开始测试的节点之前的节点名称
  3. 使用相同的 thread_id 调用 Agent,并将 interrupt_after 参数设置为要停止的节点名称

示例:仅执行线性图中的第二和第三个节点

def create_graph() -> StateGraph:
    class MyState(TypedDict):
        my_key: str

    graph = StateGraph(MyState)
    graph.add_node("node1", lambda state: {"my_key": "hello from node1"})
    graph.add_node("node2", lambda state: {"my_key": "hello from node2"})
    graph.add_node("node3", lambda state: {"my_key": "hello from node3"})
    graph.add_node("node4", lambda state: {"my_key": "hello from node4"})
    graph.add_edge(START, "node1")
    graph.add_edge("node1", "node2")
    graph.add_edge("node2", "node3")
    graph.add_edge("node3", "node4")
    graph.add_edge("node4", END)
    return graph

def test_partial_execution_from_node2_to_node3() -> None:
    checkpointer = MemorySaver()
    graph = create_graph()
    compiled_graph = graph.compile(checkpointer=checkpointer)
    
    # 更新状态,模拟在 node1 结束时的状态
    compiled_graph.update_state(
        config={"configurable": {"thread_id": "1"}},
        values={"my_key": "initial_value"},
        as_node="node1",  # 执行将从 node2 恢复
    )
    
    # 恢复执行
    result = compiled_graph.invoke(
        None,  # 传递 None 以恢复执行
        config={"configurable": {"thread_id": "1"}},
        interrupt_after="node3",  # 在 node3 后停止
    )
    
    assert result["my_key"] == "hello from node3"

测试工具调用

对于使用工具的 Agent,可以模拟工具响应来测试 Agent 的行为:

from unittest.mock import patch

def test_agent_with_mocked_tool():
    graph = create_agent_graph()
    compiled_graph = graph.compile()
    
    with patch('my_agent.tools.search_tool') as mock_search:
        mock_search.return_value = "模拟的搜索结果"
        
        result = compiled_graph.invoke({
            "messages": [{"role": "user", "content": "搜索 LangGraph"}]
        })
        
        assert "模拟的搜索结果" in str(result)
        mock_search.assert_called_once()

测试错误处理

测试 Agent 如何处理错误情况:

def test_error_handling():
    graph = create_graph_with_error_handling()
    compiled_graph = graph.compile()
    
    # 测试无效输入
    result = compiled_graph.invoke({"invalid_key": "value"})
    assert "error" in result
    
    # 测试工具失败
    with patch('my_agent.tools.api_call') as mock_api:
        mock_api.side_effect = Exception("API 错误")
        result = compiled_graph.invoke({"query": "test"})
        assert result["status"] == "failed"

本地开发与调试

本地服务器

LangGraph 提供了本地开发服务器,可以在部署前测试应用。

启动本地服务器

langgraph dev

这将启动一个本地服务器,通常在 http://localhost:8123

使用 LangGraph Studio

LangGraph Studio 是一个可视化调试工具,可以:

在 Studio 中打开应用

langgraph dev --studio

调试技巧

1. 使用 debug 流式模式

for chunk in graph.stream(
    inputs,
    stream_mode="debug",
):
    print(chunk)

2. 检查状态历史

config = {"configurable": {"thread_id": "1"}}
history = list(graph.get_state_history(config))

for state in history:
    print(f"步骤 {state.metadata['step']}: {state.values}")

3. 添加日志节点

def log_state(state: State):
    print(f"当前状态: {state}")
    return state

graph.add_node("log", log_state)

部署到生产环境

部署到 LangSmith Cloud

LangSmith Cloud 是专为 Agent 工作负载设计的完全托管托管平台。

前提条件

部署步骤

  1. 创建 GitHub 仓库

将应用代码推送到 GitHub 仓库(支持公共和私有仓库)。

  1. 连接到 LangSmith

在 LangSmith 控制台中:

  1. 在 Studio 中测试

部署完成后:

  1. 获取 API URL

在部署详情视图中,点击 API URL 将其复制到剪贴板。

  1. 测试 API

使用 Python SDK

pip install langgraph-sdk
from langgraph_sdk import get_sync_client

client = get_sync_client(
    url="your-deployment-url",
    api_key="your-langsmith-api-key"
)

for chunk in client.runs.stream(
    None,    # 无线程运行
    "agent", # Agent 名称,在 langgraph.json 中定义
    input={
        "messages": [{
            "role": "human",
            "content": "什么是 LangGraph?",
        }],
    },
    stream_mode="updates",
):
    print(f"接收到新事件,类型: {chunk.event}")
    print(chunk.data)

使用 REST API

curl -s --request POST \
    --url <DEPLOYMENT_URL>/runs/stream \
    --header 'Content-Type: application/json' \
    --header "X-Api-Key: <LANGSMITH_API_KEY>" \
    --data '{
        "assistant_id": "agent",
        "input": {
            "messages": [{
                "role": "human",
                "content": "什么是 LangGraph?"
            }]
        },
        "stream_mode": "updates"
    }'

自托管部署

如果需要自托管,可以使用 Docker 容器化应用。

Dockerfile 示例

FROM python:3.11-slim

WORKDIR /app

# 安装依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 暴露端口
EXPOSE 8000

# 启动应用
CMD ["uvicorn", "my_agent.server:app", "--host", "0.0.0.0", "--port", "8000"]

构建和运行

docker build -t my-langgraph-agent .
docker run -p 8000:8000 --env-file .env my-langgraph-agent

使用 Kubernetes

对于大规模部署,可以使用 Kubernetes:

deployment.yaml 示例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: langgraph-agent
spec:
  replicas: 3
  selector:
    matchLabels:
      app: langgraph-agent
  template:
    metadata:
      labels:
        app: langgraph-agent
    spec:
      containers:
      - name: agent
        image: my-langgraph-agent:latest
        ports:
        - containerPort: 8000
        env:
        - name: OPENAI_API_KEY
          valueFrom:
            secretKeyRef:
              name: api-keys
              key: openai
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1000m"

可观测性与监控

使用 LangSmith 进行追踪

LangSmith 提供了强大的追踪和调试功能:

import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "your-api-key"
os.environ["LANGCHAIN_PROJECT"] = "my-agent-project"

# 现在所有的运行都会被追踪
result = graph.invoke(inputs)

自定义指标

添加自定义指标来监控 Agent 性能:

import time
from typing import TypedDict

class State(TypedDict):
    query: str
    result: str
    execution_time: float

def timed_node(state: State):
    start_time = time.time()
    
    # 执行节点逻辑
    result = process_query(state["query"])
    
    execution_time = time.time() - start_time
    
    return {
        "result": result,
        "execution_time": execution_time
    }

错误监控

集成错误监控服务(如 Sentry):

import sentry_sdk

sentry_sdk.init(
    dsn="your-sentry-dsn",
    traces_sample_rate=1.0,
)

def monitored_node(state: State):
    try:
        return process_state(state)
    except Exception as e:
        sentry_sdk.capture_exception(e)
        raise

性能优化

并行执行

利用 LangGraph 的并行执行能力:

# 并行执行多个独立节点
graph.add_edge(START, "node1")
graph.add_edge(START, "node2")
graph.add_edge(START, "node3")

缓存策略

实现缓存以减少重复计算:

from functools import lru_cache

@lru_cache(maxsize=100)
def expensive_operation(query: str):
    # 昂贵的操作
    return result

def cached_node(state: State):
    result = expensive_operation(state["query"])
    return {"result": result}

异步执行

使用异步操作提高性能:

async def async_node(state: State):
    result = await async_api_call(state["query"])
    return {"result": result}

# 使用异步调用
result = await graph.ainvoke(inputs)

最佳实践总结

  1. 结构化项目:使用清晰的目录结构,分离关注点
  2. 全面测试:编写单元测试、集成测试和端到端测试
  3. 环境管理:使用环境变量管理配置,不要硬编码敏感信息
  4. 错误处理:实现适当的错误处理和重试策略
  5. 监控追踪:使用 LangSmith 或其他工具进行追踪和监控
  6. 性能优化:利用并行执行、缓存和异步操作
  7. 文档化:为图、节点和工具编写清晰的文档
  8. 版本控制:使用 Git 管理代码,使用语义化版本控制

系列总结

通过这三篇文章,我们完整地介绍了 LangGraph 的核心概念和实践:

  1. 入门指南:介绍了 LangGraph 的基础概念、快速开始和思维方式
  2. 核心特性:深入探讨了持久化、流式输出、人机协作和记忆管理
  3. 开发部署:涵盖了项目结构、测试策略、调试方法和部署方案

LangGraph 为构建生产级 Agent 系统提供了强大的基础设施。通过掌握这些概念和实践,你可以构建可靠、可扩展的 AI Agent 应用。

参考资源


内容基于 LangGraph 官方文档改编,遵循内容许可限制


Share this post on:

Previous Post
Qwen3.5-27B 介绍:阿里巴巴的新一代多模态大语言模型
Next Post
LangGraph 核心特性详解:持久化、流式输出与人机协作