运行与安全¶
适用对象
本文档面向 运维工程师、安全审计员 和 Backend Developer, 涵盖安全架构、可观测性、运行时稳定性及故障排查指南。
1. 安全架构 (Security Architecture)¶
TTD 采用 三层纵深防御 架构,确保从用户输入到数据返回的全链路安全。
1.1 安全分层总览¶
graph TB
subgraph API 层
A1[Better Auth JWKS Authentication]
A2[Rate Limiting]
A3[CORS Policy]
A4[Input Validation]
end
subgraph 生成层
B1[Content Safety Guard]
B2[SQL Validation]
B3[EXPLAIN Cost Check]
B4[Forbidden Keywords]
end
subgraph 数据层
C1[PII Exposure Policy]
C2[Domain Boundaries]
C3[Row-Level Security]
C4[Statement Timeout]
end
A1 --> B1
B1 --> C1
1.2 各层安全机制¶
| 层级 | 机制 | 实现位置 | 说明 |
|---|---|---|---|
| API 层 | JWT 认证 | backend/app/security/auth.py |
Better Auth JWKS (RS256) 验签,Token 有效期内免重认证 |
| API 层 | Rate Limiting | backend/app/api/ |
60 次/分钟/用户,突发上限 100 |
| API 层 | CORS | backend/app/main.py |
可配置允许来源 |
| API 层 | Input Validation | backend/app/api/ |
最大问题长度 2000 字符 |
| 生成层 | Content Safety Guard | backend/app/security/guard.py |
DML 检测、Prompt Injection 检测 |
| 生成层 | SQL Validation | backend/app/security/policy.py |
Forbidden keywords、语法校验 |
| 生成层 | EXPLAIN Cost Check | backend/app/agents/ |
预估行数/成本超限则拦截 |
| 数据层 | PII Policy | semantic-plane/ YAML |
llm_exposure_policy: visible/masked/hidden |
| 数据层 | Domain Boundaries | Semantic Plane | 仅允许查询已注册的表和列 |
| 数据层 | Statement Timeout | PostgreSQL / Redshift | 30s 硬超时 |
2. 认证与授权 (Authentication & Authorization)¶
2.1 整体架构¶
TTD 采用 Better Auth 作为统一身份与会话权威,托管在 Next.js 侧。FastAPI 后端通过 JWKS 本地验签 信任 Better Auth 签发的 JWT,不维护第二套认证逻辑。
sequenceDiagram
participant U as Browser
participant W as Next.js (Better Auth)
participant API as FastAPI Backend
U->>W: POST /api/auth/sign-in/email
W->>W: 验证凭据,创建 session
W-->>U: Set-Cookie (session token)
U->>W: GET /api/auth/token (JWT plugin)
W-->>U: signed JWT (RS256)
U->>API: GET /api/v1/chats (Authorization: Bearer <JWT>)
API->>API: 从 JWKS 获取公钥,验证 JWT 签名
API->>API: 校验 iss, aud, exp
API-->>U: 200 OK (chats list)
2.2 身份提供者 (Identity Provider)¶
| 组件 | 技术 | 说明 |
|---|---|---|
| IdP 框架 | Better Auth | 托管在 Next.js,提供注册/登录/会话/JWT/JWKS 端点 |
| Session 管理 | Better Auth native cookies | 浏览器主会话,7 天有效期 |
| JWT 签发 | Better Auth JWT plugin | RS256 签名,1 小时有效,用于 API 访问 |
| JWKS 端点 | /api/auth/jwks |
公钥发布,FastAPI 据此验签 |
| 数据存储 | PostgreSQL (共用实例) | user / session / account / verification / jwks 五表 |
支持的登录方式:
| 方式 | 状态 | 说明 |
|---|---|---|
| Email/Password | ✅ 已启用 | 最小密码长度 8 字符 |
| GitHub OAuth | ⚡ 条件启用 | 需配置 GITHUB_CLIENT_ID + GITHUB_CLIENT_SECRET |
2.3 JWT 验证 (FastAPI 侧)¶
FastAPI 使用 PyJWKClient 从 Better Auth JWKS 端点获取公钥,本地验签 JWT。
# 验证配置
Algorithm: RS256 / ES256
JWKS URL: ${BETTER_AUTH_URL}/api/auth/jwks
Issuer: ${BETTER_AUTH_URL} (e.g. http://localhost:3000)
Audience: talk-to-data
JWKS Cache TTL: 3600s (1 hour)
实现位置: backend/app/security/auth.py
# 核心验证流程
jwks_client = PyJWKClient(f"{better_auth_url}/api/auth/jwks")
signing_key = jwks_client.get_signing_key_from_jwt(token)
payload = jwt.decode(token, signing_key.key, algorithms=["RS256", "ES256"],
audience="talk-to-data", issuer=better_auth_url)
2.4 Token Claims 结构¶
{
"sub": "better_auth_user_id",
"role": "admin",
"aud": "talk-to-data",
"iss": "http://localhost:3000",
"exp": 1700000000,
"iat": 1699913600
}
| Claim | 类型 | 说明 |
|---|---|---|
sub |
string | Better Auth user.id — 全系统唯一主体标识 |
role |
string | 全局角色(Better Auth Admin plugin 设置) |
roles |
string[] | 兼容扩展角色列表(可选) |
allowed_domains |
string[] | 可访问业务域(Phase 1 为空集合) |
aud |
string | 预期受众,必须匹配 talk-to-data |
iss |
string | 签发者,必须匹配 BETTER_AUTH_URL |
exp |
int | 过期时间 (Unix timestamp) |
iat |
int | 签发时间 (Unix timestamp) |
2.5 授权模型¶
Phase 1 采用全局角色模型(不引入 Organization / Team / Dynamic RBAC):
| 角色 | 权限 |
|---|---|
admin |
全部 API + Admin Panel |
user (默认) |
Chat API + 自有资源访问 |
后端授权实现:
get_current_user— 解析 JWT,返回UserContext(user_id, roles, allowed_domains)require_admin— 依赖注入,要求admin角色,否则返回 403- 资源所有权 — Chat/Feedback 按
user_id过滤,不依赖前端判断
2.6 开发模式旁路 (Dev Mode Bypass)¶
仅限开发环境
当 TTD_DEBUG=true 且请求无 Bearer Token 时,系统返回默认 admin 上下文。
生产环境必须设置 TTD_DEBUG=false。
迁移期 HS256 回退
在 TTD_DEBUG=true 时,若 JWKS 验证失败,系统尝试以旧 HS256 secret 验证 Token。
此回退将在迁移完成后(Phase 7)移除。
2.7 环境变量清单¶
| 变量 | 位置 | 默认值 | 说明 |
|---|---|---|---|
BETTER_AUTH_URL |
Web + Backend | http://localhost:3000 |
Better Auth 基础 URL |
BETTER_AUTH_SECRET |
Web | dev-secret-change-me |
会话加密密钥(生产必须强随机值) |
AUTH_DATABASE_URL |
Web | — | Better Auth 专用数据库连接串 |
GITHUB_CLIENT_ID |
Web | — | GitHub OAuth App ID(可选) |
GITHUB_CLIENT_SECRET |
Web | — | GitHub OAuth App Secret(可选) |
NEXT_PUBLIC_GITHUB_AUTH_ENABLED |
Web | — | 前端是否显示 GitHub 按钮 |
TTD_JWT_AUDIENCE |
Backend | talk-to-data |
JWT audience 校验值 |
TTD_BETTER_AUTH_URL |
Backend | http://localhost:3000 |
JWKS 获取地址 |
TTD_BETTER_AUTH_ISSUER |
Backend | http://localhost:3000 |
JWT issuer 校验值 |
TTD_JWKS_CACHE_TTL_SECONDS |
Backend | 3600 |
JWKS 缓存刷新间隔 |
2.8 API Key 支持¶
管理类操作(如强制刷新缓存、手动触发 ingest)仍支持通过 API Key 认证:
3. SQL 安全策略 (SQL Security Policies)¶
3.1 Forbidden Keywords¶
生成的 SQL 严禁包含以下关键字(大小写不敏感):
FORBIDDEN_KEYWORDS = [
"INSERT", "UPDATE", "DELETE",
"DROP", "ALTER", "CREATE",
"TRUNCATE", "GRANT", "REVOKE",
"EXECUTE"
]
违反后果
检测到 Forbidden Keyword 后,请求立即终止,返回 PolicyViolationError,
用户侧收到消息:"仅允许查询操作,不支持修改数据"。
3.2 EXPLAIN Cost Check¶
在执行 SQL 前,系统会先运行 EXPLAIN 分析查询计划:
| 检查项 | 阈值 | 配置变量 |
|---|---|---|
| 预估行数 (Estimated Rows) | ≤ 10,000,000 | TTD_MAX_ESTIMATED_ROWS |
| 预估成本 (Estimated Cost) | ≤ 100,000 | TTD_MAX_ESTIMATED_COST |
超过阈值时返回友好提示:
- 行数超限:「查询结果集过大,请添加过滤条件缩小范围」
- 成本超限:「查询复杂度过高,请简化查询条件」
3.3 执行约束¶
| 约束 | 值 | 配置变量 |
|---|---|---|
| Statement Timeout | 30 秒 | TTD_STATEMENT_TIMEOUT_MS |
| 最大返回行数 | 1,000 | TTD_MAX_ROWS |
| 最大扫描字节 | 1 GB | TTD_MAX_SCANNED_BYTES |
| Stacked Queries | 禁止 | 检测分号分隔的多语句 |
3.4 注入防护¶
# Content Safety Guard 检测模式
INJECTION_PATTERNS = [
r";\s*(DROP|DELETE|INSERT|UPDATE)", # Stacked DML
r"UNION\s+SELECT", # UNION injection
r"ignore\s+(previous|above)\s+instructions", # Prompt injection
r"system\s*prompt", # Prompt extraction
]
3.5 仅允许 SELECT¶
系统通过 AST 解析确认生成的 SQL 仅为 SELECT 语句。 任何非 SELECT 语句(包括 CTE 内嵌的 DML)均会被拦截。
4. 可观测性 (Observability)¶
系统采用统一可观测性架构,通过 ObservabilityFacade 将 Langfuse(追踪/评分)、AutoMQ(事件流)和 structlog(结构化日志)整合为一体。所有组件(Agent、Memory、Evaluator)共享同一 trace context。
graph LR
A[API Request] --> B[ObservabilityFacade]
B --> C[Langfuse Adapter<br/>trace / span / score]
B --> D[AutoMQ Exporter<br/>event streaming]
B --> E[structlog<br/>JSON logs]
C --> F[Langfuse Cloud / Self-hosted]
D --> G[Kafka-compatible Topic]
E --> H[Log Collector]
4.1 统一可观测性门面 (ObservabilityFacade)¶
文件:backend/app/observability/facade.py
ObservabilityFacade 是所有可观测性操作的唯一入口,封装了 Langfuse、AutoMQ 与 structlog 三个后端。Agent 编排、记忆系统、评估器均通过此门面记录追踪数据,确保 trace_id 贯穿完整请求链路。
核心方法 (Key Methods)¶
| 方法 | 说明 |
|---|---|
start_trace(session_id, user_id, ...) |
创建请求级 trace,返回 trace_id |
finalize_trace(trace_id, status, ...) |
关闭 trace,记录最终状态与 token 汇总 |
start_span(trace_id, name, ...) |
在 trace 下创建子 span(Agent 步骤、LLM 调用等) |
end_span(span_id, output, ...) |
关闭 span,附带输出与耗时 |
record_score(trace_id, name, value, ...) |
记录评分(评估器结果或用户反馈) |
emit_event(event_type, payload, ...) |
发送事件至 AutoMQ 流 |
get_langchain_handler(trace_id) |
返回 LangChain callback handler(自动关联 trace) |
使用示例¶
from app.observability.facade import observability
# 请求入口
trace_id = observability.start_trace(session_id=sid, user_id=uid)
# Agent 步骤
span_id = observability.start_span(trace_id, name="sql_generation")
# ... 执行逻辑 ...
observability.end_span(span_id, output={"sql": generated_sql})
# 记录评分
observability.record_score(trace_id, name="sql_quality", value=0.92)
# 发送事件
observability.emit_event(EventType.SESSION_TURN_PERSISTED, {"turn_id": turn_id})
# 请求结束
observability.finalize_trace(trace_id, status="success")
4.2 Langfuse 集成¶
文件:backend/app/observability/langfuse_adapter.py
每个用户请求对应一个 Langfuse Trace,所有后续操作(Agent 步骤、LLM 调用、记忆检索)作为 Span 挂载在该 trace 下。评估器结果和用户反馈通过 Score 关联到 trace。
graph TD
T[Trace: user request] --> S1[Span: intent_recognition]
T --> S2[Span: sql_generation]
T --> S3[Span: memory.retrieve]
S2 --> S2a[Span: llm_call]
T --> SC1[Score: sql_quality = 0.92]
T --> SC2[Score: user_feedback = like]
关联关系 (Correlation)¶
| 维度 | 说明 |
|---|---|
trace_id |
请求唯一标识,贯穿所有 span 和 score |
session_id |
同一会话的多轮对话共享 |
user_id |
用户级聚合分析 |
turn_id |
单轮对话标识 |
observe_span 装饰器(backend/app/observability/spans.py)可自动为任意函数创建 span:
from app.observability.spans import observe_span
@observe_span(name="validate_sql")
async def validate_sql(sql: str) -> ValidationResult:
...
4.3 AutoMQ 事件流¶
文件:backend/app/observability/automq_exporter.py
系统通过 Kafka-compatible 的 AutoMQ 进行轻量级事件流转发。事件仅携带引用 ID(非完整 payload),下游消费者可据此构建仪表盘、告警规则和审计线索。
事件类型 (EventType)¶
定义于 backend/app/observability/events.py:
| 事件 | 触发时机 |
|---|---|
session.created |
新会话创建 |
session.turn.started |
用户发送消息,开始处理 |
session.turn.persisted |
处理完成,结果已持久化 |
turn.feedback.received |
收到用户反馈(like/dislike) |
事件消息结构¶
{
"event_type": "session.turn.persisted",
"trace_id": "abc-123-def",
"session_id": "sess_456",
"turn_id": "turn_012",
"timestamp": "2024-01-15T10:30:01.500Z",
"ref_ids": {
"user_id": "user_789",
"model": "qwen3-coder-plus"
}
}
4.4 记忆生命周期事件 (Memory Lifecycle Events)¶
记忆系统(四层:working、profile、episodic、correction)的所有操作均为 trace-native,自动关联 trace_id、session_id、turn_id。以下 7 个事件覆盖记忆的完整生命周期:
| 事件 | 说明 |
|---|---|
memory.retrieve.completed |
记忆检索完成(含命中条数与延迟) |
memory.rank.completed |
记忆排序/重排完成 |
memory.write.candidate |
产生候选写入记忆 |
memory.upsert.completed |
记忆写入/更新完成 |
memory.suppress.completed |
记忆被抑制(去重/冲突处理) |
memory.expire.completed |
记忆过期清理完成 |
memory.delete.completed |
记忆显式删除完成 |
这些事件同时写入 Langfuse(作为 span 上的 event)和 AutoMQ(供下游审计/分析)。在 Langfuse UI 中可按 trace_id 查看某次请求涉及的所有记忆操作。
4.5 结构化日志 (structlog)¶
所有日志以 JSON 格式输出,便于日志收集和分析。
{
"timestamp": "2024-01-15T10:30:00.123Z",
"level": "info",
"event": "sql_generated",
"trace_id": "abc-123-def",
"session_id": "sess_456",
"user_id": "user_789",
"model": "qwen3-coder-plus",
"tokens_in": 2500,
"tokens_out": 180,
"latency_ms": 1200,
"agent": "sql_generation"
}
标准日志字段¶
| 字段 | 类型 | 说明 |
|---|---|---|
trace_id |
string | 请求级追踪 ID(贯穿整个 Agent 编排) |
session_id |
string | 会话 ID |
user_id |
string | 用户 ID |
agent |
string | 当前执行的 Agent 名称 |
model |
string | 使用的 LLM 模型 |
tokens_in |
int | 输入 Token 数 |
tokens_out |
int | 输出 Token 数 |
latency_ms |
int | 处理耗时 (ms) |
event |
string | 事件名称 |
4.6 Prometheus Metrics¶
当 TTD_PROMETHEUS_ENABLED=true 时,暴露 /metrics 端点:
# 请求与 LLM 指标
ttd_requests_total{endpoint, method, status}
ttd_request_duration_seconds{endpoint}
ttd_llm_calls_total{model, agent}
ttd_llm_tokens_total{model, direction}
ttd_sql_cache_hits_total
ttd_sql_cache_misses_total
ttd_active_sessions_gauge
ttd_sql_execution_duration_seconds
# 记忆系统指标
ttd_memory_retrieve_duration_seconds{layer}
ttd_memory_write_total{layer, operation}
ttd_memory_suppress_total{layer, reason}
ttd_memory_active_count{layer}
4.7 Health Check¶
返回示例:
{
"status": "healthy",
"version": "0.3.0",
"uptime_seconds": 86400,
"db_pool": {
"size": 10,
"available": 8,
"in_use": 2
},
"data_plane": "pg_mooncake",
"metadata_cache_age_seconds": 3600
}
4.8 审计日志¶
关键操作会写入审计表,包括:
- 用户查询请求(脱敏后)
- SQL 生成结果
- 安全策略触发事件
- 管理员操作
- 记忆生命周期变更(通过 ObservabilityFacade 事件采集)
配置:
TTD_AUDIT_LOG_LEVEL: INFO # 审计日志级别
TTD_AUDIT_ARCHIVE_BUCKET: ttd-audit-archive # S3 归档桶
TTD_AUDIT_ARCHIVE_AFTER_DAYS: 90 # 90 天后归档至 S3
5. 运行时稳定性 (Runtime Stability)¶
5.1 SQL Cache (快路径)¶
graph LR
A[用户提问] --> B{语义相似度 > 0.92?}
B -->|是| C[返回缓存 SQL]
C --> D[Guardrails 校验]
D --> E[执行并返回]
B -->|否| F[完整 Agent 编排]
| 配置 | 默认值 | 说明 |
|---|---|---|
TTD_SQL_CACHE_SIMILARITY |
0.92 | 相似度阈值,越高越精确 |
TTD_SQL_CACHE_TTL_MINUTES |
15 | 缓存条目有效期 |
Note
即使命中缓存,SQL 仍需经过 Guardrails 安全校验后才会执行。
5.2 Repair 机制 (SQL 修复)¶
SQL 执行失败时,系统会尝试自动修复:
graph TD
A[SQL 执行失败] --> B{重试次数 < 1?}
B -->|是| C[提取错误信息]
C --> D[构造修复 Prompt]
D --> E[重新生成 SQL]
E --> F[执行修复后的 SQL]
B -->|否| G[返回友好错误]
- 最大重试次数: 1 (
TTD_MAX_REPAIR_RETRIES) - 修复 Prompt 包含:原始 SQL、错误信息、可用表/列白名单
5.3 Circuit Breaker (熔断)¶
连续失败达到阈值时触发熔断:
| 参数 | 默认值 | 说明 |
|---|---|---|
TTD_CIRCUIT_BREAKER_THRESHOLD |
3 | 连续失败次数阈值 |
熔断触发后:
- 暂停向对应模型发送请求
- 返回 fallback 响应:"AI 模型服务暂时不可用,请稍后重试"
- 定时探活,恢复后自动解除熔断
5.4 Session 清理¶
过期会话定时回收,避免内存泄漏:
| 参数 | 默认值 | 说明 |
|---|---|---|
TTD_SESSION_TTL_HOURS |
24 | 会话最大存活时间 |
TTD_SESSION_MAX_TURNS |
20 | 单会话最大对话轮次 |
TTD_CLEANUP_INTERVAL_MINUTES |
60 | 清理任务执行间隔 |
5.5 Metadata Cache¶
语义层元数据在内存中缓存,减少数据库查询:
| 参数 | 默认值 | 说明 |
|---|---|---|
TTD_METADATA_CACHE_TTL_SECONDS |
86400 (24h) | 缓存有效期 |
缓存失效策略:
- TTL 过期后自动刷新
- 管理员可通过 API 手动刷新
- Ingest 流程完成后自动 invalidate
6. 错误处理 (Error Handling)¶
6.1 异常层次结构¶
classDiagram
TTDError <|-- ClarificationNeededError
TTDError <|-- PolicyViolationError
TTDError <|-- SQLValidationError
TTDError <|-- RetrievalMissError
TTDError <|-- ModelUnavailableError
class TTDError {
+str message
}
class ClarificationNeededError {
+list ambiguities
+to_dict()
}
class PolicyViolationError {
+list[str] errors
}
class SQLValidationError {
+str layer
+list[str] details
}
class RetrievalMissError {
}
class ModelUnavailableError {
+str model_id
+str cause
}
6.2 错误类型说明¶
| 异常类 | 触发条件 | 用户侧行为 |
|---|---|---|
ClarificationNeededError |
用户提问存在歧义 | 返回澄清选项供用户选择 |
PolicyViolationError |
触发安全策略 (DML/注入) | 拒绝并提示安全原因 |
SQLValidationError |
SQL 语法错误/成本超限 | 提示缩小范围或简化查询 |
RetrievalMissError |
检索引擎未命中任何资产 | 提示换一种方式提问 |
ModelUnavailableError |
LLM API 不可用 | 提示稍后重试 |
6.3 错误消息脱敏映射¶
技术错误自动转换为用户友好的中文消息:
| 技术错误 | 用户消息 |
|---|---|
statement timeout |
查询执行超时,请尝试缩小查询范围 |
syntax error at or near |
生成的 SQL 语法有误,系统将尝试修复,请重试 |
relation .+ does not exist |
查询引用了不存在的表,请换一种方式提问 |
column .+ does not exist |
查询引用了不存在的字段,请换一种方式提问 |
permission denied |
没有权限访问该数据,请联系管理员 |
connection refused |
数据库连接失败,请稍后重试 |
Forbidden keyword detected |
SQL 包含禁止使用的操作 |
Estimated rows exceeds limit |
查询结果集过大,请添加过滤条件缩小范围 |
Estimated cost exceeds limit |
查询复杂度过高,请简化查询条件 |
Model .+ unavailable |
AI 模型服务暂时不可用,请稍后重试 |
| (未匹配的错误) | 系统处理出现异常,请稍后重试 |
7. 维护检查清单 (Maintenance Checklists)¶
7.1 每日巡检¶
- 检查 Backend 健康状态:
curl /api/v1/health - 检查错误率趋势(日志
level=error频率) - 检查关键 API 响应延迟 (P95 < 5s)
- 检查 DB 连接池使用率 (in_use / total < 80%)
- 确认无异常的安全告警(PolicyViolation 突增)
7.2 每周巡检¶
- 抽样检查高频查询的 SQL 质量(是否语义正确)
- 复核 Semantic Plane 新增/修改的规则是否产生副作用
- 复核模型路由配置(是否需要切换模型版本)
- 检查 SQL Cache 命中率(正常范围 30%~60%)
- 审查审计日志中的异常模式(频繁 PolicyViolation 用户)
7.3 每月巡检¶
- 盘点敏感字段 PII 暴露策略(新增字段是否漏标)
- 回顾失败路径分布:clarification / rejected / error 比例
- 更新 Handbook 中过期的文档内容
- 检查依赖库安全漏洞 (
uv audit、bun audit) - 验证备份恢复流程可行性
- 评估是否需要调整 Rate Limit 或 Cost Threshold
8. 备份与恢复 (Backup & Recovery)¶
8.1 备份策略¶
| 数据源 | 备份方式 | RPO | RTO |
|---|---|---|---|
| Aurora PostgreSQL | 自动快照 (每日) + 连续归档 | 5 分钟 | < 1 小时 |
| Semantic Plane | Git 历史 (完整 YAML) | 0(每次 commit) | < 10 分钟 |
| 审计日志 | S3 归档 (90 天后) | 1 天 | < 4 小时 |
| SQL Cache | 无(临时数据,可重建) | N/A | 自动恢复 |
8.2 Semantic Plane 恢复¶
Semantic Plane 的所有元数据以 YAML 形式存储在 Git 中, 任何版本都可通过以下步骤完整恢复:
# 1. 切换到目标版本
git checkout <commit-sha> -- semantic-plane/
# 2. 全量发布到 S3(重建 R+V+G)
task dp:publish-sp
# Backend 检测 S3 变更后自动执行全量 R+V+G 导入
8.3 数据库恢复¶
8.4 全量重同步¶
当数据不一致或需要灾难恢复时:
# 构建全量 changeset(包含所有资产)
task sp:changeset:full
# 发布到 S3 触发全量导入
task dp:publish-sp
# Backend 自动检测 S3 变更并执行 R+V+G pipeline
9. 性能调优 (Performance Tuning)¶
9.1 关键调优参数¶
graph TB
subgraph 检索精度
A[TTD_TOP_K_TABLES]
B[TTD_TOP_K_COLUMNS]
C[TTD_TOP_K_METRICS]
D[TTD_TOP_K_TERMS]
E[TTD_TOP_K_FEW_SHOTS]
end
subgraph 质量阈值
F[TTD_SIMILARITY_THRESHOLD]
G[TTD_SQL_CACHE_SIMILARITY]
end
subgraph 执行限制
H[TTD_STATEMENT_TIMEOUT_MS]
I[TTD_MAX_ROWS]
J[TTD_MAX_ESTIMATED_ROWS]
end
9.2 检索范围参数¶
| 参数 | 默认值 | 调优建议 |
|---|---|---|
TTD_TOP_K_TABLES |
5 | 表较多时增加到 8~10,但会增加 Token 消耗 |
TTD_TOP_K_COLUMNS |
20 | 宽表场景可增加到 30 |
TTD_TOP_K_METRICS |
5 | 指标丰富的域可增加 |
TTD_TOP_K_TERMS |
10 | 同义词/歧义多时增加 |
TTD_TOP_K_FEW_SHOTS |
3 | 增加可提升 SQL 质量,但增加 latency |
9.3 精度/召回权衡¶
| 参数 | 默认值 | 调高效果 | 调低效果 |
|---|---|---|---|
TTD_SIMILARITY_THRESHOLD |
0.65 | 精确但可能漏召回 | 召回高但可能引入噪音 |
TTD_SQL_CACHE_SIMILARITY |
0.92 | 缓存更精确,命中率低 | 命中率高,但可能返回不匹配的缓存 |
9.4 延迟优化¶
| 优化手段 | 效果 | 配置 |
|---|---|---|
| SQL Cache | 命中时跳过 LLM 调用,延迟 < 200ms | TTD_SQL_CACHE_SIMILARITY |
| Metadata Cache | 减少 DB 查询,检索阶段提速 30%+ | TTD_METADATA_CACHE_TTL_SECONDS |
| 模型选择 | 使用更快的模型降低延迟 | TTD_*_MODEL 系列参数 |
| Graph Traversal Depth | 减少深度加速 Join 推理 | TTD_GRAPH_TRAVERSAL_DEPTH |
| Statement Timeout | 防止慢查询阻塞连接池 | TTD_STATEMENT_TIMEOUT_MS |
9.5 模型选择建议¶
| 场景 | 推荐模型 | 原因 |
|---|---|---|
| SQL 生成 | qwen3-coder-plus |
代码能力强,SQL 准确率高 |
| 洞察分析 | qwen3-max |
推理能力强,文本质量高 |
| Supervisor 路由 | deepseek-v3.2 |
速度快,路由判断准确 |
| Follow-up 生成 | deepseek-v3.2 |
轻量级任务,低延迟 |
10. 故障排查 (Troubleshooting)¶
10.1 常见问题速查表¶
| 症状 | 可能原因 | 排查命令 | 解决方案 |
|---|---|---|---|
| API 返回 401 | JWT 过期/无效 | 检查 Token exp claim | 重新获取 Token |
| API 返回 429 | 触发 Rate Limit | 查看 X-RateLimit-* 响应头 |
等待窗口重置或联系管理员提限 |
| 查询超时 | SQL 复杂度过高 | task dp:psql + EXPLAIN ANALYZE |
优化查询或提升 timeout |
| "查询引用了不存在的表" | 元数据未导入 | SELECT * FROM semlayer.table_asset |
执行 task dp:publish-sp |
| "AI 模型服务暂时不可用" | DashScope API 异常 | 检查 API Key + 网络 | 验证 TTD_DASHSCOPE_API_KEY |
| Backend 启动崩溃 | DB 连接失败 | task dp:ps 查看容器状态 |
重启 Data Plane: task dp:down && task dp:up |
| 检索不到相关资产 | Embedding 缺失 | 查询 semlayer.embedding 表 |
执行 task dp:publish-sp(Backend 自动生成 Embedding) |
| Cache 命中率异常低 | 相似度阈值过高 | 查看 Prometheus sql_cache_* |
调低 TTD_SQL_CACHE_SIMILARITY |
| 前端无法连接后端 | CORS 或端口问题 | curl localhost:8000/api/v1/health |
检查 TTD_CORS_ORIGINS 配置 |
| pg_mooncake 查询报错 | 表未加载 | task dp:psql:mooncake 查表 |
执行 task dp:load-hm |
10.2 排查工具命令¶
# 后端测试(快速验证代码正确性)
task be:test
# 代码静态检查(发现潜在问题)
task be:lint
task be:typecheck
# 元数据校验(检查 YAML 一致性)
task sp:validate
# 数据面日志(查看容器运行状态)
task dp:logs
# 数据库连接测试
task dp:psql # Aurora 替代
task dp:psql:mooncake # pg_mooncake
# 健康检查
curl -s http://localhost:8000/api/v1/health | python -m json.tool
10.3 日志分析技巧¶
# 查看最近的错误日志
docker logs ttd-backend 2>&1 | grep '"level":"error"' | tail -20
# 按 trace_id 追踪完整请求链路
docker logs ttd-backend 2>&1 | grep "trace_id.*abc-123-def"
# 统计各 Agent 的调用延迟
docker logs ttd-backend 2>&1 | grep "latency_ms" | \
python -c "import sys,json; [print(json.loads(l).get('agent','?'), json.loads(l).get('latency_ms',0)) for l in sys.stdin]"
10.4 紧急恢复步骤¶
生产环境紧急恢复
场景:元数据损坏导致全部查询失败
# 1. 确认问题
curl http://localhost:8000/api/v1/health
# 2. 从 Git 恢复到已知良好版本
git checkout <last-known-good-commit> -- semantic-plane/
# 3. 全量重建
task dp:publish-sp
# Backend 自动检测 S3 变更并执行全量 R+V+G 导入
# 4. 验证恢复
curl http://localhost:8000/api/v1/health
# 通过 Web 界面测试关键查询
场景:数据库连接池耗尽
11. 环境变量完整参考¶
所有 TTD_ 配置变量
| 变量 | 默认值 | 说明 |
|---|---|---|
TTD_HOST |
0.0.0.0 |
服务监听地址 |
TTD_PORT |
8000 |
服务监听端口 |
TTD_WORKERS |
4 |
Worker 进程数 |
TTD_DEBUG |
true |
调试模式(生产必须为 false) |
TTD_AURORA_DSN |
postgresql://... |
PostgreSQL 连接串 |
TTD_PG_POOL_MIN |
2 |
连接池最小连接数 |
TTD_PG_POOL_MAX |
10 |
连接池最大连接数 |
TTD_DATA_PLANE_BACKEND |
redshift |
数据面后端 (redshift/pg_mooncake) |
TTD_PG_MOONCAKE_DSN |
postgresql://... |
pg_mooncake 连接串 |
TTD_DASHSCOPE_API_KEY |
- | DashScope API Key |
TTD_ANTHROPIC_API_KEY |
- | Anthropic API Key |
TTD_SUPERVISOR_MODEL |
deepseek-v3.2 |
Supervisor 模型 |
TTD_SQL_GENERATION_MODEL |
qwen3-coder-plus |
SQL 生成模型 |
TTD_INSIGHTS_MODEL |
qwen3-max |
洞察分析模型 |
TTD_VISUALIZATION_MODEL |
qwen3-max |
可视化模型 |
TTD_FOLLOWUP_MODEL |
deepseek-v3.2 |
Follow-up 模型 |
TTD_JWT_SECRET |
change-me... |
JWT 签名密钥(迁移期 HS256 回退用,将移除) |
TTD_JWT_ALGORITHM |
HS256 |
JWT 算法(迁移期回退用,将移除) |
TTD_JWT_AUDIENCE |
talk-to-data |
JWT 受众校验值 |
TTD_BETTER_AUTH_URL |
http://localhost:3000 |
Better Auth 基础 URL (JWKS 端点来源) |
TTD_BETTER_AUTH_ISSUER |
http://localhost:3000 |
JWT issuer 校验值 |
TTD_JWKS_CACHE_TTL_SECONDS |
3600 |
JWKS 公钥缓存时间 |
TTD_RATE_LIMIT_PER_USER |
60 |
每用户每分钟请求限制 |
TTD_BURST_LIMIT |
100 |
突发请求上限 |
TTD_MAX_QUESTION_LENGTH |
2000 |
最大问题长度 (字符) |
TTD_SESSION_TTL_HOURS |
24 |
会话 TTL |
TTD_SESSION_MAX_TURNS |
20 |
最大对话轮次 |
TTD_TOP_K_TABLES |
5 |
检索表数量 |
TTD_TOP_K_COLUMNS |
20 |
检索列数量 |
TTD_TOP_K_METRICS |
5 |
检索指标数量 |
TTD_TOP_K_TERMS |
10 |
检索术语数量 |
TTD_TOP_K_FEW_SHOTS |
3 |
检索 Few-shot 数量 |
TTD_SIMILARITY_THRESHOLD |
0.65 |
检索相似度阈值 |
TTD_GRAPH_TRAVERSAL_DEPTH |
3 |
Graph 遍历深度 |
TTD_STATEMENT_TIMEOUT_MS |
30000 |
SQL 超时 (ms) |
TTD_MAX_ROWS |
1000 |
最大返回行数 |
TTD_SQL_CACHE_SIMILARITY |
0.92 |
SQL Cache 相似度 |
TTD_SQL_CACHE_TTL_MINUTES |
15 |
SQL Cache TTL |
TTD_METADATA_CACHE_TTL_SECONDS |
86400 |
元数据缓存 TTL |
TTD_MAX_REPAIR_RETRIES |
1 |
SQL 修复最大重试 |
TTD_CIRCUIT_BREAKER_THRESHOLD |
3 |
熔断连续失败阈值 |
TTD_MAX_ESTIMATED_ROWS |
10000000 |
EXPLAIN 行数上限 |
TTD_MAX_ESTIMATED_COST |
100000 |
EXPLAIN 成本上限 |
TTD_PROMETHEUS_ENABLED |
true |
是否启用 Prometheus |
TTD_METRICS_PATH |
/metrics |
Metrics 端点路径 |