Skip to content
 
 

Repository files navigation

面向结构化数据问数的可控 Text-to-SQL Agent

目标不是演示“LLM 会写 SQL”,而是把自然语言问数做成一条可运行、可观测、可评测、可迭代的工程链路。

项目围绕企业结构化数据分析场景展开,覆盖从前端请求、服务运行时、语义预检、元数据召回、图执行、SQL 安全校验、有界纠错、结果恢复、SSE 返回到评测闭环的完整流程。当前版本已经完成最后一轮 targeted hardening,进入项目封结状态。

项目定位

很多 Text-to-SQL Demo 会把 schema 直接塞给模型,然后让模型一次性生成 SQL。这个项目更关注真实系统里的控制问题:

  • 用户问题需要先被判断是否适合问数,恶意操作、越权探测、注入类输入不能进入 SQL 链路。
  • 表、字段、指标、字段取值来自不同信息源,不能只依赖模型硬猜。
  • SQL 生成后必须经过确定性安全校验、schema 校验、执行和有界修复。
  • 结果异常、空结果、修复耗尽等场景需要有可追踪的 recovery 分支。
  • 项目质量不能只靠主观演示,需要场景集、评分器、bad case 分析和回归套件。

一句话概括:这是一个面向企业结构化数据的可控 Text-to-SQL Agent 工程原型,不是一个已经具备完整 RBAC/ABAC 和生产 SLA 的企业上线系统。

主链路

flowchart LR
    A["React 前端"] --> B["FastAPI /api/query"]
    B --> C["QueryService"]
    C --> D["QueryRuntime"]
    D --> E["Preflight 语义预检"]
    E --> SP["SemanticPlan assist"]
    SP --> F["LangGraph 问数图"]
    F --> G["Event Normalize"]
    G --> H["SSE 流式返回"]
Loading
flowchart TD
    Q["用户自然语言问题"] --> P["Preflight: 问数/澄清/拒绝"]
    P --> SP["SemanticPlan assist"]
    SP --> K["extract_keywords"]
    K --> R1["recall_column"]
    K --> R2["recall_value"]
    K --> R3["filter_metric"]
    R1 --> S["retrieval_selection 证据包筛选"]
    R2 --> S
    R3 --> S
    S --> C["add_extra_context"]
    C --> G["generate_sql"]
    G --> V["check_sql_safety / validate_sql"]
    V --> X["run_sql"]
    V --> VE["可修复错误"]
    VE --> Fix["correct_sql 有界纠错"]
    Fix --> V
    X --> QR["check_recovery"]
    QR --> RN["正常"]
    RN --> F["finalize_sql_result"]
    QR --> RA["空结果/异常/修复耗尽"]
    RA --> D["diagnose_recovery"]
    D --> DR["retry_retrieval"]
    DR --> K
    D --> DG["regenerate_sql"]
    DG --> G
    D --> DS["停止"]
    DS --> FR["finalize_recovery"]
Loading

已落地能力

服务与运行时边界

  • React -> FastAPI -> QueryService -> QueryRuntime -> LangGraph -> SSE 分层清晰。
  • 前端不直接绑定 LangGraph 内部节点事件,后端通过事件归一化层输出稳定 SSE 协议。
  • QueryRuntime 统一管理一次查询生命周期,承接 preflight、graph 执行、事件封装和错误返回。

检索到 SQL 的推理链路

  • SemanticPlan assist 先把用户问题整理成结构化语义计划,再增强 extract_keywords 和召回输入。
  • 多路召回:字段、指标、字段取值分别召回。
  • retrieval_selection 输出结构化证据包,不是把所有候选文本直接堆给模型。
  • SQL 生成前会补充上下文,降低模型硬猜表字段和指标口径的概率。

SemanticPlan SFT 微调闭环

  • 已完成 SemanticPlan 数据构建、SFT 微调、离线评估、远端 provider 接入和 targeted A/B 验证。
  • 微调目标不是让模型直接生成 SQL,而是先输出可校验的业务语义计划,增强关键词抽取、字段/指标/过滤召回和风险信号识别。
  • SemanticPlan 只作用于召回输入增强层,不绕过 SQL 安全校验、schema 校验、graph 路由和执行闭环。

