
Windows 上把 OpenClaw 拉起来飞书那边发消息没回日志却停在 qwen_client.py 调 Qwen 千问 401。这多半不是飞书机器人坏了也不是 gateway.py 的 /feishu/webhook 写错而是第二步 QwenClient 的 base_url 还指着 dashscope 的 text-generation 地址requests 又多带了一层 /v1。把这条链路改到 TaoToken 统一接入先去 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建 YOUR_API_KEY再把 qwen_client.py 的 Base URL 填成 https://taotoken.net/api模型保留 qwen-turbo让 QwenClient 先单独跑通最后回到 gateway.py 的 /feishu/webhook 验证飞书消息。下面按排障顺序拆。1. OpenClaw 飞书链路断在 qwen_client.py 的 4011.1 先确认报错发生在 Qwen API 调用之前飞书发消息之后OpenClaw 这边如果还能看到POST /feishu/webhook的访问日志说明飞书事件已经推到了 gateway.py消息解析也没把程序直接打崩。真正的断点出现在 QwenClient 发起模型请求那一步日志里常见的是401 Unauthorized、Invalid API key或者干脆在抛异常前卡一下网络超时。这个顺序很重要如果连/feishu/webhook都没收到先去查飞书开放平台的事件订阅和回调地址如果收到了但 QwenClient 报 401就不要再反复重启飞书机器人问题在模型通道的 Key 或 Base URL 上。原文第二步把self.base_url写成 dashscope 的 text-generation 地址并在 headers 里用Authorization: Bearer api_key。照着 2.1 去阿里云百炼申请 Key 之后很多人会把 Key 复制到环境变量再把地址原样粘进qwen_client.py。这样做本身不算错但 dashscope 原生接口和 OpenAI 兼容接口的路径写法并不一样手工拼 URL 时特别容易多一个/v1或者把/chat/completions拼到 text-generation 后面。飞书链路会直接断在 Qwen API 调用前表现就是机器人不回复、日志里只有 401 或 404。1.2 dashscope 的 text-generation 地址和 /v1 为什么会撞车dashscope 的 text-generation 地址在浏览器里打开是一回事放到 requests 里拼路径是另一回事。有的文档写/api/v1/services/aigc/text-generation/generation有的 OpenAI 兼容示例又要求 base_url 以/v1结尾然后再由 SDK 补/chat/completions。当你把地址抄进qwen_client.py的self.base_url再在请求时手动拼路径最终的 URL 可能变成https://某地址/v1/chat/completions也可能变成https://某地址/api/v1/chat/completions。服务端收到的路径和它认识的路径对不上就会返回 404如果 Key 的鉴权方式也不匹配就会直接 401。当前这篇排障的核心不是研究 dashscope 每一层路径而是先把变量锁死。TaoToken 在这里作为统一模型通道出现Base URL 只填https://taotoken.net/api末尾不带/v1也不带任何查询参数。请求路径统一走/chat/completions让代码回退到最朴素的 OpenAI 兼容写法。这样 QwenClient 只要能返回内容就说明 Key、地址、模型名三件事至少没有互相打架后面再回到飞书链路就不会被模型调用层反复干扰。1.3 TaoToken 统一通道在这类排障里的位置排障最怕同时改三个变量Key、地址、模型名。你一边怀疑百炼的 Key 复制错了一边怀疑 dashscope 地址多写了/v1还一边怀疑 qwen-turbo 这个模型名是不是过期了最后只会把 qwen_client.py 改成一团乱麻。更稳的做法是先把模型通道固定下来打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建一把新 Key模型广场里确认qwen-turbo还在列表里然后把qwen_client.py的 Base URL 改成https://taotoken.net/api。这一步不是为了把 OpenClaw 变成另一个项目而是用一个规范的兼容通道把 dashscope 直连鉴权和路径写法问题先排除掉。如果 401 消失、QwenClient 能正常返回一句话说明飞书链路里的模型调用层已经通了。接下来再去看gateway.py的/feishu/webhook日志会干净很多要么是飞书事件订阅没配对要么是消息格式没解析对要么是回调地址飞书访问不到。至少不会再出现“明明飞书后台显示推送成功OpenClaw 却只报 Qwen API 401”这种两头不靠的情况。2. 把 2.1 的百炼 Key 换成 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建2.1 Windows 上准备 Key、Base URL 和 qwen-turbo原文 2.1 让你去阿里云百炼申请 api_key这里把动作换到 TaoToken。在 Windows 浏览器里打开 TaoToken注册并登录进入控制台创建 API Key。复制出来之后不要直接写死在代码里先在项目根目录建一个.env或者用系统环境变量存起来变量名可以叫TAOTOKEN_API_KEY值统一写成YOUR_API_KEY作为占位。准备材料只有三样API Key从 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建复制时注意不要带空格。Base URLhttps://taotoken.net/api末尾不要加/v1也不要加 UTM 参数。模型名排障阶段保留qwen-turbo正式使用以 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 模型广场当时列表为准。Windows 上确认 Python 环境能跑起来建议在 OpenClaw 目录里先执行python -m pip install requests。如果你之前装过 dashscope SDK也不用急着卸载先让 qwen_client.py 改用 requests 发请求减少 SDK 在 base_url 上自动补齐路径带来的干扰。2.2 qwen_client.py 里 self.base_url 和 headers 的改法打开 OpenClaw 目录下的qwen_client.py找到__init__里设置self.base_url的那一行。原来的 dashscope text-generation 地址整行删掉改成 TaoToken 的兼容通道地址。注意这里只写https://taotoken.net/api不要写成https://taotoken.net/api/v1也不要把?utm_sourcetaotoken_aicg_blog_end拼到 API 地址后面。下面是一份可以直接对照的完整写法import os import requests class QwenClient: def __init__(self, api_key: str | None None): self.api_key api_key or os.environ.get(TAOTOKEN_API_KEY, ) if not self.api_key: raise ValueError(缺少 TAOTOKEN_API_KEY请从 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建) self.base_url https://taotoken.net/api self.model qwen-turbo def chat(self, user_text: str) - str: url f{self.base_url}/chat/completions headers { Authorization: fBearer {self.api_key}, Content-Type: application/json, } body { model: self.model, messages: [ {role: system, content: 你是飞书里的助手回答保持简洁。}, {role: user, content: user_text}, ], temperature: 0.3, } resp requests.post(url, headersheaders, jsonbody, timeout60) if resp.status_code ! 200: raise RuntimeError(fQwen API {resp.status_code}: {resp.text}) data resp.json() return data[choices][0][message][content]改完之后headers里保留Authorization: Bearer YOUR_API_KEY不要混入 dashscope 专用的鉴权头。如果你原来在 headers 里写了X-DashScope-API-Key也先删掉排障阶段只保留一种鉴权方式。2.3 请求路径拼 /chat/completions 而不是 text-generationTaoToken 兼容通道在代码里按 OpenAI 风格使用所以请求路径是/chat/completions不是 dashscope 的/text-generation/generation。这一点和原文第二步差别最大原文可能用requests.post(self.base_url, ...)直接打 text-generation 地址或者用 dashscope SDK 的Generation.call。现在要么把路径改成f{self.base_url}/chat/completions要么把整个调用换成上面那段 requests 写法。响应解析也要跟着换。dashscope 原生返回常见的是output.textOpenAI 兼容返回的是choices[0].message.content。如果你的gateway.py里还在读output.textQwenClient 就算请求成功飞书那边也会因为取不到字段而报错。排障时先让verify_qwen.py打印完整 JSON确认结构之后再回去改 gateway 里的解析字段。3. 单独跑 QwenClient先别急着点飞书3.1 写一个最小 requests 验证脚本在 OpenClaw 目录里新建verify_qwen.py只做一件事用 QwenClient 发一句话看能不能拿到文本。这个脚本不要经过飞书也不要经过 gateway.py避免把飞书回调的问题混进来。from qwen_client import QwenClient def main(): client QwenClient(api_keyYOUR_API_KEY) answer client.chat(用一句话说明飞书机器人已经连上 Qwen 千问。) print(Qwen 返回, answer) if __name__ __main__: main()Windows 下在项目目录打开 PowerShell执行python verify_qwen.py。如果终端里打印出模型返回的一句话说明 Base URL、Key、模型名这条线已经通了。如果报 401先检查YOUR_API_KEY有没有复制完整如果报 404重点看self.base_url是不是多了/v1或者还留着 text-generation 路径。3.2 401、404、/v1 重复的日志对照下面这张表按本篇 qwen_client.py 的配置整理只覆盖排障时最可能撞上的几种。现象日志/报错关键词常见原因处理401Invalid API key、UnauthorizedKey 未创建、复制错、带空格或用了旧百炼 Key回 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 重新创建 YOUR_API_KEY404Not Found、url not foundbase_url 多写/v1或路径仍是 text-generationBase URL 只写https://taotoken.net/api请求路径改/chat/completions400model not found模型 ID 不在当前列表排障先用qwen-turbo正式模型以 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 模型广场为准超时Read timed out网络慢或 body 太大保留timeout60先发短句测试这张表里没有把 401 和 404 混在一起讲因为它们的修法完全不同。401 是身份没被认出来404 是路径没被认出来。把self.base_url改成https://taotoken.net/api之后如果 404 还在优先看路径拼接而不是反复换 Key。3.3 请求通了再启动 gateway.pyverify_qwen.py能稳定返回之后再去启动gateway.py。Windows 上建议开两个终端一个跑 gateway一个用curl或浏览器访问本地端口确认服务活着。OpenClaw 的 gateway 通常负责接收飞书事件QwenClient 只是它内部调用的一个模块。如果 gateway 启动时 import qwen_client 就报错先回去检查类名和文件路径如果启动成功但飞书没反应再看/feishu/webhook有没有收到请求。这里要分清顺序QwenClient 单独跑通只证明模型调用没问题gateway 能启动只证明本地服务没问题飞书消息能回来才证明整条链路都通了。排障时按这个顺序一层层确认比在飞书后台反复点“重新发送”有效得多。4. 回到飞书 /feishu/webhook 验证消息4.1 检查 gateway.py 的启动顺序和端口gateway.py 启动之后先看它监听的端口和路径。OpenClaw 的飞书入口一般是/feishu/webhook本地可以用http://127.0.0.1:端口/feishu/webhook试一下确认服务会返回飞书 challenge 或者 405 之类的响应。如果本地都访问不到飞书那边更不可能推送成功。Windows 防火墙偶尔会拦 Python 的监听端口如果本地能访问、飞书访问不到就去检查防火墙入站规则和回调地址是否写成了局域网 IP。确认 gateway 活着之后再看它有没有加载到正确的 QwenClient。有的项目会在启动时初始化模型客户端如果初始化阶段就抛 401gateway 可能表面启动成功但一收到消息就报错。看日志里有没有 QwenClient 的初始化记录没有的话就在 gateway 里加一行日志打印当前base_url和模型名确认不是又读到了旧的 dashscope 配置。4.2 飞书事件订阅与回调地址飞书开放平台里要确认事件订阅已经开启并且请求网址就是 gateway 暴露出来的地址。如果 QwenClient 已经通了飞书还是收不到消息优先看 gateway 控制台有没有POST /feishu/webhook。没有这行日志说明请求根本没到 OpenClaw问题在飞书回调地址、事件类型或者权限配置上跟 Qwen 的 401 已经不是同一层了。有这行日志但立刻报错再看错误堆栈。如果是KeyError: output说明 gateway 还在按 dashscope 原生结构取字段如果是RuntimeError: Qwen API 401说明 QwenClient 拿到的 Key 不对。把这两类错误分开飞书链路的排查会快很多。4.3 用飞书发一条测试消息看完整链路在飞书里给机器人发一条短消息比如“测试 Qwen 是否在线”。理想情况下日志顺序是飞书推送 POST 到/feishu/webhookgateway 解析出用户文本QwenClient 请求https://taotoken.net/api/chat/completions并返回gateway 再把结果发回飞书。如果中间任何一步断了日志会停在对应位置。看到 QwenClient 返回内容、但飞书里没显示就检查飞书消息发送接口的 token 和接收人 ID。看到 401 再次出现就回到 qwen_client.py确认self.api_key不是空字符串self.base_url没有多写/v1。飞书这条链路一旦跑通后面再换模型或加新机器人都能用同一套排障顺序复用。5. 跑通后的 Key 管理和后续接入5.1 模型对话里确认 qwen-turboQwenClient 在本地返回正常之后可以打开 TaoToken 模型对话用同一把 Key 发一条测试消息。模型对话里能看到qwen-turbo是否还在可选列表也能确认 Base URL 和模型 ID 的对应关系。如果这里返回正常而 OpenClaw 里报 401基本可以判定是项目里还残留了旧配置比如.env里还写着百炼 Key或者qwen_client.py被另一个文件覆盖了。5.2 控制台看用量与创建新 Key飞书机器人跑起来之后去 控制台 API Keys 看一眼这次调用有没有记上账。如果用量在涨说明请求确实走了统一通道如果用量不动但本地能返回就要检查是不是有缓存或者请求打到了别处。需要给测试环境、生产环境分开 Key 时也在同一个控制台创建不要复用同一把 Key 写进多个机器人。5.3 需要写代码时再看 Coding Plan 和 Claude Code 文档OpenClaw 的飞书机器人稳定之后如果后面还想把日常写代码的流程接上可以看 Coding Plan 是否覆盖你的使用量。Claude Code 的环境变量和配置文件写法对照 Claude Code 接入文档 里的ANTHROPIC_BASE_URL、ANTHROPIC_AUTH_TOKEN、ANTHROPIC_MODEL三项即可Base URL 同样填https://taotoken.net/api不要加/v1也不要把官网链接的 UTM 参数带进去。这条链路排障到最后真正要记住的只有两个动作Key 从 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建Base URL 在 qwen_client.py 里只写https://taotoken.net/api。先让 QwenClient 单独返回一句话再回 gateway.py 的/feishu/webhook看飞书消息。401 消失之后剩下的就是飞书事件订阅和消息格式不再难查。