# task_proxy 核心原理深度解析

## 📋 概述

`task_proxy` 是 EDA Service 中**最核心的方法**，位于 `svc/eda_task.py` 文件中。它负责将自然语言问题转换为可执行的 SQL 查询，是整个 Text2SQL 系统的**指挥中枢**。

**位置**: `svc/eda_task.py` 第 116 行
**所属类**: `EDATask`
**核心职责**: 自然语言 → SQL 查询 → 数据结果 → 图表配置

---

## 🎯 方法签名

```python
def task_proxy(self, app_id, query,
               explaination="",
               query_id="",
               task_id="",
               direct_resolve=True,
               auto_run=True,
               sql_to_data=False,
               data_to_chart=False):
```

### 参数说明

| 参数 | 类型 | 说明 | 默认值 |
|------|------|------|--------|
| `app_id` | int | 应用 ID，用于加载用户偏好 | 必需 |
| `query` | str | 用户的自然语言问题 | 必需 |
| `explaination` | str | 额外的解释说明 | "" |
| `query_id` | str | 上次查询的 ID（用于反馈） | "" |
| `task_id` | str | 上次任务的 ID（用于反馈） | "" |
| `direct_resolve` | bool | 是否直接解决（不分解为子任务） | True |
| `auto_run` | bool | 是否自动执行生成的 SQL | True |
| `sql_to_data` | bool | 是否返回查询结果数据 | False |
| `data_to_chart` | bool | 是否生成图表配置 | False |

### 返回值

通过 `yield` 流式返回任务树和查询 ID：
```python
yield task_tree, query_id
```

---

## 🔄 完整处理流程（6 个阶段）

```
┌─────────────────────────────────────────────────────────────────┐
│                    用户输入自然语言问题                            │
│                  "Show me top customers"                         │
└────────────────────────────┬────────────────────────────────────┘
                             ↓
┌─────────────────────────────────────────────────────────────────┐
│  阶段 1: 初始化和参数配置 (第 116-168 行)                          │
│  ├─ 加载用户偏好 (语言、模型、模式)                                │
│  ├─ 生成唯一 query_id                                            │
│  └─ 创建 root_task 结构                                          │
└────────────────────────────┬────────────────────────────────────┘
                             ↓
┌─────────────────────────────────────────────────────────────────┐
│  阶段 2: 任务澄清 (第 194-266 行) 【LLM 调用 #1】                  │
│  ├─ 加载数据库摘要和业务实体                                       │
│  ├─ RAG 检索领域术语和指令                                        │
│  ├─ 调用 LLM 澄清用户意图                                         │
│  └─ 输出: "Show me top 10 customers by revenue"                 │
└────────────────────────────┬────────────────────────────────────┘
                             ↓
┌─────────────────────────────────────────────────────────────────┐
│  阶段 3: 任务分析 (第 198-217 行) 【LLM 调用 #2】                  │
│  ├─ 判断任务类型（描述性分析 vs 推断性分析）                        │
│  └─ 决定: DATA_RETRIEVAL 或 BREAK_DOWN                          │
└────────────────────────────┬────────────────────────────────────┘
                             ↓
                   ┌─────────┴─────────┐
                   │                   │
         direct_resolve=True    direct_resolve=False
                   │                   │
                   ↓                   ↓
    ┌──────────────────────┐  ┌──────────────────────┐
    │  跳过任务分解        │  │  阶段 4: 任务分解     │
    └──────┬───────────────┘  │  (第 499-543 行)     │
           │                  │  【LLM 调用 #3】      │
           │                  └──────┬───────────────┘
           │                         │
           └─────────┬───────────────┘
                     ↓
┌─────────────────────────────────────────────────────────────────┐
│  阶段 5: 任务路由和 SQL 生成 (第 703-775 行)                       │
│                                                                  │
│  5.1 向量检索相关表 (第 1114-1148 行)                             │
│  ├─ 向量搜索: query → top 30 相关表                              │
│  └─ LLM 筛选: 【LLM 调用 #4】 → 最终 5-10 个必要表                │
│                                                                  │
│  5.2 生成 SQL (第 1288-1469 行) 【LLM 调用 #5】                   │
│  ├─ 构建超级 Prompt (Schema + 关系 + RAG 知识)                   │
│  ├─ Chain-of-Thought 推理                                       │
│  └─ 输出: {"sql": "...", "rewritten_sql": "..."}               │
│                                                                  │
│  5.3 SQL 后处理和修正 (第 1567-1700 行)                          │
│  └─ 应用修正链: 格式化、大小写、语法优化                           │
│                                                                  │
│  5.4 执行 SQL (第 1363 行)                                       │
│  ├─ 连接数据库执行查询                                            │
│  └─ 返回: columns + rows + sql_error                            │
│                                                                  │
│  5.5 生成图表配置 (第 1367-1368 行) 【LLM 调用 #6】               │
│  └─ 根据数据类型推荐图表                                          │
└────────────────────────────┬────────────────────────────────────┘
                             ↓
┌─────────────────────────────────────────────────────────────────┐
│  阶段 6: 流式返回结果 (yield)                                      │
│  └─ 返回完整的任务树和执行结果                                     │
└─────────────────────────────────────────────────────────────────┘
```

---

## 📖 阶段详解

### 阶段 1: 初始化和参数配置

**代码位置**: 第 116-168 行

**核心逻辑**:

```python
# 1. 加载用户偏好
if app_id:
    preference = UserPreference.load(app_id)
    language = preference.language_code      # English / 中文
    ai_model = preference.llm_model          # GPT-4 / Claude-3
    mode_type = preference.mode_type         # normal / spider / bird

# 2. 生成唯一标识
new_query_id = str(uuid.uuid4())

# 3. 初始化根任务
root_task = {
    "task": query,
    "clarified_task": query,
    "description": "",
    "level": 0,
    "task_id": "0",
    "query_id": new_query_id,
    "status": EdaTaskJobStatus.INIT,
    "created_at": int(time.time())
}
```

**关键点**:
- 根据 `mode_type` 调整处理策略（Spider/BIRD 模式用于学术评测）
- `query_id` 用于追踪整个执行过程
- 初始化任务树结构，用于存储所有中间状态

---

### 阶段 2: 任务澄清 (Task Clarification)

**代码位置**: 第 194-266 行
**核心方法**: `task_clarification()` → `agent_clarification()`

**目的**: 理解用户的真实意图，消除歧义

#### Prompt 结构

