ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

QQBot发送本地文件失败?用Skill打通桌面文件直发链路

QQBot发送本地文件失败?用Skill打通桌面文件直发链路 1. 桌面文件发不出去问题到底卡在哪如果你正在用 OpenClaw 搭配 QQBot 做自动化大概率遇到过这个场景文件明明就在桌面上路径复制得一字不差结果一发送就报错Media path must be inside QQ Bot media storage。这个报错信息看起来像是权限问题实际上跟权限一点关系都没有。QQBot 的媒体发送机制有一套自己的规则它只接受位于特定媒体存储目录内的文件或者是一个它能直接下载的 HTTP(S) URL。你电脑上任意路径的文件比如C:\Users\你的用户名\Desktop\report.pdf对 QQBot 来说属于非法输入——不是文件不存在而是这个路径不在它的可访问范围内。这个设计本身有它的道理QQBot 作为消息通道需要确保发送的媒体文件来源可控、格式可预期。但对使用者来说这就造成了一个体验断层——我明明有文件为什么发不出去解决思路其实不复杂在本地文件和QQBot 发送之间加一层中转。把文件先复制到 QQBot 认可的媒体目录再用富媒体标签发送。手动做这件事当然可以但每次都要记目录、复制、改路径太繁琐。所以我把这个流程封装成了一个 Skill叫qqbot-send让整个链路自动化。这篇文章会从报错现场开始一步步带你配置 Skill、写 settings.json、跑通验证请求最后把常见的坑列出来。目标很明确让你桌面上的文件能直接发到 QQ不用手动搬来搬去。2. 前置准备TaoToken 与 OpenClaw 环境确认在动手改配置之前先确认你的 OpenClaw 环境能正常调用模型。QQBot 的文件发送能力依赖 OpenClaw 的 Skill 机制而 Skill 的执行又需要模型接口可用。如果你还没配置模型接入可以先去 TaoToken 拿一个 API Key。TaoToken 的定位是模型 API 聚合接入支持 Claude、GPT 等主流模型的统一调用。对于 OpenClaw 这类需要频繁调用模型的工具来说用聚合接口的好处是切换模型时不用改代码只换 Key 和 base_url 就行。具体操作访问 https://taotoken.net/api 了解接口规范然后到 https://taotoken.net/api-keys 创建一个 API Key。创建时注意选择对应的模型权限OpenClaw 里如果用 Claude 系列做 Skill 调度就确保 Key 有 Claude 的调用权限。拿到 Key 之后在 OpenClaw 的配置文件里填入。通常是在~/.openclaw/config.json或项目根目录的.env文件中设置{ model: { provider: taotoken, api_key: sk-你的Key, base_url: https://taotoken.net/api, model_name: claude-sonnet-4-20250514 } }如果你用的是环境变量方式export TAOTOKEN_API_KEYsk-你的Key export TAOTOKEN_BASE_URLhttps://taotoken.net/api配置完成后可以先跑一个简单的对话测试确认模型能正常响应。如果这一步就报错先排查 Key 是否有效、base_url 是否写对。模型对话的在线测试入口在 https://taotoken.net/models 可以直接在页面上验证 Key 的可用性。环境确认没问题后再进入 Skill 的配置环节。这一步看起来跟文件发送无关但实际上是基础——Skill 的调度逻辑需要模型来解析用户意图模型不通后面都白搭。3. qqbot-send Skill 配置骨架与 settings.json 片段qqbot-send的核心逻辑分三步识别文件来源、判断是否需要中转、执行发送。Skill 的配置文件需要定义触发条件、执行脚本路径、以及媒体目录的位置。先看 Skill 的目录结构。在 OpenClaw 的 skills 目录下创建qqbot-send文件夹~/.openclaw/skills/ └── qqbot-send/ ├── skill.json ├── scripts/ │ └── stage_media.py └── README.mdskill.json是 Skill 的入口定义内容如下{ name: qqbot-send, version: 1.0.0, description: 将本地文件中转至 QQBot 媒体目录并发送, trigger: { keywords: [发送文件, 发到QQ, send file, qqbot send], patterns: [发送.*文件, 把.*发到QQ] }, actions: { stage_and_send: { script: scripts/stage_media.py, args: [{{source_path}}], description: 中转本地文件并发送 } }, media: { relay_dir: ~/.openclaw/media/qqbot/, max_size_mb: 10, allowed_extensions: [.png, .jpg, .jpeg, .gif, .pdf, .zip, .txt, .docx, .xlsx] } }关键字段说明relay_dir是 QQBot 认可的媒体中转目录所有本地文件必须先复制到这里max_size_mb限制单文件大小超过 10MB 的文件会被拒绝allowed_extensions定义可发送的文件类型不在列表里的扩展名会触发错误提示。接下来是stage_media.py脚本负责实际的文件复制和中转#!/usr/bin/env python3 import os import sys import shutil from pathlib import Path RELAY_DIR Path.home() / .openclaw / media / qqbot MAX_SIZE_MB 10 def stage_media(source_path: str) - str: src Path(source_path).expanduser().resolve() if not src.exists(): raise FileNotFoundError(f源文件不存在: {src}) if not src.is_file(): raise ValueError(f路径不是文件: {src}) size_mb src.stat().st_size / (1024 * 1024) if size_mb MAX_SIZE_MB: raise ValueError(f文件大小 {size_mb:.2f}MB 超过限制 {MAX_SIZE_MB}MB) RELAY_DIR.mkdir(parentsTrue, exist_okTrue) dest RELAY_DIR / src.name if dest.exists(): stem dest.stem suffix dest.suffix counter 1 while dest.exists(): dest RELAY_DIR / f{stem}_{counter}{suffix} counter 1 shutil.copy2(src, dest) return str(dest) if __name__ __main__: if len(sys.argv) 2: print(用法: python stage_media.py source_path) sys.exit(1) try: result stage_media(sys.argv[1]) print(fSTAGED:{result}) except Exception as e: print(fERROR:{e}) sys.exit(1)这个脚本做了几件事检查源文件是否存在、验证大小、创建中转目录、处理文件名冲突、复制文件并返回目标路径。复制用shutil.copy2保留元数据不修改原文件。settings.json里需要注册这个 Skill并配置 QQBot 的媒体发送参数{ skills: { qqbot-send: { enabled: true, path: ~/.openclaw/skills/qqbot-send, auto_load: true } }, qqbot: { media_storage: ~/.openclaw/media/qqbot/, rich_media_tag: qqmedia, send_timeout_seconds: 30 } }media_storage必须和 Skill 里的relay_dir保持一致否则中转后的文件仍然不在 QQBot 的识别范围内。rich_media_tag定义发送时使用的标签名默认是qqmedia。配置写完后重启 OpenClaw 让 Skill 加载生效。如果启动日志里看到Skill loaded: qqbot-send说明注册成功。4. 验证请求从桌面选取文件到成功发送配置完成后跑一次完整的验证流程。我试过用一个桌面上的 PDF 文件来测试步骤如下。第一步确认文件在桌面ls ~/Desktop/test-report.pdf输出应该显示文件存在。如果用的是 Windows 路径在 OpenClaw 的终端里可能需要转换格式比如C:\Users\你的用户名\Desktop\test-report.pdf对应 WSL 下的/mnt/c/Users/你的用户名/Desktop/test-report.pdf。第二步手动执行 stage 脚本确认中转逻辑正常python ~/.openclaw/skills/qqbot-send/scripts/stage_media.py ~/Desktop/test-report.pdf预期输出STAGED:/home/你的用户名/.openclaw/media/qqbot/test-report.pdf如果输出ERROR:源文件不存在检查路径是否正确如果输出ERROR:文件大小超过限制换一个小文件测试。第三步确认中转目录里文件已就位ls -la ~/.openclaw/media/qqbot/应该能看到test-report.pdf出现在列表里。第四步通过 OpenClaw 发送。在对话中输入把桌面上的 test-report.pdf 发到 QQOpenClaw 会解析意图触发qqbot-sendSkill执行 stage 脚本然后用富媒体标签发送。发送成功后QQ 端会收到文件消息。如果你想手动构造发送请求来验证可以直接调用 OpenClaw 的发送接口curl -X POST http://localhost:3000/api/send \ -H Content-Type: application/json \ -d { type: media, target: qqbot, media_path: ~/.openclaw/media/qqbot/test-report.pdf, tag: qqmedia }返回{status: ok, message_id: xxx}表示发送成功。如果返回Media path must be inside QQ Bot media storage说明media_path没有指向中转目录检查路径是否写错。整个验证流程的核心是确认三件事文件能复制到中转目录、中转目录在 QQBot 的媒体存储范围内、富媒体标签能正确引用中转后的路径。这三步都通过文件直发链路就打通了。5. 本篇常见错误排查即使配置看起来没问题实际跑的时候还是可能遇到各种报错。下面列出几个高频问题和对策。报错一Media path must be inside QQ Bot media storage这是最典型的错误说明发送时引用的路径不在 QQBot 的媒体目录内。排查步骤确认settings.json里的media_storage和 Skill 里的relay_dir是否一致确认 stage 脚本执行后文件确实复制到了中转目录确认发送时用的是中转后的路径而不是原始桌面路径。报错二FileNotFoundError: 源文件不存在stage 脚本找不到源文件。常见原因是路径格式问题Windows 路径在 WSL 环境下需要转换中文路径可能需要加引号。另外如果文件在 OneDrive 同步目录里实际路径可能跟显示的不一样用realpath命令确认真实路径。报错三文件大小超过限制默认限制是 10MB超过这个大小的文件会被拒绝。如果你需要发送更大的文件可以调整skill.json里的max_size_mb字段但要注意 QQBot 本身对媒体文件也有大小限制调太大可能发送失败。建议先压缩文件或者分卷发送。报错四Skill 加载失败日志显示skill.json parse errorJSON 格式错误通常是多了逗号、少了引号、或者注释没删干净。用python -m json.tool skill.json验证格式会指出具体哪一行有问题。报错五发送成功但 QQ 端收不到文件检查 QQBot 的媒体发送权限是否开启有些机器人配置里默认关闭了富媒体发送。另外确认rich_media_tag的值和 QQBot 实际支持的标签一致不同版本的 QQBot 可能用不同的标签名。报错六文件名冲突导致覆盖如果中转目录里已经有同名文件脚本会自动加数字后缀避免覆盖。但如果你手动复制文件到中转目录可能会覆盖已有文件。建议统一走 stage 脚本不要手动操作中转目录。排查时的一个实用技巧在 stage 脚本里加一行日志输出把源路径和目标路径都打印出来方便对比。如果问题出在发送环节检查 OpenClaw 的日志里有没有qqmedia标签的解析记录。6. 接入文档与后续扩展qqbot-send解决的是本地文件到 QQBot 媒体目录这一层中转问题。如果你还需要处理更复杂的场景比如从 URL 下载文件再发送、批量发送多个文件、或者根据文件类型自动选择发送方式可以在现有 Skill 基础上扩展。扩展的方向有几个在 stage 脚本里增加 URL 下载逻辑用requests库把远程文件拉到中转目录增加批量处理模式接受文件列表参数增加文件类型判断图片走图片通道、文档走文件通道。这些都可以在skill.json的actions里定义新的 action然后在脚本里实现对应逻辑。如果你在配置过程中遇到模型调用相关的问题比如 Skill 调度时模型返回超时或权限错误可以到 https://taotoken.net/doc 查看接口文档确认 base_url 和模型名称是否匹配。长期做编码类任务的话Coding Plan 的接入方式在 https://taotoken.net/coding-plan 有说明适合需要频繁调用模型进行代码生成和调试的场景。整个链路的核心思路其实就一句话QQBot 不是不能发文件它只是不能直接发任意路径的文件。补上中转这一层问题就解决了。qqbot-send把这个中转过程自动化让你不用每次手动复制文件、改路径。配置一次后面直接说把桌面上的文件发到 QQ就行。
返回列表