1. 从 CopoHub 到 XHub:一个鸿蒙原生应用的 AI 重构现场
CopoHub 是一个跑在 HarmonyOS 上的第三方 GitHub 客户端,最早从 iOS 端起步,后来用 Cursor 补了一版鸿蒙原生实现。那个阶段 AI 编码刚起步,对 ArkTS 和鸿蒙原生 API 的理解很浅,一个需求下来十几个语法错误是常态,基本靠人肉逐个修。应用后来迭代了 8 个版本,接入内购之后开始有了一点收入,但维护两端的问题越来越突出:iOS 和 Harmony 各改各的,个人开发者根本没有完整的测试覆盖,改一处漏一处。
于是有了 Flutter 改造的想法。新建一个文件夹,把原有 harmony 代码放进去,让 AI 对照原型图和旧代码制定 Flutter 化计划,两三个小时出雏形,三天左右完成主体迁移。之后又在 CopoHub 的 UI 基础上复刻出 CopoGit(Gitee 第三方客户端),同样是三天提交审核。再往后,两个应用重复代码太多,干脆抽成一套工程 XHub,公共逻辑和 UI 下沉到 packages,两个应用分别放在 apps 目录下。
这套流程里真正卡人的不是业务逻辑,而是 AI 工具链的接入方式:Cursor、Codex、Claude Code 各自一套 Key,额度、模型、计费口径全不一样,切换一次就要重新配一遍。这篇就围绕 XHub 这个真实项目,讲清楚怎么用 TaoToken 统一 Key 和 API 通道,把 Cursor 的 skills 机制接进来,让鸿蒙 + Flutter 的混合工程在 AI 辅助下跑顺。
2. TaoToken 前置:统一 Key 与 API 通道要解决什么
XHub 这种工程有几个特点:目录里同时存在 harmony 和 flutter 两套构建产物,AI 会话需要跨目录读取;skills 要能调用本地脚本(比如打包脚本、宣传图生成);模型调用频繁且分散在 Cursor、命令行 Agent、脚本里。如果每个入口都单独配 Key,会出现三个问题。
第一是额度分散。你在 Cursor 里配一个 Key,在命令行 Agent 里配另一个,月底根本不知道钱花在哪。第二是模型口径不一致,同一个重构任务,Cursor 里用的是 A 模型,脚本里用的是 B 模型,输出风格和代码质量对不上。第三是切换成本,换一个模型要改多处配置,改漏一处就报 401。
TaoToken 在这里的角色是一个统一的 API 网关:你只维护一份 Key,所有入口都指向同一个 base_url,模型名在请求里指定。对 XHub 来说,这意味着 Cursor 的 config.toml、命令行 Agent 的 settings.json、以及 skills 里调用的脚本,可以共用同一套凭证。
注意:TaoToken 是合规的 API 聚合通道,不是任何形式的网络代理工具。它的作用是把多家模型的调用收敛到一个入口,方便统一管理和计费。
具体到操作,你需要先拿到 Key。访问 https://taotoken.net/api-keys 创建,然后到 https://taotoken.net/doc 确认当前支持的模型名和 base_url 格式。这两步做完,后面所有配置都围绕同一个 Key 展开。
3. 可复制配置:config.toml 与 settings.json 骨架
XHub 工程根目录下我放了一个.ai/目录,专门存 AI 工具链配置,避免和业务代码混在一起。下面这份 config.toml 是 Cursor 侧的骨架,重点是base_url和model两个字段。
# .ai/config.toml # XHub 工程 AI 通道配置,所有入口共用同一 Key [provider] name = "taotoken" base_url = "https://taotoken.net/api" api_key = "sk-你的TaoToken密钥" # 密钥建议用环境变量注入,见下方说明 [model] # 重构任务用长上下文模型,日常补全用轻量模型 default = "claude-sonnet-4-5" heavy = "claude-opus-4-1" light = "gpt-4o-mini" [workspace] # 让 AI 能同时看到 harmony 和 flutter 两套代码 include = ["apps/", "packages/", "scripts/"] exclude = ["build/", ".dart_tool/", "oh_modules/"] [skills] # skills 目录,存放宣传图生成、打包等自定义能力 dir = ".ai/skills" enabled = ["store-screenshot-composer", "harmony-build"]密钥不要硬编码进文件,用环境变量更稳。在 shell 的 profile 里加一行:
export TAOTOKEN_API_KEY="sk-你的TaoToken密钥"然后 config.toml 里改成api_key = "${TAOTOKEN_API_KEY}"。这样即使配置文件进了 git,也不会泄露凭证。
命令行 Agent 侧用 settings.json,结构和 config.toml 对应,但字段名不同:
{ "apiProvider": { "type": "openai-compatible", "baseUrl": "https://taotoken.net/api", "apiKey": "${TAOTOKEN_API_KEY}" }, "models": { "default": "claude-sonnet-4-5", "fallback": "gpt-4o-mini" }, "skills": { "path": ".ai/skills", "autoLoad": true }, "workspace": { "root": ".", "respectGitignore": true } }两份配置的核心是base_url完全一致,模型名按任务类型分流。重构这种需要读大量旧代码的任务走 heavy,日常补全走 light,能明显压住成本。
4. 验证请求:从一次真实重构调用看结果
配置写完不能直接上大任务,先用一个小请求验证通道是否通。在 XHub 根目录下执行:
curl -s https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer ${TAOTOKEN_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-5", "messages": [ {"role": "user", "content": "读取 apps/copohub/lib/main.dart,用一句话说明它的入口结构"} ], "max_tokens": 200 }'返回里如果能看到对 main.dart 入口结构的描述,说明 Key、base_url、模型名三件套都对上了。这一步失败的话,先别急着调 skills,回到第 5 节排查。
通道验证通过后,进入真实重构场景。XHub 里 harmony 用的是社区版 Flutter,iOS 和 Android 用公版,电脑上维护了两个 Flutter 版本。我让 AI 做了一个打包脚本,通过别名区分:
# scripts/build.sh # h-flutter 指向社区版,flutter 指向公版 PLATFORM=$1 DEVICE=$2 if [ "$PLATFORM" = "harmony" ]; then h-flutter build hap --target-platform ohos-arm64 elif [ "$PLATFORM" = "ios" ]; then flutter build ios --release elif [ "$PLATFORM" = "android" ]; then flutter build apk --release fi if [ -n "$DEVICE" ]; then flutter install -d "$DEVICE" fi这个脚本本身是 AI 根据我的自然语言描述生成的,但真正让它跑起来的是 skills 机制——把脚本注册成一个 skill,AI 在会话里就能直接调用,不用我每次手动敲命令。
skills 的验证动作很简单:在.ai/skills/下建一个harmony-build/SKILL.md,写清楚触发条件和执行命令,然后在会话里说“帮我打一个 harmony 包”,看 AI 是否正确识别并调用脚本。识别成功的话,它会输出类似“正在调用 harmony-build skill,执行 h-flutter build hap”的反馈。
另一个实际用到的 skill 是store-screenshot-composer。上架前要制作应用商店宣传图,以前是手动裁剪尺寸,现在把几张截屏丢进项目目录,让 AI 根据截屏内容和项目整体情况生成宣传图,多种样式可选。CopoHub 和 CopoGit 商店里的图就是这么出来的。这个 skill 和鸿蒙开发用的其他 skills 一起放在 https://github.com/yanglfree/harmony-skills,可以直接参考结构。
5. 本篇常见错排查
报 401 Unauthorized:九成是 Key 没注入成功。先echo $TAOTOKEN_API_KEY确认环境变量存在,再检查 config.toml 里是不是写成了字面量${TAOTOKEN_API_KEY}而没被解析。有些工具不支持环境变量插值,这种情况就老老实实写明文,但把配置文件加进 .gitignore。
报 model not found:模型名写错了。TaoToken 的模型名和官方文档一致,去 https://taotoken.net/doc 核对。注意别把claude-sonnet-4-5写成claude-3-5-sonnet,后者是旧命名。
skills 不触发:先确认.ai/skills/目录被 config.toml 的dir字段正确指向,再检查 SKILL.md 里的触发条件是不是太模糊。触发条件要写具体动作,比如“当用户要求打 harmony 包时”,而不是“当用户需要构建时”。
AI 读不到 harmony 代码:workspace 的 include 字段没覆盖到。XHub 的 harmony 代码在 apps 目录下,如果 include 只写了packages/,AI 就看不到。把apps/加进去,同时确认 exclude 没有误伤。
打包脚本权限不足:chmod +x scripts/build.sh,然后确认 skill 里调用的是绝对路径或相对于工程根目录的路径,别用相对当前工作目录的路径。
两个 Flutter 版本冲突:h-flutter和flutter的别名要在 shell profile 里都配好,且 PATH 顺序不能乱。用which h-flutter和which flutter确认指向不同版本。
6. 把统一 Key 接进你的鸿蒙工程
XHub 这套配置的核心思路是:一份 Key,两个配置文件,skills 作为能力扩展层。你不需要照搬目录结构,但建议把 AI 配置和业务代码分开,避免配置文件被构建流程误打包。
如果你正在做鸿蒙原生应用或者 Flutter 跨平台工程,想先把模型通道跑通,可以直接用 https://taotoken.net/api-keys 创建 Key,配置文档在 https://taotoken.net/doc。长期做编码和 Agent 任务的话,Coding Plan 会更划算,入口在 https://taotoken.net/coding-plan。想先验证模型输出质量,用模型对话页面试几次再决定,地址是 https://taotoken.net/chat。
鸿蒙开发里 skills 的价值不在于多复杂,而在于把重复动作固化下来。打包、宣传图、代码审查这些事,写一次 SKILL.md,后面一句自然语言就能触发。XHub 从 CopoHub 到 CopoGit 再到统一工程,真正省时间的不是某一次重构,而是这些被沉淀下来的自动化动作。