SQL 安全与有界纠错

  • SQL 安全校验使用 sqlglot AST,而不是只靠字符串正则。
  • 已覆盖只读约束、多语句、DDL/DML、注释注入、SELECT *、未知表/列、LIMIT 注入/钳位等场景。
  • SQL 纠错链具备失败分类、修复预算、重复无进展终止。
  • 对破坏性意图和 SQL 注入类输入,纠错链会快速终止,避免把“应该拒绝的请求”硬修成查询。
  • schema 校验已支持 CTE 和子查询别名,避免把虚拟表/别名误报为未知表。

Recovery Agent

  • 已实现 check_recovery -> diagnose_recovery -> prepare_recovery_* -> finalize_recovery 的最小闭环。
  • 支持空结果、异常结果、SQL 修复耗尽等触发原因。
  • 支持 retry_retrievalregenerate_sql 路由。
  • max_attempts 硬预算和 attempted_retrieval_queries 记录,避免 recovery 无限重入。

观测与评测

  • 运行链路带 request_id,便于从 route/service/runtime/graph 追踪一次请求。
  • SSE 事件统一为 progress / result / error / completed
  • 已有 85 case 最终评测集、30 case targeted live E2E 样本、bad case 分析报告和已知问题文档。

最终评测与 Bad Case 收敛

离线与组件回归

最后一轮 targeted hardening 后,离线回归结果:

299 passed, 0 failed, 3 deselected

其中 deselected 是需要 live LLM / live graph 的用例,离线回归不会启动真实服务。

第一轮:85 Case 用来暴露问题

评测文件:app/eval/scenarios/final_eval_suite_v1.json

结果摘要见 docs/final_eval_summary_qwen3.mddocs/badcase_analysis_qwen3.md

这轮评测的定位是压力测试和问题发现,不是为了给项目刷一个漂亮总分。它把系统在更大样本、更复杂标签下的真实问题打了出来:

指标 结果 说明
场景数 85 core / multi / metric / sql_safety / recovery / bug_hunt 等
final_success_rate 69% 原始 SQL 最终成功率
safety_pass_rate 91% 安全评分通过率
filter_binding_rate 41% 用户过滤条件绑定到正确字段/取值的比例
recovery_action_hit_rate 92% recovery 预期动作命中率

这轮评测中有 26 个失败,其中 21 个是 DashScope 429 限流导致的基础设施噪音,不代表模型或链路能力。真正值得处理的问题主要是三类:

  • 安全绕过:恶意输入被模型“善意改写”为安全 SELECT,没有在输入层拒绝。
  • SQL 纠错死循环:破坏性意图、SELECT *、子查询别名等问题进入无意义修复。
  • filter binding 一致性仍有提升空间:部分样本中 SQL 虽然可执行,但用户过滤条件与目标字段/取值的对应关系还不够稳定。

因此,第一轮 85 case 的价值是明确问题边界和优化优先级,而不是直接作为项目最终展示口径。

第二轮:30 Case 验证 Bad Case 收敛

评测文件:app/eval/scenarios/targeted_hardening_suite.json

第二轮不是一个独立的新总分测试,也不是替代 85 case。它是针对第一轮 bad case 的解释和验证集:把可低风险优化的问题抽出来,构造成 30 条真实 graph + 外部依赖的 targeted live E2E 样本,验证归因是否成立、修复是否收敛、正常主链路是否没有被破坏。

这 30 条样本包含两类问题:

  • 第一轮暴露过的失败模式,例如破坏性意图、SQL 注入、敏感字段探测、SELECT *、CTE/子查询别名、纠错快速终止。
  • 新增的同类变体和正常问数回归,避免只针对原始 bad case 做硬编码补丁。
指标 结果 说明
场景数 30 安全、纠错终止、CTE/子查询、正常问数、管线集成
safety_pass_rate 97% 29/30 安全评分通过
normal core success 10/11 正常问数主链路基本稳定
safety interception 12/12 破坏性、注入、敏感、越权、导出类请求均被拒绝
quick termination 2/2 不可执行意图不会进入无意义纠错
table_hit_rate 100% 目标表命中
metric_hit_rate 100% 目标指标命中
recovery_action_hit_rate 100% recovery 动作命中

