尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

39、【Agent】【OpenCode】本地代理分析(body拼接):用 TaoToken 统一 Key 打通分块传输调试链路

发布时间:2026/9/27 11:53:27

资讯中心
01
ARTICLE

39、【Agent】【OpenCode】本地代理分析(body拼接):用 TaoToken 统一 Key 打通分块传输调试链路

39、【Agent】【OpenCode】本地代理分析(body拼接):用 TaoToken 统一 Key 打通分块传输调试链路
1. OpenCode 本地代理为什么总在 body 拼接上翻车如果你正在用 OpenCode 这类 Agent 工具并且想让它走自己的统一 API 通道大概率会碰到一个很具体的场景OpenCode 只认 OpenAI 风格的/v1/chat/completions而你的上游通道需要统一 Key、统一入口。于是你在本地起了一个代理负责把 OpenCode 发来的请求接住、拼完整、再转发出去。问题就出在“拼完整”这一步。OpenCode 发出的 HTTP 请求 body 不一定是带Content-Length的一次性写入很多时候是分块传输chunked。Node.js 的req.on(data)每次只给你一个数据片断如果你直接把每个 chunk 当成完整 JSON 去JSON.parse就会看到类似Unexpected end of JSON input或者Unexpected token的报错。更隐蔽的情况是前几个 chunk 恰好拼成了合法 JSON 的前半段解析不报错但字段缺失转发出去后上游返回 400你回头查日志却看不出哪里断了。这篇就聚焦 OpenCode Agent 本地代理下 body 拼接与分块传输的调试链路用 TaoToken 统一 Key 和 API 通道接入本地代理配置。你会拿到可复制的config.toml骨架、settings.json片段以及分块传输的验证动作和报错排查清单。适合已经在跑 OpenCode、想自己写一层本地代理做请求分析或通道统一的开发者。2. TaoToken 前置统一 Key 与 API 通道准备本地代理要转发就得有一个稳定的上游入口。TaoToken 在这里的角色是提供统一的 API 通道和 Key 管理让 OpenCode 的本地代理只需要认一个 base URL 和一把 Key不用在代理里硬编码多个上游。先拿到 Key。打开控制台创建 API Keyhttps://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite创建后你会得到类似sk-xxxx的字符串。这个 Key 就是本地代理转发时放在Authorization: Bearer里的凭证。注意不要在客户端代码里明文提交放到本地代理的环境变量或配置文件里。TaoToken 的 API 入口是https://taotoken.net/api本地代理的上游 base URL 就填这个路径保持 OpenAI 风格即/v1/chat/completions。这样 OpenCode 发到本地代理的请求代理拼完 body 后原样转发到https://taotoken.net/api/v1/chat/completions认证头换成你刚创建的 Key。如果你还没确认模型通道是否通可以先用模型对话页面做一次最小验证https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite这一步的意义是在写代理之前先确认 Key 和通道本身没问题。否则代理报错时你分不清是拼接逻辑错了还是上游认证失败。3. 可复制配置config.toml 骨架与 settings.json 片段OpenCode 的配置一般分两层一层是 OpenCode 自己的config.toml声明 provider 和 base URL另一层是本地代理的settings.json声明监听端口和上游地址。下面给的是骨架字段名按你实际版本微调。先看 OpenCode 侧的config.toml# ~/.config/opencode/config.toml [provider.local_proxy] name local-proxy base_url http://127.0.0.1:8787/v1 api_key sk-local-placeholder model your-model-name [agent] provider local_proxy这里的关键是base_url指向本地代理的/v1而不是直接指向 TaoToken。OpenCode 会把/v1/chat/completions拼到这个 base_url 后面所以本地代理必须监听这个路径。再看本地代理的settings.json{ listen: { host: 127.0.0.1, port: 8787, path: /v1/chat/completions }, upstream: { base_url: https://taotoken.net/api, path: /v1/chat/completions, api_key_env: TAOTOKEN_API_KEY }, body: { max_bytes: 10485760, join_chunks: true, parse_after_end: true }, log: { level: debug, dump_body: false } }join_chunks和parse_after_end是这篇的核心开关。前者表示把所有data事件拼成一个完整字符串后者表示只在end事件触发后才做JSON.parse。max_bytes是保护阈值防止异常大 body 把内存打满。代理的核心拼接逻辑用 Node.js 写出来大概是这样const http require(http); const server http.createServer((req, res) { if (req.method ! POST || req.url ! /v1/chat/completions) { res.writeHead(404); return res.end(not found); } let body ; let size 0; req.on(data, chunk { size chunk.length; if (size 10 * 1024 * 1024) { req.destroy(); return; } body chunk; }); req.on(end, () { let payload; try { payload JSON.parse(body); } catch (e) { res.writeHead(400, { Content-Type: application/json }); return res.end(JSON.stringify({ error: invalid json body })); } // 转发到 TaoToken forward(payload, res); }); }); server.listen(8787, 127.0.0.1);注意body chunk这一行。它看起来简单但前提是chunk是 Buffer 或字符串Node.js 默认给的是 Buffer会隐式转成字符串。如果 body 里有非 UTF-8 字节隐式转换可能出问题稳妥写法是显式chunk.toString(utf8)或者用数组收集后Buffer.concat。4. 验证请求分块传输下 body 拼接是否成功配置写完后不要直接上 OpenCode 跑先用 curl 模拟分块传输确认代理的拼接逻辑是对的。第一种验证带Content-Length的一次性请求。curl -v http://127.0.0.1:8787/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer sk-local-placeholder \ -d {model:your-model-name,messages:[{role:user,content:ping}]}这种请求 Node.js 可能一次就收到完整 bodydata事件只触发一次。如果代理返回正常说明基础转发链路通了。第二种验证强制分块传输。用Transfer-Encoding: chunked并且手动分两次写curl -v http://127.0.0.1:8787/v1/chat/completions \ -H Content-Type: application/json \ -H Transfer-Encoding: chunked \ -H Authorization: Bearer sk-local-placeholder \ --data-binary - EOF {model:your-model-name,messages:[{role:user,content:ping EOF上面这个写法不完整更可靠的方式是用 Node.js 脚本模拟分块const http require(http); const req http.request({ host: 127.0.0.1, port: 8787, path: /v1/chat/completions, method: POST, headers: { Content-Type: application/json, Transfer-Encoding: chunked } }, res { let data ; res.on(data, c data c); res.on(end, () console.log(status:, res.statusCode, body:, data)); }); req.write({model:your-model-name,); setTimeout(() req.write(messages:[{role:user,content:ping}]}), 200); req.end();这个脚本故意把 JSON 切成两段中间隔 200ms。如果代理的join_chunks生效上游会收到完整 JSON 并正常返回如果代理在第一个 chunk 就解析会直接 400。成功的结果是代理日志里能看到data事件触发两次end事件触发一次JSON.parse成功转发后上游返回 200响应体里有正常的choices字段。5. 本篇常见错排查清单报错一Unexpected end of JSON input原因几乎都是JSON.parse写在了data事件里而不是end事件里。检查你的代码parse必须等所有 chunk 到齐。另一个可能是max_bytes太小body 被截断但这种情况通常会先触发req.destroy()。报错二Unexpected token in JSON at position 0说明 body 开头不是{可能是上游返回了 HTML 错误页或者代理把响应体当成了请求体。检查转发逻辑里Content-Type是否被正确设置以及是否误把上游响应写回了请求解析流程。报错三上游返回 401 或 403本地代理转发时没有带上正确的Authorization头或者 Key 从环境变量读取失败。检查TAOTOKEN_API_KEY是否在启动代理的 shell 里 export 了。可以用printenv TAOTOKEN_API_KEY确认。报错四OpenCode 侧一直转圈代理日志没有请求说明 OpenCode 的base_url没指向本地代理或者端口不对。检查config.toml里的base_url是否是http://127.0.0.1:8787/v1以及代理是否真的在 8787 监听。用curl http://127.0.0.1:8787/v1/chat/completions发个 GET 看是否返回 404说明服务活着。报错五分块传输时 body 拼接后多了换行或空格某些客户端在 chunk 之间会插入\r\n如果你手动处理了 chunk 边界可能把分隔符也拼进去了。Node.js 的data事件已经去掉了 chunked 编码的元数据正常情况下不会有多余字符。如果确实有检查是否在chunk.toString()之后又做了trim()或replace。报错六大 body 导致内存飙升body chunk在超大请求下会频繁创建新字符串。如果 OpenCode 发送的上下文很长建议改成数组收集const chunks []; req.on(data, c chunks.push(c)); req.on(end, () { const body Buffer.concat(chunks).toString(utf8); // parse... });这样内存占用更可控也避免了隐式编码转换的问题。6. 接入文档与后续调试入口本地代理跑通后如果你要把它接到更完整的编码工作流里比如让 OpenCode 长时间跑 Agent 任务建议看一下 Coding Plan 的配置方式它涉及更细的通道和额度管理https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite如果你在接入过程中遇到认证或路径问题接入文档里有完整的 endpoint 说明和示例https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite需要重新生成或管理 Key 时回到 API Keys 页面https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite最后提醒一个实操细节本地代理的日志级别在调试阶段开到debug但dump_body保持false。因为 OpenCode 的请求 body 里可能包含你的代码片段和上下文打到日志里既占空间又有泄露风险。确认拼接逻辑没问题后把日志级别调回info只保留状态码和耗时。这样你的本地代理既能稳定拼接分块 body又不会在长期运行中留下敏感数据。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。