1. 从聊天窗口到 CLI:Free-Claude-Code 消息平台集成要解决什么
Free-Claude-Code 是一套把 Claude Code CLI 包装成聊天机器人服务的开源方案,它能让你在 Discord 或 Telegram 里直接发消息,由后台拉起 Claude Code 子进程完成编码任务,再把结果流式回传到聊天窗口。适合谁?适合想在手机或团队频道里随手驱动 CLI、又不想每次开终端的人;也适合想研究 Bot 中间件架构的工程师。它最核心的两个能力,一是消息平台适配层,二是树形会话队列。
我先把问题摆清楚。传统 Bot 处理消息是先进先出队列:用户发一条,Bot 处理一条,回复一条。单轮问答没问题,但编码场景天然是多轮、可分支的。你在 Discord 里回复某条历史消息说“改成迭代版本”,在 Telegram 里引用另一条说“用 Java 重写”,这两条诉求指向不同的上下文分支。线性队列会把它们串成一条线,上下文互相污染,最后谁也说不清哪条回复对应哪段代码。
Free-Claude-Code 的解法是把每条对话建模成一棵树。根节点是用户的第一条消息,回复某条消息就在对应节点下挂子节点。每棵树内部维持 FIFO 串行处理,不同树之间并行。再配合fork_session机制,从某个历史节点分叉时复用父会话上下文但创建独立的新会话,分支之间互不影响。
这套设计要跑起来,绕不开一个现实问题:Claude Code CLI 需要可用的 API 通道和 Key。本文用 TaoToken 统一 Key 配置,把config.toml和settings.json的可复制骨架给全,再走一遍 Discord/Telegram Bot 的联调验证,目标是让你从消息平台到会话队列整条链路跑通。下面按“前置配置 → 可复制配置 → 验证 → 排障 → 分流”的顺序展开。
2. TaoToken 前置:统一 Key 与 API 通道准备
在动 Bot 代码之前,先把模型通道打通。Free-Claude-Code 底层调用的是 Claude Code CLI,CLI 读取的是环境变量和配置文件里的 Base URL 与 Key。TaoToken 提供统一的 API 入口,你只需要一个 Key 就能驱动 CLI,不用在多个平台之间来回切换。
第一步,去控制台创建 API Key。打开 https://taotoken.net/console ,登录后在 API Keys 页面新建一个 Key,复制保存。注意 Key 只在创建时完整显示一次,丢了只能重建。
第二步,确认 API 通道地址。TaoToken 的 API 基址是 https://taotoken.net/api ,这个地址要写进 CLI 的配置里,作为 Anthropic 兼容端点。Claude Code CLI 认的是ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY这两个环境变量,或者写进settings.json。
第三步,选模型 ID。TaoToken 支持多种模型,编码场景常用的是 Claude 系列。你可以在模型对话页面先试一下模型是否可用:打开 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite ,发一条测试消息,确认返回正常。这一步很关键,因为后面 Bot 联调如果报 401 或模型不存在,先排除通道问题能省很多时间。
第四步,如果你打算长期跑编码 Agent,建议看一下 Coding Plan,它更适合高频、长时间的 CLI 调用场景: https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。普通按量调用用 API Key 就够,长期跑再考虑套餐。
这里要强调一点:TaoToken 是合规的 API 聚合通道,不是灰色中转。你拿到的 Key 直接用于官方 CLI 的标准接口,配置方式和官方文档一致,只是 Base URL 指向统一入口。这样做的价值在于,一个 Key 管所有模型调用,Bot 侧不用维护多套凭证。
前置准备清单:一个可用的 API Key、确认过的 Base URL、一个测试通过的模型 ID。这三样齐了,再往下写配置。
3. 可复制配置:config.toml 与 settings.json 骨架
这一节给可直接复制的配置。Free-Claude-Code 的配置分两层:一层是 Claude Code CLI 自己的settings.json,管模型通道;一层是项目侧的config.toml,管消息平台和队列行为。两层的路径要和项目实际结构一致,下面按常见布局写。
先看 CLI 侧的settings.json。它通常放在~/.claude/settings.json,或者项目根目录下由 CLI 读取。核心是 Base URL、Key 和模型 ID 三件套:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的TaoToken密钥", "ANTHROPIC_MODEL": "claude-sonnet-4-20250514" }, "permissions": { "allow": [ "Bash(git*)", "Read", "Write", "Edit" ] } }注意ANTHROPIC_BASE_URL后面不要带斜杠,也不要加 UTM 参数,API 调用地址就是干净的https://taotoken.net/api。Key 用你在控制台创建的那串。模型 ID 换成你在模型对话页验证通过的那个。
再看项目侧的config.toml。Free-Claude-Code 用它来配置消息平台、会话队列和限流参数。放在项目根目录:
[messaging] # 平台选择: "discord" / "telegram" / "none" platform = "discord" # Discord 配置 discord_bot_token = "你的Discord Bot Token" discord_allowed_channels = ["112233445566778899", "998877665544332211"] # Telegram 配置(platform = "telegram" 时生效) telegram_bot_token = "你的Telegram Bot Token" telegram_allowed_user_id = "123456789" [queue] # 树形队列:每棵树内部串行,树之间并行 max_concurrent_trees = 4 # 单棵树内待处理节点上限,防止刷屏 max_pending_per_tree = 20 # 节点状态消息的编辑节流窗口(秒) status_edit_throttle_secs = 1.0 [rate_limit] # 全局消息发送限流:窗口内最多 N 条 max_messages_per_window = 1 window_secs = 1.0 # 触发平台限流后的暂停秒数 flood_wait_pause_secs = 30 [cli] # Claude Code CLI 可执行文件路径 claude_bin = "claude" # 工作目录 workspace = "./workspace" # 是否启用 fork_session 分支 enable_fork_session = true [voice] # 语音转写(可选) enabled = false whisper_model = "base" whisper_device = "cpu"如果你用 Telegram,把platform改成"telegram",填telegram_bot_token和telegram_allowed_user_id。Discord 的discord_allowed_channels填允许 Bot 响应的频道 ID,留空表示不限制,但生产环境建议限制。
关于fork_session,它是树形队列的关键开关。开启后,当用户回复某个历史节点时,CLI 会用--resume <session_id> --fork-session启动,复用父会话上下文但生成新的 session_id。这样分支之间不会互相覆盖。配置里enable_fork_session = true就是打开这个行为。
环境变量方式也可以,适合容器部署:
export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_API_KEY="sk-你的TaoToken密钥" export ANTHROPIC_MODEL="claude-sonnet-4-20250514" export MESSAGING_PLATFORM="discord" export DISCORD_BOT_TOKEN="你的Discord Bot Token"配置写完后,先单独验证 CLI 能不能通。在终端跑:
claude -p "用一句话说明快速排序的原理" --output-format stream-json如果返回流式 JSON 且内容正常,说明 Key 和 Base URL 没问题。这一步过了再启动 Bot,否则 Bot 报错你会分不清是通道问题还是平台问题。
4. 验证请求:Discord/Telegram Bot 联调与成功结果
配置就绪后,开始联调。先启动服务,再在聊天平台发消息,观察状态消息的流转。
启动命令,项目推荐用 uv:
uv run python server.py或者直接用 Python:
python server.py启动日志里应该能看到平台连接成功、队列管理器初始化、SessionStore 加载(首次为空)。如果看到Messaging platform: discord和Tree queue manager ready,说明服务起来了。
Discord 侧验证动作。在允许的频道里 @Bot 发一条消息:
@Bot 写一个 Python 函数计算斐波那契数列预期现象:Bot 先回一条状态消息,内容类似“Launching new Claude CLI instance...”,然后状态消息被流式编辑,逐步显示“Processing...”,最后变成“Done”并附上代码块。这条状态消息本身也被注册为树节点,你可以直接回复它继续对话。
接着验证分支。回复 Bot 刚才那条结果消息,发:
改成迭代版本,避免栈溢出预期:Bot 识别这是回复消息,找到父节点,在树里挂子节点,CLI 用--resume复用上下文,返回迭代版代码。再回复最初那条用户消息,发:
再用 Java 实现一遍预期:Bot 从根节点分叉,CLI 用--resume <父session> --fork-session创建新分支,返回 Java 版本。此时树结构是根节点下两个分支,互不干扰。
Telegram 侧验证动作类似。给 Bot 发消息,或者引用某条消息回复。Telegram 的引用回复会带上reply_to_message_id,适配器把它转成IncomingMessage.reply_to_message_id,后续逻辑和 Discord 一致。语音消息如果开启了voice.enabled,发一条语音,Bot 会先回“Transcribing...”,转写完成后进入正常处理流程。
验证成功的标志有三个:状态消息能流式更新、回复历史消息能正确分叉、/stop能中断当前任务。/stop的验证方式是发一条耗时任务,然后立刻发/stop,状态消息应变成“Stopped.”,子进程被终止。
如果你想确认会话 ID 的映射是否正确,可以在日志里找register_real_session_id和fork from parent session这两条记录。前者说明临时 ID 到真实 session_id 的映射建立了,后者说明分叉走了fork_session路径。
联调阶段建议把日志级别调到 debug,能看到队列的入队、出队、节点状态变化。生产环境再调回 info,减少日志量。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
联调时最容易撞的几类报错,这里逐个对照。
401 Unauthorized。现象是 CLI 启动后立刻返回鉴权失败,Bot 状态消息变成错误。原因通常是 Key 不对或 Base URL 写错。检查settings.json里的ANTHROPIC_API_KEY是否是完整的 TaoToken Key,ANTHROPIC_BASE_URL是否是https://taotoken.net/api(不带尾斜杠、不带多余路径)。如果环境变量和配置文件同时存在,环境变量优先级更高,确认没有旧的环境变量覆盖。改完重启服务。
local proxy failed / connection refused。现象是 CLI 连不上 API 端点。先确认网络能访问https://taotoken.net/api,用 curl 测一下:
curl -s -o /dev/null -w "%{http_code}" https://taotoken.net/api如果返回 401 或 404,说明端点可达,问题在鉴权或路径;如果超时,说明网络层有问题。注意不要配置任何非官方的网络转发工具,直接用系统网络访问即可。另外检查settings.json里有没有残留的旧 Base URL 指向别的地址。
reading choices / 解析响应失败。现象是 CLI 收到响应但解析报错,日志里出现reading 'choices'之类的字段访问错误。这通常是模型返回格式和 CLI 预期不一致,或者模型 ID 写错导致返回了错误结构。确认ANTHROPIC_MODEL是 TaoToken 支持的模型 ID,去模型对话页核对。另外检查有没有在配置里混入 OpenAI 格式的参数,Claude Code CLI 用的是 Anthropic 格式,两者不通用。
OAuth 相关报错。现象是 CLI 提示需要登录或 OAuth token 失效。Claude Code CLI 支持 OAuth 登录和 API Key 两种模式。用 TaoToken 统一 Key 时,应该走 API Key 模式,不要触发 OAuth 流程。检查settings.json里是否残留了 OAuth 相关的凭证字段,如果有,清掉,只保留env里的 Base URL 和 Key。如果 CLI 仍然尝试 OAuth,确认启动命令没有带--login之类的参数。
Bot 收不到消息。Discord 侧检查三件事:Bot 是否已加入目标服务器、Developer Portal 里 MESSAGE CONTENT INTENT 是否开启、频道 ID 是否在discord_allowed_channels里。Telegram 侧检查 Bot Token 是否正确、telegram_allowed_user_id是否包含你的用户 ID。
回复消息没有分叉,而是新建了树。检查reply_to_message_id是否被正确传递。Discord 里如果消息的reference为空(比如原消息被删除),适配器拿不到父节点 ID,就会新建树。Telegram 论坛话题里还要确认message_thread_id有没有传。另外确认状态消息是否注册到了树里,register_node没调用的话,回复状态消息也找不到父节点。
/stop 后任务还在跑。检查_process_node里的异常处理有没有吞掉asyncio.CancelledError。取消信号是通过抛CancelledError实现的,如果代码里写了except Exception把取消也捕获了且没重新抛出,取消就会失效。确保取消异常单独处理或重新抛出。
服务重启后会话丢失。这是预期行为的一部分。SessionStore 持久化的是消息树结构和 session_id 映射,但 CLI 子进程在重启时已被终止,PENDING 和 IN_PROGRESS 节点会被标记为 ERROR,提示“Lost during server restart”。历史树结构可以恢复用于展示,但正在跑的任务无法续跑。要恢复上下文,需要重新发消息,CLI 会用--resume加载云端会话。
6. 语义一致 CTA:把链路跑通之后
整条链路跑通的顺序是:TaoToken 拿 Key → 写settings.json和config.toml→ 单独验证 CLI → 启动 Bot → 平台发消息验证 → 回复历史消息验证分叉 →/stop验证中断。每一步都有明确的成功标志,卡在哪一步就查对应章节。
如果你在排障阶段反复撞 401 或连接问题,先去 API Keys 页面确认 Key 状态,再对照接入文档检查配置字段: https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 和 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。文档里有各语言和 CLI 的接入示例,配置字段的命名以文档为准。
如果你只是想先确认模型通道可用,用模型对话页面发一条测试消息最快: https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite 。通道确认后再回来配 Bot,能少走弯路。
如果你打算把 Free-Claude-Code 长期挂在服务器上跑编码 Agent,Coding Plan 更适合高频调用场景: https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。按量调用和套餐的差别主要在成本和配额管理,功能上都是同一套 API 通道。
最后给一个实用技巧:联调阶段把max_concurrent_trees设小一点(比如 2),方便观察队列行为;status_edit_throttle_secs设成 1.0 以上,避免触发平台限流。等链路稳定了再按实际负载调整。树形队列的价值在多人多分支场景才明显,单用户单线程用起来和线性队列差别不大,但一旦有人开始回复历史消息,分支隔离的优势就出来了。