注意:这个 targeted suite 的原始 final_success_rate 是 47%,不能作为主结论。因为安全拒绝场景在 SQL 状态上通常是 failed,但行为上是正确的。它应该被解读为 bad case 收敛验证:安全通过率、正常问数成功率、quick termination 和目标 hardening 行为是否命中,才是这一轮的关键指标。

换句话说,项目最终评测口径不是“85 case 得 69%,30 case 得 47%”,而是:

85 case 用来暴露系统问题;30 case targeted live E2E 用来验证其中可低风险优化的问题已经收敛,同时保留过滤条件绑定一致性、权限治理等需要下一阶段架构升级的边界。

已知边界

项目已经完成最后一轮 targeted hardening,但仍保留清晰边界:

  • filter_binding_rate 在 85 case 中是一个值得关注的观测指标,它反映了部分场景下过滤条件与目标字段/取值之间的一致性仍不够稳定。但这个指标本身并不能脱离业务域、schema 复杂度和样本构成,被直接当作模型优劣的单一结论。后续如果继续做架构升级,更合适的方向仍然是通过 semantic plan、指标/维度 registry 和整体检索表达能力的增强去改善这类一致性问题,而不是继续堆 graph 节点。
  • user_passwords 这类不存在表名的敏感探测仍有一次安全漏判:模型可能把恶意探测“善意纠正”为已有表查询。
  • CTE 场景中曾出现中文别名导致的 SQL 生成失败,属于模型生成稳定性问题。
  • 当前权限治理仍是轻量安全控制,不是完整 RBAC/ABAC。真实企业上线还需要表/字段/指标权限贯穿召回、生成、校验、执行四层。
  • 85 case 全量评测受外部模型限流影响明显,正式展示时应开启 delay 和 429 retry。

SemanticPlan SFT 微调闭环

在完成 targeted hardening 之后,项目继续补齐了 SemanticPlan SFT 微调链路,用结构化中间表示增强 extract_keywords,降低关键词抽取对通用分词和 prompt 临场发挥的依赖。

这部分工作不是让模型直接生成 SQL,而是让模型先输出可校验的业务语义计划:

  • 用户问题中的指标、维度、过滤条件、时间范围、对比关系、风险信号被解析为 SemanticPlan
  • SemanticPlan 进入关键词和召回输入层,增强字段、指标和过滤语义的结构化表达。
  • SQL 安全校验、schema 校验、graph 路由、执行和 recovery 主链路保持不变。

微调数据分三步构建:

阶段 结果
Pilot 数据 固定小规模人工 gold,用于验证数据格式、训练脚本和评估链路
first_run_v1 构建 1000+ 训练样本,dev/test 使用 human gold 隔离
first_run_v1_1 增加 260 条 targeted hardening 样本,强化 enum boundary、comparison、time/filter、risk_flags、clarification

V1.1 最终训练包规模:

train: 1359
dev:   100
test:  100

云端 LoRA 微调基于 Qwen2.5-1.5B-Instruct + SemanticPlan V1.1 adapter 完成,训练结果如下:

指标 V1 Dev V1.1 Dev V1 Test V1.1 Test
parse valid 0.84 0.95 0.82 0.94
schema valid 0.84 0.95 0.82 0.94
overall 0.6808 0.8478 0.6624 0.8280

其中 dev overall 从 0.6808 提升到 0.8478,test overall 从 0.6624 提升到 0.8280;schema 边界稳定性从 82%-84% 提升到 94%-95%。

模型接入采用远端 provider 方式:模型服务只负责加载 base model + LoRA adapter 并暴露 SemanticPlan HTTP 服务,业务主链路继续负责检索、SQL 生成、安全校验、执行和结果返回。这样可以把模型推理资源和业务运行时解耦。

最终 A/B 使用现有 30 条 targeted live E2E 样本,比较 legacy keyword extractionassist + SemanticPlan V1.1

指标 Legacy Assist
success count 15/30 15/30
semantic used 0 13
provider fallback - 2
regressions - 0
safety regressions - 0
infrastructure errors - 0
go/no-go - go

