Defense Knowledge Base

毕业答辩终极知识库

覆盖系统架构、数据源建模、Schema-RAG、值证据、知识增强、复杂问题处理、SQL 生成校验、SSE 主链路、结果后处理、运行配置和实验评测。

12 核心知识域
129 4D 记忆卡片
4D 概念 · 控制流 · 代码 · 金句

$ study all_domains --goal defense

> mainline: metadata -> retrieval -> evidence -> generation -> validation -> execution -> evaluation

> output: high-density 4D cards with exact code anchors

核心主线:系统把真实数据源转化为可检索、可验证、可执行的问答闭环;Schema-RAG 提供表字段地基,值证据和知识增强补充语义,SQL 计划、Guard、Verifier 和 Fixer 控制生成风险,SSE 与后处理负责把结果稳定交付给前端,实验评测则证明收益、边界和成本。

系统总体架构与研究定位

本知识域回答系统为什么不是普通聊天工具,而是围绕真实数据源、元数据、检索增强、SQL 生成校验和结果执行构建的 NL2SQL 工程闭环。

论文原图:系统总体架构与核心数据流图
论文原图 · 系统总体架构与核心数据流图 答辩开场可先用这张图说明边界:前端提交问题,ChatService 编排 Schema-RAG、增强知识、SQL 校验修复和数据源执行,最终把结果回流到交互界面。

读图顺序

  1. 先看入口层:用户在前端 ChatView 提交自然语言问题,前端不直接接触数据库,只负责请求、流式展示和状态合并。
  2. 再看编排层:后端 FastAPI 路由把请求交给 ChatService,ChatService 是主控制器,负责串起问题改写、数据源选择、Schema-RAG、增强知识、SQL 生成、校验执行和结果落库。
  3. 然后看知识与元数据层:数据源同步后的表、字段、关系、证据、术语、SQL 样例和领域记忆被组织为可检索上下文,服务于 Prompt 构造。
  4. 最后看执行闭环:生成 SQL 之后经过 Guard、Executor、Semantic Verifier 和 Fixer,只有合规结果才会返回前端并写入问答记录。

代码对应:backend/chat/service.py 承担主编排,backend/services/schema_retrieval.py 负责 Schema-RAG,backend/services/sql_guard.pysql_executor.pysql_semantic_verifier.pysql_semantic_fixer.py 构成生成后控制链。

答辩讲法:这张图的核心不是“调用大模型”,而是把自然语言问答放进一个受真实数据源、元数据、检索证据和 SQL 安全边界约束的工程闭环。

01

研究定位:受真实数据源约束的 NL2SQL 执行系统

Research positioning and problem boundary
NL2SQL 研究定位 真实数据源
【核心概念与设计初衷】

本系统的研究定位是面向结构化数据分析场景的自然语言数据库问答系统。它不是开放域聊天,也不是传统 BI 报表工具,而是把用户问题转化为受当前数据源约束的 SQL 查询,并返回 SQL、查询结果、图表和解释。设计痛点在于:大模型会生成看似合理但脱离真实表字段、连接关系和业务取值的 SQL,因此系统必须先建立数据源边界,再把生成、校验、执行和修复纳入同一条链路。

系统类型 核心输出 主要约束
通用聊天 自然语言回答 知识来自模型参数或文档上下文
传统 BI 固定报表与仪表盘 依赖人工配置指标和图表
本系统 SQL、执行结果、图表与解释 必须落在真实数据源、表字段、关系和只读执行边界内
【算法逻辑与控制流向】
  1. Input:用户自然语言问题、当前会话上下文、可用数据源集合。
  2. 系统先判断目标数据源,并读取该数据源下可用的表、字段、关系和业务证据。
  3. Schema-RAG 与增强知识模块把数据库结构、术语、样例、领域记忆和值证据组织成 Prompt 上下文。
  4. 模型生成候选 SQL 后,系统执行安全校验、结构一致性检查、只读执行和语义验证。
  5. 如果出现可修复错误,则进入自动修复分支,修复 SQL 仍需重新经过校验链路。
  6. Output:最终 SQL、结果数据、阶段日志、可选图表解释和推荐追问。
【代码精准溯源 (Code Anchor)】
  • latex/final.tex:246 · 论文把自然语言数据库问答定义为受真实数据源约束的查询执行流程。
  • latex/final.tex:252 · 明确输入是自然语言问题,输出包括可执行 SQL、查询结果和必要解释。
  • graduation-design/README.md:3 · 项目定位为本地可运行的 NL2SQL 系统。
  • graduation-design/README.md:7 · 明确它不是通用 BI 平台,而是自然语言问数研究型工程实现。
  • graduation-design/backend/chat/service.py:2106 · stream_chat() 承担在线问答主链路编排。
“我的系统不是让大模型自由聊天,而是让它在真实数据库结构、安全规则和执行反馈约束下完成一次可落地的问数任务。”
02

总体分层架构与三条核心数据流

Layered architecture and data flow
Architecture Data Flow ChatService
【核心概念与设计初衷】

总体架构采用前端交互层、后端问答编排层、元数据与知识资产层、模型与向量服务层、数据库执行层的分层结构。论文中的系统架构图可拆成三条流:蓝色在线问答流负责从问题到结果,绿色离线支撑流负责元数据同步、语义资产和值画像构建,紫色外部模型流负责 LLM 与 Embedding 能力调用。这样设计是为了把“用户体验链路”和“知识准备链路”解耦,避免每次问答临时扫描全库或临时重建索引。

架构层 职责 代表实现
前端交互层 问题输入、阶段展示、SQL 和结果渲染 ChatView.vuechatApi
问答编排层 串联检索、生成、校验、执行、修复 ChatService
知识资产层 保存 Schema、术语、样例、证据、记忆 datasourceterminologytraining
模型服务层 SQL 生成与向量检索 openai_client.pyembedding_service.py
执行控制层 SQL Guard、Executor、Verifier、Fixer sql_guard.pysql_executor.py
【算法逻辑与控制流向】
  1. 离线支撑流:数据源接入后同步表字段、关系和值画像,并构建表级或知识片段向量。
  2. 在线问答流:前端提交问题,ChatService 选择数据源并召回 Schema、值证据、术语、样例和记忆。
  3. 模型调用流:Embedding 服务参与检索排序,LLM 服务参与 SQL 生成和必要修复。
  4. 执行控制流:SQL 进入 Guard、Executor、Semantic Verifier 和 Fixer,形成可恢复闭环。
  5. 结果反馈流:后端通过 SSE 推送阶段事件和查询结果,前端合并到当前问答草稿。
【代码精准溯源 (Code Anchor)】
  • latex/final.tex:254 · 论文说明前端、后端、模型与向量服务在总体架构中的职责。
  • latex/final.tex:265 · 论文解释蓝色在线链路、绿色离线能力和紫色模型能力三类数据流。
  • graduation-design/backend/api/router.py:20:26 · 统一挂载认证、数据源、问答、术语、样例和设置路由。
  • graduation-design/backend/main.py:135 · 将聚合后的 api_router 挂载到 /api/v1
  • graduation-design/frontend/src/router/index.ts:78:89:103:127:138 · 前端按数据源、语义建模、对话、术语和样例组织工作区。
“总体架构可以按三条线讲:在线问答负责跑流程,离线支撑负责准备知识,模型服务负责提供生成和向量能力。”
03

三类元数据对象与数据源组织单位

Metadata taxonomy and datasource boundary
Metadata Datasource Traceability
【核心概念与设计初衷】

系统把运行依赖的元数据分成三类:数据源与 Schema 画像、增强知识与证据、问答运行记录。这个划分解决的是“哪些信息约束数据库结构、哪些信息增强业务语义、哪些信息用于复盘追踪”的问题。所有对象都以数据源为基本组织单位,避免不同业务库的表结构、术语和历史问答互相污染。

元数据类别 典型对象 服务阶段
数据源与 Schema 画像 DatasourceDatasourceTableDatasourceFieldDatasourceValueIndex 结构召回、值定位、校验执行
增强知识与证据 DatasourceEvidenceDomainMemorySnippet、术语、SQL 样例 Prompt 增强、修复提示、业务口径补充
问答运行记录 ChatChatRecordChatLog 结果保存、阶段追踪、错误复盘
【算法逻辑与控制流向】
  1. Input:用户维护的数据源配置、同步得到的表字段、运营补充的证据和知识、问答运行产生的记录。
  2. 数据源同步阶段写入 Schema 画像,形成后续检索与校验的结构边界。
  3. 知识维护阶段写入术语、样例、Domain Memory 和 evidence,形成可检索的语义增强材料。
  4. 问答运行阶段持续写入 ChatRecord 和 ChatLog,记录问题、SQL、结果、错误和模型调用过程。
  5. Output:系统可以在答辩中解释每一次 SQL 生成“基于哪些结构、哪些证据、产生了哪些中间步骤”。
【代码精准溯源 (Code Anchor)】
  • latex/final.tex:267 · 论文明确系统运行依赖的三类元数据对象。
  • graduation-design/backend/datasource/models.py:108 · Datasource 保存数据源配置、状态、关系和数据源级向量字段。
  • graduation-design/backend/datasource/models.py:297:333 · DatasourceTableDatasourceField 保存表字段元数据与启用边界。
  • graduation-design/backend/datasource/models.py:368 · DatasourceValueIndex 保存字段取值画像。
  • graduation-design/backend/datasource/models.py:194:234 · DatasourceEvidenceDomainMemorySnippet 保存增强证据和领域记忆。
  • graduation-design/backend/chat/models.py:77:111:166 · ChatChatRecordChatLog 保存会话、问答结果和步骤日志。
“三类元数据就是三本账:结构账告诉模型库里有什么,知识账告诉模型业务怎么理解,运行账记录每次问答是怎么跑出来的。”
04

后端应用入口与模块化 API 路由

FastAPI entrypoint and router aggregation
FastAPI Router Backend
【核心概念与设计初衷】

后端入口采用 FastAPI 统一创建应用实例、生命周期钩子、中间件、异常处理、健康检查和 API 路由注册。模块化路由把认证、数据源、问答、术语、SQL 样例和设置分开维护,但最终统一挂载到 /api/v1。这样既方便前端只认一个 API 根路径,也避免所有业务接口堆在单个文件中。

【算法逻辑与控制流向】
  1. 启动时执行 lifespan(),初始化元数据库、默认数据和增强索引 warmup。
  2. 创建 FastAPI 应用,配置 OpenAPI、文档路由和生命周期函数。
  3. 添加 CORS 中间件,允许前端开发地址访问后端接口。
  4. 注册全局兜底异常处理,保证未捕获异常也能以统一 JSON 格式返回。
  5. 暴露根入口和健康检查接口,便于判断服务与元数据库是否可用。
  6. 通过 api_router 聚合各业务子路由,并统一挂载到 settings.API_V1_STR
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/main.py:37 · lifespan() 定义启动与关闭生命周期。
  • graduation-design/backend/main.py:60 · 创建 FastAPI 应用实例。
  • graduation-design/backend/main.py:69 · 注册 CORS 中间件。
  • graduation-design/backend/main.py:79 · 全局兜底异常处理器。
  • graduation-design/backend/main.py:103:119 · 根入口和健康检查接口。
  • graduation-design/backend/api/router.py:20:26 · 聚合认证、数据源、问答、术语、训练和设置路由。
“后端入口像总闸门:启动时准备基础资源,请求进来后按模块路由分发,异常和健康状态也都在这一层统一收口。”
05

前端交互层与后端 API 边界

Frontend workspace and API boundary
Vue API Boundary SSE
【核心概念与设计初衷】

前端交互层负责工作区组织、登录态、数据源管理、语义建模、对话问答、术语库和 SQL 样例库展示;后端负责真实业务逻辑和数据库访问。前后端通过 REST API 和 SSE 事件流通信,前端不直接访问数据库,也不本地执行 SQL。这个边界能把用户体验、权限路由和状态展示留在浏览器,把数据源连接、模型调用和 SQL 安全控制集中在服务端。

【算法逻辑与控制流向】
  1. Input:用户在前端页面完成登录、数据源维护、语义建模或聊天提问。
  2. Vue Router 根据路由元信息进入数据源、元数据、聊天、设置、术语或训练样例页面。
  3. 普通业务请求通过 request() 自动拼接 /api/v1、鉴权头和 JSON 请求体。
  4. 聊天问答通过 askStream() 使用 fetch 发起流式请求,并读取 SSE 响应。
  5. Output:前端只展示阶段状态、SQL、查询结果和错误信息,不越过 API 边界操作业务数据库。
【代码精准溯源 (Code Anchor)】
  • graduation-design/frontend/src/main.ts:21:26 · 创建 Vue 应用,注册 Pinia、Router、主题和视口同步。
  • graduation-design/frontend/src/router/index.ts:59 · 创建前端路由器。
  • graduation-design/frontend/src/router/index.ts:78:89:103:127:138 · 数据源、语义建模、聊天、术语、样例页面路由。
  • graduation-design/frontend/src/router/index.ts:165 · beforeEach() 处理登录、管理员权限和初始化状态。
  • graduation-design/frontend/src/api/http.ts:34:137 · 统一 API 根地址和普通 HTTP 请求封装。
  • graduation-design/frontend/src/api/chat.ts:188 · askStream() 发起 /chat/ask SSE 请求。
“前端只负责把问数过程看得见、点得动;真正的数据源访问、模型调用和 SQL 安全边界都收在后端。”
06

应用生命周期、初始化与降级进入机制

Lifecycle initialization and degraded access
Lifecycle Warmup Degraded
【核心概念与设计初衷】

系统启动不仅是启动 Web 服务,还要准备元数据库、默认管理员、基础配置和增强索引状态。设计上没有把业务入口强绑定到所有增强索引完全成功,而是启动后台 warmup,并通过初始化状态接口告诉前端当前是否阻塞、降级或完成。这样可以保证基础管理页面可用,同时把向量索引等增强能力的准备状态透明化。

【算法逻辑与控制流向】
  1. 后端启动进入 lifespan()
  2. init_database() 导入所有 SQLModel 模型并初始化元数据库表结构。
  3. bootstrap_default_data() 补齐默认管理员、模型设置和基础运行数据。
  4. start_background_warmup() 异步预热增强索引,不阻塞全部业务入口。
  5. 前端路由守卫读取初始化状态,若阻塞则跳转初始化页,若可降级则允许进入工作区。
  6. Output:系统可以在“基础可用”和“增强能力准备中”之间给出清晰状态,而不是启动失败或沉默不可用。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/main.py:37 · lifespan() 中统一执行数据库初始化、默认数据 bootstrap 和索引 warmup。
  • graduation-design/backend/core/database.py:382 · init_database() 初始化元数据库结构。
  • graduation-design/backend/core/bootstrap.py:22 · bootstrap_default_data() 补齐默认运行数据。
  • graduation-design/backend/services/index_initialization_service.py:142 · start_background_warmup() 启动后台增强索引预热。
  • graduation-design/backend/settings/router.py:78 · get_index_initialization_status() 向前端暴露初始化状态。
  • graduation-design/frontend/src/router/index.ts:193 · 前端根据初始化阻塞状态跳转初始化页。
“启动初始化不是一把梭拦住所有页面,而是先保证基础系统可用,再把增强索引的准备状态通过初始化页和降级模式透明展示。”
07

问答运行记录与可追溯闭环

Runtime traceability and record ledger
ChatRecord ChatLog Audit
【核心概念与设计初衷】

问答运行记录是系统可解释和可复盘的基础。每一轮问答不仅保存最终 SQL 和数据结果,还保存运行状态、错误信息、阶段日志、模型输入输出和本地操作记录。它解决的是答辩中最容易被追问的问题:系统如何证明某条结果不是黑盒生成,而是经过了哪些步骤、用了哪些上下文、在哪个阶段失败或成功。

【算法逻辑与控制流向】
  1. Input:一次用户提问和 ChatService 运行过程中产生的阶段材料。
  2. 创建 ChatRecord,初始状态从 pending/running 开始。
  3. 每个关键阶段创建或完成 ChatLog,保存 prompt、响应、用量、本地操作标记和错误状态。
  4. SQL 生成后写入 sql_answersql_textsql_tables_json 等结果字段。
  5. 执行完成后写入 data_json、图表、解释、推荐追问或错误信息。
  6. Output:前端可以查看历史问答,开发和答辩时可以根据日志复盘每个阶段。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/models.py:21 · ChatLogStep 枚举完整记录问答阶段。
  • graduation-design/backend/chat/models.py:63 · ChatRecordStatus 定义 pending、running、retrying、cancelling、cancelled、failed、completed 等状态。
  • graduation-design/backend/chat/models.py:111 · ChatRecord 保存问题、SQL、结果、图表、解释、推荐追问和错误信息。
  • graduation-design/backend/chat/models.py:166 · ChatLog 保存每个步骤的 prompt、响应、usage、本地操作和错误标记。
  • graduation-design/backend/chat/repository.py:382:618:713:751:878 · 仓储层分别创建问答记录、步骤日志、SQL 结果、查询结果和完成状态。
“ChatRecord 记录最后结果,ChatLog 记录中间过程,所以系统不是只给答案,还能追溯答案是怎么一步步生成和验证出来的。”
08

研究型工程实现与答辩演示闭环

Research prototype and demonstration loop
Demo Path Engineering Closed Loop
【核心概念与设计初衷】

系统是研究型工程实现,目标是证明多层检索增强、SQL 校验修复和流式交互在自然语言问数场景中可以形成闭环。因此它保留了登录、数据源接入、元数据同步、语义建模、知识维护、聊天执行、图表解释和经验沉淀等完整演示路径,而不是只交付一个离线评测脚本或单次模型调用样例。

【算法逻辑与控制流向】
  1. Input:一个可连接的 MySQL/PostgreSQL/Excel/CSV 数据源和若干自然语言问题。
  2. 登录系统后新增数据源,完成连接测试和元数据同步。
  3. 在语义建模页维护表注释、字段注释、表关系和 evidence。
  4. 在术语库和 SQL 样例库补充业务口径与 few-shot 示例。
  5. 进入聊天页提问,观察 Schema-RAG、SQL 生成、校验执行和结果返回。
  6. 查询成功后生成图表、解释和推荐追问,并将成功问答沉淀为经验候选。
  7. Output:答辩现场可以从数据接入一路演示到结果解释,体现研究方案的工程可运行性。
【代码精准溯源 (Code Anchor)】
  • graduation-design/README.md:3:5 · README 给出完整演示主链路:登录、数据源接入、元数据同步、RAG、SQL 修复、结果执行、图表解释和经验沉淀。
  • graduation-design/README.md:16:30 · 概述已落地的核心能力,包括数据源、知识增强、SSE、修复、图表和设置。
  • graduation-design/README.md:40 · README 的“核心链路”说明数据接入、知识增强和聊天执行三条主线。
  • graduation-design/frontend/src/router/index.ts:78:148 · 前端路由对应演示路径中的数据源、语义建模、聊天、设置、术语和样例页面。
  • graduation-design/backend/api/router.py:21:26 · 后端模块路由对应演示闭环中的认证、数据源、问答、术语、样例和设置能力。
“我的工程闭环是从数据源接入开始,到自然语言问数、SQL 校验修复、结果解释和经验沉淀结束,能现场跑通研究方案。”

数据源接入、元数据同步与语义建模

本知识域回答数据源如何进入系统,表字段与关系如何被同步和维护,以及这些元数据如何转化为后续 Schema-RAG、Value Grounding 和 Prompt 构造可复用的语义资产。

01

统一数据源抽象与配置模型

Datasource abstraction and configuration contract
Datasource Config Boundary
【核心概念与设计初衷】

统一数据源抽象是系统接入真实业务库和文件表格的入口。系统把 MySQL、PostgreSQL、Excel/CSV 都收敛成 Datasource 主对象与 DatasourceConfig 配置对象,后续元数据同步、Schema-RAG、值画像、表关系和证据维护都以 datasource_id 为组织边界。这样可以保证不同数据源之间的表字段、业务术语、关系和问答记录不会相互污染。

对象 核心字段 答辩作用
Datasource namedb_typeconfig_jsontable_relation_json 数据源主入口和多数据源隔离边界
DatasourceConfig hostportdatabase_namefile_pathsheets 统一保存数据库型与文件型连接参数
DatasourceType mysqlpostgresqlexcel 让方言处理和前端表单按类型分支
【算法逻辑与控制流向】
  1. Input:用户在前端提交的数据源名称、类型、连接配置或文件导入结果。
  2. 后端用 DatasourceType 区分 MySQL、PostgreSQL 和 Excel/CSV 文件型数据源。
  3. 连接参数统一进入 DatasourceConfig,再序列化为 config_json 持久化。
  4. 数据源主表保存运行状态、表数量、最近同步时间、关系 JSON、向量快照和推荐配置。
  5. Output:一个稳定的 datasource_id,后续表字段、关系、证据、值画像和问答记录都挂在它下面。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/datasource/models.py:21 · DatasourceType 定义 MySQL、PostgreSQL、Excel/CSV 三类接入类型。
  • graduation-design/backend/datasource/models.py:79 · DatasourceConfig 统一保存数据库连接参数和文件型数据源路径。
  • graduation-design/backend/datasource/models.py:108 · Datasource 保存数据源主记录、配置 JSON、关系 JSON 和 embedding 字段。
  • graduation-design/backend/datasource/service.py:322 · _serialize_config() 将配置对象序列化进元数据库。
  • graduation-design/backend/datasource/service.py:346 · _deserialize_table_relations() 将表关系 JSON 反序列化为关系配置列表。
“数据源抽象就是给每个业务库发一张身份证,后面的表、字段、关系、证据和问答记录都按这张身份证归档。”
02

数据库方言适配、连接测试与结构探测

Dialect adapter, connection test and introspection
Dialect SQLAlchemy Inspect
【核心概念与设计初衷】

方言适配层负责屏蔽 MySQL、PostgreSQL 和本地 SQLite 文件型数据源之间的连接差异。系统不让上层同步逻辑直接拼接不同数据库的连接串,而是由 db_dialect.py 统一构建 SQLAlchemy Engine、执行 SELECT 1 连接测试,并通过 SQLAlchemy Inspector 探测表和字段。设计痛点是不同数据库的连接参数、schema 搜索路径和注释读取方式不同,需要在接入层集中处理。

【算法逻辑与控制流向】
  1. Input:db_typeDatasourceConfig
  2. build_database_url() 按类型生成 SQLAlchemy 连接串。
  3. create_datasource_engine() 为 PostgreSQL 注入 search_path,为 SQLite 文件源设置 check_same_thread=False
  4. test_connection() 建立连接并执行 SELECT 1,失败时抛出统一连接检测异常。
  5. inspect_schema() 读取表名、表注释、字段名、字段类型、字段注释和字段顺序。
  6. Output:标准化的 RemoteTableMetaRemoteColumnMeta 列表,供同步算法落库。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/db_dialect.py:45:63 · RemoteColumnMetaRemoteTableMeta 定义远程结构探测结果。
  • graduation-design/backend/services/db_dialect.py:221 · build_database_url() 按数据源类型构造连接串。
  • graduation-design/backend/services/db_dialect.py:256 · create_datasource_engine() 创建业务数据源 SQLAlchemy 引擎。
  • graduation-design/backend/services/db_dialect.py:291 · test_connection() 执行 SELECT 1 检查连接可用性。
  • graduation-design/backend/services/db_dialect.py:329 · inspect_schema() 使用 Inspector 读取远程表字段元数据。
  • graduation-design/backend/datasource/service.py:1051 · run_connection_test() 将连接检测结果封装为前端响应。
“方言层就像转换插头,上层只要说我要连这个数据源,底层负责把 MySQL、PostgreSQL 和文件 SQLite 的差异消化掉。”
03

Excel / CSV 文件型数据源导入

File datasource ingestion
Excel CSV SQLite
【核心概念与设计初衷】

文件型数据源把 Excel/CSV 转换成后端可统一处理的本地 SQLite 数据源。它解决了答辩演示和小型业务数据分析中“没有远程数据库也要能问数”的问题。导入后,文件中的每个 Sheet 或 CSV 会变成 SQLite 表,后续连接测试、元数据同步、表字段维护、预览和问答都复用同一套数据源抽象。

【算法逻辑与控制流向】
  1. Input:前端上传的 .xlsx.xls.csv 文件。
  2. 前端限制文件大小并调用 /datasource/uploadExcel
  3. 后端用 pandas 读取 CSV 或 Excel 多 Sheet,并规范化列名。
  4. 为每个 Sheet 生成去重后的 SQLite 表名,写入本地 .sqlite3 文件。
  5. 返回 filenamefile_pathsheets 给前端表单。
  6. 用户保存数据源后,文件型配置进入 DatasourceConfig,后续按 excel 方言连接 SQLite。
  7. Output:一个可同步、可预览、可问答的文件型数据源。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/datasource/service.py:243 · _read_uploaded_tables() 读取 CSV 或 Excel 工作表。
  • graduation-design/backend/datasource/service.py:268 · upload_file_datasource() 将文件转换成本地 SQLite 表。
  • graduation-design/backend/services/db_dialect.py:221 · build_database_url()excel 类型返回 sqlite:///... 连接串。
  • graduation-design/backend/datasource/router.py:101 · /datasource/uploadExcel 接收前端上传文件。
  • graduation-design/frontend/src/components/datasource/DatasourceFormModal.vue:581 · handleFileSelected() 处理文件选择、上传和表单回填。
  • graduation-design/frontend/src/api/datasource.ts:56 · uploadExcel()FormData 调用后端上传接口。
“文件型数据源不是单独开一条链路,而是先把 Excel/CSV 变成 SQLite 表,再复用数据库接入、同步和问答的统一流程。”
04

数据源生命周期:创建、更新、删除与自动同步

Datasource lifecycle management
Lifecycle Auto Sync Ownership
【核心概念与设计初衷】

数据源生命周期管理把“保存连接配置”和“生成可用元数据”绑定起来。创建或更新数据源时,系统不仅保存配置,还立即执行连接测试和元数据同步;删除数据源时,系统清理 evidence、值画像、表字段元数据以及文件型本地存储。这样可以避免出现“列表里有数据源,但没有表字段上下文可供问答”的半成品状态。

【算法逻辑与控制流向】
  1. Input:当前用户、数据源创建或更新请求。
  2. 校验数据源名称是否重复,并确认当前用户对目标数据源有所有权。
  3. 执行连接测试,失败则不进入保存流程。
  4. 创建或更新 Datasource 主记录,写入类型、配置、状态和更新时间。
  5. 立即调用 sync_datasource_metadata() 同步表字段。
  6. 删除时先清理文件型存储,再删除 evidence、值画像、字段、表和主记录。
  7. Output:前端拿到已完成初次同步或重新同步的数据源详情。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/datasource/service.py:940 · create_datasource() 创建数据源并自动执行初次同步。
  • graduation-design/backend/datasource/service.py:980 · update_datasource() 更新配置后重新同步元数据。
  • graduation-design/backend/datasource/service.py:1030 · delete_datasource() 删除数据源及其本地元数据。
  • graduation-design/backend/datasource/service.py:434:460 · 所有权检查和重名检查。
  • graduation-design/frontend/src/components/datasource/DatasourceFormModal.vue:634 · runConnectionTest() 让用户保存前测试连接。
  • graduation-design/frontend/src/components/datasource/DatasourceFormModal.vue:657 · submitForm() 调用创建或更新接口。
“数据源保存不是只存一串连接参数,而是要马上验证、同步表字段,确保它保存完就能进入问答链路。”
05

表字段元数据同步算法

Schema synchronization algorithm
Sync Schema Upsert
【核心概念与设计初衷】

元数据同步是把远程业务数据库或文件型 SQLite 中的表字段结构复制到系统元数据库中,形成后续 NL2SQL 的结构边界。同步算法既要新增新表新字段,也要更新已有注释、类型和字段顺序,还要删除远程已经不存在的本地表字段。核心设计是保留人工维护的业务注释和启用状态,同时用远程结构刷新客观元数据。

【算法逻辑与控制流向】
  1. Input:datasource_id 和当前用户。
  2. 读取数据源配置,调用 inspect_schema() 得到远程表字段列表。
  3. 按表名查找本地已有 DatasourceTable,存在则更新原始注释和同步时间,不存在则新增并默认 checked=True
  4. 对每张表按字段名 upsert DatasourceField,同步字段类型、原始注释和顺序。
  5. 本轮不存在的旧字段和旧表会被删除,避免检索到已失效结构。
  6. 更新数据源 table_countstatuslast_sync_time
  7. 触发值画像、RAG embedding、Domain Memory 和推荐问题缓存刷新。
  8. Output:表数量、字段数量和“同步完成”消息。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/datasource/service.py:1119 · sync_datasource_metadata() 是表字段同步主流程。
  • graduation-design/backend/datasource/service.py:1182 · _upsert_table() 插入或更新本地表元数据。
  • graduation-design/backend/datasource/service.py:1227 · _sync_table_fields() 同步单表字段列表。
  • graduation-design/backend/datasource/service.py:1299 · _delete_removed_tables_and_fields() 删除远程已不存在的表字段。
  • graduation-design/backend/datasource/router.py:341 · /datasource/{datasource_id}/sync 暴露同步接口。
  • graduation-design/frontend/src/views/datasource/MetadataView.vue:454 · syncCurrentDatasource() 在语义建模页触发重新同步。
“元数据同步就是把真实库的表字段定期照相,但保留人工补充的业务注释和启用开关,让结构边界既真实又可运营。”
06

表字段语义建模:业务注释与启用边界

Table and field semantic modeling
Semantic Checked Annotation
【核心概念与设计初衷】

表字段语义建模是管理员对同步后的原始结构进行业务化解释和筛选。真实数据库里的字段名可能是缩写、英文、历史遗留命名,原始注释也可能为空;系统允许维护 custom_comment 作为业务语义补充,并通过 checked 控制表字段是否参与后续问答。这样既能提高检索和 Prompt 的语义可读性,也能排除敏感、脏数据或业务无关字段。

【算法逻辑与控制流向】
  1. Input:用户在语义建模页修改表业务注释、字段业务注释或启用状态。
  2. 前端调用 updateTable()updateField(),只提交发生变化的字段。
  3. 后端检查数据源和表字段所有权,更新 custom_commentchecked
  4. 如果表或字段被停用,则删除对应值画像,避免停用字段继续参与 Value Grounding。
  5. 更新后刷新 RAG embedding 和 Domain Memory,使新注释进入后续检索上下文。
  6. Output:更新后的表或字段元数据对象,前端立即替换当前列表项。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/datasource/models.py:297 · DatasourceTable 保存表注释、业务注释和 checked
  • graduation-design/backend/datasource/models.py:333 · DatasourceField 保存字段类型、字段注释、业务注释和启用状态。
  • graduation-design/backend/datasource/service.py:1451 · update_table_metadata() 更新表业务注释和启用状态。
  • graduation-design/backend/datasource/service.py:1490 · update_field_metadata() 更新字段业务注释和启用状态。
  • graduation-design/frontend/src/views/datasource/MetadataView.vue:353:372 · 前端保存表注释和切换表启用状态。
  • graduation-design/frontend/src/views/datasource/MetadataView.vue:393:407 · 前端保存字段注释和切换字段启用状态。
“语义建模不是改数据库结构,而是在系统元数据库里给表字段补业务说明、设启用边界,让模型只看该看的结构。”
07

表关系建模与 JOIN 证据持久化

Table relation modeling and join evidence
Relation JOIN Graph
【核心概念与设计初衷】

表关系建模用于维护当前数据源内表与字段之间的显式关联。很多真实业务库没有完整外键,或者外键约束没有暴露给应用层;如果只靠字段名推断,JOIN 路径容易不稳定。系统提供前端关系画布,让用户把表加入画布并连接两个字段,最终把节点和边保存到 table_relation_json,供 Schema-RAG 关系补全、Prompt 外键说明和 SQL Guard JOIN 校验复用。

【算法逻辑与控制流向】
  1. Input:当前数据源表列表和用户在关系画布中建立的字段连线。
  2. 前端加载已保存关系,并按涉及表懒加载字段列表。
  3. 用户添加表节点,依次点击两个不同表的字段建立一条关系边。
  4. 前端去重、过滤自连接和失效字段,构造节点与边 payload。
  5. 后端将关系列表序列化为 table_relation_json,并刷新 Domain Memory。
  6. Output:当前数据源可复用的显式表关系证据。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/datasource/service.py:1414 · get_table_relations() 读取数据源关系配置。
  • graduation-design/backend/datasource/service.py:1427 · update_table_relations() 保存关系 JSON 并刷新 Domain Memory。
  • graduation-design/backend/datasource/service.py:337 · _serialize_table_relations() 规范化并序列化关系列表。
  • graduation-design/frontend/src/components/datasource/TableRelationEditor.vue:574 · loadSavedRelations() 加载并还原关系画布。
  • graduation-design/frontend/src/components/datasource/TableRelationEditor.vue:723 · handlePortClick() 处理两字段连线逻辑。
  • graduation-design/frontend/src/components/datasource/TableRelationEditor.vue:802 · saveRelations() 保存关系配置。
“表关系建模就是把数据库里没声明清楚的 JOIN 路径画出来,之后检索、生成和校验都能按这张关系图说话。”
08

数据源 Evidence 与长期业务语义

Datasource-level evidence and business semantics
Evidence Business Rule Domain Memory
【核心概念与设计初衷】

数据源 Evidence 是针对单个数据源长期稳定成立的业务补充说明,包含公式定义、枚举映射、时间规则、业务规则和其他说明。它解决的是表字段注释无法表达的业务口径问题,例如指标公式、枚举值含义和日期字段解析规则。Evidence 保存后会刷新 Domain Memory,在线问答时可作为可追溯证据参与 Prompt 组织。

【算法逻辑与控制流向】
  1. Input:用户为当前数据源维护的 evidence 列表。
  2. 前端按 kind 区分公式、枚举映射、时间规则、业务规则和其他说明。
  3. 后端规范化标题和正文,限制单条长度、去重并限制单数据源最多 20 条。
  4. 保存时先删除旧 evidence,再按排序写入新列表。
  5. 保存后刷新 Domain Memory,让 evidence 转化为可检索的长期知识片段。
  6. Output:数据源级业务证据配置,后续可被问答链路召回。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/datasource/models.py:36 · DatasourceEvidenceKind 定义 formula、enum_mapping、time_rule、business_rule 等类型。
  • graduation-design/backend/datasource/models.py:194 · DatasourceEvidence 保存数据源级证据。
  • graduation-design/backend/datasource/service.py:796 · _normalize_datasource_evidence_items() 校验、去重并限制 evidence 数量。
  • graduation-design/backend/datasource/service.py:866 · save_datasource_evidence_config() 保存 evidence 并刷新 Domain Memory。
  • graduation-design/frontend/src/components/datasource/DatasourceEvidenceConfigModal.vue:122 · evidencePlaceholder() 为不同 evidence 类型提供维护提示。
  • graduation-design/frontend/src/components/datasource/DatasourceEvidenceConfigModal.vue:187 · submitConfig() 提交 evidence 配置。
“表字段说明解决‘这列是什么’,Evidence 解决‘这个数据源里的业务口径怎么算、枚举怎么解释、时间怎么理解’。”
09

同步后的语义资产刷新联动

Post-sync semantic asset refresh
Embedding Value Index Warmup
【核心概念与设计初衷】

数据源同步不仅更新表字段,还会触发一组语义资产刷新:字段取值画像、表级与数据源级 RAG embedding、Domain Memory 片段和推荐问题缓存。这些资产服务于后续 Schema-RAG、Value Grounding、业务记忆检索和聊天入口推荐。设计上这些刷新是增强能力,不应该阻塞数据源管理主流程;失败时记录日志,保留基础元数据可用性。

【算法逻辑与控制流向】
  1. Input:刚完成元数据同步或表字段语义更新的数据源。
  2. 同步主流程先落库表字段,再调用 _refresh_datasource_value_grounding() 重建字段值画像。
  3. 调用 _refresh_datasource_rag_embeddings() 重建数据源和表级向量快照。
  4. 调用 _refresh_datasource_domain_memory() 将表字段、关系和 evidence 转为长期知识片段。
  5. 调用 _refresh_datasource_recommended_questions() 生成或刷新起始推荐问题缓存。
  6. 任一增强刷新失败只记录日志,不回滚已经同步成功的表字段元数据。
  7. Output:可被在线问答检索的最新语义资产;失败时仍保留关键词和基础 Schema 可用。
【代码精准溯源 (Code Anchor)】
  • latex/final.tex:745 · 论文说明索引与缓存在数据源同步后刷新,或系统启动后预热。
  • latex/final.tex:747 · 论文说明索引刷新不作为核心入口强制前置条件,向量不可用时可降级运行。
  • graduation-design/backend/datasource/service.py:82 · _refresh_datasource_rag_embeddings() 尝试刷新 RAG 向量。
  • graduation-design/backend/datasource/service.py:119 · _refresh_datasource_domain_memory() 刷新 Domain Memory。
  • graduation-design/backend/datasource/service.py:135 · _refresh_datasource_value_grounding() 刷新字段取值画像。
  • graduation-design/backend/datasource/service.py:1119 · sync_datasource_metadata() 在表字段同步完成后串联这些刷新动作。
“同步表字段是打地基,刷新向量、值画像和领域记忆是铺检索资产;地基必须成功,增强资产失败也不能让数据源管理瘫痪。”
10

前端数据源与语义建模工作台

Frontend datasource and metadata workspace
Frontend Workbench Preview
【核心概念与设计初衷】

