1. 从 401 invalid x-api-key 复盘:IP 头像设计 Skill 的 Key 该放哪层
把 IP 头像设计 Skill 接进 Claude Code 后,第一次批量生成 8 张头像就遇到401 invalid x-api-key。复盘发现不是 Skill 出错,而是 Key 放错了层级:CLI 读的是全局配置,脚本读的是项目.env,两边各写了一份。后来把供应商统一到 TaoToken,先去官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=ip-avatar-key-layer 拿 Key,再把 Base URL 固定为https://taotoken.net/api,问题才收敛。这个过程让我意识到,IP 头像设计 Skill 开箱即用的前提,不是把 prompt 写得多花哨,而是先回答一个工程问题:Key 到底应该放在哪一层。
如果只是单次对话,把 Key 贴在命令行里也能跑;但只要进入“Skill + CLI + 批处理脚本 + 多供应商切换”的组合,Key 的层级就会直接决定排障成本。放在 shell 环境变量里,对当前终端有效,换一个窗口就失效;放在项目.env里,脚本能读到,但 Claude Code 的 settings.json 不一定继承;放在 Codex 的 config.toml 里,又不应该继续套用ANTHROPIC_*。所以这篇复盘不讨论头像 prompt 的审美,而是把 IP 头像设计 Skill 当成一个可复现的小型工程,拆开配置层、执行层和输出层,把 TaoToken 的 Key 放到正确的位置。
先给结论:项目.env适合放业务变量和输出路径,不适合作为 Key 的唯一来源;Claude Code 的 Key 放在settings.json的env层;Codex 的 Key 放在config.toml的model_providers层,并通过TAOTOKEN_API_KEY这类独立环境变量读取;CC Switch 则把 Key、Base URL、模型映射作为三件套放在切换层。所有层最终都指向同一个 Base URL:https://taotoken.net/api。Key 占位符统一写成YOUR_API_KEY,真实 Key 从 TaoToken 官网控制台获取,避免在多个文件里复制出不同版本。
2. 复现目录:把 IP 头像设计 Skill 拆成配置层、执行层、输出层
先把目录结构固定下来。这样后面讨论 Key 放哪层时,不会把“配置文件位置”和“运行时注入”混在一起。
ip-avatar-skill/ ├── .env.example ├── .gitignore ├── skills/ │ └── ip-avatar/ │ ├── SKILL.md │ ├── prompt.md │ └── references/ │ ├── style-cyberpunk.md │ ├── style-flat.md │ └── style-3d-cartoon.md ├── configs/ │ ├── claude/ │ │ └── settings.json │ ├── codex/ │ │ └── config.toml │ └── cc-switch/ │ └── providers.json ├── scripts/ │ ├── render_avatar.py │ ├── batch_run.sh │ └── check_env.sh └── output/ └── .gitkeep这个目录里,skills/ip-avatar是 Skill 本体,负责描述任务、风格参考和输出约束。configs是供应商配置层,分别服务 Claude Code、Codex 和 CC Switch。scripts是执行层,批处理脚本只读取环境变量,不硬编码 Key。output是产物目录,头像文件按批次和风格归档。.env.example是模板,不代表真实 Key 应该只放在这里。
为什么要把.env单独拿出来?因为很多人写 IP 头像设计 Skill 时,第一反应是新建.env,然后把ANTHROPIC_API_KEY、OPENAI_API_KEY、TAOTOKEN_API_KEY全塞进去。结果 Claude Code 启动时读的是~/.claude/settings.json,Codex 读的是~/.codex/config.toml,批处理脚本又用python-dotenv读项目.env。三套读取路径不一致,就会出现“终端里明明有 Key,Skill 却报 401”的经典问题。
更稳的做法是:.env只放非敏感或可替换的默认值,真实 Key 通过 TaoToken 官网创建后,写入对应工具的配置层。需要统一的是 Base URL,而不是把 Key 复制到所有文件。下面先写.env.example,但注意它只是模板,不是唯一入口。
# .env.example # 业务配置 IP_AVATAR_OUTPUT_DIR=./output IP_AVATAR_BATCH_SIZE=8 IP_AVATAR_STYLE=cyberpunk # TaoToken 统一入口 # 真实 Key 请在 TaoToken 官网创建后写入对应工具配置层 TAOTOKEN_BASE_URL=https://taotoken.net/api TAOTOKEN_API_KEY=YOUR_API_KEY # Claude Code 兼容变量 # 仅 Claude Code 使用,不要复制到 Codex ANTHROPIC_BASE_URL=https://taotoken.net/api ANTHROPIC_API_KEY=YOUR_API_KEY ANTHROPIC_MODEL=claude-sonnet-4-20250514再配一个.gitignore,避免 Key 被误提交:
.env output/*.png output/*.jpg configs/cc-switch/providers.local.json执行层脚本只做一件事:检查当前环境是否具备调用条件,不负责“猜”Key 在哪。
#!/usr/bin/env bash # scripts/check_env.sh set -euo pipefail if [[ -z "${TAOTOKEN_API_KEY:-}" ]]; then echo "[ERROR] TAOTOKEN_API_KEY is empty." echo "[HINT] Create a key from TaoToken console, then export it or put it in the right config layer." exit 1 fi if [[ "${TAOTOKEN_BASE_URL:-}" != "https://taotoken.net/api" ]]; then echo "[WARN] TAOTOKEN_BASE_URL is not https://taotoken.net/api" fi echo "[OK] base_url=${TAOTOKEN_BASE_URL:-unset}" echo "[OK] api_key=${TAOTOKEN_API_KEY:0:6}****"本地执行:
cp .env.example .env # 编辑 .env,把 YOUR_API_KEY 换成真实 Key source .env bash scripts/check_env.sh如果输出类似下面这样,说明最外层环境变量已经就绪:
[OK] base_url=https://taotoken.net/api [OK] api_key=sk-****但请注意,这一步只证明 shell 能读到。Claude Code 和 Codex 是否读到,要看下一节的配置层。
3. 环境变量与 .env 边界:写 .env 之前先去 TaoToken 官网拿 Key
写.env之前,先去 TaoToken 官网拿 Key。入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=env-before-dotenv,进入控制台后创建 API Key,把生成的 Key 先放在密码管理器或临时安全位置,不要直接写进 Git 跟踪的文件。然后把 Base URL 填为https://taotoken.net/api。这个 Base URL 是后续所有工具的统一入口,不需要额外加 UTM。
很多 IP 头像设计 Skill 的教程会直接让你在.env里写:
ANTHROPIC_API_KEY=YOUR_API_KEY但如果 Skill 是通过 Claude Code CLI 调用,CLI 并不一定从项目.env读取。Claude Code 通常读取settings.json的env字段,或者读取进程环境变量。也就是说,.env更适合作为“人类可读的模板”和“脚本入口”,不是唯一配置源。
我建议的层级关系是:
- 真实 Key 只在 TaoToken 控制台生成和轮换。
- 项目
.env放占位符和业务变量,方便本地复现。 - Claude Code 的 Key 写入
configs/claude/settings.json的env。 - Codex 的 Key 写入
configs/codex/config.toml的model_providers,并通过TAOTOKEN_API_KEY读取。 - CC Switch 的三件套放在
configs/cc-switch/providers.json,做多供应商切换。 - 输出目录和批大小放在
.env或脚本参数里,和 Key 解耦。
这样做的好处是,当你要把 IP 头像设计 Skill 从一台机器复制到另一台机器时,只需要替换配置层里的YOUR_API_KEY,而不是全项目搜索 Key。另一个好处是排障时能快速定位:如果curl能通、脚本能通、Claude Code 不通,那问题一定在 Claude Code 的 settings.json 层。
可以用一个最小请求验证 Base URL 和 Key 是否匹配。命令由读者本地执行,不要在远程生产环境直接跑:
curl -sS https://taotoken.net/api/v1/models \ -H "Authorization: Bearer ${TAOTOKEN_API_KEY}" \ -H "Content-Type: application/json" | head -c 500如果返回模型列表或正常 JSON,说明 Key 和 Base URL 基本正确。如果返回 401,先检查 Key 是否复制完整;如果返回 404,先检查 Base URL 是否误写成了其他路径;如果返回 429,说明请求频率或额度需要去控制台确认。注意,这些命令都在本地终端执行,不要把 Key 输出到日志里。
4. Claude Code 的 Key 层级:settings.json 里 ANTHROPIC_* 怎么放
Claude Code 的配置重点是settings.json。Key 应该放在env层,而不是散落在项目.env。下面是一个可复制的配置示例,放在configs/claude/settings.json:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "YOUR_API_KEY", "ANTHROPIC_MODEL": "claude-sonnet-4-20250514", "ANTHROPIC_SMALL_FAST_MODEL": "claude-3-5-haiku-20241022" }, "permissions": { "allow": [ "Read", "Write", "Bash(python scripts/render_avatar.py:*)", "Bash(bash scripts/batch_run.sh:*)" ] } }这里的层级关系很明确:ANTHROPIC_BASE_URL指向https://taotoken.net/api,ANTHROPIC_API_KEY使用YOUR_API_KEY占位,真实值从 TaoToken 控制台获取。ANTHROPIC_MODEL和ANTHROPIC_SMALL_FAST_MODEL决定主模型和快速模型。把这段放在settings.json的env里,Claude Code 启动时会注入到自己的进程环境,Skill 调用时就能读到。
启动方式:
claude --settings ./configs/claude/settings.json如果你希望使用全局配置,也可以把它合并到~/.claude/settings.json。但不建议同时在项目.env、shell profile、全局 settings.json 里写三份不同的 Key。那样一旦轮换 Key,就会漏改。更稳的方式是:全局 settings.json 只写ANTHROPIC_BASE_URL和模型名,Key 通过 CI 或本地 secret 注入,项目.env只留YOUR_API_KEY占位。
在 Claude Code 里运行 IP 头像设计 Skill 时,可以这样描述任务:
使用 skills/ip-avatar 这个 Skill,为我的技术博客生成 8 张 IP 头像。 风格:赛博朋克 + 扁平化混合,高对比度,圆形构图,适合头像框。 输出目录:output/cyberpunk-batch-01。 每张图保留 prompt 和 seed,写入 output/cyberpunk-batch-01/manifest.json。运行日志应该能看到供应商和 Base URL 被加载:
$ claude --settings ./configs/claude/settings.json [INFO] loaded settings: ./configs/claude/settings.json [INFO] provider: taotoken [INFO] base_url: https://taotoken.net/api [INFO] api_key: YOUR_API_KEY**** [INFO] skill: ip-avatar [INFO] model: claude-sonnet-4-20250514 [INFO] batch_size: 8 [INFO] output_dir: output/cyberpunk-batch-01 [INFO] request 200 OK [INFO] saved: output/cyberpunk-batch-01/avatar_01.png [INFO] saved: output/cyberpunk-batch-01/avatar_02.png ...如果这里仍然报401,优先检查settings.json是否被正确加载。可以用claude --help或启动日志确认 settings 路径。另一个常见问题是 JSON 中多了一个逗号,导致配置解析失败,工具退回默认供应商。此时日志里的base_url可能不是https://taotoken.net/api,一眼就能看出来。
5. Codex 的 Key 层级:config.toml 不要套 ANTHROPIC_*
Codex 的配置格式和 Claude Code 不同,最忌讳把ANTHROPIC_*直接套过来。Codex 使用config.toml,供应商在model_providers里声明。下面是一个可复制的示例,放在configs/codex/config.toml:
model = "gpt-5-codex" model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "TAOTOKEN_API_KEY" wire_api = "chat"然后通过环境变量提供 Key:
export TAOTOKEN_API_KEY=YOUR_API_KEY export TAOTOKEN_BASE_URL=https://taotoken.net/api codex --config ./configs/codex/config.toml注意这里读取的是TAOTOKEN_API_KEY,不是ANTHROPIC_API_KEY。Codex 的供应商配置层和 Claude Code 的settings.json是两套体系,不应该混用。如果你在 Codex 的config.toml里写ANTHROPIC_API_KEY,运行时大概率找不到,或者被忽略后退回默认供应商,最终表现为 401 或 404。
Codex 启动日志可以关注这些字段:
$ codex --config ./configs/codex/config.toml [INFO] config: ./configs/codex/config.toml [INFO] model_provider: taotoken [INFO] base_url: https://taotoken.net/api [INFO] env_key: TAOTOKEN_API_KEY [INFO] api_key: YOUR_API_KEY**** [INFO] wire_api: chat [INFO] model: gpt-5-codex如果 Codex 报missing env_key,说明TAOTOKEN_API_KEY没有导出到当前 shell。如果报404 page not found,优先检查base_url是否写成了https://taotoken.net/api/v1或其他路径。统一使用https://taotoken.net/api,让工具自己拼接接口路径。
对于 IP 头像设计 Skill,Codex 更适合承担“批量脚本生成”和“配置文件检查”这类任务。你可以在 Codex 里让它读取skills/ip-avatar/prompt.md,然后生成一批本地执行的命令。但命令仍然由你本地执行,不要让它直连生产数据库或执行不可逆操作。IP 头像生成属于文件输出任务,风险相对可控,但也建议先在小批量IP_AVATAR_BATCH_SIZE=2下验证。
6. CC Switch 三件套:把 Key、Base URL、模型映射放在切换层
如果你同时使用 Claude Code、Codex 和多个供应商,CC Switch 可以作为切换层。它的三件套是:API Key、Base URL、模型映射。配置放在configs/cc-switch/providers.json,示例:
{ "providers": [ { "name": "TaoToken", "baseUrl": "https://taotoken.net/api", "apiKey": "YOUR_API_KEY", "models": { "default": "claude-sonnet-4-20250514", "fast": "claude-3-5-haiku-20241022", "codex": "gpt-5-codex" } } ], "active": "TaoToken" }这里的 Key 仍然使用YOUR_API_KEY占位。真实 Key 从 TaoToken 官网控制台创建,入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=cc-switch-key。创建后,把 Key 填入 CC Switch 的供应商配置,或者通过环境变量TAOTOKEN_API_KEY注入。不要把真实 Key 提交到 Git,也不要在截图里露出完整 Key。
CC Switch 的价值在于把“切换供应商”这件事从 Claude Code 和 Codex 的配置里抽出来。比如今天用 TaoToken 跑 IP 头像批量生成,明天要对比另一个供应商,只需要在 CC Switch 里切换 active,而不需要改settings.json和config.toml。但切换层也有代价:如果 CC Switch 的 Key 和 Claude Code 的 Key 不一致,就会出现“切换了但没生效”的错觉。因此建议在切换后,用一次最小请求验证:
bash scripts/check_env.sh curl -sS https://taotoken.net/api/v1/models \ -H "Authorization: Bearer ${TAOTOKEN_API_KEY}" \ -H "Content-Type: application/json" | head -c 300如果 CC Switch 写入了本地文件,记得把providers.local.json加入.gitignore。团队协作时,只提交providers.example.json,真实 Key 由每个人本地创建。这样 IP 头像设计 Skill 的仓库可以公开复现,但不会泄露 Key。
7. 运行日志与排障:从 401/404/超时到头像批量产出
下面是一段完整的可复现运行日志,包含环境检查、Claude Code 启动、Skill 执行和输出落盘:
$ cp .env.example .env $ vim .env $ source .env $ bash scripts/check_env.sh [OK] base_url=https://taotoken.net/api [OK] api_key=YOUR_API_KEY**** $ claude --settings ./configs/claude/settings.json [INFO] loaded settings: ./configs/claude/settings.json [INFO] provider: taotoken [INFO] base_url: https://taotoken.net/api [INFO] api_key: YOUR_API_KEY**** [INFO] skill: ip-avatar [INFO] prompt_file: skills/ip-avatar/prompt.md [INFO] style: cyberpunk [INFO] batch_size: 8 [INFO] model: claude-sonnet-4-20250514 [INFO] request 200 OK [INFO] saved: output/cyberpunk-batch-01/avatar_01.png [INFO] saved: output/cyberpunk-batch-01/avatar_02.png [INFO] saved: output/cyberpunk-batch-01/avatar_03.png [INFO] saved: output/cyberpunk-batch-01/avatar_04.png [INFO] saved: output/cyberpunk-batch-01/avatar_05.png [INFO] saved: output/cyberpunk-batch-01/avatar_06.png [INFO] saved: output/cyberpunk-batch-01/avatar_07.png [INFO] saved: output/cyberpunk-batch-01/avatar_08.png [INFO] manifest: output/cyberpunk-batch-01/manifest.json [INFO] done in 42.8s如果日志停在request之前,说明配置加载阶段有问题。常见报错和排查方向如下:
| 现象 | 可能层级 | 排查动作 |
|---|---|---|
401 invalid x-api-key | Key 层 | 检查settings.json或config.toml中的 Key 是否为YOUR_API_KEY未替换,或环境变量未导出 |
404 page not found | Base URL 层 | 确认填的是https://taotoken.net/api,不要多加/v1或/chat |
model not found | 模型映射层 | 检查 Claude Code 的ANTHROPIC_MODEL与 Codex 的model是否写错 |
429 too many requests | 额度/频率层 | 降低IP_AVATAR_BATCH_SIZE,并在控制台确认额度与限速 |
timeout | 网络/并发层 | 先单张运行,再逐步增加并发,不要一次开 50 个进程 |
settings.json parse error | 配置格式层 | 用python -m json.tool configs/claude/settings.json检查 JSON |
missing env_key | Codex 环境变量层 | 导出TAOTOKEN_API_KEY,不要用ANTHROPIC_API_KEY代替 |
批量脚本建议加一个简单的重试和日志落盘:
# scripts/render_avatar.py 的简化片段 import os import json import time from pathlib import Path OUTPUT_DIR = Path(os.getenv("IP_AVATAR_OUTPUT_DIR", "./output")) BATCH_SIZE = int(os.getenv("IP_AVATAR_BATCH_SIZE", "8")) BASE_URL = os.getenv("TAOTOKEN_BASE_URL", "https://taotoken.net/api") API_KEY = os.getenv("TAOTOKEN_API_KEY", "YOUR_API_KEY") def check_config(): if API_KEY == "YOUR_API_KEY": raise RuntimeError("Please replace YOUR_API_KEY with a real key from TaoToken.") if BASE_URL != "https://taotoken.net/api": raise RuntimeError(f"Unexpected base_url: {BASE_URL}") def render_one(index: int): # 这里只描述本地批处理框架,实际调用由读者在本地按官方文档接入 output_file = OUTPUT_DIR / f"avatar_{index:02d}.png" output_file.parent.mkdir(parents=True, exist_ok=True) time.sleep(0.1) return str(output_file) def main(): check_config() manifest = [] for i in range(1, BATCH_SIZE + 1): file_path = render_one(i) manifest.append({"index": i, "file": file_path}) print(f"[INFO] saved: {file_path}") manifest_path = OUTPUT_DIR / "manifest.json" manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False)) print(f"[INFO] manifest: {manifest_path}") if __name__ == "__main__": main()运行:
source .env python scripts/render_avatar.py注意,脚本中只使用TAOTOKEN_BASE_URL和TAOTOKEN_API_KEY,不要在 Codex 场景里套ANTHROPIC_*。Claude Code 场景下,Key 已经在settings.json的env层注入,脚本可以只负责读取输出目录和批大小。这样分层之后,排障路径会非常清晰:环境变量层看check_env.sh,Claude Code 层看settings.json,Codex 层看config.toml,切换层看 CC Switch,输出层看output/manifest.json。
8. 头像风格一致性:Skill prompt 与模型参数怎么配合
Key 层级解决后,才轮到 IP 头像设计 Skill 的本职工作:让 8 张头像保持统一风格。建议把 prompt 拆成三层:全局风格、单张差异、输出约束。skills/ip-avatar/prompt.md可以这样写:
# IP 头像设计 Skill Prompt ## 全局风格 - 圆形构图,主体居中,适合社交平台头像框 - 高对比度,边缘清晰,缩小到 128x128 仍可识别 - 背景简洁,不出现文字、水印、二维码 ## 单张差异 - 每张头像更换主色调:青、紫、橙、绿、蓝、粉、金、红 - 每张头像更换一个配饰:耳机、眼镜、帽子、围巾、面具、发带、耳环、项链 - 保持同一角色特征:短发、几何脸型、科技感外套 ## 输出约束 - 输出目录:output/cyberpunk-batch-01 - 文件命名:avatar_01.png 到 avatar_08.png - manifest.json 记录 index、文件路径、主色调、配饰然后在 Claude Code 中调用 Skill 时,只需要补充批次信息:
使用 skills/ip-avatar 生成一批头像,批次号 cyberpunk-batch-01。 全局风格按 prompt.md 执行,单张差异按主色调和配饰轮换。 输出 8 张 PNG,并写 manifest.json。如果你在 Codex 中做批处理编排,可以把 prompt 文件路径和输出目录作为参数传入,但不要在 Codex 的config.toml里写ANTHROPIC_*。Codex 只负责读取TAOTOKEN_API_KEY和https://taotoken.net/api,执行层由本地脚本完成。这样即使未来更换供应商,IP 头像设计 Skill 的 prompt 和输出结构也不需要重写。
9. 文末 CTA:从模型对话到 Coding Plan,再到创建 Key 与 Claude Code 文档
复盘到最后,Key 放哪层其实是一个工程习惯问题:不要把所有配置塞进.env,而是让每一层只做一件事。Claude Code 的settings.json管ANTHROPIC_*,Codex 的config.toml管model_providers,CC Switch 管供应商切换三件套,脚本只读环境变量和输出目录。所有层最终指向同一个 Base URL:https://taotoken.net/api,Key 占位符统一为YOUR_API_KEY。
如果你准备把这套 IP 头像设计 Skill 真正跑起来,可以按下面的路径操作:
先在模型对话页试跑一次头像 prompt,确认风格方向:
https://taotoken.net/models/detail/chat?utm_source=taotoken_aicg_blog_end&utm_content=ip-avatar-chat确认需要批量生成后,查看 Coding Plan 的额度与模型覆盖:
https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=ip-avatar-coding-plan在控制台创建 API Key,替换配置层里的
YOUR_API_KEY:
https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=ip-avatar-api-keys按 Claude Code 文档把
ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY写入settings.json:
https://taotoken.net/doc/ClaudeCodeAnthropic?utm_source=taotoken_aicg_blog_end&utm_content=ip-avatar-claude-code-doc
回到开头那个401 invalid x-api-key,它并不是 Skill 的错,而是 Key 层级没有对齐。把 Key 放到正确的层,把 Base URL 固定为https://taotoken.net/api,再用check_env.sh和运行日志做验证,IP 头像设计 Skill 才算真正开箱即用。