Skip to content

第 30 章 生产架构最佳实践 ​

30.1 分层架构与状态存储边界 ​

LangGraph 生产部署推荐五层架构。接口层(API/Gateway)负责鉴权、租户识别、限流、协议转换与 TLS 终止,入口形态可为 FastAPI、LangGraph Server、Nginx+Lua 或企业 API 网关。编排层(LangGraph Server 或自建 Python worker 进程)运行图,管理 checkpoint、interrupt、Send 扇出与子图调用。工具层封装内部微服务、RAG 检索、数据库与外部 SaaS 访问,对外提供单一职责、可幂等的工具接口。模型层通过统一模型网关路由到多家模型供应商,支持按任务复杂度调度、按可用性 fallback、按成本预算分流。存储层包括 Postgres(checkpoint 与 Store)、Redis(缓存、队列、分布式限流)、向量库(embedding 检索)、对象存储(S3/OSS/COS,存放大文件与文档)。

数据类型推荐存放理由
运行时控制流数据(current_intent、attempts、路由标记、revision_count)State自动 checkpoint,天然支持中断恢复
会话内短期对话State.messages + trim_messages 按 token 裁剪LangGraph 原语支持,避免历史无限增长
用户长期事实/偏好(常用地址、风格偏好、历史摘要、称呼)Store(按 user_id namespace)跨会话复用,不污染 checkpoint 体积
业务主数据(订单详情、用户基础信息、物流轨迹)业务数据库State 只存主键 ID,工具按需查询,避免数据漂移
大型内容(文档全文、base64 图片、音视频二进制、查询大结果集)对象存储State 只存 URL 引用,避免 checkpoint 体积爆炸
查询结果中间缓存与热点数据Redis / Store低延迟复用,TTL 可控
日志与 tracing专用日志系统 + LangSmith与业务状态分离,保留期独立配置
Prompt 版本与配置Git YAML / LangSmith Prompts支持版本化、A/B 测试与回滚

Checkpoint 体积是生产稳定性的关键指标。经验阈值:单 checkpoint 序列化后 < 100 KB;若 State 中出现大列表、长文本、二进制对象,应改为引用或写入对象存储。违反该原则会导致 Postgres 写入延迟飙升、递归恢复变慢、内存占用异常。生产环境可在 compile 后添加中间件统计 checkpoint 体积,超过阈值打印 warn 日志,超过 1 MB 直接拒绝写入以保护数据库。

State 设计的两条反模式需警惕:一是把完整消息历史无限追加进 messages,应使用 trim_messages 按 max_tokens 裁剪(如保留最近 4000 token),历史摘要由 summary_node 存入 Store;二是把工具返回的大型结果(如 1000 行查询结果、完整文档)直接塞回 State,应只保留 ID 或前 N 行预览,完整结果写入对象存储或 Redis 并返回引用。

30.2 Prompt 管理与工具设计 ​

Prompt 必须版本化管理,禁止硬编码在 Python 源码字符串中。两种推荐方式:LangSmith Prompts 提供云端版本管理、A/B 测试、回滚与团队协作界面;Git 管理 YAML 文件,CI/CD 流水线打包为 artifacts,节点通过 prompt_registry 按版本号加载。A/B 测试通过 configurable 注入 prompt_version,按 user_id 或 session_id 哈希分桶,LangSmith 数据集做效果对比(准确率、用户满意度、token 成本)。Prompt 变更需经 Golden Dataset 回归门禁,不得直接修改线上版本。

工具设计九条原则:

  1. 单一职责:一个工具只做一件事,避免"万能工具"同时处理查询与写入。
  2. 可幂等:写操作必须支持 idempotency_key,重复调用不产生重复副作用。
  3. 显式超时:所有外部调用必须设置超时,默认 HTTP 5-10 秒、数据库 10 秒、LLM 30-60 秒。
  4. 错误语义明确:返回结构化 dict {"ok": bool, "data": ..., "error": {"code":..., "message":...}},不抛未捕获异常给 LLM。
  5. 输入校验:使用 Pydantic 模型校验入参类型、长度、枚举、正则,校验前置到工具入口。
  6. 返回结构化数据:下游节点直接消费 dict,禁止返回自然语言错误或状态描述让 LLM 再次解析。
  7. Docstring 清晰:只描述"做什么""参数含义""取值范围""示例",不写实现细节或冗长说明。
  8. 日志与追踪:工具调用前后打点,记录延迟、参数摘要(脱敏)、错误码,run_id 贯穿日志。
  9. 重试与熔断:读操作带指数退避重试,写操作禁自动重试或仅在幂等键保证下重试;错误率超阈值触发熔断返回降级。