前端工作台把数据源接入、元数据同步、语义建模、表关系维护、evidence 配置和数据预览组织为可操作界面。它的设计目标不是让用户写配置文件,而是让答辩演示和日常维护都能通过页面完成:先新增数据源,再同步结构,然后维护表字段语义、关系和证据,最后进入聊天问答。

【算法逻辑与控制流向】
  1. Input:用户在数据源列表、表单弹窗、语义建模页和关系编辑器中的操作。
  2. DatasourceView 加载数据源列表,支持新增、编辑、删除、同步、证据配置和推荐问题配置。
  3. DatasourceFormModal 统一处理数据库型和文件型数据源的表单、上传、连接测试和保存。
  4. MetadataView 加载表列表和字段列表,维护表字段注释、启用状态和样例数据预览。
  5. TableRelationEditor 维护关系图,把节点和边保存为后端可持久化的关系 payload。
  6. datasourceApi 封装 REST 接口,前端不直接拼后端业务细节。
  7. Output:可视化完成数据源从接入到语义建模的完整维护闭环。
【代码精准溯源 (Code Anchor)】
  • graduation-design/frontend/src/views/datasource/DatasourceView.vue:165 · loadDatasources() 加载数据源列表。
  • graduation-design/frontend/src/views/datasource/DatasourceView.vue:236 · syncDatasource() 从列表页触发结构同步。
  • graduation-design/frontend/src/components/datasource/DatasourceFormModal.vue:410 · handleDbTypeChange() 根据数据源类型切换默认配置。
  • graduation-design/frontend/src/views/datasource/MetadataView.vue:302 · reloadAll() 加载数据源详情、表列表和当前字段。
  • graduation-design/frontend/src/views/datasource/MetadataView.vue:439 · loadPreview() 读取当前表样例数据。
  • graduation-design/frontend/src/api/datasource.ts:148:271 · datasourceApi 对齐后端数据源、同步、表字段、关系、预览等接口。
“前端工作台把接入、同步、注释、关系、证据和预览串起来,让数据源从一串连接参数变成可被问答系统理解的语义资产。”

向量化与 Schema-RAG 核心检索流

本知识域回答三个核心问题:Schema 如何向量化、如何从海量表中召回相关表、如何通过关系补全恢复多表 SQL 的结构边界。

论文原图:通用 RAG 基本工作机制图
论文原图 · 通用 RAG 基本工作机制图 用于回答理论依据:系统的 Schema-RAG 本质上沿用“检索外部知识,再约束生成”的 RAG 思路,只是知识对象从文档变成了数据库表字段和关系。

读图顺序

  1. 用户问题先被向量化,形成可以和知识库条目比较的语义表示。
  2. 检索器从外部知识库召回与问题最相关的片段,而不是让模型只依赖参数记忆。
  3. 召回内容被拼接到 Prompt 中,成为生成阶段的上下文约束。
  4. 大模型基于“问题 + 检索证据”生成答案,从而降低幻觉和上下文缺失风险。

迁移到本系统:普通 RAG 检索的是文档片段,本系统检索的是表级 Schema 快照、字段说明、关系边和值证据;生成目标也不是自然语言回答,而是可执行 SQL。

答辩讲法:Schema-RAG 就是把“查资料再回答”的 RAG 思路换成“查数据库结构再写 SQL”,让模型先知道库里有什么,再决定怎么查。

论文原图:基础 Schema-RAG 与复杂问题增强控制流图
论文原图 · 基础 Schema-RAG 与复杂问题增强控制流图 用于串联第 3、8、9 域:Schema-RAG 先给出结构边界,值证据、计划、校验验证与修复再沿主链路逐层增强。

读图顺序

  1. 基础层先完成数据源确定、Schema 检索、关系补全和聚焦模式文本构造,这是所有后续模块共享的结构边界。
  2. 生成前增强层补充条件值定位、术语、SQL 样例、领域记忆、检索证据和 SQL 计划,用来解决业务缩写、真实取值、指标口径和复杂查询结构。
  3. 生成阶段把聚焦 Schema 与增强上下文统一送入 Prompt Builder,由模型生成候选 SQL。
  4. 生成后控制层再执行 SQL Guard、数据库查询、语义验证和可选自动修复,防止“能生成”但“不安全、不合法或语义不对”。

关键边界:增强模块不是全部无条件开启,而是按配置、召回结果和问题复杂度进入链路;Schema-RAG 始终是最基础的结构约束。

答辩讲法:这张图说明我的系统是“先收窄结构,再补充证据,再生成 SQL,最后校验修复”,不是把所有材料一次性塞给模型碰运气。

01

表级向量化语义快照

Table-level embedding document
Embedding 表级粒度 元数据快照
【核心概念与设计初衷】

表级向量化是把一张数据表的名称、注释、字段名、字段类型和字段注释压缩成一段语义文档,再生成 embedding。系统选择“表级”而不是“字段级”作为基础粒度,是为了保留同一张表内部字段之间的上下文,避免字段被拆散后 JOIN 路径难以恢复。

【算法逻辑与控制流向】
  1. Input:DatasourceDatasourceTable、该表启用字段列表。
  2. 拼接数据源名、描述、数据库类型、表名、表注释。
  3. field_index 排序拼接字段名、字段类型、字段注释。
  4. 调用 embedding 模型生成向量。
  5. Output:文本快照保存到 embedding_text,向量 JSON 保存到 embedding_json
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/embedding_service.py:89 · build_table_embedding_text() 构造表级文本。
  • graduation-design/backend/services/embedding_service.py:298 · refresh_table_embeddings() 批量重建表向量。
  • graduation-design/backend/services/embedding_service.py:239 · embed_texts() 调用 embedding 客户端并按批处理。
“我不是把字段零散丢给模型,而是先给每张表做一张语义身份证,再用这张身份证去和用户问题做相似度匹配。”
02

向量新鲜度与降级机制

Freshness check and graceful fallback
Freshness Keyword fallback 稳定性
【核心概念与设计初衷】

向量新鲜度用于保证 embedding 和当前表字段元数据一致。因为表注释、字段注释、字段启用状态都可能被管理员修改,如果不做 fresh check,系统可能拿旧向量召回错误表。

【算法逻辑与控制流向】
  1. Input:当前表/字段元数据、历史 embedding_text、历史 embedding_json
  2. 重新构造最新表级文本。
  3. 判断最新文本是否等于历史 embedding_text
  4. 对启用表,要求向量必须存在;对未启用表,要求不保留历史向量。
  5. 如果 embedding 服务不可用,系统保留文本快照、清空向量,后续检索退化为关键词召回。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/embedding_service.py:141 · is_table_embedding_fresh() 判断表向量是否新鲜。
  • graduation-design/backend/services/embedding_service.py:218 · embedding_is_available() 判断 embedding 能力是否可用。
  • graduation-design/backend/datasource/service.py:1119 · sync_datasource_metadata() 同步元数据后刷新索引。
  • graduation-design/backend/datasource/service.py:1451 / :1490 · 编辑表或字段元数据后刷新 RAG embedding。
“向量不是一次生成永久有效的缓存,只要表字段说明变了,我就重新核对;向量服务挂了也不影响系统运行,只是降级成关键词检索。”
03

SchemaRetrievalResult 检索结果契约

Traceable retrieval contract
Data Contract Ranking 可追溯
【核心概念与设计初衷】

SchemaRetrievalResult 是 Schema-RAG 的核心返回对象。它不仅包含 Prompt 需要的 schema_text,还保存直接命中表、关系补全表、外键、排序证据等诊断信息,供 SQL 生成、SQL Guard、语义验证和自动修复复用。

【算法逻辑与控制流向】
  1. Input:用户问题 question、数据源 ID、最大表数量 max_tables
  2. 加载启用表字段。
  3. 计算每张表得分。
  4. 筛选 Top-K 主召回表。
  5. 执行关系补全并构造 M-Schema。
  6. Output:schema_textretrieved_tablesselected_tablesrelation_tablesforeign_keysranking
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/schema_retrieval.py:182 · TableSchemaBundleRelationEdgeSchemaRetrievalResult 定义。
  • graduation-design/backend/services/schema_retrieval.py:1389 · retrieve_relevant_schema() 主入口。
“Schema-RAG 返回的不是一段字符串,而是一份可追踪的检索报告:哪些表是直接命中的,哪些表是为了 JOIN 补进来的,为什么这么排,都能查到。”
04

Embedding + Keyword + Heuristic 混合召回

Hybrid schema ranking
Hybrid RAG Final Score Top-K
【核心概念与设计初衷】

混合召回同时利用 embedding 的语义相似、关键词的精确命中和启发式规则的业务信号。这样可以避免单纯向量召回对字段名、缩写、日期、金额等结构线索不敏感,也避免单纯关键词无法理解语义相近表达。

【算法逻辑与控制流向】
  1. Input:用户问题、所有启用表字段、表级向量。
  2. _tokenize() 提取问题检索单元。
  3. _calculate_bundle_score() 计算关键词得分:表名权重最高,表注释次之,字段名/字段注释也参与。
  4. 若 embedding 可用且表向量新鲜,则计算问题向量与表向量的 cosine similarity。
  5. Hybrid 模式下:final = embedding_score * weight + normalized_keyword * (1-weight) + heuristic_bonus
  6. final_score 排序,选择 Top-K;若全部无正分则退化取排序前 K 张表。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/schema_retrieval.py:634 · _iter_text_candidates() 定义关键词候选权重。
  • graduation-design/backend/services/schema_retrieval.py:663 · _calculate_bundle_score() 计算关键词得分。
  • graduation-design/backend/services/schema_retrieval.py:1446:1495 · hybrid 融合与排序。
“向量负责理解语义像不像,关键词负责确认名字有没有对上,启发式规则负责补数据库查询里的特殊信号,三者合起来比单一路径更稳。”
05

启发式加分与 Grounding Evidence

Database-aware ranking signals
Heuristic Grounding 字段证据
【核心概念与设计初衷】

启发式加分是对向量相似度的结构性修正,专门处理数据库问题中常见但 embedding 不一定敏感的信号,如日期、金额、姓名、Top/Max、枚举值、大写缩写、指标字段等。Grounding Evidence 则把这些命中字段和标签记录进 ranking,方便 Prompt 和日志解释。

【算法逻辑与控制流向】
  1. Input:问题 tokens、表名/字段名/注释、字段类型。
  2. 判断问题是否包含金额、支付、日期、人名、极值、枚举或大写缩写。
  3. 若字段集合中有对应字段,如 amountpaymentdatefirst_namelast_name,给表加小额 bonus。
  4. 对命中的字段写入 grounding_fields
  5. 对命中类型写入 grounding_tags,如 person-filterdate-filterfinancial-filter
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/schema_retrieval.py:688 · _calculate_bundle_heuristic_bonus() 计算启发式加分。
  • graduation-design/backend/services/schema_retrieval.py:534 · _collect_bundle_grounding_evidence() 收集字段证据。
  • graduation-design/tests/test_schema_retrieval_guard.py:73 · 支付金额字段加分测试。
  • graduation-design/tests/test_schema_retrieval_guard.py:83 · 人名字段 grounding 测试。
“启发式加分就像给检索器戴了一副数据库眼镜:看到金额问题就更关注金额字段,看到人名就更关注姓名字段。”
06

关系补全与 JOIN 路径恢复

Relation expansion for multi-table SQL
JOIN Foreign Keys 关系补表
【核心概念与设计初衷】

Top-K 表召回只能解决“哪些表相关”,但 SQL 还需要知道“这些表怎么连”。关系补全用于把与主命中表存在外键或可推断关系的邻接表补进上下文,避免模型因为缺少维表、关系表而写不出正确 JOIN。

【算法逻辑与控制流向】
  1. Input:主命中表 selected_bundles、所有候选表 all_bundles、表关系配置、字段集合。
  2. 优先读取前端维护的显式表关系 table_relation_json
  3. 如果没有显式关系且配置允许,则根据 customer_idlink_to_order 等 ID 命名推断关系。
  4. 对显式关系,补入与主命中表相邻的关系端点表。
  5. 对推断关系,按问题相关性评分并受 RAG_SCHEMA_RELATION_SUPPLEMENT_LIMIT 限制。
  6. Output:扩展后的 expanded_bundlesforeign_keysrelation_tables
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/schema_retrieval.py:739 · _load_relation_edges() 解析显式关系。
  • graduation-design/backend/services/schema_retrieval.py:1128 · _infer_relation_edges() 推断隐式关系。
  • graduation-design/backend/services/schema_retrieval.py:1253 · _expand_bundles_with_relations() 执行关系补全。
  • graduation-design/tests/test_schema_retrieval_guard.py:117 · 关键词兜底下补关系表的测试。
“主召回找到的是主角,关系补全负责把和主角必须同台的配角也带上,不然多表 SQL 没法正确 JOIN。”
07

M-Schema 文本构造与 Prompt 证据注入

Focused schema prompt
M-Schema Prompt Evidence
【核心概念与设计初衷】

M-Schema 是最终注入大模型的聚焦数据库结构文本。它不是完整数据库 DDL,而是只包含本轮问题相关的表、字段、字段说明和外键关系,目的是控制 Token 成本并减少无关表干扰。

【算法逻辑与控制流向】
  1. Input:扩展后的表集合 bundles、外键 foreign_keys、数据源配置。
  2. 生成 【DB_ID】
  3. 生成 【Schema】,逐表输出表名、表注释、字段名、字段类型、字段注释。
  4. 若存在外键,则追加 【Foreign keys】
  5. Prompt 层再压缩 ranking,输出 direct-hit tables、relation-expanded tables 和保守的 top1 preference。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/schema_retrieval.py:806 · _build_schema_text() 构造 M-Schema。
  • graduation-design/backend/services/prompt_builder.py:607 · _build_retrieval_evidence() 构造检索证据 Prompt 块。
  • graduation-design/backend/services/prompt_builder.py:700 · 明确 direct-hit 不是硬性表选择。
  • graduation-design/tests/test_retrieval_evidence_prompt.py:13 · 保守注入策略测试。
“M-Schema 就是给大模型看的精简数据库地图,只画本轮可能用到的路和路口,不把整个城市地图都塞进去。”
08

ChatService 在线调用与下游复用

Pipeline integration
ChatService SSE 下游复用
【核心概念与设计初衷】

Schema-RAG 是问答链路的结构边界入口。它先于 SQL 生成执行,结果会被 Prompt 构造、值证据补表、SQL 计划、SQL Guard 和自动修复复用,因此它不是一个孤立检索模块,而是整条 NL2SQL 链路的地基。

【算法逻辑与控制流向】
  1. Input:runtime.effective_question、目标 datasource
  2. ChatService 推送 build_schema 阶段事件。
  3. 调用 retrieve_relevant_schema()
  4. 将结果绑定到 SQLGenerationMemoryBroker
  5. 写入日志,包括 strategy、retrieved tables、selected tables、relation tables、foreign keys、ranking 和 schema text。
  6. 后续 Value Grounding 若命中强证据表,会用 augment_schema_result_with_tables() 反向补表。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/service.py:1077 · _collect_schema_prompt_stage() 执行在线 Schema 阶段。
  • graduation-design/backend/services/memory_broker.py:54 · bind_schema() 绑定检索结果。
  • graduation-design/backend/services/memory_broker.py:162 · Prompt 上下文传入 schema、retrieved tables、relation tables、ranking。
  • graduation-design/backend/services/schema_retrieval.py:985 · augment_schema_result_with_tables() 强证据补表。
“Schema-RAG 先给 SQL 生成划定可用表字段的边界,后面的计划、校验和修复都在这条边界里工作。”
09

检索边界与参数化控制

Retrieval boundary and knobs
Boundary Config Traceable
【核心概念与设计初衷】

Schema-RAG 的检索边界不是完全交给模型判断,而是先受数据源元数据配置约束:只有被管理员启用的表和字段才进入候选集。随后系统通过可配置参数控制召回表数、向量与关键词权重、关系补表上限,让检索行为既能解释,也能在消融实验和不同数据集上调整。

【算法逻辑与控制流向】
  1. Input:datasource_id、用户问题、数据源表字段元数据和系统 RAG 配置。
  2. 候选裁剪:只读取 checked=True 的表与字段,避免未启用或被业务隐藏的结构进入 Prompt。
  3. 策略判定:默认策略为 keyword_fallback;embedding 可用且表向量新鲜时,切换为 embedding_hybridembedding_only
  4. 参数控制:CHAT_SCHEMA_TABLE_LIMIT 限制直接召回表数,RAG_HYBRID_EMBEDDING_WEIGHT 控制向量权重,RAG_SCHEMA_RELATION_SUPPLEMENT_LIMIT 控制关系补表数量。
  5. Output:retrieved_tables 表示直接召回表,selected_tables 表示关系补全后的最终表集合。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/schema_retrieval.py:1416 / :1421 · 只读取 checked=True 的表和字段。
  • graduation-design/backend/services/schema_retrieval.py:1446 / :1467 · 判断 embedding 是否可用,并在 keyword_fallbackembedding_hybridembedding_only 之间切换。
  • graduation-design/backend/services/schema_retrieval.py:1530 / :1540 · 区分直接召回表 retrieved_tables 与补全后表集合 selected_tables
  • graduation-design/backend/core/config.py:90:125 · 定义 Schema-RAG 开关、混合权重、关系补表上限和表数上限。
“Schema-RAG 不是盲搜全库,而是先按人工元数据划定可用边界,再用配置化参数控制召回、融合和补表,所以它既可解释也可调优。”
10

本模块的实验与答辩结论

Evidence from ablation
BIRD Ablation EX
【核心概念与设计初衷】

Schema-RAG 是系统最稳定的基础支撑模块。论文实验中关闭数据库模式检索后,生成成功率、可执行率和 EX 都明显下降,说明结构召回不是锦上添花,而是 NL2SQL 正确性的前置条件。

【算法逻辑与控制流向】
  1. 对比方式:完整配置组 vs No Schema Retrieval。
  2. 观察指标:生成成功率、可执行率、执行准确率 EX。
  3. 论文结果:BIRD 200 条完整配置组 EX 为 57.0%,关闭 Schema Retrieval 后降至 47.0%,下降 10.0 个百分点。
【代码精准溯源 (Code Anchor)】
  • graduation-design/scripts/run_thesis_final_experiments.py:56 · 实验脚本配置入口。
  • latex/final.tex:910 · BIRD 与 Spider 主对比实验。
  • latex/final.tex:1040 · 模块消融实验。
“大模型再强,也必须先知道当前数据库有哪些真实表字段;Schema-RAG 就是把自由生成变成有边界的数据库查询生成。”
没有匹配的卡片。换个关键词试试,比如 架构、数据源、Schema、SSE、Guard、EX、消融、成本。

条件值定位与 Value Grounding

本知识域回答自然语言中的实体名、枚举值、日期和数值范围如何落到真实数据库取值上,并解释值证据如何影响 WHERE 条件、Schema 补充、SQL 计划和执行后语义验证。

01

模块定位与值证据数据契约

Purpose and evidence contract
Value Grounding WHERE Evidence
【核心概念与设计初衷】

Value Grounding 是 SQL 生成前的值证据定位模块,用于把用户问题中的自然语言字面值映射到数据库真实单元格值和具体表字段。它不直接生成 SQL,而是输出候选过滤条件、列范围画像和强证据表,帮助模型在 WHERE 条件中选择正确字段和值,避免把实体名、业务缩写或枚举值落到错误字段上。

证据字段 含义 后续用途
table_name / field_name 候选值所在位置 约束 WHERE 字段选择
value / match_type 真实数据库取值与匹配方式 避免模型改写大小写、缩写和完整形式
confidence / source_phrase 置信度和对应问题原文 候选排序、日志追踪和强证据判断
profile_kind text、date、numeric 画像类型 区分候选过滤值和列范围提示
【算法逻辑与控制流向】
  1. Input:用户问题、目标数据源、当前 Schema-RAG 检索结果。
  2. 模块读取当前数据源的 DatasourceValueIndex 值画像。
  3. 从问题中抽取可能对应真实取值的短语。
  4. 对文本画像样本计算匹配置信度,并可选执行数据库等值查找。
  5. 返回 ValueGroundingCandidate 候选集合和日期/数值列范围画像。
  6. Output:Prompt 中的 <value-grounding> 块、日志候选列表和强证据表集合。
【代码精准溯源 (Code Anchor)】
  • latex/final.tex:382 · 论文说明 Value Grounding 放在生成前证据环节,用于建立自然语言字面值与数据库取值空间的对应关系。
  • latex/final.tex:397 · 论文表格定义候选值证据字段分类。
  • graduation-design/backend/services/value_grounding.py:117 · ValueGroundingCandidate 定义候选值证据对象。
  • graduation-design/backend/services/value_grounding.py:633 · retrieve_value_grounding_candidates() 召回候选值和列范围画像。
  • graduation-design/backend/services/value_grounding.py:779 · get_value_grounding_prompt_block() 返回 Prompt 片段和候选集合。
“Schema-RAG 告诉模型该查哪几张表,Value Grounding 告诉模型自然语言里的这个词应该落到哪张表的哪个真实取值上。”
02

字段画像类型识别:text / date / numeric

Profile kind classification
Profile Type Heuristic
【核心概念与设计初衷】

字段画像类型识别决定一个字段应该采样 distinct 文本值,还是只记录 min/max 范围。系统通过字段类型和字段名启发式把字段分为 textdatenumeric 三类,并排除典型 ID 字段。这样既能为枚举、名称、城市、状态等字段提供真实候选值,也能为日期和数值字段提供范围提示,而不会把大量 ID 列误当作业务数值条件。

画像类型 识别依据 采样方式
text char/text/enum/string,或 name/status/category/city/code 等字段名 采样非空 distinct 值
date date/time/timestamp,或字段名含 date/time/day/month/year 记录 min/max 范围
numeric int/decimal/float/money 等非 ID 数值字段 记录 min/max 范围
【算法逻辑与控制流向】
  1. Input:已启用的 DatasourceField,包括字段名和字段类型。
  2. 如果字段类型或字段名符合日期模式,返回 date
  3. 如果字段类型或字段名符合文本/枚举/名称模式,返回 text
  4. 如果字段是数值类型且字段名不像 ID 或外键,返回 numeric
  5. 其他字段返回 None,不建立值画像。
  6. Output:字段画像类型,供同步后的值画像构建使用。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/value_grounding.py:28:42 · 定义文本、日期、数值和 ID 字段识别正则。
  • graduation-design/backend/services/value_grounding.py:162 · _profile_kind() 根据字段类型和字段名返回画像类型。
  • graduation-design/backend/services/value_grounding.py:269 · refresh_datasource_value_index() 只对 _profile_kind() 非空字段建画像。
  • graduation-design/backend/datasource/models.py:368 · DatasourceValueIndex 持久化字段画像类型、样本值和范围值。
“字段画像先判断这列像不像名字、日期或金额;只有像业务值的列才采样,ID 这类技术字段默认不拿来做条件值证据。”
03

数据源取值画像构建与刷新

Value profile indexing
Index Sample Sync
【核心概念与设计初衷】

取值画像构建是在数据源同步后为已启用字段建立轻量索引。文本字段采样少量 distinct 非空值,日期和数值字段记录最小值和最大值。它解决的是在线问答不能临时全表扫描所有字段取值的问题:先在同步后构建可控规模的画像,在线阶段只读取画像或对少量短语做精确查库补强。

【算法逻辑与控制流向】
  1. Input:数据源对象和已同步的启用表字段。
  2. 如果 RAG_VALUE_GROUNDING_ENABLED 关闭,则删除该数据源旧画像并返回 0。
  3. 读取启用表和启用字段,按画像类型筛选可建索引字段,并受字段数量上限控制。
  4. 先删除当前数据源旧的 DatasourceValueIndex
  5. text 字段执行 SELECT DISTINCT 采样真实值。
  6. date / numeric 字段执行 MIN/MAX 采样范围。
  7. 构造 DatasourceValueIndex 记录并写入元数据库。
  8. Output:画像记录数量,供日志和初始化状态参考。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/value_grounding.py:208 · _sample_text_values() 对文本字段采样 distinct 非空值。
  • graduation-design/backend/services/value_grounding.py:242 · _sample_range_values() 对日期/数值字段采样 min/max。
  • graduation-design/backend/services/value_grounding.py:269 · refresh_datasource_value_index() 重建整个数据源的取值画像。
  • graduation-design/backend/datasource/service.py:135 · 数据源同步后通过 _refresh_datasource_value_grounding() 触发画像刷新。
  • graduation-design/tests/test_value_grounding.py:46 · 测试覆盖取值画像构建和候选召回。
“取值画像不是把整张表都塞给模型,而是在同步后给关键字段做一份小样本和值范围索引,在线问答时按需查这份索引。”
04

问题短语抽取与规范化

Question phrase extraction
Phrase Regex Normalize
【核心概念与设计初衷】

问题短语抽取负责从自然语言问题里找出可能对应数据库真实值的片段,包括引号短语、日期字面值、全大写缩写和英文标题式短语。该步骤的目标不是理解整句话,而是定位“可能作为 WHERE 值”的候选文本,并通过归一化和停用词过滤减少无意义短语进入匹配。

【算法逻辑与控制流向】
  1. Input:用户自然语言问题。
  2. 使用引号正则抽取用户显式标出的实体短语。
  3. 使用日期正则抽取年份、年月或年月日字面值。
  4. 使用全大写正则抽取类似 LAMEUR 的缩写。
  5. 使用标题式短语正则抽取英文实体名或专有名词。
  6. 归一化大小写、空格、连字符和下划线,并过滤停用词和重复短语。
  7. Output:QuestionValuePhrase 列表,每个短语保留 textkind
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/value_grounding.py:44:51 · 定义引号、日期、大写缩写和标题式短语正则。
  • graduation-design/backend/services/value_grounding.py:107 · QuestionValuePhrase 保存短语文本和来源类型。
  • graduation-design/backend/services/value_grounding.py:366 · _normalize_value_text() 规范化匹配文本。
  • graduation-design/backend/services/value_grounding.py:377 · _add_phrase_candidate() 过滤纯停用词短语。
  • graduation-design/backend/services/value_grounding.py:400 · _extract_question_phrase_items() 抽取并去重候选短语。
“短语抽取就像先把问题里可能是条件值的词圈出来,比如引号里的名字、年份、LAM 这种缩写,再拿它们去数据库值空间里对号入座。”
05

候选值匹配评分与阈值过滤

Candidate scoring and thresholding
Scoring Confidence Top-K
【核心概念与设计初衷】

候选值匹配评分用于判断画像样本值是否真的被用户问题提到。系统默认偏保守:精确匹配得分最高,弱包含匹配和 token 覆盖匹配受配置开关控制,只有得分达到 VALUE_GROUNDING_MIN_CONFIDENCE 的候选才会进入结果。这样可以降低“看起来相似但语义错误”的值证据误导模型。

匹配类型 触发条件 可靠性
exact 问题短语归一化后等于真实值 强,默认可作为过滤候选
value_in_phrase / phrase_in_value 开启弱匹配后,真实值与短语互相包含 中,需阈值控制
token_cover / token_exact 开启弱匹配后,token 集被问题覆盖 中低,用于补充召回
【算法逻辑与控制流向】
  1. Input:真实样本值、原始问题、抽取短语列表。
  2. 对真实值和短语做归一化处理。
  3. 若短语与真实值完全相等,得分为 1.0,匹配类型为 exact
  4. 若弱匹配开启,则计算包含覆盖或 token 覆盖得分。
  5. 低于最小置信度阈值的候选被丢弃。
  6. 如果候选表属于当前 Schema 选中表,得分小幅加成。
  7. Output:携带 match_typeconfidencesource_phrase 的候选值。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/value_grounding.py:436 · _token_set() 构造去停用词 token 集。
  • graduation-design/backend/services/value_grounding.py:448 · _score_value_match() 计算真实值与问题短语的匹配分数。
  • graduation-design/backend/services/value_grounding.py:633 · retrieve_value_grounding_candidates() 遍历文本画像样本并过滤低置信候选。
  • graduation-design/backend/core/config.py:110:114 · 配置 Top-K、最小置信度、DB 查找和弱匹配开关。
  • graduation-design/tests/test_value_grounding.py:122 · 测试 Orange CountyActive 等真实取值能进入 Prompt。
“候选评分不是模糊猜字段,而是先看问题里的短语和真实取值是否能对上号,对不上阈值就不让它进提示词。”
06

数据库等值查找补强 db_exact

Exact DB lookup supplement
db_exact Lookup Strong Evidence
【核心概念与设计初衷】

数据库等值查找是对采样画像的补强机制。文本画像只采样有限 distinct 值,目标值可能没有出现在样本里;当问题短语适合直接查库时,系统会对文本字段执行大小写无关等值查询。如果命中真实值,就生成 db_exact 候选,置信度为 1.0。这个机制能弥补画像采样不足,但仍受候选短语类型、选中表范围和配置开关控制。

【算法逻辑与控制流向】
  1. Input:文本画像记录、问题短语、数据源配置和当前 Schema 选中表。
  2. 如果 VALUE_GROUNDING_DB_LOOKUP_ENABLED 关闭,直接返回空。
  3. 过滤适合查库的短语:日期、纯数字、停用词不参与;引号、大写缩写和标题式短语优先。
  4. 对文本字段构造大小写无关表达式,例如 LOWER(CAST(field AS TEXT))
  5. 执行 SELECT DISTINCT field ... WHERE lower(field)=:lookup_value LIMIT 3
  6. 命中后构造 match_type=db_exactconfidence=1.0 的候选。
  7. Output:可作为强证据的真实数据库等值命中结果。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/value_grounding.py:521 · _db_lookup_text_expr() 构造大小写无关文本表达式。
  • graduation-design/backend/services/value_grounding.py:531 · _normalize_db_lookup_text() 规范化查库短语。
  • graduation-design/backend/services/value_grounding.py:539 · _is_db_lookup_phrase() 判断短语是否适合直接查库。
  • graduation-design/backend/services/value_grounding.py:556 · _lookup_exact_text_values() 执行 DB 等值查找。
  • graduation-design/backend/core/config.py:112:113 · 控制 DB lookup 和全局精确查找范围。
“采样画像像通讯录摘要,db_exact 像临时去数据库查身份证号;样本没覆盖时,它能把确实存在的真实值补回来。”
07

候选去重排序与强证据表判定

Ranking, deduplication and strong tables
Ranking Strong Top-K
【核心概念与设计初衷】

候选召回后需要去重、排序和强证据判定。系统按表、字段、规范化值去重,保留最高置信候选;排序时优先置信度,再考虑值长度和表字段名稳定排序。强证据指 exactdb_exact 且置信度足够高的候选,它们不仅进入 Prompt,还会产生 strong_tables,用于反向补充 Schema 和放宽 SQL Guard 的允许表边界。

【算法逻辑与控制流向】
  1. Input:画像匹配候选和 DB 等值查找候选。
  2. table_name + field_name + normalized(value) 为 key 去重。
  3. 同 key 候选只保留置信度最高的一条。
  4. 按置信度、值长度、表名、字段名排序。
  5. 截断到 VALUE_GROUNDING_MATCH_TOP_K
  6. ChatService 选择 match_type in {exact, db_exact} 且置信度不低于 0.99 的候选所在表作为强证据表。
  7. Output:Top-K 候选列表、列范围画像和强证据表列表。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/value_grounding.py:697:709 · 对候选按表字段和值去重并排序。
  • graduation-design/backend/services/value_grounding.py:704 · 排序 key 优先置信度和值长度。
  • graduation-design/backend/services/value_grounding.py:714 · 返回 Top-K 候选和最多 12 条日期/数值画像。
  • graduation-design/backend/chat/service.py:190 · ValueGroundingPromptArtifacts 保存 Prompt、候选和强证据表。
  • graduation-design/backend/chat/service.py:1235:1243 · ChatService 判定 strong_tables
“强证据不是所有相似值,而是精确命中且高置信的真实值;它会告诉系统这张表可能必须被纳入当前查询边界。”
08

Prompt 片段格式化与 MemoryBroker 注入

Prompt block and context binding
Prompt MemoryBroker XML Block
【核心概念与设计初衷】

Value Grounding 的输出会被格式化为结构化 Prompt 块,而不是散乱自然语言。Prompt 中包含使用说明、候选过滤值、源短语、表字段、真实值、建议谓词和列范围画像。这样模型可以明确知道哪些值来自真实数据库,哪些候选是强证据,哪些日期/数值字段只提供范围提示。

【算法逻辑与控制流向】
  1. Input:候选值列表和日期/数值画像列表。
  2. 如果二者都为空,返回空字符串,主链路继续执行。
  3. 构造 <value-grounding> 根块。
  4. <candidate-filters> 中逐条写入置信度、匹配类型、源短语、表、列、值和建议谓词。
  5. <column-profiles> 中写入日期和数值字段范围。
  6. ChatService 将该文本绑定到 SQLGenerationMemoryBroker
  7. Output:SQL 生成 Prompt 和修复 Prompt 都可复用同一份 value grounding 上下文。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/value_grounding.py:717 · _format_predicate() 构造建议过滤谓词。
  • graduation-design/backend/services/value_grounding.py:726 · format_value_grounding_prompt() 生成 <value-grounding> Prompt 块。
  • graduation-design/backend/chat/service.py:1224 · ChatService 获取 value grounding Prompt 和候选列表。
  • graduation-design/backend/services/memory_broker.py:97 · bind_value_grounding() 将值证据绑定到上下文总线。
  • graduation-design/backend/services/memory_broker.py:184:220 · SQL 生成和修复 Prompt 都携带 value grounding 文本。
“值证据进 Prompt 时不是一句提醒,而是一块结构化清单:原问题短语、真实表字段、真实值和建议 WHERE 谓词都写清楚。”
09

强值证据与 Schema、SQL 计划、校验验证联动

Downstream integration
Schema SQL Plan Verifier
【核心概念与设计初衷】

Value Grounding 的强证据不只影响 Prompt,还会进入下游控制链路。强证据表可反向补充 Schema-RAG 的选中表集合;强值候选可进入 SQL Plan 的过滤条件;SQL Guard 会把强证据表纳入允许边界;语义验证器会检查强候选值是否出现在 SQL 中,并在结果为空时给出风险。这体现了值证据从“生成提示”升级为“计划和验证依据”。

【算法逻辑与控制流向】
  1. Input:ChatService 收集到的 strong_tablesvalue_grounding_candidates
  2. 如果存在强证据表,调用 augment_schema_result_with_tables() 把相关表补进当前 Schema。
  3. 构建 SQL Plan 时,高置信 exact/db_exact 候选转为过滤条件。
  4. SQL Guard 校验表边界时,把强证据表加入允许表集合。
  5. 语义验证阶段检查强候选值是否出现在 SQL 中。
  6. 如果 SQL 执行结果为空且存在强值候选,标记 empty_result_with_grounding 风险。
  7. Output:生成、计划、校验、验证和修复阶段都共享同一份值证据。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/service.py:1562:1578 · 先收集 Value Grounding,再用强证据表补充 Schema。
  • graduation-design/backend/services/schema_retrieval.py:985 · augment_schema_result_with_tables() 将指定表并入 Schema 结果。
  • graduation-design/backend/services/sql_planner.py:308 · _add_value_grounding_filters() 把强候选转为 SQL Plan 过滤条件。
  • graduation-design/backend/services/sql_guard.py:631:636 · Guard 将强证据表纳入允许表集合。
  • graduation-design/backend/services/sql_semantic_verifier.py:168:218:277 · 语义验证器检查缺失强值和空结果风险。
  • graduation-design/tests/test_sql_planner.py:136graduation-design/tests/test_sql_semantic_verifier.py:54graduation-design/tests/test_schema_retrieval_guard.py:238 · 测试覆盖计划、语义验证和 Guard 联动。
“强值证据不是只提醒模型一句话,它会一路影响 Schema 补表、SQL 计划、Guard 允许边界和语义验证。”
10

配置开关、降级策略与能力边界

Configuration, degradation and limits
Config Fallback Boundary
【核心概念与设计初衷】

Value Grounding 是增强能力,不是系统唯一结构来源。它受开关、采样上限、匹配阈值、Top-K、DB lookup 和弱匹配配置控制;当值画像为空、匹配失败或功能关闭时,系统仍依靠 Schema-RAG、术语、样例和 SQL 校验继续执行。其边界也很清楚:它只能证明某个自然语言短语可能对应真实取值,不能替代 Schema-RAG 的表字段召回,也不能保证模型一定采用该候选。

【算法逻辑与控制流向】
  1. Input:系统配置、数据源画像状态和用户问题。
  2. 如果总开关关闭,画像刷新阶段删除旧画像,在线召回返回空。
  3. 画像构建受字段数量、文本 distinct 数、最大值长度限制。
  4. 在线召回受最小置信度、Top-K、DB lookup 和弱匹配开关控制。
  5. 无候选时 Prompt 中不插入 <value-grounding> 块,主链路继续执行。
  6. 候选存在但不强时,只作为提示材料,不触发强证据补表和强验证。
  7. Output:可控、可降级的值证据能力,避免把不确定取值当成硬约束。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/core/config.py:95 · RAG_VALUE_GROUNDING_ENABLED 控制 Value Grounding 总开关。
  • graduation-design/backend/core/config.py:107:114 · 控制画像字段上限、样本数量、最大值长度、Top-K、阈值、DB lookup 和弱匹配。
  • graduation-design/backend/services/value_grounding.py:269 · 关闭总开关时删除旧画像并返回 0。
  • graduation-design/backend/services/value_grounding.py:633 · 问题为空、开关关闭或无画像时返回空候选。
  • graduation-design/backend/services/value_grounding.py:726 · 候选和画像都为空时 Prompt 片段为空。
  • latex/final.tex:451 · 论文说明条件值定位受字段画像和采样影响,不能替代数据库模式检索。
