最新n1n v2.0.1 正式上线!企业级大模型接口聚合平台 (LLM API Gateway),为您接入 500+ AI Models,价格低至 1 折,立即尝试

为 LangGraph 智能体构建生产级后端架构

作者
  • avatar
    姓名
    Nino
    职业
    Senior Tech Editor

在将 AI 智能体(AI Agent)从 Jupyter Notebook 中的原型转化为生产级应用时,数据管理方式需要发生根本性的转变。在大多数演示 Demo 中,开发者通常依赖 LangGraph 内置的内存状态存储器 MemorySaver 来跟踪对话状态。然而,一旦服务器重启,所有的对话历史、用户偏好以及智能体的中间运行状态都会瞬间消失。

对于真实的业务场景——例如一个需要管理机票、酒店或会议预订的助理系统——你必须构建一个持久化的后端。这个后端需要将智能体内部的执行状态(Checkpoints)与应用程序的业务数据(如预订信息、用户账户)进行清晰的分离。

在本教程中,我们将使用 FastAPI、PostgreSQL 和 SQLAlchemy 构建一个生产级的 LangGraph 后端。同时,我们将配置该智能体,使其通过 n1n.ai 提供的统一 API 网关,调用 Claude 3.5 Sonnet 和 DeepSeek-V3 等高性能大语言模型(LLM)。

架构设计:智能体状态与业务数据的分离

在编写代码之前,我们需要理清后端需要管理的两种不同类型的数据:

  1. 智能体状态 (Agent State / LangGraph Checkpoints): 这一部分是元数据,用于告诉 LangGraph 当前执行到了图(Graph)的哪一个节点、当前图的变量中存储了什么,以及当前特定线程(Thread)的历史消息。这由 LangGraph 的 Checkpointer 负责管理。
  2. 业务数据 (Application State): 这是传统的结构化业务数据库,包含业务实体。例如,一个 bookings 表,包含 booking_iduser_iddatestatus 等字段。智能体通过工具(Tools,即 API 或直接的数据库查询)与该表交互,但智能体本身不直接管理该表的 Schema。

组件之间的交互关系如下:

[ 用户客户端 ] <---> [ FastAPI 后端 ] <---> [ LangGraph 引擎 ]
                            |                          |
                            v                          v
                  [ 业务数据库表 ]             [ Postgres 检查点 ]
                            |                          |
                            +---------> [ PostgreSQL ] <+

为了确保在后端调用大语言模型时具有低延迟和高可用性,我们将使用 n1n.ai 来分发 LLM 请求。这样可以避免管理多个不同平台的 API Key,并提供自动的灾备切换。

第一步:配置 PostgreSQL 数据库

我们将使用 PostgreSQL 同时存储业务数据和 LangGraph 的状态。首先,我们使用 SQLAlchemy 定义数据库连接以及预订系统的业务数据表结构。

# database.py
import os
from sqlalchemy import create_engine, Column, Integer, String, DateTime, ForeignKey
from sqlalchemy.orm import declarative_base, sessionmaker
from datetime import datetime

DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://postgres:postgres@localhost:5432/agent_db")

engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    email = Column(String, unique=True, index=True)
    name = Column(String)

class Booking(Base):
    __tablename__ = "bookings"
    id = Column(Integer, primary_key=True, index=True)
    user_id = Column(Integer, ForeignKey("users.id"))
    service_name = Column(String, nullable=False)
    booking_time = Column(DateTime, default=datetime.utcnow)
    status = Column(String, default="pending")  # pending, confirmed, cancelled

def init_db():
    Base.metadata.create_all(bind=engine)

第二步:实现 LangGraph Postgres 检查点机制

LangGraph 提供了官方的 Postgres 检查点支持库 langgraph-checkpoint-postgres。它可以直接替换 MemorySaver,自动将线程状态保存到 PostgreSQL 中。

首先安装依赖:

pip install langgraph-checkpoint-postgres psycopg

接下来,初始化 Checkpointer。在生产环境中,建议使用连接池(Connection Pool)来高效管理数据库连接:

# checkpointer.py
from contextlib import contextmanager
from psycopg_pool import ConnectionPool
from langgraph.checkpoint.postgres import PostgresSaver
import os

DB_URI = os.getenv("DATABASE_URL", "postgresql://postgres:postgres@localhost:5432/agent_db")

# 为检查点创建连接池
pool = ConnectionPool(conninfo=DB_URI, max_size=10)

@contextmanager
def get_checkpointer():
    with pool.connection() as conn:
        checkpointer = PostgresSaver(conn)
        # 确保数据库中存在检查点所需的表结构
        checkpointer.setup()
        yield checkpointer

第三步:定义 LangGraph 智能体与工具

智能体需要与数据库交互以创建和查询预订信息。我们将编写工具函数供智能体调用。这些工具会从配置参数中获取当前用户的上下文信息。

为了驱动智能体的推理,我们将连接到 n1n.ai。通过使用其统一的 API 接口,我们可以在需要复杂推理时调用 claude-3-5-sonnet,在需要高性价比处理时切换到 deepseek-v3

# agent.py
from typing import Annotated, Dict, Any
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langchain_core.messages import BaseMessage
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from database import SessionLocal, Booking
import os

# 配置 LangChain 使用 n1n.ai 的 API 聚合网关
llm = ChatOpenAI(
    model="claude-3-5-sonnet",
    openai_api_key=os.getenv("N1N_API_KEY"),
    openai_api_base="https://api.n1n.ai/v1"
)