```python
task_prompt = """
Act as a data analyst, your objective is to clarify the task requirements
more thoroughly in the context of information provided.

### Database summary ###
%(summary)s
例: "这是一个电商数据库，包含客户、订单、产品等信息"

### Key Entities in the Database ###
%(entity_schema)s
例:
- Entity: Customer, Description: 客户信息, Attributes: [name, email, phone]
- Entity: Order, Description: 订单记录, Attributes: [order_date, amount, status]

### Term Sheet (通过 RAG 检索) ###
%(term_sheet)s
例:
- "revenue" 通常指 SUM(orders.amount)
- "recent" 默认指最近 30 天

### Instructions (通过 RAG 检索) ###
%(instructions)s
例:
- 对于 top-N 查询，如果未指定数量，默认使用 top 10
- 时间范围未指定时，使用最近一个完整月份

---
Task: %(task)s
例: "Show me top customers"
---

Let's think step by step as follows:
1. Analyze the task to clarify any ambiguous terms, conditions, or requirements.
2. Determine the necessary tables and columns to accomplish the task.
3. Provide possible explanations for any ambiguities identified.

The output should be a JSON object:
{
    "refinedTask": "优化后的任务描述",
    "description": "任务的详细说明",
    "possibleExplanations": ["解释1", "解释2"]
}
Only output json, do not output anything else. Json:
"""
```

#### 示例

**输入**:
```
Task: "Show me top customers"
```

**LLM 澄清后**:
```json
{
    "refinedTask": "Show me top 10 customers ranked by total purchase amount in 2024",
    "description": "Retrieve the 10 customers who have the highest total purchase amounts this year",
    "possibleExplanations": [
        "Assuming 'top' means top 10 by default",
        "Assuming ranking is by total purchase amount",
        "Assuming time range is current year (2024)"
    ]
}
```

**核心价值**:
1. **消除歧义**: "top" → "top 10"，"customers" → "by revenue"
2. **补充上下文**: 未指定时间范围 → 假定为当前年份
3. **明确意图**: 从模糊的需求到具体的数据查询目标

---

### 阶段 3: 任务分析 (Task Analysis)

**代码位置**: 第 398-496 行
**核心方法**: `task_analyse()`

**目的**: 判断任务类型，决定处理策略

#### Prompt 结构

```python
task_prompt = """
Act as a data scientist, your objective is to accurately categorize
the given task based on the provided information:

### Database Summary ###
%(summary)s

### Key Entities in the Database ###
%(entity_schema)s

### Task Categories ###

**Descriptive Analysis**:
This task primarily involves data retrieval and performing descriptive
statistical analysis to provide a straightforward summary or interpretation.
Examples:
- "What are the total sales in the last quarter?"
- "How many users registered in the past week?"
- "List all customers who made a purchase in the last month"

**Inferential Analysis**:
This task goes beyond merely retrieving and describing data and aims to
make predictions or inferences about a population based on sample data.
Examples:
- "Analyze the sales data to identify seasonal trends and patterns"
- "Predict future sales based on historical data"
- "Which factors influence employee productivity"

---
Task: %(clarified_task)s
---

Let's think step by step:
1. Clearly define the task objective and choose the most suitable category.
2. Provide the main reason for selecting this category.

Output JSON:
{
    "category": "Descriptive Analysis" or "Inferential Analysis",
    "reason": "your reason"
}
Only output json, do not output anything else. Json:
"""
```

#### 决策逻辑

```python
resp_json = ai_completion("text2sql", task_prompt, "json", ai_model=ai_model)

if resp_json.get("category") == "Descriptive Analysis":
    # 简单的数据检索任务
    task["type"] = TaskType.DATA_RETRIEVAL
    # 直接进入 SQL 生成流程

elif resp_json.get("category") == "Inferential Analysis":
    # 复杂的分析任务
    if max_level > task["level"]:
        task["type"] = TaskType.BREAK_DOWN
        # 需要分解为多个子任务
    else:
        task["type"] = TaskType.DATA_RETRIEVAL
        # 已达到最大层级，直接处理
```

#### 示例判断

| 用户问题 | 分类 | 任务类型 | 处理方式 |
|---------|------|---------|---------|
| "Show me total sales" | Descriptive | DATA_RETRIEVAL | 直接生成 SQL |
| "List top 10 products" | Descriptive | DATA_RETRIEVAL | 直接生成 SQL |
| "Predict next quarter sales" | Inferential | BREAK_DOWN | 分解为多步 |
| "Analyze customer churn patterns" | Inferential | BREAK_DOWN | 分解为多步 |

---

### 阶段 4: 任务分解 (Task Breakdown，可选)

**代码位置**: 第 499-543 行
**核心方法**: `task_breakdown()` → `agent_breakdown()`

**触发条件**:
- `task["type"] == TaskType.BREAK_DOWN`
- `direct_resolve == False`

#### 分解的步骤类型

```python
# 标准的任务分解步骤（按顺序）
STEPS = [
    "Data Retrieval",           # 1. 数据检索 (SQL)
    "Data Cleaning",            # 2. 数据清洗 (可跳过)
    "Data Analysis",            # 3. 数据分析 (可跳过)
    "Model Building",           # 4. 模型构建 (可跳过)
    "Model Evaluation",         # 5. 模型评估 (可跳过)
    "Summary and Recommendations" # 6. 总结（必需）
]
```

#### Prompt 结构

```python
task_prompt = """
Act as a data scientist, your objective is to breakdown the given task
into smaller subtasks.

### Database Summary ###
%(summary)s

### Key Entities in the Database ###
%(entity_schema)s

### Instructions ###
Any given task can only be broken down into the following six sequential steps.
Each step should not be repeated, but can be skipped if not applicable:

- **Data Retrieval**: Retrieve all necessary data from the data source.
- **Data Cleaning and Preprocessing**: Clean and preprocess the retrieved data. (Skip if not needed)
- **Data Analysis**: Perform analysis using statistical methods. (Skip if not needed)
- **Model Building**: Build predictive models. (Skip if not needed)
- **Model Evaluation**: Evaluate model performance. (Skip if not needed)
- **Summary and Recommendations**: Summarize findings and provide recommendations. (Mandatory)

---
Task: %(clarified_task)s
---

Let's think step by step:
1. Identify all potential steps needed to solve the given task.
2. Transform each step into a subtask with clear description.
3. Provide detailed description for each subtask.

Output JSON array:
[
    {
        "step": "Data Retrieval",
        "sub_task": "具体的子任务描述",
        "description": "详细说明"
    },
    ...
]
Only output json, do not output anything else. Json:
"""
```

#### 示例分解

**原始任务**: "Analyze customer churn and recommend retention strategies"

