一、部署架构总览
我们将基于你之前的带人工干预的双智能体系统,构建一个完整的生产级部署方案,包含三个核心部分:
- FastAPI 接口层:封装 Agent 为标准 HTTP 接口,支持任务启动、人工干预、状态查询
- Redis 持久化层:替代 MemorySaver,实现状态持久化和服务重启恢复
- Docker 容器化:打包整个应用为镜像,实现一键部署和环境一致性
标准部署架构图
plaintext
客户端 → FastAPI 接口 → LangGraph Agent → Redis(状态持久化)
二、第一步:项目结构标准化
先将你的代码整理为生产级项目结构:
plaintext
langgraph-agent-deploy/
├── agent/ # Agent核心逻辑
│ ├── __init__.py
│ ├── multi_agent.py # 双智能体系统代码
│ └── state.py # 状态定义
├── main.py # FastAPI入口
├── requirements.txt # 依赖清单
├── Dockerfile # 镜像构建文件
├── docker-compose.yml # 服务编排
└── .env # 环境变量配置
三、第二步:FastAPI 接口封装
3.1 核心依赖安装
bash
运行
pip install fastapi uvicorn python-multipart langgraph-checkpoint-redis
3.2 完整 FastAPI 代码
# main.py
import asyncio
from typing import Optional
from fastapi import FastAPI, HTTPException, CORS
from pydantic import BaseModel
from langgraph.types import Command
from agent.multi_agent import build_multi_agent_system
from agent.state import MultiAgentState
# 初始化FastAPI
app = FastAPI(title="LangGraph 双智能体写作系统 API", version="1.0.0")
# 配置CORS,允许前端跨域访问
app.add_middleware(
CORS,
allow_origins=["*"], # 生产环境改为具体域名
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 初始化Agent系统(全局单例,避免重复初始化)
agent = build_multi_agent_system()
# ==================== 请求响应模型 ====================
class StartTaskRequest(BaseModel):
thread_id: str
task: str
topic: str
class ResumeTaskRequest(BaseModel):
thread_id: str
human_input: str
class TaskStatusResponse(BaseModel):
thread_id: str
status: str # running, interrupted, completed, failed
current_step: Optional[str] = None
interrupt_info: Optional[dict] = None
final_article: Optional[str] = None
error: Optional[str] = None
# ==================== 核心接口 ====================
@app.post("/api/task/start", response_model=TaskStatusResponse)
async def start_task(request: StartTaskRequest):
"""启动一个新的写作任务"""
try:
config = {"configurable": {"thread_id": request.thread_id}}
# 初始化任务状态
initial_state: MultiAgentState = {
"task": request.task,
"topic": request.topic,
"research_notes": "",
"draft": "",
"final_article": "",
"current_agent": "researcher",
"turn_count": 0,
"max_turns": 5,
"messages": [],
"error": None,
"human_feedback": ""
}
# 异步执行Agent,避免阻塞事件循环
result = await asyncio.to_thread(
agent.invoke,
initial_state,
config=config
)
# 构建响应
return await _build_status_response(request.thread_id, result)
except Exception as e:
raise HTTPException(status_code=500, detail=f"任务启动失败: {str(e)}")
@app.post("/api/task/resume", response_model=TaskStatusResponse)
async def resume_task(request: ResumeTaskRequest):
"""恢复被中断的任务,传入人类反馈"""
try:
config = {"configurable": {"thread_id": request.thread_id}}
# 用Command恢复执行
result = await asyncio.to_thread(
agent.invoke,
Command(resume=request.human_input),
config=config
)
return await _build_status_response(request.thread_id, result)
except Exception as e:
raise HTTPException(status_code=500, detail=f"任务恢复失败: {str(e)}")
@app.get("/api/task/status/{thread_id}", response_model=TaskStatusResponse)
async def get_task_status(thread_id: str):
"""查询任务当前状态"""
try:
config = {"configurable": {"thread_id": thread_id}}
# 获取最新状态
state = await asyncio.to_thread(agent.get_state, config)
result = state.values
return await _build_status_response(thread_id, result)
except Exception as e:
raise HTTPException(status_code=500, detail=f"状态查询失败: {str(e)}")
# ==================== 辅助函数 ====================
async def _build_status_response(thread_id: str, result: dict) -> TaskStatusResponse:
"""构建统一的状态响应"""
# 检查是否有中断
if "__interrupt__" in result:
interrupt_info = result["__interrupt__"][0]["value"]
return TaskStatusResponse(
thread_id=thread_id,
status="interrupted",
current_step=interrupt_info["type"],
interrupt_info=interrupt_info,
error=result.get("error")
)
# 检查是否完成
if result.get("final_article"):
return TaskStatusResponse(
thread_id=thread_id,
status="completed",
final_article=result["final_article"],
error=result.get("error")
)
# 检查是否出错
if result.get("error"):
return TaskStatusResponse(
thread_id=thread_id,
status="failed",
error=result["error"]
)
# 运行中
return TaskStatusResponse(
thread_id=thread_id,
status="running",
current_step=result.get("current_agent"),
error=result.get("error")
)
# 启动服务
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
3.3 修改 Agent 代码,使用 Redis 持久化
将之前的MemorySaver替换为RedisSaver,实现状态持久化:
# agent/multi_agent.py
import os
from langgraph.checkpoint.redis import RedisSaver
def build_multi_agent_system():
# ... 其他代码不变 ...
# 从环境变量获取Redis连接地址
redis_url = os.getenv("REDIS_URI", "redis://localhost:6379/0")
checkpointer = RedisSaver.from_url(redis_url)
return builder.compile(checkpointer=checkpointer)
四、第三步:Docker 容器化
4.1 编写 requirements.txt
# requirements.txt
fastapi==0.115.0
uvicorn==0.30.6
python-multipart==0.0.12
langgraph==0.2.39
langchain==0.2.16
langchain-openai==0.1.25
pydantic-settings==2.5.2
python-dotenv==1.0.1
langgraph-checkpoint-redis==1.0.11
redis==5.2.1
4.2 编写 Dockerfile(多阶段构建,优化镜像体积)
dockerfile
# Dockerfile
# 第一阶段:构建阶段
FROM python:3.11-slim AS builder
# 设置工作目录
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# 创建虚拟环境
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# 复制依赖文件并安装
COPY requirements.txt .
RUN pip install --no-cache-dir --upgrade pip \
&& pip install --no-cache-dir -r requirements.txt
# 第二阶段:运行阶段
FROM python:3.11-slim
# 设置工作目录
WORKDIR /app
# 复制虚拟环境
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# 创建非root用户,增强安全性
RUN useradd -m appuser
USER appuser
# 复制应用代码
COPY --chown=appuser:appuser . .
# 暴露端口
EXPOSE 8000
# 启动命令
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]
4.3 编写 docker-compose.yml
yaml
# docker-compose.yml
version: '3.8'
volumes:
redis-data:
driver: local
services:
# Redis服务:状态持久化
redis:
image: redis:7-alpine
container_name: langgraph-redis
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 1s
retries: 5
# LangGraph Agent API服务
langgraph-agent:
build: .
container_name: langgraph-agent
restart: unless-stopped
ports:
- "8000:8000"
depends_on:
redis:
condition: service_healthy
env_file:
- .env
environment:
- REDIS_URI=redis://redis:6379/0
- PYTHONUNBUFFERED=1 # 禁用Python输出缓冲,确保日志实时显示
4.4 编写 .env 配置文件
env
# .env
# 智谱API配置
ZHIPU_API_KEY=你的智谱API密钥
ZHIPU_BASE_URL=https://open.bigmodel.cn/api/paas/v4
LLM_MODEL=glm-4.6
LLM_BACKUP_MODEL=glm-4-flash
LLM_TIMEOUT=30
# Redis配置(docker-compose中会覆盖这个值)
REDIS_URI=redis://localhost:6379/0
五、第四步:部署与运行
5.1 一键启动所有服务
# 构建镜像并启动服务
docker-compose up -d --build
# 查看服务状态
docker-compose ps
# 查看日志
docker-compose logs -f langgraph-agent
5.2 测试 API 接口
1. 启动任务
curl -X POST http://localhost:8000/api/task/start \
-H "Content-Type: application/json" \
-d '{
"thread_id": "test_task_001",
"task": "写一篇关于LangGraph多智能体系统的技术文章",
"topic": "LangGraph多智能体系统的原理、架构与实现"
}'
2. 查询任务状态
bash
curl http://localhost:8000/api/task/status/test_task_001
3. 恢复中断任务(当任务等待人工确认时)
bash
curl -X POST http://localhost:8000/api/task/resume \
-H "Content-Type: application/json" \
-d '{
"thread_id": "test_task_001",
"human_input": "通过"
}'
4. 访问自动生成的 API 文档
- Swagger UI:http://localhost:8000/docs
- ReDoc:http://localhost:8000/redoc
六、生产环境优化最佳实践
6.1 性能优化
-
增加 Worker 进程数 :在 Dockerfile 的 CMD 中调整
--workers参数,通常设置为 CPU 核心数的 2-4 倍 -
使用 Gunicorn + Uvicorn :生产环境推荐用 Gunicorn 管理 Uvicorn Worker,提高并发能力
dockerfile
CMD ["gunicorn", "main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:8000"] -
添加 Nginx 反向代理:处理静态资源、SSL 终止、负载均衡
6.2 安全优化
- 限制 CORS 来源 :将
allow_origins=["*"]改为具体的前端域名 - 添加 API 密钥认证:给接口添加 API 密钥验证,防止未授权访问
- 使用 Docker Secrets:生产环境不要用.env 文件存储敏感信息,改用 Docker Secrets 或 Kubernetes Secrets
- 定期更新基础镜像:及时修复安全漏洞
6.3 可观测性
-
添加日志配置:配置结构化日志,方便日志收集和分析
-
添加健康检查接口 :
python
@app.get("/health") async def health_check(): return {"status": "healthy", "timestamp": datetime.now().isoformat()} -
集成监控系统:用 Prometheus + Grafana 监控服务指标
6.4 高可用部署
- 多实例部署:启动多个 Agent 实例,用 Nginx 或 Kubernetes 进行负载均衡
- Redis 集群:生产环境使用 Redis 集群,保证数据高可用
- 自动扩缩容:根据请求量自动调整实例数量
七、常见问题排查
- Redis 连接失败:检查 docker-compose 中的 Redis 服务是否正常启动,REDIS_URI 是否正确
- 接口超时:增加 Uvicorn 的超时时间,或优化 Agent 执行逻辑
- 状态丢失:确保使用了 RedisSaver,并且 Redis 数据卷配置正确
- 镜像体积过大:使用多阶段构建,删除不必要的依赖和文件
按照这个方案部署后,你的 LangGraph Agent 系统就具备了生产级的稳定性、可扩展性和可维护性,可以安全地对外提供服务。