ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

多客户端共享 App Server,TaoToken 只在服务端注入

多客户端共享 App Server,TaoToken 只在服务端注入 1. 多客户端共享 App Server 的 Token 注入点当 TUI、IDE、Web 和 SDK 同时连一个 Codex App Server 时thread/resume报404、turn/start报401很常见。根因通常是每个客户端各持一份 Key。TaoToken 只在服务端注入先到官网https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentcsdn_ugc_app_server_intro领取 KeyApp Server 统一用https://taotoken.net/api发请求。客户端只发协议操作、订阅事件不再各自配置模型凭证。这个改动的价值不只是安全。Codex App Server 把任务拆成 Thread、Turn、Item 三层Thread 管长期任务Turn 表示一次推进Item 则是推理、命令、补丁、工具调用和审批这些可订阅的小块。多客户端共享同一个 App Server 时任何一端发起的turn/start都应该落到同一个 Thread ID 上Token 消耗由服务端统一调度才能按 Thread 和 Turn 归因。本文用一个本地可复现的路径把 TUI、IDE、Web/SDK 接到同一个 App Server观察事件流、状态同步和消耗。准备清单已安装 Codex CLI并能运行codex app-server。已从 TaoToken 官网领取 API Key记为YOUR_API_KEY。本地开放一个端口例如127.0.0.1:8787。三个客户端终端 TUI、一个 IDE 插件、一个用 HTTP 直连的脚本。先不要在每个客户端里填 Key。只要 App Server 进程能读到TAOTOKEN_API_KEY所有下游客户端都会复用同一条模型入口。2. 在 Codex config.toml 里把模型入口切到 TaoToken Base URLCodex 的供应商配置在~/.codex/config.toml。这里只写 Codex 自己的字段不要把 Claude Code 的ANTHROPIC_*混进来。一个可用的配置如下# ~/.codex/config.toml model gpt-5.6-sol model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chat这里的base_url不加任何查询参数保持https://taotoken.net/api。Key 通过环境变量注入避免写入仓库export TAOTOKEN_API_KEYYOUR_API_KEY如果你使用 CC Switch 管理多个供应商可以在 CC Switch 里维护“三件套”ProviderTaoTokenBase URL 为https://taotoken.net/api。API KeyYOUR_API_KEY。ModelCodex 侧填gpt-5.6-solClaude Code 侧另配claude-sonnet-4-5。CC Switch 只负责把这三项切换成当前终端环境不替代 App Server 的注入点。启动 App Server 前确认环境变量已经生效echo $TAOTOKEN_API_KEY codex app-server --listen 127.0.0.1:8787如果这里输出为空后面所有客户端都会收到 401。如果你还没有 Key可以从 TaoToken 官网https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentcsdn_ugc_app_server_config领取当前先把服务端跑通。3. 三个客户端同时连 App ServerTUI、IDE、Web/SDK 的事件流对照先起 TUI 客户端。不同版本的 Codex CLI 参数可能略有差异核心是让 TUI 指向已经运行的 App Servercodex --remote http://127.0.0.1:8787然后在 TUI 里创建一个新任务记下返回的 Thread ID。通常可以调用codex rpc thread/start --params {model:gpt-5.6-sol}返回示例{ thread_id: th_01J8Z9W3KQ, status: active }接着让 IDE 插件连接同一个地址。多数 Codex IDE 插件会在设置里提供App Server URL或Remote Runtime填http://127.0.0.1:8787不要填模型 API 地址。IDE 插件只负责展示和提交 Turn模型请求由 App Server 转发。再用一个最小 Web/SDK 脚本连接。下面用 Python 的 requests 模拟 JSON-RPCimport json import requests BASE http://127.0.0.1:8787 THREAD_ID th_01J8Z9W3KQ def rpc(method, paramsNone): payload {method: method, params: params or {}} r requests.post(BASE /rpc, jsonpayload, timeout30) r.raise_for_status() return r.json() # 复用 TUI 创建的 Thread print(rpc(thread/resume, {thread_id: THREAD_ID})) # 从 Web 客户端发起一次 Turn print(rpc(turn/start, { thread_id: THREAD_ID, input: [{type: text, text: 统计当前仓库里的 TODO 数量并给出文件列表}] }))在三个客户端都连上之后观察同一份事件流。可以用 SSE 或长轮询订阅curl -N http://127.0.0.1:8787/events你会看到类似下面的结构化事件{type:item/started,thread_id:th_01J8Z9W3KQ,turn_id:turn_01J8Z9W4AA,item:{type:reasoning,id:itm_1}} {type:item/completed,thread_id:th_01J8Z9W3KQ,turn_id:turn_01J8Z9W4AA,item:{type:reasoning,id:itm_1}} {type:item/started,thread_id:th_01J8Z9W3KQ,turn_id:turn_01J8Z9W4AA,item:{type:command,id:itm_2,command:rg -n TODO .}} {type:item/completed,thread_id:th_01J8Z9W3KQ,turn_id:turn_01J8Z9W4AA,item:{type:command,id:itm_2,exit_code:0}} {type:turn/completed,thread_id:th_01J8Z9W3KQ,turn_id:turn_01J8Z9W4AA,usage:{input_tokens:1840,output_tokens:260}}关键点有三个所有事件都带同一个thread_id说明多客户端面对的是同一套任务状态。turn_id标识这次推进Token 消耗挂在 Turn 上而不是散落在客户端。item/started与item/completed把推理、命令、文件修改、审批拆成小块方便审计。如果客户端各自配置 Key你会看到同一个 Thread 出现多个不同的鉴权主体或者 IDE 侧因为拿不到历史而重新thread/start最终形成两条互不相关的任务链。服务端注入后App Server 是唯一的模型请求出口Thread Manager 只维护一份活跃 Thread 表。4. Thread 状态同步Thread Manager、TurnContext 与多客户端恢复多客户端共享 App Server 时Thread 状态同步不是“把聊天记录广播出去”这么简单。Codex 内部有三层状态Thread长期任务容器可以 Start、Resume、Fork、Interrupt。Turn一次用户推动可以turn/start也可以在运行中turn/steer。Item可观察单元包括模型消息、推理、命令、文件补丁、工具调用和审批。App Server 对外暴露thread/start、thread/resume、thread/fork、turn/start等协议操作。真正把协议请求接到运行实例的是 Thread Manager。它维护一张以 Thread ID 为索引的活跃表找到正在跑的实例就继续投递 Turn如果实例已经离开内存才从 Thread Store 或 Rollout 装回历史重建一个可运行对象。这套机制决定了多客户端的正确用法客户端 A 创建 Thread 后客户端 B 应该用thread/resume接入而不是重新thread/start。运行中的 Turn 被客户端 B 用turn/steer追加指令时Thread Manager 会把操作送到同一个运行实例。如果客户端 C 想从某个历史快照开分支使用thread/fork而不是复制聊天文本。为了让状态同步可验证可以写一个轮询脚本从任意客户端查询 Thread 状态import requests, time BASE http://127.0.0.1:8787 THREAD_ID th_01J8Z9W3KQ def rpc(method, paramsNone): r requests.post(BASE /rpc, json{method: method, params: params or {}}, timeout30) r.raise_for_status() return r.json() for i in range(10): status rpc(thread/get, {thread_id: THREAD_ID}) print(time.strftime(%H:%M:%S), status.get(status), status.get(active_turn_id)) time.sleep(2)如果 TUI、IDE、Web 看到的active_turn_id一致说明状态同步成功。如果某个客户端看到的 Thread 已经结束而另一个客户端仍在发 Turn通常是连到了不同的 App Server 端口或者 Thread 被错误地 fork 成两条链。TaoToken 在这里的角色不是替代 Thread Manager而是让服务端只有一个模型出口。App Server 在每次模型采样时使用https://taotoken.net/api和YOUR_API_KEYThread、Turn 和 Item 的语义不变但 Token 消耗可以按 Thread 与 Turn 统一归因。5. Token 消耗观察一次 Turn 在服务端如何被归因多客户端最容易踩的坑是“消耗看得到但不知道是谁花的”。TUI 自己配了 KeyIDE 又配了另一个 KeyWeb 脚本用了第三个 Key最后在控制台只看到三条互不相关的用量曲线。把 Token 注入点收到 App Server 后所有客户端共享同一条模型入口一次 Turn 只对应一次服务端请求链。观察 Token 消耗可以分两层第一层是 App Server 事件流。turn/completed事件里通常会带usage例如{ type: turn/completed, thread_id: th_01J8Z9W3KQ, turn_id: turn_01J8Z9W4AA, usage: { input_tokens: 1840, output_tokens: 260, total_tokens: 2100 } }第二层是 TaoToken 控制台。到 TaoToken 官网https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentcsdn_ugc_app_server_usage的 API Keys 页面查看 Key 的调用量与余额变化https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentcsdn_ugc_app_server_keys如果你在多客户端测试时发现turn/completed的 usage 与 TaoToken 控制台不一致优先检查两件事App Server 是否只配置了一个TAOTOKEN_API_KEY客户端是否残留了旧的模型配置。是否有客户端绕过 App Server直接向其他 Base URL 发请求。为了更细地归因可以在本地记录每次 Turn 的元数据import json LOG turn_usage.jsonl def record(event): if event.get(type) turn/completed: row { thread_id: event[thread_id], turn_id: event[turn_id], usage: event.get(usage, {}), client: event.get(client, unknown) } with open(LOG, a, encodingutf-8) as f: f.write(json.dumps(row, ensure_asciiFalse) \n)这段脚本只读取 App Server 的事件流把 Turn 级别的消耗写入本地 JSONL方便和 TaoToken 控制台对照。命令和 SQL 都应由读者在本地环境执行不要把它接到生产库或外部业务系统。6. 排障401、404、Thread 丢失与 CC Switch 三件套多客户端共享 App Server 的报错通常集中在这几类401 Unauthorized检查TAOTOKEN_API_KEY是否在启动 App Server 的 shell 里。检查config.toml里的env_key是否写成TAOTOKEN_API_KEY而不是 Claude Code 的ANTHROPIC_*。检查客户端是否携带了旧的 Authorization Header覆盖了 App Server 的服务端注入。404 Thread not found确认所有客户端连的是同一个 App Server 地址和端口。确认客户端 B 用的是thread/resume不是thread/start。如果 Thread 已被结束并从活跃表移除用thread/resume从 Thread Store 或 Rollout 恢复。Turn 消耗分散在 App Server 进程环境里只保留一个TAOTOKEN_API_KEY。清理客户端本地的模型供应商配置让它们只提交协议操作。用 CC Switch 三件套统一维护 Provider、Key、Model启动 App Server 前切换一次而不是每个客户端各切一次。CC Switch 三件套可以理解为一张切换卡片{ provider: { name: taotoken, base_url: https://taotoken.net/api }, auth: { env_key: TAOTOKEN_API_KEY, value: YOUR_API_KEY }, models: { codex: gpt-5.6-sol, claude_code: claude-sonnet-4-5 } }这份配置只用于本地环境切换不替代 App Server 的 Thread 管理。它的目标是让“服务端注入”这件事有一个明确的来源。7. Claude Code 侧ANTHROPIC_* 只服务 Claude Code不混入 Codex如果你同时在用 Claude Code它的配置方式与 Codex 不同。Claude Code 在settings.json里使用ANTHROPIC_*{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: claude-sonnet-4-5 } }这段配置只给 Claude Code 使用不要写进 Codex 的config.toml。Codex 侧仍然使用前面的model_providers.taotoken和TAOTOKEN_API_KEY。两边可以共享同一个 TaoToken Key但变量名和配置文件必须分开否则很容易出现“Codex 读到了 ANTHROPIC_*但模型入口不匹配”的排障噪音。Claude Code 的接入手册在这里https://taotoken.net/doc/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_contentcsdn_ugc_app_server_doc8. 多客户端共享 App Server 的验证清单把上面的步骤收敛成一份可复现清单从 TaoToken 官网https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentcsdn_ugc_app_server_checklist领取 Key记为YOUR_API_KEY。在~/.codex/config.toml中把base_url设为https://taotoken.net/apienv_key设为TAOTOKEN_API_KEY。在启动 App Server 的 shell 里导出TAOTOKEN_API_KEY不要导出到客户端进程。启动codex app-server --listen 127.0.0.1:8787。用 TUI 创建 Thread记下thread_id。用 IDE 插件和 Web/SDK 脚本分别thread/resume同一个thread_id。从任意客户端发起turn/start订阅/events确认三个客户端看到相同的turn_id与 Item 序列。在turn/completed中读取 usage并与 TaoToken 控制台的 Key 用量对照。如果出现 401/404按第 6 节的顺序排查不要先怀疑模型。这套路径带来的产出很具体多客户端事件流可对照、Thread 状态同步可验证、Token 消耗按 Turn 归因。TaoToken 只在服务端注入客户端不再持有模型凭证App Server 成为唯一的模型请求出口。9. 下一步模型对话、Coding Plan、API Key 与 Claude Code 文档如果你还没拿到 Key按下面顺序走一遍先在模型对话里验证 Base URL 与 Key 是否可用 https://taotoken.net/models/detail/chat?utm_sourcetaotoken_aicg_blog_endutm_contentcsdn_ugc_app_server_chat需要长期跑多客户端、多 Turn 的 Coding Agent查看 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcsdn_ugc_app_server_plan到控制台创建和管理 API Key https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentcsdn_ugc_app_server_keysClaude Code 的settings.json/ANTHROPIC_*配置参考 https://taotoken.net/doc/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_contentcsdn_ugc_app_server_doc回到多客户端 App Server 这件事客户端可以换界面可以增但 Token 注入点不要跟着客户端走。把https://taotoken.net/api和YOUR_API_KEY固定在服务端Thread 与 Turn 的状态才有一致的归因口径。模型决定下一步做什么App Server 决定这一步在哪个 Thread、哪个 Turn、哪份上下文里发生而 TaoToken 负责让这一步的模型调用从服务端统一出去。
返回列表