数据分析与智能问数
智能问数(用自然语言查数据,也叫 Text-to-SQL)的做法是:把相关表的结构和字段说明写进提示词,让模型生成 SQL,程序确认这是一条只读查询后,用只读数据库账号执行,再由模型把查询结果写成几句业务结论。按每月 2 万次提问、另加 300 份报表和表格汇总估算,用各模型最低价分组的实时价格计算,模型费用每月约 ¥395。
价格更新于 2026年11月13日 17:58
月成本估算
假设:每月 2 万次提问(约 100 名业务人员,每人每个工作日 10 次);生成 SQL 每次输入约 4,000 tokens(指令和示例约 1,000、相关表结构约 2,500、问题约 500),输出约 300 tokens,约 10% 校验不通过要重写一次;解读结果每次输入约 1,500 tokens(最多 50 行结果);另有 300 份报表和表格汇总,每份输入约 8,000 tokens 的统计摘要。
业务问题
运营、销售和管理层经常要临时查一个数:上周各渠道的退货率、华东区有多少复购用户、哪家门店的客单价降得最多。每次都要找数据团队写 SQL,简单的问题也要排队等。
大模型可以把这类问题翻译成 SQL,但它不知道你们的表名、字段含义和统计口径,容易编出不存在的字段,或者漏掉“已退款订单不计入销售额”这样的条件。生成的语句如果不加检查就执行,还可能修改数据,或者一次扫描整张大表、拖慢数据库。
稳妥的做法是:只把相关表的结构交给模型,生成的 SQL 先过程序校验,再用只读账号在只读副本上执行,限制返回行数和执行时间;结果和 SQL 一起展示给用户,口径对不对一眼就能核对。
推荐模型组合
推荐模型按实时目录自动选取,价格取各模型最低价分组,更新于 2026年11月13日 17:58。点模型名可查看全部分组价格。
找出相关的表(Embeddings)
text-embedding-3-smallOpenAI
输入 ¥0.04 / 输出 ¥0.04 每百万 tokens标准分组
表很多时,没法把全部表结构都放进提示词。给每张表写一段说明(用途、字段含义、常见问法)并向量化,用户提问时只取最相关的几张表交给模型。表只有二三十张时可以省掉这一步,直接把全部表结构写进提示词。
生成 SQL(对话模型)
deepseek-v4.1-flashDeepSeek
输入 ¥2.8 / 输出 ¥11.2 每百万 tokens国产模型分组
根据表结构、字段说明和几条示例问答写出 SQL。这是整个流程里最需要准确的一步,上线前用你们自己的历史问题和核对过的 SQL 评测几个备选模型再定。表结构和示例每次请求都一样,放在提示词开头;模型支持上下文缓存时,这部分按更低的缓存读取价计费。
解读结果与总结报表(对话模型)
qwen3.5-plus通义千问
输入 ¥1.12 / 输出 ¥6.72 每百万 tokens国产模型分组
把查询结果、报表数据或表格的统计摘要写成几句业务结论,比如环比变化、排名和异常值。输入以数字为主、输出短,单价低的模型就够用;需要看图表截图时,换成备选里能识图的模型。
参考架构
- 1
整理表结构说明
为开放查询的表写说明:表的用途、每个字段的含义和单位、枚举值、表之间怎么关联,以及“销售额是否含退款”这类统计口径。说明写得越清楚,生成的 SQL 越准。
- 2
找出相关的表
表多的时候,把每张表的说明向量化入库;用户提问时取最相关的 3 到 5 张表,把它们的建表语句和说明放进提示词。
- 3
生成 SQL
提示词里写明数据库类型(MySQL、PostgreSQL 等)、可用的表结构和几条“问题 → 核对过的 SQL”示例,要求只输出一条查询语句,不加解释。
- 4
程序校验
执行前检查:只能有一条语句,必须以 SELECT 或 WITH 开头,不能含 INSERT、UPDATE、DELETE、DROP 等写操作,只引用允许查询的表,并且带 LIMIT。不合格的把原因交回模型重写一次,仍不合格就请用户换个问法。
- 5
只读执行
用只有查询权限的数据库账号连接只读副本或数据仓库,设置查询超时和返回行数上限。即使校验漏掉了什么,这个账号也改不了数据。
- 6
解读与展示
把查询结果交给模型写成两三句结论,和 SQL、原始数据一起展示给用户。月度报表和上传的表格,先用程序算好合计、同比环比和排名,再让模型写文字说明,数字以程序算出的为准。
成本估算
假设:每月 2 万次提问(约 100 名业务人员,每人每个工作日 10 次);生成 SQL 每次输入约 4,000 tokens(指令和示例约 1,000、相关表结构约 2,500、问题约 500),输出约 300 tokens,约 10% 校验不通过要重写一次;解读结果每次输入约 1,500 tokens(最多 50 行结果);另有 300 份报表和表格汇总,每份输入约 8,000 tokens 的统计摘要。
| 项目 | 模型 | 用量假设 | 费用 |
|---|---|---|---|
| 问题向量化 | text-embedding-3-small | 20,000 次 × 输入 50 tokens | ¥0.04 |
| 生成 SQL | deepseek-v4.1-flash | 20,000 次 × 输入 4,000 + 输出 300 tokens | ¥291.2 |
| 校验不通过重写(约 10%) | deepseek-v4.1-flash | 2,000 次 × 输入 4,500 + 输出 300 tokens | ¥31.92 |
| 解读查询结果 | qwen3.5-plus | 20,000 次 × 输入 1,500 + 输出 250 tokens | ¥67.2 |
| 报表与表格汇总 | qwen3.5-plus | 300 次 × 输入 8,000 + 输出 800 tokens | ¥4.3 |
| 合计(每月) | ¥394.66 | ||
按各模型最低价分组的实时价格计算,价格更新于 2026年11月13日 17:58。
只含模型调用费用,不含数据库、向量库和服务器成本。表结构说明首次向量化是一次性费用,按 300 张表、每张说明约 400 tokens 算,约 12 万 tokens。生成 SQL 的输入里表结构和示例占大头,模型支持上下文缓存时命中部分按缓存读取价计费,实际费用会更低;推理模型的思考过程按输出计费,输出可能多于表中假设。提问量翻倍,费用大致翻倍。
示例代码
模型生成 SQL,程序检查这条语句:只有一条查询、只查允许的表、带 LIMIT,通过后用只读连接执行,再让模型解读结果。示例用 SQLite,换成你们的数据库和只读账号即可。
import os
import re
import sqlite3
from openai import OpenAI
client = OpenAI(base_url="https://www.tutujin.com/v1", api_key=os.environ["TUTUJIN_API_KEY"])
# Only the tables relevant to the question (with many tables, find them by embedding search with text-embedding-3-small).
SCHEMA = """
CREATE TABLE stores (id INTEGER PRIMARY KEY, name TEXT, region TEXT); -- region: east, north, south, west
CREATE TABLE orders (id INTEGER PRIMARY KEY, store_id INTEGER, paid_at TEXT, amount REAL, status TEXT);
-- status: paid or refunded. Sales = sum(amount) of paid orders. paid_at looks like 2026-10-31 18:05:00.
"""
ALLOWED = {"stores", "orders"}
WRITES = re.compile(r"\b(insert|update|delete|drop|alter|create|truncate|attach|pragma|grant)\b", re.I)
def write_sql(question, problem=None):
prompt = "Question: " + question
if problem:
prompt += "\nYour previous query was rejected (" + problem + "). Write it again."
resp = client.chat.completions.create(
model="deepseek-v4.1-flash",
messages=[
{"role": "system", "content": "Write one SQLite SELECT query for the question, using only these tables:\n"
+ SCHEMA + "\nAlways add a LIMIT. Reply with the SQL only."},
{"role": "user", "content": prompt},
],
)
sql = resp.choices[0].message.content.strip()
return re.sub(r"^\x60{3}(?:sql)?\s*|\s*\x60{3}$", "", sql).strip().rstrip(";") # drop a code fence
def check(sql):
"""Why the query is unsafe, or None. A SQL parser is sturdier than regexes; keep the read-only user anyway."""
if ";" in sql:
return "more than one statement"
if not re.match(r"(select|with)\b", sql, re.I):
return "not a SELECT query"
if WRITES.search(sql):
return "contains a write keyword"
ctes = set(re.findall(r"\b(\w+)\s+as\s*\(", sql, re.I))
tables = set(re.findall(r"\b(?:from|join)\s+(\w+)", sql, re.I)) - ctes
if not tables <= ALLOWED:
return "unknown table " + ", ".join(sorted(tables - ALLOWED))
if not re.search(r"\blimit\s+\d+", sql, re.I):
return "no LIMIT"
return None
def ask(question):
sql = write_sql(question)
problem = check(sql)
if problem: # one rewrite, then give up
sql = write_sql(question, problem)
problem = check(sql)
if problem:
raise ValueError("no safe query: " + problem)
# read-only connection; in production, a SELECT-only database user on a replica, with a query timeout
db = sqlite3.connect("file:shop.db?mode=ro", uri=True)
rows = db.execute(sql).fetchmany(50)
db.close()
resp = client.chat.completions.create(
model="qwen3.5-plus",
messages=[
{"role": "system", "content": "Explain the result in two or three sentences for a business reader. Use only the numbers given."},
{"role": "user", "content": f"Question: {question}\nSQL: {sql}\nRows: {rows}"},
],
)
return sql, rows, resp.choices[0].message.content
sql, rows, summary = ask("Which 5 stores in the east region had the highest sales last month?")
print(sql, rows, summary, sep="\n\n")常见问题
智能问数每月要花多少钱?
按每月 2 万次提问、每次给模型约 4,000 tokens 的表结构和示例,再加 300 份报表汇总估算,用最低价分组计算约 ¥395。费用主要取决于提问量和每次放进提示词的表结构有多长。
模型生成的 SQL 能直接执行吗?
不建议。执行前用程序检查:只能是一条查询、只查允许的表、必须带 LIMIT;执行时用只有查询权限的数据库账号,连只读副本或数据仓库,并设置查询超时。这样即使模型写错,也改不了数据,也不会拖垮主库。
查出来的数一定对吗?
不一定。SQL 能执行不代表口径正确,比如漏掉了退款订单、时区或去重条件。建议把 SQL 和结果一起展示给用户;销售额、毛利这类关键指标,用你们定义好的标准 SQL 或指标表,模型只负责把问题对应到这些指标上。
表很多、字段名都是缩写怎么办?
给每张表和每个字段写中文说明,包括单位、枚举值和统计口径;表多时先用向量检索找出相关的几张表,只把它们放进提示词。再把用户问过的典型问题和核对过的 SQL 整理成示例,一起放进提示词。
能分析 Excel 表格吗?
可以,但不要把整张表交给模型去加总和比较。先用程序(例如 pandas)读取表格,算好合计、同比环比和排名,再把这些结果交给模型写成文字说明。大模型做算术容易出错,数字以程序算出的为准。
业务数据会发给模型吗?
生成 SQL 时,请求里只需要表结构和字段说明,不需要真实数据;解读结果时,查询结果会随请求经本站转发给模型服务处理。涉及个人信息或敏感经营数据的,先脱敏或只发送聚合后的数字,并按你们自己的数据合规要求评估。