“Value Grounding 是增强证据,不是硬性真理;没有命中时系统还能靠 Schema-RAG 跑,有强命中时才把它升级为更高优先级约束。”

知识增强层:术语、样例、领域记忆、检索证据

本知识域回答系统如何把业务术语、SQL few-shot 样例、长期领域记忆、数据源 evidence 与 Schema 检索证据组织成可追踪 Prompt 上下文,并说明这些知识为什么只作为生成约束,而不能突破真实表字段边界。

01

四类知识的职责边界

Knowledge layer taxonomy
Terminology Few-shot Evidence
【核心概念与设计初衷】

知识增强层是在 Schema-RAG 已经圈定表字段边界之后,为 SQL 生成补充业务语义、查询写法和证据口径的上下文层。它解决的问题不是“数据库里有没有这张表”,而是“用户的业务词是什么意思、类似问题怎么写 SQL、当前数据源有哪些长期规则、Schema 检索为什么命中这些表”。

知识类型 核心作用 不能越过的边界
术语 Terminology 把业务词、缩写、同义表达解释成可理解的业务语义。 不能创造不存在字段。
SQL 样例 Training 提供相似问题的 SQL 写法和结构模式。 全局样例只能参考结构,不能复用表字段名。
Domain Memory 把 evidence、表注释、字段注释、关系说明沉淀为长期可检索片段。 只能解释当前数据源语义,不能替代 Schema-RAG。
Evidence Context / Retrieval Evidence 前者表达业务口径和公式,后者表达检索命中与关系补表依据。 都必须服从真实 schema、值证据和安全规则。
【算法逻辑与控制流向】
  1. Input:用户问题、当前数据源、Schema-RAG 结果、数据源级 evidence、术语库、SQL 样例库和 Domain Memory 片段。
  2. 先分别召回术语、领域记忆和 SQL 样例,保持每类知识的独立来源和日志。
  3. 再把数据源级 evidence 与问题级 evidence 聚合为 Evidence Context,并从术语、样例和 evidence 中提取指标公式提示。
  4. Prompt Builder 根据 Schema ranking 生成 Retrieval Evidence,用于提示 direct-hit 表、relation-expanded 表和高置信 top1 候选。
  5. Output:生成阶段和修复阶段都可复用的结构化上下文块,包含 <terminologies><sql-examples><domain-memory><evidence-context><retrieval-evidence>
【代码精准溯源 (Code Anchor)】
  • latex/final.tex:461 · 论文说明训练样例、经验规则、领域记忆、值证据、数据源证据与检索证据按不同功能进入提示词。
  • graduation-design/backend/services/memory_broker.py:25 · SQLGenerationMemoryBroker 统一收束 schema、术语、样例、Domain Memory、evidence 与值证据。
  • graduation-design/backend/services/prompt_builder.py:883 · build_sql_messages() 把各类上下文填充进 SQL 生成模板。
  • graduation-design/backend/prompts/template.yaml:220 · SQL Prompt 的 <Info> 区按顺序注入 evidence、value grounding、plan、retrieval evidence、术语、领域记忆和样例。
“知识增强层不是把资料一股脑塞给模型,而是把业务词、样例、证据和检索理由分仓入库、按职责注入。”
02

术语库数据模型与作用域

Terminology model and scope
Terminology Alias Scope
【核心概念与设计初衷】

术语库用于维护业务主词、同义词和解释说明,解决自然语言表达与数据库字段命名不一致的问题。例如用户说“复购率”“GMV”“活跃客户”,这些词未必直接出现在表字段中,需要通过术语说明把业务含义提前告诉模型。

【算法逻辑与控制流向】
  1. Input:术语主词 word、同义词 other_words、解释 description、是否限定数据源 specific_datasources、启用状态。
  2. 创建或更新术语时先做归一化、重复校验、数据源权限校验和范围校验。
  3. 持久化后构造 embedding 快照文本,异步或即时刷新术语向量;如果向量不可用,则保留基础术语数据。
  4. 在线问答时只从当前用户可见、已启用且作用域匹配的数据源范围内读取候选术语。
  5. Output:可参与召回的 TerminologyRead 列表,以及后续匹配阶段使用的 embedding 和别名集合。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/terminology/models.py:20 · Terminology 定义主词、说明、同义词、数据源范围、启用状态和 embedding 字段。
  • graduation-design/backend/terminology/service.py:92 · _normalize_words() 清洗主词与同义词。
  • graduation-design/backend/terminology/service.py:148 · _validate_datasource_scope() 校验术语的数据源生效范围。
  • graduation-design/backend/terminology/service.py:309 · _build_terminology_embedding_snapshot() 构造术语向量快照。
  • graduation-design/backend/terminology/service.py:383 · _refresh_terminology_embeddings() 刷新术语别名向量。
“术语库就是系统的业务词典,把用户嘴里的行话翻译成模型能遵守的业务解释。”
03

术语混合召回与 Prompt 注入

Terminology hybrid retrieval
Hybrid Retrieval XML Prompt
【核心概念与设计初衷】

术语召回采用关键词与 embedding 混合排序。关键词匹配能稳定命中完全相同的业务词和别名,embedding 匹配能覆盖近义表达;两者结合可以降低中文业务问法、缩写和别名带来的漏召回。

【算法逻辑与控制流向】
  1. Input:当前问题、当前用户、可选数据源 ID。
  2. 读取候选术语,过滤未启用、无权限或数据源作用域不匹配的记录。
  3. 对问题和术语主词/别名计算关键词分数,包含紧凑文本完全匹配、包含关系和词元重合。
  4. 当术语向量可用且快照新鲜时,生成问题向量并计算与每个术语别名向量的最大相似度。
  5. 根据配置决定是否允许纯关键词兜底;若 embedding 与关键词都无分数,则丢弃。
  6. RAG_HYBRID_EMBEDDING_WEIGHT 合成最终分数,取 Top-N。
  7. Output:<terminologies> XML 块,每个 <terminology> 包含主词、别名和 description。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/terminology/service.py:263 · _list_matchable_terminology_records() 读取可匹配术语。
  • graduation-design/backend/terminology/service.py:483 · _score_terminology_keyword() 计算术语关键词得分。
  • graduation-design/backend/terminology/service.py:511 · _score_terminology_embedding() 计算问题向量与术语别名向量相似度。
  • graduation-design/backend/terminology/service.py:908 · _build_prompt_text() 输出 <terminologies> Prompt 块。
  • graduation-design/backend/terminology/service.py:937 · match_terminologies() 完成混合召回、排序和截断。
  • graduation-design/backend/chat/service.py:1136 · _collect_terminology_prompt_stage() 在线问答阶段收集术语并发送 terminology_ready 事件。
“术语召回既看字面有没有撞上,也看语义像不像,最后只把最相关的业务解释塞进 Prompt。”
04

SQL 样例库契约与全局样例约束

SQL examples and scope rules
Few-shot Training Pattern Only
【核心概念与设计初衷】

SQL 样例库以“自然语言问题 - 推荐 SQL 写法”的形式保存少样本示例,用来让模型参考相似问题的查询结构、聚合方式、JOIN 写法和时间粒度。它解决的是“同类问题通常怎么写 SQL”的问题,而不是替代当前 Schema 判断。

样例范围 注入语义 答辩重点
datasource 绑定当前数据源,可参考具体表字段和 SQL 写法。 适合沉淀本库常见查询。
global 跨库通用样例,只允许参考 SQL 结构。 模板中明确 pattern_only,不得复用表字段名。
【算法逻辑与控制流向】
  1. Input:样例范围 scope、可选数据源 ID、样例问题 question、样例 SQL 或说明 description、启用状态。
  2. 保存时校验同一用户、同一范围下的问题重复,避免同义样例污染排序。
  3. 数据源级样例绑定具体库;全局样例不绑定数据源,只作为通用 SQL 结构模式。
  4. 构造 embedding 文本时只使用样例问题,降低把旧 SQL 字段名带入相似度计算的风险。
  5. Output:召回时可注入的 <sql-examples> 块;全局样例额外带有“不得复用表名和字段名”的约束。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/training/models.py:31 · TrainingScope 定义 datasourceglobal 两类样例范围。
  • graduation-design/backend/training/models.py:40 · DataTraining 定义样例问题、SQL 描述、作用域、启用状态和 embedding 字段。
  • graduation-design/backend/training/service.py:170 · _list_matchable_training_records() 根据用户、数据源和全局样例配置读取候选。
  • graduation-design/backend/training/service.py:196 · _build_training_embedding_text() 只用样例问题构建向量文本。
  • graduation-design/backend/training/service.py:1008 · _build_prompt_text() 输出 <sql-examples>,全局样例写入 pattern_only 约束。
“SQL 样例是写法参考,不是复制粘贴;全局样例只能学结构,不能拿别的库表字段来用。”
05

SQL 样例混合召回与截断策略

Few-shot retrieval and selection
Hybrid Retrieval Top-K
【核心概念与设计初衷】

样例召回用于从 SQL 样例库中挑选最像当前问题的 few-shot 示例。它既需要命中当前数据源的高相关样例,也允许少量全局结构样例参与,但必须通过数量上限控制 Prompt 长度,防止样例过多反而干扰当前 Schema。

【算法逻辑与控制流向】
  1. Input:用户问题、当前用户、当前数据源 ID、召回上限。
  2. 读取启用样例;当允许全局样例时,候选包含当前数据源样例与全局样例。
  3. 计算关键词分数:问题完全相同加高分,包含关系加分,词元重合加分。
  4. 如果样例 embedding 可用,则计算问题向量与样例问题向量的相似度,并按阈值过滤。
  5. 按 embedding 与关键词混合分排序后,先优先选择当前数据源样例,再按 CHAT_SQL_GLOBAL_EXAMPLE_LIMIT 补充少量全局样例。
  6. Output:Top-K TrainingRead<sql-examples> Prompt 片段。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/training/service.py:963 · _score_training_match() 计算样例关键词匹配分。
  • graduation-design/backend/training/service.py:217 · _refresh_training_embeddings() 批量刷新样例向量。
  • graduation-design/backend/training/service.py:1032 · _select_ranked_training_items() 控制数据源样例与全局样例的比例。
  • graduation-design/backend/training/service.py:1073 · match_trainings() 完成混合召回、排序、截断与 Prompt 构造。
  • graduation-design/backend/chat/service.py:1323 · _collect_training_prompt_stage() 在主链路中收集 SQL 样例并发送 training_ready 事件。
“样例召回像找参考答案:优先找同一套题里的相似题,再少量参考通用解题套路。”
06

Domain Memory 片段构建与刷新

Long-term business memory
Domain Memory Snippet Refresh
【核心概念与设计初衷】

Domain Memory 是数据源级长期业务记忆,把 evidence、表说明、字段说明和显式表关系转成统一的文档片段。它的设计初衷是避免在线问答时临时拼接散乱元数据,而是在数据源同步或 evidence 维护后提前构建可检索、可排序、可追踪的业务知识资产。

【算法逻辑与控制流向】
  1. Input:当前数据源、已维护的 datasource evidence、表元数据、字段元数据和表关系 JSON。
  2. 把每条 evidence 转为 source_kind=evidence 片段,保留标题、正文、启用状态和排序。
  3. 把有业务注释的表转为 source_kind=table 片段,未启用表不参与在线检索。
  4. 把有业务注释的字段转为 source_kind=field 片段,并要求字段和所属表都处于 checked 状态。
  5. 解析显式关系边,生成 source_kind=relation 片段,用自然语言描述 JOIN 关系。
  6. 删除当前数据源旧片段,重新写入新片段,并为启用片段生成 embedding;向量不可用时保留文本快照并跳过向量构建。
  7. Output:持久化的 DomainMemorySnippet 集合,供在线问答阶段检索。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/datasource/models.py:52 · DomainMemorySourceKind 定义 evidence、table、field、relation 四类来源。
  • graduation-design/backend/datasource/models.py:234 · DomainMemorySnippet 定义长期记忆片段持久化模型。
  • graduation-design/backend/services/domain_memory_service.py:61 · _load_relation_edge_snippets() 将显式表关系转换为记忆片段。
  • graduation-design/backend/services/domain_memory_service.py:128 · build_domain_memory_snippets() 汇总 evidence、表、字段和关系片段。
  • graduation-design/backend/services/domain_memory_service.py:217 · refresh_domain_memory_snippets() 删除旧片段、写入新片段并刷新 embedding。
  • graduation-design/backend/datasource/service.py:119 · _refresh_datasource_domain_memory() 在数据源同步和 evidence 保存后触发刷新。
“Domain Memory 就是把数据源里的长期业务说明提前做成可检索小纸条,问答时按需取用。”
07

Domain Memory 混合检索与来源优先级

Memory ranking and prompt budget
Ranking Char Budget
【核心概念与设计初衷】

Domain Memory 检索负责在长期片段中找出与当前问题相关的业务说明。它与术语召回类似采用 embedding + keyword hybrid,但额外引入来源优先级:evidence 片段通常比普通字段注释更接近业务口径,因此排序时给予更高权重。

【算法逻辑与控制流向】
  1. Input:当前数据源 ID、用户问题、可选召回上限。
  2. 读取当前数据源下启用的 Domain Memory 片段。
  3. 用标题词元交集和正文词元交集计算关键词分,标题命中权重更高。
  4. 若 Domain Memory 向量可用,则计算问题向量与片段向量相似度,并用阈值筛选。
  5. 按混合分排序,并叠加来源优先级:evidence 高于 relation,relation 高于 table,table 高于 field。
  6. 按 Top-N 截断,并在构造 Prompt 时用字符预算控制 <domain-memory> 长度。
  7. Output:匹配片段、ranking 日志和 <domain-memory> Prompt 块。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/domain_memory_retrieval.py:31 · _KIND_PRIORITY 定义 evidence、relation、table、field 的排序加权。
  • graduation-design/backend/services/domain_memory_retrieval.py:37 · _CHAR_BUDGET 控制 Domain Memory Prompt 字符预算。
  • graduation-design/backend/services/domain_memory_retrieval.py:68 · _build_prompt_text() 构造 <domain-memory> Prompt 块。
  • graduation-design/backend/services/domain_memory_retrieval.py:91 · match_domain_memory() 完成片段检索、混合排序和 ranking 输出。
  • graduation-design/backend/chat/service.py:1271 · _collect_domain_memory_prompt_stage() 在线问答阶段收集 Domain Memory 并写入日志。
“Domain Memory 检索不是全文搜索大杂烩,它会优先相信更像业务规则的片段,再受 Prompt 长度预算约束。”
08

Evidence Context 与指标公式提示

Evidence aggregation and formula hints
Evidence Formula Priority
【核心概念与设计初衷】

Evidence Context 统一处理数据源级 evidence、问题级临时 evidence,以及从术语和样例中提取出的公式线索。它的核心价值是显式表达业务口径和指标公式,并规定优先级:问题级 evidence 可优先于数据源级 evidence,但不能违反当前 schema 和真实字段语义。

【算法逻辑与控制流向】
  1. Input:启用的数据源 evidence、用户本轮问题级 evidence、术语 Prompt、样例 Prompt、命中术语列表和命中样例列表。
  2. 先把问题级 evidence 规范化;如果存在,就作为最高优先级临时补充写入 <question-evidence>
  3. 再把数据源级 evidence 按顺序写入 <datasource-evidence>,每条保留 kind、title 和 content。
  4. 从问题 evidence、数据源 evidence、术语说明、样例答案和命中样例描述中收集公式来源文本。
  5. 调用公式抽取函数提取 metric_formula_hints,并去重保序。
  6. Output:EvidenceContext(prompt_block, metric_formula_hints, datasource_evidence_count, question_evidence_present)
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/datasource/models.py:36 · DatasourceEvidenceKind 定义 formula、enum_mapping、time_rule、business_rule 等 evidence 类型。
  • graduation-design/backend/services/evidence_service.py:23 · EvidenceContext 定义统一证据聚合结果。
  • graduation-design/backend/services/evidence_service.py:64 · _collect_formula_hint_sources() 汇总可抽取公式的文本来源。
  • graduation-design/backend/services/evidence_service.py:108 · _build_evidence_prompt_block() 构造带优先级说明的 <evidence-context>
  • graduation-design/backend/services/evidence_service.py:144 · build_evidence_context() 返回 Prompt 块与指标公式提示。
  • graduation-design/backend/services/prompt_builder.py:364 · extract_metric_formula_hints() 提取指标公式线索。
“Evidence Context 像答题口径说明书:先看本题临时说明,再看数据源长期规则,但都不能越过真实字段。”
09

Retrieval Evidence:Schema 检索证据注入

Retrieval evidence prompt
Schema Evidence Top1 Preference
【核心概念与设计初衷】

Retrieval Evidence 是 Schema-RAG 排序结果的轻量解释层。它把直接命中的表、关系补入的表、字段级 grounding 线索和高置信候选主表写入 Prompt,使模型知道“为什么这些表被召回”。但它采用保守注入策略,明确说明 direct-hit 只是候选,不是硬性表选择。

【算法逻辑与控制流向】
  1. Input:Schema-RAG 输出的 retrieved_tablesrelation_tables 和 ranking 明细。
  2. 若检索证据开关关闭,或三类输入均为空,则返回空块。
  3. 按配置 Top-K 过滤 ranking,优先保留 direct-hit 表对应的排名证据。
  4. 为每个候选表输出表名、最终分数、grounding fields 和 grounding tags。
  5. 只有 top1 分数达到阈值、领先第二名足够明显、且包含强 grounding 标签时,才输出 <top1-preference>
  6. Output:<retrieval-evidence> 块,包含 usage guidance、direct-hit-tables、relation-expanded-tables、top1 preference 和 top-ranking。
【代码精准溯源 (Code Anchor)】
  • latex/final.tex:488 · 论文说明 Retrieval Evidence 显式写入检索来源和结构命中线索,且采用保守注入。
  • graduation-design/backend/services/prompt_builder.py:607 · _build_retrieval_evidence() 构造检索证据 Prompt 块。
  • graduation-design/backend/services/prompt_builder.py:579 · _should_emit_top1_preference() 判断是否输出高置信 top1 表偏好。
  • graduation-design/backend/services/prompt_builder.py:20 · _RETRIEVAL_EVIDENCE_TOP1_MIN_LEAD_RETRIEVAL_EVIDENCE_TOP1_MIN_SCORE 和强 grounding 标签集合定义保守阈值。
  • graduation-design/tests/test_retrieval_evidence_prompt.py:13 · 检索证据 Prompt 的单元测试覆盖 direct-hit、top1 preference 和保守降级。
“Retrieval Evidence 不是让模型盲信第一名,而是把检索为什么选这些表讲清楚,并提醒它还要结合 schema、值证据和 JOIN。”
10

MemoryBroker 统一编排与修复复用

Context broker orchestration
MemoryBroker Prompt Context Repair
【核心概念与设计初衷】

MemoryBroker 是 SQL 生成链路中的上下文编排器,负责把分散收集到的 schema、术语、Domain Memory、样例、Evidence Context、Value Grounding、历史上下文、问题分解和 SQL Plan 收束成统一对象。它的关键设计是生成阶段与修复阶段复用同一批领域知识,修复时只允许替换为更聚焦的 schema,避免口径漂移。

【算法逻辑与控制流向】
  1. Input:有效问题、问题级 evidence、Schema-RAG 结果、术语召回结果、Domain Memory 结果、样例结果和数据源 evidence。
  2. 主链路按阶段调用 bind_schema()bind_value_grounding()bind_terminology()bind_domain_memory()bind_training()
  3. 样例阶段之后调用 build_evidence(),因为公式提示需要汇总术语、样例和数据源 evidence。
  4. 生成前调用 build_sql_prompt_context(),输出 SQLPromptContext 给 Prompt Builder。
  5. 修复时调用 build_sql_repair_prompt_context(),复用术语、样例、evidence、值证据和计划,只替换 focused schema 与 previous SQL / error。
  6. Output:生成与修复两类 Prompt Context,供模型调用、日志记录和后续诊断复用。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/memory_broker.py:61 · bind_terminology() 绑定术语 Prompt 与命中项。
  • graduation-design/backend/services/memory_broker.py:73 · bind_domain_memory() 绑定领域记忆 Prompt 与命中片段。
  • graduation-design/backend/services/memory_broker.py:85 · bind_training() 绑定 SQL 样例 Prompt 与命中样例。
  • graduation-design/backend/services/memory_broker.py:104 · build_evidence() 汇总数据源 evidence、问题 evidence、术语和样例。
  • graduation-design/backend/services/memory_broker.py:162 · build_sql_prompt_context() 构建首次生成上下文。
  • graduation-design/backend/services/memory_broker.py:195 · build_sql_repair_prompt_context() 构建修复上下文并复用知识增强材料。
  • graduation-design/backend/chat/service.py:1592 · 主链路按术语、Domain Memory、样例顺序收集知识增强材料。
“MemoryBroker 像装配台:各增强模块各自产出零件,最后由它统一装成生成和修复都能复用的上下文。”
11

配置开关、降级策略与成本边界

Feature flags and fallback
Config Fallback Cost
【核心概念与设计初衷】

知识增强层是可配置增强能力,不是主链路的硬依赖。系统通过术语、样例、Domain Memory、全局样例、检索证据和关键词兜底开关控制触发范围,并用 Top-K 与字符预算限制 Prompt 成本。这样可以在增强收益与 token、时延、噪声之间保持工程平衡。

【算法逻辑与控制流向】
  1. Input:系统配置、embedding 服务可用性、当前数据源知识资产是否已构建。
  2. 若术语、样例或 Domain Memory 检索开关关闭,对应模块返回空块,不阻断 Schema-RAG 与 SQL 生成。
  3. 若 embedding 不可用,且 RAG_KEYWORD_FALLBACK_ENABLED 开启,则保留关键词召回;否则仅使用可用向量结果。
  4. EMBEDDING_TERMINOLOGY_TOP_COUNTEMBEDDING_TRAINING_TOP_COUNTEMBEDDING_DOMAIN_MEMORY_TOP_COUNTCHAT_PROMPT_RETRIEVAL_EVIDENCE_TOP_K 控制注入规模。
  5. Domain Memory 还用字符预算二次裁剪,避免长期知识片段拖长 Prompt。
  6. Output:命中则增强 Prompt;未命中、关闭或失败则对应块为空,主链路继续执行并记录日志。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/core/config.py:95:104 · 术语、样例、Domain Memory、Value Grounding、关键词兜底等 RAG 开关。
  • graduation-design/backend/core/config.py:106:112 · 术语、样例和 Domain Memory 的相似度阈值与 Top-K 上限。
  • graduation-design/backend/core/config.py:133 · CHAT_SQL_GLOBAL_EXAMPLE_LIMIT 控制全局样例进入数量。
  • graduation-design/backend/core/config.py:145 · CHAT_PROMPT_RETRIEVAL_EVIDENCE_ENABLED 控制检索证据注入。
  • latex/final.tex:461 · 论文说明各类知识先分别召回和过滤,再由记忆编排模块绑定,未命中时不阻断主流程。
  • latex/final.tex:1208 · 论文指出完整配置的额外开销主要来自术语、样例、经验规则、值证据、检索证据和 SQL 计划等生成前证据。
“知识增强能帮复杂问题补语义,但它有开关、有 Top-K、有降级,避免为了多给知识反而把模型带偏。”

复杂问题增强:问题改写、问题分解、SQL Experience

本知识域回答系统如何处理多轮追问、省略指代、复杂推理口径和历史错误经验,并说明这些增强策略如何进入生成前 Prompt、修复阶段 Prompt 与经验沉淀闭环。

01

复杂问题增强层的定位与边界

Complex enhancement boundary
Rewrite Decompose Experience
【核心概念与设计初衷】

复杂问题增强层位于基础 Schema-RAG 之后、SQL 生成之前和修复阶段之中。它不负责直接执行 SQL,也不替代 Schema-RAG 的表字段边界,而是针对多轮追问、省略指代、多步聚合、时间粒度、Top-N 语义和历史错误模式补充约束,让模型不再完全依赖一次性自由生成。

增强能力 解决的核心痛点 输出形态
问题改写 多轮追问中的省略、指代、继承时间范围或指标。 有效问题 effective_question
问题分解 月均、比例、先聚合后筛选、目标输出列形态等复杂推理。 <question-decomposition> 结构化提示。
SQL Experience 历史错误中反复出现的聚合、JOIN、LIMIT、Schema 对齐问题。 <sql-generation-experience><sql-repair-experience>
【算法逻辑与控制流向】
  1. Input:原始问题、历史问答、历史成功 SQL、Schema-RAG 结果、知识增强材料、执行错误信息。
  2. 若存在历史上下文且改写开启,先把当前追问改写成自包含问题。
  3. 用有效问题进入数据源选择、Schema-RAG、Value Grounding、术语、Domain Memory 和 SQL 样例召回。
  4. 在生成前识别复杂问题风险,必要时生成问题分解或本地 planning hints。
  5. 同时从 SQL Experience 规则库检索当前问题相关经验,拼接进 SQL 样例上下文。
  6. 若后续 Guard、执行或语义验证进入修复分支,则按错误信息重新检索 repair 阶段经验规则。
  7. Output:更完整的有效问题、更明确的推理约束、可复用的历史错误规则。
【代码精准溯源 (Code Anchor)】
  • latex/final.tex:466 · 第 3 章“复杂问题增强机制设计”小节。
  • latex/final.tex:635 · 智能问答主链路算法说明问题改写、证据组织、问题分解和 SQL 计划的执行顺序。
  • graduation-design/backend/chat/service.py:2137 · stream_chat() 先执行问题改写,再进入数据源、Prompt 资产收集、SQL 生成和修复闭环。
  • graduation-design/backend/chat/service.py:1546 · _collect_stream_prompt_artifacts() 汇总 Schema、值证据、术语、样例、分解和计划。
  • graduation-design/backend/core/config.py:116:132 · 复杂增强相关配置开关和预算。
“复杂问题增强层不是另起炉灶生成 SQL,而是在基础 Schema 边界上补上下文、推理步骤和历史错误约束。”
02

多轮问题改写与自包含问题生成

Question rewrite and follow-up resolution
Multi-turn effective_question
【核心概念与设计初衷】

问题改写器用于把多轮追问补全为一个自包含问题。它借鉴 Vanna 的追问合并思想,但扩展为可读取多轮历史,并额外带上上一轮成功 SQL,帮助模型理解“上一轮实际查了什么”,从而处理“那去年呢”“按地区分一下”“只看已支付的”这类省略问题。

【算法逻辑与控制流向】
  1. Input:当前原始问题 current_question、历史成功问答对 history_pairs、LLM 客户端。
  2. 先做短路判断:改写关闭、空问题、无历史、无模型客户端时直接跳过。
  3. 把历史问题和历史 SQL 格式化为 <history-item>,与当前问题共同构造重写 Prompt。
  4. temperature=0.0 调用模型,要求只输出最终问题文本,不输出解释。
  5. 清洗模型输出:去掉 Markdown 代码块、JSON 包裹、中文前缀和多行解释。
  6. 如果输出为空、与原问题一致或异常过长,则不应用改写。
  7. Output:QuestionRewriteResult,其中 effective_question 是后续链路真正使用的问题。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/question_rewriter.py:50 · QuestionRewriteResult 定义原问题、有效问题、改写结果、跳过原因和 token 用量。
  • graduation-design/backend/services/question_rewriter.py:97 · _normalize_rewritten_question() 清洗模型输出。
  • graduation-design/backend/services/question_rewriter.py:140 · rewrite_question() 实现短路、模型调用、失败回退和异常长度保护。
  • graduation-design/backend/services/prompt_builder.py:1091 · _format_history_pairs() 将历史问题和历史 SQL 格式化为 XML 风格上下文。
  • graduation-design/backend/services/prompt_builder.py:1117 · build_question_rewrite_messages() 构建问题改写 Prompt。
“问题改写就是把‘那这个呢’翻译成完整题目,让后面的 Schema 检索和 SQL 生成不猜上下文。”
03

有效问题在主链路中的传播

Effective question propagation
ChatService SSE Trace
【核心概念与设计初衷】

effective_question 是当前轮问答在后续检索、证据召回、SQL 生成和经验沉淀中使用的统一问题文本。设计上保留原始问题与有效问题两份数据:前者用于用户可见和审计,后者用于让后端所有增强模块在一致语义上工作。

【算法逻辑与控制流向】
  1. Input:ChatStreamRuntime,其中初始 effective_question=payload.question.strip()
  2. 创建 ChatRecord 后,ChatService 进入 _rewrite_question_stage()
  3. 阶段日志记录原问题、历史问答、配置开关和模型输出。
  4. rewrite_result.effective_question 回写到 runtime。
  5. 向前端发送 question_rewritten SSE 事件,包含 applied、skip_reason 和 rewritten_question。
  6. 后续数据源选择、Schema-RAG、Value Grounding、术语、样例、分解、计划、SQL Experience 和候选经验沉淀都使用该有效问题。
  7. Output:可追踪的原问题/有效问题双账本,支持答辩解释多轮语境如何进入 SQL 生成。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/service.py:877 · _create_stream_runtime() 初始化 effective_question
  • graduation-design/backend/chat/service.py:922 · _rewrite_question_stage() 执行问题改写并记录日志。
  • graduation-design/backend/chat/service.py:964 · 将改写后的 effective_question 写回 runtime。
  • graduation-design/backend/chat/service.py:979 · 发送 question_rewritten SSE 事件。
  • graduation-design/backend/chat/service.py:2206 · 成功问答沉淀经验候选时也使用 runtime.effective_question
“原始问题负责还原用户怎么问,有效问题负责让系统按完整语义去检索、生成和复盘。”
04

问题分解的结构化输出契约

Decomposition payload contract
Structured Output Planning Hints
【核心概念与设计初衷】

问题分解不是让模型先写一段 SQL,而是让系统在 SQL 生成前显式表达复杂推理风险和最终答案形态。它把“是否需要分解、按什么顺序推理、最终返回几列、有哪些风险点”变成结构化字段,供后续生成和修复阶段共同遵守。

字段 含义 答辩说法
mode directdecompose 决定是否显式提示多步推理。
sub_questions 按推理顺序排列的子问题 约束 SQL 的中间逻辑顺序。
answer_shape_type 单值、实体列、时间键、单行多指标等 防止 SELECT 列形态跑偏。
risk_flags / planning_hints 风险标签与生成提示 把月均、比例、先聚合后排序等风险显式化。
【算法逻辑与控制流向】
  1. Input:有效问题、聚焦 Schema、历史上下文、术语、样例、Evidence Context、指标公式提示和检索证据。
  2. 分解服务先判断问题是否具备复杂风险信号。
  3. 若需要调用模型,则要求模型返回放在 <json-response> 内的结构化 JSON。
  4. 系统解析为 QuestionDecompositionPayload,并校验枚举值和字段类型。
  5. 对子问题、风险标签和 planning hints 进行去重、截断和清洗。
  6. 若 mode 为 decompose 但没有有效子问题,则回退为 direct。
  7. Output:QuestionDecompositionResult 和格式化后的 <question-decomposition> Prompt 块。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/question_decomposer.py:44 · QuestionDecompositionPayload 定义结构化输出字段。
  • graduation-design/backend/services/question_decomposer.py:72 · QuestionDecompositionResult 定义运行结果、跳过原因、模型调用和 token 用量。
  • graduation-design/backend/services/question_decomposer.py:119:154 · 对子问题、风险标签和提示列表进行规范化。
  • graduation-design/backend/services/question_decomposer.py:304 · _normalize_payload() 清洗模型结构化输出。
  • graduation-design/backend/services/prompt_builder.py:322 · format_question_decomposition() 输出 XML 风格提示块。
“问题分解的重点不是把题拆得更长,而是把最终 SQL 必须遵守的推理顺序和返回形态写清楚。”
05

问题分解触发、白名单与本地启发式

Heuristic trigger and whitelist
Risk Flags Whitelist Fallback
【核心概念与设计初衷】

当前实现对问题分解采用保守策略:先用本地正则和关键词识别复杂风险,再通过白名单控制真正注入的题型。这样做的原因是分解并非所有问题都有收益,简单问题上额外推理可能改变输出粒度;因此系统更偏向只在高风险题型上触发。

【算法逻辑与控制流向】
  1. Input:有效问题文本和已有指标公式提示。
  2. should_trigger_question_decomposition() 扫描月均、年均、比例、差值、极值、先聚合后比较、时间粒度和多子句等风险。
  3. 若没有风险标签,则返回 heuristic_not_triggered
  4. should_allow_question_decomposition() 进一步执行白名单判断;当前高置信允许路径主要是 monthly_average
  5. 若 evidence 已经明确覆盖月均公式,则跳过分解,避免重复注入同类约束。
  6. 若命中月均白名单且未被公式覆盖,则不额外调用 LLM,直接构造本地 planning hints。
  7. Output:保守的 decomposition 结果;未触发或未允许时记录 skip_reason,主链路继续直接生成。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/question_decomposer.py:172 · _build_heuristic_hints() 根据风险标签生成 SQL 规划提示。
  • graduation-design/backend/services/question_decomposer.py:223 · _infer_heuristic_answer_shape_type() 推断最终答案形态。
  • graduation-design/backend/services/question_decomposer.py:266 · _build_heuristic_decomposition_result() 构造无需 LLM 的本地分解结果。
  • graduation-design/backend/services/question_decomposer.py:292 · _monthly_formula_covered_by_evidence() 避免月均公式重复注入。
  • graduation-design/backend/services/question_decomposer.py:331 · should_trigger_question_decomposition() 识别复杂风险标签。
  • graduation-design/backend/services/question_decomposer.py:379 · should_allow_question_decomposition() 执行题型白名单。
  • graduation-design/tests/test_question_decomposition.py:186 · 覆盖月均题型无需 LLM 的启发式结果。
“问题分解不是越多越好,当前实现只在风险足够明确时给提示,避免简单题被过度规划带偏。”
06

分解结果如何进入生成与修复 Prompt

Decomposition prompt injection
Prompt Generation Repair
【核心概念与设计初衷】

分解结果进入 Prompt 后,主要约束 SQL 生成的推理顺序、风险口径和 SELECT 列形态。生成阶段用它避免遗漏中间聚合或错误输出列;修复阶段继续复用它,避免修复 SQL 虽然能执行但背离原始复杂问题的答案形态。

【算法逻辑与控制流向】
  1. Input:分解结果、MemoryBroker、SQL Prompt Context 或 Repair Prompt Context。
  2. ChatService 在术语、Domain Memory、样例和 evidence 收集后执行分解,因为分解需要这些上下文判断公式和口径。
  3. decomposition_result.applied 为真,则格式化为 <question-decomposition>;否则向后传空块。
  4. MemoryBroker 通过 bind_question_decomposition() 绑定该块。
  5. Prompt Builder 在 SQL 生成模板和 SQL 修复模板中都注入 {question_decomposition}
  6. 模板规则要求 answer-shape、planning-hints 和 risk-flags 作为强约束参与 SQL 生成/修复。
  7. Output:生成和修复共用的复杂问题推理提示。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/service.py:1406 · _collect_decomposition_prompt_stage() 负责收集分解提示。
  • graduation-design/backend/chat/service.py:1464 · 将分解结果格式化为 <question-decomposition>
  • graduation-design/backend/chat/service.py:1601 · 主链路在知识增强后、SQL Plan 前执行问题分解。
  • graduation-design/backend/chat/service.py:1630 · memory_broker.bind_question_decomposition() 绑定分解提示。
  • graduation-design/backend/services/memory_broker.py:136 · MemoryBroker 保存 question_decomposition_text
  • graduation-design/backend/prompts/template.yaml:220 · SQL 生成模板在 <Info> 中注入 {question_decomposition}
  • graduation-design/backend/prompts/template.yaml:270 · SQL 修复模板同样约束 answer-shape 与 planning-hints。
“分解结果不是单独跑一条 SQL,而是作为路线图贴进生成和修复 Prompt,提醒模型按正确步骤走。”
07

SQL Experience 规则库数据契约

Experience rule library
Rule Library Error Memory
【核心概念与设计初衷】

SQL Experience 是从历史错误归纳出的抽象规则库,来源不是某条具体 SQL 的直接复用,而是把常见错误模式转成可解释的生成约束。例如默认 LIMIT 与 Top-N 混淆、聚合函数遗漏、JOIN 路径错误、字段名和业务名错配等,都可以沉淀为规则提示。

规则字段 含义 用途
rule_id / rule 规则唯一标识与自然语言约束文本 最终注入 Prompt 的核心内容。
primary_category / categories 主错误类型与相关错误类型 用于意图过滤、排序和类别限额。
keywords / weight 触发关键词与基础权重 用于检索打分。
source_count / error_types 规则来源样本数量与错误分布 用于提升高频经验的排序稳定性。
【算法逻辑与控制流向】
  1. Input:配置中的 JSONL 规则文件路径。
  2. 按行读取规则,解析 JSON,过滤缺失 rule_idrule 的无效记录。
  3. 清洗 categories、primary_category、keywords、weight、source_count 和 error_types。
  4. 如果 primary_category 不在 categories 中,则插入为第一类。
  5. 使用文件路径和 mtime 做缓存,避免每轮问答重复加载规则文件。
  6. Output:SQLExperienceRule 列表,供生成阶段和修复阶段按需检索。