多模型路由策略按三维度调度。任务复杂度维度:分类、抽取、关键词匹配、摘要压缩等轻任务用小模型(gpt-4o-mini、Claude Haiku、ERNIE-Speed、Qwen-Turbo);生成、推理、批评、规划等重任务用大模型(gpt-4o、Claude Sonnet/Opus、Qwen-Max)。可用性维度:主模型连续 5xx 或超时超过阈值(如 30 秒内错误率 > 30%)自动切备用模型,主模型恢复后按冷却时间切回。成本维度:按租户或 user_id 配置月度预算,预算紧张时优先小模型或走缓存命中路径。

密钥管理:开发阶段使用 .env(python-dotenv 加载)且不提交仓库;生产环境使用云厂商 KMS 或 Secret Manager(AWS Secrets Manager、阿里云 KMS、HashiCorp Vault),容器通过挂载 secret 卷或运行时环境变量注入;禁止将 API Key、数据库密码、签名密钥硬编码或写入镜像;日志与 tracing 中对 authorization、api_key、password、token 等字段做正则脱敏;LangSmith metadata 不记录密钥。

30.3 限流、熔断、可观测性 ​

限流、熔断、降级构成稳定三角。LLM API 并发限流:进程内使用 asyncio.Semaphore 控制单 worker 并发,叠加令牌桶(aiometer、limits 库)做 QPS 限制;多 worker 部署时使用 Redis + Lua 脚本做分布式限流,保证总并发不超模型供应商配额。熔断使用断路器模式(pybreaker),错误率连续 10 秒超过 30%、或慢调用比例超过 50% 时打开熔断,30 秒冷却期内直接返回降级响应,半开状态放行少量请求探测恢复。降级策略:工具失败时返回缓存或默认文案;模型不可用时切换备用模型;长流程在关键 interrupt 断点保留 checkpoint,依赖恢复后通过 Command(resume=...) 续跑;前端展示降级提示与转人工入口。

可观测性三件套:

  • Tracing:接入 LangSmith 或 OpenTelemetry,run_id 贯穿全链路,记录节点输入输出、token 消耗、工具调用参数与结果、延迟;按 graph_name、tenant_id、assistant_version 维度筛选。
  • Metrics:Prometheus 采集 QPS、延迟分位数(P50/P95/P99)、HTTP/gRPC 错误率、LLM 错误率与 429 比例、token 消耗(prompt/completion 分别统计)、checkpoint 写入延迟、Postgres 连接池占用、缓存命中率、各节点耗时分位;Grafana 看板按租户与图名分组,并配置错误率与延迟告警。
  • Logging:结构化 JSON 日志,字段必须包含 ts、level、run_id、thread_id、tenant_id、graph_name、node_name、assistant_version、message、latency_ms;异常日志带 stacktrace,但对敏感字段脱敏;日志通过 Filebeat/Fluent Bit 采集至 ELK 或 Loki。

30.4 发版、多租户与异步长任务 ​

发版策略四条:Assistants 版本化(v1/v2/v3 共存),新老版本使用独立 graph_name 注册,configurable 通过 assistant_version 选择版本,避免覆盖线上;灰度发布按 tenant_id 或 user_id 百分比切流,梯度 1% → 5% → 20% → 50% → 100%,每梯度至少观察 30 分钟错误率与核心指标;回滚预案为一旦新版本在 Golden Dataset 准确率下降超过阈值(如 2%)或 P95 延迟上升超过 50%,立即在网关层把流量切回旧 Assistant,无需重新部署;Golden Dataset 回归测试作为 CI/CD 门禁,每次发版必须全量通过且准确率、延迟、token 成本不劣化超过阈值。

