AskTable

如何优化 AI 查询效果:AskTable 最佳实践

AskTable 团队
AskTable 团队

如何优化 AI 查询效果:AskTable 最佳实践

AI 查询的准确性取决于多个因素:数据库元数据质量、训练样本、权限配置、提问方式等。本文将系统介绍如何优化 AskTable 的查询效果,让 AI 更准确地理解你的需求。

一、元数据优化

1.1 为什么元数据很重要

元数据是 AI 理解数据库结构的基础。高质量的元数据可以:

1.2 表和字段描述

添加清晰的描述

# 好的描述
table: "orders"
description: "客户订单记录,包含订单基本信息、金额、状态等"

field: "order_status"
description: "订单状态:pending(待处理)、paid(已支付)、shipped(已发货)、completed(已完成)、cancelled(已取消)"

# 不好的描述
table: "orders"
description: "订单"  # 太简单

field: "status"
description: "状态"  # 没有说明可能的值

描述最佳实践

  1. 表描述:说明表的业务含义、主要用途、数据范围
  2. 字段描述:说明字段含义、数据类型、可能的值、单位等
  3. 枚举值:对于状态字段,列出所有可能的值及其含义
  4. 关系说明:说明外键关系和表之间的关联

1.3 字段可见性控制

隐藏不需要的字段可以:

# 隐藏内部字段
field: "internal_id"
visibility: false

field: "created_by_system"
visibility: false

# 保留业务字段
field: "order_id"
visibility: true

field: "customer_name"
visibility: true

建议隐藏的字段

1.4 示例值注入

AskTable 支持自动注入示例值到字段描述中:

# 原始描述
field: "region"
description: "销售区域"

# 注入示例值后
field: "region"
description: "销售区域(e.g. \"华东\",\"华北\",\"华南\")"

工作原理

  1. 用户提问时,AskTable 提取关键词
  2. 在值索引中搜索匹配的值
  3. 将匹配的值注入到字段描述中
  4. AI 看到具体示例,更容易生成正确的查询

启用值索引

# 配置 Azure AI Search
aisearch_host: "https://your-search.search.windows.net"
aisearch_master_key: "your-key"

二、语义搜索优化

2.1 语义搜索工作流程

当用户提问时,AskTable 使用两阶段检索:

用户问题: "上周华东地区的销售额"
    ↓
┌─────────────────────────────────────┐
│ 1. 提取子查询和关键词                │
│    subqueries: ["销售额", "地区"]    │
│    keywords: ["华东", "上周"]        │
└─────────────────────────────────────┘
    ↓
┌─────────────────────────────────────┐
│ 2. 语义搜索字段                      │
│    - 在向量数据库中搜索相关字段       │
│    - 匹配: sales.amount, sales.region│
└─────────────────────────────────────┘
    ↓
┌─────────────────────────────────────┐
│ 3. 全文搜索值                        │
│    - 在值索引中搜索关键词            │
│    - 匹配: region="华东"             │
└─────────────────────────────────────┘
    ↓
┌─────────────────────────────────────┐
│ 4. 合并结果并注入示例值              │
│    region: "销售区域(e.g. \"华东\")" │
└─────────────────────────────────────┘

2.2 向量数据库配置

AskTable 使用 Qdrant 存储字段向量:

# 字段向量化
field_vector = embed_model.encode(
    f"{table.name} {field.name} {field.description}"
)

# 存储到 Qdrant
qdrant.upsert(
    collection_name=f"ds_{datasource_id}_fields",
    points=[{
        "id": field_id,
        "vector": field_vector,
        "payload": {
            "schema_name": schema.name,
            "table_name": table.name,
            "field_name": field.name,
            "description": field.description,
        }
    }]
)

优化建议

  1. 定期同步元数据:数据库结构变更后及时同步
  2. 使用高质量描述:描述越详细,向量表示越准确
  3. 监控搜索质量:查看检索到的字段是否相关

2.3 值索引配置

值索引用于全文搜索具体的数据值:

# 索引字段的唯一值
unique_values = datasource.query(
    f"SELECT DISTINCT {field.name} FROM {table.name} LIMIT 1000"
)

# 存储到 Azure AI Search
for value in unique_values:
    search_client.upload_documents([{
        "id": f"{field_id}_{value}",
        "schema_name": schema.name,
        "table_name": table.name,
        "field_name": field.name,
        "value": value,
        "type": "value"
    }])