class AgentState(TypedDict):
    messages: Annotated[list[BaseMessage], add_messages]
    user_id: int

@tool
def create_booking(service_name: str, config: dict) -> str:
    """为当前用户预订服务。"""
    # 从图配置中获取 user_id
    user_id = config["configurable"].get("user_id")
    if not user_id:
        return "Error: 用户未登录。"

    db = SessionLocal()
    try:
        new_booking = Booking(user_id=user_id, service_name=service_name, status="confirmed")
        db.add(new_booking)
        db.commit()
        db.refresh(new_booking)
        return f"成功预订 {service_name} (预订 ID: {new_booking.id})。"
    except Exception as e:
        db.rollback()
        return f"预订失败: {str(e)}"
    finally:
        db.close()

tools = [create_booking]
llm_with_tools = llm.bind_tools(tools)

def call_model(state: AgentState, config: dict):
    messages = state["messages"]
    response = llm_with_tools.invoke(messages, config)
    return {"messages": [response]}

# 构建图结构
workflow = StateGraph(AgentState)
workflow.add_node("agent", call_model)
workflow.add_edge(START, "agent")

# 我们将在 API 层动态编译图,以便注入持久化 Checkpointer

第四步:构建 FastAPI Web 服务器

接下来,我们构建 API 服务层。FastAPI 服务器将暴露聊天接口,处理用户认证,提取对应的线程 ID(Thread ID),并将这些配置传递给 LangGraph 引擎。

# main.py
from fastapi import FastAPI, Depends, HTTPException
from pydantic import BaseModel
from database import init_db, SessionLocal, User
from checkpointer import get_checkpointer
from agent import workflow
from langchain_core.messages import HumanMessage

app = FastAPI(title="LangGraph 生产级后端")

@app.on_event("startup")
def startup_event():
    init_db()

class ChatRequest(BaseModel):
    message: str
    thread_id: str
    user_id: int

@app.post("/chat")
def chat_with_agent(payload: ChatRequest):
    # 验证用户是否存在于业务数据库中
    db = SessionLocal()
    user = db.query(User).filter(User.id == payload.user_id).first()
    db.close()

    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    # 使用上下文管理器获取持久化检查点
    with get_checkpointer() as checkpointer:
        # 编译包含 Postgres 检查点的图
        compiled_graph = workflow.compile(checkpointer=checkpointer)

        # 配置线程与元数据
        config = {
            "configurable": {
                "thread_id": payload.thread_id,
                "user_id": payload.user_id
            }
        }

        # 运行智能体
        initial_state = {
            "messages": [HumanMessage(content=payload.message)],
            "user_id": payload.user_id
        }

        events = compiled_graph.stream(initial_state, config, stream_mode="values")

        # 提取最终的响应消息
        final_message = ""
        for event in events:
            if "messages" in event:
                final_message = event["messages"][-1].content

        return {"response": final_message}

对比分析:状态持久化方案

在扩展后端系统时,选择合适的 Checkpointer 至关重要。以下是 PostgreSQL 与其他常见方案的对比:

特性MemorySaver (演示)PostgresSaver (生产级)Redis Checkpointer (缓存)
持久化重启即丢失永久保存可配置生存时间 (TTL)
扩展性仅单实例支持多实例 / 水平扩展高吞吐量 / 支持集群
部署复杂度中等 (需要数据库迁移)中等 (需要 Redis 实例)
查询延迟< 1ms5ms - 15ms2ms - 5ms
适用场景原型开发关键业务数据高并发聊天应用

生产环境部署建议 (Pro Tips)

  1. 线程隔离与安全验证: 务必在后端验证当前已认证的用户是否真正拥有他们请求的 thread_id。绝对不要在未经验证的情况下,直接信任客户端传入的 thread_id
  2. 数据库事务管理: 当编写修改业务数据库的工具(Tools)时,确保正确管理数据库会话(Session)。如果智能体在执行中途报错崩溃,你不希望数据库中留下未完成的脏数据。利用 SQLAlchemy 的上下文管理器来确保事务能够安全回滚。
  3. 利用 n1n.ai 实现 LLM 容灾备份: 如果你的主模型(如 Claude 3.5 Sonnet)触发了速率限制或遭遇服务中断,你可以在后端代码中轻松实现备用模型逻辑。由于 n1n.ai 聚合了多个主流模型提供商,你只需在 API 调用中更改模型名称即可,无需修改 SDK 配置或安装新的依赖包。
  4. 处理长耗时任务: 如果智能体包含复杂的循环或需要人工介入(Human-in-the-loop)的审批步骤,不要阻塞 HTTP 请求。应使用 FastAPI 的 BackgroundTasks 或 Celery 将其放入后台队列执行,并提供 WebSocket 或轮询接口供前端查询状态。

运行测试

我们可以编写一个简单的测试脚本来注册用户并发送请求,验证系统是否正常运行:

# test.py
import requests
from database import SessionLocal, User

# 在数据库中创建一个测试用户
db = SessionLocal()
if not db.query(User).filter(User.email == "[email protected]").first():
    dev_user = User(email="[email protected]", name="Developer")
    db.add(dev_user)
    db.commit()
db.close()

# 向 FastAPI 服务器发送请求
response = requests.post("http://localhost:8000/chat", json={
    "message": "帮我预订一张机票。",
    "thread_id": "session_abc_123",
    "user_id": 1
})
print(response.json())

通过将 LangGraph 智能体的运行状态与应用程序的关系型业务数据进行解耦,你就为系统打下了坚实的基础,能够轻松应对成千上万用户的并发访问。

Get a free API key at n1n.ai