新闻详情

新闻详情

首页 / 资讯中心 / 详情

如何让 LLM 通过反思提升 SQL 正确率:以 Gemini + sqlite 为例,配 TaoToken 统一 Key 跑通 Agent Reflection

发布时间:2026/9/25 14:02:21来源:尧图网络
如何让 LLM 通过反思提升 SQL 正确率:以 Gemini + sqlite 为例,配 TaoToken 统一 Key 跑通 Agent Reflection
1. 为什么 Gemini 写 sqlite SQL 总在“看起来对”的地方翻车你让 Gemini 写一句 sqlite SQL它给你一段语法完全合法、跑起来也不报错的查询但结果就是不对。比如问“NBA 球员体重的中位数是多少”它给你SELECT WT FROM nba_roster WHERE WT ! ORDER BY REPLACE(WT, lbs, ) LIMIT 1 OFFSET (...) / 2执行没报错返回的却是一个带lbs后缀的字符串根本不是数值中位数。这就是 LLM 生成 SQL 最典型的失败模式语法正确、语义错误、静默返回幻觉结果。Agent Reflection智能体反思要解决的就是这件事。它的核心思路特别朴素先让模型出第一版 SQL拿去真库执行把执行结果或报错原样回灌给模型让它自己判断“这版查询有没有回答原问题”然后重写。这跟人写 SQL 的习惯一模一样——先写一版跑一下看结果对不对不对就改。区别在于反思闭环把这个“跑一下、看一眼、改一版”的循环自动化了而且可以重复多轮。这篇面向的是已经在用 Gemini 或类似模型做 Text-to-SQL、但被首轮正确率折磨的开发者。我会用 sqlite 的nba_roster.db做例子把 Agent Reflection 的闭环拆成可复制的代码同时用 TaoToken 统一 Key 管理模型调用避免在多个 API Key 和 base_url 之间来回切换。目标很明确把首轮正确率提升到可观测、可复现的稳定水平而不是靠运气。2. TaoToken 前置统一 Key 与 base_url 的配置骨架在写反思逻辑之前先把模型调用的入口统一掉。我试过在代码里硬编码 Gemini 的 API Key 和 base_url一旦要换模型或加一个备用模型就得改多处。TaoToken 的作用是提供一个统一的 OpenAI 兼容入口你只需要维护一个 Key 和一个 base_url模型名通过参数切换。官网入口在这里https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 注意 API 地址不加 UTM 参数。你需要先去控制台创建一个 API Key然后把它写进环境变量或配置文件。2.1 config.toml 骨架如果你用 Python 项目推荐把配置放在config.toml里用tomllibPython 3.11或tomli读取[llm] base_url https://taotoken.net/api api_key sk-your-taotoken-key model gemini-2.0-flash max_tokens 512 temperature 0.0 [reflection] max_rounds 3 execute_before_reflect truetemperature 0.0很关键。反思场景要的是稳定复现不是创意发散。温度调高会让模型在重写 SQL 时引入不必要的“发挥”反而降低收敛速度。2.2 settings.json 骨架如果你用 Node.js 或需要跨语言共享配置settings.json版本如下{ llm: { baseUrl: https://taotoken.net/api, apiKey: sk-your-taotoken-key, model: gemini-2.0-flash, maxTokens: 512, temperature: 0.0 }, reflection: { maxRounds: 3, executeBeforeReflect: true } }两个配置文件的字段一一对应选你项目顺手的那份即可。Key 不要提交到 Git用.env或本地覆盖文件管理。2.3 读取配置并初始化客户端import tomllib import openai with open(config.toml, rb) as f: cfg tomllib.load(f) client openai.OpenAI( api_keycfg[llm][api_key], base_urlcfg[llm][base_url], ) MODEL cfg[llm][model] MAX_ROUNDS cfg[reflection][max_rounds]到这里模型调用的入口就统一了。后面无论跑首轮生成还是反思重写都走同一个client换模型只改config.toml里的model字段。3. 可复制配置sqlite 建表、schema 注入与首轮 SQL 生成反思闭环要能跑起来前提是有一个真实的 sqlite 库和一份清晰的 schema 描述。schema 描述的质量直接决定首轮 SQL 的准确率这一步不能省。3.1 建表与造数据import sqlite3 conn sqlite3.connect(./nba_roster.db) cur conn.cursor() cur.execute( CREATE TABLE IF NOT EXISTS nba_roster ( Team TEXT, NAME TEXT, Jersey TEXT, POS TEXT, AGE INTEGER, HT TEXT, WT TEXT, COLLEGE TEXT, SALARY TEXT ) ) cur.executemany( INSERT INTO nba_roster VALUES (?,?,?,?,?,?,?,?,?), [ (Toronto Raptors, Otto Porter Jr., 0, PF, 22, 6 7\, 232 lbs, Michigan, $9,945,830), (Boston Celtics, Jayson Tatum, 0, SF, 25, 6 8\, 210 lbs, Duke, $32,600,060), (Denver Nuggets, Nikola Jokic, 15, C, 28, 6 11\, 284 lbs, --, $47,607,350), ], ) conn.commit()注意WT字段是TEXT类型值形如232 lbs这就是后面中位数查询翻车的根源——模型需要先剥离单位再转数值。3.2 schema 描述函数def get_schema(): return 0|Team|TEXT eg. Toronto Raptors 1|NAME|TEXT eg. Otto Porter Jr. 2|Jersey|TEXT eg. 0 and when null has a value NA 3|POS|TEXT eg. PF 4|AGE|INT eg. 22 in years 5|HT|TEXT eg. 6 7 or 6 10 6|WT|TEXT eg. 232 lbs and when null has a value -- 7|COLLEGE|TEXT eg. Michigan and when null has a value -- 8|SALARY|TEXT eg. $9,945,830 and when null has a value -- 把每个字段的类型、示例值、空值表示都写清楚模型生成 SQL 时才有依据。这一步偷懒反思阶段就要花更多轮次去补。3.3 首轮 SQL 生成def make_message(user, system): messages [] if system: messages.append({role: system, content: system}) messages.append({role: user, content: user}) return messages def get_llm_sql(messages): resp client.chat.completions.create( modelMODEL, messagesmessages, max_tokenscfg[llm][max_tokens], temperaturecfg[llm][temperature], ) text resp.choices[0].message.content if sqlite in text: return text.replace(sqlite\n, ).replace(\n, ).strip() if sql in text: return text.replace(sql\n, ).replace(\n, ).strip() return text.strip() question What is the median weight in the NBA? system fYou are an NBA analyst with 15 years of experience writing complex SQL queries. Consider the nba_roster table with the following schema: {get_schema()} Write a sqlite query to answer the following question. Follow instructions exactly. messages make_message(question, system) sql_v1 get_llm_sql(messages) print(首轮 SQL:, sql_v1)首轮输出大概率是类似SELECT WT FROM nba_roster WHERE WT ! ORDER BY REPLACE(WT, lbs, ) LIMIT 1 OFFSET (...) / 2的查询。语法没问题但WT是带单位的字符串排序和取中位数的逻辑都不对。4. 验证请求执行、报错捕获与反思回灌反思闭环的关键动作是“执行 回灌”。执行结果无论是报错还是错误数据都要作为上下文喂回模型。4.1 执行并捕获结果import pandas as pd def execute_sql(sql): try: df pd.read_sql(sql, conconn) return df, None except Exception as e: return None, str(e) df_v1, err_v1 execute_sql(sql_v1) print(首轮执行结果:) print(df_v1 if err_v1 is None else err_v1)首轮执行不报错但返回的是一个带lbs的字符串不是数值中位数。这就是需要反思的信号执行成功不等于答案正确。4.2 构造反思消息并重写def reflect_and_rewrite(question, sql, result, error, system): if error: feedback fQuery: {sql}\nExecution error: {error}\nThis query failed. Write a corrected sqlite query. else: feedback ( fQuestion: {question}\n fQuery: {sql}\n fExecution result: {result.to_string()}\n fThis result does not correctly answer the question. fWrite a corrected sqlite query that returns the numeric median weight. ) messages make_message(feedback, system) return get_llm_sql(messages) sql_v2 reflect_and_rewrite(question, sql_v1, df_v1, err_v1, system) print(反思后 SQL:, sql_v2)反思提示词里要把原问题、上一版 SQL、执行结果或报错三样都带上。模型看到“返回的是字符串不是数值”这个事实才会去写CAST(SUBSTR(WT, 1, INSTR(WT, )) AS INTEGER)这类转换逻辑。4.3 多轮反思循环def run_reflection_loop(question, system, max_rounds3): messages make_message(question, system) sql get_llm_sql(messages) history [] for i in range(max_rounds): df, err execute_sql(sql) history.append({round: i, sql: sql, error: err, rows: None if df is None else len(df)}) if err is None and df is not None and len(df) 0: # 这里可以加一个答案校验函数判断是否真的回答了问题 pass sql reflect_and_rewrite(question, sql, df, err, system) return sql, history final_sql, history run_reflection_loop(question, system, MAX_ROUNDS) print(最终 SQL:, final_sql) df_final, err_final execute_sql(final_sql) print(df_final if err_final is None else err_final)max_rounds建议设 3。实测下来大多数语义错误在 1 到 2 轮反思内就能收敛设太多轮反而可能让模型在“过度修正”里绕圈。5. 本篇常见错排查反思不生效的六个坑反思闭环跑不通通常不是模型能力问题而是工程细节没对齐。下面这几个坑我基本都踩过。坑一schema 描述太粗。只写字段名不写类型和示例值模型不知道WT是带单位的字符串首轮就会写出错误的排序逻辑。把示例值写进 schema首轮正确率能明显提升。坑二反思提示词没带执行结果。只告诉模型“这版不对重写”模型没有判断依据重写出来的 SQL 可能换汤不换药。必须把df.to_string()或报错信息原样带上。坑三temperature 没调低。反思阶段需要稳定收敛温度高于 0.3 会让模型在重写时引入随机变化多轮之间不收敛。设成 0.0。坑四把执行成功当成答案正确。这是最隐蔽的坑。pd.read_sql不报错不代表结果回答了问题。需要在反思提示词里明确写出“结果没有正确回答问题”让模型自己判断语义。坑五max_tokens 太小。反思消息里带了执行结果上下文变长如果max_tokens还是 100模型可能截断输出SQL 不完整。设成 512 以上。坑六base_url 或 Key 配错。如果客户端初始化时base_url写成了别的地址或者 Key 失效首轮请求就会失败反思逻辑根本没机会跑。先用一个最简单的client.chat.completions.create验证连通性再跑完整闭环。排查顺序建议先确认客户端能通再确认 schema 描述完整然后确认反思提示词带了执行结果最后调 temperature 和 max_tokens。6. 语义一致 CTA把统一 Key 接进你的 Agent 工作流反思闭环跑通之后下一步是把它接进你日常的 Agent 工作流。如果你还在手动管理多个模型的 Key 和 base_url建议先把入口统一到 TaoToken再去控制台创建 API Key然后按接入文档把base_url和 Key 写进config.toml或settings.json。需要创建和管理 Keyhttps://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite需要看接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite想先在网页里验证模型对话效果https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite长期跑编码或 Agent 任务考虑 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite如果你用的是 Claude Code 或 Anthropic 风格的调用对应的接入入口在这里https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite把反思循环里的client换成统一入口之后你可以在config.toml里一行切换模型对比 Gemini 和其他模型在同一个 sqlite 任务上的首轮正确率和反思收敛轮数。这才是把“首轮正确率提升到可观测稳定水平”落地的关键——不是靠某一次调参而是靠可复现的配置和可对比的模型入口。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Atlas 300V 24G跑YOLO:推理卡部署与模型转换实战指南 2026/9/25 14:34:21

