拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Text-to-SQL提示工程实战:用TaoToken统一Key跑通PostgreSQL查询生成

1. 为什么 Text-to-SQL 在 PostgreSQL 上总是差一口气Text-to-SQL 这件事听起来像是把一句中文或英文丢给大模型它就能吐出一段能跑的 SQL。但真正在 PostgreSQL 上落地过的人都知道第一次生成的语句往往「看着像那么回事一执行就报错」。问题通常不在模型本身而在提示工程没有把数据库的上下文喂到位。Text-to-SQL 指的是把自然语言问题翻译成可执行 SQL 查询的技术它能让不熟悉 SQL 语法的人直接问数据。适合谁数据分析师、后端开发、做 BI 报表的同学以及想把「问数」能力嵌进自己产品的工程师。PostgreSQL 作为对象关系型数据库有 schema、大小写敏感标识符、类型转换这些细节模型如果不知道表结构就会凭空编字段名。我试过用同一句「找出每个岛上数量最多的企鹅种类」去问不同提示写法结果差别很大只给问题模型返回SELECT species FROM penguins漏了分组和计数给了表结构但没给示例模型把island写成IslandPostgreSQL 直接报column Island does not exist加上 Few-shot 示例和「只输出 SQL」的约束后才稳定返回SELECT species, island, COUNT(*) FROM penguins GROUP BY species, island。这一篇就围绕 PostgreSQL 场景把 Schema 描述、Few-shot 示例、约束解码这几步拆开讲给出可复制的 Prompt 模板并用 TaoToken 的统一 Key 把请求跑通。你会看到对同一个自然语言问题做多轮提示迭代再用执行结果比对来验证生成 SQL 是否正确。核心检索词就是 Text-to-SQL、Prompt Engineering、PostgreSQL全文围绕这三者展开。2. 用 TaoToken 统一 Key 接入 LLM 的前置准备做 Text-to-SQL 提示工程第一步不是写 Prompt而是先把模型调用通道固定下来。因为你要反复迭代提示、对比不同模型输出如果每次换模型都要改一套鉴权和 Base URL迭代成本会很高。TaoToken 在这里的作用是提供统一的 API Key 和兼容 OpenAI 协议的入口让你用同一套代码切换模型。你需要准备三样东西Base URL、API Key、Model ID。这三件套是后面所有配置的基础缺一不可。Base URL 用https://taotoken.net/api注意这个地址不带任何查询参数。API Key 在控制台的 API Keys 页面创建创建后只显示一次复制下来存到环境变量里别硬编码进代码。Model ID 按你的场景选做 Text-to-SQL 这种需要强代码能力的任务选代码能力强的模型如果只是做简单查询翻译通用模型也够用。具体有哪些可选去模型对话页面看当前支持的列表那里会实时更新。环境变量这样设置Linux/macOS 用 exportWindows 用 setexport TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/apiPython 里读取就用os.getenv。这里有个坑很多人把 Base URL 写成带/v1的完整路径结果 SDK 又拼了一次/v1变成/v1/v1/chat/completions直接 404。TaoToken 的 Base URL 就是https://taotoken.net/apiOpenAI SDK 会自动补/v1/chat/completions你不用手动加。如果你用的是 Claude Code 这类工具配置方式不太一样需要走 Anthropic 兼容入口具体看接入文档里的说明。但无论哪种方式Base URL、Key、Model ID 这三件套的逻辑是一样的。把这一步做扎实后面迭代提示时你只需要改 Prompt 字符串不用碰任何网络配置。3. 可复制的 Prompt 模板与 TaoToken 配置片段这一节是全文的核心给出能直接抄的配置和 Prompt。先说配置用 OpenAI Python SDK 指向 TaoTokenimport os from openai import OpenAI client OpenAI( api_keyos.getenv(TAOTOKEN_API_KEY), base_urlhttps://taotoken.net/api, ) MODEL_ID 你的模型ID # 从模型对话页面确认然后是 Prompt 模板。Text-to-SQL 的提示结构分四块语言声明、Schema 描述、Few-shot 示例、输出约束。我把它写成一个可复用的函数def build_prompt(question, schema, examplesNone): lines [] lines.append(-- Language: PostgreSQL) lines.append(f-- Schema: {schema}) if examples: lines.append(-- Examples:) for q, sql in examples: lines.append(f-- Q: {q}) lines.append(f-- A: {sql}) lines.append(-- 只输出一条可直接执行的 PostgreSQL 查询不要解释不要 markdown 代码块。) lines.append(f-- Question: {question}) lines.append(SELECT 1;) return \n.join(lines)Schema 描述不要直接把pg_dump的建表语句全塞进去那样 token 消耗大还容易让模型分心。用精简格式只保留表名、列名、类型schema ( Table penguins, columns [ species text, island text, bill_length_mm double precision, bill_depth_mm double precision, flipper_length_mm bigint, body_mass_g bigint, sex text, year bigint] )Few-shot 示例给一到两个就够多了反而占 token。示例要覆盖你关心的查询模式比如分组聚合examples [ (统计每个岛上的企鹅数量, SELECT island, COUNT(*) FROM penguins GROUP BY island), ]调用的时候把 temperature 设低Text-to-SQL 不需要创造性0 到 0.2 之间比较稳def generate_sql(question, schema, examplesNone): prompt build_prompt(question, schema, examples) resp client.chat.completions.create( modelMODEL_ID, messages[{role: user, content: prompt}], temperature0, ) return resp.choices[0].message.content.strip()这里解释一下为什么 Prompt 最后放一句SELECT 1;。这是从 pg-text-query 项目里学到的技巧给模型一个「续写」的锚点让它倾向于直接输出 SQL 而不是先写一段解释。实测下来加了这句之后模型返回纯 SQL 的概率明显提高省去了从 markdown 代码块里抠 SQL 的麻烦。约束解码这块除了在 Prompt 里写「只输出 SQL」还可以在调用参数上做限制。比如用stop参数在遇到分号加换行时停止避免模型画蛇添足。不过不同模型对 stop 的支持不一样先用 Prompt 约束不够再加参数。4. 多轮迭代与执行结果比对验证Prompt 写好了不代表就完事Text-to-SQL 的准确率是靠迭代磨出来的。这一节演示对同一个问题做多轮提示迭代并用真实执行结果来验证。准备一个测试问题「找出每个岛上数量最多的企鹅种类」。第一轮只给问题和 Schema不给示例q 找出每个岛上数量最多的企鹅种类 sql_v1 generate_sql(q, schema) print(sql_v1)第一轮大概率返回类似SELECT species, island, COUNT(*) FROM penguins GROUP BY species, island的语句。它能跑但语义不对——它返回的是每个岛上每种企鹅的数量不是「数量最多的那一种」。这就是典型的「语法正确、语义偏差」。第二轮在 Prompt 里补充业务语义明确「最多」的含义q2 找出每个岛上数量最多的企鹅种类即对每个 island按 species 分组计数后取计数最大的那一行 sql_v2 generate_sql(q2, schema, examples) print(sql_v2)这一轮模型可能返回带窗口函数的语句SELECT island, species, cnt FROM ( SELECT island, species, COUNT(*) AS cnt, ROW_NUMBER() OVER (PARTITION BY island ORDER BY COUNT(*) DESC) AS rn FROM penguins GROUP BY island, species ) t WHERE rn 1第三轮如果发现模型对窗口函数写法不稳定可以在 Few-shot 里加一个窗口函数的示例把它「教」会。迭代的关键是每次只改一个变量要么改问题描述要么加示例要么调 Schema 粒度别一次全改否则你不知道是哪个改动起了作用。验证环节把生成的 SQL 丢进 PostgreSQL 执行和手写的标准答案比对结果集。用 psycopg2 连接import psycopg2 conn psycopg2.connect( hostlocalhost, dbnametestdb, userpostgres, passwordyourpass ) cur conn.cursor() def run_sql(sql): cur.execute(sql) return cur.fetchall() golden run_sql( SELECT island, species FROM ( SELECT island, species, COUNT(*) AS cnt, ROW_NUMBER() OVER (PARTITION BY island ORDER BY COUNT(*) DESC) AS rn FROM penguins GROUP BY island, species ) t WHERE rn 1 ) generated run_sql(sql_v2) print(一致 if set(generated) set(golden) else 不一致)比对时注意用集合而不是列表因为 SQL 不保证返回顺序。如果结果不一致把两边的结果打印出来看差异再回到 Prompt 里补信息。这个「生成—执行—比对—改 Prompt」的循环就是 Text-to-SQL 提示工程的日常。5. 常见报错排查401、local proxy failed、reading choices迭代过程中会遇到各种报错这一节把高频的几个列出来对照真实错误信息给排查方向。401 Unauthorized。错误信息通常是Error code: 401 - {error: {message: Invalid API key}}。原因就两个Key 没设置对或者 Key 前面多了空格。检查os.getenv(TAOTOKEN_API_KEY)是否返回了值打印出来看首尾有没有空白字符。另外确认你用的是 TaoToken 控制台创建的 Key不是别处的。local proxy failed / connection error。这类错误信息类似APIConnectionError: Connection error或local proxy failed。先确认 Base URL 写的是https://taotoken.net/api没有多余路径。然后检查网络能不能正常访问这个域名用 curl 测一下curl -s -o /dev/null -w %{http_code} https://taotoken.net/api/v1/models \ -H Authorization: Bearer $TAOTOKEN_API_KEY返回 200 说明通道正常返回 000 说明网络层有问题。注意不要用任何非官方的网络工具直接走正常网络即可。reading choices 报错。错误信息类似KeyError: choices或TypeError: NoneType object is not subscriptable出现在resp.choices[0]这一行。这通常是因为返回体结构和你预期的不一样可能是模型 ID 写错了或者请求被拒绝返回了错误对象。先把resp整个打印出来看结构resp client.chat.completions.create(...) print(resp)如果返回的是错误信息而不是正常的 completion 对象里面会有error字段照着改。OAuth / 鉴权相关报错。如果你用的是 Claude Code 或类似工具报 OAuth 错误说明鉴权方式没配对。这类工具需要走 Anthropic 兼容入口配置里要写全 Base URL、Key、Model ID 三件套缺一个都会鉴权失败。具体路径看接入文档别自己猜。模型返回带 markdown 代码块。这不是报错但会让你的 SQL 执行失败因为sql这行不是合法 SQL。解决办法是在 Prompt 里明确「不要 markdown 代码块」或者在代码里做清洗import re def clean_sql(text): text re.sub(rsql\s*, , text) text re.sub(r, , text) return text.strip()排查的核心思路是先看错误信息属于哪一类鉴权、网络、返回结构、内容格式再针对性检查对应的配置项。别一上来就改 Prompt很多问题根本不在 Prompt 层。6. 把 Text-to-SQL 接进你的工作流走到这里你已经有了可复制的 Prompt 模板、统一的 TaoToken 配置、多轮迭代方法和排错清单。接下来就是把它接进实际工作流。如果你只是偶尔验证模型输出用模型对话页面手动试几句最快不用写代码。如果你要长期做编码类任务、把 Text-to-SQL 做成 Agent 的一个工具那 Coding Plan 更合适它按长期使用场景设计成本更可控。接入文档里有完整的参数说明和示例遇到配置问题先翻那里。实际落地时有几个经验值得记一下。Schema 描述要跟着数据库变更走表结构改了 Prompt 里的 schema 字符串也得改否则模型会引用不存在的列。Few-shot 示例要定期更新把线上跑错的 case 补进去当新示例这是提升准确率最直接的办法。生成的 SQL 在执行前一定要过一遍审查尤其是带UPDATE、DELETE的语句别让模型直接改生产数据。Text-to-SQL 不是一次调通就完事的它更像一个需要持续喂养示例和 schema 的系统。把迭代循环跑顺了准确率会随着你积累的示例稳步上升。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门