【代码精准溯源 (Code Anchor)】
  • latex/final.tex:484 · 论文说明 SQL Experience 来源于历史错误归纳,并作为生成前错误边界。
  • graduation-design/backend/services/sql_experience_service.py:1 · 文件说明强调使用抽象规则、不引入向量检索依赖。
  • graduation-design/backend/services/sql_experience_service.py:379 · SQLExperienceRule 定义规则字段契约。
  • graduation-design/backend/services/sql_experience_service.py:395 · SQLExperienceMatch 定义命中结果与打分原因。
  • graduation-design/backend/services/sql_experience_service.py:517 · _rule_path() 解析规则库路径。
  • graduation-design/backend/services/sql_experience_service.py:521 · _load_rule_library() 加载、清洗并缓存 JSONL 规则库。
“SQL Experience 不是记住某道题答案,而是把踩坑经验抽象成生成 SQL 前的自检规则。”
08

SQL Experience 检索评分与过滤

Experience retrieval scoring
Scoring Intent Filter Schema Filter
【核心概念与设计初衷】

SQL Experience 检索使用可解释规则打分,而不是向量召回。这样每条规则为什么命中都能记录为 reasons,并且可以结合问题意图、Schema 信号和错误信息做更可控的过滤,避免把无关经验规则塞进 Prompt。

【算法逻辑与控制流向】
  1. Input:有效问题、SchemaRetrievalResult、可选错误信息、阶段 generationrepair
  2. 从问题文本、Schema 结果和错误信息中识别 category 分数,如 aggregation、join_path、ordering_limit、schema_linking、execution。
  3. 提取问题词元、Schema 词元、交集词元、字段特征和大写字面值。
  4. 若开启 intent filter,则只保留规则类别与强意图类别相交的规则;修复阶段会额外偏向 execution 类。
  5. 若开启 schema filter,则要求规则词元与问题 Schema 交集、Schema 特征或通用复杂意图至少命中一类。
  6. 打分时累加基础权重、主类别加分、附加类别加分、关键词命中、意图/Schema 加分、修复阶段 execution 加分和 source_count 加分。
  7. 排序后去重,并在过滤开启时执行主类别限额,最后截断 Top-K。
  8. Output:带 score 和 reasons 的 SQLExperienceMatch 列表。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/sql_experience_service.py:578 · detect_sql_experience_categories() 从问题、Schema 和错误信息识别风险类别。
  • graduation-design/backend/services/sql_experience_service.py:638 · _extract_schema_terms_and_features() 提取表字段词元和 Schema 特征。
  • graduation-design/backend/services/sql_experience_service.py:696 · _build_retrieval_context() 汇总检索上下文。
  • graduation-design/backend/services/sql_experience_service.py:764 · _filter_rule() 执行意图过滤和 Schema 过滤。
  • graduation-design/backend/services/sql_experience_service.py:803 · _score_rule() 生成分数和命中原因。
  • graduation-design/backend/services/sql_experience_service.py:883 · retrieve_sql_experience_rules() 完成加载、过滤、排序、去重和 Top-K 截断。
  • graduation-design/tests/test_sql_experience_service.py:72 · SQL Experience 检索和 Prompt 注入的单元测试入口。
“经验规则检索是可解释打分:先判断这题像哪类坑,再看当前 Schema 是否支持这条经验。”
09

SQL Experience 在生成与修复阶段的注入

Generation and repair experience injection
Generation Repair Prompt Budget
【核心概念与设计初衷】

SQL Experience 有两个注入位置:首次生成阶段用于提前规避已知错误,修复阶段用于结合具体错误信息给模型更精准的修复约束。两者使用不同标签,便于模型区分“生成前自检规则”和“失败后修复经验”。

【算法逻辑与控制流向】
  1. Input:当前有效问题、Schema 结果、可选错误信息、阶段名。
  2. 生成阶段在 SQL 样例收集阶段调用 get_sql_experience_prompt_block(..., phase="generation")
  3. 将 SQL 样例 Prompt 与经验规则 Prompt 拼接为 combined_training_prompt,再绑定到 MemoryBroker。
  4. 格式化时按字符预算裁剪,输出 <sql-generation-experience>
  5. 修复阶段先构造 focused schema,再以错误信息和 repair phase 重新检索规则。
  6. 若有 repair 经验块,则追加到修复 Prompt 的 data_training
  7. Output:首次生成和修复各自阶段感知的历史错误约束。
【代码精准溯源 (Code Anchor)】
  • latex/final.tex:486 · 论文说明经验规则主要进入首次生成和修复两个阶段。
  • graduation-design/backend/services/sql_experience_service.py:956 · format_sql_experience_prompt() 根据 phase 输出 sql-generation-experiencesql-repair-experience
  • graduation-design/backend/services/sql_experience_service.py:994 · get_sql_experience_prompt_block() 返回 Prompt 块和命中规则。
  • graduation-design/backend/chat/service.py:1323 · _collect_training_prompt_stage() 首次生成阶段拼接 SQL 样例和 SQL Experience。
  • graduation-design/backend/chat/service.py:1353 · 生成阶段检索 SQL Experience 规则。
  • graduation-design/backend/chat/service.py:2052 · 修复阶段带错误信息重新检索 repair experience。
  • graduation-design/backend/chat/service.py:2058 · 将 repair experience 追加到修复 Prompt 的 data_training
“生成阶段的经验是提前避坑,修复阶段的经验是拿着具体报错对症下药。”
10

成功 SQL 的经验候选沉淀与人工审核

Experience candidate feedback loop
Candidate Review Training
【核心概念与设计初衷】

系统不会把每次成功 SQL 直接变成正式 SQL 样例,而是先沉淀为 SQL 经验候选,等待人工审核后再进入 training 库。这样能避免模型偶然生成的可执行但口径不一定正确的 SQL 反过来污染后续 few-shot 样例。

【算法逻辑与控制流向】
  1. Input:成功问答的 datasource_id、chat_id、record_id、有效问题、最终 SQL、表名、图表类型、是否来自 repair。
  2. 对数据源 ID、规范化问题和规范化 SQL 计算 SHA-256 去重哈希。
  3. 如果候选已存在,则更新来源记录和 from_repair 标记。
  4. 如果不存在,则创建 SqlExperienceCandidate,状态默认为 pending
  5. 管理员或用户审核通过时,将候选问题和 SQL 导入 DataTraining,范围为当前数据源。
  6. 审核通过后刷新训练样例 embedding;拒绝时只更新候选状态和审核备注。
  7. Output:从运行结果到可控 SQL 样例库的闭环,但未经审核内容不参与生成。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/experience_memory_service.py:1 · 文件说明强调成功 SQL / repair SQL 先进入可审核候选队列。
  • graduation-design/backend/services/experience_memory_service.py:32 · build_sql_experience_dedupe_hash() 生成候选去重哈希。
  • graduation-design/backend/services/experience_memory_service.py:50 · collect_sql_experience_candidate() 采集成功问答 SQL 候选。
  • graduation-design/backend/training/models.py:91 · SqlExperienceCandidate 定义候选状态、来源记录、SQL 文本和去重哈希。
  • graduation-design/backend/training/service.py:586 · approve_sql_experience_candidate() 审核通过后转入 DataTraining
  • graduation-design/backend/training/service.py:639 · reject_sql_experience_candidate() 拒绝候选。
  • graduation-design/tests/test_experience_memory_service.py:114 · 候选去重和审核流的测试。
“成功 SQL 先进入待审核草稿箱,确认没问题后才升级成正式样例,避免经验库被错误答案污染。”
11

配置开关、实验收益与能力边界

Flags, ablation and cost boundary
Config Ablation Cost
【核心概念与设计初衷】

复杂问题增强是可配置能力,收益主要集中在中高难度问题。论文消融显示,问题改写、问题分解和经验规则在 challenging 样本上更有帮助,但在 simple 样本上可能引入额外成本或轻微口径干扰。因此答辩时要强调:这些模块不是越多越好,而是服务于复杂约束与风险场景。

【算法逻辑与控制流向】
  1. Input:运行配置、问题复杂度、是否存在历史上下文、是否命中风险标签、规则库是否可用。
  2. 问题改写由 CHAT_QUESTION_REWRITE_ENABLED 与最大 token 控制;无历史时自动跳过。
  3. 问题分解由 CHAT_QUESTION_DECOMPOSITION_ENABLED 控制,默认关闭,并通过启发式和白名单收缩触发范围。
  4. SQL Experience 由 CHAT_SQL_EXPERIENCE_ENABLED、Top-K、最大字符数和可选意图/Schema 过滤控制。
  5. 模块失败、未命中或关闭时,对应 Prompt 块为空,主链路仍依赖 Schema-RAG 和基础校验执行。
  6. Output:在复杂问题中尽量提高约束质量,同时用配置控制 token、时延和噪声风险。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/core/config.py:116:120 · 问题改写与问题分解开关和 token 上限。
  • graduation-design/backend/core/config.py:128:134 · SQL Experience 开关、Top-K、字符预算、过滤器和规则路径。
  • latex/final.tex:934:936 · 实验配置对比 Pure Base-RAG、Base-RAG 和 Full Final。
  • latex/final.tex:1072:1077 · 消融表记录经验规则、问题分解、问题改写在不同难度上的增量。
  • latex/final.tex:1094 · 论文解释增强策略更适合由问题复杂度和风险信号触发。
  • latex/final.tex:1208 · 成本分析说明生成前证据会增加输入 Token 和尾部时延。
“复杂增强的正确使用方式是按风险触发;简单问题少加约束,复杂问题才用改写、分解和经验规则兜住口径。”

SQL 计划、Prompt 构造与生成约束

本知识域回答一个核心问题:系统如何在调用大模型之前把自然语言意图、Schema、值证据、业务知识和安全边界收敛为可解析、可校验的 SQL 生成上下文。

论文原图:BIRD 三难度模块贡献图
论文原图 · BIRD 三难度模块贡献图 用于回答“SQL Plan 为什么是可配置增强项”:热力图显示 SQL 计划在 simple、moderate、challenging 三个难度层分别约为 +1.0、+1.0、+3.0 个百分点,平均贡献约 +1.7 个百分点。

读图顺序

  1. 先看“数据库模式检索”这一行,它在三个难度层都是最稳定的基础能力;这说明 SQL Plan 不是替代 Schema-RAG,而是建立在结构召回之后的约束层。
  2. 再看“SQL 计划”这一行,它在 simple 与 moderate 的增量较小,在 challenging 的增量更明显,说明计划约束主要服务于复杂过滤、聚合口径和结果形态。
  3. 最后横向比较 SQL 计划、检索证据、问题分解和语义验证:这些增强项都不是无条件越多越好,而是复杂题和风险题中更有价值。

代码对应:backend/services/sql_planner.py 负责构造计划,backend/services/prompt_builder.py 负责把计划和其他上下文写入 Prompt,backend/chat/service.py 负责在主链路中记录、注入并解析模型输出。

答辩讲法:SQL Plan 的价值不是让所有题都暴涨准确率,而是在复杂题里把“必须用哪些表、哪些条件、什么结果形态”提前写清楚,减少模型自由发挥。

01

生成前控制层的模块边界

Pre-generation control boundary
Plan Prompt Boundary
【核心概念与设计初衷】

SQL 计划与 Prompt 构造共同构成 SQL 生成前的控制层。SQL Plan 把问题中的目标表、过滤条件、指标口径和结果形态转成结构化约束;Prompt Builder 再把 Schema、值证据、术语、样例、领域记忆、问题分解、SQL Plan、方言规则和输出格式拼成模型消息。设计初衷是避免模型只凭自然语言自由生成 SQL,把生成空间收敛到当前数据源真实结构和可校验输出边界内。

模块 核心职责 不负责什么
SQL Planner 结构化描述“SQL 应该满足什么约束”。 不调用 LLM,不直接生成 SQL。
Prompt Builder 把所有上下文填入 YAML 模板,形成 system/user messages。 不判断 SQL 是否安全,也不访问数据库。
ChatService 生成阶段 调用模型、解析 JSON、记录日志、输出 SQL 结果对象。 不跳过后续 Guard、执行和语义验证。
【算法逻辑与控制流向】
  1. Input:有效问题 effective_question、Schema-RAG 结果、Value Grounding 候选、术语、样例、领域记忆、检索证据、问题分解和运行配置。
  2. 先基于当前召回 Schema 与值证据构造 SQLPlanResult,计划对象只记录结构约束。
  3. 根据模式与置信度决定是否把 <sql-plan> 片段注入 Prompt。
  4. MemoryBroker 汇总各增强模块的 Prompt 文本,生成 SQLPromptContext
  5. Prompt Builder 读取基础模板与数据库方言模板,填充上下文、硬规则、示例和用户问题。
  6. ChatService 将消息数组交给 LLM,要求模型返回 <json-response> 包裹的结构化 JSON。
  7. Output:SQLGenerationResult,包含 success、sql、tables、chart_type、brief 或失败 message。
【代码精准溯源 (Code Anchor)】
  • latex/final.tex:193:216 · 论文将 Prompt 构造定义为任务说明、结构约束和输出控制,并给出 SQL 生成抽象式。
  • latex/final.tex:492:536 · 论文定义显式 SQL 计划约束生成策略、字段契约和注入判断。
  • graduation-design/backend/services/sql_planner.py:1 · 文件说明强调计划只描述结构约束,不直接生成 SQL,且默认不额外调用 LLM。
  • graduation-design/backend/services/prompt_builder.py:1 · 文件说明表明 Prompt 通过 YAML 模板和运行参数填充构建。
  • graduation-design/backend/chat/service.py:1546 · _collect_stream_prompt_artifacts() 汇总 Schema、值证据、知识增强、问题分解、SQL Plan 和 Prompt messages。
“SQL Plan 是先画查询草图,Prompt Builder 是把草图、地图和交通规则一起交给模型,模型再按这些边界写 SQL。”
02

SQL PlanResult 数据契约

Structured plan contract
Dataclass Contract Traceable
【核心概念与设计初衷】

SQLPlanResult 是系统在生成 SQL 前构造的结构化计划对象,对应论文中的 Plan(q)=<T,C,F,M,A,G,H,O,J,R,U,S,c>。它把自然语言里容易被模型漏掉的查询要素拆成可记录字段,使计划可以进入 Prompt、运行日志、语义验证和修复提示,而不是停留在不可追踪的自然语言提醒。

计划字段 含义 答辩解释
required_tables / target_columns 必要表与目标列。 SQL 至少要看哪些结构。
filter_conditions 来自强值证据、日期和字面值规则的过滤条件。 WHERE 或条件聚合不能漏。
metrics / aggregation 指标公式、差值、平均、计数、条件聚合等口径。 算什么、怎么算。
result_shape 期望结果形态和列数。 返回单值、单列列表还是单行多指标。
risk_flags / unresolved_items 风险标签与未解决项。 告诉后续链路哪里需要谨慎。
confidence / should_inject 计划明确度和是否注入 Prompt。 控制计划是否真的影响生成。
【算法逻辑与控制流向】
  1. Input:用户问题、召回后的 SchemaRetrievalResult、值候选、指标公式提示。
  2. 创建 SQLPlanResult,记录原问题、模式、启用状态和默认空字段。
  3. 后续规则逐步向 plan 中追加必要表、目标列、过滤条件、JOIN 提示、指标口径和风险标签。
  4. 每个过滤条件用 SQLPlanFilterCondition 记录 table、column、operator、value、source、confidence、scope。
  5. 结果形态用 SQLPlanResultShape 记录 type、expected_columns、row_intent。
  6. 最后调用 to_dict() 写入阶段日志,保证答辩或调试时能解释为什么计划注入或跳过。
  7. Output:可序列化、可格式化、可被后续语义验证复用的计划对象。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/sql_planner.py:52 · SQLPlanFilterCondition 定义单条过滤约束。
  • graduation-design/backend/services/sql_planner.py:68 · SQLPlanResultShape 定义结果形态。
  • graduation-design/backend/services/sql_planner.py:78 · SQLPlanResult 定义 SQL 计划主体字段。
  • graduation-design/backend/services/sql_planner.py:99 · to_dict() 将计划序列化为日志和调试对象。
  • latex/final.tex:503 · 论文用抽象字段解释 SQL Plan 的结构契约。
“SQLPlanResult 就像生成 SQL 前的任务单:写清楚要查哪些表、哪些条件不能漏、结果应该长什么样。”
03

Schema 映射、字段校验与计划补表

Schema mapping and supplement tables
Schema Supplement Guardrail
【核心概念与设计初衷】

SQL Plan 不应成为第二套无边界召回器,所以它先把当前 Schema-RAG 结果转成表名和字段名映射,后续计划项原则上只能引用已确认的表字段。少数高置信场景会在构造计划前补入必要表,例如月度事实问题缺少 yearmonth 时补表,避免后续日期条件没有落点。

【算法逻辑与控制流向】
  1. Input:Schema-RAG 产出的 schema_result.bundles 与有效问题。
  2. _schema_maps() 遍历 bundles,生成小写表名到真实表名的映射,以及每张表的字段集合。
  3. infer_sql_plan_schema_supplement_tables() 检查 SQL Plan 是否启用、模式是否非 off、问题是否包含月份年份和月度事实表语义。
  4. 如果当前召回结果缺少 yearmonth,函数返回补充表列表。
  5. ChatService 调用 augment_schema_result_with_tables() 将补表加入 Schema 结果,并重新绑定到 MemoryBroker。
  6. 后续添加过滤条件和目标列时,_has_field() 会检查字段是否真实存在;不存在则记录 unresolved_items,不强行注入。
  7. Output:更完整但仍受控的 Schema 上下文,以及不会引用未知字段的计划对象。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/sql_planner.py:144 · _schema_maps() 从召回 bundles 构建表字段映射。
  • graduation-design/backend/services/sql_planner.py:154 · infer_sql_plan_schema_supplement_tables() 推断少量高置信补表。
  • graduation-design/backend/services/sql_planner.py:174 · _has_field() 校验计划中的表字段是否存在。
  • graduation-design/backend/services/sql_planner.py:188 · _add_filter() 字段缺失时写入 unresolved_items 而不是伪造条件。
  • graduation-design/backend/chat/service.py:1580 · 主链路调用计划补表推断。
  • graduation-design/backend/chat/service.py:1583 · 通过 augment_schema_result_with_tables() 把补表加入当前 Schema 结果。
“计划只能在当前地图上画路线;确实缺了高置信必要表,才小范围补地图,不能凭空画不存在的路。”
04

过滤、日期、指标与结果形态信号提取

Plan signal extraction
Filter Metric Shape
【核心概念与设计初衷】

计划信号提取负责把强证据和启发式口径转成结构化字段。它重点处理四类容易出错的内容:真实取值过滤、日期月份表达、业务缩写/同义词、复杂指标和结果形态。这样模型在生成 SQL 时不仅看到“用户问什么”,还看到“哪些条件必须落地、哪些指标不能算错、最终应返回几列几行”。

【算法逻辑与控制流向】
  1. Input:问题文本、Schema 映射、Value Grounding 候选、指标公式提示。
  2. 先用问题模式和风险标签构建 result_shape,识别单标量、单列列表、单行多指标等结果形态。
  3. 遍历值候选,仅把 confidence >= 0.99match_typeexactdb_exact 的候选写入过滤条件。
  4. 识别 SME、LAM、KAM、CZK、EUR 等少量高置信业务缩写,补充为字段过滤。
  5. 抽取月份年份表达,转换为 YYYYMM;如果问题含局部指标条件,设置 scope=conditional_metric,避免误放到全局 WHERE。
  6. 按问题类型补充目标列、必要表、JOIN 提示、指标公式、聚合表达和风险标签。
  7. Output:包含 filters、metrics、aggregation、joins、risk_flags 和 result_shape 的计划草稿。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/sql_planner.py:293 · _build_result_shape() 根据问题和风险标签推断结果形态。
  • graduation-design/backend/services/sql_planner.py:308 · _add_value_grounding_filters() 只接收 exact/db_exact 高置信值证据。
  • graduation-design/backend/services/sql_planner.py:332 · _add_common_value_synonyms() 处理 SME、LAM、KAM、CZK、EUR 等缩写。
  • graduation-design/backend/services/sql_planner.py:351 · _add_date_hints() 把月份表达转为日期过滤或条件聚合提示。
  • graduation-design/backend/services/sql_planner.py:379 · _add_target_and_metric_hints() 生成目标列、指标、聚合、JOIN 和风险标签。
  • latex/final.tex:511:526 · 论文解释计划字段对过滤、指标、聚合和结果形态的作用。
“计划信号提取就是把题干里的硬条件和易错口径先翻译成检查清单,防止模型写 SQL 时漏条件、算错指标。”
05

注入模式、启发式置信度与跳过原因

Injection mode and confidence
Mode Confidence Config
【核心概念与设计初衷】

SQL Plan 是可配置增强项,不是所有问题都强制注入。系统用 offshadowsoftenforced 四种模式控制计划影响范围,并用启发式置信度判断计划是否足够明确。这样既能在实验中观察计划信号,也能避免低质量计划误导模型。

模式 行为 适用场景
off 不构建有效计划,返回 disabled。 关闭能力或做消融实验。
shadow 构建并记录计划,但不注入 Prompt。 观察计划质量,避免影响线上结果。
soft 达到阈值后注入结构化计划片段。 常规增强,保留模型判断空间。
enforced 达到阈值后按强约束写入 Prompt。 高风险复杂题或实验配置。
【算法逻辑与控制流向】
  1. Input:CHAT_SQL_PLAN_ENABLEDCHAT_SQL_PLAN_MODECHAT_SQL_PLAN_MIN_CONFIDENCE 与计划草稿。
  2. 如果功能关闭或模式为 off,设置 skip_reason=disabled
  3. 统计计划信号数量:必要表、目标列、过滤条件、指标、聚合和风险标签。
  4. 如果信号数为 0,设置 skip_reason=no_plan_signal,不注入空计划。
  5. 从 0.55 起计算启发式置信度:过滤条件、指标、目标列、明确结果形态分别加分,未解决项扣分。
  6. 只有模式为 softenforced 且置信度达到阈值时,设置 should_inject=true
  7. Output:带有 confidenceshould_injectskip_reason 的计划对象。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/sql_planner.py:481 · build_sql_plan() 是计划构造和注入判断主函数。
  • graduation-design/backend/services/sql_planner.py:485 · 读取 CHAT_SQL_PLAN_MODECHAT_SQL_PLAN_ENABLED
  • graduation-design/backend/services/sql_planner.py:515 · 统计计划信号数量,空信号返回 no_plan_signal
  • graduation-design/backend/services/sql_planner.py:528:540 · 计算启发式置信度并决定 should_inject
  • graduation-design/backend/core/config.py:121:123 · SQL Plan 开关、模式和最小置信度配置。
  • latex/final.tex:530:532 · 论文说明 disabled、no signal、shadow、low confidence、soft/enforced 的注入逻辑。
“SQL Plan 的置信度不是数学概率,而是这张查询任务单够不够清楚;不清楚就只记日志,不拿去干扰模型。”
06

计划格式化与确定性计划修正

Prompt block and deterministic fixes
XML Block Fix Narrow Rules
【核心概念与设计初衷】

计划注入并不是把 Python 对象原样塞进 Prompt,而是格式化为可读的 <sql-plan> 结构化片段,包含必要表、目标列、结果形态、过滤条件、指标提示、聚合提示、JOIN 提示、风险标签和 LIMIT 策略。执行链路中还保留少量确定性计划修正,用于处理明确且可控的窄场景。

【算法逻辑与控制流向】
  1. Input:SQLPlanResult 与模型生成出的 SQL。
  2. format_sql_plan() 先检查 enabledshould_inject;不满足则返回空字符串。
  3. 满足注入条件时,输出带 mode、confidence 的 <sql-plan> 块,并按字段生成 XML 风格片段。
  4. 如果结果形态是完整列表型单列结果,额外加入 <limit-policy>,提醒不要机械追加默认 LIMIT。
  5. LLM 生成 SQL 后,ChatService 在语义修正阶段调用 apply_sql_plan_fixes()
  6. 若命中 transaction_level_list,移除不该出现的 DISTINCT 或默认 LIMIT 200
  7. 若命中 spent_dual_metric_month,将全局月份过滤改写成条件聚合,避免把局部月份条件套到总金额上。
  8. Output:格式化后的 Prompt 片段,以及可能被窄规则修正后的 SQL。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/sql_planner.py:562 · apply_sql_plan_fixes() 只对高置信计划支持的窄场景做确定性修正。
  • graduation-design/backend/services/sql_planner.py:573 · transaction_level_list 场景移除 DISTINCT 和默认 LIMIT。
  • graduation-design/backend/services/sql_planner.py:583 · spent_dual_metric_month 场景改写为条件聚合 SQL。
  • graduation-design/backend/services/sql_planner.py:603 · format_sql_plan() 生成 Prompt 可读的 <sql-plan> 块。
  • graduation-design/backend/chat/service.py:468 · _apply_sql_semantic_fixes_to_result() 在语义修正后继续应用计划修正。
  • latex/final.tex:536 · 论文说明确定性计划修正规则范围很窄,不承担通用 SQL 优化器职责。
“计划先以结构化清单进 Prompt;如果模型犯的是非常明确的窄错误,系统再用确定性规则把它掰回来。”
07

MemoryBroker 与 SQLPromptContext 契约

Prompt context assembly
MemoryBroker Context Assembly
【核心概念与设计初衷】

SQLGenerationMemoryBroker 是生成上下文编排器,SQLPromptContext 是 Prompt Builder 的输入契约。前者负责在主链路中逐步绑定 Schema、术语、领域记忆、SQL 样例、值证据、历史、问题分解和 SQL Plan;后者把这些材料变成一个字段完整、可测试、可替换模板的上下文对象。

【算法逻辑与控制流向】
  1. Input:从各阶段收集到的 prompt 文本和运行时信息。
  2. 主链路创建 SQLGenerationMemoryBroker(question, question_evidence)
  3. Schema-RAG 阶段绑定裁剪后的 M-Schema、retrieved tables、relation tables 和 ranking。
  4. 知识增强阶段绑定术语、Domain Memory、SQL 样例、SQL Experience、evidence context 和 value grounding prompt。
  5. 复杂增强阶段绑定问题分解文本和 SQL Plan 文本。
  6. 历史阶段绑定 conversation history、prior SQL cases 和 current_time。
  7. 调用 build_sql_prompt_context() 生成 SQLPromptContext,交给 Prompt Builder。
  8. Output:一个包含全部生成上下文的 dataclass,而不是散落的字符串参数。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/memory_broker.py:25 · SQLGenerationMemoryBroker 定义生成上下文编排类。
  • graduation-design/backend/services/memory_broker.py:54:142 · 一组 bind_* 方法逐步绑定 Schema、知识、历史、问题分解和 SQL Plan。
  • graduation-design/backend/services/memory_broker.py:142 · bind_sql_plan() 保存格式化后的计划片段。
  • graduation-design/backend/services/memory_broker.py:162 · build_sql_prompt_context() 构造 SQLPromptContext
  • graduation-design/backend/services/prompt_builder.py:51 · SQLPromptContext 定义 SQL 生成 Prompt 所需字段。
  • graduation-design/backend/chat/service.py:1629:1637 · 主链路绑定 history、decomposition、SQL Plan 并构造最终 prompt messages。
“MemoryBroker 像打包台:每个增强模块把材料放上来,最后统一封装成 SQLPromptContext 交给模板填充。”
08

Prompt 模板资产、方言规则与定向示例

Templates, dialect rules and targeted examples
YAML Dialect Examples
【核心概念与设计初衷】

Prompt 不是硬编码在业务函数里的长字符串,而是由基础 YAML 模板、数据库方言模板、公共强规则、基础 SQL 示例和定向推理示例组合而成。这样可以把“通用 NL2SQL 约束”和“MySQL/PostgreSQL/Excel 方言差异”分开维护,也便于后续在不改主链路的情况下调整提示词策略。

【算法逻辑与控制流向】
  1. Input:SQLPromptContext.db_type 和模板文件。
  2. _load_base_template() 读取 backend/prompts/template.yaml,得到 SQL system/user 模板。
  3. _load_sql_example_template() 根据 db_type 选择 MySQL.yamlPostgreSQL.yamlSQLite.yaml
  4. _build_sql_prompt_assets() 拼装 query limit、方言引用规则、limit 规则、多表规则、时间排序规则、JOIN 偏好和 no additional info。
  5. _build_targeted_reasoning_examples() 根据指标公式、问题分解和 SQL Plan 动态补充月均公式、单行多指标差值、年均差值等示例。
  6. 模板占位符统一由 build_sql_messages_with_overrides() 填充。
  7. Output:两条 OpenAI 兼容消息:system 放规则和上下文,user 放当前问题和背景信息。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/prompt_builder.py:714 · _load_base_template() 读取基础 YAML 模板。
  • graduation-design/backend/services/prompt_builder.py:734 · _load_sql_example_template() 按数据库类型选择方言模板。
  • graduation-design/backend/services/prompt_builder.py:805 · _build_sql_prompt_assets() 拼装公共规则、方言规则和基础示例。
  • graduation-design/backend/services/prompt_builder.py:406 · format_metric_formula_hints() 将指标公式提示格式化为 Prompt 块。
  • graduation-design/backend/services/prompt_builder.py:420 · _build_targeted_reasoning_examples() 根据复杂信号补充定向示例。
  • graduation-design/backend/prompts/template.yaml:140 · SQL 生成基础模板定义任务说明、规则、Info 和 Examples 区块。
“Prompt Builder 不是拼一个大字符串,而是把公共规则、数据库方言、上下文证据和动态示例按模板装配起来。”
09

SQL 生成 Prompt 的强约束规则

Generation constraints
Readonly JSON Rules
【核心概念与设计初衷】

SQL 生成 Prompt 的强约束目标是让模型输出“可执行、可解析、可校验”的只读查询结果,而不是自由文本答案。模板明确限制 SQL 方言、只读范围、单条语句、真实表字段、JSON 返回格式、图表类型、标题长度、计划约束、值证据、问题分解、检索证据和历史样例的使用方式。

【算法逻辑与控制流向】
  1. Input:Prompt 模板、当前上下文和用户问题。
  2. 系统指令先限定角色:唯一目标是根据问题、数据库类型、表结构、知识和样例生成可执行只读查询 SQL。
  3. 输出格式强制为 <json-response>{...}</json-response>,成功时包含 success/sql/tables/chart-type/brief,失败时包含 success=false/message
  4. 只读边界要求不得输出 INSERT、UPDATE、DELETE、DDL、权限操作、多语句脚本、解释文字、Markdown 或额外字段。
  5. 证据优先级要求:高置信 Value Grounding 候选要保留真实值;SQL Plan 的高置信 filter 要落实到 WHERE、JOIN 或条件聚合;公式证据优先于通用启发式。
  6. 结果形态约束要求 question decomposition 与 sql plan 的 answer-shape、result-shape、expected-columns 影响最终 SELECT 列形态。
  7. 图表约束要求 chart-type 从 table、column、bar、line、pie 中选择,并结合结果字段角色认真判断。
  8. Output:模型被限制为返回可解析 SQL 生成结果,而不是自然语言解释。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/prompts/template.yaml:140 · SQL 生成 Instruction 定义只读 SQL 任务和 JSON 响应格式。
  • graduation-design/backend/prompts/template.yaml:153:178 · 规则约束语言、方言、JSON、单条只读 SQL、tables、chart-type 和 brief。
  • graduation-design/backend/prompts/template.yaml:180:217 · 规则约束 evidence、value grounding、sql plan、question decomposition 和 retrieval evidence 的使用边界。
  • graduation-design/backend/prompts/template.yaml:221:241 · 规则约束指标语义、公式、比例、时间键、文本值和 top-ranking 偏好。
  • graduation-design/backend/prompts/template.yaml:248:268 · Info 区块承载 schema、evidence、value grounding、sql plan、decomposition、retrieval evidence、知识和历史。
  • latex/final.tex:199:216 · 论文解释 Prompt 同时承担任务说明、结构约束和输出控制。
“Prompt 的核心不是让模型多说,而是让模型少乱说:只许输出单条只读 SQL 的结构化 JSON。”
10

Prompt 覆盖配置与默认模板保护

Prompt override profile
Override Settings Template
【核心概念与设计初衷】

Prompt 覆盖能力允许系统在管理端替换 SQL、图表、解释等阶段的 system/user 模板,但默认情况下仍使用内置 YAML 模板。它的设计价值在于支持实验和运营调参,同时保留开关控制:只有 profile 启用且对应字段非空时,才覆盖默认模板,避免空配置把生成约束清掉。

【算法逻辑与控制流向】
  1. Input:数据库中的 PromptSetting 记录和当前问答运行时。
  2. ChatService 在创建运行上下文时调用 build_prompt_override_profile(),读取当前激活的 Prompt 配置。
  3. 如果 PromptOverrideProfile.enabled 为 false 或配置为空,Prompt Builder 使用默认 YAML 模板。
  4. 如果启用且 sql_system_prompt 非空,则替换 system 模板;如果 sql_user_prompt 非空,则替换 user 模板。
  5. 无论是否覆盖,Prompt Builder 仍用同一组上下文字段进行 format() 填充。
  6. Output:允许模板替换,但主链路、上下文契约和输出解析仍保持一致。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/settings/models.py:144 · PromptSetting 定义可持久化的 Prompt 配置。
  • graduation-design/backend/settings/models.py:180 · PromptOverrideProfile 定义运行时 Prompt 覆盖快照。
  • graduation-design/backend/settings/models.py:539 · build_prompt_override_profile() 从当前会话读取覆盖配置。
  • graduation-design/backend/chat/service.py:703 · ChatService 构造运行上下文时读取 Prompt 覆盖项。
  • graduation-design/backend/services/prompt_builder.py:898 · build_sql_messages_with_overrides() 接收覆盖 profile。
  • graduation-design/backend/services/prompt_builder.py:924:928 · 覆盖 SQL system/user 模板的条件判断。
“Prompt Override 是可控换模板,不是换掉整条链路;上下文字段和解析契约仍然不变。”
11

SQL 生成调用、结构化解析与兜底提取

LLM generation and parsing
LLM Parser Fallback
【核心概念与设计初衷】

SQL 生成阶段负责把 Prompt messages 交给模型,并把模型返回文本解析为系统内部的 SQLGenerationResult。由于模型输出可能出现字段别名、JSON 包裹、轻微格式错误甚至直接返回 SQL,代码提供结构化解析、字段归一化和正则兜底提取,保证后续 Guard 和执行阶段拿到统一数据对象。

【算法逻辑与控制流向】
  1. Input:Prompt messages、LLM 客户端、模型配置、取消控制器和 record_id。
  2. ChatService 创建 SQL 生成日志,并推送 stage 事件。
  3. 根据模型配置解析 max_tokens,调用 complete_text_with_control() 获取模型响应。
  4. 若响应为空或因长度截断没有正文,抛出解析异常并记录错误日志。
  5. _parse_sql_generation_response_detail() 调用 parse_json_object(),按 SQLGenerationResult 模型解析 JSON。
  6. _normalize_sql_generation_payload() 兼容 chart_type/chartType/table_names 等字段别名,并把 tables 字符串归一化为列表。
  7. 如果 JSON 解析失败但文本中能提取 SELECTWITH 语句,则使用 regex_sql_fallback 生成最小可用结果。
  8. Output:结构化 SQL 结果,以及记录 source、parser、repaired、fallback_used 的解析元信息。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/service.py:277 · _extract_sql_from_text() 从非 JSON 文本中兜底提取 SQL。
  • graduation-design/backend/chat/service.py:295 · _normalize_sql_generation_payload() 兼容模型返回字段别名和 tables 类型。
  • graduation-design/backend/chat/service.py:1651 · _stream_sql_generation_step() 统一处理 SQL 生成、日志、取消和阶段事件。
  • graduation-design/backend/chat/service.py:1678 · 调用 complete_text_with_control() 执行模型请求。
  • graduation-design/backend/chat/service.py:1700 · 调用结构化解析并检查 success/sql
  • graduation-design/backend/chat/service.py:2301 · _parse_sql_generation_response_detail() 返回解析结果和解析元信息。
“模型可以有输出格式波动,但系统入口只认 SQLGenerationResult;先解析成统一对象,再交给后面的 Guard 和执行。”
12

配置、实验消融与能力边界

Config, ablation and boundary
Ablation Config Limit
【核心概念与设计初衷】

SQL 计划与 Prompt 生成约束的收益边界要结合实验解释:Schema-RAG 是基础,SQL Plan 是复杂问题增强。论文在 Spider 消融中显示关闭 SQL Plan 对基础泛化集影响不明显;在 BIRD 难度分层消融中,SQL Plan 对 challenging 样本贡献更高。答辩时不能把计划说成万能模块,而要说明它主要降低复杂过滤、聚合和结果形态偏差。

