问数 Agent 整体架构、意图识别、历史上下文与 NL2SQL

第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. 来源

  1. 原始题目表,第 48 题(T5):问数 Agent 整体架构、意图识别、历史上下文与 NL2SQL。
  2. OpenAI Agents SDK --- Agent Orchestration / Handoffs / Running Agents:当前文档提供结构化分类后由代码路由、Handoff,以及 Session/Conversation State 管理模式。
  3. LangGraph Documentation --- Memory Overview:说明短期 Memory 可以包含 Conversation History 和其他 Agent State,并指出长历史可能增加成本、延迟和旧信息干扰。
  4. Spider 2.0: Evaluating Language Models on Real-World Enterprise Text-to-SQL Workflows:说明真实企业 Text-to-SQL 涉及大型 Schema、元数据检索、SQL 方言和复杂多步工作流。
  5. EntSQL: A Benchmark for Grounding Text-to-SQL in Long-Context Enterprise Knowledge, 2026:说明企业 NL2SQL 经常依赖私有业务指标、报表规则和企业内部知识。
  6. OWASP SQL Injection Prevention Cheat Sheet:强调数据库账号最小权限,并可使用 View 等机制限制数据访问范围。
  7. PostgreSQL Documentation --- SET TRANSACTION / Read-only Transaction:说明 Read-only Transaction 会禁止多种数据修改和 DDL 操作。
  8. PostgreSQL Documentation --- EXPLAIN:说明可在执行前查看 Query Plan 与估计执行 Cost。
相关推荐
Linux-lucky1 小时前
33-Linux学习之旅之MySQL用户管理
java·linux·运维·学习·mysql·ubuntu
SimonKing1 小时前
将cURL 命令直接变成 Java 代码?用JQuick-Curl搞起来
java·后端·程序员
IT大白鼠1 小时前
MySQL 分布式集群系列 · 第二篇:架构深度拆解--NDB 三大核心节点
分布式·mysql·架构
海宇AI1 小时前
零信任架构实战:基于海宇运营商近3个月平均账单构建自动化P2P信审网关
人工智能·架构·自动化·p2p
凤山老林1 小时前
企业级文件服务中台:Spring Boot 集成 MinIO 实现分片存储、生命周期管理与多租户隔离
java·spring boot·后端·minio·文件服务
醉颜凉1 小时前
Kafka ISR与AR深度解析:副本同步机制核心概念
分布式·架构·kafka·ar
青山木1 小时前
Hot 100 --- 买卖股票的最佳时机
java·数据结构·算法·leetcode·贪心算法
程序员良辰1 小时前
Eclipse Memory Analyzer(MAT)入门教程:从生成 Heap Dump 到定位 Java 内存问题
java·ide·eclipse·tomcat·idea
深圳市益普科技有限公司1 小时前
半导体MES的数字孪生:虚拟调试如何把上线风险提前清零
java·开发语言