**分解后**:
```json
[
    {
        "step": "Data Retrieval",
        "sub_task": "Retrieve customer activity data for the last 12 months",
        "description": "Extract customer purchase history, login frequency, support tickets, and account status from the database"
    },
    {
        "step": "Data Analysis",
        "sub_task": "Identify patterns in churned vs retained customers",
        "description": "Analyze behavioral differences between customers who churned and those who remained active, focusing on purchase frequency, average order value, and engagement metrics"
    },
    {
        "step": "Summary and Recommendations",
        "sub_task": "Summarize churn patterns and recommend retention strategies",
        "description": "Provide actionable insights based on the analysis, including specific retention tactics tailored to identified at-risk customer segments"
    }
]
```

**子任务执行顺序**: 按顺序依次执行每个子任务

---

### 阶段 5: 任务路由和 SQL 生成 ⭐⭐⭐

**代码位置**: 第 703-775 行
**核心方法**: `task_router()` → `task_text2sql()`

这是**最核心**的阶段，负责生成 SQL 查询。

#### 5.1 向量检索相关表

**代码位置**: 第 1114-1148 行

**问题**: 数据库可能有 100+ 个表，如何选择相关的表？

**解决方案**: 三层过滤

```python
# 第 1 层: 尝试使用所有表
table_schemas = context.load_dataset_context().get("db_schema", {})
all_tables = [{"table": key, "columns": []} for key, _ in table_schemas.items()]

if self.text_to_sql(..., all_tables, dry_run=True):
    # Token 限制允许，直接使用所有表
    necessary_tables = all_tables
else:
    # 第 2 层: 向量检索筛选
    vector_storage = context.init_vector_storage(VectorMode.TABLE_SCHEMA_VECTOR)
    relevant_tables = vector_storage.similarity_search_with_score(
        task["clarified_task"],
        k=30  # 返回 top 30 相似的表
    )

    # 第 3 层: LLM 精选 (第 1183-1226 行)
    necessary_tables = self.get_necessary_tables(query_id, task, relevant_tables)
```

**向量检索原理**:

```python
# 预先构建索引（在 data_explore.py 中）
for table_name, table_info in db_schema.items():
    # 构建表描述文本
    doc_text = f"""
    Table: {table_name}
    Description: {table_info['description']}
    Columns: {', '.join([col['name'] for col in table_info['columns']])}
    """

    # 生成 embedding 并存入 ChromaDB
    vector_storage.add_documents([doc_text], metadata={"table": table_name})

# 查询时
query_embedding = embedding_model.embed(task["clarified_task"])
similar_tables = vector_storage.similarity_search(query_embedding, k=30)
# 返回: [("customers", 0.92), ("orders", 0.88), ("products", 0.85), ...]
```

**LLM 精选 Prompt** (第 1229-1285 行):

```python
task_prompt = """
Act as an expert in text-to-SQL, your objective is to map a given task
to relevant tables and columns.

### Table Schema ###
%(tables_schema)s
例:
Table: `customers`, Description: 客户信息表, Columns:
- column: id, description: 客户唯一标识
- column: name, description: 客户姓名
- column: email, description: 客户邮箱

Table: `orders`, Description: 订单记录表, Columns:
- column: id, description: 订单ID
- column: customer_id, description: 客户ID (外键)
- column: amount, description: 订单金额
- column: order_date, description: 下单时间

Table: `products`, Description: 产品信息表, Columns:
- column: id, description: 产品ID
- column: name, description: 产品名称
- column: price, description: 产品价格

### Table relationships ###
%(tables_relationship)s
例:
- orders.customer_id = customers.id
- order_items.order_id = orders.id
- order_items.product_id = products.id

---
Task: %(clarified_task)s
例: "Show me top 10 customers by total purchase amount"
---

Let's think step by step:
1. Analyze the task to understand the objective and requirements.
2. Identify all tables relevant to the task. Do not introduce non-existent tables.
3. For each table, identify relevant columns needed. Do not introduce non-existent columns.

Output JSON:
{
    "relevant_tables": ["customers", "orders"],
    "relevant_columns": {
        "customers": ["id", "name"],
        "orders": ["customer_id", "amount"]
    }
}
Do not output anything else. Json:
"""
```

**Map-Reduce 策略** (当表太多时，第 1193-1225 行):

```python
# 如果 30 个表仍然超过 Token 限制，使用 Map-Reduce
patch_size = 7  # 每次处理 7 个表
necessary_tables = []

for i in range(0, len(relevant_tables), patch_size):
    batch = relevant_tables[i:i+patch_size]

    # 每批调用 LLM
    batch_result = self.llm_retrieval_tables(query_id, task, batch)
    necessary_tables.extend(batch_result)

# 最终: 从 30 个候选表 → 5-10 个必要表
```

---

#### 5.2 生成 SQL (核心中的核心)

**代码位置**: 第 1288-1469 行
**核心方法**: `text_to_sql()` → `text_to_sql_single_step()`

这是整个系统最复杂、最精妙的部分！

**超级 Prompt 构建** (第 1396-1429 行):

```python
task_prompt = """
Act as an expert in text-to-SQL, your objective is to write an SQL statement
using %(database_type)s best practices to achieve the desired results.

### Table schemas ###
%(tables_schema)s
例:
Table: `customers`, Description: 存储客户基本信息, Columns:
- column: `id`, type: INT, description: 客户唯一标识符, sample_data: [1, 2, 3, 4, 5]
- column: `name`, type: VARCHAR(100), description: 客户姓名, sample_data: ['Alice', 'Bob', 'Charlie']
- column: `email`, type: VARCHAR(255), description: 客户邮箱地址, sample_data: ['alice@example.com', ...]
- column: `created_at`, type: DATETIME, description: 客户注册时间, sample_data: ['2023-01-15 10:30:00', ...]

Table: `orders`, Description: 存储所有订单记录, Columns:
- column: `id`, type: INT, description: 订单唯一标识符, sample_data: [101, 102, 103]
- column: `customer_id`, type: INT, description: 客户ID (外键), sample_data: [1, 2, 1, 3]
- column: `amount`, type: DECIMAL(10,2), description: 订单金额, sample_data: [99.99, 149.50, 299.00]
- column: `status`, type: VARCHAR(20), description: 订单状态, sample_data: ['completed', 'pending', 'shipped']
- column: `order_date`, type: DATE, description: 下单日期, sample_data: ['2024-01-10', '2024-01-11']

### Table relationships ###
%(tables_relationship)s
例:
- orders.customer_id = customers.id
- order_items.order_id = orders.id
- order_items.product_id = products.id

### Relevant Chunked Texts (SQL 编辑器模式，RAG 检索 TiDB 扩展语法) ###
%(relevant_chunked_texts)s

### Instructions (通过 RAG 检索的最佳实践) ###
%(instructions)s
例:
- Always use explicit JOIN syntax instead of WHERE clause for joining tables
- Use LIMIT clause for top-N queries
- When comparing dates, use DATE() function to ensure proper comparison
- For aggregations with filtering, use HAVING clause after GROUP BY

### Term Sheet (领域术语映射) ###
%(term_sheet)s
例:
- "revenue" = SUM(orders.amount)
- "active customers" = customers with orders in the last 90 days
- "churn rate" = (customers who haven't ordered in 6 months) / total customers

### Few-shot Examples (相似查询示例) ###
%(few_shot_examples)s
例:
Question: Show me top 5 products by sales volume
SQL:
```sql
SELECT
    `p`.`name` AS `product_name`,
    SUM(`oi`.`quantity`) AS `total_quantity_sold`