配置 / 指标 含义 边界解释
CHAT_SQL_PLAN_ENABLED 是否启用计划能力。 默认关闭,可用于消融和灰度。
CHAT_SQL_PLAN_MODE off / shadow / soft / enforced。 控制计划只记录还是进入生成。
CHAT_SQL_PLAN_MIN_CONFIDENCE 注入阈值。 低明确度计划不应影响模型。
CHAT_DEFAULT_QUERY_LIMIT 默认查询返回上限。 列表类问题由 limit-policy 防止机械截断。
CHAT_SQL_GENERATION_MAX_TOKENS SQL 生成 token 预算。 Prompt 越复杂,越需要预算控制。
【算法逻辑与控制流向】
  1. Input:运行配置、数据集难度、问题复杂度和可用证据信号。
  2. 简单问题如果缺少计划信号,计划会自动变成空块或仅记录日志,不增加 Prompt 噪声。
  3. 中高难度问题如果存在高置信过滤、指标或结果形态信号,计划进入 Prompt,并可能被语义验证和修复复用。
  4. Spider 消融结果中 No SQL Plan 与 Base-RAG 差异不明显,说明跨库结构泛化主要依赖 Schema-RAG。
  5. BIRD 三难度消融中 SQL Plan 平均贡献约 +1.7 pp,challenging 层约 +3.0 pp,说明复杂约束场景更受益。
  6. 局限性:当前计划主要依赖本地规则和少量领域启发式,对长尾复杂 SQL 仍需更精细的计划识别。
  7. Output:对 SQL Plan 做“增强而非替代”的定位,避免答辩中过度承诺。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/core/config.py:121:123 · SQL Plan 开关、模式和置信度阈值。
  • graduation-design/backend/core/config.py:145:146 · 默认查询 LIMIT 与 SQL 生成 token 预算。
  • latex/final.tex:991 · Spider 消融表记录 No SQL Plan 组结果。
  • latex/final.tex:1069 · BIRD 三难度模块消融表记录 SQL 计划贡献。
  • latex/final.tex:1085:1094 · 论文解释增强策略更适合复杂问题和风险信号触发。
  • latex/final.tex:1126 · Q1481 案例说明 SQL Plan 可在语义验证和修复中补齐缺失年份过滤。
  • latex/final.tex:1248 · 论文总结 SQL Plan 当前为轻量约束形式,长尾复杂 SQL 仍需继续细化。
“SQL Plan 不是万能生成器,而是复杂题里的约束放大器:简单题不添乱,复杂题帮模型少漏条件、少算错口径。”

SQL 安全校验、语义验证与自动修复

本知识域回答一个核心问题:模型生成 SQL 之后,系统如何在访问真实数据库前后持续控制风险,并把可恢复错误转化为有边界的修复重试。

论文原图:SQL 校验、语义验证与自动修复状态边界图
论文原图 · SQL 校验、语义验证与自动修复状态边界图 用于回答“为什么能执行不等于答对”:生成 SQL 必须先过 Guard,再执行,再做语义验证;只有可修复错误才回到修复分支。

读图顺序

  1. 初始 SQL 先进入确定性修正与 SQL Guard,检查只读限制、多语句、危险关键字、表字段存在性、别名和 JOIN 关系。
  2. Guard 通过后才交给 Executor 访问真实数据源;如果数据库执行报错,错误被转成统一执行结果对象。
  3. 执行成功后,Semantic Verifier 继续检查强值证据、聚合意图、极值意图、百分比尺度和 SQL 计划约束是否被 SQL 正确体现。
  4. Guard、Executor 或 Verifier 产生的问题都会先判断是否可修复;可修复且未超过重试上限时,Fixer 基于裁剪后的上下文生成修复 SQL。
  5. 修复 SQL 不会直接执行,而是重新回到 Guard,形成“修复也必须受同一安全边界约束”的闭环。

代码对应:backend/services/sql_guard.py 做执行前边界检查,backend/services/sql_executor.py 做只读查询,backend/services/sql_semantic_verifier.py 做执行后语义检查,backend/services/sql_semantic_fixer.py 构造修复提示并生成修复 SQL。

答辩讲法:自动修复不是让模型随便重写一遍,而是把“校验失败、执行失败、语义风险”统一收敛成受重试次数和错误类型约束的恢复分支。

01

校验、执行、验证、修复统一状态机

Guard-execute-verify-repair loop
State Machine ChatService Repair Loop
【核心概念与设计初衷】

SQL 校验验证修复链路是模型生成 SQL 之后的执行控制层。它把“是否允许执行”“是否能执行”“是否回答了原问题”拆成三个层次处理,避免把可执行 SQL 误认为正确答案,也避免未经审查的模型输出直接访问真实数据库。

阶段 拦截对象 失败后去向
SQL Guard 非只读、未知表字段、JOIN 关系异常、证据漂移 可修复则进入 repair_sql
SQL Executor 数据库方言错误、运行时执行错误、结果结构异常 非基础设施错误可进入 repair_sql
Semantic Verifier 能执行但语义可疑的 SQL 抛出语义验证异常,进入 repair_sql
Repair Loop 上一次失败 SQL、错误信息和裁剪后的 Schema 生成新 SQL 后重新回到 Guard
【算法逻辑与控制流向】
  1. Input:LLM 生成的 SQLGenerationResult、Schema-RAG 结果、值证据、SQL Plan、数据源配置。
  2. 若开启本地 Guard,先执行 guard_query_sql(),通过后得到规范化 SQL。
  3. 调用执行器访问业务数据库,返回 SQLExecutionResult
  4. 若语义验证开启且还有修复额度,则基于问题、SQL、执行结果、值证据和 SQL Plan 检测语义风险。
  5. 任一阶段抛出可修复异常时,构造 repair prompt,生成新 SQL,并把新 SQL 重新送回 Guard。
  6. Output:ChatExecutionOutcome,包含最终 SQL、执行结果和 repair_used 标记。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/service.py:1960 · _execute_sql_with_optional_repair() 统一编排 Guard、执行、语义验证和修复重试。
  • graduation-design/backend/chat/service.py:1725 · _stream_guard_sql_step() 负责执行前本地静态自检和日志记录。
  • graduation-design/backend/chat/service.py:1804 · _stream_execute_sql_step() 执行 SQL 并返回结构化结果。
  • graduation-design/backend/chat/service.py:1873 · _stream_verify_sql_semantics_step() 执行后语义风险检查。
  • graduation-design/backend/chat/service.py:154 · ChatExecutionOutcome 封装最终执行结果与修复状态。
“这条链路不是 SQL 生成器的附属品,而是数据库执行闸门:先问能不能安全执行,再问能不能跑通,最后问有没有真正回答问题。”
02

只读白名单与危险 SQL 拦截

Read-only validation boundary
Readonly SQL Parse Security
【核心概念与设计初衷】

只读白名单是执行安全的第一道硬边界。系统只允许单条查询类 SQL 进入执行阶段,并显式拦截写操作、DDL、权限操作、过程调用、文件读写函数和 SELECT ... INTO ... 等逃逸模式,防止模型输出或提示词注入造成真实数据破坏。

【算法逻辑与控制流向】
  1. Input:模型生成的原始 SQL 字符串。
  2. 清理 Markdown 代码块、尾部分号和空白字符。
  3. 使用 sqlparse.split() 检查是否只有一条语句。
  4. 只允许 SELECTWITHSHOW 开头的查询类语句。
  5. 扫描 insert/update/delete/drop/alter/grant/call/execute 等危险关键字。
  6. 额外拦截文件读写和读权限逃逸模式,例如 LOAD_FILEpg_read_fileINTO OUTFILE
  7. Output:通过校验后的规范 SQL;失败则抛出 SQLValidationError
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/sql_executor.py:32 · FORBIDDEN_KEYWORDS 定义写操作和危险操作关键字。
  • graduation-design/backend/services/sql_executor.py:48 · READ_ESCAPE_PATTERNS 定义文件读写与系统函数逃逸规则。
  • graduation-design/backend/services/sql_executor.py:209 · validate_query_sql() 实现单语句、只读类型和危险模式检查。
  • graduation-design/tests/test_sql_executor_validation.py:13 · 只读边界回归测试覆盖普通查询、CTE、SHOW 和危险模式拒绝。
“只读校验相当于数据库门禁:模型可以建议查询,但只有单条、安全、只读的 SQL 才能拿到执行通行证。”
03

Schema 边界自检:表、字段、别名与歧义

Schema-aware static guard
Schema Guard Alias Ambiguity
【核心概念与设计初衷】

Schema 边界自检负责把模型生成 SQL 限定在 Schema-RAG 已确认的结构范围内。它不访问业务数据库,而是基于检索得到的表、字段、关系和模型声明的 tables 列表,提前发现未知表、未知字段、多表歧义字段和声明不一致等低级错误。

【算法逻辑与控制流向】
  1. Input:SQL、SchemaRetrievalResult、模型声明的 declared_tables、强值证据表。
  2. 先复用 validate_query_sql() 完成只读安全校验。
  3. 解析 SQL 中的 CTE、表引用和别名映射,抽取真实引用表。
  4. 将 SQL 引用表与 Schema-RAG 的 bundles 以及强 value grounding 表合并成允许边界。
  5. 检查实际引用表是否越界,模型声明表是否和实际引用表一致。
  6. 解析限定字段,发现不存在字段或多表查询中的通配字段。
  7. 多表场景下扫描裸字段,若字段在多个表中出现但 SQL 没有限定来源,则判定为歧义字段。
  8. Output:SQLGuardResult;若有风险,抛出携带结果对象的 SQLGuardError
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/sql_guard.py:173 · SQLGuardResult 记录规范 SQL、引用表、声明表、别名和问题列表。
  • graduation-design/backend/services/sql_guard.py:578 · guard_query_sql() 是执行前 Schema 自检主入口。
  • graduation-design/backend/services/sql_guard.py:620:673 · 构造允许表字段边界并检查未知表、字段、通配字段和声明表偏差。
  • graduation-design/backend/services/sql_guard.py:675:701 · 多表场景下检测未限定来源的歧义字段。
  • graduation-design/tests/test_schema_retrieval_guard.py:227 / :250 / :261 · 覆盖未知表、未知字段和多表歧义字段测试。
“Schema Guard 就像拿着本轮检索出的表字段清单逐项验票:没在清单里的表字段不能用,多表同名字段必须说清楚来自哪里。”
04

JOIN 关系校验与 Top1 证据漂移检测

Join integrity and grounding drift
JOIN Grounding Drift
【核心概念与设计初衷】

JOIN 关系校验关注的是“表用对了但连接错了”的问题;Top1 证据漂移检测关注的是“Schema-RAG 已经给出强证据表,但 SQL 绕开它”的问题。两者共同防止模型在多表场景中生成看似可执行、实际口径偏移的 SQL。

【算法逻辑与控制流向】
  1. Input:SQL、Schema-RAG 的 foreign_keysrankingretrieved_tables、用户问题和强值证据表。
  2. 在多表查询中解析 ON a.x = b.y 形式的 JOIN 条件。
  3. 将 JOIN 字段对与 Schema-RAG 已知主外键关系比对,若表对存在已知关系但 SQL 使用其他字段连接,则拦截。
  4. 读取 ranking 中的 grounding_tagsgrounding_fields,识别金融、人名、枚举等关键证据。
  5. 若 Top1 直接命中表有关键证据且得分领先,但 SQL 没有使用该表,也没有使用强值证据表,则判定为证据漂移。
  6. Output:JOIN 错误或证据漂移会合并进 SQLGuardResult.issues,触发可修复异常。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/sql_guard.py:356 · _parse_known_foreign_key_pairs() 将 Schema-RAG 外键文本转成可比对关系。
  • graduation-design/backend/services/sql_guard.py:392 · _extract_join_pairs() 从 SQL 中解析 JOIN 等值条件。
  • graduation-design/backend/services/sql_guard.py:703:726 · 检查 JOIN 条件是否命中已知关系。
  • graduation-design/backend/services/sql_guard.py:483 · _detect_top1_grounding_drift() 检测直接命中强证据表是否被 SQL 绕开。
  • graduation-design/tests/test_schema_retrieval_guard.py:276 / :346 · 覆盖 JOIN 关系错误和高置信证据漂移测试。
“这一步不是只看 SQL 能不能跑,而是看它有没有沿着系统已知的关系和证据走,防止模型走错路但仍然返回一张表。”
05

只读执行器与结果结构化返回

Execution sandbox and result contract
Executor LIMIT Result
【核心概念与设计初衷】

SQL 执行器负责把已经通过校验的查询发送到外部业务数据库,并把数据库返回值统一转换成前端和后处理模块可消费的结构。它再次调用只读校验,并为缺少限制条件的查询追加默认 LIMIT,控制结果规模和响应风险。

【算法逻辑与控制流向】
  1. Input:数据源类型、连接配置、已生成 SQL、可选限制行数。
  2. 执行前再次调用 validate_query_sql(),保证执行器入口自身也具备安全边界。
  3. 若 SQL 未显式包含 LIMIT,通过 ensure_query_limit() 追加默认限制。
  4. 根据数据源类型创建 SQLAlchemy engine,使用 text() 执行查询。
  5. 将日期、时间、Decimal 等数据库类型归一化为 JSON 友好的值。
  6. Output:SQLExecutionResult,包含 executed_sqlfieldsrowsrow_counttruncatedelapsed_ms
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/sql_executor.py:78 · SQLExecutionResult 定义执行结果契约。
  • graduation-design/backend/services/sql_executor.py:248 · ensure_query_limit() 为未限制查询追加默认行数。
  • graduation-design/backend/services/sql_executor.py:267 · execute_query_sql() 创建连接、执行查询、归一化结果并记录耗时。
  • graduation-design/backend/core/config.py:145 · CHAT_DEFAULT_QUERY_LIMIT 默认限制行为 200。
  • graduation-design/backend/chat/service.py:1804 · ChatService 的执行阶段负责 SSE 阶段事件和日志记录。
“执行器不是简单把 SQL 丢给数据库,它会再验一遍只读边界、补上结果规模上限,并把数据库结果整理成统一数据结构。”
06

执行后语义验证器

Post-execution semantic verifier
Semantic Value SQL Plan
【核心概念与设计初衷】

语义验证器用于发现“SQL 可以执行,但可能没有回答原问题”的风险。它综合用户问题、SQL 文本、执行结果、强值证据和 SQL Plan,对过滤值缺失、ID 与文本值混用、聚合遗漏、极值遗漏、百分比尺度、结果列数和计划约束缺失做保守检查。

【算法逻辑与控制流向】
  1. Input:已执行 SQL、用户问题、执行结果、Value Grounding 候选、SQL Plan。
  2. 如果语义验证配置关闭,直接返回空问题列表。
  3. 检查强值证据是否出现在 SQL 过滤条件中。
  4. 检查是否把明显文本实体直接写到 ID 或外键字段上。
  5. 根据问题意图检查 count、极值、金额、百分比和单标量输出形态。
  6. 结合 SQL Plan 的高置信过滤条件、风险标记和期望结果列数检查计划约束是否落地。
  7. Output:SemanticVerificationResult;若存在 issue,raise_if_sql_semantics_suspicious() 抛出 SemanticSQLVerificationError 进入修复分支。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/sql_semantic_verifier.py:36 · SemanticVerificationIssue 定义语义风险代码和说明。
  • graduation-design/backend/services/sql_semantic_verifier.py:50 · SemanticVerificationResult 统一返回验证结果。
  • graduation-design/backend/services/sql_semantic_verifier.py:186 · verify_sql_semantics() 汇总强值证据、聚合、百分比和 SQL Plan 检查。
  • graduation-design/backend/services/sql_semantic_verifier.py:408 · raise_if_sql_semantics_suspicious() 在可疑时抛出可修复异常。
  • graduation-design/tests/test_sql_semantic_verifier.py:43 · 回归测试覆盖 ID 文本混用、强值缺失、过度聚合和百分比尺度。
“语义验证器专门处理‘跑得通但答偏了’的问题,它不重写 SQL,只把可解释的语义风险转成修复信号。”
07

规则化语义修补器

Deterministic semantic fixer
Fixer Deterministic Plan Fix
【核心概念与设计初衷】

规则化语义修补器是在重新请求大模型之前执行的高置信确定性修正层。它只处理能够用规则明确改写的窄场景,例如文本型日期键格式、月份截取偏移、百分比输出尺度、额外排序、标量问题多列输出和部分 SQL Plan 支持的确定性改写。

【算法逻辑与控制流向】
  1. Input:模型生成 SQL、用户问题、Schema-RAG 结果、可选 SQL Plan。
  2. 按固定顺序执行一组规则修补器,每个修补器返回新 SQL 和命中的规则名。
  3. 处理文本日期字段的字面量格式和 ISO 月份截取位置。
  4. 处理明确尺寸字面值、分组差值冗余 CASE、百分比小数精度和百分比输出列。
  5. 若问题没有要求排序,则移除无关顶层 ORDER BY
  6. 对单标量或单时间键问题,尝试把多列结果包成只返回目标列的外层查询。
  7. 再调用 apply_sql_plan_fixes() 处理 SQL Plan 高置信窄场景。
  8. Output:修正后的 SQL;若无规则命中,保持原 SQL 不变。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/sql_semantic_fixer.py:140 · SemanticSQLFixResult 记录修正 SQL 与命中规则。
  • graduation-design/backend/services/sql_semantic_fixer.py:1230 · apply_semantic_sql_fixes() 串联全部确定性修补规则。
  • graduation-design/backend/services/sql_semantic_fixer.py:1268 · detect_semantic_sql_issues() 将可规则修补的问题转成 Guard 阶段 issue。
  • graduation-design/backend/services/sql_planner.py:562 · apply_sql_plan_fixes() 对 SQL Plan 支持的窄场景做确定性修正。
  • graduation-design/backend/chat/service.py:449 · _apply_sql_semantic_fixes_to_result() 在首次生成和修复生成后统一调用修补器。
  • graduation-design/tests/test_sql_semantic_fixer.py:79 · 回归测试覆盖百分比、日期、排序、差值和输出列形态修复。
“能用确定性规则修的小问题,就不要再让大模型猜一次;规则修补器只修高置信窄场景,避免把自动修复变成无边界重写。”
08

自动修复上下文与重试边界

Repair prompt context and retry boundary
Repair Focused Schema Retry
【核心概念与设计初衷】

自动修复不是无条件重试,而是在错误可修复且未超过重试上限时,把失败 SQL、错误信息、裁剪后的 Schema、原有知识增强上下文和修复阶段 SQL Experience 重新组织成 repair prompt。修复后的 SQL 必须重新经过 Guard、执行和语义验证,不能绕过原有安全边界。

【算法逻辑与控制流向】
  1. Input:上一版失败 SQL、异常信息、原始 prompt artifacts、Schema-RAG 结果、数据源配置。
  2. 判断异常是否可修复:SQLValidationError 可修复,非基础设施类 SQLExecutionError 可修复,连接类基础设施错误不修复。
  3. 检查 CHAT_SQL_AUTO_REPAIR_ENABLEDCHAT_SQL_AUTO_REPAIR_MAX_RETRIES,默认最多修复 1 次。
  4. 构造 repair focused schema:优先围绕失败 SQL 实际引用表,补充 direct-hit 表和关系邻居。
  5. MemoryBroker 复用原问题、历史、术语、样例、领域记忆、值证据、检索证据、SQL Plan 等上下文。
  6. 按错误信息检索 repair 阶段 SQL Experience,并追加到修复提示词。
  7. 调用 LLM 生成修复 SQL,执行确定性语义修补后保存,再回到 Guard 重新校验。
  8. Output:成功则返回修复后的 ChatExecutionOutcome,失败或超过上限则向上抛出错误。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/service.py:1947 · _is_repairable_sql_error() 判断哪些错误允许进入修复分支。
  • graduation-design/backend/chat/service.py:419 · _build_repair_schema_result() 构造面向失败 SQL 的裁剪 Schema。
  • graduation-design/backend/services/memory_broker.py:195 · build_sql_repair_prompt_context() 复用生成阶段上下文并补充失败 SQL 与错误信息。
  • graduation-design/backend/services/prompt_builder.py:98 · SQLRepairPromptContext 定义修复提示词所需字段。
  • graduation-design/backend/services/prompt_builder.py:1003 · build_sql_repair_messages() 构造修复阶段 system/user messages。
  • graduation-design/backend/core/config.py:151:155 · 定义 Guard、自动修复和语义验证开关及修复次数。
  • graduation-design/tests/test_chat_async_fast_path.py:276 · 测试修复阶段复用预计算上下文,避免重新抓取上游增强信息。
“自动修复不是放宽规则,而是带着失败原因重做一次更聚焦的 SQL 生成;修完以后还要重新过闸门。”

ChatService 智能问答主链路与 SSE 流式交互

本知识域回答一次自然语言提问如何从前端提交、后端编排、模型生成、SQL 执行,最终以 SSE 事件流合并回前端草稿状态。

论文原图:流式问答交互时序图
论文原图 · 流式问答交互时序图 用于解释前后端协同:前端只提交一次问题,后端按阶段推送 SSE 事件,前端按事件类型合并草稿状态、SQL、查询结果和终止态。

读图顺序

  1. 前端 ChatView 创建本地草稿和 AbortController,然后通过 /chat/ask 发起一次流式请求。
  2. 后端 ChatService 创建问答记录,依次执行问题改写、数据源选择、Schema-RAG、值证据、知识召回、SQL 生成、校验执行和结果保存。
  3. SSE 中间层把后端阶段转成事件:stage 表示进度,schema_ready 等表示上下文已准备,sql_answer_chunksql_generated 表示生成进展,query_resultdone 表示结果与完成态。
  4. 前端不重新推断后端状态,而是按事件类型归并到当前草稿中,逐步更新阶段条、SQL 区域、结果表格和结束状态。
  5. 如果用户停止或后端异常,链路通过取消标记、error 事件或最终清理逻辑收敛,避免前端卡在“生成中”。

代码对应:backend/chat/router.pyStreamingResponse 输出 SSE,backend/chat/service.pystream_chat() 产生事件,前端 frontend/src/api/sse.ts 解析事件块,chatRunControl.ts 合并运行态。

答辩讲法:SSE 的价值是把一个长耗时 NL2SQL 任务拆成可观察的阶段事件,让用户看到系统正在检索、生成、校验和执行,而不是等待一个黑盒结果。

01

SSE 事件契约与选择依据

Server-sent event contract
SSE Contract FastAPI
【核心概念与设计初衷】

SSE 是后端向前端单向持续推送事件的 HTTP 流式机制。本系统问答链路属于“用户提交一次问题,服务端持续返回阶段状态和最终结果”的非对称交互,不需要 WebSocket 的双向常驻连接,因此使用 text/event-stream 承载阶段事件、结果事件和终止事件。

事件类型 代表事件 前端职责
阶段事件 stageschema_readyterminology_readytraining_ready 展示当前处理进度和检索上下文
生成事件 sql_answer_chunksql_generated 逐步展示模型原始回答和最终 SQL
结果事件 query_result 渲染结果表格、行数、耗时和截断状态
终止事件 doneerror 标记草稿完成或失败
【算法逻辑与控制流向】
  1. Input:前端向 /chat/ask 发送 chat_idquestion 和可选补充证据。
  2. FastAPI 路由返回 StreamingResponse,媒体类型为 text/event-stream
  3. 后端每到一个关键节点,调用 _serialize_event(type, payload) 生成一段 data:{...}\n\n
  4. 每条事件都带 type 字段,常见负载包含 record_idstagemessagesqlresult
  5. Output:浏览器读到连续事件块,前端按 type 合并状态,而不是轮询后端状态。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/router.py:209 · /chat/ask 是问答主链路入口。
  • graduation-design/backend/chat/router.py:225 · 使用 StreamingResponse(..., media_type="text/event-stream") 返回 SSE。
  • graduation-design/backend/chat/service.py:242 · _serialize_event() 统一把事件负载序列化成 SSE data: 块。
  • graduation-design/frontend/src/types/chat.ts:139 · ChatStreamEventType 定义前端可识别的事件类型集合。
  • latex/final.tex:631 · 论文说明主链路采用 SSE 的原因。
“SSE 就像后端边处理边递小纸条:每张纸条都有 type,前端只要按 type 合并状态,就能把长链路变成可观察进度。”
02

运行时上下文与 Prompt 产物总线

Runtime and artifacts bus
Runtime Artifacts MemoryBroker
【核心概念与设计初衷】

主链路把一次问答拆成运行时上下文和 Prompt 产物两类对象。ChatStreamRuntime 保存会话、记录、LLM 配置、历史上下文和有效问题;ChatPromptArtifacts 保存选库、Schema、值证据、知识增强、SQL Plan 和最终 Prompt。这样后续 SQL 生成、修复、日志记录可以复用同一份上下文,避免各阶段重复检索和口径漂移。

【算法逻辑与控制流向】
  1. Input:已创建的 ChatRecord、前端请求、当前会话和模型配置。
  2. 创建 ChatStreamRuntime,保存原问题、历史问答、历史 SQL case、LLM client 和 effective_question
  3. 进入检索增强阶段,创建 SQLGenerationMemoryBroker 作为上下文绑定器。
  4. 依次绑定 Schema、Value Grounding、术语、领域记忆、SQL 样例、问题分解和 SQL Plan。
  5. 构造 ChatPromptArtifacts,把 prompt messages、强值证据表、值候选、SQL Plan 和数据源配置一起交给下游。
  6. Output:生成阶段和修复阶段都围绕同一份 artifacts 工作。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/service.py:110 · ChatStreamRuntime 定义一次流式问答运行期上下文。
  • graduation-design/backend/chat/service.py:134 · ChatPromptArtifacts 定义 SQL 生成前的检索增强产物。
  • graduation-design/backend/chat/service.py:154 · ChatExecutionOutcome 封装执行阶段最终结果和修复状态。
  • graduation-design/backend/chat/service.py:1546 · _collect_stream_prompt_artifacts() 汇总 Schema、值证据、知识和 SQL Plan。
  • graduation-design/backend/chat/service.py:1632 · 通过 memory broker 构造最终 SQL Prompt 上下文。
“主链路不是每一步各查各的,而是先把本轮问答的上下文装进一个运行时背包,后面的生成、修复、日志都从这个背包里取材料。”
03

ChatService 主编排控制流

End-to-end orchestration
Pipeline Orchestration NL2SQL
【核心概念与设计初衷】

stream_chat() 是智能问答主链路的总调度器。它不直接让模型回答问题,而是按固定顺序完成记录创建、问题改写、数据源解析、Schema-RAG、值证据、知识增强、问题分解、SQL Plan、SQL 生成、校验执行、结果保存和完成事件推送。

【算法逻辑与控制流向】
  1. Input:ChatAskRequest(chat_id, question, evidence)
  2. 校验问题非空,创建 ChatRecord,注册取消事件。
  3. 创建运行时上下文,执行问题改写,解析目标数据源。
  4. 收集 Prompt artifacts:Schema、值证据、术语、领域记忆、SQL 样例、分解结果和 SQL Plan。
  5. 调用模型生成 SQL,并在生成后执行确定性语义修补。
  6. 保存 SQL 生成结果,推送 sql_generated
  7. 进入 Guard、执行、语义验证和可选修复链路。
  8. 保存查询结果,推送 query_result,标记记录完成,最后推送 done
  9. Output:一串 SSE 字符串迭代器,可被 FastAPI 直接流式返回。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/service.py:2106 · stream_chat() 是完整问答主链路入口。
  • graduation-design/backend/chat/service.py:2127 · 创建本轮 ChatRecord
  • graduation-design/backend/chat/service.py:2137:2140 · 改写问题、解析数据源并收集 Prompt artifacts。
  • graduation-design/backend/chat/service.py:2141:2177 · 生成 SQL、保存并推送 sql_generated
  • graduation-design/backend/chat/service.py:2179:2202 · 执行 SQL 并推送 query_result
  • graduation-design/backend/chat/service.py:2221 · 推送 done 终止事件。
  • latex/final.tex:635 · 论文算法描述主链路整体过程。
“ChatService 是总导演:用户只看到一次提问,但后台按剧本依次完成改写、检索、生成、校验、执行和收尾。”
04

ChatRecord 与 ChatLog 双账本

Persistent record and step ledger
Record Log Trace
【核心概念与设计初衷】

主链路同时维护两套持久化对象:ChatRecord 记录本轮问答的最终状态、SQL、结果和错误;ChatLog 记录每个阶段的输入、输出、耗时、模型名、Token 和错误状态。前者服务用户回看,后者服务答辩中的可追踪性和问题定位。

【算法逻辑与控制流向】
  1. Input:会话、用户问题、阶段名称、阶段输入输出。
  2. 问题开始时创建 ChatRecord,状态从 pending/running 逐步变为 completed、failed 或 cancelled。
  3. 每个阶段开始时调用 start_log() 记录 prompt 或本地操作输入。
  4. 阶段结束时调用 finish_log() 写入响应、用量、完成时间和错误标记。
  5. SQL 生成后写入 sql_textsql_answer、命中表和图表建议。
  6. SQL 执行后写入结构化 data_json;链路成功后 finish_record() 标记完成。
  7. Output:页面可展示最终结果,后台可展开阶段日志复盘每一步。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/models.py:21 · ChatLogStep 定义完整阶段枚举。
  • graduation-design/backend/chat/models.py:111 · ChatRecord 是本轮问答记录表。
  • graduation-design/backend/chat/models.py:166 · ChatLog 是步骤日志表。
  • graduation-design/backend/chat/repository.py:382 · create_chat_record() 创建问答记录。
  • graduation-design/backend/chat/repository.py:618 / :658 · start_log()finish_log() 记录阶段日志。
  • graduation-design/backend/chat/repository.py:713 / :751 / :878 · 保存 SQL、查询结果并标记记录完成。
“SSE 负责实时给用户看进度,ChatRecord 和 ChatLog 负责事后能复盘:这一轮问答最终是什么结果,每一步为什么这么走。”
05

SQL 生成流式输出与结构化落库

Streaming SQL generation
LLM Chunk SQL
【核心概念与设计初衷】

SQL 生成阶段既要调用大模型,又要让前端尽早看到模型输出。系统先发送 generate_sql 阶段事件,再调用 LLM 得到结构化回答;若开启 stream_answer_chunks,会把模型原始回答切成 sql_answer_chunk 逐段推送,最后再发送解析后的 sql_generated 事件。

【算法逻辑与控制流向】
  1. Input:Prompt messages、LLM client、模型配置、当前 record id、取消事件。
  2. 开始 generate_sql 日志,标记 record running,推送 stage
  3. 调用 complete_text_with_control(),并注入取消控制。
  4. 解析模型响应为 SQLGenerationResult,若失败则记录错误并抛出。
  5. 成功后保存日志;若需要流式展示,则用 _chunk_text() 生成 sql_answer_chunk
  6. 对 SQL 做确定性语义修补,保存 SQL、表名、图表类型和标题摘要。
  7. Output:sql_generated 事件,携带 sqltableschart_typebrief
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/service.py:1651 · _stream_sql_generation_step() 封装生成/修复阶段的模型调用。
  • graduation-design/backend/chat/service.py:1675:1688 · 标记运行中、推送阶段事件并调用 LLM。
  • graduation-design/backend/chat/service.py:1700:1702 · 解析并校验模型返回的 SQL 结构。
  • graduation-design/backend/chat/service.py:1719:1722 · 将模型回答切成 sql_answer_chunk
  • graduation-design/backend/chat/service.py:2151:2177 · 修补、落库并推送 sql_generated
“前端看到的 SQL 不是一次性跳出来的:模型原文可以先分块流出,解析确认后的 SQL 再作为正式结果事件落库和展示。”
06

查询结果返回、完成态与主链路边界

Query result and completion boundary
Result Done Boundary
【核心概念与设计初衷】

主链路的核心闭环到 query_resultdone 为止:它负责返回可执行 SQL 的查询结果,而图表生成、解释生成和推荐追问属于后处理能力,可以在记录完成后按需调用。这个边界减少主链路阻塞,保证用户先拿到数据库查询结果。

【算法逻辑与控制流向】
  1. Input:_execute_sql_with_optional_repair() 返回的执行结果。
  2. 构造 query_payload:执行 SQL、字段、行数据、行数、是否截断、耗时。
  3. 调用 save_query_result() 写入问答记录。
  4. 推送 query_result,前端可以立即渲染结果表格。
  5. 标记 record completed,并尝试沉淀 SQL Experience candidate;候选沉淀失败不阻塞主回答。
  6. 推送 done,告诉前端本轮流式问答结束。
  7. Output:完成态记录 + 可渲染查询结果;图表和解释留给后处理接口。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/service.py:2179 · 执行 Guard/SQL/语义验证/修复闭环。
  • graduation-design/backend/chat/service.py:2193:2202 · 构造并推送 query_result
  • graduation-design/backend/chat/service.py:2204 · finish_record() 标记问答完成。
  • graduation-design/backend/chat/service.py:2205:2220 · 成功结果进入 SQL Experience 候选队列,但不阻塞完成事件。
  • graduation-design/tests/test_chat_async_fast_path.py:97 · 测试主流在 query_result 后完成,不在主流里生成图表和解释。
“主链路先保证 SQL 和结果表闭环,图表、解释、推荐追问是结果之后的附加处理,不拖慢用户拿到查询结果。”
07

取消请求与错误事件收敛

Cancellation and error convergence
Cancel Error Abort
【核心概念与设计初衷】

取消与错误收敛机制保证长链路可中断、失败可落库、前端可感知。前端有本地 AbortController 和停止按钮,后端有会话级取消事件;无论是用户手动终止、模型取消、SQL 校验失败还是数据库错误,最终都会通过 error 事件反馈前端,并写入记录状态。

【算法逻辑与控制流向】
  1. Input:前端点击“停止”或后端任一阶段抛出异常。
  2. 问答开始时后端调用 begin_chat_stream(chat_id, record_id) 注册取消事件。
  3. 前端停止时调用 stop 接口;后端设置对应 Event,并把记录标记为 cancelling。
  4. 主链路在模型调用、分块推送、阶段切换时检查取消事件,触发 ChatCancelledError
  5. 取消异常写入 cancelled 状态;普通异常写入 failed 状态。
  6. 两类失败都向前端推送 error,finally 中清理取消事件,避免污染下一轮问答。
  7. Output:前端草稿显示错误/取消信息,后端记录进入可追踪终态。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/cancellation.py:35 · begin_chat_stream() 为会话注册取消事件。
  • graduation-design/backend/chat/cancellation.py:46 · request_chat_stop() 设置取消标记。
  • graduation-design/backend/chat/router.py:154 · stop_chat_question() 暴露停止接口。
  • graduation-design/backend/chat/service.py:2227:2248 · 取消和异常统一落库并推送 error
  • graduation-design/frontend/src/views/chat/ChatView.vue:1964 · stopStreaming() 前端停止当前流式问答。
  • graduation-design/tests/test_chat_async_fast_path.py:513 · 测试停止请求和取消状态落库。
“取消不是前端把请求断掉就算了,而是前后端共同标记同一条 record,让用户界面和数据库记录都知道这轮被终止。”
08

前端 SSE 读取与事件解析

Frontend stream parser
Frontend Parser Buffer
【核心概念与设计初衷】

前端没有使用浏览器 EventSource,而是用 fetch + ReadableStream 手动读取流。这样可以携带 Bearer Token、复用现有鉴权封装,并通过 AbortController 控制当前请求中断。

【算法逻辑与控制流向】
  1. Input:ChatAskPayload、事件回调、可选 AbortController
  2. 使用 fetch() POST 到 /chat/ask,请求头携带 JSON 和 Authorization。
  3. response.body.getReader() 获取流读取器,使用 TextDecoder 增量解码。
  4. 把每次读到的文本追加进 buffer,用空行 \n\n 切分完整 SSE block。
  5. 保留未完整的 rest 到下一次读取,避免网络分片导致 JSON 半截解析。
  6. 对每个 block 提取 data: 行,JSON parse 成 ChatStreamEvent
  7. Output:逐条调用 callbacks.onEvent(event),交给页面状态 reducer。
【代码精准溯源 (Code Anchor)】
  • graduation-design/frontend/src/api/chat.ts:183 · askStream() 发起流式问答请求。
  • graduation-design/frontend/src/api/chat.ts:188:196 · 使用 fetch 携带 token、payload 和 abort signal。
  • graduation-design/frontend/src/api/chat.ts:211:240 · 读取 ReadableStream、解码、切块并回调事件。
  • graduation-design/frontend/src/api/sse.ts:12 · extractSseBlocks() 处理 CRLF 归一化和半包缓存。
  • graduation-design/frontend/src/api/sse.ts:24 · parseSseEventBlock() 提取 data: 并解析 JSON。
“前端读 SSE 的关键不是一次读完,而是维护 buffer:完整事件立刻处理,半截事件留到下一包再拼。”
09

前端运行态、草稿合并与阶段进度

Frontend reducer and progress state
Reducer Draft Progress
【核心概念与设计初衷】

前端用 ChatRunStateChatStreamDraft 表示“正在生成中的临时问答记录”。SSE 事件不会直接操作页面 DOM,而是先进入 applyChatStreamEvent() reducer,把 SQL、Schema、结果、错误和阶段进度合并到草稿对象,再由 Vue 响应式系统驱动界面更新。

【算法逻辑与控制流向】
  1. Input:用户提交问题后创建的本地草稿、后端持续返回的 ChatStreamEvent
  2. createStreamDraft() 初始化 question、datasource、schema、sql、result、stages、finished 等字段。
  3. startChatRun() 把草稿放入按 chatId 索引的 reactive registry,并设置 sending。
  4. 每条事件进入 appendChatRunEvent(),再由 applyChatStreamEvent() 按 type 合并。
  5. stage 追加阶段日志,schema_ready 更新 Schema,sql_answer_chunk 追加模型文本,sql_generated 更新 SQL,query_result 写入结果。
  6. doneerror 把草稿标记 finished;流结束后 markChatRunNeedsHydration() 触发详情补齐。
  7. buildStageProgress() 根据已遇到的阶段生成 done/active/pending 状态。
  8. Output:页面可实时显示阶段条、SQL、结果表和错误状态。
