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

- 姓名
- 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)。
架构设计:智能体状态与业务数据的分离
在编写代码之前,我们需要理清后端需要管理的两种不同类型的数据:
- 智能体状态 (Agent State / LangGraph Checkpoints): 这一部分是元数据,用于告诉 LangGraph 当前执行到了图(Graph)的哪一个节点、当前图的变量中存储了什么,以及当前特定线程(Thread)的历史消息。这由 LangGraph 的 Checkpointer 负责管理。
- 业务数据 (Application State): 这是传统的结构化业务数据库,包含业务实体。例如,一个
bookings表,包含booking_id、user_id、date和status等字段。智能体通过工具(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 实例) |
| 查询延迟 | < 1ms | 5ms - 15ms | 2ms - 5ms |
| 适用场景 | 原型开发 | 关键业务数据 | 高并发聊天应用 |
生产环境部署建议 (Pro Tips)
- 线程隔离与安全验证: 务必在后端验证当前已认证的用户是否真正拥有他们请求的
thread_id。绝对不要在未经验证的情况下,直接信任客户端传入的thread_id。 - 数据库事务管理: 当编写修改业务数据库的工具(Tools)时,确保正确管理数据库会话(Session)。如果智能体在执行中途报错崩溃,你不希望数据库中留下未完成的脏数据。利用 SQLAlchemy 的上下文管理器来确保事务能够安全回滚。
- 利用 n1n.ai 实现 LLM 容灾备份: 如果你的主模型(如 Claude 3.5 Sonnet)触发了速率限制或遭遇服务中断,你可以在后端代码中轻松实现备用模型逻辑。由于 n1n.ai 聚合了多个主流模型提供商,你只需在 API 调用中更改模型名称即可,无需修改 SDK 配置或安装新的依赖包。
- 处理长耗时任务: 如果智能体包含复杂的循环或需要人工介入(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