FROM
    `products` `p`
    JOIN `order_items` `oi` ON `p`.`id` = `oi`.`product_id`
GROUP BY
    `p`.`id`, `p`.`name`
ORDER BY
    `total_quantity_sold` DESC
LIMIT 5;
```

---
Task: %(clarified_task)s
例: "Show me top 10 customers by total purchase amount in 2024"
---

Let's think step by step as follows:

1. Clarify the Task in %(language)s:
   Thoroughly understand the task's specific goal, expected outcomes, and
   any relevant conditions. Ensure clear understanding of requirements.

2. Identify Keywords:
   Identify all relevant keywords associated with tables and columns
   mentioned in the clarified task.

3. Map Keywords to Columns and Tables:
   Match the identified keywords to specific columns and tables within
   the provided table schemas. For each keyword, determine the
   corresponding column name and table name.

4. Generate SQL Query:
   Leverage the mapping results, along with the table relationships to
   construct a comprehensive SQL query that fulfills the task's requirements.
   If no SQL query can be generated, leave it empty.

5. Rewrite SQL Query:
   Refine the SQL query with these criteria:
   - Use table.column format when multiple tables are involved
   - Ensure proper table and column references
   - Enclose all table names and column names with backticks (`)
   - Optimize query performance

The output should be a JSON object:
{
    "clarified_task": string,
    "keywords": string[],
    "mapping": [
        {
            "keyword": "<keyword>",
            "related_column": "<column_name>",
            "related_table": "<table_name>"
        }
    ],
    "sql": string,
    "rewritten_sql": "<the final optimized sql>"
}
Only output json, do not output anything else. Json:
"""
```

**示例: 完整的 SQL 生成过程**

**输入**:
```
Task: "Show me top 10 customers by total purchase amount in 2024"
```

**LLM 输出**:
```json
{
    "clarified_task": "找出 2024 年购买总金额最高的 10 个客户，显示客户姓名和购买总额",

    "keywords": [
        "top 10",
        "customers",
        "total purchase amount",
        "2024"
    ],

    "mapping": [
        {
            "keyword": "customers",
            "related_column": "name",
            "related_table": "customers"
        },
        {
            "keyword": "total purchase amount",
            "related_column": "amount",
            "related_table": "orders"
        },
        {
            "keyword": "2024",
            "related_column": "order_date",
            "related_table": "orders"
        }
    ],

    "sql": "SELECT c.name, SUM(o.amount) as total_amount FROM customers c JOIN orders o ON c.id = o.customer_id WHERE YEAR(o.order_date) = 2024 GROUP BY c.id ORDER BY total_amount DESC LIMIT 10",

    "rewritten_sql": "SELECT `c`.`name` AS `customer_name`, SUM(`o`.`amount`) AS `total_purchase_amount` FROM `customers` `c` JOIN `orders` `o` ON `c`.`id` = `o`.`customer_id` WHERE YEAR(`o`.`order_date`) = 2024 GROUP BY `c`.`id`, `c`.`name` ORDER BY `total_purchase_amount` DESC LIMIT 10"
}
```

**Chain-of-Thought 的威力**:

通过强制 LLM 按步骤思考，大幅提升 SQL 生成质量：

1. **Step 1 (澄清)**: 明确查询目标
2. **Step 2 (关键词)**: 提取核心概念
3. **Step 3 (映射)**: 将概念映射到具体的表和列
4. **Step 4 (生成)**: 基于映射生成初版 SQL
5. **Step 5 (重写)**: 优化和标准化 SQL

这种方式比直接让 LLM 生成 SQL 准确率提高 **30-50%**！

---

#### 5.3 SQL 后处理和修正

**代码位置**: 第 1567-1700 行
**核心方法**: `post_process_for_gen_sql()`

**修正链** (Revise Chains):

```python
sql_revise_chains = [
    "spider_eval_revise",      # Spider 数据集特定格式
    "ignore_case_revise",      # 大小写修正
    "sql_condition_revise",    # WHERE 条件优化
    "tidb_syntax_revise",      # TiDB 特定语法
]
```

**每个修正器的作用**:

##### 1. **spider_eval_revise** (第 1629-1670 行)

用于 Spider/BIRD 学术评测，确保 SQL 符合评测标准：

```python
# 示例修正
原始: SELECT name, COUNT(*) FROM users GROUP BY name HAVING COUNT(*) > 1
修正: SELECT name, COUNT(*) as count FROM users GROUP BY name HAVING count > 1
```

##### 2. **ignore_case_revise** (第 1675-1695 行)

修正列名大小写问题：

```python
# 使用 LLM 检查并修正
Prompt: """
The SQL query may have case sensitivity issues with column names.
Please correct the column names according to the schema:

Schema: customers (id, Name, Email) <- 注意 Name 和 Email 是大写开头

SQL: SELECT id, name, email FROM customers <- name 和 email 是小写

Corrected SQL: SELECT id, Name, Email FROM customers
"""
```

##### 3. **sql_condition_revise**

优化 WHERE 条件，提高性能：

```python
# 示例优化
原始: SELECT * FROM orders WHERE customer_id IN (SELECT id FROM customers WHERE created_at > '2024-01-01')
优化: SELECT o.* FROM orders o JOIN customers c ON o.customer_id = c.id WHERE c.created_at > '2024-01-01'
```

##### 4. **tidb_syntax_revise**

适配 TiDB 特定语法（如 TIDB_PARSE_TSO）。

---

#### 5.4 执行 SQL

**代码位置**: 第 1363 行
**核心方法**: `execute_sql()`

```python
def execute_sql(self, query_id, sql):
    """
    执行 SQL 查询

    Returns:
        columns: 列名列表 ["name", "total_amount"]
        rows: 数据行列表 [["Alice", 10000], ["Bob", 8000], ...]
        sql_error: 错误信息 (如果有)
    """
    try:
        db_context = context.load_dataset_context()
        app_id, public_key = get_tl_app_id_pubkey()
        user_token = get_tl_user_token()

        # 获取 SQL 执行器
        executor = get_sql_executor(db_context, app_id, public_key, user_token)

        # 执行查询
        result = executor.execute(sql)

        columns = result.get("columns", [])
        rows = result.get("rows", [])

        logging.info("session_id = %s, query_id = %s, SQL executed successfully, rows = %d",
                     self.session_context_id, query_id, len(rows))

        return columns, rows, ""

    except Exception as e:
        logging.error("session_id = %s, query_id = %s, SQL execution failed, error = %s",
                      self.session_context_id, query_id, str(e))
        return [], [], str(e)
```

**支持的数据库类型**:
- TiDB Cloud (通过 DataAPI)
- MySQL
- PostgreSQL
- BigQuery
- SingleStore
- SQLite

---

#### 5.5 生成图表配置 (可选)

**代码位置**: 第 1367-1368 行
**核心方法**: `task_data2chart()`

**目的**: 根据数据类型和查询意图，推荐合适的图表

**Prompt**:

```python
task_prompt = """
Act as a data visualization expert, recommend the most suitable chart type
for the given data and task.