【代码精准溯源 (Code Anchor)】
  • graduation-design/frontend/src/types/chat.ts:153 · ChatStreamEvent 定义 SSE 事件负载字段。
  • graduation-design/frontend/src/types/chat.ts:189 · ChatStreamDraft 定义流式草稿状态。
  • graduation-design/frontend/src/views/chat/chatRunControl.ts:11 · ChatRunState 定义运行态、取消控制器和补齐标记。
  • graduation-design/frontend/src/views/chat/chatRunControl.ts:154 · applyChatStreamEvent() 是事件 reducer。
  • graduation-design/frontend/src/views/chat/chatViewLogic.ts:156 · buildStageProgress() 生成阶段进度条状态。
  • graduation-design/frontend/src/views/chat/ChatView.vue:1887:1918 · 提交问题后创建草稿、注册控制器并启动 SSE。
  • graduation-design/frontend/src/views/chat/ChatView.vue:1985 · handleStreamEvent() 把事件合并到当前会话并处理选库、标题和滚动。
“前端不是猜后端跑到哪一步,而是把后端推来的事件当成状态变更日志,一条条 reduce 成当前问答草稿。”

图表、解释与推荐问题后处理

本知识域回答一个核心问题:SQL 已执行成功后,系统如何把结构化结果继续转成可视化图表、自然语言解释和下一轮可点击问题,同时不影响主查询链路的稳定性。

论文原图:图表生成结果
论文原图 · 图表生成结果 用于回答“为什么图表属于后处理”:主链路先返回 SQL 与结果表,随后记录级图表接口基于已执行结果生成可切换、可导出的可视化配置。

读图顺序

  1. 图中展示的是结果表之后的可视化区域,说明系统先完成数据库查询,再基于字段、样例数据和推荐图表类型生成图表配置。
  2. 图表不是把 SQL 重新执行一遍,而是消费已落库的 data_jsonsql_text、字段列表和样例行。
  3. 前端根据统一图表配置渲染柱状图、条形图、折线图、饼图或表格,并支持切换、全屏和导出。
  4. 如果图表模型失败,后端会用本地字段启发式生成兜底图表或表格配置,因此后处理失败不会破坏已经完成的问答结果。

代码对应:backend/chat/service.py 的记录级接口读取结果上下文,backend/services/chart_service.py 生成或兜底图表配置,frontend/src/views/chat/chat-block/ChartBlock.vuefrontend/src/views/chat/component/normalize.ts 负责前端规范化与渲染。

答辩讲法:SQL 是“查出数据”,后处理是“把数据讲清楚、画出来、引导继续问”,三者解耦能保证主查询先稳定完成。

01

结果后处理层的定位与边界

Post-processing boundary
Postprocess Optional UX
【核心概念与设计初衷】

图表、解释和推荐问题属于 SQL 执行成功后的结果后处理层。它们不参与 SQL 正确性判定,也不决定数据库是否执行,而是把已经得到的结构化结果转化为更适合用户阅读和继续探索的交互产物。这样可以让主链路先稳定返回 SQL 与结果表,再按需补充可视化、总结和追问。

后处理产物 输入 输出 失败影响
图表 SQL、字段、行数据、Schema、推荐图表类型。 前端可渲染图表配置。 回退表格或本地图表,不影响结果表。
解释 问题、SQL、字段、结果预览。 中文结果总结。 返回本地兜底解释。
推荐问题 数据源 Schema 或当前问答结果。 起始问题或追问列表。 返回缓存、手工配置或本地兜底。
【算法逻辑与控制流向】
  1. Input:已经 completed 的 ChatRecord,其中包含 sql_textdata_jsonsuggested_chart_type、命中表和结果字段。
  2. 前端展示主查询结果后,根据记录状态按需触发图表、解释和推荐问题接口。
  3. 后端先读取缓存;若缓存存在且未强制刷新,直接返回。
  4. 缓存缺失时,后端从记录中解析执行结果上下文,再调用对应服务。
  5. 服务调用模型时只消费结果预览,不重新决定 SQL 生成逻辑。
  6. 若模型失败,各服务使用本地降级策略生成可展示内容。
  7. Output:图表配置、解释文本或推荐问题列表,并保存到记录或推荐问题表中。
【代码精准溯源 (Code Anchor)】
  • latex/final.tex:820 · 论文说明功能测试在问答记录生成后补充调用图表与解释接口。
  • graduation-design/backend/chat/models.py:31:60 · ChatLogStepgenerate_chartgenerate_analysisgenerate_recommended_questions 定义为独立步骤。
  • graduation-design/backend/chat/models.py:123:151 · ChatRecord 保存图表、解释和推荐问题字段。
  • graduation-design/backend/chat/router.py:250 · 记录级图表接口 /record/{record_id}/chart
  • graduation-design/backend/chat/router.py:264 · 记录级解释接口 /record/{record_id}/analysis
  • graduation-design/backend/chat/router.py:188 · 记录级推荐追问接口 /record/{record_id}/recommend_questions
“主链路负责把数据查准,后处理负责把结果讲清楚、画出来、引导下一问;后处理失败也不能拖垮主答案。”
02

记录级后处理上下文与缓存复用

Record postprocess context and cache
Record Cache Context
【核心概念与设计初衷】

记录级后处理上下文是图表、解释和推荐追问共同依赖的基础数据包。它从已经落库的问答记录中读取结果字段、结果行和已执行 SQL,确保后处理基于同一份执行结果,而不是重新调用 SQL 生成或重新访问不确定上下文。缓存复用则避免重复调用模型,提高页面二次打开和刷新时的响应速度。

【算法逻辑与控制流向】
  1. Input:record_id 与 force_refresh 参数。
  2. 先通过 _get_owned_record() 校验记录存在性与访问权限。
  3. 如果图表或解释缓存存在且未强制刷新,则直接返回 source=cache
  4. 缓存缺失时,_resolve_record_postprocess_context() 解析 data_json
  5. 从结果 payload 中提取 rowsfieldsexecuted_sql;SQL 优先取执行结果中的 SQL,兜底取 record.sql_text
  6. 如果 SQL 缺失或结果格式不合法,则抛出错误,拒绝做无依据后处理。
  7. Output:后处理服务可直接使用的 rows、fields、executed_sql 和记录对象。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/service.py:650 · _resolve_record_postprocess_context() 读取记录级结果上下文。
  • graduation-design/backend/chat/service.py:668 · get_record_chart() 先读缓存再生成图表。
  • graduation-design/backend/chat/service.py:750 · get_record_analysis() 先读解释缓存再生成解释。
  • graduation-design/backend/chat/service.py:820 · get_recommended_questions() 生成或读取追问推荐。
  • graduation-design/backend/chat/repository.py:780 · save_chart_result() 保存图表原始回答与图表 JSON。
  • graduation-design/backend/chat/repository.py:812 · save_analysis_result() 保存解释文本。
  • graduation-design/backend/chat/repository.py:836 · save_recommended_questions() 保存记录级推荐追问。
“后处理只消费已经落库的记录结果,就像在同一份查询报告上补图表和摘要,不会重新改写原始 SQL。”
03

图表生成服务主流程

Chart generation pipeline
Chart Prompt Cache
【核心概念与设计初衷】

图表生成服务把 SQL 执行结果转成前端 G2 图表可消费的配置对象。它既尊重 SQL 生成阶段给出的 suggested_chart_type,又会根据实际字段结构进行二次判断和本地规范化,防止模型推荐的图表类型与查询结果不匹配。

【算法逻辑与控制流向】
  1. Input:record_id、问题、已执行 SQL、结果字段、结果行、推荐图表类型。
  2. 如果 suggested_chart_typetable,标记为本地操作,不调用 LLM。
  3. 如果需要图形化,重新基于记录问题检索相关 Schema,并结合已执行 SQL 与声明表构建图表用 Schema 文本。
  4. 创建 generate_chart 阶段日志,记录 question、sql、schema、fields、recommended_chart_type 和 force_refresh。
  5. 调用 generate_chart(),传入默认 LLM 配置和 Prompt Override Profile。
  6. 完成后保存 chart_answerchart_json
  7. Output:ChatChartRead,包含 record_id、source 和 chart 配置。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/chat/service.py:668 · get_record_chart() 是记录级图表入口。
  • graduation-design/backend/chat/service.py:678 · 读取 chart_json 缓存。
  • graduation-design/backend/chat/service.py:683 · 当推荐类型为 table 时设置 local_operation
  • graduation-design/backend/chat/service.py:686:699 · 图表需要模型时重新构造图表用 Schema。
  • graduation-design/backend/chat/service.py:720 · 调用 generate_chart()
  • graduation-design/backend/services/chart_service.py:732 · generate_chart() 执行图表配置生成。
  • graduation-design/backend/chat/models.py:292 · ChatChartRead 定义图表接口响应。
“图表不是前端拍脑袋画的,而是后端基于 SQL、字段、样例数据和推荐类型生成一份可校验配置。”
04

图表配置数据契约与字段规范化

Chart config normalization
Axis Field Contract
【核心概念与设计初衷】

图表配置契约要求所有图表字段必须来自 SQL 查询结果字段或别名,不能让模型臆造坐标轴。后端用大小写无关字段映射、轴配置规范化和旧格式兼容逻辑,把模型输出统一转成前端可消费的 type/chart_type/title/axis/dimension/metrics/series/reason 结构。

图表类型 必要字段 典型场景
table columns 明细表、文本列多、无法图形化。
column/bar/line axis.x + axis.y 维度 + 指标,趋势或对比。
pie axis.series + axis.y 占比、构成、份额。
multi-quota 多个 y 指标,无 series。 同一维度下多指标并列比较。
【算法逻辑与控制流向】
  1. Input:模型返回的图表 payload、问题、字段列表、结果行和推荐类型。
  2. 构建 field_lookup,把反引号、引号、方括号包裹的字段名统一清洗后小写匹配。
  3. 识别 typechart_type,不在支持集合内则回退为 table。
  4. 如果 payload 是旧格式的 dimension/metrics/series,先转换成新版 axis
  5. xyseriesmulti-quota 逐一校验字段是否真实存在。
  6. 如果必要轴字段缺失,则回退为表格配置,并写入 reason。
  7. Output:字段可映射、类型合法、前端可渲染的图表配置。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/chart_service.py:26 · SUPPORTED_CHART_TYPES 限定 table、column、bar、line、pie。
  • graduation-design/backend/services/chart_service.py:54 · _normalize_identifier() 清洗字段标识符。
  • graduation-design/backend/services/chart_service.py:71 · _build_field_lookup() 构建字段映射。
  • graduation-design/backend/services/chart_service.py:95 · _make_field_config() 生成标准字段配置。
  • graduation-design/backend/services/chart_service.py:282 · _build_axis_from_legacy_payload() 兼容旧版图表结构。
  • graduation-design/backend/services/chart_service.py:439 · _normalize_axis_payload() 规范化轴配置。
  • graduation-design/backend/services/chart_service.py:507 · _normalize_chart_payload() 转换最终图表配置。
  • graduation-design/backend/prompts/template.yaml:342 · 图表 Prompt 明确要求所有 value 必须来自查询结果字段。
“图表配置里的每个坐标轴字段都要能在查询结果里对上号,对不上就回退,不能让模型凭空造字段。”
05

图表本地兜底、类型修正与排序语义

Fallback, type correction and sort order
Fallback Sort Heuristic
【核心概念与设计初衷】

图表后处理必须保证“有可展示结果”,因此模型失败、字段不匹配、图表结构不成立时,系统会基于字段类型和样例行生成本地兜底图表或表格。同时,系统会修正容易误导的图表类型,例如折线图遇到重复维度时回退为柱状图,避免把非时间序列误画成连续趋势。

【算法逻辑与控制流向】
  1. Input:字段列表、结果行、问题文本、推荐图表类型和可选 SQL。
  2. 若推荐类型为 table,直接生成 local_table 配置,token 用量为 0。
  3. 若 LLM 失败,_build_fallback_chart() 先判断是否有字段和行数据。
  4. 识别数值字段、时间字段和维度候选;没有数值或维度时回退表格。
  5. 有“占比/比例/构成/份额”语义时优先饼图;时间维度优先折线图;普通维度优先柱状图。
  6. 如果折线图维度存在重复值,则改为柱状图并追加 reason。
  7. 排序语义由 _resolve_chart_sort_order() 决定:时间趋势可按 chronological,排行类保留结果顺序。
  8. Output:source=local_tablegeneratedlocal_fallback 的可展示图表结果。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/chart_service.py:47 · _should_skip_chart_llm() 判断 table 推荐是否跳过 LLM。
  • graduation-design/backend/services/chart_service.py:115 · _parse_numeric_value() 解析数值单元格。
  • graduation-design/backend/services/chart_service.py:137 · _is_numeric_field() 判断数值字段。
  • graduation-design/backend/services/chart_service.py:152 · _is_time_like_field() 判断时间字段。
  • graduation-design/backend/services/chart_service.py:187 · _build_series_count_chart_override() 处理两个维度加计数指标的分组图。
  • graduation-design/backend/services/chart_service.py:389 · _resolve_chart_sort_order() 计算 result 或 chronological 排序语义。
  • graduation-design/backend/services/chart_service.py:419 · _has_duplicate_dimension_values() 检测重复维度值。
  • graduation-design/backend/services/chart_service.py:640 · _build_fallback_chart() 生成本地兜底图表配置。
“图表生成有安全网:模型画不出来,系统就按字段类型自己兜底;折线图会误导时也会自动退回柱状图。”
06

前端图表规范化、渲染与导出链路

Frontend chart rendering
Frontend G2 Export
【核心概念与设计初衷】

前端图表链路负责把后端图表配置与结果表数据再次规范化为可渲染结构,并提供图表类型切换、标签开关、PNG 导出、CSV 导出和全屏查看。前端仍会校验字段映射与可用图表类型,避免历史配置或旧格式数据导致页面渲染异常。

【算法逻辑与控制流向】
  1. Input:后端返回的 ChatChartConfig 与当前记录的 ChatResultData
  2. ChartBlock 调用 normalizeChartConfig(),把后端配置和结果行合并成统一结构。
  3. 如果后端返回 table 但结果满足“两个维度 + 一个计数指标”,前端也会构建分组图轴配置。
  4. 根据 axis 判断可切换图表类型,至少保留 table;有 y 轴且有 x 或 series 时允许 column、bar、line、pie。
  5. DisplayChartBlock 根据当前类型调用 ChartComponent
  6. loadChartInstance() 动态加载 Column、Bar、Line、Pie 实现,减少首屏负担。
  7. 用户可切换图表类型、显示标签、导出 PNG、导出 CSV、全屏或查看完整表格。
  8. Output:同一份结果数据的多种展示方式。
【代码精准溯源 (Code Anchor)】
  • graduation-design/frontend/src/views/chat/chat-block/ChartBlock.vue:31 · 调用 normalizeChartConfig() 规范化后端图表配置。
  • graduation-design/frontend/src/views/chat/chat-block/ChartBlock.vue:57 · 计算可切换图表类型。
  • graduation-design/frontend/src/views/chat/chat-block/ChartBlock.vue:63 · exportImage() 导出 PNG。
  • graduation-design/frontend/src/views/chat/chat-block/ChartBlock.vue:76 · exportCsv() 导出 CSV。
  • graduation-design/frontend/src/views/chat/component/normalize.ts:586 · normalizeChartConfig() 统一字段、坐标轴、排序和可用类型。
  • graduation-design/frontend/src/views/chat/component/normalize.ts:520 · adaptAxesForType() 根据图表类型重排坐标轴。
  • graduation-design/frontend/src/views/chat/component/BaseChart.ts:16 · 前端支持的图表类型枚举。
  • graduation-design/frontend/src/views/chat/component/index.ts:18 · loadChartInstance() 按需加载图表实现。
“后端给的是图表配置,前端再把它和真实结果表对齐,最终才交给 G2 渲染和导出。”
07

结果解释生成与本地兜底文本

Explanation generation
Analysis LLM Fallback
【核心概念与设计初衷】

结果解释模块负责把查询结果转成简洁中文结论,帮助用户理解结果表和图表表达的含义。它只解释当前结果,不重新推断业务背景,也不替代 SQL 校验。为了保证展示稳定,模型失败或空输出时会返回本地兜底文本。

【算法逻辑与控制流向】
  1. Input:问题、已执行 SQL、字段列表和查询结果行。
  2. 记录级接口先检查 record.analysis 缓存;未强刷且存在缓存时直接返回。
  3. generate_explanation() 截取前 CHAT_RESULT_PREVIEW_LIMIT 行作为结果预览。
  4. 通过 build_analysis_messages() 构造解释 Prompt,要求 3 到 6 句话、只解释当前结果、不编造背景。
  5. 调用默认 LLM,温度为 0.2,最大 token 为 700。
  6. 如果模型返回非空文本,则保存到 record.analysis
  7. 如果模型异常或为空,_build_fallback_explanation() 根据行数和字段构造本地中文解释。
  8. Output:ChatAnalysisRead,包含 record_id、source 和 analysis 文本。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/explanation_service.py:22 · ExplanationGenerationResult 定义解释结果对象。
  • graduation-design/backend/services/explanation_service.py:37 · _build_fallback_explanation() 构造空结果和普通结果的兜底解释。
  • graduation-design/backend/services/explanation_service.py:62 · generate_explanation() 调用模型生成解释。
  • graduation-design/backend/services/prompt_builder.py:231 · AnalysisPromptContext 定义解释 Prompt 上下文。
  • graduation-design/backend/services/prompt_builder.py:1195 · build_analysis_messages() 构建解释消息。
  • graduation-design/backend/prompts/template.yaml:395 · 解释 Prompt 要求只解释当前结果,空结果要说明未查询到数据。
  • graduation-design/backend/chat/service.py:750 · get_record_analysis() 是记录级解释入口。
  • graduation-design/backend/chat/models.py:305 · ChatAnalysisRead 定义解释接口响应。
“解释模块只给已查询结果写摘要,不重新创造事实;模型失败时也能用行数和字段生成稳定兜底说明。”
08

推荐问题数据契约、解析与过滤

Recommendation parsing and filtering
Recommendation Parser Retry
【核心概念与设计初衷】

推荐问题模块为用户提供可直接点击的后续自然语言问题。它的关键不是生成一段说明,而是稳定得到一个问题数组,因此代码把模型输出限定为 <json-array>[...]</json-array>,并提供结构化解析、嵌入式问题提取、行级兜底、去重、长度过滤和重试机制。

【算法逻辑与控制流向】
  1. Input:system prompt、user prompt、limit、候选池大小和 force_refresh。
  2. 模型调用要求返回 <json-array> 包裹的问题列表。
  3. _parse_question_array() 优先用结构化解析器读取数组,也兼容 questions/items/recommendations 字段。
  4. 如果结构化解析失败,尝试从引号包裹内容或逐行文本中提取问题。
  5. _normalize_question_list() 清理编号、项目符号、空白、过短文本和重复项,并截断到 200 字以内。
  6. 若第一次模型输出不可解析,第二次追加 retry hint,要求只返回可解析 JSON 数组。
  7. force_refresh 时使用随机 variant_seed 从候选池轮换展示,避免刷新后还是同一组问题。
  8. Output:RecommendationResult,包含 source、questions、raw_answer 和 usage。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/recommendation_service.py:63 · RecommendationResult 定义推荐问题结果对象。
  • graduation-design/backend/services/recommendation_service.py:180 · _normalize_question_list() 清洗、去重并截断问题列表。
  • graduation-design/backend/services/recommendation_service.py:213 · _select_question_batch() 从候选池选择当前展示批次。
  • graduation-design/backend/services/recommendation_service.py:237 · _extract_embedded_question_items() 从非标准文本中提取问题项。
  • graduation-design/backend/services/recommendation_service.py:264 · _parse_question_array() 解析模型返回的问题数组。
  • graduation-design/backend/services/recommendation_service.py:966 · _generate_questions_with_llm() 执行 LLM 调用、解析、重试和轮换。
  • graduation-design/backend/core/config.py:135:138 · 推荐问题数量、候选池大小、token 和重试次数配置。
“推荐问题不是让模型随便写建议,而是必须返回可解析的问题数组,再由系统清洗、去重、过滤和兜底。”
09

数据源起始推荐问题:手工与自动双模式

Starter question recommendation
Starter Schema Digest Cache
【核心概念与设计初衷】

数据源起始推荐问题用于聊天空状态或切换数据源时引导用户提问。它支持手工维护和自动生成两种模式:手工模式适合演示和业务强控制,自动模式根据数据源 Schema 摘要生成问题,并把 LLM 成功结果短期缓存,fallback 只用于当前响应,不污染数据库。

【算法逻辑与控制流向】
  1. Input:datasource、current_user、limit 和 force_refresh。
  2. 如果 recommended_config == 2,读取 DatasourceRecommendedProblem 中人工维护的问题。
  3. 自动模式先从缓存读取 remark 为 __AUTO_GENERATED__ 的推荐问题,并检查 TTL 是否新鲜。
  4. 缓存缺失或强制刷新时,构建 Schema Digest:按关系度、注释质量、时间字段和字段数量挑选核心表。
  5. LLM 根据数据源名称、说明、类型和 Schema 摘要生成候选问题。
  6. 过滤“有哪些表、表结构、推荐几个问题”等泛泛元问题。
  7. 只有 source=llm 的成功结果会落库,fallback 当前返回但不保存。
  8. Output:DatasourceRecommendedQuestionsRead,包含 datasource_id、source 和 questions。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/recommendation_service.py:292 · _extract_relation_degree_map() 根据关系图统计表连接度。
  • graduation-design/backend/services/recommendation_service.py:728 · _collect_schema_digest_candidates() 收集 starter Schema 摘要候选表。
  • graduation-design/backend/services/recommendation_service.py:795 · _build_schema_digest() 构造推荐问题使用的 Schema 摘要。
  • graduation-design/backend/services/recommendation_service.py:825 · _build_manual_questions() 读取手工推荐问题。
  • graduation-design/backend/services/recommendation_service.py:879 · _build_fallback_starter_questions() 构造本地起始推荐兜底问题。
  • graduation-design/backend/services/recommendation_service.py:1148 · _generate_datasource_recommended_questions() 调用 LLM 生成起始推荐问题。
  • graduation-design/backend/services/recommendation_service.py:1213 · refresh_datasource_recommended_question_cache() 刷新自动推荐缓存。
  • graduation-design/backend/services/recommendation_service.py:1271 · get_datasource_recommended_questions() 获取手工、缓存或新生成问题。
  • graduation-design/backend/datasource/router.py:245 · 数据源起始推荐问题接口。
“起始推荐相当于给数据源准备开场白:手工模式可控,自动模式按 Schema 摘要生成,失败也有本地兜底。”
10

问答后追问推荐与空结果恢复

Follow-up recommendation and recovery
Follow-up Recovery Record Cache
【核心概念与设计初衷】

问答后追问推荐基于当前问题、执行 SQL、命中表、结果字段、结果预览、Schema 摘要和最近成功问题生成下一步分析方向。它还特别处理空结果场景:当查询成功但返回 0 行时,不继续沿用失败筛选条件下钻,而是推荐确认时间范围、可用枚举值和放宽条件的恢复型问题。

【算法逻辑与控制流向】
  1. Input:当前 ChatRecord、数据源、用户、结果数据、limit 和 force_refresh。
  2. 读取 record.data_json,判断 row_count 是否为空结果。
  3. 非空结果且已有记录级推荐缓存时,直接返回 source=cache
  4. 空结果时,调用 _generate_empty_result_follow_up_questions(),Prompt 要求生成排查或放宽筛选条件的问题。
  5. 空结果过滤器会剔除继续机械复用失败年份的追问,除非追问本身是确认该条件是否存在。
  6. 非空结果时,构造包含原问题、SQL、命中表、字段、结果预览、Schema 摘要和最近问题的 Prompt。
  7. LLM 失败时,非空结果基于当前字段和样例行生成拆分、趋势、Top/尾部对比等兜底追问;空结果生成恢复型兜底追问。
  8. 只有 source=llm 的追问会保存到 record.recommended_questions_json
  9. Output:ChatRecommendedQuestionsRead,前端可作为下一轮输入按钮。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/services/recommendation_service.py:74 · _extract_year_literals() 提取失败筛选中的年份字面量。
  • graduation-design/backend/services/recommendation_service.py:99 · _filter_empty_result_questions() 过滤空结果场景下继续沿用失败条件的问题。
  • graduation-design/backend/services/recommendation_service.py:620 · _build_result_fallback_questions() 基于当前结果字段生成追问兜底。
  • graduation-design/backend/services/recommendation_service.py:678 · _build_empty_result_recovery_questions() 构造空结果恢复型兜底追问。
  • graduation-design/backend/services/recommendation_service.py:1043 · _list_recent_questions_for_recommendation() 获取最近成功且非空的问题。
  • graduation-design/backend/services/recommendation_service.py:1066 · _generate_empty_result_follow_up_questions() 生成空结果恢复型追问。
  • graduation-design/backend/services/recommendation_service.py:1323 · get_follow_up_recommended_questions() 是记录级追问推荐主入口。
  • graduation-design/backend/chat/service.py:820 · get_recommended_questions() 记录日志、调用服务并保存 LLM 成功结果。
  • graduation-design/backend/chat/models.py:282 · ChatRecommendedQuestionsRead 定义推荐追问响应。
“追问推荐不是简单续写问题;空结果时它会先引导用户排查筛选条件,而不是继续在错误条件上越钻越深。”
11

前端后处理懒加载、局部回写与推荐入口

Frontend lazy hydration
Lazy Load State Suggestions
【核心概念与设计初衷】

前端不会把图表、解释和推荐问题混入主 SSE 结果里一次性等待,而是在记录已有结果表后按条件懒加载。这样用户先看到 SQL 和结果表,后处理产物再局部回写到当前记录,不需要整页刷新,也不会因为可选产物失败而破坏主回答。

【算法逻辑与控制流向】
  1. Input:当前 ChatDetail、record_id、数据源 ID、loading map 和 force_refresh。
  2. shouldAutoFetchChart() 判断记录有数据、无错误、无图表且推荐类型不是 table 时自动补图表。
  3. shouldAutoFetchAnalysis() 判断记录有数据、无错误且无解释时自动补解释。
  4. hydrateRecordArtifacts() 在记录加载或完成后触发图表和解释补齐。
  5. ensureRecordChart()ensureRecordAnalysis() 调用后端接口,并用 updateRecordLocal() 局部写回当前记录。
  6. ensureRecommendedQuestions() 调用追问推荐接口,并同时更新 recommendedQuestionMap 与 record 字段。
  7. loadStarterQuestions() 在无数据源或指定数据源场景加载起始推荐;无指定数据源时从多个数据源混合抽样。
  8. Output:用户在同一聊天页中看到逐步补齐的图表、解释和问题按钮。
【代码精准溯源 (Code Anchor)】
  • graduation-design/frontend/src/views/chat/ChatView.vue:431 · 结果记录区域按 chart/loading/autoFetch 条件展示图表块。
  • graduation-design/frontend/src/views/chat/ChatView.vue:1199 · loadStarterQuestions() 加载数据源起始推荐问题。
  • graduation-design/frontend/src/views/chat/ChatView.vue:1312 · shouldAutoFetchChart() 判断是否自动获取图表。
  • graduation-design/frontend/src/views/chat/ChatView.vue:1319 · shouldAutoFetchAnalysis() 判断是否自动获取解释。
  • graduation-design/frontend/src/views/chat/ChatView.vue:1332 · updateRecordLocal() 局部回写单条记录。
  • graduation-design/frontend/src/views/chat/ChatView.vue:1347 · ensureRecordChart() 请求并回写图表。
  • graduation-design/frontend/src/views/chat/ChatView.vue:1380 · ensureRecordAnalysis() 请求并回写解释。
  • graduation-design/frontend/src/views/chat/ChatView.vue:1417 · hydrateRecordArtifacts() 补齐图表和解释。
  • graduation-design/frontend/src/views/chat/ChatView.vue:1438 · ensureRecommendedQuestions() 请求并回写推荐追问。
  • graduation-design/frontend/src/api/chat.ts:118:162 · 前端封装图表、解释和推荐追问 API。
“前端先让主答案落地,再懒加载图表、解释和追问;这些都是局部增强,不会卡住用户看结果。”
12

配置参数、功能测试与能力边界

Config, testing and boundary
Config Test Boundary
【核心概念与设计初衷】

后处理层的配置重点控制 token 成本、预览行数、推荐数量、缓存时效和重试次数。论文功能测试证明系统在正常问答后可以补充图表与解释,但答辩时要明确边界:图表、解释和推荐提升的是可读性与交互连续性,不等价于 SQL 正确率提升,也不能替代 SQL Guard 和语义验证。

配置项 作用
CHAT_RESULT_PREVIEW_LIMIT 控制图表和解释传给模型的结果预览行数。
CHAT_RECOMMENDATION_LIMIT 控制最终展示的推荐问题数量。
CHAT_RECOMMENDATION_CANDIDATE_POOL_SIZE 控制候选池大小,支持刷新轮换。
CHAT_RECOMMENDATION_LLM_MAX_RETRIES 控制推荐问题模型解析失败后的重试次数。
CHAT_STARTER_QUESTION_CACHE_TTL_HOURS 控制自动起始推荐问题缓存有效期。
【算法逻辑与控制流向】
  1. Input:运行配置、已执行结果、缓存状态和用户刷新意图。
  2. 图表和解释只使用结果预览,避免把大结果集直接塞进模型。
  3. 推荐问题通过 limit、候选池、TTL 和重试次数控制成本与稳定性。
  4. 功能测试 FT01 至 FT07 覆盖正常问答、图表和解释补充;FT08 验证错误数据域按预期拦截。
  5. 如果后处理失败,系统应降级为表格、兜底解释或兜底推荐,而不是改写 SQL 结果。
  6. Output:更好的复习展示和演示体验,但不改变 NL2SQL 主链路的正确性定义。
【代码精准溯源 (Code Anchor)】
  • graduation-design/backend/core/config.py:135:143 · 推荐数量、候选池、token、重试、TTL、Schema 摘要和结果预览行数配置。
  • latex/final.tex:820:852 · 功能测试说明问答记录生成后补充调用图表与解释接口,FT01 至 FT07 均为是。
  • latex/final.tex:875:877 · 论文图表生成结果截图。
  • latex/final.tex:899 · 后端单元测试覆盖图表生成、模型客户端等模块。
  • latex/final.tex:1216 · 论文总结功能测试覆盖结果表格、图表展示、解释生成和异常提示。
  • graduation-design/backend/services/chart_service.py:760:827 · 图表生成支持本地 table 跳过、模型生成和本地兜底三种 source。
  • graduation-design/backend/services/explanation_service.py:101:114 · 解释生成失败时返回本地兜底文本和 0 token usage。
  • graduation-design/backend/services/recommendation_service.py:1213:1268 · 自动 starter 推荐只有 LLM 成功结果会落库。
“后处理提升的是表达和交互,不是替 SQL 背书;SQL 对不对仍由生成、校验、执行和语义验证链路负责。”

配置、模型客户端与索引预热降级机制

本知识域回答一个运行态问题:增强能力很多、模型服务可能波动、向量索引可能未就绪时,系统如何仍然保持可配置、可复现、可观测和可降级。

论文原图:Token 与时延成本对比图
论文原图 · Token 与时延成本对比图 用于回答“为什么需要配置开关和成本边界”:完整增强链路能提升复杂样本能力,但额外上下文和模型调用会明显增加 Token 与时延。

读图顺序

  1. 图中对比 Pure Base-RAG、Base-RAG 和 Full Final 三种配置,横向展示平均耗时和单题 Token 的增长关系。
  2. Full Final 的准确率最高,但相对 Base-RAG 增加约 3977.48 ms 平均耗时和 1764.77 单题 Token,只换来约 1.5 个百分点 EX 增量。
  3. 论文进一步指出数据库执行本身不是主耗时来源,真正的成本集中在模型生成、长 Prompt、语义检查和自动修复重试。
  4. 因此本系统把检索数量、证据 Top-K、修复次数、结果行数和增强开关全部配置化,避免每个问题都无差别启用最高成本链路。

代码对应:backend/core/config.py 统一定义 RAG、Value Grounding、SQL Plan、Guard、Verifier、Fixer、结果预览和模型预算;backend/services/index_initialization_service.py 负责把索引准备从在线问答主链路移到启动后台任务或离线预构建任务。

答辩讲法:配置层不是“参数堆砌”,而是把准确率、成本、延迟和可用性变成可控旋钮。

01

配置体系总边界

Settings as runtime contract
Config Reproducible Runtime
【核心概念与设计初衷】

配置体系是系统运行态的总契约,负责把应用基础信息、数据库连接、模型供应商、Embedding 参数、检索增强开关、SQL 生成预算和降级策略集中到同一个 Settings 对象。它解决的痛点是:增强模块多、实验组合多,如果参数散落在业务代码中,答辩复现实验或临时调整功能时会不可控。

配置类别 代表控制内容 答辩解释
结构检索配置 表级召回、向量权重、关键词兜底、关系补表数量。 控制 Schema 上下文规模,向量不可用时保留基础召回。
证据增强配置 Value Grounding、SQL Experience、Evidence Top-K。 限制真实值、历史经验和证据进入 Prompt 的范围。
生成校验配置 SQL Plan、Guard、Verifier、Fixer、最大修复次数。 控制生成前约束、执行前拦截、执行后检查和失败恢复。
成本控制配置 SQL token 预算、默认查询行数、结果预览行数。 约束模型调用成本、数据库返回规模和前端展示负载。
【算法逻辑与控制流向】
  1. Input:.env、环境变量、默认字段值和运行时数据库设置。
  2. 后端启动时实例化 Settings,通过 Pydantic Settings 读取配置并完成类型转换。
  3. 校验器把 CORS 字符串、布尔值、PostgreSQL URL 等外部输入转成后端可直接消费的结构。
  4. 各服务不再硬编码参数,而是读取 settings 中的开关、阈值和预算。
  5. Output:一个全局只读配置对象,供数据源、检索、模型、生成、校验、前端状态接口共同使用。
【代码精准溯源 (Code Anchor)】

核心实现在 backend/core/config.pySettings 类定义于 :25model_config.env 读取配置;parse_bool_value():215 处理布尔兼容;cors_origins:236 规范化跨域列表;sqlalchemy_database_uri:251 拼接数据库 URL;全局实例 settings = Settings() 位于 :285。论文设计依据对应 latex/final.tex:718 的“系统配置与索引预热设计”。

【答辩白话解析 (防卡壳金句)】
“配置层就是系统总控台:不是每次改代码调能力,而是用开关和预算决定这次问答走多深、花多少成本、失败怎么降级。”
02

核心开关与成本预算

Feature flags and cost budgets
Switch Budget Cost
【核心概念与设计初衷】

核心开关与成本预算把增强链路拆成可独立控制的能力单元,例如 Schema-RAG、术语、样例、领域记忆、条件值定位、SQL Plan、语义验证和自动修复。设计初衷是让系统可以在“基础可用”和“完整增强”之间平滑切换,并把 Prompt 长度、模型调用次数、查询返回规模控制在可解释范围内。

【算法逻辑与控制流向】
  1. Input:本轮问答的数据源、问题、运行环境和配置开关。
  2. 检索阶段读取 RAG_*_ENABLEDRAG_SCHEMA_* 参数,决定是否启用向量检索、关键词兜底、启发式加分和关系补表。
  3. 证据阶段读取 VALUE_GROUNDING_*SQL_EXPERIENCE_*RETRIEVAL_EVIDENCE_*,限制候选数量和注入文本长度。
  4. 生成阶段读取 SQL_GENERATION_MAX_TOKENSCHAT_SCHEMA_TABLE_LIMITCHAT_DEFAULT_LIMIT 等预算,控制 SQL 和结果规模。
  5. 校验修复阶段读取 SQL_GUARD_ENABLEDSQL_SEMANTIC_VERIFIER_ENABLEDSQL_AUTO_FIX_MAX_ATTEMPTS,决定执行前后检查和修复次数。
  6. Output:一条按配置裁剪后的问答控制流,而不是固定启用所有增强模块。
【代码精准溯源 (Code Anchor)】

集中定义在 backend/core/config.py:Embedding 配置位于 :84-89;RAG 开关和召回参数位于 :91-112;Value Grounding 参数位于 :113-119;聊天、问题改写、分解、SQL Plan、样例、SQL Experience、推荐、结果预览、SQL 生成和语义验证参数位于 :121-156。论文表格依据在 latex/final.tex:731-743

【答辩白话解析 (防卡壳金句)】
“这些开关相当于增强链路的挡位:简单问题低挡省成本,复杂问题高挡补证据、做校验、允许修复。”
03

模型配置对象与客户端工厂

LLM config and factory
LLM Factory Provider
【核心概念与设计初衷】

模型配置对象把模型供应商、模型名、API Key、Base URL、温度、最大 token、超时和额外请求头封装为统一结构;客户端工厂负责把该结构实例化为具体模型客户端。它解决的是“业务服务不应该关心底层模型供应商差异”的问题,使 Prompt 构造、SQL 生成、解释、推荐等模块只依赖统一的补全文本接口。

【算法逻辑与控制流向】
  1. Input:当前数据库会话中的激活模型设置,或环境变量中的默认模型配置。
  2. get_default_llm_config(session) 优先读取后台模型设置;如果存在激活配置,则转换成 LLMConfig
  3. 当 provider 为 github_copilot 时,构造 GitHub Copilot 运行时配置;普通 OpenAI 兼容服务则读取 provider/model/base_url/api_key。
  4. 如果数据库设置缺失或读取失败,回退到 settings.DEFAULT_LLM_*
  5. LLMFactory.create_client() 根据 provider 创建 OpenAIClientGitHubCopilotClient
  6. Output:一个具有统一 complete_text()complete_text_controlled() 接口的模型客户端。