多租户:构建图时通过 configurable 传入 tenant_id;工具层根据 tenant_id 路由到对应数据源、API endpoint、向量库 namespace 与模型配额;Store namespace 形如 (tenant_id, "users", user_id) 实现数据逻辑隔离;Checkpointer 的 thread_id 建议包含 tenant_id 前缀(如 t123:sess:456)避免跨租户冲突;LangSmith metadata 与结构化日志字段携带 tenant_id;限流配额、熔断阈值与预算按 tenant_id 维度设置,防止单一租户占用全部资源。

异步长任务模式适用于长文写作、深度研究、批量报表生成、数据导出等分钟级以上任务。流程为:客户端提交任务立即返回 run_id 与初始状态;任务进入 Redis/消息队列,后台 worker 消费执行;过程中节点通过 custom stream 写入 Redis Pub/Sub 进度频道;遇到 HITL 断点时 interrupt 暂停并通知前端;完成或失败通过 Webhook、Kafka/RabbitMQ 或 Redis 通知业务系统;前端可通过 SSE 订阅任务状态或按需轮询。中断与恢复完全依赖 PostgresSaver,worker 重启、版本升级不丢任务。

安全清单:

检查项具体要求
工具权限最小化数据库账号只读;API 服务账号按 scope 授权;K8s Service Account 最小 RBAC
SQL 注入防护Text2SQL 使用只读账号 + 关键字白名单 + AST/正则校验 + 表名白名单 + LIMIT
提示注入防护系统提示与用户输入分消息传递;工具调用前做输入过滤;高风险操作必须 HITL
PII 检测与脱敏日志与 tracing 中身份证、手机、银行卡、邮箱脱敏;schema 中敏感列屏蔽;回复中对用户隐私二次脱敏
人工审批退款、下单、发邮件、内容发布、线上配置变更等高风险动作必须 interrupt 等待审批,保留审批人 ID 与决策审计
审计日志所有工具调用、审批决策、模型输入输出摘要落审计库,保留期 ≥ 180 天;按 tenant_id 与 run_id 可检索
速率与配额按 tenant/user/IP 多维限流;异常流量自动封禁;模型 token 预算按租户设限
数据加密传输 TLS 1.2+;存储加密(磁盘加密 + 敏感字段列加密);KMS 管理密钥,定期轮换
依赖安全定期扫描 CVE;固定依赖版本;供应链攻击防护(sigstore/lockfile)

30.5 容量规划与典型反模式 ​

容量规划估算表(典型场景,数值为经验起点,需以真实流量压测校准):

场景业务 QPS/并发平均 LLM 调用/请求模型 QPS 需求DB 连接池worker 数(4C8G)checkpoint 日增量估算
智能客服100 QPS2-3(意图 + 业务回答,含 RAG)250-30030-50(PG 读写)20-30100 QPS × 8 KB × 86400 ≈ 66 GB/日
长文写作流水线10 并发任务30-50(大纲 + N×研究 + N×写作 + critic + 修订)峰值 10×8=80 并发20(checkpointer)10 worker + 8 并发信号量10 任务 × 50 KB × 多次 checkpoint ≈ 5 GB/日
数据分析助手50 QPS2-4(生成 + 纠错 + 解释)150-20020(只读 DB) + 10(checkpointer)10-1550 × 4 KB × 86400 ≈ 17 GB/日
RAG 知识问答200 QPS1-2(检索 + 回答)200-40030(向量库) + 20(PG)30-40200 × 3 KB × 86400 ≈ 50 GB/日

估算方法:checkpoint 日增量 ≈ QPS × 单请求平均 checkpoint 数 × 单 checkpoint 平均体积 × 86400;模型 QPS ≈ 业务 QPS × 单请求平均 LLM 调用次数 × (1 + 重试率);DB 连接池 ≈ worker 数 × 每 worker 最大持有连接数,通常为 worker 数 × 1.5 并留出 headroom;worker 数依据 CPU 核数与平均 I/O wait 调整,I/O 密集型(工具调用多)可取核数的 2-4 倍。上线前必须用真实业务负载压测校准,尤其是 checkpoint 写入路径与 LLM 并发路径。