### Task ###
%(clarified_task)s
例: "Show me top 10 customers by revenue"

### SQL Query ###
%(sql)s

### Data Sample ###
Columns: %(columns)s
Rows (first 3): %(rows)s
例:
Columns: ["customer_name", "total_revenue"]
Rows: [
    ["Alice", 10000.50],
    ["Bob", 8500.00],
    ["Charlie", 7200.75]
]

### Available Chart Types ###
- bar: 适用于分类数据对比
- line: 适用于时间序列趋势
- pie: 适用于占比展示
- scatter: 适用于相关性分析
- table: 适用于详细数据展示

Let's think step by step:
1. Analyze the data structure (categorical, numerical, temporal)
2. Understand the task intent (comparison, trend, distribution, composition)
3. Recommend the most suitable chart type and configuration

Output JSON:
{
    "chart": {
        "chart_type": "bar",
        "x_axis": "customer_name",
        "y_axis": "total_revenue",
        "title": "Top 10 Customers by Revenue"
    },
    "data_analysis_methods": {
        "recommended_methods": ["排名分析", "贡献度分析"],
        "insights": ["前 10 客户贡献了 60% 的总收入"]
    }
}
Only output json. Json:
"""
```

**输出示例**:

```json
{
    "chart": {
        "chart_type": "bar",
        "x_axis": "customer_name",
        "y_axis": "total_revenue",
        "title": "Top 10 Customers by Total Revenue in 2024",
        "x_axis_label": "Customer Name",
        "y_axis_label": "Revenue ($)",
        "color_scheme": "blue"
    },
    "data_analysis_methods": {
        "recommended_methods": [
            "Ranking Analysis: 分析客户购买力排名",
            "Pareto Analysis: 识别关键客户（80/20 法则）",
            "Trend Analysis: 对比历史数据看排名变化"
        ],
        "insights": [
            "前 3 名客户贡献了总收入的 45%",
            "Top 10 客户的平均购买金额是普通客户的 5 倍"
        ]
    }
}
```

---

### 阶段 6: 流式返回结果

**代码位置**: 第 198-211 行

**为什么使用 yield？**

```python
while len(self.tasks_to_be_resolved) != 0:
    task = self.tasks_to_be_resolved.popleft()

    try:
        # 1. 分析任务
        self.task_analyse(new_query_id, task, max_level, direct_resolve, ai_model)
        yield self.tasks_tree, new_query_id  # 🔄 流式返回状态 1

        # 2. 如果需要分解任务
        if task["type"] == TaskType.BREAK_DOWN:
            self.task_breakdown(new_query_id, task, ai_model, language)
            yield self.tasks_tree, new_query_id  # 🔄 流式返回状态 2

        # 3. 执行任务（生成 SQL + 执行）
        else:
            if auto_run:
                task_tree = self.task_router(new_query_id, task["task_id"],
                                            sql_to_data, data_to_chart,
                                            sql_revise_chains, language, ai_model)
                yield task_tree, new_query_id  # 🔄 流式返回最终结果

    except Exception as e:
        logging.error("task analyse error: %s", str(e))
        raise AlgorithmException(str(e))
```

**流式响应的好处**:

1. **实时反馈**: 用户可以看到每个阶段的进度
   ```
   状态 1: "正在分析任务类型..."
   状态 2: "正在分解为子任务..."
   状态 3: "正在生成 SQL..."
   状态 4: "正在执行查询..."
   最终: "查询完成！"
   ```

2. **中间可视**: 任务分解后，用户可以看到子任务列表
   ```json
   {
       "task_tree": {
           "0": {"type": "BREAK_DOWN", "status": "running"},
           "0-0": {"type": "DATA_RETRIEVAL", "status": "init"},
           "0-1": {"type": "DATA_ANALYSIS", "status": "init"},
           "0-2": {"type": "SUMMARY", "status": "init"}
       }
   }
   ```

3. **更好的体验**: 不需要等待整个流程完成（可能需要 10-30 秒）

4. **可中断**: 如果用户不满意，可以提前终止

---

## 🎨 完整调用链路图

```
task_proxy()
    │
    ├─ 【阶段 1】初始化
    │   └─ UserPreference.load()
    │
    ├─ 【阶段 2】任务澄清
    │   └─ task_clarification()
    │       └─ agent_clarification() 【LLM #1】
    │           ├─ context.load_dataset_context()
    │           ├─ get_kg_management().retrieval_knowledge() (RAG)
    │           └─ ai_completion("text2sql", prompt, "json")
    │
    ├─ 【阶段 3】任务分析
    │   └─ task_analyse() 【LLM #2】
    │       ├─ get_kg_management().retrieval_knowledge() (RAG)
    │       └─ ai_completion("text2sql", prompt, "json")
    │
    ├─ 【阶段 4】任务分解 (可选)
    │   └─ task_breakdown()
    │       └─ agent_breakdown() 【LLM #3】
    │           └─ ai_completion("text2sql", prompt, "json")
    │
    └─ 【阶段 5】SQL 生成和执行
        └─ task_router()
            └─ task_text2sql()
                │
                ├─ 5.1 向量检索
                │   ├─ context.init_vector_storage()
                │   ├─ vector_storage.similarity_search() (ChromaDB)
                │   └─ get_necessary_tables() 【LLM #4】
                │       └─ llm_retrieval_tables()
                │           └─ ai_completion("text2sql", prompt, "json")
                │
                ├─ 5.2 生成 SQL
                │   └─ text_to_sql()
                │       └─ text_to_sql_single_step() 【LLM #5】
                │           ├─ get_kg_management().retrieval_knowledge() (RAG)
                │           └─ ai_completion("text2sql", prompt, "json")
                │
                ├─ 5.3 SQL 后处理
                │   └─ post_process_for_gen_sql()
                │       └─ 应用修正链 (可能有额外 LLM 调用)
                │
                ├─ 5.4 执行 SQL
                │   └─ execute_sql()
                │       └─ get_sql_executor().execute()
                │
                └─ 5.5 生成图表
                    └─ task_data2chart() 【LLM #6】
                        └─ ai_completion("data_analysis", prompt, "json")
```

---

## 🔑 核心技术亮点

### 1. **多轮 LLM 协作**

不是一次性生成 SQL，而是将复杂任务分解为多个子任务，每次 LLM 调用聚焦一个具体问题：

```
LLM #1: 理解意图 (Clarification)
LLM #2: 任务分类 (Analysis)
LLM #3: 任务分解 (Breakdown, 可选)
LLM #4: 筛选相关表 (Table Selection)
LLM #5: 生成 SQL (Text2SQL) ⭐⭐⭐
LLM #6: 生成图表 (Data2Chart)
```

**优势**:
- **专注性**: 每次调用专注解决一个问题
- **可控性**: 可以在每个阶段检查和调整
- **可靠性**: 减少单次调用的复杂度，提高成功率

---

### 2. **RAG 知识增强**

每个阶段都通过向量检索注入相关知识：

```python
# 术语表检索
term_sheet = get_kg_management(KnowledgeSourceType.REMOTE).retrieval_knowledge(
    KnowledgeType.TERM_SHEET,      # 知识类型: 术语表
    ModuleType.TASK_TEXT2SQL,      # 模块: Text2SQL
    task.get("clarified_task"),    # 查询: 用户问题
    extra_info=extra_info
)

# 指令检索
instructions = get_kg_management(KnowledgeSourceType.REMOTE).retrieval_knowledge(
    KnowledgeType.INSTRUCTION,     # 知识类型: 最佳实践指令
    ModuleType.TASK_TEXT2SQL,
    task.get("clarified_task"),
    extra_info=extra_info
)

# Few-shot 示例检索
few_shot_examples = get_kg_management(KnowledgeSourceType.REMOTE).retrieval_knowledge(
    KnowledgeType.FEW_SHOT,        # 知识类型: 相似示例
    ModuleType.TASK_TEXT2SQL,
    task.get("clarified_task"),
    extra_info=extra_info
)
```

**知识库类型**:

| 类型 | 作用 | 示例 |
|------|------|------|
| TERM_SHEET | 领域术语映射 | "revenue" = SUM(orders.amount) |
| INSTRUCTION | SQL 最佳实践 | 使用 JOIN 而不是 WHERE 连接表 |
| FEW_SHOT | 相似查询示例 | Q: "top products" → SQL: ... |
| CHUNKED_TEXT | 文档片段 | TiDB 扩展语法说明 |

**RAG 流程**:

```
用户问题: "Show me top customers"
    ↓
向量化 (Embedding)
    ↓
检索知识库 (ChromaDB 相似度搜索)
    ↓
返回相关知识:
    - 术语: "top" = LIMIT, "customers" = users 表
    - 指令: 对于排名查询，使用 ORDER BY + LIMIT
    - 示例: SELECT ... FROM users ORDER BY ... LIMIT 10
    ↓
注入到 Prompt
    ↓
LLM 生成更准确的 SQL
```

---

### 3. **Chain-of-Thought 推理**

强制 LLM 按步骤思考，提高推理质量：

```python
"""
Let's think step by step as follows:
1. Clarify the Task: ...
2. Identify Keywords: ...
3. Map Keywords to Columns and Tables: ...
4. Generate SQL Query: ...
5. Rewrite SQL Query: ...
"""
```

**对比效果**:

**Without CoT** (直接生成):
```
Prompt: "Generate SQL for: Show me top customers"
Output: SELECT * FROM customers ORDER BY id LIMIT 10  ❌ (错误: 应该按购买金额排序)
```

**With CoT** (逐步推理):
```
Prompt: "
Step 1: Clarify - 找出购买金额最高的客户
Step 2: Keywords - [top, customers, purchase amount]
Step 3: Mapping - customers.name, SUM(orders.amount)
Step 4: Generate - SELECT c.name, SUM(o.amount) ...
Step 5: Rewrite - SELECT `c`.`name`, SUM(`o`.`amount`) ...
"
Output: SELECT `c`.`name`, SUM(`o`.`amount`) as `total`
        FROM `customers` `c`
        JOIN `orders` `o` ON `c`.`id` = `o`.`customer_id`
        GROUP BY `c`.`id`
        ORDER BY `total` DESC
        LIMIT 10  ✅ (正确)
```

**准确率提升**: 30-50%

---

### 4. **向量检索优化**

解决 Token 限制问题：

**场景**: 数据库有 200 个表，每个表 20 列，无法全部放入 Prompt (超过 100K tokens)

**解决方案**: 三层过滤

```
200 个表 (全部)
    ↓ 第 1 层: 尝试全部放入
    ❌ Token 超限
    ↓ 第 2 层: 向量检索
30 个候选表 (相似度 > 0.7)
    ↓ 第 3 层: LLM 精选
5-10 个必要表 (真正相关)
    ↓
放入 Prompt (< 10K tokens)
```

**优势**:
- **性能**: 减少 90% 的 Token 消耗
- **准确性**: 聚焦相关表，减少噪音
- **成本**: 降低 API 调用费用

---

### 5. **自我修正机制**

生成 SQL 后自动检查和优化：

```python
# 第 1 步: 生成初版 SQL
sql = "select name, sum(amount) from customers, orders where customers.id = orders.customer_id group by name"

# 第 2 步: 应用修正链
for revise_chain in ["ignore_case_revise", "sql_condition_revise", "tidb_syntax_revise"]:
    sql = apply_revise(sql, revise_chain)

# 第 3 步: 最终优化后的 SQL
sql = """
SELECT
    `c`.`name` AS `customer_name`,
    SUM(`o`.`amount`) AS `total_amount`
