第 2 章 整体架构与设计哲学¶
本章学习目标 - 掌握 TTD 的全局架构与三个关键"分离"设计 - 深入理解五层逻辑模型的设计动机与层间调用约束 - 逐 walk through 在线查询链路的 9 个步骤与离线发布管道 - 理解 R/V/G/D 四引擎如何在 PG Supernode 上协作 - 把握八项架构原则背后的工程取舍
前置知识:第 1 章 导论 关联代码:
backend/app/agents/builder.py、backend/app/main.py、data-plane/docker-compose.yml
2.1 全局架构¶
C4Deployment
title TTD 全局架构 — Deployment Diagram
Deployment_Node(browser_tier, "用户浏览器", "Chrome / Edge / Safari", "纯客户端运行环境,无服务端逻辑") {
Container(web_frontend, "Web 前端", "Next.js 16 · React 19", "用户交互层:SSE 流式展示,Better Auth 签发 JWT")
}
Deployment_Node(haproxy_tier, "HAProxy 负载均衡", "HAProxy 2.9 · TCP/HTTP", "基于 X-Chat-ID 做 ketama 一致性哈希") {
Container(haproxy, "HAProxy", "Consistent Hash (ketama)", "会话亲和路由,健康检查 5s,实例增减仅 ~1/N 受影响")
}
Deployment_Node(swarm_cluster, "Agent Runtime Pool", "Docker Swarm · N×16C/32G", "无状态 FastAPI 实例水平扩展,单 worker/实例") {
Container(runtime_1, "Runtime #1", "FastAPI · LangGraph · 1 worker", "完整 Agent 管线:Supervisor → QU → Router → RAG → SQL Gen → Guardrails → Viz")
Container(runtime_n, "Runtime #N", "FastAPI · LangGraph · 1 worker", "与 #1 完全一致,实例间 zero gossip,共享状态通过 PG")
}
Deployment_Node(pg_tier, "PG Supernode", "PostgreSQL 18 · pgvector · AGE", "R/V/G 引擎统一部署,事务一致") {
ContainerDb(pg_supernode, "PG Supernode", "PostgreSQL 18", "semlayer.* + ttd_governance AGE 图 + 检查点 + 长期记忆 + SQL 缓存")
}
Deployment_Node(data_tier, "Data Plane", "Redshift / pg_mooncake", "双后端,环境变量切换") {
Container(data_plane, "Data Plane", "Redshift / pg_mooncake", "执行用户 SQL 查询,sqlglot 适配方言")
}
Deployment_Node(publish_tier, "离线发布管道", "GitHub Actions · Python 3.12", "YAML 从编辑到 S3 发布") {
Container(yaml_pipeline, "发布管道", "Git · CI · PR · S3", "4 校验脚本通过后自动发布到 S3,Backend 后台同步")
}
System_Ext(dashscope, "DashScope API", "阿里云·百炼平台", "提供 LLM 推理与 Embedding")
Rel(web_frontend, haproxy, "HTTP + JWT header", "HTTPS · X-Chat-ID")
Rel(haproxy, runtime_1, "hash(chat_id) 路由", "HTTP · ketama")
Rel(haproxy, runtime_n, "hash(chat_id) 路由", "HTTP · ketama")
Rel(runtime_1, pg_supernode, "RAG检索·检查点·锁", "asyncpg · TCP")
Rel(runtime_n, pg_supernode, "RAG检索·检查点·锁", "asyncpg · TCP")
Rel(runtime_1, data_plane, "执行 SQL", "redshift-connector / psycopg")
Rel(runtime_n, data_plane, "执行 SQL", "redshift-connector / psycopg")
Rel(runtime_1, dashscope, "调用 LLM + Embedding", "HTTPS")
Rel(runtime_n, dashscope, "调用 LLM + Embedding", "HTTPS")
Rel(yaml_pipeline, pg_supernode, "离线同步语义资产", "R+V+G Pipeline")
UpdateElementStyle(web_frontend, $fontColor="#202124", $bgColor="#e8f0fe", $borderColor="#1a73e8")
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")
UpdateElementStyle(data_plane, $fontColor="#202124", $bgColor="#e0f2f1", $borderColor="#0d7377")
UpdateElementStyle(yaml_pipeline, $fontColor="#202124", $bgColor="#f3e8fd", $borderColor="#9334e6")
UpdateElementStyle(dashscope, $fontColor="#5f6368", $bgColor="#f8f9fa", $borderColor="#dadce0")
UpdateRelStyle(haproxy, runtime_1, $textColor="#1a73e8", $lineColor="#1a73e8")
UpdateRelStyle(runtime_1, pg_supernode, $textColor="#0d7377", $lineColor="#0d7377")
UpdateRelStyle(runtime_1, dashscope, $textColor="#5f6368", $lineColor="#dadce0")
UpdateLayoutConfig($c4ShapeInRow="4", $c4BoundaryInRow="2")
2.1.1 三个关键分离¶
架构的精髓在三个"分离",每个分离都解决一个核心矛盾:
1. 治理态与执行态分离(Two-Plane)
语义资产在 Git 里以 YAML 编写(治理态),发布到运行时 DB 才生效(执行态)。
- 解决的矛盾:治理需要版本控制、代码审查、可追溯(慢节奏、高质量);运行时查询需要低延迟、高吞吐(快节奏、高性能)。两者迭代节奏根本不同。
- 代价:需要同步管道,存在短暂一致性窗口。
- 详见 ADR-1、第 9 章。
2. 在线链路与离线链路分离
用户查询走在线链路(Supervisor → SQL 执行);元数据发布走离线链路(YAML → Git hooks → CI → PR → S3 → Backend 导入)。
- 解决的矛盾:在线查询要求稳定不被打扰;元数据发布是批量操作,可能耗时(embedding 生成)。两者解耦后,发布不影响在线查询。
- 实现:Backend 后台轮询 S3 manifest hash,检测变更后异步执行 R/V/G pipeline。
3. 编排与智能分离
LangGraph 图负责"编排"(路由、流程控制、重试),各 Sub-agent 负责"智能"(LLM 调用、领域逻辑)。
- 解决的矛盾:编排需要确定性、可审计(控制面);智能需要灵活性、LLM 驱动(数据面)。混在一起会让流程不可控、智能难替换。
- 结果:编排是确定性的、可审计的;智能是局部的、可替换的(换模型不影响流程)。
2.2 五层逻辑模型¶
TTD 采用五层逻辑架构,每层职责单一、边界清晰,只能向下调用,不允许跳层:
| 层级 | 名称 | 核心组件 | 关键目录 |
|---|---|---|---|
| L1 | 交互层 Interaction | Web Frontend (Next.js 16, SSE, Admin Panel, shadcn/ui), Better Auth | web/ |
| L2 | 编排层 Orchestration | LangGraph Supervisor, Query Understanding, Router, 7 路由 | backend/app/agents/ |
| L3 | 智能层 Intelligence | Sub-agents (SQL Gen, Guardrails, Insights, Viz, Analytics, Graph RAG) | backend/app/agents/sub_agents/ |
| L4 | 数据层 Data | Data Plane (Redshift/pg_mooncake), Semantic Layer (pgvector+AGE+Relational) | data-plane/, backend/app/skills/ |
| L5 | 治理层 Governance | Semantic Plane (YAML), Backend Publishing Pipeline, CI Scripts | semantic-plane/, backend/app/agents/semantic_plane/, scripts/ |
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#e8f0fe','primaryTextColor':'#202124','primaryBorderColor':'#1a73e8','lineColor':'#5f6368','secondaryColor':'#e0f2f1','tertiaryColor':'#f8f9fa'}}}%%
flowchart LR
subgraph L1["L1 交互层"]
WEB["Next.js 16<br/>SSE · Admin · Better Auth"]
end
subgraph L2["L2 编排层(控制面)"]
SUP["Supervisor<br/>QU · Router · 7 路由"]
end
subgraph L3["L3 智能层(数据面)"]
AG["SQL Gen · Guardrails<br/>Insights · Viz · Analytics<br/>Graph RAG · ML Tools"]
end
subgraph L4["L4 数据层"]
DP["Data Plane · Semantic Layer<br/>R + V + G + D 四引擎"]
end
subgraph L5["L5 治理层"]
YML["YAML Assets<br/>pre-commit · CI · PR · S3"]
end
L1 -->|"SSE + JWT"| L2 -->|"Command(goto)"| L3 -->|"SQL 执行<br/>RAG 检索"| L4
L5 -.->|"Git+CI/CD<br/>离线发布"| L4
classDef bpProcess fill:#e8f0fe,stroke:#1a73e8,stroke-width:2px,color:#202124
classDef bpData fill:#e0f2f1,stroke:#0d7377,stroke-width:2px,color:#202124
classDef bpExternal fill:#f8f9fa,stroke:#dadce0,stroke-width:2px,color:#5f6368
classDef bpInfo fill:#f3e8fd,stroke:#9334e6,stroke-width:2px,color:#202124
class WEB,SUP,AG bpProcess
class DP bpData
class YML bpInfo
2.2.1 各层职责深度解析¶
L1 交互层:用户唯一接触点。负责流式展示(SSE)、会话管理、可视化渲染、管理后台。Better Auth 托管在此层,签发 JWT 给下层。这层不包含任何业务逻辑——它只负责"展示"与"转发"。
L2 编排层:系统的控制面。LangGraph StateGraph 定义了 20+ 节点的拓扑与条件路由。所有"下一步做什么""失败怎么办""何时降级"的决策都在此层。这是系统可审计性的根基——流程是确定性的、可回放的。
L3 智能层:系统的数据面。每个 Sub-agent 专注单一能力域(SQL 生成、护栏、洞察、可视化...),内部调用 LLM 或规则引擎。这层是"可替换"的——换模型、换实现不影响 L2 编排。
L4 数据层:双重职责。一是承载语义层存储(PG Supernode 的 R/V/G),供 L2/L3 检索;二是承载业务数据(Redshift/pg_mooncake),供 SQL 执行。两者物理分离但逻辑统一。
L5 治理层:完全离线。语义资产在 Git 中以 YAML 编写,经 hooks + CI + PR 审查后发布到 S3,Backend 自动同步到 L4。不参与在线请求路径,保证不影响查询性能。
层间调用约束
- 只能向下调用:L1 → L2 → L3 → L4,L1 不可直接调 L4(否则绕过编排控制面,破坏可审计性)
- 治理层独立发布:L5 通过离线管道写入 L4,不参与在线请求路径
- 编排层是唯一控制面:所有 Sub-agent 的调度、重试、降级决策均在 L2 完成
这三条约束是系统可维护性的根基。违反任一条都会导致控制流混乱、审计断裂。
2.3 认证与令牌链路¶
TTD 采用 Better Auth 作为统一身份源,托管在 Next.js(L1),FastAPI(L2/L3)通过 JWKS 本地验签信任其签发的 JWT。
sequenceDiagram
autonumber
box rgb(248,249,250) Browser
participant U as Browser
end
box rgb(232,240,254) Frontend
participant W as Next.js (Better Auth)
end
box rgb(224,242,241) Backend & Data
participant DB as PostgreSQL (auth tables)
participant LB as HAProxy
participant API as FastAPI Runtime
end
Note over U,W: 1. 用户登录
U->>W: POST /api/auth/sign-in/email
W->>DB: 验证凭据,创建 session
W-->>U: Set-Cookie: better-auth.session_token
Note over U,API: 2. 获取 API Token
U->>W: GET /api/auth/token
W->>DB: 从 jwks 表取私钥
W-->>U: signed JWT (RS256, 1h TTL)
Note over U,API: 3. 访问后端 API
U->>LB: GET /api/v1/chats (Authorization: Bearer)
LB->>API: hash(chat_id) → runtime
API->>API: PyJWKClient → JWKS 公钥验签
API-->>U: 200 OK
2.3.1 设计要点¶
| 原则 | 说明 | 为什么这样设计 |
|---|---|---|
| 单一身份源 | Better Auth 是唯一用户/会话权威 | 避免双套认证的数据不一致 |
| JWT 仅用于 API | 浏览器主会话由 cookie 管理,JWT 是短期令牌 | cookie 有自动过期与 SameSite 保护,JWT 短命降低泄露风险 |
| 本地验签 | FastAPI 通过 JWKS 公钥本地验证 | 避免逐请求 introspection 的网络延迟 |
| Identity Continuity | Better Auth user.id 直接作为后端 user_id |
无映射表,避免 ID 转换错误 |
| RS256 非对称签名 | 私钥在 Next.js 签发,公钥在 FastAPI 验签 | 私钥不离开签发方,比 HS256 对称密钥更安全 |
2.4 在线查询链路¶
以下序列图展示一个典型 NL2SQL 查询从提问到返回的完整链路。这是全书最重要的图之一——后续第 4-8 章都是在展开这条链路的各个环节:
sequenceDiagram
autonumber
box rgb(248,249,250) 用户前端
participant U as 用户
participant W as Web (Next.js)
end
box rgb(232,240,254) Agent 运行时
participant API as Backend API
participant SUP as Supervisor
participant QU as Query Understanding
participant RTR as Router
end
box rgb(224,242,241) 检索与生成
participant DR as Data Retrieval
participant RR as Reranker
participant SP as Semantic Planner
participant SG as SQL Generator
participant GR as Guardrails
participant CR as Corrective Retrieval
end
box rgb(224,242,241) 执行与后处理
participant EX as SQL Executor
participant RP as Result Processor
participant VZ as Visualization
participant IN as Insights
end
box rgb(224,242,241) 数据基础设施
participant DP as Data Plane
participant PG as PG Supernode
end
box rgb(243,232,253) 外部模型
participant LLM as LLM
end
U->>W: 输入自然语言问题
W->>API: POST /api/v1/chats/{id}/messages/stream (SSE)
Note over SUP,PG: Step 1: Embedding + 治理叠加层
SUP->>PG: compute embedding (text-embedding-v4)
SUP->>PG: resolve_governance_context()
Note over QU,LLM: Step 2: 意图解析
SUP->>QU: 委派
QU->>LLM: intent parsing + entity extraction
QU-->>RTR: intent + rewritten_question
Note over RTR: Step 3: 路由决策(确定性映射)
RTR->>RTR: intent → _INTENT_TO_ROUTE mapping
RTR->>RTR: check SQL Cache (sim ≥ 0.92)
RTR-->>DR: Command(goto="data_retrieval")
Note over DR,RR: Step 4: R/V/G/D 四引擎检索 + 重排
DR->>PG: R/V/G/D 四引擎并行检索 (asyncio.gather)
DR-->>RR: retrieval_results + term_bindings
RR->>RR: 术语绑定加分 + RRF 重排序
RR-->>SP: 精排结果
Note over SP,SG: Step 5-6: 语义规划 + SQL 生成
SP->>SP: KMB Steiner 树 join 路由 + 代数重写
SP-->>SG: semantic_guidance(结构化 join 建议)
SG->>LLM: prompt(RAG 检索 + guidance + few_shots + 方言)
SG-->>GR: generated_sql
Note over GR: Step 7: 五层护栏校验
GR->>GR: 语法 → 策略禁词 → AST 列引用 → 术语绑定 → EXPLAIN
alt 校验通过
GR-->>EX: execute
else 可修复(列错误/术语违规,最多2次)
GR-->>CR: corrective_retrieval
CR-->>SG: 补充列信息 → 重新生成
SG-->>GR: 重试
else 不可修复(策略违规/禁止操作)
GR-->>API: reject(用户友好错误)
end
Note over EX,IN: Step 8-9: 执行 + 可视化 + 洞察
EX->>DP: 执行 SQL(注入 LIMIT + statement_timeout)
EX-->>RP: result rows
RP-->>VZ: cleaned result
VZ->>VZ: 规则推荐图表(95%+ 无需 LLM)
VZ-->>IN: 触发洞察生成
IN->>LLM: 生成 insights(趋势解读 + 异动解释)
IN-->>API: SSE 流式返回
API-->>W: events(status → sql → result → viz → insights)
W-->>U: 渐进式渲染(ThinkingSteps + 表格 + ECharts)
2.4.1 九步详解¶
Step 1 — Supervisor(嵌入 + 治理):计算问题的 embedding 向量(text-embedding-v4),解析治理叠加层(tenant/region/compliance)。Supervisor 极轻量(ADR-3),只做这两件事就委托给 QU。embedding 是后续所有向量检索的基础。
Step 2 — Query Understanding(意图解析):LLM 将自然语言解析为结构化 JSON——intent_type(17 种)、entities、metric_candidates、dimension_candidates、时间/地域约束、needs_clarification。这是"理解用户到底要什么"的关键一步。详见 第 4 章。
Step 3 — Router(路由决策):纯确定性映射(非 ML),用 _INTENT_TO_ROUTE 表把 intent 映射到 7 条路由。同时检查 SQL Cache——若问题 embedding 与缓存 SQL 的 embedding 相似度 ≥ 0.92,直接跳转 guardrails,跳过检索与生成。详见 第 4 章。
Step 4 — Data Retrieval + Reranker(检索增强):四引擎并行检索(R/V/G/D),Reranker 做术语绑定感知重排。这是 RAG 的核心,详见 第 5 章。术语绑定(term binding)在此步建立——"GMV" 绑定到 metric_gmv,贯穿后续全管道。
Step 5 — Semantic Planner(语义规划):纯计算节点(无 LLM),用 KMB Steiner 树找最小代价 join 子图,用代数重写识别 chasm trap/多余 join/存在性语义。产出结构化 guidance 增强 LLM 生成。详见 第 6 章。
Step 6 — SQL Generation(SQL 生成):LLM 在 RAG 检索结果 + 语义 guidance + few-shot 约束下生成 SQL。Prompt 工程极其详尽(方言指导、白名单、性能要求、反幻觉约束)。详见 第 6 章。
Step 7 — Guardrails(五层校验):语法 → 策略禁词 → AST 列引用 → 术语绑定语义 → EXPLAIN 成本。失败时触发修复循环(corrective_retrieval → 重新生成),最多 2 次。详见 第 6 章。
Step 8 — Execution + Post-processing(执行 + 后处理):在数据面执行 SQL(注入 LIMIT + timeout),结果格式化截断,SQL Explainer 用 LLM 生成业务解释。
Step 9 — Visualization + Insights(可视化 + 洞察):规则推荐图表(95%+ 无需 LLM),LLM 生成数据洞察与追问建议。详见 第 8 章。
2.4.2 路由决策矩阵¶
| Route | 触发意图 | 执行路径 | 特点 |
|---|---|---|---|
kpi_lookup |
KPI 直查 | retrieval → reranker → sql_gen → guardrails → executor → explainer | 最短路径 |
nl2sql_query |
趋势/对比/排名 | 完整管道 + viz + insights | 主路径 |
deep_analysis_workflow |
根因分析/报告 | planner + 全链路 + 三级评估器 | 含评估 |
analytical_workflow |
归因/预测/分群 | + analytical_agent (ML) | v5.0 |
graph_reasoning |
关系探索 | graph_rag_agent (NL2Cypher) | 失败回退 SQL |
business_knowledge_qa |
政策/SOP 问答 | retrieval → knowledge_qa_agent | 不生成 SQL |
clarification_required |
模糊意图 | retrieval → follow_up_agent | 返回澄清选项 |
SQL Cache 快速路径
当 Router 检测到问题 embedding 与缓存 SQL 的 embedding 相似度 ≥ 0.92 时,直接跳转 guardrails_agent,跳过检索与生成,大幅降低延迟。这是"用空间换时间"的优化,详见 第 7 章 SQL 缓存。
2.5 离线发布链路¶
语义资产从 YAML 编辑到线上生效的完整管道——这是"治理态到执行态"的桥梁:
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#e8f0fe','primaryTextColor':'#202124','primaryBorderColor':'#1a73e8','lineColor':'#5f6368','secondaryColor':'#e0f2f1','tertiaryColor':'#f8f9fa'}}}%%
flowchart TB
subgraph DevPhase["开发阶段(本地)"]
direction LR
EDIT["Data Steward<br/>编辑 YAML"]
HOOK["pre-commit hooks<br/>schema · sqlglot 快速校验"]
EDIT -->|"git commit"| HOOK
end
subgraph CIPhase["CI / PR 阶段(GitHub)"]
direction LR
CI["GitHub Actions<br/>4 个校验脚本并行"]
PR["PR Review<br/>Governance Lead 审批"]
CI -->|"全部通过"| PR
end
subgraph DeployPhase["部署阶段"]
direction LR
PUB["合并后<br/>自动发布到 S3"]
BACKEND["Backend 检测 manifest<br/>R+V+G pipeline 同步"]
PUB -->|"manifest hash 变更"| BACKEND
end
DevPhase -->|"git push → 创建 PR"| CIPhase
CIPhase -->|"merge to main"| DeployPhase
classDef bpProcess fill:#e8f0fe,stroke:#1a73e8,stroke-width:2px,color:#202124
classDef bpData fill:#e0f2f1,stroke:#0d7377,stroke-width:2px,color:#202124
classDef bpDecision fill:#fef7e0,stroke:#f9ab00,stroke-width:2px,color:#202124
classDef bpSuccess fill:#e6f4ea,stroke:#1e8e3e,stroke-width:2px,color:#202124
classDef bpGroup fill:#f8f9fa,stroke:#dadce0,stroke-width:1px,color:#3c4043
class EDIT,HOOK bpProcess
class CI,PR bpDecision
class PUB,BACKEND bpSuccess
2.5.1 端到端流程¶
| 步骤 | 环节 | 工具 | 失败处理 |
|---|---|---|---|
| 1 | 本地编辑 | IDE + YAML | — |
| 2 | 本地校验 | pre-commit hooks(快速 schema 校验) | 阻止提交 |
| 3 | CI 校验 | validate_all_yaml.py(JSON Schema) |
阻断 PR |
| 4 | CI 校验 | validate_sql_definitions.py(metric SQL 语法) |
阻断 PR |
| 5 | CI 校验 | validate_cross_layer_refs.py(跨层引用) |
阻断 PR |
| 6 | CI 校验 | check_version_bump.py(版本递增) |
强制 bump |
| 7 | 审查 | GitHub PR Review(MAJOR 变更需 Governance Lead) | 人工把关 |
| 8 | 发布 | 合并后自动发布 YAML 到 S3 | 重试 |
| 9 | 同步 | Backend semantic_plane agent(R+V+G pipeline) |
事务回滚 + 重试 |
Backend 后台轮询 S3 manifest hash,检测变更后异步执行:Upsert 关系表(Engine R)→ MERGE AGE 图(Engine G)→ 生成 embedding 写入 pgvector(Engine V)。详见 第 9 章。
2.6 R/V/G/D 四引擎协作¶
TTD 的 PG Supernode 将 R/V/G 三引擎统一部署在同一 PostgreSQL 实例,再叠加 Engine D(动态 Few-Shot),实现"一个连接池、四种检索范式":
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#e8f0fe','primaryTextColor':'#202124','primaryBorderColor':'#1a73e8','lineColor':'#5f6368','secondaryColor':'#e0f2f1','tertiaryColor':'#f8f9fa'}}}%%
flowchart LR
subgraph PG["PostgreSQL — PG Supernode"]
direction TB
subgraph ER["Engine R — Relational"]
R1["semlayer.*<br/>17 张关系表"]
end
subgraph EV["Engine V — Vector"]
V1["pgvector<br/>8 张 embedding 表<br/>HNSW 索引"]
end
subgraph EG["Engine G — Graph"]
G1["Apache AGE<br/>ttd_governance 属性图"]
end
subgraph ED["Engine D — Dynamic Few-Shot"]
D1["semlayer.<br/>dynamic_few_shot_cache<br/>pgvector · approved"]
end
end
Q["查询请求<br/>embedding + search_terms"] -->|"精确匹配<br/>term ILIKE"| ER
Q -->|"语义向量<br/>cosine top-k"| EV
Q -->|"图遍历<br/>NL2Cypher"| EG
Q -->|"经验复用<br/>sim≥0.95"| ED
classDef bpProcess fill:#e8f0fe,stroke:#1a73e8,stroke-width:2px,color:#202124
classDef bpData fill:#e0f2f1,stroke:#0d7377,stroke-width:2px,color:#202124
classDef bpGroup fill:#f8f9fa,stroke:#dadce0,stroke-width:1px,color:#3c4043
class Q bpProcess
class R1,V1,G1,D1 bpData
2.6.1 为什么需要四引擎¶
NL2SQL 场景存在四种截然不同的检索模式,单一引擎无法同时优化:
| 检索模式 | 例子 | 最佳引擎 |
|---|---|---|
| 精确匹配 | "GMV" 术语定义查找 | R(关系查询,< 5ms) |
| 语义模糊 | "和销售相关的表" | V(向量相似度,10-50ms) |
| 关系推理 | "fact_transaction 能 join 到哪些表" | G(图遍历,10-100ms) |
| 经验复用 | "上次类似查询怎么写的" | D(动态 few-shot,10-30ms) |
2.6.2 四引擎对比¶
| 维度 | Engine R | Engine V | Engine G | Engine D |
|---|---|---|---|---|
| 目的 | 精确查询 | 语义模糊匹配 | 关系推理 | 在线学习 few-shot |
| 访问模式 | FK lookup, 精确匹配 | Top-K cosine | Cypher 遍历 | Top-K cosine + 审批过滤 |
| 写入时机 | 发布管道实时 | 发布管道实时 | 发布管道实时 | SQL 修复成功时(待审批) |
| 延迟 | < 5ms | 10-50ms | 10-100ms | 10-30ms |
四引擎的检索编排、Reranker、补偿检索等细节在 第 5 章 深入。
2.7 架构原则¶
| # | 原则 | 核心要点 |
|---|---|---|
| 1 | 治理优先 Governance First | SQL 生成必须经术语、规则、上下文约束 |
| 2 | 异步优先 Async First | 全链路 async/await,最大化并发吞吐 |
| 3 | 纵深防御 Defense in Depth | 安全检查在意图→检索→生成→执行多层重复 |
| 4 | 可观测 Observable | 全链路结构化日志 + Prometheus + Langfuse |
| 5 | 可演进 Evolvable | 语义资产、模型、数据源支持热切换 |
| 6 | 本地可复现 Locally Reproducible | 笔记本能跑通完整闭环,无需 AWS 账号 |
| 7 | Fail-Safe | 不确定时拒绝执行,而非尝试 |
| 8 | 配置集中 Centralized Config | TTD_ 前缀 + Pydantic Settings 统一管理 |
2.7.1 原则 1:治理优先¶
语义治理不是事后补充,而是内嵌于查询管道的核心约束:
- SQL Generator 的 prompt 中必须包含治理上下文(术语规范、业务规则)
- Guardrails Agent 检查 SQL 是否违反 Layer 3 业务规则
- Graph Engine (AGE) 在检索阶段执行边界约束
governance_overlays在 Supervisor 阶段一次性解析,下游所有节点共享
2.7.2 原则 3:纵深防御¶
安全检查不依赖单点,每一层独立执行各自的安全职责:
[意图层] QU 识别高风险意图 → 标记 requires_elevated_check
↓
[检索层] Data Retrieval 过滤 sensitivity_level=pii 的列
↓
[生成层] SQL Generator 遵循 llm_exposure_policy 约束
↓
[校验层] Guardrails 检测 forbidden_keywords + EXPLAIN cost
↓
[执行层] SQL Executor 注入 LIMIT + statement_timeout
AI Agent 理论关联:确定性 DAG vs ReAct 自主循环
Agent 编排有两种主流范式:
- ReAct 自主循环:LLM 在每一步自主决定"思考→行动→观察",循环直至完成。灵活但不可预测、难审计、易跑偏。代表:原生 ReAct、AutoGPT 式自主 Agent。
- 确定性 DAG + 条件路由:预定义节点拓扑与路由规则,LLM 只在节点内部做局部决策。可预测、可审计、可控,但灵活性低。代表:LangGraph StateGraph、多数生产 Agent 系统。
TTD 选择后者,因为 NL2SQL 场景对安全性与可审计性的要求高于灵活性——一条错误的 SQL 可能扫垮生产库。但这也意味着系统无法处理"预料之外"的查询模式,需要靠路由扩展来适应。这一取舍的利弊在 第 4 章 与 第 16 章 进一步讨论。
2.7.4 架构反模式¶
八项原则的正面陈述容易读过即忘——下面用反模式(违反原则会导致什么)来加深理解。每个反模式都是 TTD 在设计过程中主动规避的,部分曾在早期原型中出现过。
| 违反的原则 | 反模式 | 具体后果 | TTD 的规避方式 |
|---|---|---|---|
| 治理优先 | 把治理检查放在 SQL 执行后("先生成再过滤") | 治理与生成耦合,改一处动全身;危险的 SQL 已生成并可能执行 | 治理信号在 Supervisor 一次性解析为 governance_overlays,注入检索/Prompt/护栏全程 |
| 双面板分离 | 让在线查询路径直接读 Git 仓库的 YAML | 查询延迟受 Git I/O 影响;运行时与发布时耦合,无法独立扩缩容 | 语义面发布到 S3 + 数据面 semlayer.* 表,在线路径只读数据面 |
| L2 只能向下调用 | 让数据面(L4)反向调用编排层(L2)回调 Agent | 层间循环依赖,无法独立测试;状态管理混乱 | 严格单向调用;数据面执行器是纯函数,完成后由编排层轮询/回调 |
| 纵深防御 | 只在执行层做安全检查("反正最后会拦") | 生成层已消耗 LLM token 与延迟;危险 SQL 可能在拦截前被缓存 | 五层逐层收窄,从认证到执行每层独立拦截 |
| 确定性优先 | 用 LLM 做路由决策("让模型自己决定走哪条路") | 路由不确定,同一问题每次走不同路径,无法复现与调试 | 路由用显式 _INTENT_TO_ROUTE 映射表,纯确定性 |
| 异步优先 | 同步等待 LLM 完成才返回 HTTP 响应 | 长查询阻塞连接,并发能力骤降;用户体验差(长时间无反馈) | 全链路 SSE 流式返回,Thinking Steps 实时推送 |
| 配置集中化 | 把数据库密码硬编码进源码或 docker-compose | 密钥泄露风险;无法按环境切换;审计困难 | 全部走 TTD_ 前缀 + Pydantic Settings,敏感值标注 :material-lock:(见 附录 B) |
| 幂等可重放 | 查询结果不持久化,重试需重新跑全链路 | 重试成本高;无法做 A/B 对比;调试无回放 | turn 级别持久化 + Langfuse trace + SQL Cache,支持 /admin/evaluation_replay |
反模式的价值
反模式不是"别人犯过的错"——它们是设计诱惑。每个反模式在某种场景下看似合理(如"用 LLM 做路由更灵活"),但在 NL2SQL 的安全性与可审计性要求下会暴露问题。理解"为什么不这么做"比理解"应该怎么做"更能建立架构直觉。
2.8 方案选型对比¶
2.8.1 Agent 编排框架对比¶
| 维度 | LangGraph | AutoGen | CrewAI | LlamaIndex Agent |
|---|---|---|---|---|
| 编排模型 | 显式状态图(DAG + 条件边) | 对话式多 Agent | 角色分工流水线 | 工具循环 |
| 可控性 | 高(图结构显式可见) | 中(靠对话涌现) | 中 | 中 |
| 状态管理 | 内置 Checkpointer(持久化) | 需自建 | 弱 | 弱 |
| human-in-the-loop | 原生支持 interrupt | 需自建 | 弱 | 弱 |
| 适合场景 | 需要可审计的复杂工作流 | 多 Agent 对话协作 | 角色明确的任务分工 | 简单工具调用 |
| TTD 选择理由 | SQL 生成需要可审计、可回退、可持久化的工作流,LangGraph 的显式图最契合 |
2.8.2 单体 Agent vs 多 Agent 编排¶
| 维度 | 单体重型 Agent | 多 Agent 编排(TTD 选择) |
|---|---|---|
| 实现 | 一个大 prompt 干所有事 | 20+ 专职节点各司其职 |
| 可测试性 | 难(端到端黑盒) | 好(每节点可单测) |
| 可演进 | 改一处怕回归全链路 | 新增节点即新增能力 |
| 开销 | 少(少多次 LLM 调用) | 多(多次 LLM 调用,但可并行) |
| TTD 取舍 | 选多 Agent 换可维护性,代价是延迟与 token 成本 |
当前实现可改进之处
- 图节点过重:部分节点(如
sql_generation.py34KB、rag.py61KB)承载过多逻辑,违背"节点单一职责"。理想情况下应进一步拆分。改进:按子能力拆节点,或提取为可复用的 Skill。 - 状态字段过多:
AgenticBIState约 50 个字段,是"上帝对象"反模式,字段间隐含依赖难以追踪。改进:用子状态分组(input/retrieval/generation/...)或引入 dataclass 收敛。 - 缺 human-in-the-loop 中断点:LangGraph 原生支持 interrupt,但 TTD 只在可视化环节有 HITL,SQL 执行前没有"高危查询人工确认"的中断点。改进:对 EXPLAIN 成本超阈值的查询加 interrupt。
改进方向
这些改进点在 第 16 章 有对应方案。核心思路是:在保持确定性 DAG 可审计性的前提下,引入动态子图与中断点,让系统在关键决策处更灵活。
2.9 数据面切换¶
TTD 支持双数据面后端,通过环境变量一键切换:
| 维度 | 生产环境 (Redshift) | 开发环境 (pg_mooncake) |
|---|---|---|
| 引擎 | AWS Redshift Serverless | pg_mooncake (PostgreSQL + columnstore) |
| 连接 | redshift-connector |
psycopg |
| SQL 方言 | Redshift SQL | PostgreSQL |
| 成本 | 按用量计费 | 本地免费 |
SQL Generator 会在 prompt 中注入当前方言,确保生成的 SQL 兼容目标引擎。数据面的容器编排与 schema 细节见 第 10 章。
2.10 小结与延伸阅读¶
本章要点:
- TTD 架构基于三个分离:治理/执行态、在线/离线链路、编排/智能。
- 五层逻辑模型(L1-L5)只能向下调用,治理层独立离线发布。
- 在线查询 9 步链路:Supervisor → QU → Router → Retrieval → Reranker → Planner → SQL Gen → Guardrails → Execute → Viz/Insights。
- R/V/G/D 四引擎在 PG Supernode 上协作,各司其职。
- 编排选择"确定性 DAG + 条件路由"而非 ReAct 自主循环,换取可审计性与安全性。
延伸阅读:
- LangGraph 官方文档 — langchain-ai.github.io/langgraph
- Designing Data-Intensive Applications(Martin Kleppmann)— 分离策略的经典论述
下一章:第 3 章 关键设计决策(ADR)——逐条审视 18 个架构决策的来龙去脉,每条都附"反思与改进方向"。