【代码精准溯源 (Code Anchor)】

核心实现在 backend/services/llm_factory.pyLLMConfig 定义于 :20LLMTextResponse 定义于 :46get_default_llm_config() 位于 :64,包含数据库激活配置、GitHub Copilot 配置和默认环境变量回退;LLMFactory.create_client() 位于 :120,按 provider 创建具体客户端。

【答辩白话解析 (防卡壳金句)】
“模型工厂就是适配器:上层只说‘我要补全文本’,底层到底是 OpenAI 兼容接口还是 Copilot,由工厂统一换插头。”
04

OpenAI 兼容客户端与统一响应

OpenAI-compatible client
OpenAI API SDK Embedding
【核心概念与设计初衷】

OpenAI 兼容客户端是系统访问大模型和 Embedding 服务的底层协议封装。它的设计目标是把 SDK 初始化、请求参数、超时、错误包装、usage 统计、特殊 curl 传输和向量接口统一收敛,避免各业务服务直接操作第三方 SDK。

【算法逻辑与控制流向】
  1. Input:LLMConfig,包括 api_keybase_urlmodel_name、timeout 和 headers。
  2. 构造函数校验必需字段,初始化 OpenAI SDK 客户端,并根据模型/地址判断是否需要 GLM curl 传输。
  3. 文本生成调用 complete_text_controlled(),合并温度、最大 token 和消息列表。
  4. 普通 OpenAI 兼容服务走 SDK;特殊 GLM 编码接口走 curl 子进程并解析 HTTP 状态和 JSON 响应。
  5. 响应被统一包装为 LLMTextResponse,携带 content、usage、raw_model、finish_reason 和空内容标记。
  6. Embedding 调用 embed_texts(),批量提交文本并校验返回向量数量与输入数量一致。
【代码精准溯源 (Code Anchor)】

核心实现在 backend/services/openai_client.pyOpenAIClient 位于 :35__init__():45 校验配置并初始化 SDK;_should_use_glm_curl_transport() 位于 :73_run_glm_curl_command() 位于 :85_complete_text_via_glm_curl() 位于 :131complete_text_controlled() 位于 :264embed_texts() 位于 :382;usage 标准化在 _build_usage_dict():411)。

【答辩白话解析 (防卡壳金句)】
“OpenAIClient 是模型网关:业务层不碰 SDK 细节,只拿统一的文本响应、usage 和向量结果。”
05

大模型调用控制:取消、重试、超时

LLM call control
Retry Cancel Timeout
【核心概念与设计初衷】

大模型调用控制层把取消信号、有限重试、可重试错误识别和重试通知从业务编排层抽离出来。它解决的痛点是:SQL 生成、改写、解释、推荐等多个阶段都会调用模型,如果每个阶段自行处理 429、超时、用户停止,会导致语义不一致、代码重复和停不下来的同步阻塞。

【算法逻辑与控制流向】
  1. Input:模型客户端、messages、可选 temperature/max_tokens、LLMCallControl
  2. 控制对象携带 cancel_eventretry_policyon_retry 回调和取消提示文案。
  3. 调用前、等待中、调用后都会检查取消信号;如果用户停止,抛出 LLMCallCancelled
  4. 遇到 429、5xx、timeout、network error 等可恢复错误时,根据 LLMRetryPolicy 最多重试 3 次,并按 0、1.5、4 秒退避。
  5. 遇到 invalid api key、unauthorized、bad request、context length 等不可恢复错误时,直接失败,不做无意义重试。
  6. Output:成功时返回统一 LLMTextResponse;失败时向上抛出可解释异常,由主链路转成 SSE 错误或阶段日志。
【代码精准溯源 (Code Anchor)】

核心实现在 backend/services/llm_control.py:可重试状态码定义在 :22LLMRetryPolicy 位于 :57,默认 max_attempts=3retry_delays=(0.0, 1.5, 4.0)LLMCallControl 位于 :90;取消检查函数 raise_if_control_cancelled() 位于 :101;可取消 sleep 位于 :110;错误分类 is_retryable_llm_error() 位于 :143;统一入口 complete_text_with_control() 位于 :176;阻塞 SDK 调用外包到后台线程的 run_blocking_call_with_cancellation() 位于 :207

【答辩白话解析 (防卡壳金句)】
“调用控制层就是模型请求的安全带:能重试的短暂故障自动缓一下,不能恢复的配置错误立刻暴露,用户点停止也能尽快停。”
06

Embedding 配置解析与可用性门控

Embedding availability gate
Embedding Gate Batch
【核心概念与设计初衷】

Embedding 配置解析与可用性门控负责判断当前环境是否具备向量化能力,并在可用时批量生成向量,在不可用时显式进入降级路径。它的价值是防止向量服务配置缺失时拖垮数据源同步、Schema-RAG 和启动流程。

【算法逻辑与控制流向】
  1. Input:需要向量化的文本列表、可选数据库会话、Embedding 相关环境变量。
  2. _build_embedding_config() 优先读取 EMBEDDING_BASE_URLEMBEDDING_API_KEYEMBEDDING_MODEL
  3. 如果 Embedding 专用配置缺失,则尝试复用当前激活 LLM 设置;仍缺失时回退到默认 LLM base_url/api_key。
  4. embedding_is_available() 同时检查开关、provider、model、base_url、api_key,任一关键项缺失即判定不可用。
  5. 可用时 embed_texts()EMBEDDING_BATCH_SIZE 分批调用模型客户端向量接口。
  6. Output:向量列表;若不可用则抛出明确错误或由上层刷新函数进入非向量降级。
【代码精准溯源 (Code Anchor)】

核心实现在 backend/services/embedding_service.py:Embedding 配置构造函数 _build_embedding_config() 位于 :182;可用性判断 embedding_is_available() 位于 :218;批量向量化 embed_texts() 位于 :239。相关环境配置在 backend/core/config.py:84-89

【答辩白话解析 (防卡壳金句)】
“Embedding 门控先看发动机有没有油:有配置才跑向量,没有配置就不要假装能跑,直接走关键词和启发式兜底。”
07

向量快照新鲜度与刷新降级

Embedding freshness and refresh
Freshness Snapshot Degrade
【核心概念与设计初衷】

向量快照机制把“用于生成 embedding 的文本”与“实际 embedding_json”一起管理,用文本快照判断向量是否过期。设计初衷是避免表名、字段、注释、checked 状态变化后继续使用旧向量,同时在向量服务不可用时保留可追踪的文本快照,为后续补建索引做准备。

【算法逻辑与控制流向】
  1. Input:数据源、表、字段、业务注释和 checked 状态。
  2. build_table_embedding_text() 把数据源名、描述、表名、表注释、字段名和字段注释拼成表级向量文本。
  3. is_table_embedding_fresh() 判断当前文本快照是否等于历史快照;checked 表必须有向量,未 checked 表应清空向量。
  4. 刷新表向量时,如果 Embedding 可用,则对 checked 表批量生成并写入 embedding_jsonembedding_text、更新时间。
  5. 如果 Embedding 不可用,刷新函数只保存最新文本快照并清空旧向量,避免系统误用过期语义索引。
  6. Output:新向量数量或降级刷新结果;在线问答可继续使用关键词、注释和启发式召回。
【代码精准溯源 (Code Anchor)】

核心实现在 backend/services/embedding_service.py:表向量文本构造 build_table_embedding_text() 位于 :89;数据源向量文本构造 build_datasource_embedding_text() 位于 :118;表新鲜度检查 is_table_embedding_fresh() 位于 :141;数据源新鲜度检查 is_datasource_embedding_fresh() 位于 :162;表向量刷新 refresh_table_embeddings() 位于 :298;数据源向量刷新 refresh_datasource_embedding() 位于 :340;一键刷新 refresh_rag_embeddings() 位于 :374。论文依据在 latex/final.tex:745-747

【答辩白话解析 (防卡壳金句)】
“快照就是向量的身份证:Schema 文本变了,旧向量就不能继续冒充当前表。”
08

应用启动生命周期与后台 warmup 入口

Startup warmup lifecycle
Startup Warmup Non-blocking
【核心概念与设计初衷】

启动生命周期把数据库初始化、默认数据引导和索引预热串在 FastAPI lifespan 中执行,但索引预热采用后台线程,不把它作为系统入口的硬阻塞条件。设计初衷是让增强索引准备慢或失败时,用户仍能进入基础工作区,并通过状态接口感知当前增强能力是否就绪。

【算法逻辑与控制流向】
  1. Input:后端进程启动事件。
  2. lifespan 首先调用 init_database(),确保业务表结构存在。
  3. 随后调用 bootstrap_default_data(),补齐默认数据和基础配置。
  4. 最后调用 index_initialization_manager.start_background_warmup(),创建后台预热线程。
  5. 主应用继续加载路由、中间件和健康检查,不等待所有向量索引完成。
  6. Output:应用进入可访问状态;预热进度由状态接口和前端轮询展示。
【代码精准溯源 (Code Anchor)】

启动入口在 backend/main.py:FastAPI lifespan 定义于 :37;数据库初始化、默认数据引导和后台 warmup 调用位于 :51-53;CORS 使用统一 settings 配置在 :71;健康检查接口位于 :118。后台预热入口 start_background_warmup()backend/services/index_initialization_service.py:142

【答辩白话解析 (防卡壳金句)】
“启动时先把门打开,再在后台热身增强索引;基础功能不因为向量预热慢就整站不可用。”
09

IndexInitializationManager 计划、阶段与执行

Index warmup plan and stages
Plan Stage Progress
【核心概念与设计初衷】

IndexInitializationManager 是运行时索引预热的调度器,负责扫描缺失或过期的表向量、数据源向量、术语向量、SQL 样例向量和推荐问题缓存,并按阶段补齐。它把“索引准备”从临时散落的同步动作升级为可计划、可进度化、可恢复的后台任务。

阶段 处理对象 作用
scan 数据源、表字段、术语、训练样例、推荐缓存。 判断哪些索引缺失或过期。
datasource 表级向量与数据源级向量。 补齐 Schema-RAG 和数据源选择所需向量。
terminology / training 业务术语、SQL few-shot 样例。 补齐知识增强检索索引。
recommendation 起始推荐问题缓存。 提升数据源空状态体验,减少首次生成等待。
【算法逻辑与控制流向】
  1. Input:当前数据库中的全部数据源、表字段元数据、术语、训练样例和推荐缓存状态。
  2. _build_plan() 扫描所有对象,用新鲜度函数判断哪些向量或缓存需要刷新。
  3. 如果计划总量为 0,直接进入 completed;否则进入 running 并初始化总任务数和已处理数量。
  4. 按 datasource、terminology、training、recommendation 阶段顺序执行刷新。
  5. 每处理一个目标就更新 processed_items、current_stage 和状态摘要。
  6. 任一阶段异常会把状态置为 failed,并保留 last_error 和建议操作;下次启动或离线预构建可继续补齐。
  7. Output:completed / failed 状态、阶段进度、降级标记和后续建议。
【代码精准溯源 (Code Anchor)】

核心实现在 backend/services/index_initialization_service.py:离线命令常量位于 :37,阶段标签 _STAGE_LABELS 位于 :39-46DatasourceWarmupTarget 位于 :51IndexInitializationPlan 位于 :62,总任务数计算位于 :73;管理器类 IndexInitializationManager 位于 :88;主执行函数 _run_warmup() 位于 :267;计划构建 _build_plan() 位于 :319;数据源、术语、训练、推荐阶段分别在 :388:419:440:461

【答辩白话解析 (防卡壳金句)】
“预热管理器像开机自检清单:先扫一遍哪里缺索引,再按数据源、术语、样例、推荐逐项补齐并报进度。”
10

降级状态、状态接口与前端轮询

Degraded status and frontend polling
Degraded Polling UX
【核心概念与设计初衷】

降级状态机制把初始化状态从后端任务内部暴露为可读 API,并映射成前端的 blockeddegradedready 三类工作区访问语义。设计初衷是让用户知道当前是完全可用、增强索引后台准备中,还是必须停留在初始化页,而不是只看到空白或静默失败。

【算法逻辑与控制流向】
  1. Input:后端 IndexInitializationManager 当前状态。
  2. 后端构造状态快照,包含 state、blocking、degraded、workspace_access、summary、recommended_action、offline_prebuild_command、当前阶段、进度和错误。
  3. 前端调用 /settings/runtime/index-initialization 获取状态。
  4. 工具函数把后端状态映射为 blocked/degraded/ready:blocked 跳初始化页,degraded 允许进入但展示横幅,ready 停止轮询。
  5. Pinia store 每 2 秒轮询仍在进行或可恢复的状态;路由守卫负责初始化状态检查与跳转。
  6. Output:用户可见的初始化页面、降级横幅和后台索引准备进度。
【代码精准溯源 (Code Anchor)】

后端状态快照由 backend/services/index_initialization_service.py_build_status_snapshot_locked() 生成(:192),状态校正位于 :220,外部读取入口 get_status() 位于 :250。接口在 backend/settings/router.py:74,响应模型 SystemInitializationStatusReadbackend/settings/models.py:318。前端调用在 frontend/src/api/settings.ts:175;访问语义函数在 frontend/src/utils/systemInitialization.ts:28:41:50:77;Pinia store 的 2 秒轮询在 frontend/src/stores/systemInitialization.ts:24:52:85;路由守卫在 frontend/src/router/index.ts:190-193;降级横幅在 frontend/src/layouts/AppShell.vue:200-203

【答辩白话解析 (防卡壳金句)】
“降级不是偷偷少做功能,而是明确告诉前端:现在能进系统,但向量增强还在后台补齐。”
11

离线预构建脚本与失败恢复

Offline prebuild and recovery
Prebuild Recovery Ops
【核心概念与设计初衷】

离线预构建脚本是索引 warmup 的运维兜底入口,用于部署前、答辩演示前、Embedding 配置变更后或后台预热失败后,主动补齐运行时索引。它把“等用户第一次访问时慢慢补”改成“提前构建好关键索引”,降低冷启动和展示风险。

【算法逻辑与控制流向】
  1. Input:命令行执行 .venv/bin/python scripts/prebuild_runtime_indexes.py
  2. 脚本初始化数据库,并引导默认数据,保证运行环境与在线服务一致。
  3. 调用 index_initialization_manager.run_prebuild(),同步执行同一套索引计划。
  4. 脚本打印 state、workspace_access、processed_items、total_items、summary 和 last_error。
  5. 如果存在 last_error,脚本以非 0 状态退出,便于部署脚本或人工检查发现失败。
  6. Output:预构建完成的向量/缓存,或明确的失败原因和可重复执行命令。
【代码精准溯源 (Code Anchor)】

离线命令在 backend/services/index_initialization_service.py:37_OFFLINE_PREBUILD_COMMAND 暴露给前端状态接口;同步预构建入口 run_prebuild() 位于 :158;推荐操作生成在 :182。脚本位于 scripts/prebuild_runtime_indexes.py:用途说明在 :5-9,主函数 main() 位于 :27,其中调用 init_database()bootstrap_default_data()run_prebuild()

【答辩白话解析 (防卡壳金句)】
“离线预构建就是把上台前要用的索引先热好;现场即使后台 warmup 慢,也有一条可重复执行的恢复命令。”
12

成本实验与工程边界

Cost trade-off boundary
Experiment Latency Trade-off
【核心概念与设计初衷】

成本实验边界说明:配置、模型客户端和索引预热不是为了“越复杂越好”,而是让增强链路在准确率收益、Token 成本、时延和可用性之间可调。论文实验表明,完整配置组确实能提升 EX,但额外模型上下文和检查修复会带来明显时延与 Token 增量,因此工程上必须通过开关、预算和降级策略控制触发范围。

【算法逻辑与控制流向】
  1. Input:不同实验配置下的平均耗时、总 Token、单题 Token、EX、SQL 生成耗时和数据库执行耗时。
  2. 对比 Pure Base-RAG、Base-RAG、Full Final 三组配置的准确率和运行成本。
  3. 识别成本主因:生成前证据、长 Prompt、执行前后检查、语义验证日志、自动修复重试。
  4. 区分数据库执行耗时与模型调用耗时:日志显示数据库执行仅几十毫秒,模型生成通常数秒级。
  5. 根据实验结论,把 Full Final 定位为复杂样本和能力上限配置,而不是所有请求的默认高成本路径。
  6. Output:答辩中可解释的工程取舍,即“增强有收益,但必须按风险触发”。
【代码精准溯源 (Code Anchor)】

论文依据集中在 latex/final.tex:成本对比表位于 :1150-1171,图 fig4-5_cost_comparison 位于 :1173-1180;增量分析位于 :1183-1200;“数据库执行不是主耗时来源”位于 :1206;成本来源和按需触发结论位于 :1208-1212。工程控制点对应 backend/core/config.py:91-156 的增强开关、候选上限、token 预算、默认查询行数和修复次数。

【答辩白话解析 (防卡壳金句)】
“完整增强不是免费午餐:它能多拿一些复杂题,但成本主要花在模型上下文和检查修复,所以系统必须按风险开能力。”

实验评测、消融与成本分析

本知识域回答答辩中最容易被追问的证据问题:系统效果如何证明、对比组怎么设置、EX 怎么计算、消融能说明什么、成本为什么上升以及这些结论的边界在哪里。

论文原图:BIRD 200 主对比 EX 柱状图
论文原图 · BIRD 200 主对比 EX 柱状图 用于回答“主实验到底证明了什么”:完整配置组高于纯基础组和基础增强组,但关闭 Schema-RAG 后明显下降,说明结构检索是基础支撑。

读图顺序

  1. 先比较 Pure Base-RAG、Base-RAG、Full Final:EX 从 52.5% 到 55.5% 再到 57.0%,说明增强策略带来增量,但完整增强相对 Base-RAG 只有 1.5 个百分点。
  2. 再看 No Schema Retrieval:EX 降到 47.0%,且生成成功率和可执行率同步下降,说明没有结构边界时,值证据、经验规则和修复不能单独撑住 SQL 生成。
  3. 最后注意样本量是 200 条,论文没有把 1.5 pp 解释成绝对稳定收益,而是继续通过难度分层和消融分析限定结论。

代码对应:scripts/run_thesis_final_experiments.py 组织对比组,scripts/run_bird_mini_dev_eval.py 逐题生成、执行并比较结果,论文结论写在 latex/final.tex:912-973

答辩讲法:主实验最强的结论不是“所有增强都必然大幅提升”,而是“Schema-RAG 是地基,增强策略在地基可靠时提供额外收益”。

论文原图:BIRD 难度分层提升图
论文原图 · BIRD 难度分层提升图 用于回答“增强为什么不是简单题也全开”:完整配置组在 simple 上无增量,在 moderate 和 challenging 上增量更明显。

读图顺序

  1. simple 层提升为 0.0 pp,说明简单单表或低约束问题只靠 Schema-RAG 已经足够,额外证据未必带来收益。
  2. moderate 层提升 2.0 pp,说明约束和连接逐渐增多时,证据和校验开始产生作用。
  3. challenging 层提升 6.0 pp,是完整链路最能体现价值的区域,通常涉及复杂 JOIN、条件值、业务术语、聚合口径或语义风险。

代码对应:BIRD 脚本通过 --difficulty simple moderate challenging 筛选样本(scripts/run_bird_mini_dev_eval.py:285-289),论文分层结果写在 latex/final.tex:1003-1038

答辩讲法:增强策略的收益是“复杂度相关”的,越复杂越需要证据、计划、验证和修复,简单题反而要避免过度加工。

论文原图:典型样本处理轨迹图
论文原图 · 典型样本处理轨迹图 用于回答“消融数字背后的样本级原因”:增强链路可能纠偏、阻断,也可能在简单题上过度修复。

读图顺序

  1. 纠偏轨迹:初始 SQL 局部漏条件或字段语义错配,语义验证发现风险,自动修复后匹配 Gold SQL。
  2. 阻断轨迹:结构证据不足时不强行生成猜测 SQL,而是把高风险问题停在受控失败状态。
  3. 过度修复轨迹:简单问题中修复改变输出列粒度,SQL 可执行但严格执行结果不匹配,说明修复也需要输出形态约束。

代码对应:单题记录中的 semantic_verifier_triggeredsemantic_repair_attemptedsemantic_repair_succeededfailure_stageerror_typescripts/run_bird_mini_dev_eval.py:926-1460 写入,论文样本解释位于 latex/final.tex:1102-1146

答辩讲法:消融不能只看平均数,必须解释样本轨迹;系统有时是修正错误,有时是阻断风险,有时也会暴露增强副作用。

01

测试设计与评测边界

Evaluation scope
Design Boundary Eval
【核心概念与设计初衷】

实验评测被拆成两层:功能测试验证系统链路是否端到端可用;离线 Text-to-SQL 评测验证生成 SQL 的执行结果是否与 Gold SQL 一致。这样设计是为了避免把 UI 展示、图表解释等体验能力混入 SQL 准确率,同时保留系统完整闭环的工程证据。

【算法逻辑与控制流向】
  1. Input:功能测试数据源、BIRD Mini-Dev 样本、Spider dev 样本、评测配置组。
  2. 功能测试通过问答流式接口提交问题,并在记录生成后补充图表与解释接口,验证端到端闭环。
  3. 离线评测不统计图表和解释,只保留 SQL 生成、执行、Gold SQL 执行、结果比对、耗时和 token。
  4. 主对比先看完整方案与基础方案差异,再用消融和难度分层分析差异来源。
  5. Output:功能可用性结论、执行准确率结论、模块贡献解释和成本边界。
【代码精准溯源 (Code Anchor)】

论文测试设计写在 latex/final.tex:754-768;功能测试边界写在 latex/final.tex:820-880。离线评测脚本入口为 scripts/run_thesis_final_experiments.py:56 的参数构造和 :904 的主函数;BIRD 单任务脚本说明在 scripts/run_bird_mini_dev_eval.py:3-15,明确只统计“SQL 生成 + 执行结果比对”,不混入图表/解释阶段成本。

【答辩白话解析 (防卡壳金句)】
“功能测试证明系统能跑通,离线评测证明 SQL 答得对;这两个问题不能混在一个指标里讲。”
02

数据集定位:BIRD 与 Spider

Dataset roles
BIRD Spider Benchmark
【核心概念与设计初衷】

BIRD Mini-Dev 和 Spider dev 在论文中的作用不同:BIRD 更接近真实数据库问答,包含数据库值、外部证据和领域约束;Spider 更强调跨数据库结构泛化,考验未见数据库下的表字段匹配和 SQL 结构生成。两者组合可以避免只在单一 benchmark 上解释系统效果。

数据集 主要考察 论文定位
BIRD Mini-Dev 真实数据库结构、条件值、外部证据、复杂约束、执行结果一致性。 主定量评测数据。
Spider dev 跨领域、跨数据库 Schema 泛化和 SQL 结构生成。 补充泛化验证。
【算法逻辑与控制流向】
  1. Input:BIRD Mini-Dev JSON、Spider dev.json、对应 MySQL/SQLite 数据库。
  2. BIRD 脚本按 difficulty、question_id、db_id、offset、limit 筛选样本。
  3. Spider 脚本按 db_id、SQL 结构类别、balanced/sequential 策略和 per-db 上限筛选样本。
  4. 两类样本都转成统一的单题评测对象,进入同一套 SQL 生成和结果比对流程。
  5. Output:可横向比较的 cases.jsonl、summary.json 和 summary.md。
【代码精准溯源 (Code Anchor)】

论文数据集定义见 latex/final.tex:760-764,测试环境表见 latex/final.tex:768-790。BIRD 样本对象 BirdMiniDevSamplescripts/run_bird_mini_dev_eval.py:154,样本加载函数 load_bird_samples():527。Spider 样本加载与筛选在 scripts/run_spider_dev_eval.py:139:171,Spider 样本转 BIRD 兼容对象在 :241

【答辩白话解析 (防卡壳金句)】
“BIRD 看真实业务约束下能不能查对,Spider 看换一个陌生数据库结构后还能不能保持基本泛化。”
03

指标体系:EX、可执行率、时延与 Token

Metrics contract
EX Latency Token
【核心概念与设计初衷】

论文以 EX(执行结果匹配率)作为主指标,而不是 SQL 文本完全一致率。原因是同一个自然语言问题可能有多条语义等价 SQL,文本不一样但执行结果一致仍应视为正确。同时记录生成成功率、可执行率、P95 时延和 Token,用于区分“生成不了”“能执行但不匹配”“成本太高”等不同问题。

【算法逻辑与控制流向】
  1. Input:预测 SQL、Gold SQL、预测执行结果、Gold 执行结果、模型 usage 和耗时。
  2. 先判断是否生成预测 SQL,统计生成成功率。
  3. 再执行预测 SQL,统计预测 SQL 可执行率。
  4. 执行 Gold SQL,得到标准结果快照。
  5. 若 SQL 中有 ORDER BY,按顺序敏感比较;否则对结果行排序后比较。
  6. 数值结果允许极小浮点尾差,字符串和结构差异保持严格比较。
  7. Output:result_match_ratesql_text_equal_rate、平均/P95 时延、总 Token 和单题 Token。
【代码精准溯源 (Code Anchor)】

公式定义在 latex/final.tex:798-814。结果比较函数 compare_execution_results() 位于 scripts/run_bird_mini_dev_eval.py:1543;规范化行构造在 :1567;浮点容差比较在 :1600;摘要指标汇总在 build_summary():1713)。数值容差测试在 graduation-design/tests/test_bird_eval_compare.py:24-53

【答辩白话解析 (防卡壳金句)】
“SQL 文字像解题过程,EX 看最终答案;只要执行结果和标准答案一致,就不能因为写法不同直接判错。”
04

功能测试与自动化测试

Functional and automated tests
Function Unit Test Frontend
【核心概念与设计初衷】

功能测试验证系统是否能在关系型数据源、文件型数据源和 BIRD 数据源上完成完整问答,包括 SQL、结果表、图表、解释和错误提示;自动化测试验证核心模块的可重复正确性。两者共同支撑“系统可运行”和“模块有回归保护”两个答辩结论。

【算法逻辑与控制流向】
  1. Input:Chinook、Olist、Online Retail II、BIRD Mini-Dev 等功能测试数据源。
  2. 通过流式问答接口发起自然语言问题,验证单表聚合、多表关联、时间趋势、文件型数据源查询和错误数据域提示。
  3. 完成问答记录后,补充调用图表和解释接口,检查后处理能力。
  4. 后端执行 unittest,覆盖 Schema 检索、SQL 校验、执行、Prompt、图表、模型客户端等。
  5. 前端逻辑测试覆盖请求保护、SSE 解析、鉴权状态、系统初始化、聊天运行状态和输入区交互。
  6. Output:功能测试 completed/拦截结果、后端 124 项 OK、前端 8 项 PASS。
【代码精准溯源 (Code Anchor)】

功能测试表在 latex/final.tex:820-880,自动化测试表在 latex/final.tex:882-906。最终实验脚本通过 run_unit_tests() 执行后端 unittest discover 和前端 npm run test:logic,代码在 scripts/run_thesis_final_experiments.py:386-410。相关测试文件包括 graduation-design/tests/test_schema_retrieval_guard.pygraduation-design/tests/test_openai_client.pygraduation-design/tests/test_bird_eval_compare.py 和前端逻辑测试入口。

【答辩白话解析 (防卡壳金句)】
“功能测试看整条路能不能走通,自动化测试看关键零件以后改代码会不会坏。”
05

最终实验总入口与产物闭环

Final experiment runner
Runner Report Manifest
【核心概念与设计初衷】

run_thesis_final_experiments.py 是论文实验的一键总入口,负责固定 BIRD 和 Spider 样本规模、选择实验组、运行单元测试、调用各数据集评测脚本、记录命令日志,并生成 Markdown 报告、manifest 和 summary CSV。它解决的是实验可复现和结果可追溯问题。

【算法逻辑与控制流向】
  1. Input:run_id、数据集选择、limit/offset、实验 suite、模型配置、并行参数和 group 覆盖参数。
  2. 先构造 BIRD/Spider 实验组目录,包括 baseline、full_no_plan、full 和扩展消融组。
  3. 运行后端与前端逻辑测试,必要时 stop-on-error。
  4. 按顺序或并行方式调用 BIRD/Spider 单数据集评测脚本,每组写入独立日志和 summary。
  5. 读取各组 summary,渲染主对比表、消融表、模块诊断表和逐题差异。
  6. Output:Thesis_Final_Experiment_Record_*.mdmanifest.jsonsummary_table.csv 和每组日志。
【代码精准溯源 (Code Anchor)】

总入口说明在 scripts/run_thesis_final_experiments.py:3-7;参数在 :56-103ExperimentGroupStepResult:32:41;BIRD/Spider 组目录在 :106:197;命令执行与日志在 :266;并行执行在 :475;最终报告在 write_final_report():735);manifest 在 :856;主函数在 :904

【答辩白话解析 (防卡壳金句)】
“最终实验脚本就是实验流水线:同一批样本、同一套命令、同一套输出,保证表格数字不是手工凑出来的。”
06

BIRD 评测脚本如何复用主链路

BIRD pipeline reuse
BIRD Pipeline JSONL
【核心概念与设计初衷】

BIRD 评测脚本不是另写一套简化版生成器,而是复用当前系统的 Schema 检索、术语检索、样例检索、值证据、SQL Experience、SQL Plan、Prompt 构造、大模型生成、Guard、执行、语义验证和修复能力。这样保证离线实验测到的是系统真实链路,而不是论文专用链路。

【算法逻辑与控制流向】
  1. Input:BIRD 样本问题、evidence、Gold SQL、difficulty、数据源配置和模型配置。
  2. 初始化数据库与默认数据,解析评测数据源;必要时自动创建或同步 BIRD MySQL 数据源。
  3. 读取预设和命令行开关,临时覆盖 settings,得到本组实验配置。
  4. 逐题执行:问题改写、Schema-RAG、Value Grounding、术语、样例、SQL Experience、Evidence、分解、SQL Plan。
  5. 构造 Prompt 调用模型,解析 JSON SQL 响应,并应用语义修正规则和计划修正规则。
  6. 执行 Guard、预测 SQL、语义验证和必要修复;再执行 Gold SQL,比较结果。
  7. Output:每题 JSONL/CSV、预测 SQL 文件、summary.json 和 Markdown 报告。
【代码精准溯源 (Code Anchor)】

BIRD 脚本位于 scripts/run_bird_mini_dev_eval.py。主链路依赖导入在 :60-99;预设配置在 :107-133,开关映射在 :136-151;参数入口在 :271;主函数在 :441;数据源解析和同步在 :630-663;临时 settings 覆盖在 :717-730;逐轮评测输出在 run_evaluation():860);单题主流程在 run_single_case():926-1460)。

【答辩白话解析 (防卡壳金句)】
“BIRD 脚本测的就是产品里的那条 NL2SQL 链路,只是把前端交互换成逐题批处理和结果比对。”
07

Spider dev 泛化评测链路

Spider cross-database evaluation
Spider SQLite Generalization
【核心概念与设计初衷】

Spider 评测链路把每个 Spider 数据库作为独立 SQLite 数据源接入系统,再把 Spider 样本转换成与 BIRD 兼容的单题对象,复用同一套 run_single_case()。设计初衷是用最小重复代码验证跨数据库 Schema 泛化,同时保证指标口径与 BIRD 一致。

【算法逻辑与控制流向】
  1. Input:Spider dev.json、SQLite database 目录、limit、offset、SQL 结构类别和采样策略。
  2. 加载样本并标注 SQL 结构类别;balanced 策略按结构和数据库限制样本分布。
  3. 对每个 db_id 找到或创建对应 SQLite 数据源,必要时同步元数据。
  4. SpiderSample 转为 BirdMiniDevSample 形态,evidence 置空。
  5. 复用 BIRD 的 run_single_case() 完成生成、执行、比较和日志记录。
  6. Output:Spider 的 cases、summary、按 SQL category 聚合结果和模块诊断。
【代码精准溯源 (Code Anchor)】

Spider 脚本位于 scripts/run_spider_dev_eval.py。脚本说明在 :3-8;复用 BIRD 评测函数的导入在 :53-68;参数入口在 :83;样本加载和筛选在 :139:171;数据源创建/同步在 :197;样本转换在 :241;配置快照在 :253;评测循环在 :333;模块诊断增强在 :412;主函数在 :496

【答辩白话解析 (防卡壳金句)】
“Spider 评测不是新写一套算法,而是把每个 Spider 库当成系统数据源,继续走同一条生成和比对链路。”
08

主对比实验配置矩阵

Main comparison matrix
Matrix Preset Ablation
【核心概念与设计初衷】

主对比配置矩阵把系统能力拆成从基础到完整的几组实验,用于回答“到底是哪一层能力带来变化”。Pure Base-RAG 只保留结构检索;Base-RAG 加入经验规则、SQL Guard 和一次修复;Full Final 打开完整增强;No Schema Retrieval 只关闭结构检索,用于验证 Schema-RAG 是否是不可替代的地基。

实验组 关键开关 用于回答的问题
Pure Base-RAG 仅保留 Schema-RAG,关闭术语、样例、值证据、计划、校验、修复、验证。 基础结构检索能做到什么水平。
Base-RAG 保留 Schema-RAG、经验规则、SQL Guard 与一次修复。 低成本安全增强是否有效。
Full Final 打开完整证据、SQL Plan soft、Guard、Verifier、Repair。 系统能力上限是多少。
No Schema Retrieval 除 Schema-RAG 外其余与 Full Final 一致。 没有结构召回时增强能否补救。
【算法逻辑与控制流向】
  1. Input:实验 suite、BIRD/Spider group key、preset 和额外开关参数。
  2. 总入口脚本从 group catalog 中选择实验组,每组包含 keylabelpresetextra_args 和 role。
  3. 单数据集脚本根据 preset 构造基础覆盖项,再把命令行开关映射到 settings
  4. 评测期间用 context manager 临时修改 settings,评测结束后恢复原值。
  5. Output:不同配置组下可比较的 EX、生成成功率、可执行率、时延和 Token。
【代码精准溯源 (Code Anchor)】

论文配置矩阵见 latex/final.tex:912-941。总入口的 BIRD 组目录在 scripts/run_thesis_final_experiments.py:106-194,Spider 组目录在 :197-229。BIRD 脚本中的 PRESET_OVERRIDES 位于 scripts/run_bird_mini_dev_eval.py:107-133,开关参数映射 SETTING_SWITCH_ARGUMENTS 位于 :136-151,覆盖项构造在 build_setting_overrides():666),临时应用在 temporary_setting_overrides():717)。

【答辩白话解析 (防卡壳金句)】
“配置矩阵就是控制变量:只改变某一层能力,才能说明这个模块到底有没有贡献。”
09

BIRD 主结果与 Schema-RAG 基础作用

BIRD main results
BIRD Schema-RAG Result
【核心概念与设计初衷】

BIRD 主结果证明两点:完整配置组相对基础组有增量,但最大、最稳定的基础支撑仍是 Schema-RAG。关闭 Schema-RAG 后 EX 降到 47.0%,比 Full Final 低 10.0 pp,同时生成成功率和可执行率也从 92% 左右降到 74%,说明结构召回缺失会直接破坏 SQL 生成边界。

实验组 EX 核心解释
Pure Base-RAG 52.5% 只靠结构召回已有基础能力。
Base-RAG 55.5% 经验规则、Guard 和修复带来低成本增量。
Full Final 57.0% 完整增强进一步提升,但幅度较小。
No Schema Retrieval 47.0% 结构边界缺失后明显退化。
【算法逻辑与控制流向】
  1. Input:四组配置在 BIRD Mini-Dev offset 0 与 offset 100 合计 200 条样本上的评测结果。
  2. 统计每组生成成功率、预测 SQL 可执行率、EX、平均耗时和总 Token。
  3. 计算 Full Final 相对 Pure Base-RAG 的 EX 增量:+4.5 pp。
  4. 计算 Full Final 相对 Base-RAG 的 EX 增量:+1.5 pp,并标注为小幅变化。
  5. 计算 No Schema Retrieval 相对 Full Final 的下降:-10.0 pp。
  6. Output:Schema-RAG 是基础结构能力,完整增强收益受复杂样本比例和证据质量影响。
【代码精准溯源 (Code Anchor)】

BIRD 主结果表和图对应 latex/final.tex:950-973。脚本层面,结果行由 scripts/run_thesis_final_experiments.pysummary_row() 读取 summary.json:578),主对比表由 render_comparison_table() 渲染(:666),报告生成逻辑在 write_final_report() 的 BIRD 主对比段(:767-802)。单组 summary 的 EX 来自 scripts/run_bird_mini_dev_eval.py:1815-1816result_match_rate

【答辩白话解析 (防卡壳金句)】
“BIRD 主实验说明地基最关键:没有 Schema-RAG,后面再多证据和修复也会因为表字段边界不稳而掉分。”
10

Spider 结果与泛化解释边界

Spider interpretation boundary
Spider Generalization Boundary
【核心概念与设计初衷】

Spider dev 结果用于补充说明系统在跨数据库结构泛化任务上的表现,而不是作为完整增强稳定提升的强证明。Full Final 在 Spider dev 上 EX 为 72.9%,比 Base-RAG 的 71.9% 高 1.0 pp;论文谨慎解释为“小幅参照”,因为 Spider 更偏结构泛化,值证据和业务外部知识的作用不如 BIRD 直接。

【算法逻辑与控制流向】
  1. Input:Spider dev 199 条样本,覆盖多个 SQLite 数据库和 SQL 结构类别。
  2. 对 Base-RAG、No SQL Plan、Full Final、No Value Grounding、No SQL Experience、No SQL Guard 等配置组执行同口径评测。
  3. 对每题记录生成成功、可执行、EX、时延、Token 和模块诊断。
  4. 按 SQL category 聚合,观察不同 SQL 结构下的表现。
  5. Output:完整链路在 Spider 上保持基础跨库能力,但不能过度宣称稳定泛化提升。
【代码精准溯源 (Code Anchor)】

Spider 论文结果见 latex/final.tex:975-1001。Spider 评测按 SQL 类别聚合的逻辑在 scripts/run_spider_dev_eval.py:412-429,Markdown 报告渲染在 :437-493。最终实验总入口中 Spider 组调用在 scripts/run_thesis_final_experiments.py:442-472,Spider 报告段在 :804-827

【答辩白话解析 (防卡壳金句)】
“Spider 的作用是补充看跨库泛化;1.0 个百分点只能说明保持了基本适应性,不能夸成稳定大幅提升。”
11

难度分层与模块消融

Difficulty and ablation
Difficulty Ablation Heatmap
【核心概念与设计初衷】

难度分层用于回答“增强策略在哪些问题上有效”,模块消融用于回答“哪些模块贡献更稳定”。实验结论是:Schema-RAG 在三个难度层均为正贡献,平均约 +10.0 pp;其他增强项更依赖问题难度和风险信号,challenging 样本上更明显,simple 样本上可能出现负贡献。

模块 平均贡献 解释要点
数据库模式检索 +10.0 pp 最稳定基础支撑,提供表字段和关系边界。
检索证据 / 术语召回 +2.3 pp 更适合业务表达和结构线索复杂的样本。
SQL 计划 / 问题改写 +1.7 pp 主要在复杂过滤、聚合口径和多约束问题中发挥作用。
语义验证器 +0.0 pp challenging 有收益,但 simple/moderate 可能过度干预。
【算法逻辑与控制流向】
  1. Input:simple、moderate、challenging 三个难度层,每层 100 条样本。
  2. 先比较 Pure Base-RAG 与 Full Final,得到分层整体增量:0.0、+2.0、+6.0 pp。
  3. 再对每个模块执行 Full-NoModule 对比,得到每个模块在三种难度下的贡献。
  4. 把贡献绘制为热力图,横向看同一模块随难度变化,纵向看同一难度下模块差异。
  5. Output:增强策略应按复杂度和风险触发,不能把所有模块线性相加解释。
【代码精准溯源 (Code Anchor)】

难度分层结论见 latex/final.tex:1003-1038;消融表与热力图说明见 latex/final.tex:1040-1098。图 fig4-4_bird_ablation_heatmap 已在本 HTML 的 SQL Plan 域插入并解释。脚本层面,消融组来自 scripts/run_thesis_final_experiments.py:111-152 和扩展组 :154-194;消融表渲染在 render_ablation_table():678);模块诊断统计在 module_diagnostics():615)。

【答辩白话解析 (防卡壳金句)】
“消融结论不能按模块简单加总;Schema-RAG 是常驻地基,其他增强更像高风险复杂题的工具箱。”
12

典型样本轨迹与成本收益边界

Case trajectories and cost trade-off
Case Cost Trade-off
【核心概念与设计初衷】

典型样本分析把聚合数字还原到单题轨迹,解释增强链路的三种结果:纠正局部错误、阻断证据不足查询、在简单题上引入输出口径偏差。成本分析则说明完整增强不是免费收益,Token 和模型耗时会显著增加,因此更适合作为复杂样本和能力上限配置。

【算法逻辑与控制流向】
  1. Input:单题 cases.jsonl 中的检索表、值证据、SQL Plan、Verifier、Repair、错误阶段、耗时和 usage。
  2. 对匹配和失败样本按轨迹分类:纠偏、阻断、过度修复。
  3. 统计不同难度下修复触发和成功情况:challenging 100 条触发 17 次、6 次最终匹配;moderate 触发 7 次、6 次匹配;simple 触发 9 次、3 次匹配。
  4. 成本侧比较 Pure Base-RAG、Base-RAG、Full Final 的平均耗时、总 Token、单题 Token 和 EX。
  5. 识别主成本来源:生成前证据、执行前后检查、语义验证日志、自动修复重试和长 Prompt。
  6. Output:增强应按召回置信度、SQL 风险和结果形态要求触发,不适合作为所有请求的无差别默认配置。
【代码精准溯源 (Code Anchor)】

典型样本表和轨迹图在 latex/final.tex:1102-1146;成本分析在 latex/final.tex:1148-1212;章节结论在 latex/final.tex:1216-1222。代码层面,单题结果字段由 scripts/run_bird_mini_dev_eval.py:952-1049 初始化,并在 :1191-1460 写入 SQL Plan、生成、Guard、执行、Verifier、Repair、Gold 执行和结果比较。Token 合并在 merge_usage_dict():1491),summary 中的耗时与 token 统计在 build_summary():1713-1824)。

【答辩白话解析 (防卡壳金句)】
“完整增强能救一部分复杂题,也会花更多 token 和时间;我的结论是按风险触发,而不是所有问题都上满配置。”

论文图表与算法速记

集中复盘 latex/final.tex 中的正式图片、算法伪代码和核心公式。答辩时可以把这一节当作“论文图怎么讲、算法怎么背、公式怎么解释”的速查区。

论文原图索引与新增补齐

当前 final.tex 实际引用 13 张图片:系统架构、RAG、增强控制流、修复状态机、SSE、功能测试、实验结果和成本图均已在本 HTML 中覆盖。下面两张是此前缺失的第 5 章功能测试截图,适合在答辩中证明系统不是只跑离线评测,也有前后端真实功能闭环。

论文原图:错误领域问题提示截图
论文原图 · 错误领域问题提示截图 这张图对应第 5 章功能测试中的越界问题场景:当用户问题明显脱离当前数据源业务域时,系统不应该强行拼出 SQL,而应进入可解释的错误提示或拒答路径。

答辩讲解

  1. 先强调测试目标:验证系统具备“知道不能答”的能力,而不是任何问题都盲目生成 SQL。
  2. 再说明控制点:主链路会在检索、Prompt、Guard、执行和语义验证阶段不断检查问题是否能落到当前数据源。
  3. 最后落到用户体验:前端展示的是明确错误提示,不是空白、崩溃或无依据 SQL。

代码对应:错误收敛在 backend/chat/service.pystream_chat() 主链路和运行时事件封装中完成;SQL 越界或不安全查询会在 backend/services/sql_guard.pyguard_query_sql() 阶段被拦截;前端通过 frontend/src/api/sse.tsfrontend/src/views/chat/chatRunControl.ts 合并错误事件并展示。

答辩讲法:这张图证明系统的目标不是“永远生成 SQL”,而是“能答就查,不能答就有边界地拒绝”。

论文原图:多表 JOIN 查询结果截图
论文原图 · 多表 JOIN 查询结果截图 这张图对应功能测试中的多表查询场景:用户只提出自然语言问题,系统需要召回相关表、补全关系表、生成 JOIN SQL、执行并把结果表返回给前端。

答辩讲解

  1. 先看输入:用户没有手写 JOIN,只给出业务问题。
  2. 中间链路由 Schema-RAG 召回直接相关表,再通过显式关系或推断关系补入连接路径。
  3. 生成后 SQL 还要经过表字段边界、JOIN 关系和只读执行校验,最后把结构化结果渲染成表格。

代码对应:关系补全由 backend/services/schema_retrieval.py_load_relation_edges()_infer_relation_edges()_expand_bundles_with_relations() 实现;执行由 backend/services/sql_executor.py 完成;结果流式回传和落库由 backend/chat/service.py 主链路完成。

答辩讲法:这张图证明 Schema-RAG 不是只找表名,它还能把 JOIN 所需的关系路径补齐,最终落成真实执行结果。

论文图片 答辩作用 HTML 位置
fig2_rag_general_process 说明 RAG 通用流程,为后续 Schema-RAG 铺垫理论基础。 Schema-RAG 域:RAG 通用流程图
fig3-1_system_architecture 答辩开场总图,说明前端、ChatService、增强服务、数据库和日志闭环。 系统总体架构域:总体架构图
fig3-3_enhanced_control_flow 展示生成前增强、生成后校验、执行与修复的多策略控制流。 Schema-RAG 域:增强控制流图
fig3-4_repair_state_machine 解释 SQL Guard、执行、语义验证和自动修复的状态迁移。 校验验证修复域:修复状态机图
fig3-5_stream_sequence 解释一次提问如何通过 SSE 分阶段传给前端。 主链路 SSE 域:流式交互图
fig5_3_error_domain_prompt_cropped 证明系统对越界问题有拒答和错误收敛能力。 本节:错误领域问题提示截图
fig5_2_join_query_result_cropped 证明多表 JOIN 从检索、补表、生成到执行结果展示可跑通。 本节:多表 JOIN 查询结果截图
fig5_1_chart_generation_cropped 证明查询结果可进一步生成图表,不停留在 SQL 文本。 结果后处理域:图表生成截图
fig4-2_bird_main_ex 主对比实验图,说明 Full Final、Base-RAG 和 Pure Base-RAG 的 EX 差异。 实验域:BIRD 主对比图
fig4-3_bird_difficulty_gain 解释收益随难度变化,避免把平均提升讲得过度绝对。 实验域:难度分层图
fig4-4_bird_ablation_heatmap 说明各增强模块的消融影响和交互边界。 SQL 计划域:消融热力图
fig4_case_trajectory_option_b 用典型样本轨迹解释“为什么对、为什么错、为什么修复”。 实验域:样本轨迹图
fig4-5_cost_comparison 展示增强链路的 token 与时延成本,支撑按风险触发的结论。 运行配置域:成本对比图

核心算法伪代码 4D 速记

A1

算法 1:数据库模式混合召回与关系补全

Hybrid schema retrieval and relation completion
Schema-RAG 算法 关系补全
【核心概念与设计初衷】

该算法对应论文 alg:chapter3-schema-retrieval,目标是在真实数据库中从大量表字段里选出与问题最相关的 Schema 子集。设计初衷是解决大模型直接面对全量 Schema 时上下文过长、无关表干扰、JOIN 路径缺失和幻觉字段生成的问题。

【算法逻辑与控制流向】
  1. Input:自然语言问题 q、数据源标识 datasource_id、启用表字段集合、表向量快照、显式关系边。
  2. 对问题做分词与归一化,读取 checked=True 的表和字段,构建表级 bundle。
  3. 计算关键词命中分、向量相似度分和启发式加分,得到表级混合排序分。
  4. 选出 Top-k 直接命中表,加载显式关系;若显式关系不足,再按字段命名规则推断潜在关系。
  5. 围绕直接命中表补入必要关系邻居,并控制补表数量,避免无边界扩张。
  6. Output:focused_schemaretrieved_tablesselected_tablesrelation_tablesforeign_keys 和 ranking evidence。
【代码精准溯源 (Code Anchor)】

论文位置:latex/final.tex:326-353。工程实现集中在 graduation-design/backend/services/schema_retrieval.py:入口函数是 retrieve_relevant_schema()(约 :1389),分数计算在 _calculate_bundle_score()(约 :663)和 _calculate_bundle_heuristic_bonus()(约 :688),显式关系加载在 _load_relation_edges()(约 :739),关系推断在 _infer_relation_edges()(约 :1128),关系扩展在 _expand_bundles_with_relations()(约 :1253)。

【答辩白话解析 (防卡壳金句)】
“Schema-RAG 不是把全库塞给模型,而是先找直接相关表,再把 JOIN 必需的邻居表补进来。”
A2

算法 2:值证据候选生成与条件值定位

Value grounding candidate generation
Value Grounding WHERE 强证据
【核心概念与设计初衷】

该算法对应论文 alg:chapter3-value-grounding,负责把用户问题中的实体词、枚举值、时间词或条件短语映射到真实数据库字段取值。设计痛点是自然语言里的“华东”“已完成”“2024 年”并不天然等于某个字段值,若不做值定位,模型容易把 WHERE 条件写错、漏写或写成不存在的值。

【算法逻辑与控制流向】
  1. Input:自然语言问题、数据源 Schema、字段画像配置、可选的直接数据库查找开关。
  2. 构建或刷新字段值画像:文本/枚举字段采样高频值,日期/数值字段记录范围画像。
  3. 从问题中抽取候选短语,过滤过短、纯停用词或明显不适合查值的片段。
  4. 用精确匹配、包含匹配、相似匹配和可选 DB exact lookup 生成候选值证据。
  5. 对候选按置信度、匹配类型、字段重要性和去重规则排序截断。
  6. Output:ValueGroundingCandidate 列表、字段画像摘要、强证据表集合和可注入 Prompt 的值证据块。
【代码精准溯源 (Code Anchor)】

论文位置:latex/final.tex:424-458。工程实现集中在 graduation-design/backend/services/value_grounding.py:画像刷新在 refresh_datasource_value_index()(约 :269),问题短语抽取在 _extract_question_phrase_items()_extract_question_phrases()(约 :400:428),DB 精确查找在候选生成逻辑中(约 :621 起),Prompt 注入由 format_value_grounding_prompt()get_value_grounding_prompt_block()(约 :728:779)完成。

【答辩白话解析 (防卡壳金句)】
“Value Grounding 就是给 WHERE 条件找真实落点,先确认用户说的值在数据库里到底长什么样。”
A3

算法 3:SQL 校验、语义验证与自动修复循环

Guard, execution, verifier and repair loop
SQL Guard Verifier Repair
【核心概念与设计初衷】

该算法对应论文 alg:chapter3-guard-verify-repair,负责回答“生成出来的 SQL 能不能安全执行、执行后是否可能答偏、失败时是否可控修复”。设计初衷是把 SQL 从模型输出文本转化为受只读边界、Schema 边界、执行反馈和语义风险共同约束的可审计结果。

【算法逻辑与控制流向】
  1. Input:模型生成 SQL、当前 focused schema、问题、SQL Plan、值证据、修复次数上限。
  2. 先执行确定性语义修补,例如方言兼容、明显日期字段或别名问题的规则化修正。
  3. 解析 SQL 引用的表字段,进行只读白名单、表字段存在性、歧义列和 JOIN 关系校验。
  4. 通过 SQL Executor 在只读边界内执行,捕获数据库错误、行数和结果预览。
  5. 执行语义验证,判断 SQL 是否遗漏条件、误用聚合、结果形态偏离或证据冲突。
  6. 若通过则输出最终 SQL 与结果;若失败且可修复、未超过次数上限,则构造聚焦修复上下文重新生成修复 SQL。
  7. Output:通过的 SQL/result,或带错误类型、修复轨迹和失败原因的可解释终态。
【代码精准溯源 (Code Anchor)】

论文位置:latex/final.tex:579-614。工程实现分散在生成后控制链:只读与 Schema 边界校验由 graduation-design/backend/services/sql_guard.pyguard_query_sql()(约 :578)完成;执行由 sql_executor.py 完成;语义验证由 sql_semantic_verifier.pyverify_sql_semantics()(约 :186)完成;确定性修补由 sql_semantic_fixer.pyapply_semantic_sql_fixes()(约 :1230)完成;主循环由 backend/chat/service.py 调度。

【答辩白话解析 (防卡壳金句)】
“这条链路先问能不能安全跑,再问跑出来是不是答题,失败才在有限次数内修。”
A4

算法 4:ChatService 智能问答主链路

End-to-end orchestration with SSE events
ChatService SSE 端到端
【核心概念与设计初衷】

该算法对应论文 alg:chapter3-chat-orchestration,描述一次自然语言提问如何被后端编排为检索、增强、计划、生成、校验、执行、后处理和流式返回的完整流程。设计初衷是把多个增强模块统一纳入可追踪主链路,避免模块各自工作但无法解释最终答案来源。

【算法逻辑与控制流向】
  1. Input:用户问题、会话标识、可选数据源、历史上下文、前端 SSE 连接。
  2. 创建 ChatRecord、运行时上下文和 SSE 阶段事件,必要时进行多轮问题改写。
  3. 选择数据源,执行 Schema-RAG 与 Value Grounding,并根据强证据补充 Schema。
  4. 检索术语、样例、Domain Memory、Evidence、SQL Experience,并按上下文契约汇总。
  5. 构造 SQL Plan 与 Prompt,调用 LLM 流式生成 SQL JSON。
  6. 执行确定性修补、SQL Guard、SQL Executor、Semantic Verifier 和有限自动修复。
  7. 保存 SQL、结果、日志、token 和错误信息,向前端发送 stepsql_deltaresultdoneerror 事件。
  8. Output:一条可复盘的问答记录、最终 SQL、执行结果、阶段日志和前端可展示状态。
【代码精准溯源 (Code Anchor)】

论文位置:latex/final.tex:637-665。工程主入口在 graduation-design/backend/chat/service.pyChatService 类约从 :499 开始,运行时创建在 _create_stream_runtime()(约 :877),模型流式调用在 complete_text_with_control() 调用处(约 :1680),Guard 调用约在 :1761,语义验证流式步骤约在 :1873:2016,对外流式接口是 stream_chat()(约 :2106)。

【答辩白话解析 (防卡壳金句)】
“ChatService 像总调度,把检索、证据、生成、校验、执行和 SSE 展示串成一条可复盘流水线。”

核心公式速记

公式 解释口径 代码/论文对应
y_hat = argmax_y P_theta(y | P(q,S,K,V,E,Pi,H,C,F)) SQL 不是只由问题 q 决定,而是由聚焦 Schema、知识、值证据、检索证据、计划、历史、约束和反馈共同编排后的 Prompt 决定。 论文 latex/final.tex:207-214;工程落点是 backend/services/prompt_builder.pybackend/chat/service.py 汇总上下文。
Score(T_i,q)=w_e*Sim(E(q),E(T_i))+(1-w_e)*Norm(KW(T_i,q))+H(T_i,q) Schema-RAG 的表级排序由向量语义、关键词匹配和启发式业务信号共同决定;它不是端到端训练出的重排器,而是可解释的混合召回分。 论文 latex/final.tex:317-322;工程落点是 schema_retrieval.py_calculate_bundle_score() 和启发式加分函数。
Plan(q)=<T,C,F,M,A,G,H,O,J,R,U,S,c> SQL Plan 把用户问题拆成必要表、目标列、过滤条件、指标、聚合、分组、排序、JOIN、风险、未解决项、结果形态和置信度。 论文 latex/final.tex:496-503;工程落点是 backend/services/sql_planner.pySQLPlanResult 与计划注入逻辑。
EX = N_match / N_totalDelta EX = EX_target - EX_baseline EX 关注执行结果是否匹配,而不是 SQL 文本是否完全一致;Delta EX 用来解释目标系统相对基线的增量收益。 论文 latex/final.tex:798-814;工程落点是 scripts/run_bird_mini_dev_eval.py 中的 gold 执行、结果比较和 summary 统计。

高频追问速答

聚焦委员会常问的设计取舍、降级策略、关系补全边界、条件值定位、执行安全、语义验证、自动修复、实验指标、消融解释和成本边界。

老师追问 建议回答
你的系统和普通 ChatGPT 问答最大的区别是什么? 普通问答主要生成自然语言,本系统必须把问题落到当前真实数据源,先检索表字段和关系,再生成 SQL,并经过安全校验、执行和语义验证。
为什么说它不是传统 BI 平台? 传统 BI 依赖预先配置好的指标和报表;本系统重点是动态 NL2SQL,把临时自然语言问题转成可执行查询,再按结果生成表格、图表和解释。
三类元数据为什么要分开讲? 数据源与 Schema 画像约束结构,增强知识与证据补充业务语义,问答运行记录负责追踪和复盘;三者职责不同,混在一起会导致边界不清。
为什么要前后端分离? 前端负责交互状态、阶段展示和结果渲染;后端负责数据源连接、模型调用、SQL 安全和执行。这个边界可以避免浏览器直接接触数据库和模型密钥。
系统启动时为什么还要做索引预热? Schema、术语、样例和领域记忆需要向量或索引支撑检索;后台 warmup 可以提前准备增强能力,同时通过初始化状态允许基础页面降级进入。
如何证明问答结果不是黑盒生成? 系统会保存 ChatRecord 和 ChatLog,记录问题、SQL、执行结果、阶段日志、Prompt、模型响应和错误信息,因此可以按步骤复盘每次问答。
为什么数据源创建后要立刻同步元数据? 因为 NL2SQL 不能只依赖连接配置,必须先知道当前数据源有哪些表、字段和注释;创建后自动同步可以保证数据源保存完就具备问答结构边界。
Excel/CSV 为什么要转成本地 SQLite? 这样文件型数据源可以复用数据库型数据源的连接、同步、预览、Schema-RAG 和 SQL 执行流程,不需要为文件单独实现一套问答链路。
表字段的 checked 开关有什么意义? checked 是人工可控的结构边界。未启用的表字段不会进入检索、值画像和 Prompt,可排除脏字段、敏感字段或业务无关字段。
为什么要维护 custom_comment,直接用数据库原始注释不行吗? 真实库的原始注释经常为空、过旧或偏技术命名;custom_comment 用于补充业务语义,让检索文本和 Prompt 更贴近用户自然语言。
为什么表关系要前端手动建模? 很多真实库没有显式外键,或外键不完整。手动关系建模可以把事实表和维表的 JOIN 路径固化下来,供关系补全、生成提示和 SQL 校验复用。
同步后的向量和值画像刷新失败会影响数据源管理吗? 不会。同步后的 embedding、值画像、Domain Memory 刷新属于增强能力,代码中异常只记录日志,基础元数据同步和数据源维护仍然可用。
为什么不用字段级向量检索? 字段级召回容易拆散同表上下文,JOIN 路径也更难恢复;本系统先用表级召回保结构完整,再通过字段证据和关系补全细化。
embedding 不可用时系统会不会瘫痪? 不会。代码会退化为 keyword_fallback,保留关键词和启发式召回,数据源管理与基础问答仍可运行。
关系补全会不会乱补表? 显式关系优先;无显式关系时才基于 ID 命名推断,并用问题相关性评分和补表上限控制范围。
检索证据会不会强迫模型选错表? 不会。Prompt 里明确说明 direct-hit 只是候选,不是硬约束;只有高置信且有强 grounding 标签时才给 top1 preference。
retrieved_tablesselected_tables 有什么区别? retrieved_tables 是直接召回命中的表,selected_tables 是关系补全后的最终表集合;后者可能包含为了 JOIN 必须补入的桥接表。
为什么 Schema-RAG 要过滤 checked=True 的表字段? 这是人工元数据边界。管理员未启用的表字段不会进入候选集,避免脏字段、敏感字段或业务无关字段干扰模型生成。
Value Grounding 和 Schema-RAG 的区别是什么? Schema-RAG 解决“查哪些表字段”,Value Grounding 解决“问题里的实体值落在哪个真实字段取值上”;前者给结构边界,后者给 WHERE 值证据。
为什么 Value Grounding 不直接生成 SQL? 它只提供候选过滤条件和列范围提示,最终是否使用仍由 SQL 生成、计划、校验和语义验证共同决定,避免把不确定值证据当硬规则。
强值证据的判定标准是什么? 代码中把 exactdb_exact 且置信度不低于 0.99 的候选视为强证据;它会产生 strong tables,并影响 Schema 补表、Guard 和语义验证。
为什么还要 DB 等值查找,采样画像不够吗? 采样画像有数量上限,目标值可能没被采到;DB 等值查找只对适合的短语做大小写无关精确查询,用来补回画像样本未覆盖但真实存在的值。
日期和数值字段为什么只记录范围? 日期和数值取值空间通常较大,枚举式采样意义不大;记录 min/max 可以提示模型合法范围和时间边界,又不会把大量连续值塞进 Prompt。
Value Grounding 失败会不会让问答失败? 不会。它是增强能力,未命中或关闭时 Prompt 块为空,主链路仍依赖 Schema-RAG、术语、样例和 SQL 校验继续执行。
为什么知识增强层要拆成术语、样例、Domain Memory 和 Evidence? 因为它们解决的问题不同:术语解释业务词,样例提供 SQL 写法,Domain Memory 保存长期业务片段,Evidence 约束指标口径;混成一个文本块会丢失优先级和来源。
术语召回会不会让模型使用不存在的字段? 不会。术语只解释业务含义,最终字段仍必须来自 M-Schema;Prompt 和 Guard 都要求不能臆造表字段。
全局 SQL 样例为什么不能直接复用表名字段名? 全局样例跨数据源使用,只能提供查询结构和写法模式;代码会把它标成 pattern_only 并写入不得复用表字段名的约束。
Domain Memory 和 datasource evidence 有什么关系? datasource evidence 是人工维护的业务证据;Domain Memory 会把 evidence、表注释、字段注释和关系说明统一转成可检索片段,是 evidence 的长期检索化形态之一。
问题级 evidence 和数据源级 evidence 冲突时怎么办? 问题级 evidence 优先,因为它是本轮问题的临时补充;但两者都不能违反当前 Schema 和真实字段语义。
Retrieval Evidence 为什么是保守注入? 它只解释 Schema-RAG 的 direct-hit、关系补表和 ranking 依据,不替代表选择;只有 top1 明显领先且有强 grounding 标签时,才给出高置信偏好。
问题改写为什么不每轮都调用大模型? 改写只在存在历史问答时才有意义;无历史、功能关闭或模型不可用时直接跳过,避免为了简单单轮问题增加成本和改写风险。
改写后的问题会不会覆盖用户原问题? 不会。系统同时保留原始问题和 effective_question,日志里能看到是否 applied、skip_reason 和模型原始输出,便于复盘。
问题分解为什么默认偏保守? 分解对复杂题有帮助,但简单题可能改变输出粒度;所以当前实现先用风险标签和白名单收缩范围,未命中时主链路直接生成。
SQL Experience 和 SQL 样例有什么区别? SQL 样例是“相似问题怎么写”的 few-shot 参考;SQL Experience 是“历史上哪里容易错”的规则提醒,强调错误边界和自检。
为什么 SQL Experience 不用向量检索? 经验规则数量和结构更适合可解释规则打分;代码会记录类别、关键词、Schema 特征和错误信息命中的 reasons,便于控制和排查。
成功 SQL 为什么不能直接进入样例库? 可执行不代表口径一定正确。系统先进入 SQL 经验候选队列,人工审核通过后才导入正式 DataTraining,避免污染样例库。
SQL Plan 和数据库执行计划有什么区别? 数据库执行计划服务于执行代价优化;本系统的 SQL Plan 服务于生成前语义约束,描述必要表、过滤条件、指标口径和结果形态。
为什么 SQL Plan 不直接生成 SQL? 直接生成 SQL 会把计划层变成第二个模型生成器;当前实现只用本地规则产出结构化约束,降低延迟,也避免和 LLM 的生成口径互相漂移。
shadowsoftenforced 有什么区别? shadow 只记录计划不注入 Prompt;softenforced 在达到置信度阈值后注入,区别在于答辩解释上 soft 更偏提示,enforced 更偏强约束。
SQL Plan 的置信度能当概率解释吗? 不能。它是启发式明确度分数,过滤条件、指标、目标列和结果形态会加分,未解决项会扣分,用于判断计划是否值得注入。
Prompt 为什么强制模型输出 JSON? 后端需要稳定解析 SQL、表名、图表类型和失败原因;如果模型返回自然语言混排文本,后续 Guard、执行、前端展示和日志复盘都会不稳定。
Prompt Override 会不会破坏默认生成约束? 覆盖能力受 PromptOverrideProfile.enabled 和非空字段控制;未启用或字段为空时仍走默认 YAML 模板,主链路上下文契约和解析对象保持不变。
为什么有了 SQL Guard 还要语义验证? Guard 主要回答“能不能安全执行、表字段是否越界”;语义验证回答“执行结果是否可能答偏”。能执行不等于答对,所以两层检查不能合并。
自动修复会不会把错误 SQL 越修越乱? 修复受错误类型和重试次数限制,默认最多 1 次;修复 SQL 还要重新经过 Guard、执行和语义验证,因此不是无边界重写。
为什么修复阶段要裁剪 Schema? 修复时如果继续给全量上下文,模型容易被无关表干扰;系统优先围绕失败 SQL 实际引用表、direct-hit 表和关系邻居构造 focused schema。
语义验证器为什么可能在简单问题上有副作用? 语义验证依赖保守规则,复杂问题收益更明显;简单问题中额外检查可能触发过度修复或改变输出列形态,所以论文中也把它解释为适合高风险场景触发。
为什么主链路用 SSE,而不是 WebSocket? 本系统是“客户端提交一次问题,服务端持续返回阶段状态和结果”的单向推送场景;SSE 基于普通 HTTP,足够承载阶段事件,也比 WebSocket 更轻。
为什么不直接等后端结束后一次性返回? 问答链路很长,包含检索、生成、校验、执行、修复等阶段;SSE 可以把阶段状态实时推给前端,避免用户面对长时间空白等待。
为什么每条事件都要带 record_id record_id 是本轮问答的稳定锚点,前端可把事件合并到正确草稿,后端也能把日志、SQL、结果和错误统一落到同一条记录。
为什么图表和解释不放在主 SSE 流里一起生成? 主流优先保证 SQL 与查询结果闭环;图表、解释和推荐追问属于结果后处理,按需生成可以减少主链路阻塞。
图表生成失败会不会影响已经查出的结果? 不会。图表是记录级可选后处理,失败时会回退为本地图表或表格配置;主结果表、SQL 和执行状态都已经落库。
为什么图表字段还要做规范化校验? 模型可能返回大小写不一致或不存在的字段名;后端和前端都会把坐标轴字段映射回真实结果字段,映射失败就回退,避免图表引用幻觉字段。
解释生成会不会编造业务结论? Prompt 明确要求只解释当前问题、SQL 和结果预览,不编造背景;模型失败时只用行数和字段名生成兜底说明。
起始推荐问题和追问推荐有什么区别? 起始推荐面向数据源空状态,基于 Schema 摘要或手工配置;追问推荐面向某条已完成记录,基于原问题、SQL、结果字段、结果预览和最近问题。
为什么 fallback 推荐不写入数据库缓存? fallback 是当前请求的保底结果,不一定代表高质量业务推荐;代码只把 LLM 成功生成的自动 starter 或记录级追问写入缓存,避免污染后续展示。
空结果时为什么推荐“恢复型追问”? 0 行结果通常说明时间、枚举或筛选条件过严;系统优先推荐确认可用范围、放宽条件和查看总体分布,而不是继续沿着失败条件下钻。
配置为什么要集中到 Settings,不能各模块自己写默认值吗? 集中配置能保证实验可复现、线上行为可解释;如果默认值散落在各服务里,增强开关、召回数量、修复次数和 token 预算很难统一控制。
模型配置从哪里来,数据库设置和环境变量谁优先? 有数据库会话时优先读取当前激活的模型设置;如果没有激活设置或读取失败,再回退到 settings.DEFAULT_LLM_* 环境配置。
Embedding 配置缺失时系统会不会启动失败? 不会。Embedding 可用性由门控函数判断,不可用时刷新函数会保存最新文本快照、清空旧向量,并让在线检索退回关键词和启发式排序。
为什么索引 warmup 不阻塞系统入口? 因为索引是增强能力,不是数据源管理和基础问答的硬前置。启动时先初始化数据库和默认数据,再后台预热索引,前端通过状态接口展示 degraded 或 ready。
warmup 失败后用户怎么知道该怎么办? 状态接口会返回 degradedsummaryrecommended_actionlast_error 和离线预构建命令;前端初始化页和降级横幅会展示这些信息。
离线预构建脚本解决什么问题? 它用于部署前、答辩演示前或 warmup 失败后同步补齐表向量、数据源向量、术语、样例和推荐缓存,降低冷启动和现场等待风险。
为什么完整配置组更慢但仍然有意义? 完整配置组增加术语、样例、值证据、SQL Plan、语义验证和修复等上下文,Token 和模型耗时会上升;它的意义在于覆盖复杂问题和能力上限,而不是无条件替代轻量链路。
为什么论文主指标用 EX,而不是 SQL 文本完全一致率? 因为同一个问题可能有多条语义等价 SQL,文本不同但执行结果相同仍应判为正确;EX 更贴近用户关心的“查出来的结果对不对”。
BIRD 和 Spider 分别证明什么? BIRD 主要验证真实数据库值、外部证据和复杂业务约束下的执行效果;Spider 作为补充,验证跨数据库结构泛化,不能把两者混成同一种结论。
为什么 No Schema Retrieval 组很关键? 它只关闭数据库模式检索,其他增强保持完整配置;如果该组明显下降,就能说明结构召回是基础约束,不是被值证据或修复轻易替代的模块。
Full Final 只比 Base-RAG 高 1.5 pp,怎么解释? 要谨慎解释为小幅增量,不能夸大成稳定大幅提升;它说明完整增强在当前 200 条样本上有收益,但还需要结合难度分层和消融说明收益主要来自复杂题。
为什么增强策略在 simple 样本上可能没有收益甚至负贡献? 简单题通常只需要少量表字段,基础 Schema-RAG 已足够;额外验证、修复或证据注入可能改变输出列粒度或增加噪声,所以增强更适合按风险触发。
消融实验里的模块贡献能直接相加吗? 不能。模块之间有依赖和交互,Full-NoModule 只是近似观察关闭单个模块后的变化,必须结合难度、样本类型和触发条件解释。
典型样本分析为什么重要? 平均指标只能说明总体变化,典型样本能解释变化原因:有的样本被语义验证修正,有的因结构证据不足被阻断,也有简单题被过度修复。
运行成本主要花在哪里? 主要花在模型调用和长 Prompt,不是数据库执行。论文日志显示 SQL 生成通常是数秒级,预测 SQL 执行只有几十毫秒量级。
论文里的 13 张图答辩时应该按什么顺序讲? 先讲系统架构图定边界,再讲 RAG 和 Schema-RAG 控制流说明方法,随后讲修复状态机和 SSE 证明工程闭环,最后用功能截图、BIRD/Spider/消融/成本图证明效果与边界。
功能测试截图能不能作为论文证据? 可以,但证据类型不同。功能截图证明系统链路和交互可用,不能替代离线 EX 指标;论文中应把它作为工程实现与功能闭环证据,指标结论仍看 BIRD、Spider 和消融实验。
错误领域问题截图想证明什么? 它证明系统不是无边界生成器。问题脱离当前数据源时,系统应该返回可解释错误或拒答,而不是编造表字段和 SQL,这对应 Guard、主链路错误收敛和前端错误展示能力。
多表 JOIN 功能截图想证明什么? 它证明自然语言问题可以经过 Schema-RAG 召回、关系补全、SQL 生成、执行和结果渲染变成真实多表查询结果,重点支撑“关系补表不是纸面设计”。
算法 1 的输入输出如果老师要求现场说清楚,怎么答? 输入是问题、数据源、启用表字段、向量快照和关系边;输出是 focused schema、直接召回表、关系补全后的最终表、外键关系和排序证据。核心就是先召回,再补 JOIN 路径。
算法 2 为什么要把值画像和 DB exact lookup 结合? 值画像快、可缓存,但采样可能漏值;DB exact lookup 慢一些但能补真实存在的精确值。两者结合是为了在成本可控前提下提高 WHERE 条件落点准确性。
算法 3 为什么不是简单 try-catch 重试? 它不是盲目重试,而是先分类错误来源:只读越界、表字段不存在、JOIN 风险、执行错误、语义偏差。只有可修复且未超过次数上限时才构造聚焦上下文修复。
算法 4 和系统架构图有什么区别? 架构图讲模块边界和数据流,算法 4 讲一次请求的时间顺序。前者回答“系统由什么组成”,后者回答“用户点发送之后每一步怎么走”。
提示词目标公式是不是只是装饰? 不是。公式把 Prompt 的组成变量显式化:Schema、知识、值证据、检索证据、计划、历史、约束和反馈都进入生成条件,工程上对应 PromptBuilder 与 ChatService 的上下文拼装。
混合召回公式里的 H(T_i,q) 怎么解释? 它是启发式加分项,用来补足向量和关键词难覆盖的业务信号,例如表名/字段名强命中、值证据强关联、关系表必要性等,不是不可解释的模型参数。
SQL Plan 公式里的置信度 c 为什么不能当概率? 因为它不是统计训练得到的概率,而是计划完整度和明确度分数。它只用于判断计划是否适合注入 Prompt,以及在日志里解释计划约束强弱。
为什么 EX 不看 SQL 文本完全一致? NL2SQL 存在多条等价写法,比如子查询和 JOIN、不同别名、条件顺序不同都可能得到同样结果;EX 以执行结果为准,更贴近用户关心的答案正确性。
消融热力图如果出现负贡献,是否说明模块没用? 不能简单这么说。负贡献可能说明模块在某些样本上引入噪声或过度约束,结论应是“需要按风险触发和按场景开关”,而不是把模块完全否定。
成本图如何避免被老师追问“太慢不实用”? 要承认完整增强更慢,然后强调系统支持分层配置:简单问题走轻量链路,复杂或高风险问题再启用语义验证、修复和更多证据;成本图正是用来说明这种工程取舍。
如果老师问代码和论文算法是否完全一一对应,怎么回答? 论文算法是工程流程的抽象表达,不会逐行等同代码;但关键输入输出和控制阶段一一对应,例如 Schema-RAG 对应 schema_retrieval.py,Value Grounding 对应 value_grounding.py,修复链路对应 Guard、Executor、Verifier、Fixer 和 ChatService。
前端如何避免 SSE 半包解析失败? 前端维护 buffer,用空行切出完整事件块,未完整的 rest 保留到下一次读取,只有完整 data: 块才 JSON parse。