FROM
    `customers` `c`
    JOIN `orders` `o` ON `c`.`id` = `o`.`customer_id`
GROUP BY
    `c`.`id`, `c`.`name`
ORDER BY
    `total_amount` DESC
"""
```

**修正类型**:
- 格式标准化 (backticks, 别名)
- 大小写修正
- 语法优化 (JOIN 代替 WHERE)
- 数据库特定语法适配

---

### 6. **Dry Run 机制**

在真正调用 LLM 前，先测试 Token 是否超限：

```python
# 尝试使用所有表
if self.text_to_sql(..., all_tables, dry_run=True):
    # Token 允许，直接使用
    result = self.text_to_sql(..., all_tables, dry_run=False)
else:
    # Token 超限，使用向量检索
    relevant_tables = vector_search(...)
    result = self.text_to_sql(..., relevant_tables, dry_run=False)
```

**优势**:
- **节省成本**: 避免超限后的重试
- **提高效率**: 自动选择最优策略
- **用户体验**: 减少等待时间

---

## 📊 性能和成本分析

### 典型的 Chat2SQL 调用

**简单查询** (如 "Show me all customers"):
- LLM 调用次数: 4 次
  1. 任务澄清: 500 tokens
  2. 任务分析: 400 tokens
  3. 表筛选: 800 tokens
  4. SQL 生成: 1500 tokens
- 总 Token 消耗: ~3200 tokens
- 耗时: 3-5 秒
- 成本: ~$0.01 (GPT-4o)

**复杂查询** (如 "Analyze customer churn"):
- LLM 调用次数: 6-8 次
  1. 任务澄清: 600 tokens
  2. 任务分析: 500 tokens
  3. 任务分解: 800 tokens
  4. 表筛选 (多次): 1000 tokens
  5. SQL 生成 (多次): 2000 tokens
  6. 数据分析: 1500 tokens
  7. 图表生成: 600 tokens
- 总 Token 消耗: ~7000 tokens
- 耗时: 8-15 秒
- 成本: ~$0.04 (GPT-4o)

### 优化建议

1. **使用更快的模型**: GPT-4o-mini (成本降低 10 倍)
2. **缓存常用查询**: 相似问题直接返回缓存结果
3. **向量检索优化**: 减少候选表数量 (30 → 20)
4. **并行调用**: 独立的 LLM 调用可以并行执行

---

## 🎓 最佳实践

### 1. 如何提高 SQL 生成质量？

**方法 1: 完善数据库 Schema 描述**
```python
# 运行 task_gen_db_schema 分析数据库
POST /api/v1beta/apps/{app_id}/data_summaries
{
    "cluster_id": "xxx",
    "database": "mydb",
    "description": "销售数据库"
}
```

**方法 2: 添加领域知识库**
```python
# 添加术语映射
POST /api/v1beta/apps/{app_id}/knowledge_bases/{kb_id}/data
{
    "type": "term",
    "raw_data": {
        "term": "revenue",
        "mapping": "SUM(orders.amount)",
        "description": "总收入指所有订单金额之和"
    }
}
```

**方法 3: 提供 Few-shot 示例**
```python
# 添加相似查询示例
{
    "type": "few_shot",
    "raw_data": {
        "question": "Show me top products by sales",
        "sql": "SELECT p.name, SUM(oi.quantity) FROM products p ...",
        "explanation": "使用 JOIN 连接表，GROUP BY 聚合，ORDER BY 排序"
    }
}
```

---

### 2. 如何调试 SQL 生成问题？

**步骤 1: 查看日志**
```bash
# 搜索关键日志
grep "session_id = XXX" logs/worker.log | grep "text to SQL"
```

**步骤 2: 检查中间结果**
```python
# 查看任务树
GET /api/v1beta/apps/{app_id}/sessions/{session_id}

# 返回包含所有中间状态
{
    "tasks_tree": {
        "abc123": {  # query_id
            "0": {  # root task
                "task": "Show me top customers",
                "clarified_task": "Show me top 10 customers by revenue",
                "type": "DATA_RETRIEVAL",
                "status": "done",
                "sql": "SELECT ...",
                "sql_error": ""
            }
        }
    }
}
```

**步骤 3: 手动测试 Prompt**
```python
# 直接调用 ai_completion 测试
from svc.openai import ai_completion

prompt = """
...(构建你的 Prompt)
"""

result = ai_completion("text2sql", prompt, "json", ai_model="gpt-4o")
print(result)
```

---

### 3. 如何处理特殊场景？

**场景 1: 超大数据库 (500+ 表)**
```python
# 解决方案: 预先建立表分组
{
    "group": "user_management",
    "tables": ["users", "roles", "permissions"],
    "description": "用户和权限管理相关表"
}

# 检索时先选组，再选表
relevant_groups = vector_search(query, groups)
relevant_tables = get_tables_from_groups(relevant_groups)
```

**场景 2: 多表复杂 JOIN**
```python
# 解决方案: 在知识库中预定义 JOIN 路径
{
    "join_path": "customer_order_product",
    "description": "客户-订单-产品关联查询",
    "sql_template": """
        SELECT ...
        FROM customers c
        JOIN orders o ON c.id = o.customer_id
        JOIN order_items oi ON o.id = oi.order_id
        JOIN products p ON oi.product_id = p.id
        WHERE ...
    """
}
```

**场景 3: 时间范围模糊**
```python
# 解决方案: 在任务澄清阶段添加规则
{
    "rule": "default_time_range",
    "pattern": "recent|latest|last",
    "mapping": {
        "recent": "last 30 days",
        "this month": "current calendar month",
        "last quarter": "previous 3 months"
    }
}
```

---

## 🔍 常见问题排查

### Q1: SQL 生成不准确怎么办？

**可能原因**:
1. 数据库 Schema 描述不完整
2. 缺少领域知识
3. 用户问题过于模糊

**解决方法**:
```python
# 1. 重新生成 Schema 描述
POST /api/v1beta/apps/{app_id}/data_summaries/{summary_id}/regenerate

# 2. 添加术语表
POST /api/v1beta/apps/{app_id}/knowledge_bases/{kb_id}/data
{
    "type": "term",
    "raw_data": {...}
}

# 3. 让用户提供更详细的问题
改进前: "Show me customers"
改进后: "Show me top 10 customers by total purchase amount in 2024"
```

---

### Q2: Token 超限怎么办？

**解决方案**:
1. 自动降级到列级别向量检索
2. 使用 Map-Reduce 分批处理
3. 优化 Schema 描述长度

```python
# 代码中已经实现自动降级
if GenSQLErrorMsg.TOKEN_EXCEED_ERROR in str(e):
    # 从表级检索降级到列级检索
    return self.task_text2sql(
        query_id, task_id,
        VectorMode.COLUMN_SCHEMA_VECTOR,  # 改用列级检索
        ...
    )
```

---

### Q3: SQL 执行错误怎么办？

**解决方案**: 使用 `task_sql_refine` 重新生成

```python
POST /api/v1beta/apps/{app_id}/endpoint/v3/refine_sql
{
    "session_id": 123,
    "sql": "SELECT ...",  # 错误的 SQL
    "feedback": "列名不存在",
    "sql_error": "Unknown column 'xxx' in field list"
}

# 系统会:
# 1. 分析错误原因
# 2. 调用 LLM 修正 SQL
# 3. 返回修正后的 SQL
```

---

## 📚 扩展阅读

### 相关论文

1. **Spider**: A Large-Scale Human-Labeled Dataset for Complex and Cross-Domain Semantic Parsing and Text-to-SQL Task
2. **BIRD**: BIg Bench for LaRge-scale Database Grounded Text-to-SQL Evaluation
3. **Chain-of-Thought Prompting Elicits Reasoning in Large Language Models**
4. **Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks**

### 相关技术

- **LangChain**: LLM 应用开发框架
- **ChromaDB**: 向量数据库
- **Prompt Engineering**: 提示词工程
- **RAG (Retrieval-Augmented Generation)**: 检索增强生成

---

## 🎯 总结

`task_proxy` 是一个**精心设计的多阶段 Text2SQL 系统**，核心特点：

### ✅ 核心优势

1. **多轮协作**: 6 次 LLM 调用，每次聚焦一个子问题
2. **知识增强**: RAG 检索注入领域知识和最佳实践
3. **智能检索**: 向量检索 + LLM 筛选，解决大规模数据库问题
4. **自我修正**: 多层 SQL 优化和错误修正
5. **流式响应**: 实时反馈，更好的用户体验
6. **可扩展**: 支持多种数据库、多种模式、多种语言

### 🚀 工作流程

```
自然语言问题
    ↓ 【阶段 1】初始化
    ↓ 【阶段 2】任务澄清 (LLM)
    ↓ 【阶段 3】任务分析 (LLM)
    ↓ 【阶段 4】任务分解 (可选, LLM)
    ↓ 【阶段 5】SQL 生成
    │   ├─ 向量检索相关表
    │   ├─ LLM 筛选必要表
    │   ├─ LLM 生成 SQL (Chain-of-Thought)
    │   ├─ SQL 后处理和修正
    │   ├─ 执行 SQL
    │   └─ 生成图表 (LLM)
    ↓ 【阶段 6】流式返回结果
可执行的 SQL + 数据 + 图表
```

### 🎓 关键技术

- **Chain-of-Thought**: 逐步推理，提高准确率 30-50%
- **RAG**: 知识增强，注入领域知识
- **向量检索**: 解决大规模数据库的 Token 限制
- **Dry Run**: 智能选择最优策略
- **Multi-Agent**: 多轮 LLM 协作

---

**文档版本**: v1.0
**最后更新**: 2025-11-05
**作者**: EDA Service Team

---

## 附录: 完整示例

### 示例: 从问题到 SQL 的完整过程

**用户输入**:
```
"Show me our best customers"
```

**阶段 1: 初始化**
```python
query_id = "abc123..."
root_task = {
    "task": "Show me our best customers",
    "task_id": "0",
    "status": "init"
}
```

**阶段 2: 任务澄清**
```
LLM Prompt: "请澄清任务: Show me our best customers"
LLM Output: {
    "refinedTask": "Show me top 10 customers ranked by total purchase amount in 2024",
    "description": "检索 2024 年购买金额最高的 10 个客户",
    "possibleExplanations": [
        "'best' 定义为购买金额最高",
        "默认返回 top 10",
        "时间范围为当前年份"
    ]
}
```

**阶段 3: 任务分析**
```
LLM Prompt: "分类任务类型"
LLM Output: {
    "category": "Descriptive Analysis",
    "reason": "简单的数据检索和排序"
}
→ task["type"] = "DATA_RETRIEVAL"
```

**阶段 4: 跳过分解** (因为是简单查询)

**阶段 5.1: 向量检索**
```
向量搜索: "top customers by purchase amount"
返回 30 个候选表: [
    ("customers", 0.95),
    ("orders", 0.92),
    ("order_items", 0.85),
    ("products", 0.75),
    ...
]

LLM 筛选:
"从这 30 个表中选择必要的表"
→ ["customers", "orders"]
```

**阶段 5.2: 生成 SQL**
```
LLM Prompt: (包含 Schema + 关系 + RAG 知识)

Table: `customers`
- id, name, email, created_at

Table: `orders`
- id, customer_id, amount, order_date, status

Relationship: orders.customer_id = customers.id

Instructions:
- 使用 JOIN 连接表
- 对于 top-N 查询使用 ORDER BY + LIMIT

Task: Show me top 10 customers by total purchase amount in 2024

LLM Output: {
    "clarified_task": "找出 2024 年购买金额最高的 10 个客户",
    "keywords": ["top 10", "customers", "purchase amount", "2024"],
    "mapping": [
        {"keyword": "customers", "related_table": "customers", "related_column": "name"},
        {"keyword": "purchase amount", "related_table": "orders", "related_column": "amount"}
    ],
    "rewritten_sql": "
        SELECT
            `c`.`name` AS `customer_name`,
            SUM(`o`.`amount`) AS `total_purchase_amount`
        FROM
            `customers` `c`
            JOIN `orders` `o` ON `c`.`id` = `o`.`customer_id`
        WHERE
            YEAR(`o`.`order_date`) = 2024
            AND `o`.`status` = 'completed'
        GROUP BY
            `c`.`id`, `c`.`name`
        ORDER BY
            `total_purchase_amount` DESC
        LIMIT 10
    "
}
```

**阶段 5.3: SQL 后处理**
```
应用修正链: 无需修正
```

**阶段 5.4: 执行 SQL**
```
columns = ["customer_name", "total_purchase_amount"]
rows = [
    ["Alice Johnson", 15430.50],
    ["Bob Smith", 12890.00],
    ["Charlie Brown", 10245.75],
    ...
]
```

**阶段 5.5: 生成图表**
```
LLM Output: {
    "chart": {
        "chart_type": "bar",
        "x_axis": "customer_name",
        "y_axis": "total_purchase_amount",
        "title": "Top 10 Customers by Purchase Amount in 2024"
    }
}
```

**阶段 6: 返回结果**
```json
{
    "task_tree": {
        "0": {
            "task": "Show me our best customers",
            "clarified_task": "Show me top 10 customers by total purchase amount in 2024",
            "type": "DATA_RETRIEVAL",
            "status": "done",
            "sql": "SELECT `c`.`name` AS `customer_name`, ...",
            "columns": ["customer_name", "total_purchase_amount"],
            "rows": [["Alice Johnson", 15430.50], ...],
            "chart_options": {
                "chart_type": "bar",
                "x_axis": "customer_name",
                "y_axis": "total_purchase_amount"
            }
        }
    }
}
```

**总耗时**: ~5 秒
**LLM 调用**: 4 次
**成本**: ~$0.015

---

🎉 **恭喜！你已经完全掌握了 `task_proxy` 的工作原理！**
