多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

微信生态最小步骤:TaoToken 给个人小程序补上 Key

微信生态最小步骤:TaoToken 给个人小程序补上 Key 把个人小程序接进微信 AI 生态最小调用链上真正缺的往往只有两样东西一个能长期用的 Key和一个稳定的请求地址。TaoTokenhttps://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentwx_miniapp_intro补的就是这一段官网拿 Key请求地址统一写 https://taotoken.net/api。很多同学第一次做会直接在小程序里wx.request打模型接口然后立刻收到request:fail url not in domain list就算域名加进了白名单把 Key 硬编码进小程序包也会在代码安全扫描环节被拦下来。所以真正可复现的最小步骤不是「在小程序前端调模型」而是「小程序只负责收输入和渲染输出服务端持 Key 转发到网关」。这条链路一旦跑通后面无论是换成流式输出、加内容安全校验还是接进微信 AI 场景都只是在这条链路上加节点而不是重写架构。下面这篇按「最小步骤清单 → 请求模板 → 调试日志 → 开发者工具配置 → 上线前检查」的顺序写每一步都能本地复现不需要改动你现有的小程序页面结构。1. 最小调用链拆解为什么 Key 只能落在服务端先把链路画清楚后面所有报错都能对上号。个人小程序接 AI最小可用链路是四段小程序端收集用户输入文本框、按钮、语音转写结果都行通过wx.cloud.callFunction或wx.request把文本发出去。你的服务端微信云函数、CloudBase、自建 Node 服务、甚至一台轻量服务器都可以它持有 Key。模型网关请求地址填https://taotoken.net/api携带Authorization: Bearer YOUR_API_KEY。回程服务端拿到结果裁剪成小程序需要的最小字段一般只要content和一个可选的usage返回给页面。为什么第 2 段不能省三个原因都是硬约束。第一域名白名单。小程序wx.request只能请求在「开发管理 → 开发设置 → 服务器域名 → request 合法域名」里配置过的 HTTPS 域名且域名需要完成 ICP 备案。你当然可以去配但一旦以后换供应商就要重新走配置流程用云函数callFunction则完全不走这套域名校验改地址只改服务端一行环境变量。第二Key 的暴露面。小程序包是可以被反编译的任何写进app.js或config.js的字符串都等于公开。Key 一旦泄漏被刷的是你的账单不是别人的。服务端持有 Key小程序端连 Key 的影子都看不到这是唯一正确的姿势。第三可观测性。服务端的日志能记录请求时间、模型、耗时、错误码小程序端只能拿到一个笼统的errMsg。排障效率差一个数量级。还有一个容易忽略的点小程序端默认超时和云函数默认超时不一致。wx.request的timeout可以在调用时指定但云函数默认超时通常只有 3 秒需要改成 60 秒云开发在config.json里配timeout: 60否则你会看到一个特别迷惑的现象——本地curl两秒返回小程序里永远「请求失败」。这个坑在「最小步骤」里就必须解决不要留到上线后。2. 最小步骤清单从零到跑通一共 7 步这 7 步就是本文承诺的「最小步骤清单」建议按顺序执行每一步都有明确的验收标准。第 1 步拿 Key。打开 TaoToken 官网https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentwx_miniapp_step1进入控制台的 API Keys 页面创建一把 Key。创建后立刻复制页面刷新后通常不再完整展示。把 Key 记在密码管理器里不要贴在聊天窗口。第 2 步记下请求地址。所有调用统一走https://taotoken.net/api。这个地址是后面所有配置的唯一变量云函数、Node 服务、Claude Code、Codex 都用它只是路径拼接方式略有差别。第 3 步把 Key 放进环境变量而不是代码。微信云开发在「云函数 → 配置 → 环境变量」里加TAOTOKEN_API_KEY值填你自己的 Key自建 Node 服务用.envdotenv。仓库里只留YOUR_API_KEY占位符永远不要提交真实 Key。第 4 步写请求模板。复制第 3 节的代码改两处环境变量名、模型 ID模型 ID 在模型对话页能查到先用一个你确认可用的。第 5 步本地curl验证。这一步不要跳过它能帮你把「Key 无效」「模型名写错」「网络不通」三类问题在小程序之外解决掉。第 6 步小程序端接云函数。页面里用wx.cloud.callFunction调拿到result.content渲染。注意加loading状态和失败提示否则用户点一次没反应会连点。第 7 步加日志并回归。按第 4 节的模板打三条日志再跑一次正常请求 一次故意传错 Key 的请求确认日志能区分两者。验收标准很简单清空本地缓存用真机扫码输入一句话3 秒内出现回答打开云函数日志能看到一条带requestId的成功记录。3. 请求模板Node 云函数里把 Base URL 指向 TaoToken下面这份代码可以直接放进微信云开发的云函数目录也可以放在自建 Node 服务里去掉wx-server-sdk相关两行即可。关键点有三个地址走环境变量、Key 只从环境变量读、返回给小程序前做字段裁剪。{ permissions: { openapi: [] }, timeout: 60 }上面是云函数的config.json重点是timeout改成 60避免长回答被云函数默认超时截断。// cloudfunctions/aiChat/index.js const cloud require(wx-server-sdk) cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) // 请求地址统一走 TaoToken 网关 const BASE_URL process.env.TAOTOKEN_BASE_URL || https://taotoken.net/api const API_KEY process.env.TAOTOKEN_API_KEY || YOUR_API_KEY const MODEL_ID process.env.TAOTOKEN_MODEL || YOUR_MODEL_ID exports.main async (event) { const prompt (event event.prompt ? String(event.prompt) : ).trim() if (!prompt) { return { ok: false, code: EMPTY_PROMPT, msg: 输入为空 } } if (prompt.length 500) { return { ok: false, code: TOO_LONG, msg: 输入过长 } } const startedAt Date.now() // 日志一请求前确认地址与模型 console.log([aiChat][req], { baseUrl: BASE_URL, model: MODEL_ID, keyTail: API_KEY.slice(-4), promptLen: prompt.length }) const controller new AbortController() const timer setTimeout(() controller.abort(), 45000) try { const res await fetch(${BASE_URL}/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${API_KEY} }, body: JSON.stringify({ model: MODEL_ID, messages: [ { role: system, content: 你是小程序内的助手回答控制在 150 字以内。 }, { role: user, content: prompt } ], max_tokens: 512, temperature: 0.6 }), signal: controller.signal }) const requestId res.headers.get(x-request-id) || res.headers.get(request-id) || // 日志二响应后确认状态码与链路 ID console.log([aiChat][res], { status: res.status, requestId, costMs: Date.now() - startedAt }) if (!res.ok) { const text await res.text() return { ok: false, code: UPSTREAM_ res.status, msg: text.slice(0, 300) } } const data await res.json() const content data data.choices data.choices[0] data.choices[0].message ? data.choices[0].message.content : return { ok: true, content, usage: (data data.usage) || null, requestId, costMs: Date.now() - startedAt } } catch (err) { // 日志三异常区分超时与其它错误 const isAbort err err.name AbortError console.error([aiChat][err], { name: err err.name, message: err err.message, isAbort, costMs: Date.now() - startedAt }) return { ok: false, code: isAbort ? TIMEOUT : NETWORK, msg: isAbort ? 模型响应超时请重试 : 网络异常 } } finally { clearTimeout(timer) } }小程序页面里这样调注意只传 prompt不要在前端拼接任何和 Key 有关的东西// pages/chat/chat.js Page({ data: { input: , answer: , loading: false }, onInput(e) { this.setData({ input: e.detail.value }) }, async onAsk() { if (this.data.loading) return const prompt this.data.input.trim() if (!prompt) return this.setData({ loading: true, answer: }) try { const res await wx.cloud.callFunction({ name: aiChat, data: { prompt } }) const r res.result || {} this.setData({ answer: r.ok ? r.content : [${r.code}] ${r.msg || 请求失败} }) } catch (e) { this.setData({ answer: [CLIENT] 调用云函数失败 (e.errMsg || ) }) } finally { this.setData({ loading: false }) } } })如果你不用云开发、坚持自建服务那小程序端换成wx.request同时必须把服务域名加进 request 合法域名并且服务地址必须是 HTTPS。请求模板不变只是把BASE_URL从前端挪到服务端的配置文件里——Key 依然不能出现在小程序里。关于流式输出再补一句小程序不支持EventSource但基础库较高版本支持wx.request的enableChunked: true分块接收。云函数场景下更省事的做法是先做非流式等链路稳定再考虑「云函数聚合 分段返回」或前端直连你的自建 SSE 服务。不要在最小步骤阶段就上流式排障成本会翻倍。4. 调试日志三条日志定位绝大多数问题「最小步骤」的可复现产出里调试日志和步骤清单同样重要。上面模板里埋的三条日志分别对应三个排查维度[aiChat][req]证明请求发出去了baseUrl和model打印出来能一眼看出是不是地址写成了别的域名、模型 ID 有没有配置成功。keyTail只打印后四位用来确认环境变量有没有读进来同时避免泄漏。[aiChat][res]拿到状态码和requestId。requestId是排障时最有用的东西本地curl和线上日志可以用它对齐同一次请求。[aiChat][err]区分超时AbortError和网络异常。超时通常是 max_tokens 给太大、或者模型本身响应慢网络异常则要检查云函数是否绑定了 VPC、出口是否正常。再给一份本地验证用的curl放在服务端跑不进小程序curl -sS -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer YOUR_API_KEY \ -H Content-Type: application/json \ -d { model: YOUR_MODEL_ID, messages: [{role: user, content: 只回复两个字收到}], max_tokens: 32 }常见报错和处置顺序按这个表对照就行现象最可能原因处置request:fail url not in domain list小程序直连了模型域名改成走云函数或把自建服务域名加进 request 合法域名401/invalid api keyKey 没读到、复制时多了空格打印keyTail确认重新创建 Key404路径漏了/v1或模型 ID 不存在核对${BASE_URL}/v1/chat/completions与模型 ID429短时间并发过高服务端加节流与重试退避 1s/2s/4s云函数 3 秒左右失败默认超时太短config.json里把timeout调到 60小程序端一直 loading云函数抛异常但前端没处理前端try/catch 后端统一返回ok/code/msg这里特别提醒重试只对429和5xx做重试401、400重试多少次都一样只会浪费额度。重试次数上限设成 2 次并且加requestId去重日志。5. 开发者工具侧配置Claude Code / Codex / CC Switch 三件套小程序只是接入的一端日常写代码时你大概率还会用到命令行工具。它们和小程序共用同一个请求地址https://taotoken.net/api但配置文件完全不同别混用。Claude Code 改settings.json走 Anthropic 变量{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: YOUR_MODEL_ID, ANTHROPIC_SMALL_FAST_MODEL: YOUR_MODEL_ID } }Codex 改config.toml用 OpenAI 风格配置注意这里不要出现ANTHROPIC_*model YOUR_MODEL_ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api/v1 env_key TAOTOKEN_API_KEY wire_api chat对应地把TAOTOKEN_API_KEY写进 shell 环境变量export TAOTOKEN_API_KEYYOUR_API_KEY如果你用 CC Switch 这类切换工具记住「三件套」要同时改缺一个就会切不干净供应商地址统一填https://taotoken.net/apiOpenAI 兼容路径再接/v1。API Key填你的 Key不要填旧供应商的 Key。模型映射把默认模型和快速模型都指到你确认可用的模型 ID 上。切换完做一次验证命令行发一句话能返回内容说明三件套都生效了如果返回 401多半是第 2 项没改返回 404多半是第 1 项少了或多了路径段。6. 小程序上线前检查清单链路跑通不等于可以上线还有几项在小程序侧必须确认域名与协议自建服务必须是 HTTPS且完成备案用云函数则跳过这一条。超时设置前端wx.request的timeout与云函数timeout要对齐建议前端 45 秒、云函数 60 秒中间留缓冲。内容安全用户输入和模型输出都建议过一遍微信的内容安全接口msgSecCheck尤其是 UGC 类小程序。这一步放在服务端做不要放在前端。降级策略模型侧返回429或超时时给用户一个明确的「稍后重试」提示而不是空白。可以在服务端缓存一段兜底话术。Key 轮换Key 只存在服务端环境变量里换 Key 时只改配置不发版。建议在控制台保留两把 Key一把主力一把备用。日志脱敏日志里不要打印完整 Key 和完整用户输入只留keyTail和长度。把这六条过完你这个个人小程序就算真正接入了微信生态的 AI 能力而且是从「可复现」而不是「碰运气」的角度接进去的。7. 排障顺序与下一步最后给一个固定的排障顺序遇到问题按这个走比到处搜报错快得多服务端curl直接打https://taotoken.net/api/v1/chat/completions先确认 Key 和模型 ID 没问题。云函数里单独调用看[aiChat][req]和[aiChat][res]两条日志。小程序端callFunction看返回结构是不是ok: true。页面渲染检查数据绑定字段对不对最常见的就是把content写成了text。真机回归清缓存再跑一次。整个「最小步骤」到这里就闭环了Key 从官网拿请求地址统一用https://taotoken.net/api服务端持 Key小程序只做展示。剩下的事情——换模型、加流式、做多轮会话——都是在同一条链路上做增量。如果你还没开始建议按这个顺序走一遍先在模型对话页把模型跑通确认它符合你的场景再根据自己的调用量选择 Coding Plan然后回到控制台创建 API Keyhttps://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentwx_miniapp_keys最后打开 Claude Code 文档https://taotoken.net/doc/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_contentwx_miniapp_ccdoc把settings.json按第 5 节改好。三个入口分别是模型对话先试跑https://taotoken.net/models/detail/chat?utm_sourcetaotoken_aicg_blog_endutm_contentwx_miniapp_chat按用量选套餐https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentwx_miniapp_plan创建 API Keyhttps://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentwx_miniapp_keysClaude Code 配置文档https://taotoken.net/doc/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_contentwx_miniapp_ccdoc官网总入口放在这里备查https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentwx_miniapp_endKey 相关的操作都在控制台完成。把第 2 节的 7 步走完把第 4 节的三条日志加上你的个人小程序就已经具备了一条稳定、可观测、可替换模型的 AI 调用链。
返回列表