SemanticPlan 实际介入的 13 条样本全部成功,A/B 没有引入主链路回归或安全回归。相比 legacy,assist 模式将 first_pass_success_rate0.43 提升到 0.47,将 correction_needed_rate0.07 降到 0.03,说明语义计划对关键词和召回输入有正向收敛效果;同时 provider 侧保留回退能力,不会把主链路稳定性押注在单一模型路径上。

技术栈

模块 技术
Agent 编排 LangGraph
后端接口 FastAPI / SSE
SQL AST sqlglot
元数据与数仓 MySQL / SQLAlchemy
向量召回 Qdrant
全文检索 Elasticsearch
Embedding TEI / BAAI/bge-large-zh-v1.5
日志与上下文 loguru / ContextVar
前端 React / Vite / Tailwind CSS
环境管理 uv / pnpm / Docker Compose

项目结构

app/
  agent/              LangGraph 图、节点、状态、SQL 安全、recovery
  api/                FastAPI 路由
  clients/            MySQL / Qdrant / Elasticsearch / Embedding 客户端
  eval/               场景集、评分器、runner、报告生成
  events/             SSE 事件协议与事件归一化
  runtime/            QueryRuntime 与 preflight
  services/           QueryService 与业务服务层
conf/                 app_config.yaml / meta_config.yaml
docker/               本地依赖服务配置
docs/                 设计、计划、评测总结、bad case 分析
frontend/             React 前端
logs/                 评测输出与运行日志
prompts/              SQL 生成、纠错、过滤 prompt
scripts/              本地初始化与启动脚本
tests/                单测、契约测试、eval 测试、targeted hardening 测试

快速开始

1. 安装依赖

uv sync
corepack enable
pnpm --dir frontend install

2. 配置环境变量

Copy-Item .env.example .env

.env 中写入模型 API Key 和本地依赖配置。

3. 初始化本地开发环境

powershell -ExecutionPolicy Bypass -File scripts/init-dev.ps1

该脚本会安装依赖、启动基础服务并构建元数据知识库。

4. 启动开发环境

powershell -ExecutionPolicy Bypass -File scripts/start-dev.ps1

可选:

powershell -ExecutionPolicy Bypass -File scripts/start-dev.ps1 -BackendOnly
powershell -ExecutionPolicy Bypass -File scripts/start-dev.ps1 -FrontendOnly
powershell -ExecutionPolicy Bypass -File scripts/start-dev.ps1 -BackendPort 8010 -FrontendPort 5180

测试与评测

离线回归

uv run pytest -q

85 Case 最终评测

需要本地外部依赖和模型配置可用:

uv run python -m app.scripts.run_final_eval `
  --suite app/eval/scenarios/final_eval_suite_v1.json `
  --output logs/final-eval-report.json `
  --summary docs/final_eval_summary.md `
  --issues docs/known_issues.md `
  --delay-seconds 2 `
  --retry-429-attempts 2 `
  --retry-429-backoff-seconds 5

30 Case Targeted Live E2E

用于最后一轮 targeted hardening 的真实链路验证:

uv run python -m app.scripts.run_final_eval `
  --suite app/eval/scenarios/targeted_hardening_suite.json `
  --output logs/targeted-hardening-report.json `
  --summary docs/targeted_hardening_summary.md `
  --issues docs/targeted_hardening_issues.md `
  --delay-seconds 2 `
  --retry-429-attempts 2 `
  --retry-429-backoff-seconds 5

当前状态

项目已进入封结状态。SemanticPlan SFT 已完成数据构建、云端训练、离线评估、远端 provider、主链路 assist 接入、A/B 验证和一键回滚闭环。后续不再做无止境功能迭代,除非目标变成真实上线系统;如果继续推进,优先级应是:

  1. 完整 RBAC/ABAC 权限治理。
  2. 更大规模、更稳定的线上评测环境。

About

面向企业结构化数据问数的可控 Text-to-SQL Agent 工程实践,覆盖语义预检、多路元数据召回、LangGraph 编排、SQL 安全校验、有界纠错、Recovery Agent 与真实链路评测闭环。

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages