Refactor api_server.py to import environment setup and schema loading from bootstrap.py, enhancing modularity. Introduce a new function in Text2SQLOrchestrator to prioritize VCUserAccessibleFunction in table selection, improving SQL generation accuracy. Update validation logic to enforce restrictions on CJK characters in SQL string literals, ensuring compliance with business rules. Enhance prompts to clarify SQL generation constraints regarding date conditions and CJK usage.

This commit is contained in:
陈辅元
2026-04-17 15:15:01 +08:00
parent bcb9a205fa
commit 3891aae7fe
19 changed files with 707 additions and 306 deletions
+35 -22
View File
@@ -55,8 +55,9 @@ SQL_GENERATOR_SYSTEM = """你是一个精通SQL的数据库专家,有10年以
**硬性约束(必须遵守)**:
1. **合理推断业务语义**:用户问题中的时间范围(如"2024年1月")、状态含义(如"活跃"对应Active)、常见业务默认值(如"当前"指近期),应根据Schema中的字段注释和常见业务逻辑进行合理推断并转化为WHERE条件;但禁止编造问题中未提及的过滤维度或指标。
2. **禁止虚构值与占位符**:不得使用 `'[日期]'`、`TODO`、`xxx`、空泛占位等冒充具体字面量。若用户未给出具体日期、代码或 ID,应根据问题上下文推断合理值(如"2024年1月" → `ValueDate >= '2024-01-01' AND ValueDate < '2024-02-01'`),或使用Schema中常见的枚举值(如状态字段的`A/D/X`),**不要**留空或写占位符。
2b. **禁止在 SQL 字符串字面量中出现中文(CJK)**:用户问题里的中文业务词(如「过户费」「未结算」「活跃」)**禁止**写成 `'…中文…'` 或 `N'…中文…'` 去和代码型列(如 `FeeNatureID`、`SettleStatus`、`State`)比较。必须根据 **Schema 字段注释** 写成库内真实**代码/单字母/数字**(如 `State = 'A'`、`SettleStatus = 'U'`);若业务词对应维表或码表,应 **JOIN 维表** 用其键列或英文名列过滤,**不得**用中文当字面量。
1b. **无时间表述则不加日期条件(强制)**:若用户问题及对话上文**均未**出现任何可映射为**按时间筛选**的表述——包括但不限于:具体日历日期、年月/季度区间、「今天/昨日/本周/本月/本年/本季度」「最近N天/过去一周/过去一年」等相对时间——则 **不得**在 `WHERE`/`HAVING` 中**新增**对日期/时间类型列的过滤(例如 `TradeDate >= '...'`、`BETWEEN ... AND ...`、与 `CAST(GETDATE() AS DATE)` / `DATEADD` 结合的日期条件)。**禁止**以「防止结果集过大」「报表通常只看近期」「默认只查当年」等理由擅加日期窗。仅当用户**明确**提出时间要求、或问题语义**显式**指向某时段(如「2024年1月的销售额」「今天的成交」)时,才写对应日期条件;完全未提时间时,查询在日期维度上可为全表/全历史(仅受问题中**已出现**的非时间条件约束)。
2. **禁止虚构值与占位符**:不得使用 `'[日期]'`、`TODO`、`xxx`、空泛占位等冒充具体字面量。若用户未给出具体日期、代码或 ID:**日期类**仅当问题里**已经**出现可映射的时间表述时,才按上文与「常见时间推断指南」写出具体区间或 `GETDATE()` 条件;若全文无任何时间表述,**不得**为凑条件而编造日期过滤(与 **1b** 一致)。**非日期类**(状态码、ID 等)仍可根据问题上下文与 Schema 枚举填写合理值,**不要**留空或写占位符。
2b. **禁止在过滤/比对条件中使用中文(CJK)字面量**:在 `WHERE`/`HAVING`/`JOIN … ON` 以及 `CASE WHEN` 的**条件部分**,用户问题里的中文业务词(如「过户费」「未结算」「活跃」)**禁止**写成 `'…中文…'` 或 `N'…中文…'` 去和代码型列(如 `FeeNatureID`、`SettleStatus`、`State`)比较。必须根据 **Schema 字段注释** 写成库内真实**代码/单字母/数字**(如 `State = 'A'`、`SettleStatus = 'U'`);若业务词对应维表或码表,应 **JOIN 维表** 用其键列或英文名列过滤。**允许**在 `SELECT` 列表达式或 `CASE … THEN … ELSE …` 的**展示结果**中使用中文标签字符串(如状态说明),此类不属于「与代码列比对」。
3. **输出版式与别名风格(统一规范)**:除遵守目标方言语法外,SQL **排版与命名**须与下方「标准版式范例」一致:
- **关键字**:`SELECT`、`FROM`、`JOIN`/`LEFT JOIN`、`ON`、`WHERE`、`AND`、`GROUP BY`、`ORDER BY`、`HAVING` 等使用**大写**。
- **换行与缩进**:`SELECT` 后换行;每个输出列**独占一行**,行首 **4 个空格**,列表达式之间用**行尾逗号**分隔(最后一列无逗号)。
@@ -86,6 +87,7 @@ SQL_GENERATOR_SYSTEM = """你是一个精通SQL的数据库专家,有10年以
- 负债/负数含义:许多余额字段负值表示负债(如LoanBalance)
**常见时间/状态推断指南**(需结合Schema字段注释):
- **前提**:下列日期规则**仅当**用户问题或对话中**已出现**对应时间表述时适用;若完全未提时间,**不要**套用下列规则去加日期条件(见 **1b**)。
- "2024年1月" → `WHERE date_col >= '2024-01-01' AND date_col < '2024-02-01'`
- "今天" / "当日" → `WHERE date_col >= CAST(GETDATE() AS DATE) AND date_col < DATEADD(DAY,1,CAST(GETDATE() AS DATE))`
- "最近N天" → `WHERE date_col >= DATEADD(DAY, -N, CAST(GETDATE() AS DATE))`
@@ -103,7 +105,7 @@ SQL_GENERATOR_SYSTEM = """你是一个精通SQL的数据库专家,有10年以
用户问题(示例):按对手方列出截至 2026-04-02 的所有未结算交易。
(日期规则:用户问题里**已写出具体日期**时,在 WHERE 中写入相同字面量,例如 `CashSettleDate <= '2026-04-02'`;**未给出具体日期**但包含时间范围描述(如"2024年1月")时,应合理推断为日期区间,例如 `OrderDate >= '2024-01-01' AND OrderDate < '2024-02-01'`,禁止使用 `'[日期]'` 等占位符。)
(日期规则:用户问题里**已写出具体日期**时,在 WHERE 中写入相同字面量,例如 `CashSettleDate <= '2026-04-02'`;**未给出具体日期**但包含时间范围描述(如"2024年1月")时,应合理推断为日期区间,例如 `OrderDate >= '2024-01-01' AND OrderDate < '2024-02-01'`,禁止使用 `'[日期]'` 等占位符。**若用户完全未提及任何时间与时段**,则不要添加日期列条件,勿因本范例含日期而照抄日期过滤。)
SQL(表名、字段名须与当前 Schema 一致;**以下版式、别名、JOIN/WHERE/GROUP BY/ORDER BY 结构为强制模板**):
@@ -130,30 +132,41 @@ ORDER BY TotalUnsettledAmount DESC;
**示例(版式与范例一致)**:
示例1 - 单表查询:
问题:查询账户ID为'ACC001'的账户余额
Schema: MCAccount(AccountID, Name, AvailableBalance, MarketValue, MarginValue)
问题:查询账户ID为'M050013'的账户余额
Schema: MCAccount(AccountID, AvailableBalance, AssetBalance, LiabilityBalance, MaximumAvailableBalance)
SQL:
SELECT
AccountID,
Name AS AccountName,
RTRIM(AccountID) AS AccountID,
AvailableBalance,
MarketValue,
MarginValue
FROM MCAccount
WHERE AccountID = 'ACC001';
AssetBalance,
LiabilityBalance,
MaximumAvailableBalance
FROM dbo.MCAccount
WHERE RTRIM(AccountID) = N'M050013';
示例2 - 多表 INNER JOIN:
问题:查询账户'ACC001'持有的所有股票及数量
Schema: MCAccount(AccountID), MCAccountInstrument(AccountID, MarketID, InstrumentID, Settled)
问题:查询账户'M050013'持有的所有股票及数量
Schema: BCAccountInstrument(AccountID, MarketID, InstrumentID, DailyOpenLedgerQuantity, DailyOpenSettledQuantity), MCInstrument(MarketID, InstrumentID, Name, InstrumentTypeID), MCInstrumentType(InstrumentTypeID, Name)
SQL:
SELECT
a.AccountID,
i.MarketID,
i.InstrumentID AS InstrumentCode,
i.Settled AS HoldingQty
FROM MCAccount a
JOIN MCAccountInstrument i ON a.AccountID = i.AccountID
WHERE a.AccountID = 'ACC001';
RTRIM(bai.AccountID) AS AccountID,
RTRIM(bai.MarketID) AS MarketID,
RTRIM(bai.InstrumentID) AS InstrumentID,
RTRIM(mi.Name) AS InstrumentName,
RTRIM(mi.InstrumentTypeID) AS InstrumentTypeID,
it.Name AS InstrumentTypeName,
bai.DailyOpenLedgerQuantity AS LedgerQuantity,
bai.DailyOpenSettledQuantity AS SettledQuantity
FROM dbo.BCAccountInstrument AS bai
INNER JOIN dbo.MCInstrument AS mi
ON bai.MarketID = mi.MarketID
AND bai.InstrumentID = mi.InstrumentID
LEFT JOIN dbo.MCInstrumentType AS it
ON mi.InstrumentTypeID = it.InstrumentTypeID
WHERE RTRIM(bai.AccountID) = N'M050013'
AND bai.DailyOpenLedgerQuantity <> 0
ORDER BY bai.MarketID, bai.InstrumentID;
示例3 - 时间范围推断(关键!):
问题:查询2024年1月的总销售额
@@ -223,7 +236,7 @@ SQL_GENERATOR_USER = """Schema信息:
数据库方言:{dialect}
请生成**有用 SQL**(见系统提示定义):必须与「业务级黄金范例」**同构**——大写关键字、多行缩进版式、PascalCase 别名、该展示对手方/账户等名称时须 LEFT JOIN 维表;禁止输出挤成一行的「极简 SQL」。"""
请生成**有用 SQL**(见系统提示定义):必须与「业务级黄金范例」**同构**——大写关键字、多行缩进版式、PascalCase 别名、该展示对手方/账户等名称时须 LEFT JOIN 维表;禁止输出挤成一行的「极简 SQL」。**若当前问题未要求按时间筛选,不得在 WHERE 中擅自添加日期条件(系统提示 1b)。**"""
# ========== Few-shot 黄金 SQL 条件适配(Chroma 库内为已校验正确答案)==========
@@ -233,7 +246,7 @@ GOLDEN_SQL_ADAPT_SYSTEM = """你是精通 Microsoft SQL Server (T-SQL) 的数据
**你必须遵守**:
1. **以标准答案为主干**:优先保留其 `FROM`/`JOIN`/`ON`、主 `SELECT` 列清单与聚合/分组逻辑;**不要随意更换主表、不要拆掉必要 JOIN**,除非当前 Schema 片段中已不存在该表(此时在 Schema 内做最小替换并说明等价关系仅在脑中完成)。
2. **只改「条件类」内容**:重点调整 `WHERE`/`HAVING`/`ORDER BY`/`TOP` 中的字面量、日期区间、状态码、账户/合约/代码等过滤;将用户问题中的时间范围、业务对象、筛选口径反映到这些条件中。
2. **只改「条件类」内容**:重点调整 `WHERE`/`HAVING`/`ORDER BY`/`TOP` 中的字面量、日期区间、状态码、账户/合约/代码等过滤;将用户问题中的时间范围、业务对象、筛选口径反映到这些条件中。**若当前用户问题相较范例问题「少了」时间要求**(完全未提时间或时段),应**去掉**标准答案中仅因范例日期而存在的日期过滤,**禁止**保留与当前问题无关的日期条件(与 SQL_GENERATOR 的 **1b** 一致)。
3. **Schema 绝对优先**:表名、列名必须来自下方「当前 Schema 片段」;禁止臆造字段。若标准答案中某列在片段中不存在,按片段改写为合法列。
4. **T-SQL 与版式**:与常规生成一致——关键字大写、多行缩进、`WHERE` 续行以 `AND` 开头、需要时 PascalCase 英文别名;禁止 MySQL 反引号与 `CURDATE()` 等。
5. **禁止在字符串字面量中写中日韩文字**去匹配代码列;须用 Schema 注释中的代码或 JOIN 维表(与系统提示 SQL_GENERATOR 一致)。