跳转至

第 11 章 Backend 服务参考

本章学习目标 - 掌握 Backend 的 API 端点全貌(Chat BI / Admin / Utility) - 理解应用生命周期、中间件栈与优雅关闭 - 了解数据库模型(ORM)组织与异常层次 - 理解生产部署的 Agent Runtime Pool 架构 - 知道去哪里查环境变量与配置(附录 B)

前置知识第 4-8 章 AI Agent 内核 关联代码backend/app/main.pybackend/app/api/backend/app/db/models.py

本章定位

本章是 Backend 的服务面参考(API、生命周期、ORM 模型、部署)。AI Agent 内核(编排、RAG、SQL、记忆、工具)已在第 4-8 章详解,本章不重复。环境变量完整参考见 附录 B


11.1 技术基线

组件 版本/规格 用途
Python 3.12+ 运行时
FastAPI 0.115+ ASGI Web 框架
LangGraph ≥ 0.4.0 状态图编排(详见 第 4 章
psycopg 3 latest 异步 PG 驱动(raw pool)
SQLAlchemy 2.0 latest ORM(Admin 资源管理)
Pydantic v2 latest 数据校验 + Settings
structlog latest 结构化 JSON 日志
slowapi latest 请求限流

当前版本:4.0.0(见 backend/app/main.py),包名 ttd-backend(uv workspace member)。


11.2 应用生命周期

启动序列

应用使用 FastAPI 的 lifespan 上下文管理器进行资源初始化和清理:

sequenceDiagram
    autonumber
    box rgb(232,240,254) FastAPI 运行时
        participant App as FastAPI App
        participant PG as PG Pool
        participant MR as Model Registry
        participant CP as Checkpointer
        participant SG as Supervisor Graph
    end

    App->>PG: AsyncConnectionPool(min=5, max=20)
    opt Swarm Mode (TTD_SWARM_MODE=true)
        App->>App: InstanceRegistry + heartbeat + GracefulShutdown
    end
    App->>MR: ModelRegistry() + load_from_db()
    App->>CP: AsyncPostgresSaver.setup()
    App->>SG: build_supervisor_graph(checkpointer, store, registry, pool)
    Note over App: ✓ "TTD Chat BI started"

关闭序列(优雅关闭)

Swarm 模式下的优雅关闭是生产稳定性的关键:

  1. Graceful Drain(Swarm):停止接受新请求,等待 in-flight 完成(max 120s)
  2. 停止 heartbeat + 标记实例 shutdown
  3. 取消后台清理任务
  4. 关闭 Memory Store → Checkpointer → PG Pool → SQLAlchemy Engine

这保证了滚动更新时不会丢失正在处理的查询——HAProxy 健康检查会摘除 draining 实例,新请求路由到健康实例。

中间件栈

中间件 功能
CORSMiddleware 跨域(生产收紧到 BETTER_AUTH_URL)
Rate Limiter (slowapi) 按 IP 限流,60 req/min/user
Prometheus Metrics /metrics 端点(TTD_PROMETHEUS_ENABLED

11.3 API 端点

所有路由挂载在 /api/v1 前缀。

11.3.1 Chat BI API(主接口)

方法 路径 说明
GET /chats 列出当前用户所有对话
POST /chats 创建新对话
GET /chats/{id} 获取对话详情(含消息历史)
PATCH /chats/{id} 更新对话(标题/状态)
DELETE /chats/{id} 删除对话
POST /chats/{id}/messages 发送消息(非流式)
POST /chats/{id}/messages/stream 发送消息(SSE 流式)
POST /messages/{id}/feedback 提交消息反馈

SSE 流式事件类型(status/sql/result/viz/insights/followup 等 29 种)详见 第 4 章第 12 章

11.3.2 Admin API

分组 前缀 说明
LLM Models /admin/llms/* LLM 模型 CRUD
Embedding Models /admin/embedding-models/* Embedding 模型管理
Reranker Models /admin/reranker-models/* Reranker 模型管理
Knowledge Bases /admin/knowledge-bases/* 知识库 CRUD
Data Sources /admin/datasources/* 数据源管理
Documents / Chunks /admin/documents/*/admin/chunks/* 文档与 chunk
Graph /admin/graph/* KG Entity/Relationship
Chat Engines /admin/chat-engines/* 聊天引擎配置
Evaluations /admin/evaluations/* 评估任务管理
Feedbacks /admin/feedbacks/* 反馈审核
Few-Shot Review /admin/few-shots/* 动态 Few-Shot 审批(详见 第 7 章
Semantic Plane /admin/semantic-plane/* 语义层资产浏览
API Keys / Site Settings / Stats / Uploads /admin/* 系统管理

11.3.3 Utility API

方法 路径 说明
GET /health 健康检查
GET /metrics Prometheus 指标(可选)

11.4 数据库模型

ORM 模型定义在 backend/app/db/models.py,Schema:ttd(与 semlayer 语义层分离)。

分类 模型 表名
核心业务 Chat / ChatMessage / Feedback ttd_chats / ttd_chat_messages / ttd_feedback
模型管理 LLMModel / EmbeddingModel / RerankerModel / ChatEngine ttd_llm_models / ...
知识库 KnowledgeBase / DataSource / Document / Chunk / KGEntity / KGRelationship ttd_knowledge_bases / ...
评估 EvaluationDataset / EvaluationTask / EvaluationTaskItem ttd_evaluation_*
系统 Upload / SiteSettings / ApiKey ttd_uploads / ...
记忆 MemoryRecord / MemoryEvidence ttd_memory_records / ...

Alembic 迁移在 backend/alembic/versions/。Better Auth 表(user/session/account/verification/jwks)由 web 端 @better-auth/cli migrate 创建。


11.5 配置参考

所有环境变量使用 TTD_ 前缀,通过 app/config.py 的 Pydantic Settings 管理。

环境变量完整参考

环境变量的唯一权威完整列表附录 B · 环境变量完整参考。本章不重复,只列分类摘要:

分类 示例变量 说明
服务器 TTD_HOSTTTD_PORTTTD_DEBUG 服务绑定与调试
Runtime Pool TTD_SWARM_MODETTD_INSTANCE_ID 多实例部署
数据库 TTD_AURORA_DSNTTD_PG_POOL_MIN/MAX PG Supernode 连接
数据面 TTD_DATA_PLANE_BACKENDTTD_REDSHIFT_* 双数据面切换
模型 TTD_DASHSCOPE_API_KEYTTD_SUPERVISOR_MODEL LLM/Embedding 配置
认证 TTD_BETTER_AUTH_URLTTD_JWT_AUDIENCE Better Auth JWKS
检索 TTD_TOP_K_*TTD_SIMILARITY_THRESHOLD RAG 参数
执行 TTD_STATEMENT_TIMEOUT_MSTTD_MAX_ROWS SQL 执行限制
记忆 TTD_SQL_CACHE_SIMILARITYTTD_SHORT_TERM_WINDOW 记忆系统
修复 TTD_MAX_REPAIR_RETRIESTTD_MAX_ESTIMATED_ROWS 护栏阈值
监控 TTD_PROMETHEUS_ENABLEDTTD_AUDIT_LOG_LEVEL 可观测性

11.6 生产部署 — Agent Runtime Pool

生产环境采用 Agent Runtime Pool 模式:多个无状态实例通过 Docker Swarm 编排,HAProxy consistent hashing 实现 session affinity。

C4Deployment
title Agent Runtime Pool — Production Deployment

    Deployment_Node(haproxy_tier, "HAProxy 负载均衡", "HAProxy 2.9 · 2C/4G", "四层 TCP 反向代理,ketama 一致性哈希") {
        Container(haproxy, "HAProxy", "consistent hash · X-Chat-ID", "健康检查 5s fall 3 rise 2,实例增减仅 ~1/N 受影响。性能优化非正确性依赖")
    }

    Deployment_Node(swarm_cluster, "Docker Swarm 集群", "N×16C/32G · Overlay Network", "无状态 Runtime 水平扩展池") {
        Container(runtime_1, "Runtime #1", "FastAPI · LangGraph · 1 worker", "完整 Agent 管线,PG Advisory Lock 跨实例并发")
        Container(runtime_n, "Runtime #N", "FastAPI · LangGraph · 1 worker", "与 #1 完全一致,zero gossip,共享状态通过 PG")
    }

    Deployment_Node(pg_tier, "PG Supernode", "PostgreSQL 18 · 16C/64G · SSD", "共享状态后端:检查点、锁、缓存") {
        ContainerDb(pg_supernode, "PG Supernode", "PostgreSQL 18 · pgvector · AGE", "检查点 + 记忆 + R/V/G 语义资产 + SQL 缓存 + Auth 表")
    }

    Rel(haproxy, runtime_1, "hash(chat_id) 路由", "HTTP · ketama")
    Rel(haproxy, runtime_n, "hash(chat_id) 路由", "HTTP · ketama")
    Rel(runtime_1, pg_supernode, "读写检查点·获取锁·检索·缓存", "asyncpg · TCP")
    Rel(runtime_n, pg_supernode, "读写检查点·获取锁·检索·缓存", "asyncpg · TCP")

    UpdateElementStyle(haproxy, $fontColor="#202124", $bgColor="#e8f0fe", $borderColor="#1a73e8")
    UpdateElementStyle(runtime_1, $fontColor="#202124", $bgColor="#e8f0fe", $borderColor="#1a73e8")
    UpdateElementStyle(runtime_n, $fontColor="#202124", $bgColor="#e8f0fe", $borderColor="#1a73e8")
    UpdateElementStyle(pg_supernode, $fontColor="#202124", $bgColor="#e0f2f1", $borderColor="#0d7377")

    UpdateRelStyle(haproxy, runtime_1, $textColor="#1a73e8", $lineColor="#1a73e8")
    UpdateRelStyle(runtime_1, pg_supernode, $textColor="#0d7377", $lineColor="#0d7377")

    UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="2")

11.6.1 关键设计决策

决策 选择 理由
实例间状态共享 PG Supernode(已有) 不引入新中间件(如 Redis)
并发控制 PG Advisory Lock 跨实例互斥,事务结束自动释放
路由策略 Consistent Hash (ketama) 缓存 warmth + 最小迁移(实例增减时只有 1/N session 受影响)
单 worker/instance Docker Swarm replicas 避免 GIL 竞争、内存膨胀;水平扩展靠实例数
实例间通信 无(zero gossip) 所有共享通过 PG,简化架构

一致性哈希与 Session Affinity

HAProxy 基于 X-Chat-ID header 做 ketama 一致性哈希——同一会话的请求总路由到同一实例。这保证了缓存 warmth(SQL Cache、Metadata Cache 在同一实例命中率高)。

关键:一致性哈希是性能优化,非正确性依赖。即使请求路由到不同实例,因为有 PG Supernode 共享状态(Checkpointer + Advisory Lock),正确性仍保证。一致性哈希只是让缓存更热、延迟更低。

11.6.2 故障转移

  • 节点故障:一致性哈希环自动 rehash,仅 ~1/N sessions 受影响
  • 状态恢复:从 PG checkpoint 恢复,无状态丢失
  • Health check:HAProxy inter 5s, fall 3, rise 2 自动摘除/恢复节点

11.6.3 部署命令

task ha:up      # 一键启动 Swarm HA
task ha:down    # 一键拆除
N=5 task deploy:swarm:scale    # 扩缩容
task deploy:swarm:update       # 滚动更新
task deploy:swarm:status       # 查看实例状态

11.7 异常层次与错误处理

TTDError                          # 基类
├── ClarificationNeededError      # Follow-up 发现歧义
├── PolicyViolationError          # Guardrails 安全策略违规
├── SQLValidationError            # SQL 校验失败(syntax/policy/EXPLAIN)
├── RetrievalMissError            # R/V/G 三引擎均未命中
└── ModelUnavailableError         # 模型 API 不可达且无 fallback

错误通过 state["errors"] 列表传播,不直接抛异常(符合 LangGraph 的状态增量模式)。技术错误经 Sanitization 转为用户友好中文消息(如 "statement timeout" → "查询执行超时,请尝试缩小查询范围")。


11.8 请求生命周期

一个 Chat BI 请求从客户端到响应的完整调用链:

sequenceDiagram
    autonumber
    box rgb(248,249,250) 外部客户端
        participant C as 客户端
        participant H as HAProxy
    end
    box rgb(232,240,254) FastAPI 运行时
        participant F as FastAPI
        participant MW as 中间件栈
        participant R as Router (chats.py)
        participant LG as LangGraph
        participant S as SSE Stream
    end
    box rgb(224,242,241) 数据面
        participant DP as DataPlane
    end

    C->>H: POST /api/v1/chats/{id}/messages
    H->>H: 一致性哈希 (X-Chat-ID) → 目标实例
    H->>F: 转发请求
    F->>MW: CORS → 速率限制 → JWT 验签 → 请求日志
    MW->>R: 认证后的 request + user
    R->>R: 加载 session + 初始化 AgenticBIState
    R->>LG: graph.astream(initial_state, config)
    loop SSE 事件流
        LG->>LG: 执行节点 (supervisor→QU→router→...)
        LG-->>R: node_complete 事件
        R-->>S: yield SSE event
        S-->>C: 流式推送(29 事件类型)
    end
    LG->>DP: SQL 执行(仅 sql_executor 节点)
    DP-->>LG: 结果集
    LG-->>R: 最终结果 + insights
    R-->>S: yield data + insights + status=completed
    S-->>C: 关闭流

中间件栈(按执行顺序)

顺序 中间件 职责 失败行为
1 CORS 允许前端域名跨域
2 slowapi 速率限制 60/minute per IP(第 14 章 429 Too Many Requests
3 JWT 验签 JWKS 公钥验签 RS256 JWT 401 Unauthorized
4 请求日志 structlog 记录 request_id + user_id + 耗时

依赖注入

FastAPI 的依赖注入在 Router 层解析:

# backend/app/api/chats.py
@router.post("/{chat_id}/messages")
@limiter.limit("60/minute")
async def send_message(
    chat_id: str,
    body: MessageCreate,
    request: Request,
    user: AuthUser = Depends(get_current_user),      # JWT → user
    store: AsyncPostgresStore = Depends(get_store),   # LangGraph Store
    session: AsyncSession = Depends(get_db_session),  # ORM session
):

get_current_user 从 request 中提取 JWT → JWKS 验签 → 返回 AuthUserget_store / get_db_session 从连接池获取。


11.9 并发模型

async/await 在 Agent 场景的最佳实践

TTD Backend 全程 async/await,但需注意 LangGraph 的并发特性:

维度 实践 原因
节点内 LLM 调用 await llm.ainvoke() LLM API 是 I/O 密集,async 不阻塞事件循环
节点内 DB 查询 await session.execute() asyncpg 异步驱动
并行检索 asyncio.gather(engine_r(), engine_v(), engine_g()) 四引擎无依赖,并行召回
LangGraph 并发 run asyncio.create_task(graph.astream(...)) 每个用户请求一个 task
CPU 密集(嵌入计算) asyncio.to_thread(embed_fn) 嵌入计算阻塞事件循环,丢到线程池

LangGraph 并发 run 的陷阱

多用户并发时,每个请求独立 graph.astream()——它们共享同一个 graph 编译对象(线程安全),但各自有独立的 AgenticBIState 副本。不要在节点函数中使用模块级可变状态(如全局缓存 dict),否则并发请求会相互污染。TTD 的所有状态通过 state 参数传递,或通过 LangGraph Store(线程安全)共享。

并发能力估算

资源 限制 单请求占用 理论并发上限
PG 连接池 TTD_PG_POOL_MAX=20 1 连接(查询时) 20
LLM API 并发 DashScope 默认 50 QPS 1 QPS(生成时) 50
事件循环 单进程单循环 ~1MB 栈 ~1000(理论)
实际瓶颈 PG 连接池 ~20 并发查询

上述并发上限为设计估算。生产扩容通过 Swarm 多实例 + 每实例独立连接池实现水平扩展。


11.10 性能调优

连接池配置

# backend/app/db/session.py
engine = create_async_engine(
    settings.database_url,
    pool_size=5,           # 持久连接数(常态)
    max_overflow=15,       # 突发时可超额(总上限 20)
    pool_timeout=30,       # 等待连接超时
    pool_recycle=1800,     # 30 分钟回收(防止 PG 断连)
    pool_pre_ping=True,    # 使用前 ping(检测断连)
)
参数 调优依据
pool_size 5 常态并发查询数(开发环境)
max_overflow 15 突发流量缓冲,总上限 20 对应 TTD_PG_POOL_MAX
pool_timeout 30s 超时后返回 503,避免无限等待
pool_recycle 1800s PG 默认 idle_timeout 通常 > 1h,30 分钟回收防边界
pool_pre_ping True 容器网络中连接可能被静默断开

其他生产调优

配置 效果
uvloop uvloop.install()(main.py) 替代默认 asyncio 事件循环,吞吐提升 2-4x
GC 调优 PYTHON_GC_THRESHOLD=700,10,10 减少全代 GC 频率,降低长查询尾延迟
Metadata Cache TTL 24h 元数据查询从 PG 降到内存,省 ~5ms/请求
SQL Cache TTL 1h + cosine 0.92 相似问题跳过检索+生成,命中时 ~250ms 返回
orjson ORJSONResponse 替代标准 json,序列化快 2-3x

性能数字为设计目标

上述提升倍数为经验/基准值,未经 TTD 环境实测。系统化性能基线见 第 16 章


11.11 小结

本章要点

  1. Backend 是 FastAPI + LangGraph 服务,API 分 Chat BI(主)/ Admin / Utility 三类。
  2. 请求生命周期:HAProxy → 中间件栈(CORS/限流/JWT/日志)→ Router → LangGraph → SSE 流式返回。
  3. 并发模型:全程 async/await,四引擎并行检索;实际瓶颈是 PG 连接池(~20 并发),水平扩展靠 Swarm 多实例。
  4. 性能调优:连接池(pre_ping + recycle)、uvloop、GC 调优、Metadata/SQL Cache、orjson。
  5. 生产部署用 Agent Runtime Pool + HAProxy 一致性哈希(性能优化)+ PG Advisory Lock(正确性保证)。
  6. 环境变量完整参考在 附录 B(唯一权威)。

下一章第 12 章 Web 前端——Next.js 架构、Better Auth、SSE 契约与可视化组件。