第48题:问数 Agent 整体架构、意图识别、历史上下文与 NL2SQL
1. 来源边界
原表明确标注:
本题属于 T5 技术扩展题,可以用于备考,不能表述为已经核验的相关真实面试题。
同时需要注意一个来源边界。
题目虽然写了:
- 整体架构;
- 意图识别;
- 历史上下文;
- NL2SQL;
但原表参考回答实际详细展开的主要内容是:
历史上下文与任务状态管理。
原表直接支持的内容包括:
- 不要把全部 Conversation 当作任务状态;
- 建立 Task / Subtask ID;
- 区分 Active / Suspended / Cancelled;
- 保存不可丢失约束;
- 保存关键 Decision;
- 保存 Artifact Reference;
- Summary 必须可重建并保留 Provenance;
- 用户切换话题时显式确认挂起或取消;
- 撤销旧子任务的 Worker Lease;
- 忽略取消任务的 Late Result;
- 通过 Constraint Replay 和 Regression Sample 检测 Context Compression Loss;
- 验收要覆盖越权、注入、重复执行、依赖故障、人工接管和回滚。
下面"整体架构、Intent Routing、NL2SQL"部分属于基于题目措辞和外部技术资料进行的扩展。
2. 核心回答
如果让我设计一个企业问数 Agent,我会把它拆成六层:
text
User
↓
Conversation / Task State
↓
Intent Router
↓
Business Semantic Layer
↓
NL2SQL Planning & Validation
↓
Read-only Data Execution
↓
Result Validation & Explanation
进一步展开:
text
用户问题
↓
Session / Task Manager
↓
Intent Classification
↓
Entity / Metric / Time Extraction
↓
Business Glossary Retrieval
↓
Schema Linking
↓
SQL Generation
↓
SQL AST / Permission / Cost Validation
↓
Read-only Execution
↓
Result Validation
↓
Natural Language Answer
↓
Trace / Audit / State Update
系统成功的标准应同时满足:
BusinessCorrect∧SQLCorrect∧Authorized∧ResultCorrect BusinessCorrect \land SQLCorrect \land Authorized \land ResultCorrect BusinessCorrect∧SQLCorrect∧Authorized∧ResultCorrect
只生成语法合法的 SQL 远远不够。
3. 整体架构可以怎么设计
一个比较完整的问数 Agent 可以包含:
text
┌────────────────────────────┐
│ User / BI Frontend │
└──────────────┬─────────────┘
↓
┌────────────────────────────┐
│ Session & Task State │
│ Task / Subtask / Context │
└──────────────┬─────────────┘
↓
┌────────────────────────────┐
│ Intent Router │
│ Intent + Slots + Confidence│
└──────────────┬─────────────┘
↓
┌────────────────────────────┐
│ Semantic Layer │
│ Metric / Dimension / Rule │
└──────────────┬─────────────┘
↓
┌────────────────────────────┐
│ Schema Retrieval │
│ Table / Column / Join │
└──────────────┬─────────────┘
↓
┌────────────────────────────┐
│ NL2SQL Planner │
└──────────────┬─────────────┘
↓
┌────────────────────────────┐
│ SQL Guard │
│ AST / ACL / Cost / Limit │
└──────────────┬─────────────┘
↓
┌────────────────────────────┐
│ Query Executor │
│ Read-only DB Credential │
└──────────────┬─────────────┘
↓
┌────────────────────────────┐
│ Result Validator │
└──────────────┬─────────────┘
↓
┌────────────────────────────┐
│ Answer Generator │
│ Result + Metric Definition │
└────────────────────────────┘
4. 为什么要先做 Intent Recognition
用户问数并不总是在请求 SQL。
例如:
text
销售额是多少?
属于:
text
Metric Query
用户问:
text
销售额这个指标怎么算?
属于:
text
Metric Definition
用户问:
text
为什么华东地区下降了?
可能属于:
text
Drill-down / Diagnostic Analysis
用户说:
text
把刚才那个改成按月份看。
属于:
text
Follow-up Transformation
用户说:
text
把这些数据导出成 CSV。
属于:
text
Action / Export
因此第一阶段需要判断:
Intent(x) Intent(x) Intent(x)
再选择对应执行路径。
5. Intent 可以怎样分类
一个基础分类可以包括:
| Intent | 说明 |
|---|---|
metric_query |
查询一个指标 |
trend_query |
时间趋势 |
comparison_query |
维度比较 |
drilldown_query |
下钻分析 |
metric_definition |
询问业务口径 |
nl2sql_query |
需要执行数据库查询 |
followup_modify |
修改上轮分析条件 |
export |
导出结果 |
clarification |
信息不足,需要澄清 |
unsupported |
当前系统无法处理 |
真正实现时,分类数量应由具体业务决定。
6. Intent Router 最好输出结构化结果
例如用户:
text
帮我看今年华东地区各季度的净收入。
Router 可以输出:
json
{
"intent": "trend_query",
"metric": "net_revenue",
"dimensions": ["region"],
"filters": {
"region": "华东"
},
"time_range": "current_year",
"time_granularity": "quarter",
"confidence": 0.94,
"need_clarification": false
}
然后由代码判断:
text
intent == trend_query
↓
进入 Data Query Pipeline
这种设计更容易进行:
- Test;
- Trace;
- Debug;
- 权限判断;
- 回归测试。
7. Intent Confidence 低时应该怎么办
例如用户问:
text
看一下增长情况。
缺少:
- 什么指标;
- 什么时间;
- 什么对象。
此时 Agent 不应该强行生成 SQL。
可以输出:
json
{
"intent": "clarification",
"missing": [
"metric",
"time_range"
]
}
然后询问:
text
你希望看哪个指标,以及哪个时间范围?
这样可以降低:
WrongAssumption→WrongSQL WrongAssumption \rightarrow WrongSQL WrongAssumption→WrongSQL
的风险。
8. 为什么企业问数需要 Business Semantic Layer
这是 NL2SQL 中非常关键的一层。
例如用户问:
text
GMV 是多少?
数据库中可能没有:
text
gmv
这个字段。
业务定义可能是:
$$
GMV
\sum order_amount
同时还可能规定: ```text order_status != cancelled ``` 也可能进一步规定: ```text 退款发生后是否扣除 ``` 或者: ```text 税前还是税后 ``` 因此需要保存: ```text Metric Definition Dimension Definition Business Rule Synonym Owner Version ``` 例如: ```yaml metric: net_revenue definition: paid_amount - refund_amount filters: payment_status = "PAID" time_column: payment_time owner: finance version: 2026-03 ``` ### 9. 为什么只给数据库 Schema 还不够 假设数据库有: ```text orders.amount orders.pay_amount orders.final_amount finance.net_amount ``` 用户问: ```text 收入是多少? ``` Schema 无法直接告诉模型: > 公司正式财务口径使用哪一列? 企业数据通常还有: * 内部指标定义; * 报表约定; * 特殊过滤规则; * 历史兼容规则; * 数据延迟规则。 所以企业 NL2SQL 更合理的输入是: Question+Schema+BusinessSemantics+Authorization+Context Question + Schema + BusinessSemantics + Authorization + Context Question+Schema+BusinessSemantics+Authorization+Context 仅有: Question+Schema Question + Schema Question+Schema 通常不足以确定正确业务答案。 ### 10. Schema Linking 是什么 确定业务指标之后,需要找到对应: * Database; * Schema; * Table; * Column; * Join Path。 例如: ```text 用户问题: 华东地区净收入 ``` 业务指标解析: ```text Metric: net_revenue ``` Schema Linking: ```text orders.payment_amount refund.refund_amount customer.region ``` Join Path: ```text orders.customer_id = customer.id ``` 以及: ```text refund.order_id = orders.id ``` Schema Linking 的质量通常会直接影响最终 SQL 的正确性。 #### 10.1 净收入中的一对多关联陷阱 企业 NL2SQL 中需要特别检查一对多关联产生的重复聚合问题。 假设存在一笔订单: ```text order_id = 1001 order_amount = 100 元 ``` 该订单发生两次退款: ```text refund_1 = 10 元 refund_2 = 20 元 ``` 正确净收入应为: 100−10−20=70 100-10-20=70 100−10−20=70 如果直接关联订单表和退款表: ```sql SELECT SUM(o.order_amount) - SUM(r.refund_amount) AS net_revenue FROM orders o LEFT JOIN refunds r ON o.order_id = r.order_id WHERE o.order_id = 1001; ``` Join 后可能得到: ```text order_id | order_amount | refund_amount ---------|--------------|-------------- 1001 | 100 | 10 1001 | 100 | 20 ``` 此时: ```text SUM(order_amount) = 200 SUM(refund_amount) = 30 ``` 最终得到: 200−30=170 200-30=170 200−30=170 该结果在 SQL 语法和执行层面都可以成功,但业务结果明显错误。 更稳健的处理方式是先按照订单粒度聚合退款: ```sql WITH refund_by_order AS ( SELECT order_id, SUM(refund_amount) AS total_refund FROM refunds GROUP BY order_id ) SELECT SUM( o.order_amount - COALESCE(r.total_refund, 0) ) AS net_revenue FROM orders o LEFT JOIN refund_by_order r ON o.order_id = r.order_id; ``` 此时对于订单 `1001`: ```text order_amount = 100 total_refund = 30 net_revenue = 70 ``` 这类指标至少需要覆盖三种回归样例: | 场景 | 订单金额 | 退款记录 | 期望净收入 | |------|-----:|---------|------:| | 未退款 | 100 | 无 | 100 | | 部分退款 | 100 | 10 | 90 | | 多次退款 | 100 | 10 + 20 | 70 | 因此,Schema Linking 不能只判断 Join Path 是否存在,还需要判断: ```text Join Cardinality Aggregation Grain Metric Grain ``` 是否一致。 对于一对多关系,可以把检查过程写成: ```text 订单粒度指标 ↓ 识别一对多退款关系 ↓ 退款先按 order_id 聚合 ↓ 恢复到订单粒度 ↓ 计算订单级净收入 ↓ 再进行地区、时间等上层聚合 ``` 这个例子说明,NL2SQL 的正确性还依赖于对数据粒度和关联基数的理解。 ### 11. 为什么不应该把整个数据库 Schema 都塞进 Prompt 真实企业数据库可能包含: ```text 1000+ columns ``` 甚至更多。 完整塞入会带来: * Context 太长; * Token Cost; * 无关字段干扰; * 同名字段混淆; * Schema Version 问题。 因此可以先做: ```text Question ↓ Metric Retrieval ↓ Relevant Table Retrieval ↓ Relevant Column Retrieval ↓ Join Path Retrieval ``` 最后只向 SQL Generator 提供相关子图。 ### 12. NL2SQL Pipeline 可以怎么设计 我会设计成: ```text Question ↓ Intent + Slots ↓ Metric Resolution ↓ Schema Retrieval ↓ Join Planning ↓ SQL Draft ↓ AST Parse ↓ Permission Check ↓ Cost Check ↓ Read-only Execute ↓ Result Validation ↓ Answer ``` 其中: ```text Generate SQL ``` 只占整个链路中的一环。 ### 13. 为什么 SQL 生成后还需要 AST Validation 假设模型生成: ```sql DELETE FROM orders; ``` 语法完全正确。 问数 Agent 显然不应该执行。 所以执行前需要 Parse SQL AST。 只允许例如: ```text SELECT WITH ... SELECT ``` 拒绝: ```text INSERT UPDATE DELETE DROP ALTER TRUNCATE GRANT REVOKE ``` 还可以进一步检查: * Table Allowlist; * Column Permission; * Function Allowlist; * Subquery; * External Function; * Cross-database Access。 ### 14. 数据库本身仍然应该使用只读权限 应用层 SQL Validator 存在出错可能。 数据库 Credential 也需要做到: ```text Read Only + Least Privilege ``` 形成两层控制: ```text SQL Policy ↓ Database Permission ``` 例如 PostgreSQL 可以使用 Read-only Transaction。 在 Read-only Transaction 中,大量写操作和 DDL 会直接被禁止。 这样即使生成层漏检: ```text UPDATE ``` 数据库层仍可拒绝。 ### 15. 为什么还要做 Row / Column Permission 即使执行: ```sql SELECT * FROM salary; ``` 仍可能发生越权。 所以数据库访问还需要结合: ```text User Tenant Role Department Data Classification ``` 例如: Allowed(user,column)=true Allowed(user,column)=true Allowed(user,column)=true 才允许选择该列。 可以通过: * View; * Row Level Security; * Column-level Permission; * Query Rewrite; 等方式实现。 权限应尽量在 Data Access Layer 强制执行。 ### 16. SQL 执行前为什么还要检查 Cost 只读 SQL 同样可能造成事故。 例如: ```sql SELECT * FROM trillion_row_table; ``` 虽然没有修改数据,却可能: * 扫描大量数据; * 占满数据库资源; * 导致其他查询变慢; * 产生高额云数仓费用。 因此可以在执行前做: ```text EXPLAIN ``` 获得 Query Plan 和估计 Cost。 如果: EstimatedCost\>Cmax EstimatedCost\>C_{max} EstimatedCost\>Cmax 则: ```text Reject ``` 或者: ```text Ask User ``` ### 17. 还需要设置哪些执行限制 例如: ```text query_timeout row_limit bytes_scanned_limit concurrency_limit ``` 可以自动向查询增加: ```sql LIMIT 1000 ``` 但需要注意: 对: ```text COUNT SUM AVG ``` 等 Aggregate Query,不能简单在错误位置追加 LIMIT。 所以这类修改最好基于: ```text SQL AST ``` 完成。 ### 18. SQL 执行失败后怎么办 模型第一次生成的 SQL 可能出现: * Column Not Found; * Type Mismatch; * Dialect Error; * Join Error; * Function Error。 可以有限度进行: ```text Generate ↓ Validate ↓ Execute ↓ Error ↓ Repair ``` 但需要设置: ```text max_repair_attempts ``` 例如: Nrepair≤2 N_{\\text{repair}}\\le2 Nrepair≤2 防止进入: ```text Generate → Error → Generate → Error ``` 的无限循环。 ### 19. SQL 执行成功也不代表结果正确 例如用户问: ```text 今年平均客单价是多少? ``` 模型生成: ```sql SELECT AVG(amount) FROM orders; ``` SQL: ```text Syntax Valid ``` 并且: ```text Execution Success ``` 但如果业务规定: ```text 只统计已支付订单 ``` 结果依然错误。 前面的净收入一对多退款案例也属于同一类问题。 SQL 可以: ```text Parse Success Execution Success ``` 但错误的 Join Cardinality 会造成订单金额重复聚合。 因此需要区分: ```text SQL Validity Execution Success Business Correctness Result Correctness ``` ### 20. Result Validation 怎么做 #### 20.1 空结果 例如: ```text 0 rows ``` 可能意味着: * 用户条件真的没有数据; * 时间字段错了; * Join 错了; * 权限过滤过度。 需要进一步区分。 #### 20.2 数值异常 例如: ```text 收入 = -10^15 ``` 可能需要执行异常检查。 #### 20.3 单位 例如数据库: ```text amount_cent ``` 查询结果: ```text 10000 ``` 最终应该解释成: ```text 100 元 ``` #### 20.4 时间口径 例如: ```text 2026 年 8 月 ``` 需要明确: * Calendar Month; * Fiscal Month; * 时区。 #### 20.5 聚合粒度与关联基数 对于净收入等涉及多表关联的指标,还应检查: ```text Metric Grain Join Cardinality Aggregation Order ``` 例如订单与退款存在一对多关系时,需要确认退款已经先聚合到订单粒度。 至少验证: ```text 未退款订单 部分退款订单 多次退款订单 ``` 三个代表性场景。 如果: ```text 100 元订单 + 10 元退款 + 20 元退款 ``` 最终结果必须保持为: 70 元 70\\text{ 元} 70 元 该测试能够直接发现订单金额因一对多 Join 被重复计入的问题。 ### 21. 用户看到的最终答案应该包含什么 一个问数 Agent 最终可以输出: ```text 结论: 2026 Q2 华东地区净收入为 1.23 亿元。 口径: 净收入 = 已支付金额 - 已退款金额。 时间范围: 2026-04-01 至 2026-06-30。 数据更新时间: 2026-08-30 15:00。 SQL: [可展开查看] 数据源: finance.orders_v3 finance.refunds_v2 ``` 这样用户能够知道: * 结果; * 指标定义; * 时间; * 数据新鲜度; * 来源; * SQL。 这有利于结果复核。 ### 22. 原表关于历史上下文的核心原则是什么 原表最明确的一句话是: **不要把全部对话当状态。** 建议至少区分: ```text Conversation History Task State Business Constraint Artifact External State ``` 这些数据具有不同生命周期。 ### 23. Conversation History 和 Task State 有什么区别 Conversation History 例如: ```text User: 看一下今年销售额。 Assistant: 今年销售额是... User: 再按地区拆一下。 ``` Task State 应抽象成: ```json { "task_id": "T100", "intent": "sales_analysis", "metric": "revenue", "time_range": "2026", "dimensions": ["region"], "status": "active" } ``` 后续模型主要依赖: ```text Current Task State ``` 这样可以避免每次都从几十轮历史中重新推断当前任务。 ### 24. 为什么需要 Task / Subtask ID 一个用户可能同时存在多个任务: ```text T1: 分析销售额 T2: 解释 GMV 定义 T3: 导出昨天的数据 ``` 每个任务需要独立维护: ```text task_id status constraints artifacts worker ``` 这样可以避免异步 Tool Result 返回以后无法判断其所属任务。 ### 25. 状态至少要有哪些生命周期 原表明确提出: ```text Active Suspended Cancelled ``` 还可以根据实现增加: ```text Pending Running Completed Failed ``` 例如: ```text ACTIVE ↓ SUSPENDED ↓ ACTIVE ↓ COMPLETED ``` 或者: ```text ACTIVE ↓ CANCELLED ``` Cancelled 任务的 Late Result: ```text 直接忽略 ``` 不能重新污染当前会话。 ### 26. 用户突然换话题怎么办 例如: ```text 用户: 帮我分析华东销售额。 Agent: 正在查询数据库... 用户: 先不用了,帮我看看利润率定义。 ``` 此时旧任务可能还在数据库执行。 原表要求: ```text 显式确认: Suspend 还是 Cancel? ``` 例如: ```text 旧任务 T1 → CANCELLED ``` 然后: ```text Revoke Worker Lease ``` 后续 T1 的查询结果即使晚到: ```text Ignore ``` 不能重新写入当前任务状态。 ### 27. 为什么需要 Artifact Reference 例如查询产生: ```text SQL Result Table Chart CSV Metric Definition ``` 这些内容不适合全部写进 Conversation Summary。 状态中保存: ```text artifact_id ``` 例如: ```json { "sql_artifact": "A102", "result_table": "A103", "chart": "A104" } ``` 真正内容保存在 Artifact Store。 这样可以减少: * Context Token; * Summary Loss; * 重复传输。 ### 28. Summary 为什么必须保留 Provenance 例如摘要写: ```text 用户希望分析净收入。 ``` 系统还应该知道这条信息来自: ```text user_turn_27 ``` 或者: ```text metric_definition_v3 ``` 形成: ```text Summary Claim ↓ Provenance ↓ Original Event / Artifact ``` 这样摘要被质疑时可以回溯原始来源。 ### 29. Context Compression 怎么防止丢关键约束 假设历史里用户说过: ```text 所有销售额都按人民币计算。 ``` 100 轮后进行 Summary。 如果压缩时丢掉这条约束,后续查询可能产生错误单位。 因此原表要求定期进行: **Constraint Replay。** 例如维护: ```text non_lossy_constraints ``` 单独保存: ```json { "currency": "CNY", "timezone": "Asia/Shanghai", "tenant": "A" } ``` 这些关键约束不依赖自然语言摘要保存。 ### 30. 如何测试 Context Compression Loss 可以准备 Regression Case: ```text Turn 1: 所有金额用人民币。 Turn 20: ... Turn 50: ... Turn 80: 帮我算收入。 ``` 经过多次: ```text Summary / Compaction ``` 以后检查最终 SQL 是否仍然使用正确: ```text Currency Timezone Metric Definition Tenant ``` 可以定义: ##
ConstraintRetentionRate
\frac{
N_{\text{retained constraints}}
}{
N_{\text{required constraints}}
}
### 31. NL2SQL 应该怎么评估 我会分四层评测。 #### 31.1 Intent 层 例如: ```text Intent Accuracy Macro-F1 Confusion Matrix ``` 同时评估: * Metric Extraction; * Dimension Extraction; * Time Range Extraction。 #### 31.2 SQL 层 评估: * Parse Success; * Execution Success; * Execution Accuracy; * Forbidden SQL Rate。 例如: ##
ExecutionAccuracy
\frac{
N_{\text{queries producing expected result}}
}{
N_{\text{test}}
}
SQL Exact Match 可以作为辅助指标。 两个 SQL 字符串不同,仍可能产生相同正确结果。 #### 31.3 Business 层 测试: * Metric Definition Correctness; * Filter Correctness; * Time Grain Correctness; * Join Correctness; * Unit Correctness; * Join Cardinality Correctness; * Aggregation Grain Correctness。 对于涉及一对多关系的指标,需要加入专门回归样例。 例如净收入: ```text Case 1: 100 元订单,无退款 Expected = 100 元 Case 2: 100 元订单,退款 10 元 Expected = 90 元 Case 3: 100 元订单,退款 10 元和 20 元 Expected = 70 元 ``` 这类测试可以直接检查: ```text 一对多 Join ↓ 订单金额是否重复 ↓ 退款是否先按订单聚合 ↓ 最终业务指标是否正确 ``` #### 31.4 End-to-End 层 最终看: ```text 用户问题 ↓ 正确结果 ↓ 正确解释 ``` 可以定义: ##
TaskSuccessRate
\frac{
N_{\text{correct end-to-end answers}}
}{
N
}
### 32. 为什么传统 Text-to-SQL Benchmark 不足以代表企业问数 Spider 2.0 的公开研究已经表明,真实企业 Text-to-SQL 通常需要: * 大型 Schema; * 多种数据库; * SQL Dialect; * Metadata Search; * 多条 SQL; * 数据转换; * 项目代码; * 长上下文。 Spider 2.0 中很多数据库拥有超过: ```text 1000 columns ``` 其任务复杂度明显高于传统单条 Text-to-SQL。 2026 年 EntSQL 又进一步研究: **企业 SQL 经常依赖内部业务文档和指标定义。** 这与问数 Agent 的实际问题高度一致。 系统需要同时完成: ```text 理解数据库 ``` 以及: ```text 理解企业业务语义 ``` ### 33. NL2SQL 安全测试应该覆盖什么 #### 33.1 Unauthorized Table 用户没有权限的表: ```text 必须拒绝。 ``` #### 33.2 Sensitive Column 例如: ```text salary phone id_card ``` 未经授权不能查询。 #### 33.3 Write SQL 模型生成: ```text DELETE / UPDATE ``` 必须阻断。 #### 33.4 Expensive Query 超大扫描: ```text Reject / Require Approval ``` #### 33.5 Prompt Injection 数据库 Metadata 中出现恶意自然语言时: ```text 不能改变系统权限。 ``` #### 33.6 Cross-Tenant Tenant A: ```text 无法读取 Tenant B。 ``` ### 34. 整个系统需要记录什么 Trace 建议记录: ```text trace_id session_id task_id subtask_id intent intent_confidence metric business_rule_version schema_version selected_tables sql sql_ast_hash permission_decision query_plan execution_time rows_returned result_artifact answer state_transition ``` 这样出现错误时可以判断: ```text Intent 错了? Metric 错了? Schema Linking 错了? SQL 错了? 权限错了? 数据库数据错了? Answer 解释错了? ``` ### 35. 一个典型执行例子 用户: ```text 今年华东地区净收入同比增长多少? ``` #### 35.1 Intent ```json { "intent": "comparison_query", "metric": "net_revenue", "region": "华东", "time_range": "current_year", "comparison": "YoY" } ``` #### 35.2 Business Semantic Retrieval 得到: ```text net_revenue = paid_amount - refund_amount ``` 并读取其: ```text version owner time_column ``` #### 35.3 Schema Linking 找到: ```text orders refunds customers ``` 同时需要检查: ```text orders : refunds = 1 : N ``` 如果退款表允许一笔订单对应多条退款记录,则应先将退款聚合到: ```text order_id ``` 粒度,再与订单表关联。 #### 35.4 SQL Planning 分别计算: ```text Current Year Previous Year ``` 并保证净收入的计算遵循: ```text Refunds ↓ GROUP BY order_id ↓ Orders LEFT JOIN Aggregated Refunds ↓ Order-level Net Revenue ↓ Time / Region Aggregation ``` #### 35.5 SQL Guard 检查: ```text SELECT only Authorized tables Authorized columns Query cost ``` #### 35.6 Execution 使用: ```text Read-only Credential ``` #### 35.7 Result 假设: ```text 2026 = 120M 2025 = 100M ``` 计算: ##
YoY
\frac{120-100}{100}
20%
$$
35.8 Final Answer
text
2026 年至今华东地区净收入同比增长 20%。
口径:
净收入 = 已支付金额 - 已退款金额。
比较区间:
2026 年至今 vs 2025 年同期。
并提供:
text
SQL / Metric Definition / Data Freshness
供用户复核。
36. 面试官如果问"为什么不直接把历史都塞进去"
可以回答:
全量历史适合保留审计和重放,但不适合直接等同于当前业务状态。长期对话中会同时存在旧话题、已取消任务、历史 Tool Result 和过期业务约束,如果全部直接交给模型,容易产生状态污染和 Token 成本。
我会单独维护 Task State,包括 task/subtask ID、当前 Intent、Metric、Time Range、Active/Suspended/Cancelled 状态、不可丢失约束和 Artifact Reference。Conversation History 仍保留,但当前执行主要读取结构化 Task State。
Summary 可以用于压缩上下文,但必须保留 Provenance,并通过 Constraint Replay 和 Regression Case 验证关键条件没有在压缩过程中丢失。
这一部分最贴近原表参考答案。
37. 面试官如果问"NL2SQL 最难的地方是什么"
可以回答:
企业 NL2SQL 最难的部分通常包含业务语义、Schema Linking、权限、数据粒度和结果正确性几个方面。
例如"净收入"可能不是数据库字段,而是公司定义的指标公式。所以系统需要先从 Metric Glossary 找到业务定义,再检索相关表、字段和 Join Path。
Schema Linking 还需要处理关联基数。例如一笔订单可能对应多条退款记录。直接关联后再汇总订单金额会产生重复计数,因此需要先把退款聚合到订单粒度,再计算净收入。
SQL 生成以后还要经过 AST、ACL、Cost 和 Read-only 校验。执行成功以后还要检查结果口径、单位、时间范围、聚合粒度和异常值。
所以我的验收标准是最终业务结果正确,同时满足权限和资源约束。
38. 面试时可以压缩成下面这段
问数 Agent 我会拆成 Session/Task State、Intent Router、Business Semantic Layer、Schema Retrieval、NL2SQL、SQL Guard、Read-only Executor 和 Result Validator 几层。
首先对用户问题做结构化 Intent Recognition,识别 Intent、Metric、Dimension、Filter、Time Range 和 Confidence。信息不足就先 Clarification。
NL2SQL 之前需要先做 Business Semantic Resolution,因为企业里的"GMV、净收入、活跃用户"通常都有具体业务口径,单靠数据库 Schema 不一定能确定。确定指标后再做 Schema Linking,找到相关表、字段和 Join Path。
Schema Linking 还需要判断数据粒度和 Join Cardinality。例如一笔 100 元订单存在 10 元和 20 元两次退款,正确净收入是 70 元。直接连接订单和退款后汇总可能重复计算订单金额,所以应先按 order_id 聚合退款,再与订单表关联,并用未退款、部分退款、多次退款三类样例做回归验证。
SQL 不能直接执行。我会先 Parse AST,限制为允许的只读语句,再检查表列权限、Tenant、查询 Cost 和 Row Limit,最后使用最小权限的 Read-only Database Credential 执行。执行成功后还需要验证结果范围、单位、时间口径、关联基数和业务规则。
历史上下文方面,我不会直接把全部 Conversation 当成状态。我会维护 task/subtask ID、Active/Suspended/Cancelled、不可丢失约束、Decision 和 Artifact Reference。用户换话题时显式挂起或取消旧任务,并撤销旧 Worker Lease,Late Result 不再写入新任务。Summary 必须可重建并保留 Provenance,还要用 Constraint Replay 验证压缩没有丢关键信息。
评测时分别看 Intent Accuracy、Slot Extraction、SQL Execution Accuracy、Business Correctness、Unauthorized Query Rate 和 End-to-End Task Success。
一句话总结:
问数 Agent 的关键链路是"理解业务问题 → 解析业务口径 → 找到正确 Schema 和数据粒度 → 安全地产生并执行 SQL → 验证结果 → 管理好多轮任务状态"。
39. 当前资料能够确定到什么程度
39.1 原表直接支持
原表明确支持:
- Conversation 不能直接等同 Task State;
- Task / Subtask ID;
- Active / Suspended / Cancelled;
- 不可丢失 Constraint;
- Decision;
- Artifact Reference;
- Summary 可重建;
- Provenance;
- 话题切换时确认 Cancel / Suspend;
- 撤销旧 Worker Lease;
- Late Result 丢弃;
- Constraint Replay;
- Regression Sample;
- Context Compression Loss;
- 越权测试;
- Prompt Injection 测试;
- Duplicate Execution;
- Dependency Failure;
- Human Takeover;
- Rollback;
- Trace;
- Audit。
39.2 原表未提供、由外部资料扩展
原表没有具体给出:
- 问数 Agent 完整模块架构;
- Intent Taxonomy;
- Intent Confidence;
- Metric Semantic Layer;
- Schema Linking;
- NL2SQL Prompt;
- SQL AST Validator;
- Read-only Transaction;
- EXPLAIN Cost Gate;
- Execution Accuracy 指标;
- 一对多 Join 的聚合粒度校验。
这些内容属于本次外部研究后的技术扩展,不能归因于原始面经答案。
40. 来源
- 原始题目表,第 48 题(T5):问数 Agent 整体架构、意图识别、历史上下文与 NL2SQL。
- OpenAI Agents SDK --- Agent Orchestration / Handoffs / Running Agents:当前文档提供结构化分类后由代码路由、Handoff,以及 Session/Conversation State 管理模式。
- LangGraph Documentation --- Memory Overview:说明短期 Memory 可以包含 Conversation History 和其他 Agent State,并指出长历史可能增加成本、延迟和旧信息干扰。
- Spider 2.0: Evaluating Language Models on Real-World Enterprise Text-to-SQL Workflows:说明真实企业 Text-to-SQL 涉及大型 Schema、元数据检索、SQL 方言和复杂多步工作流。
- EntSQL: A Benchmark for Grounding Text-to-SQL in Long-Context Enterprise Knowledge, 2026:说明企业 NL2SQL 经常依赖私有业务指标、报表规则和企业内部知识。
- OWASP SQL Injection Prevention Cheat Sheet:强调数据库账号最小权限,并可使用 View 等机制限制数据访问范围。
- PostgreSQL Documentation --- SET TRANSACTION / Read-only Transaction:说明 Read-only Transaction 会禁止多种数据修改和 DDL 操作。
- PostgreSQL Documentation --- EXPLAIN:说明可在执行前查看 Query Plan 与估计执行 Cost。