适合索引的字段

不适合索引的字段

三、训练样本优化

3.1 训练样本的作用

训练样本(Training Pairs)是问题-SQL 对,用于:

  1. Few-shot Learning:提供查询示例给 AI 参考
  2. Schema Linking:标记常用的表和字段
  3. 模式学习:让 AI 学习特定的查询模式

3.2 添加训练样本

通过 UI 添加

  1. 在聊天界面执行查询
  2. 点击查询结果的"添加到训练集"按钮
  3. 编辑问题和 SQL(如需要)
  4. 保存

通过 API 添加

import requests

response = requests.post(
    "https://api.asktable.com/api/v1/datasources/{ds_id}/training-pairs",
    headers={"Authorization": f"Bearer {api_key}"},
    json={
        "question": "上周华东地区的销售额",
        "sql": """
            -- 上周华东地区的销售额
            SELECT SUM(amount) as total_sales
            FROM sales
            WHERE region = '华东'
              AND order_date >= DATE_SUB(CURDATE(), INTERVAL 1 WEEK)
              AND order_date < CURDATE()
        """
    }
)

3.3 训练样本最佳实践

1. 覆盖常见查询模式

-- 时间范围查询
SELECT * FROM orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-01-31'

-- 聚合查询
SELECT region, SUM(amount) as total
FROM sales
GROUP BY region

-- 多表关联
SELECT o.order_id, c.customer_name, o.amount
FROM orders o
JOIN customers c ON o.customer_id = c.id

-- 排名查询
SELECT product_name, sales_count
FROM products
ORDER BY sales_count DESC
LIMIT 10

2. 包含业务术语

-- 问题: "本月 GMV"
-- SQL: SELECT SUM(amount) FROM orders WHERE ...

-- 问题: "活跃用户数"
-- SQL: SELECT COUNT(DISTINCT user_id) FROM user_actions WHERE ...

-- 问题: "复购率"
-- SQL: SELECT COUNT(DISTINCT CASE WHEN order_count > 1 THEN customer_id END) / COUNT(DISTINCT customer_id) ...

3. 标注复杂逻辑

-- 问题: "同比增长率"
SELECT
  current_year.month,
  (current_year.sales - last_year.sales) / last_year.sales * 100 as growth_rate
FROM
  (SELECT MONTH(order_date) as month, SUM(amount) as sales
   FROM orders
   WHERE YEAR(order_date) = 2024
   GROUP BY MONTH(order_date)) current_year
JOIN
  (SELECT MONTH(order_date) as month, SUM(amount) as sales
   FROM orders
   WHERE YEAR(order_date) = 2023
   GROUP BY MONTH(order_date)) last_year
ON current_year.month = last_year.month

4. 数量建议

3.4 训练样本的使用

AskTable 在查询时自动使用训练样本:

# 1. 从训练样本中提取相关字段
training_pairs = retrieve_training_pairs(datasource_id, question)
training_fields = extract_fields_from_sql(training_pairs)

# 2. 合并到检索结果
all_fields = semantic_search_fields + training_fields

# 3. 注入到 System Prompt
system_prompt = f"""
相关训练样本:
{format_training_pairs(training_pairs)}

相关字段:
{format_fields(all_fields)}
"""

四、权限配置优化

4.1 权限对查询的影响

权限配置会影响 AI 可以访问的数据范围:

# 用户只能看到自己部门的数据
role_policy = {
    "tables": ["sales"],
    "row_filter": "department = '{{user.department}}'"
}

# AI 生成的 SQL 会自动添加过滤条件
# 原始: SELECT * FROM sales
# 实际: SELECT * FROM sales WHERE department = '销售部'

优化建议

  1. 合理设置表权限:只授权必要的表
  2. 使用行级过滤:限制数据范围而不是隐藏整个表
  3. 避免过度限制:过多限制会导致 AI 无法回答问题

4.2 字段脱敏

对敏感字段进行脱敏:

# 配置字段脱敏
field_policy = {
    "field": "customer_phone",
    "mask_type": "phone",  # 138****5678
}

field_policy = {
    "field": "customer_email",
    "mask_type": "email",  # a***@example.com
}

详见:AskTable 数据安全最佳实践

五、提问技巧

5.1 清晰的问题

好的问题

不好的问题

5.2 包含关键信息

时间范围

维度信息

指标信息

5.3 使用业务术语

