Qwen 4B 一旦被训练成查询优化智能体它就不再是实验室里的一个权重文件而是一条会持续产生推理账单的服务链路每一次生成 Postgres 查询计划都要把 schema、候选 join 顺序、约束条件打包成 prompt 发出去再把模型吐出的计划 JSON 拿回本地做校验。对推理成本负责人来说这条链路上最先要固定的不是模型超参而是三个东西——Key 从哪来、Base URL 指向哪、每次 plan 的 Token 记在哪。本文用到的全部调用凭据都从 TaoToken 官网获取https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentqwen4b_plan_intro 。这篇文章不讨论训练算法的推导只解决工程侧最容易被忽略的问题off-policy 蒸馏之后的 Qwen 4B 已经能产出可用的 join 顺序但把它接进真实流水线时开发者常卡在「Key 填哪个文件」「Base URL 要不要带 /v1」「Claude Code 和 Codex 的配置能不能互抄」这三类琐事上。把这些填对后面的 Token 账本才有意义填错你会看到 401、404、流式截断而账单照跑。下文给出可复制的配置、一份查询计划示例、一张 Token 消耗记录表以及排查顺序全部步骤都可以在你本机执行。1. 先算账Qwen 4B 生成查询计划成本到底落在哪一段先明确成本结构否则谈「怎么省」是空的。一个查询优化智能体的生命周期里有两类支出性质完全不同。第一类是训练期的轨迹成本。要把一个 4B 模型教成会写查询计划通常需要先用一个更大的模型在同样的 schema 上跑出大量高质量轨迹再让 4B 去模仿并在此之上做智能体式强化学习。这部分是一次性或低频的用的是「轨迹条数 × 单条轨迹 Token」的口径做预算相对简单。第二类是推理期的生成成本也就是本文的重点。每当一条新 SQL 到达系统要么走规则改写要么交给 Qwen 4B 生成计划。后者的单次成本由四块组成schema 上下文表结构、索引定义、行数估算这部分通常占 prompt 的大头且大部分查询之间是重复的候选空间描述join 图、可选的连接顺序、谓词下推位置模型输出计划本身可以用紧凑 JSON 表达但模型若被训练成输出解释文本输出 Token 会翻好几倍重试与回退计划校验失败后的二次生成往往是成本失控的真正来源。公开实验里这类 4B 规模的查询优化智能体在 join 密集的基准上拿到了接近两倍的几何平均加速端到端延迟也有明显下降。但请注意这类结论成立的前提是推理侧足够便宜、足够稳定——如果每次生成都要排队等配额、或者重试率高达 20%加速就会被成本吃掉。所以作为推理成本负责人你要建立的第一条纪律是把 Qwen 4B 的调用集中到一个可计量的入口上而不是到处散落脚本。这个入口就是统一的 Base URL 加上一把可轮换、可统计的 Key。在动手之前先去 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentqwen4b_plan_setup 完成账号与凭据准备后面所有配置都基于这一步产出的 Key。2. 拿 Key 与三个填写位置缺一个都会在半夜报警很多人以为「拿到 Key 就完了」实际上同一个 Key 要填在至少三个地方而这三处的格式并不一样。位置一环境变量服务进程用这是 Qwen 4B 推理服务读取凭据的默认位置。约定两个变量名避免团队内各写各的export TAOTOKEN_BASE_URLhttps://taotoken.net/api export TAOTOKEN_API_KEYYOUR_API_KEY注意 Base URL 不要自己补/v1也不要补结尾斜杠。SDK 会按自身规则拼接具体路径手工补全反而容易出现双斜杠或/v1/v1这类 404。位置二服务配置文件容器与 CI 用如果推理服务跑在容器里环境变量建议从配置中心注入而不是写进镜像。本地开发可以用.env但.env必须进.gitignore。位置三CLI 工具配置Claude Code / Codex 用这一处最容易被漏。你本地用 Claude Code 调试 prompt、用 Codex 改脚本它们各自读不同的配置文件跟你的推理服务毫无关系。第 5、6 节会分别给出两份配置。Key 本身在这里创建与轮换https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentqwen4b_plan_key 。建议一次性创建两把一把给服务、一把给个人调试按用途分开统计月底对账时能立刻看出是谁把预算跑超了。3. 接入查询计划生成服务一份最小可运行的 Python 配置下面这段代码是接入的核心。它做的事情只有三步把 schema 与候选 join 信息送进去、要求模型返回结构化计划、把 usage 落盘。不涉及任何数据库直连SQL 校验由你在本地执行。import csv import json import time from openai import OpenAI client OpenAI( base_urlhttps://taotoken.net/api, api_keyYOUR_API_KEY, ) SYSTEM_PROMPT 你是一个 Postgres 查询计划生成器。 输入会给出表结构、索引、以及需要连接的列。 只输出 JSON格式为 {join_order: [table_a, table_b, ...], access_path: {table_a: index_scan, table_b: seq_scan}, notes: 不超过20字的理由} 不要输出解释段落不要输出 SQL 之外的内容。 def build_user_prompt(schema_ddl: str, join_edges: list, stats: dict) - str: return json.dumps({ schema: schema_ddl, join_edges: join_edges, stats: stats, }, ensure_asciiFalse) def generate_plan(schema_ddl, join_edges, stats, query_id, model你的模型标识): t0 time.time() resp client.chat.completions.create( modelmodel, messages[ {role: system, content: SYSTEM_PROMPT}, {role: user, content: build_user_prompt(schema_ddl, join_edges, stats)}, ], temperature0.2, max_tokens256, response_format{type: json_object}, ) latency time.time() - t0 content resp.choices[0].message.content usage resp.usage record { query_id: query_id, prompt_tokens: getattr(usage, prompt_tokens, 0), completion_tokens: getattr(usage, completion_tokens, 0), total_tokens: getattr(usage, total_tokens, 0), latency_ms: round(latency * 1000), plan_raw: content, } return json.loads(content), record几个工程细节值得单独说response_format要求 JSON 输出能显著降低解析失败导致的重试率。重试是成本杀手一次失败重试等于把这次 plan 的 prompt Token 花了两遍。max_tokens要设。4B 模型偶尔会「话痨」不加限制时输出 Token 可能失控。temperature调低。查询计划的正确性依赖稳定性同一 schema 下抖动的计划会让下游缓存完全失效。query_id必须带。没有它后面那张 Token 账本就无法按查询归因。4. 查询计划示例与 Token 消耗记录把产出物固定下来先给一份可对照的产出示例。假设你在本地有一个只读的测试库副本用EXPLAIN (FORMAT JSON)校验模型给的顺序是否被优化器接受。命令由你本地执行不要指向生产实例。-- 仅在本地只读副本上执行 EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) SELECT o.id, c.name FROM orders o JOIN customers c ON c.id o.customer_id JOIN regions r ON r.id c.region_id WHERE o.created_at DATE 2024-01-01 AND r.code CN;模型返回的计划结构长这样{ join_order: [regions, customers, orders], access_path: { regions: index_scan, customers: index_scan, orders: index_scan }, notes: 先过滤小表regions再走外键索引 }你会注意到模型给的是「顺序 访问路径」不是可直接执行的 SQL。这是刻意设计的让模型只负责它擅长的部分选择性与 join 顺序判断把 SQL 拼装交给确定性代码。这样既降低了输出 Token也避免了模型写出不可控语句。接下来是 Token 账本。这是推理成本负责人最该落地的产出物建议用本地表或 CSV 存CREATE TABLE plan_token_ledger ( query_id TEXT PRIMARY KEY, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), model_tag TEXT NOT NULL, prompt_tokens INTEGER NOT NULL, completion_tokens INTEGER NOT NULL, total_tokens INTEGER NOT NULL, latency_ms INTEGER NOT NULL, plan_hash TEXT, accepted BOOLEAN, retry_count INTEGER DEFAULT 0 );写入逻辑def append_ledger(record, pathplan_token_ledger.csv): with open(path, a, newline, encodingutf-8) as f: w csv.DictWriter(f, fieldnameslist(record.keys())) if f.tell() 0: w.writeheader() w.writerow(record)有了这张表你能回答三个关键问题单次 plan 的平均 Token 是多少prompt 与 completion 的比例是否健康。如果 prompt 占了九成以上说明 schema 上下文没有被复用下一步该做摘要化或缓存。重试率是多少。retry_count 0的比例超过 5%就该回头检查 prompt 约束或输出格式。哪些查询最贵。按total_tokens排序往往能发现少数超宽表 join 吃掉了大部分预算。5. Claude Code 侧settings.json 与 ANTHROPIC_* 的正确填法Claude Code 读的是自己的配置跟你的 Python 服务完全独立。它支持两种配置方式项目级settings.json和环境变量。两者同时存在时环境变量通常优先生效因此调试时若发现改了文件不生效先检查 shell 里有没有残留变量。项目级配置示例{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: 你的模型标识 } }如果你更习惯用 shell 变量export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_AUTH_TOKENYOUR_API_KEY两个易错点不要把ANTHROPIC_BASE_URL写成带/v1的形式。基地址归基地址路径由客户端拼接。ANTHROPIC_AUTH_TOKEN与ANTHROPIC_API_KEY二选一即可同时设置且值不一致时行为取决于客户端版本容易产生「有时通有时不通」的幽灵故障。Claude Code 的完整接入说明与参数含义在这里https://taotoken.net/doc/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_contentqwen4b_plan_ccdoc 。如果你在调 prompt 时希望先在网页里快速验证一轮对话可以用模型对话页做一次冒烟测试https://taotoken.net/models/detail/chat?utm_sourcetaotoken_aicg_blog_endutm_contentqwen4b_plan_chat 。6. Codex 侧config.toml 不能照抄 ANTHROPIC_*这是最常见的一类事故有人把 Claude Code 的环境变量直接复制到 Codex 的配置里结果 Codex 完全不认报「provider not found」。原因很简单Codex 用的是 TOML 配置加自定义 provider 段字段名和读取逻辑都不一样。正确的写法model 你的模型标识 model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chat配套设置export TAOTOKEN_API_KEYYOUR_API_KEY要点env_key写的是变量名不是 Key 本身。把 Key 明文写进config.toml再提交到仓库是另一种常见事故。wire_api按你实际使用的协议填改错会表现为 400 或返回体解析失败。model_provider的值必须与[model_providers.xxx]的段名一致大小写敏感。验证方式很朴素让 Codex 跑一个最小任务观察有没有立刻返回鉴权错误。如果 5 秒内报 401说明 Key 没读到如果报 404八成是base_url被多加了一段路径。7. CC Switch 三件套多供应商切换时最该盯住的三个字段当你同时维护测试环境与生产环境、或者需要在不同模型之间做 A/B手动改配置文件迟早出错。用 CC Switch 这类配置切换工具时请把「三件套」固定下来每次新增条目都检查一遍Base URL统一写https://taotoken.net/api全组一致不允许某一条目「特立独行」地带上路径后缀。鉴权字段Claude Code 用ANTHROPIC_AUTH_TOKENCodex 用env_key指向的环境变量两者不要混用。默认模型标识跟 Base URL 绑在一起存切换条目时模型名也要一起切否则会出现「用 A 环境的地址请求 B 环境的模型」这种必然报错的组合。建议把每个条目命名成「用途-环境」例如plan-prod、plan-bench而不是test1、test2。命名混乱时切错配置的概率远高于你的想象。8. 报错排查顺序从 401 到流式截断按这个次序走拿到报错别乱改配置按下面顺序排查命中率最高。401 / 403凭据问题先确认环境变量在当前 shell 里真的存在env | grep -i taotoken再确认 Key 是否被撤销或过期。多把 Key 并存时最容易出现的是「终端 A 生效、终端 B 没生效」。404路径问题九成是base_url写错。检查两件事有没有多余的/v1结尾有没有多余的斜杠。把base_url改回https://taotoken.net/api再试。400请求体问题常见于response_format与模型能力不匹配、或者max_tokens超限。先去掉response_format跑一次能通就说明是结构化输出参数的问题。429速率问题如果你在做批量计划生成这里是重试逻辑该发挥作用的地方。务必加指数退避并且记录重试次数到 Token 账本否则你看到的成本会显著低于实际。流式输出中途截断多见于max_tokens设得太小或者网络层有代理做了缓冲。先把max_tokens调大验证一次如果是长连接场景检查是否开启了中间层的响应缓冲。计划校验通过率低这不算报错但会直接推高成本。先检查 prompt 里是否给了足够的索引信息再检查输出格式约束是否足够强硬。校验失败时不要让模型「自由发挥重写」而是把失败原因作为附加信息重新请求一次并把retry_count加一。9. 成本治理把每次 plan 的 Token 压下来的六个动作推理成本负责人的价值不在于把单价谈低而在于让同样的问题少花 Token。以下六条按投入产出比排序。第一schema 摘要化。完整的 DDL 里包含大量与本次查询无关的列定义。只保留参与 join 的表、相关列、以及索引名前缀prompt 体积往往能显著下降。第二计划结果缓存。以「schema 指纹 查询模式指纹」为键缓存模型输出同一模式重复出现时直接命中不再调用。注意缓存键必须包含 schema 版本否则会返回过期计划。第三把约束前置到 prompt。与其让模型生成一个违反约束的计划再重试不如在 system prompt 里明确写出「只允许使用已存在的索引」。一次约束的成本远低于一次重试。第四批量提交。如果业务允许把同一批次的多个查询模式合并成一次请求共享 schema 上下文。这能摊薄最大的一块成本。第五设定回退阈值。当模型给出的计划与既有规则计划差异不大时直接用规则计划跳过模型调用。加速收益集中在复杂 join 上简单查询不值得花 Token。第六把 Token 账本接进监控。按天统计total_tokens与retry_count的环比变化。成本异常上涨时先看重试率再看 prompt 平均长度最后才怀疑调用量。10. 复现清单按顺序做完这五步链路就通了把上面的内容收敛成一张可执行清单在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentqwen4b_plan_checklist 完成账号准备然后在控制台创建两把 Key分别用于服务与调试。在服务环境里设置TAOTOKEN_BASE_URLhttps://taotoken.net/api与TAOTOKEN_API_KEYYOUR_API_KEY确保 Key 不进镜像、不进仓库。用第 3 节的 Python 示例跑通一次查询计划生成把 usage 落到第 4 节的plan_token_ledger。用 Claude Code 和 Codex 各做一次冒烟测试确认两边的配置文件与头字段没有互相污染。挑三条历史慢查询在本地只读副本上用EXPLAIN (ANALYZE, BUFFERS)对比规则计划与模型计划把accepted字段补全。做完这五步你手上就有了三样东西一份能复制的 Key 填写位置、一份可对照的查询计划示例、一张按查询归因的 Token 消耗记录。后面再谈模型迭代或加速倍数才有可靠的基线。需要按量还是按套餐可以直接看 Coding Plan 的说明页https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentqwen4b_plan_codingplan 。如果你习惯先小步验证先在模型对话页里跑一轮 prompt确认输出格式符合预期再回到本地配置批量生成https://taotoken.net/models/detail/chat?utm_sourcetaotoken_aicg_blog_endutm_contentqwen4b_plan_chat_cta 。Key 的创建与轮换入口在这里https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentqwen4b_plan_key_cta 。Claude Code 的字段说明与完整示例见https://taotoken.net/doc/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_contentqwen4b_plan_ccdoc_cta 。把这四处配置对齐之后Qwen 4B 每一次生成查询计划消耗的 Token 都会落在你能看到、能归因、能优化的地方。