Atlas 300V 24G跑YOLO:推理卡部署与模型转换实战指南

1. Atlas 300V 24G到底是什么卡,为什么要用它跑YOLO先聊个扎心的事实:很多团队买AI加速卡之前,根本分不清“训练卡”和“推理卡”的区别。网上到处是A100、H100的评测,真到了项目落地要做视频检测、目标识别的时候,才发…

阅读更多 →
Atlas 300V 24G推理卡实战:YOLO模型部署全流程解析 2026/9/25 14:34:21

Atlas 300V 24G推理卡实战:YOLO模型部署全流程解析

最近后台收到好几条关于 Atlas 的消息,问得最多的就是“Atlas 300V 24G 到底是不是运算加速卡”以及“怎么在它上面部署 YOLO”。这两个问题刚好撞在我的实操范围里,因为我在边缘视觉项目里用 Atlas 跑目标检测已经快两年了,从最初连工具链都…

阅读更多 →
大模型Agent技能体系设计:从描述到参数再到输出契约的完整实践 2026/9/25 14:34:21

大模型Agent技能体系设计:从描述到参数再到输出契约的完整实践

1. 整体设计思路:Agent 的“技能”到底该怎么定义1.1 为什么“技能”值得被当作一等公民来设计先聊聊我在实际做 Agent 应用时遇到的一个痛点。最开始我做了一个基于大模型的“通用助手”,把搜索、计算、查天气、记笔记等能力全部堆在系统提示词里&#…

阅读更多 →
惠普光影暗影精灵通电自启与网络唤醒避坑指南 2026/9/25 14:34:14

惠普光影暗影精灵通电自启与网络唤醒避坑指南

1. 惠普光影暗影精灵通电自启与网络唤醒的坑,我替你踩完了惠普光影精灵和暗影精灵这两个系列,在游戏本和台式机圈子里保有量极大,但有个问题几乎每隔一段时间就会被拎出来吐槽一轮:明明在BIOS里把通电自启和网络唤醒都开了&#x…

阅读更多 →
基于Python的简历生成器系统的设计与实现 2026/9/25 14:33:55

基于Python的简历生成器系统的设计与实现

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 一、项目背景与意义 在当今竞争激烈的求职市场中,一份专业、清晰、有针对性的简历是求职者获得面试机会的关键。然而,手动制作和排版简历耗时耗…

阅读更多 →
基于Django的自习室查询与学习社群系统设计与实现 2026/9/25 14:33:42

基于Django的自习室查询与学习社群系统设计与实现

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 1. 项目背景与意义 随着高校扩招与社会终身学习需求的增长,自习室作为重要的学习空间资源日益紧张。传统自习室管理方式存在信息不透明、座位利用率低、学习…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