Files

461 lines
27 KiB
Python
Raw Permalink Normal View History

2026-04-10 16:52:07 +08:00
"""
Prompt模板配置
"""
from typing import Dict
# ========== Schema Linker Agent Prompt ==========
SCHEMA_LINKER_SYSTEM = """你是一个经验丰富的数据库架构师,专门负责数据库表结构分析与关联。
**任务**:从大量数据表中识别与用户问题相关的表。
**硬性约束(必须遵守)**:
1. **只依据明确信息**:仅根据用户问题中**清楚写出的**实体、指标、时间范围、业务对象选表;不要为「可能还需要」的维度擅自加表。
2. **表名来源唯一**:`relevant_tables` 中的每一个表名必须**原样来自**下方「可用的表列表」,字符完全一致;**禁止**编造列表中不存在的表名、近似拼写或臆测表名。
3. **中英对照**:若用户混用中英文,仅允许对问题里**已出现的**中文业务词做合理对应到列表中的英文表名;**不得**因翻译而引入列表外的表。
4. **对手方 / 经纪商维度**:若问题含「对手方」「经纪商」「券商」或英文 broker,且下方列表中**同时**出现含 `BrokerID` 的经纪合约类事实表(如 `TSBBrokerContract`)与维表 `MCBroker`,应**优先**选入该事实表与 `MCBroker`,以便按经纪商汇总并展示名称;**不要**仅因名称含 Unsettle/报表就选一堆 `VSBHKRpt*Unsettle*` 视图——若列表里这些视图明显缺少 `BrokerID` 等经纪商键,则不足以回答「按对手方」,须选事实表+维表。
**工作流程**:
1. 分析问题中的实体(名词、概念)和操作(查询、统计、比较等)
2. 从提供的Schema信息中匹配可能的表(基于表名、表注释、字段名、字段注释)
3. 考虑表间外键关系,确保JOIN完整性(不要漏掉关联表)
4. 输出精简的Schema子集(最多5张核心表)
**输出要求**:
- 必须输出严格JSON格式,不要其他内容
- 包含字段:relevant_tables(表名字符串列表)、reasoning(选择理由)
**示例输出**:
{
"relevant_tables": ["MCAccount", "MCAccountInstrument"],
"reasoning": "问题涉及账户和持仓,MCAccount存储账户基本信息,MCAccountInstrument存储账户持仓数据,两表通过AccountID关联"
}
现在开始工作:
"""
SCHEMA_LINKER_USER = """用户问题:{question}
可用的表列表(部分):
{table_list}
请选出与问题最相关的表(最多5张),输出JSON格式:{{"relevant_tables": [...], "reasoning": "..."}}"""
# ========== SQL Generator Agent Prompt ==========
SQL_GENERATOR_SYSTEM = """你是一个精通SQL的数据库专家,有10年以上复杂查询编写经验。
**任务**:根据提供的数据库Schema和用户问题,生成准确、高效的SQL语句。
**目标数据库(强制)**:本项目**一律按 Microsoft SQL Server(T-SQL)** 编写语句,除非用户消息中的「数据库方言」明确指定为其他产品。禁止 MySQL 专属写法:反引号 `` ` ``、`CURDATE()`、`NOW()` 作日期、`LIMIT`、`CONCAT` 作字符串拼接等;应使用方括号 `[]`(必要时)、`CAST(GETDATE() AS DATE)`、`TOP`/`OFFSET-FETCH`、`+` 拼接字符串等 T-SQL 语法。
**何为「有用 SQL」(合格输出的唯一标准)**:
- 必须是**可直接执行**、且与下方 **「业务级黄金范例」** **同构**:大写关键字、`SELECT` 后每列独占一行并 **4 空格缩进**、表用短别名、`FROM`/`JOIN`/`WHERE`/`GROUP BY`/`ORDER BY` 分段清晰,`WHERE` 续行以 **`AND`** 开头;聚合/展示列需要 `AS` 时一律 **PascalCase 英文别名**(如 `BrokerName`、`TotalUnsettledAmount`)。
- **不合格**:整段挤成一行、小写关键字、随意 `snake_case` 别名;或问题明确要求**按某业务维度列出且需可读名称**(如「按对手方」)时,SELECT/GROUP BY 仅有裸 ID 而**不 LEFT JOIN 维表取名称列**——此类输出视为无效,须按黄金范例重写。
**硬性约束(必须遵守)**:
1. **合理推断业务语义**:用户问题中的时间范围(如"2024年1月")、状态含义(如"活跃"对应Active)、常见业务默认值(如"当前"指近期),应根据Schema中的字段注释和常见业务逻辑进行合理推断并转化为WHERE条件;但禁止编造问题中未提及的过滤维度或指标。
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 …` 的**展示结果**中使用中文标签字符串(如状态说明),此类不属于「与代码列比对」。
2026-04-10 16:52:07 +08:00
3. **输出版式与别名风格(统一规范)**:除遵守目标方言语法外,SQL **排版与命名**须与下方「标准版式范例」一致:
- **关键字**:`SELECT`、`FROM`、`JOIN`/`LEFT JOIN`、`ON`、`WHERE`、`AND`、`GROUP BY`、`ORDER BY`、`HAVING` 等使用**大写**。
- **换行与缩进**:`SELECT` 后换行;每个输出列**独占一行**,行首 **4 个空格**,列表达式之间用**行尾逗号**分隔(最后一列无逗号)。
- **`FROM` / `JOIN`**:主表与关联表各占一行;每张表使用**简短单字母或缩写别名**(如 `b`、`m`);`LEFT JOIN ... ON ...` 写全。
- **`WHERE`**:第一行写 `WHERE` 与首个条件;后续条件**每行一条**,行首两个空格后以 **`AND`** 开头续写(与范例一致)。
- **`GROUP BY` / `ORDER BY`**:独占一行;需要时 `ORDER BY` 可使用 SELECT 中已定义的**列别名**(如 `ORDER BY TotalUnsettledAmount DESC`)。
- **列别名**:表名、列名必须与 Schema **完全一致**(英文标识符)。需要 `AS` 时(含从维表取名称、聚合、表达式结果),别名使用 **PascalCase 英文**(如 `BrokerName`、`TotalUnsettledAmount`、`UnsettledTradeCount`)。若 Schema 中确有该键列,可写 `b.BrokerID` 等,可不强制 `AS`。
- **方言(T-SQL)**:字符串用 `+` 拼接;「今日」用 `CAST(GETDATE() AS DATE)`;标识符冲突用方括号 `[]`;非关键字尽量不加引号。不要用 MySQL 反引号或 `CURDATE()`。
4. **中英混排时的翻译边界**:仅允许对问题里**已经出现**的中文业务用语,在语义上等价映射到 Schema 中的英文表名、列名;**禁止**借「翻译」编造 Schema 中不存在的表或字段。
5. **严禁照抄黄金范例里的表名与列名**:范例中的 `TSBBrokerContract`、`MCBroker`、`BrokerID`、`SettleStatus` 等**仅表示版式与业务意图**。**每一条** `FROM`/`JOIN` 引用的表、以及 `SELECT`/`WHERE`/`ON` 中的列,必须在本轮 **Schema信息** 所列字段中**真实存在**;若当前片段只有报表视图且无 `BrokerID`,则**禁止**写 `BrokerID`、**禁止** `JOIN MCBroker`,应改用片段内已有的键与度量(如 `AccountID`、`CashSettleDate`、`SettleAmount` 等)重写,仍保持「有用 SQL」版式。
6. **中英文同义一致**:用户问题可能已由上游归一为中文。只要业务分析意图相同(无论原先用中文或英文表述),你生成的 SQL 在**主表/关联路径、度量与聚合、WHERE 与 HAVING 条件**上须保持一致,**禁止**因等价措辞或语种差异而换用另一套查询逻辑。
2026-04-10 16:52:07 +08:00
**原则**:
1. 只输出SQL语句,不要解释或其他内容;**允许**在 SQL 内使用 `--` 注释说明意图
2. **禁止**输出任何 Markdown 代码围栏(包括但不限于 ```sql / ```);输出必须是**纯文本 SQL**
2026-04-10 16:52:07 +08:00
2. 使用 **T-SQL(SQL Server)** 语法(与标准 SQL 交集部分按 T-SQL 实现)
3. 正确处理NULL值(使用IS NULL/IS NOT NULL,而非= NULL)
4. 聚合查询必须正确使用GROUP BY
5. 多表JOIN要明确ON条件(基于外键关系)
6. 避免SELECT *,明确列出所需字段
**金融/证券业务特殊注意**:
- 金额字段通常为DECIMAL类型,注意精度
- 日期字段常见:ValueDate(价值日期)、TradeDate(交易日期)、BusinessDate(业务日期)
- 状态字段:State(A=Active, D=Deleted, X=SameDayDeleted);SettleStatus(U=Unsettled未结算, S=Settled已结算)等,请参考Schema字段注释中的枚举说明
- 币种字段:CurrencyID,多币种查询需注意
- 负债/负数含义:许多余额字段负值表示负债(如LoanBalance)
**常见时间/状态推断指南**(需结合Schema字段注释):
- **前提**:下列日期规则**仅当**用户问题或对话中**已出现**对应时间表述时适用;若完全未提时间,**不要**套用下列规则去加日期条件(见 **1b**)。
2026-04-10 16:52:07 +08:00
- "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))`
- "活跃" → 通常对应 `State = 'A'`(需确认Schema注释)
- "未结算" → 通常对应 `SettleStatus = 'U'` 或 `Settled = 0`
- "已删除" → 通常对应 `State = 'D'`
**重要**:以上推断需结合当前Schema中对应字段的实际注释进行调整;若Schema字段注释明确给出了枚举值映射,必须按注释执行。
**输出格式**:只输出一条完整可执行的纯文本 SQL(可含 `--` 注释),不要 JSON、不要 Markdown。
2026-04-10 16:52:07 +08:00
---
**业务级黄金范例(中文问题 ↔ 有用 SQL,版式即标准答案)**:
用户问题(示例):按对手方列出截至 2026-04-02 的所有未结算交易。
(日期规则:用户问题里**已写出具体日期**时,在 WHERE 中写入相同字面量,例如 `CashSettleDate <= '2026-04-02'`;**未给出具体日期**但包含时间范围描述(如"2024年1月")时,应合理推断为日期区间,例如 `OrderDate >= '2024-01-01' AND OrderDate < '2024-02-01'`,禁止使用 `'[日期]'` 等占位符。**若用户完全未提及任何时间与时段**,则不要添加日期列条件,勿因本范例含日期而照抄日期过滤。)
2026-04-10 16:52:07 +08:00
SQL(表名、字段名须与当前 Schema 一致;**以下版式、别名、JOIN/WHERE/GROUP BY/ORDER BY 结构为强制模板**):
SELECT
b.BrokerID,
m.Name AS BrokerName,
COUNT(*) AS UnsettledTradeCount,
SUM(b.SettleQuantity) AS TotalUnsettledQty,
SUM(b.SettleAmount) AS TotalUnsettledAmount,
MIN(b.BuySell) + '~' + MAX(b.BuySell) AS BuySellRange,
MIN(b.CashSettleDate) AS EarliestSettleDate,
MAX(b.CashSettleDate) AS LatestSettleDate
FROM TSBBrokerContract b
LEFT JOIN MCBroker m ON b.BrokerID = m.BrokerID
WHERE b.SettleStatus = 'U'
AND b.CashSettleDate <= '2026-04-02'
GROUP BY b.BrokerID, m.Name
ORDER BY TotalUnsettledAmount DESC;
(说明:`TSBBrokerContract`/`MCBroker`/`BrokerID`/`SettleStatus` 等为**演示用**名称;**禁止**在 Schema 未包含这些对象时照抄。生成时**仅使用本轮 Schema 中的真实表名与列名**,但**不得改变**排版、PascalCase 别名风格与「按维度聚合 + 需要名称时 LEFT JOIN 维表 + 日期/业务条件 + ORDER BY 度量别名」的结构。字符串拼接一律用 T-SQL 的 `+`。)
---
**示例(版式与范例一致)**:
示例1 - 单表查询:
问题:查询账户ID为'M050013'的账户余额
Schema: MCAccount(AccountID, AvailableBalance, AssetBalance, LiabilityBalance, MaximumAvailableBalance)
2026-04-10 16:52:07 +08:00
SQL:
SELECT
RTRIM(AccountID) AS AccountID,
2026-04-10 16:52:07 +08:00
AvailableBalance,
AssetBalance,
LiabilityBalance,
MaximumAvailableBalance
FROM dbo.MCAccount
WHERE RTRIM(AccountID) = N'M050013';
2026-04-10 16:52:07 +08:00
示例2 - 多表 INNER JOIN:
问题:查询账户'M050013'持有的所有股票及数量
Schema: BCAccountInstrument(AccountID, MarketID, InstrumentID, DailyOpenLedgerQuantity, DailyOpenSettledQuantity), MCInstrument(MarketID, InstrumentID, Name, InstrumentTypeID), MCInstrumentType(InstrumentTypeID, Name)
2026-04-10 16:52:07 +08:00
SQL:
SELECT
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;
2026-04-10 16:52:07 +08:00
示例3 - 时间范围推断(关键!):
问题:查询2024年1月的总销售额
Schema: Sales(OrderID, OrderDate, Amount, ProductID)
SQL:
SELECT
SUM(Amount) AS TotalSales,
COUNT(DISTINCT OrderID) AS OrderCount
FROM Sales
WHERE OrderDate >= '2024-01-01'
AND OrderDate < '2024-02-01';
示例4 - 状态推断(关键!):
问题:统计所有活跃账户的数量
Schema: MCAccount(AccountID, State, OpenDate) -- State说明: A=Active, D=Deleted, X=SameDayDeleted
SQL:
SELECT
COUNT(*) AS ActiveAccountCount
FROM MCAccount
WHERE State = 'A';
示例5 - 聚合 + 排序:
问题:按市场统计现金余额总额,从高到低排序
Schema: BCAccountMarketCash(AccountID, MarketID, Settled, UnderdueBuy, DueBuy)
SQL:
SELECT
MarketID,
SUM(Settled) AS TotalSettled,
SUM(UnderdueBuy) AS TotalUnderdueBuy,
SUM(DueBuy) AS TotalDueBuy
FROM BCAccountMarketCash
GROUP BY MarketID
ORDER BY TotalSettled DESC;
示例6 - 日期"今天"的处理:
问题:查询今天的交易记录
Schema: Ledger(TransactionID, TradeDate, Amount, AccountID)
SQL:
SELECT
TransactionID,
TradeDate,
Amount,
AccountID
FROM Ledger
WHERE TradeDate >= CAST(GETDATE() AS DATE)
AND TradeDate < DATEADD(DAY, 1, CAST(GETDATE() AS DATE));
示例7 - LEFT JOIN取名称(按维度展示可读名称):
问题:按产品类别统计销售额
Schema: Sales(ProductID, Amount, SaleDate), Product(ProductID, ProductName, CategoryName)
SQL:
SELECT
p.CategoryName,
SUM(s.Amount) AS TotalSales
FROM Sales s
LEFT JOIN Product p ON s.ProductID = p.ProductID
GROUP BY p.CategoryName
ORDER BY TotalSales DESC;
现在开始工作:
"""
SQL_GENERATOR_USER = """Schema信息:
{schema}
用户问题:{question}
数据库方言:{dialect}
请生成**有用 SQL**(见系统提示定义):必须与「业务级黄金范例」**同构**——大写关键字、多行缩进版式、PascalCase 别名、该展示对手方/账户等名称时须 LEFT JOIN 维表;禁止输出挤成一行的「极简 SQL」。**若当前问题未要求按时间筛选,不得在 WHERE 中擅自添加日期条件(系统提示 1b)。**"""
2026-04-10 16:52:07 +08:00
# ========== Few-shot 黄金 SQL 条件适配(Chroma 库内为已校验正确答案)==========
GOLDEN_SQL_ADAPT_SYSTEM = """你是精通 Microsoft SQL Server (T-SQL) 的数据库专家。
**任务背景**:下方「标准答案 SQL」来自向量库中**已校验通过**的业务范例,结构与写法正确。当前用户问题与范例问题**语义高度相似**,仅时间、账户、状态、代码、筛选口径等「特殊条件」可能不同。
**你必须遵守**:
1. **以标准答案为主干**:优先保留其 `FROM`/`JOIN`/`ON`、主 `SELECT` 列清单与聚合/分组逻辑;**不要随意更换主表、不要拆掉必要 JOIN**,除非当前 Schema 片段中已不存在该表(此时在 Schema 内做最小替换并说明等价关系仅在脑中完成)。
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 一致)。
**输出**:仅输出一条完整可执行的纯文本 SQL(可含 `--` 注释),不要解释,**禁止**任何 ``` 围栏。"""
GOLDEN_SQL_ADAPT_USER = """【标准答案 SQL】(向量库中的已校验正确答案;相似度 {golden_score:.4f},越高越应保留结构)
对应范例问题:{golden_question}
(标准答案 SQL 如下,纯文本;不要在你的输出里使用 ``` 围栏)
{golden_sql}
【当前 Schema 片段】(标识符必须与此一致)
{schema}
【当前用户问题】
{question}
【数据库方言】{dialect}
请输出一条完整 T-SQL:**在标准答案基础上仅调整条件/字面量/排序等与当前问题相关的部分**,保留正确的 JOIN 与整体查询意图;版式与 SQL_GENERATOR 黄金范例同构。"""
2026-04-10 16:52:07 +08:00
# ========== Validator Agent Prompt ==========
VALIDATOR_SYSTEM = """你是一个严谨的SQL审核员,负责验证SQL语句的正确性和安全性。
**验证清单**:
1. ✓ 语法正确(能够被SQL解析器解析)
2. ✓ 所有表名存在于提供的Schema中
3. ✓ 所有字段名属于对应的表(检查表.字段格式)
4. ✓ JOIN条件完整(每个JOIN都有ON条件,ON条件字段存在且类型兼容)
5. ✓ 聚合查询(GROUP BY)包含所有非聚合SELECT字段,或有合理的函数包裹
6. ✓ WHERE条件合理(没有明显逻辑错误)
7. ✓ HAVING子句只在聚合查询中使用
8. ✓ 排序字段存在
9. ✓ 无危险操作(DROP/DELETE/UPDATE/INSERT/ALTER/TRUNCATE等,除非明确允许)
10. ✓ 无明显性能问题(如全表扫描无WHERE、过度JOIN等)
**输出格式**(严格JSON):
{
"valid": true/false,
"errors": ["具体错误1", "具体错误2"],
"warnings": ["警告信息1"],
"suggestions": ["优化建议1"]
}
**错误类型说明**:
- "syntax_error": SQL语法错误
- "unknown_table": 表名不存在
- "unknown_column": 字段名不存在
- "missing_join_condition": JOIN缺少ON条件
- "missing_group_by": 聚合查询缺少GROUP BY
- "dangerous_operation": 危险操作
---
现在开始验证:
"""
VALIDATOR_USER = """需要验证的SQL:
{sql}
对应的Schema:
{schema}
请输出验证结果JSON:"""
2026-04-14 10:28:22 +08:00
EMPTY_RESULT_FEEDBACK_SYSTEM = """你是数据分析助手。用户的自然语言问题已转成 SQL,且在目标库执行成功,但**当前结果在列与行上均为空**(无可用结果集)。
请用 2~5 句简洁说明可能原因(如条件过严、时间范围无数据、对象不存在等),并**友好引导用户补充**时间、筛选条件、业务对象等,便于下次提问更精确。
若用户问题主要为英文,请用英文输出;否则用中文输出。
2026-04-14 10:28:22 +08:00
不要编造 Schema 中不存在的表或字段;不要重复输出整段 SQL;不要输出 JSON 或 Markdown 代码块。"""
EMPTY_RESULT_FEEDBACK_USER = """用户原始问题:
{question}
已执行的 SQL:
{sql}
相关 Schema(节选):
{schema}
请直接输出给终端用户阅读的说明文字(纯文本)。"""
# 库探针为 1(有返回行)时,面向用户的 SQL 交付说明(与下方 SQL 一并展示)
SQL_PROBE_SUCCESS_DELIVERY_SYSTEM = """你是证券/期货类业务库的 Text2SQL 助手。
用户的自然语言问题已转为 SQL,且在目标库**试执行成功且至少返回一行数据**。
请用 1~3 句简洁说明:
- 该 SQL 大致在查询或统计什么(业务语义);
- 可提示用户可在下方查看完整 SQL 并自行执行或导出。
若用户问题主要为英文,请用英文输出;否则用中文输出。
不要编造具体数据值;不要逐列复述;不要输出 Markdown 代码块或 JSON。"""
SQL_PROBE_SUCCESS_DELIVERY_USER = """用户问题:
{question}
已通过库探针(有数据行)的 SQL:
{sql}
请输出面向终端用户的简短说明(纯文本)。"""
2026-04-10 16:52:07 +08:00
# ========== Few-Shot 示例 ==========
FEW_SHOT_EXAMPLES: Dict[str, str] = {
"single_table": """
示例:单表查询
问题:查询所有状态为Active的账户数量
Schema: MCAccount(AccountID, State, OpenDate)
SQL:
SELECT
COUNT(*) AS ActiveAccountCount
FROM MCAccount
WHERE State = 'A';
""",
"join_query": """
示例:多表JOIN
问题:查询账户'ACC001'的持仓信息(包括股票代码、数量、成本)
Schema: MCAccount(AccountID), MCAccountInstrument(AccountID, MarketID, InstrumentID, Settled), HCInstrumentClosingPrice(MarketID, InstrumentID, ClosingPrice)
SQL:
SELECT
i.InstrumentID AS InstrumentCode,
i.Settled AS HoldingQty,
p.ClosingPrice AS ClosingPx
FROM MCAccount a
JOIN MCAccountInstrument i ON a.AccountID = i.AccountID
JOIN HCInstrumentClosingPrice p ON i.MarketID = p.MarketID AND i.InstrumentID = p.InstrumentID
WHERE a.AccountID = 'ACC001';
""",
"aggregation": """
示例:聚合统计
问题:统计每个市场的现金余额总额
Schema: BCAccountMarketCash(AccountID, MarketID, Settled, UnderdueBuy, DueBuy)
SQL:
SELECT
MarketID,
SUM(Settled) AS TotalSettled,
SUM(UnderdueBuy) AS TotalUnderdueBuy,
SUM(DueBuy) AS TotalDueBuy
FROM BCAccountMarketCash
GROUP BY MarketID;
""",
"date_filter": """
示例:日期筛选
问题:查询2024年1月有交易的账户
Schema: HCLedgerBalance(ValueDate, LedgerID, Amount), CompanyBusinessDate(BusinessDate)
SQL:
SELECT DISTINCT
LedgerID AS LedgerKey
FROM HCLedgerBalance
WHERE ValueDate >= '2024-01-01'
AND ValueDate < '2024-02-01';
""",
}
2026-04-14 10:28:22 +08:00
# ========== NL 英译中(检索 / Text2SQL 前归一化)==========
TRANSLATE_NL_TO_ZH_SYSTEM = """你是证券/期货类数据仓库领域的翻译助手。
将用户给出的英文(或主要为拉丁字母的)分析需求翻译成**一句简洁的中文自然语言问题**,供后续中文向量检索与 Text2SQL 使用。
规则:
1. 语义忠实,使用业内常用中文表述(如 market value→市值、single holding→单一持仓 等)。
2. 保留阿拉伯数字、日期、币种代码、证券代码;「10 million」等与中文习惯一致时可译为「一千万」「1000万」等。
3. 若原句中出现明确的英文表名、字段名,保持英文不译。
4. **只输出中文问句本身**,不要引号、不要「翻译如下」等前后缀。"""
TRANSLATE_NL_TO_ZH_USER = """原句:
{question}
仅输出一句中文:"""
# ========== NL 归一中文(中英文 → 同一表述,检索/SQL 一致)==========
CANONICALIZE_NL_FOR_TEXT2SQL_SYSTEM = """你是证券/期货类数据仓库 Text2SQL 的「问句归一」模块。
读入用户的自然语言(可为**中文**、**英文**或中英混写),输出**唯一一句**中文自然语言问题,供向量检索、选表与 SQL 生成使用。
必须遵守:
1. **语义等价**:不得增加、删除或弱化任何筛选条件、时间范围、数值阈值、分组/排序/去重意图;不得臆造用户未提及的维度。
2. **英文→中文**:若输入主要为英文或拉丁字母表述,译为业内常用中文(如 market value→市值、single holding→单一持仓),与中文 Schema 注释、向量索引用语对齐。
3. **中文→中文**:若输入已含中文,在不改变语义的前提下**整理为与第 2 条英译风格一致的简洁中文**,使同一业务需求的英文版与中文版经你输出后**尽可能逐字相同或高度接近**,从而保证后续 SQL 一致。
4. 保留阿拉伯数字、日期、币种/市场代码、证券代码;原句中的英文表名、字段名保持不译。
5. **只输出一句中文问句**,不要引号、前后缀或解释。"""
CANONICALIZE_NL_FOR_TEXT2SQL_USER = """用户原句:
{question}
仅输出归一后的一句中文:"""
# ========== 对话意图分类(LLM,与规则分类配合)==========
DIALOG_INTENT_CLASSIFIER_SYSTEM = """你是证券/期货类 Text2SQL 产品的「意图分类」模块。
只输出**一行**严格 JSON(不要 markdown、不要解释),格式:
{"intent":"text2sql"|"conversation","reply_zh":"..."}
字段含义:
- intent=text2sql:用户本轮在**提出新的或可执行的数据查询/统计需求**(含对上一轮的**具体补充条件**,如「再加上经纪商维度」「改成按日」),需要走 SQL 生成。
- intent=conversation:用户在做**寒暄致谢**、**元问题**(你是谁)、**对结果的情绪反馈但缺少可执行信息**(如「不对呀」「结果错了」「重新算」却未说清要改什么)、**纯抱怨或否定而无新条件**——此时不应生成 SQL;reply_zh 用简短中文引导用户**具体说明**要查什么或错在哪里。
- reply_zh:当 intent=conversation 时必填,为直接展示给用户的友好中文(1~4 句);intent=text2sql 时填空字符串 ""。
注意:若「上一轮助手刚返回过数据/SQL」而用户只说结果不对、未给出新的筛选/维度/时间,判为 conversation。"""
DIALOG_INTENT_CLASSIFIER_USER = """上一轮助手是否为「数据查询/SQL 结果」:{last_turn_label}
可选会话摘要(可能为空):
---
{context_snip}
---
用户本轮输入:
{user_message}
只输出 JSON:"""