别再手撸 Text-to-SQL 了,用 50 行代码让你的应用学会"说人话"。
回想一下,你是否有过这样的经历:刚把复杂的多表联查调通,产品经理就走过来拍拍你的肩膀:"咱们后台能不能加个搜索框?让运营直接输入'上个月北京仓退货率最高的三个商品',就能出结果?" 你心里一算——分词、实体识别、意图理解、动态拼 SQL、权限隔离……这根本不是加个输入框的事儿,这是一整套数据中台的活儿。
可如果你告诉他:"给我半小时,我用开源项目给你整出来",对方多半会觉得你在吹牛。直到你打开了 Vanna.ai。

Vanna 是什么?
Vanna 是一个开源的 Python 框架,专门解决 用自然语言查询数据库 的问题。它不像市面上那些包装好的 SaaS 工具,而是一套可以嵌入你自己应用里的"AI数据库问答引擎"。你可以把它想象成:给你的数据库雇了一位懂业务、会写 SQL、还知道什么该说什么不该说的智能助手。
最诱人的是它的极简上手体验:
import vanna as vn# 1. 配置模型(支持 OpenAI、通义千问、本地模型等)vn.set_api_key(vn.get_api_key('my-email@example.com')) # 免费注册获取 key
vn.set_model('gpt-4o')# 2. 连接你的数据库vn.connect_to_sqlite('my_database.db')# 3. 喂给它一点"入职培训资料"vn.train(ddl="""
CREATE TABLE orders (id INT PRIMARY KEY,product_name TEXT,status TEXT,amount DECIMAL,city TEXT,created_at DATE
)
""")# 4. 开始用自然语言提问!vn.ask("上个月北京已退款订单的总金额是多少?")
几行代码下去,它真的直接返回了查询结果——一个干净的 Pandas DataFrame,甚至还附带了它生成的 SQL 语句。那一刻的冲击感,不亚于第一次看到 GitHub Copilot 自动补全一整个函数。
不止于"拼接 Prompt"——它的脑子是怎么转的?
如果你以为 Vanna 只是简单地把整个数据库 Schema 扔给 GPT 去写 SQL,那就低估它了。那种"全量 Schema 直塞"的方式有几个致命伤:
-
Token 消耗巨大:几十张表的数百个字段,光 Prompt 就吃掉几万 token;
-
准确度随表数量断崖式下跌:LLM 面对庞大的无关结构,极容易把字段张冠李戴;
-
隐私和安全堪忧:把完整库结构发给第三方 API?合规部门会找你喝茶。
Vanna 的核心,是一套轻量但精巧的 RAG(检索增强生成)架构。它会把你的"培训资料"向量化,存到向量数据库里。当用户提问时,流程是这样的:
-
语义检索:把用户问题在向量空间中搜索,找到最相关的表结构片段、业务文档、以及历史 SQL 范例。
-
动态组装 Prompt:仅将检索到的"相关上下文"拼入提示词,而不是全库 Schema。
-
LLM 生成 SQL:模型基于少量精准的信息写出 SQL,再由 Vanna 安全执行并返回结果。
这个过程,就像是你给新来的分析师扔过去一堆部门资料,他接到问题后先快速翻阅最相关的几页,再动笔写查询,而不是每次都把整本《公司百科全书》读一遍——既快又准,还不容易泄密。
知识延伸:这里的"向量化"可以简单理解为,把一段文本的语义压缩成一串数字坐标。语义越相近的文本,它们在向量空间里的距离就越近。"退货"的问题天然就能拉取到 status='returned' 的字段注释,哪怕字面上毫无重叠。这就是 RAG 的魔法。
手把手"培训"你的 AI 分析师
Vanna 的 train() 方法支持三种层次的"教材",由骨架到血肉,越丰富效果越稳定。
1. DDL 骨架 — 让模型认识你的表
这是最小启动单元。直接把建表语句丢进去,模型就有了基本的列名和类型认知:
vn.train(ddl="""
CREATE TABLE employees (id INTEGER PRIMARY KEY,name TEXT,department TEXT,salary REAL,hire_date DATE
)
""")
2. 业务文档 — 注入领域黑话
数据库里可能用 order_status = 3 来表示"退货",但运营永远只会说"退货订单"。这时候需要把业务含义"翻译"给模型听:
vn.train(documentation="""- 退货订单:指的是 order_status 字段值为 3 的记录。
- 活跃用户:过去 30 天内至少有一笔支付成功订单的用户。
- 客单价:已支付订单总金额除以已支付订单数。""")
当用户提问"上周活跃用户的平均客单价是多少",Vanna 会在向量库中搜出这三行文档,连同相关表的 DDL 一起喂给 LLM。模型秒懂业务黑话,准确率飙升。
3. SQL 示例 — 手把手教套路
这是典型的少样本学习。把常见问题和对应的标准 SQL 作为范例交给它:
vn.train(question="北京仓上个月的退货总金额", sql="""
SELECT SUM(amount)
FROM orders
WHERE warehouse='北京' AND status=3 AND created_at BETWEEN '2026-06-01' AND '2026-06-30'
""")
有了这些范例,模型不仅能模仿你的 SQL 风格,还能掌握表之间的关联关系和特殊过滤逻辑。基本上,你喂的每一条范例,都是在给 AI 注入一段"肌肉记忆"。
融入你的技术栈:自定义模型与向量库
Vanna 最大的魅力在于 透明且可控。你完全不必被绑定在某个特定模型上。得益于它的可插拔设计,你可以自由更换 LLM 和向量存储。
换成国产大模型(如通义千问)
很多团队对数据出境有严格限制。Vanna 官方文档提供了清晰的适配指南。你可以轻松切换到任何兼容 OpenAI 接口的模型服务:
from vanna.openai import OpenAI_Chat
from openai import OpenAIclient = OpenAI(api_key="your-qwen-api-key",base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)class Qwen(OpenAI_Chat):def __init__(self, config=None):OpenAI_Chat.__init__(self, client=client, config=config)vn = Qwen()
同理,你也可以把它接到 Ollama 上,用本地的 Llama 3 或 DeepSeek 模型,实现完全离线的自然语言查询。
定制向量数据库
默认用 ChromaDB 可以快速跑通,但如果你需要持久化或企业级性能,可以切到 pgvector、Qdrant 等。
from vanna.chromadb import ChromaDB_VectorStoreclass MyVanna(ChromaDB_VectorStore, Qwen):def __init__(self, config=None):ChromaDB_VectorStore.__init__(self, config=config)Qwen.__init__(self, config=config)vn = MyVanna()
这种 Mixin 式的组装,是 Vanna 架构最精彩的地方:把 LLM 能力和向量检索能力解耦,你可以像拼乐高一样搭建自己专属的 Text-to-SQL 引擎。
从脚本到应用:给 Web 加个安全的问答接口
真正要交付给业务方使用时,我们还需要一个 Web 接口,并加上安全认证。这正是 Vanna 中文文档里 web-app-auth 示例所着重强调的。
下面是一个用 Flask 搭建的最小安全接口思路(简化版):
from flask import Flask, request, jsonify
import vanna as vnapp = Flask(__name__)
vn.set_api_key('your-api-key')
vn.connect_to_sqlite('prod.db')
vn.train(...) # 已训练# 简单的 token 认证装饰器
def require_auth(f):def decorated(*args, **kwargs):token = request.headers.get('Authorization')if token != 'Bearer my-secret-token':return jsonify({"error": "Unauthorized"}), 401return f(*args, **kwargs)return decorated@app.route('/ask', methods=['POST'])
@require_auth
def ask():question = request.json.get('question')# allow_llm_to_see_data=False 可以先只生成SQL,由你审核后再执行sql = vn.generate_sql(question)# 在这里可以加入权限校验:如表白名单、Limit 强制添加等if not sql.lower().startswith('select'):return jsonify({"error": "Only SELECT allowed"}), 403df = vn.run_sql(sql)return jsonify({"sql": sql, "data": df.to_dict()})
几个关键的安全实践:
-
只给数据库只读账户:Vanna 连接的数据库账号永远不要给
DROP、DELETE权限。 -
SQL 白名单校验:在
run_sql前用正则确保只执行SELECT语句,并强制加上LIMIT 1000。 -
按用户注入行级过滤:在生成 SQL 后,自动拼接
WHERE tenant_id = '当前用户所属租户',实现数据隔离。
这些手段,在 Vanna 的文档中都有详尽的最佳实践,确保你能把 AI 的能力安全地封装成产品功能,而不是制造一个 SQL 注入的后门。
凭什么不自己从零撸?
你可能会说:"我用 LangChain 的 SQL Agent,或者直接拼 Prompt 调 GPT-4o,也能跑起来呀。" 确实,但 LangChain 的 Agent 更加通用且重,面向 SQL 场景时往往需要你写大量脚手架代码去管理 Schema 上下文、历史缓存、连接池等。而 Vanna 专注一件事:成为连接数据库和 LLM 最高效的那根管道。它用简短的代码量,提供了开箱即用的训练机制、向量记忆和结果缓存,让你能把精力放在理解业务问题本身。
写在最后
Vanna 正在让"自然语言查数据"从一个需要整个团队啃半年的项目,变成一名后端工程师一个下午就能集成完的特性。它把最复杂的语义理解、SQL 生成、上下文检索打包成了一个优雅的 Python 库,同时又把模型和存储的掌控权完整地交到了你手上。
下次产品经理再拍出那个"搜索框"需求时,你可以云淡风轻地回一句:"好啊,下班前给你 demo。"
延伸阅读与资源
Milvus向量数据库实战修炼:从 0 到 1精通向量检索与生产落地
后端工程师的 AI 转型第一课:Ollama 与私有化大模型实战
10倍开发者的 Dify 魔法书:从零构建全栈 AI 应用
后端工程师转型AI第一课-Ollama 与私有化大模型实战
大型语言模型(LLM) vLLM 高性能推理落地实战
Agent开发之LlamaIndex 实战修炼与源码进阶
大语言模型Transformers 实战修炼与源码剖析

微信公众号: 架构师日常笔记 欢迎关注!