典型反模式(Anti-patterns):

  • 上帝 Agent(God Agent):一个 Agent 挂 50+ 工具,所有任务都塞到同一个路由节点,提示词爆炸、路由准确率下降、维护困难。应拆分为 Supervisor + 业务子图,按业务域聚合工具。
  • God State:把订单详情、用户资料、文档全文、聊天记录、检索结果全部塞进 State,checkpoint 体积动辄数十 MB,写入延迟与数据库存储急剧上升。应按 30.1 边界原则拆分到业务 DB、对象存储与 Store,State 只保留控制流与主键引用。
  • 无终止循环:反思循环或错误纠正未设最大轮次、未设人工兜底,可能出现 LLM 反复自我修改陷入死循环,最终 recursion_limit 耗尽报错。必须显式设置 attempts/revision_count 上限,并在阈值后转人工或返回友好错误。
  • 无 HITL 直接执行高风险操作:退款、发邮件、下单、线上变更等动作直接让模型决定并调用工具,没有审批断点,一旦模型误判或遭遇提示注入即可造成资损或合规事故。
  • 仅做 Demo 测试就上线:没有 Golden Dataset 评估、没有压测、没有降级与熔断、没有监控告警,出现故障无法定位无法回滚。必须在灰度前完成准确率评估、稳定性压测、故障注入演练与回滚预案。
  • Prompt 硬编码:prompt 散落在代码字符串里,无法版本化、无法 A/B 测试、无法快速回滚,修改需要重新发版。应集中到 prompts/ 目录或 LangSmith Prompts 做版本化管理。
  • 工具返回自然语言:工具返回"您好,订单已成功创建"之类自然语言,下游节点只能再次让 LLM 解析,结构化信息丢失、token 浪费、错误处理困难。工具应返回结构化 dict。
  • 错误重试无边界:对写操作(退款、发通知、推送)无限重试或不设幂等键,可能造成重复执行与资损。
  • 忽略流式与 HITL 协议:前端轮询整段响应导致首字延迟高;高风险操作没有 interrupt 断点,用户体验与安全性双输。
  • 无多租户隔离:所有租户共用 thread_id、Store namespace 与工具权限,导致数据串读、配额互抢、审计困难。configurable 必须携带 tenant_id 并在各层贯穿。

上述反模式的共同根源是把 LangGraph 当作普通链式调用(chain)使用,而未充分利用其 checkpoint、interrupt、Send、Subgraph、Store 等原语做工程化设计。遵循分层架构、状态边界、可观测性、安全清单与容量规划方法,可将 Demo 级原型稳定迁移至生产环境。

上线前 Checklist(按顺序执行):

  1. 状态边界审查:打印 State 各字段类型与预估体积,确认无大对象、无业务主数据拷贝。
  2. 工具审查:每个工具都有超时、幂等键(写操作)、结构化错误返回、脱敏日志。
  3. Prompt 版本化:所有提示词来自版本化 YAML 或 LangSmith Prompts,无硬编码字符串。
  4. HITL 审计:所有高风险路径都有 interrupt 断点,审批接口有权限校验。
  5. 安全测试:SQL 注入、提示注入、越权访问、敏感列暴露均通过测试用例。
  6. 熔断降级:所有外部依赖(LLM、业务 API、DB)均配置超时、重试、熔断与降级文案。
  7. 可观测性接入:Tracing 到 LangSmith、Metrics 到 Prometheus、日志为结构化 JSON 且字段齐全。
  8. 容量压测:按预期 QPS × 2 进行 30 分钟压测,P95/P99 延迟、错误率、资源使用率达标。
  9. Golden Dataset 回归:准确率、延迟、token 成本指标不低于上一版本。
  10. 灰度与回滚:灰度策略与回滚操作手册已准备,运维与客服团队周知。
  11. 应急预案:模型宕机、数据库故障、队列堆积、HITL 超时的应急流程已演练。
  12. 文档与交接:图结构、工具列表、prompt 版本、runbook 已归档至团队 wiki。

第六篇 附录与收尾 ​