如果你的训练样本中包含业务术语,可以直接使用:

"本月 GMV"  → AI 知道 GMV = SUM(amount)
"活跃用户" → AI 知道活跃用户的定义
"复购率"   → AI 知道如何计算复购率

5.4 分步查询

对于复杂问题,可以分步查询:

步骤1: "2024年各地区的销售额"
步骤2: "华东地区的销售额占比"
步骤3: "华东地区销量前10的产品"

在 Canvas 中,可以将多个查询组合成工作流。

六、监控和调试

6.1 查看 AI 思考过程

AskTable 提供流式响应,可以看到 AI 的思考过程:

1. 搜索元数据...
   找到表: sales, orders
   找到字段: region, amount, order_date

2. 查看表结构...
   sales.region: 销售区域(e.g. "华东","华北")
   sales.amount: 销售金额
   sales.order_date: 订单日期

3. 执行 SQL...
   SELECT SUM(amount) FROM sales WHERE region = '华东' AND ...

4. 返回结果
   总销售额: 1,234,567

6.2 检查检索质量

查看 AI 检索到的表和字段是否相关:

# 在日志中查看检索结果
retrieved_fields = [
    "sales.region (score: 0.92)",
    "sales.amount (score: 0.89)",
    "sales.order_date (score: 0.85)",
]

如果检索不准确

6.3 分析失败查询

当查询失败时,检查:

  1. 元数据问题:AI 是否找到了正确的表和字段?
  2. 权限问题:用户是否有权限访问这些表?
  3. SQL 错误:生成的 SQL 是否有语法错误?
  4. 数据问题:数据库中是否有相关数据?

七、性能优化

7.1 减少元数据规模

隐藏不必要的表

# 只保留业务表
visible_tables = ["orders", "customers", "products", "sales"]

# 隐藏系统表
hidden_tables = ["_migrations", "_audit_log", "_temp_*"]

隐藏不必要的字段

# 只保留业务字段
visible_fields = ["id", "name", "amount", "status", "created_at"]

# 隐藏技术字段
hidden_fields = ["internal_*", "*_hash", "*_key"]

7.2 使用 Prompt Caching

启用 Prompt Caching 可以减少重复内容的处理时间:

# 自动启用 Prompt Caching
messages = message_builder.dump_openai(cache_control=True)

适合缓存的内容

7.3 控制训练样本数量

过多的训练样本会增加 token 消耗:

# 只检索最相关的训练样本
training_pairs = retrieve_training_pairs(
    datasource_id,
    question,
    limit=10  # 限制数量
)

7.4 使用合适的模型

根据查询复杂度选择模型:

# 简单查询:使用快速模型
model = "gpt-4o-mini"

# 复杂查询:使用强大模型
model = "gpt-4o"

# Canvas 节点:使用推理模型
model = "o1-mini"
reasoning_effort = "medium"

八、常见问题

Q1: AI 找不到相关的表和字段

可能原因

解决方案

  1. 完善表和字段描述
  2. 重新同步元数据到向量数据库
  3. 添加相关的训练样本
  4. 使用更明确的问题表述

Q2: AI 生成的 SQL 有错误

可能原因

解决方案

  1. 检查字段的 data_type 是否正确
  2. 添加类似查询的训练样本
  3. 将复杂问题分解为多个简单问题

Q3: 查询速度慢

可能原因

解决方案

  1. 隐藏不必要的表和字段
  2. 限制训练样本数量
  3. 启用 Prompt Caching
  4. 使用更快的模型

Q4: AI 返回的数据不符合权限

可能原因

解决方案

  1. 检查角色的权限配置
  2. 验证行级过滤表达式
  3. 查看生成的 SQL 是否包含过滤条件

九、总结

优化 AI 查询效果是一个持续的过程,需要从多个方面入手:

  1. 元数据优化:清晰的描述、合理的可见性、示例值注入
  2. 语义搜索:向量数据库、值索引、定期同步
  3. 训练样本:覆盖常见模式、包含业务术语、适量添加
  4. 权限配置:合理授权、行级过滤、字段脱敏
  5. 提问技巧:清晰表述、包含关键信息、使用业务术语
  6. 监控调试:查看思考过程、检查检索质量、分析失败原因
  7. 性能优化:减少元数据、Prompt Caching、选择合适模型

通过系统地应用这些最佳实践,你可以显著提升 AskTable 的查询准确性和效率。

相关资源