1. 每次新会话都要重新交代背景,问题到底出在哪
如果你正在用 Claude Code 做中大型项目,大概率经历过这个场景:新开一个会话,第一件事不是写代码,而是先打一段"项目说明书"——这是 Node.js 项目,用的 Prisma + Express,测试框架是 Jest,别动 package-lock.json,别碰 .env 文件,API 响应统一用{ data, error, meta }结构……
重复到第十次的时候,你会开始怀疑自己是不是在训练一个每天失忆的实习生。更崩溃的是,某次 Claude 帮你改完一个接口,顺手把package-lock.json"优化"了一下,600 多行 diff,review 的时候你差点以为看错了仓库。它不是故意的,但每次都得人肉盯着,自动化又变回了人工 review。
这个问题的根源在于:大多数人用 Claude Code 还停留在"对话式编程"阶段。每次新开会话,上下文清零、规则清零、约束清零。你以为在跟一个越来越懂你的搭档合作,实际上每次都是从零开始。
Claude Code 其实内置了一套完整的扩展机制来解决这个问题——Hooks、Skills、Agents 三层配置协同。Hooks 管"不能做什么",Skills 管"应该怎么做",Agents 管"谁来做"。把这三层配好,你的 Claude Code 就从"需要手把手带的实习生"变成"自带 SOP 的高级工程师"。
这篇文章面向需要反复交代上下文的中大型项目开发者,目标是让每次会话开箱即用。我会给出可直接复制的settings.json配置片段、完整的目录结构、验证动作,以及如何把 endpoint 与鉴权统一改到 TaoToken 通道,让 Hooks、Skills、Agents 三层配置真正跑起来。全程不需要写业务代码,全是配置。
2. 三层协同前,先把 Claude Code 的请求通道接到 TaoToken
在配置 Hooks、Skills、Agents 之前,有一个前置动作必须先做:把 Claude Code 的请求 endpoint 和鉴权统一到 TaoToken。原因很直接——三层配置跑起来之后,Subagent 会大量并发调用模型,Hooks 里的 prompt 类型判断也会额外发起请求,如果通道不统一,你会在多个 key、多个 endpoint 之间来回切换,排查问题时根本分不清是哪一层出的错。
TaoToken 在这里扮演的是统一接入通道的角色:一个 API Key、一个 Base URL,Claude Code 主会话、Subagent、Hooks 里的 LLM 判断全部走同一条链路。这样你在看日志、算成本、排查 401 的时候,只需要盯一个地方。
2.1 获取 API Key 与确认 Base URL
先到 TaoToken 控制台创建 API Key。地址是https://taotoken.net/api-keys,登录后点创建,复制出来的 key 形如sk-xxxxxxxx。这个 key 只显示一次,建议直接存进密码管理器。
Base URL 统一用https://taotoken.net/api,注意这个地址不带任何查询参数,是纯粹的 API 入口。官网首页是https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,控制台、文档、模型对话入口都在上面能找到。
如果你还没决定用哪个模型,可以先到模型对话页面https://taotoken.net/models试一下,确认模型 ID 再写进配置。Claude Code 场景下常用的模型 ID 需要和你账号下可用的保持一致,写错模型 ID 会直接报model not found。
2.2 环境变量方式接入(推荐)
Claude Code 读取环境变量的优先级高于配置文件,所以最省事的做法是在 shell 里导出:
export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_AUTH_TOKEN="sk-你的TaoToken密钥" export ANTHROPIC_MODEL="你的模型ID"把这三行写进~/.zshrc或~/.bashrc,source一下。这样每次开终端都自动生效,Claude Code 启动时直接读到。
注意ANTHROPIC_AUTH_TOKEN和ANTHROPIC_API_KEY的区别:前者用于自定义 endpoint 的 Bearer 鉴权,后者是官方直连时用的。走 TaoToken 通道时用ANTHROPIC_AUTH_TOKEN,写错了会出现鉴权失败。
2.3 settings.json 方式接入(团队共享)
如果你希望团队里每个人克隆仓库后开箱即用,可以把通道配置写进项目的.claude/settings.json。但 key 不能提交到 git,所以正确做法是:settings.json 里只写 Base URL 和模型 ID,key 通过环境变量注入。
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_MODEL": "你的模型ID" } }然后每个人在自己的~/.zshrc里放ANTHROPIC_AUTH_TOKEN。这样仓库里没有敏感信息,通道又是统一的。
2.4 验证通道是否打通
配置完先别急着写 Hooks,用一条最小请求验证通道:
curl https://taotoken.net/api/v1/messages \ -H "Authorization: Bearer $ANTHROPIC_AUTH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "model": "'"$ANTHROPIC_MODEL"'", "max_tokens": 64, "messages": [{"role": "user", "content": "reply with ok"}] }'返回里能看到content字段和正常的usage,说明通道通了。如果返回 401,先检查 key 有没有复制完整、有没有多余空格;如果返回model not found,去模型对话页面确认模型 ID 拼写。
这一步做完,后面 Hooks 里的 prompt 判断、Subagent 的并发调用,全部走这条通道,不用再单独配。
3. 可复制的 settings.json:Hooks 让 Claude 自己守规矩
通道打通后,进入正题。Hooks 的核心思想很简单:在 Claude 执行特定操作的前后,自动触发你定义的逻辑。用过 Git 的 pre-commit hook 或者 Spring 的 AOP,概念一模一样。
3.1 九种事件覆盖完整生命周期
| 事件 | 触发时机 | 核心用途 |
|---|---|---|
| PreToolUse | 工具执行前 | 拦截危险操作、修改输入参数 |
| PostToolUse | 工具执行后 | 自动格式化、跑 linter |
| UserPromptSubmit | 用户提交 prompt 时 | 注入上下文、安全警告 |
| Stop | 主 Agent 准备停止时 | 检查是否跑了测试/build |
| SubagentStop | 子 Agent 准备停止时 | 验证子任务完成度 |
| SessionStart | 会话开始时 | 加载环境变量、设置项目上下文 |
| SessionEnd | 会话结束时 | 清理临时文件、记录日志 |
| PreCompact | 上下文压缩前 | 保留关键信息不被丢弃 |
| Notification | 通知发送时 | 桌面提醒(权限请求、空闲提示) |
每个事件支持两种 Hook 类型:command执行 Shell 脚本,适合确定性检查,默认超时 60 秒;prompt让 LLM 做判断,适合需要语义理解的场景,默认超时 30 秒,仅 PreToolUse、PostToolUse、Stop、SubagentStop、UserPromptSubmit 支持。
Matcher 决定这个 Hook 监听哪些工具:"Write"精确匹配,"Read|Write|Edit"匹配多个,"*"匹配所有,"mcp__.*__delete.*"正则匹配。
3.2 完整 settings.json 配置(Node.js 项目)
这是我在生产项目里实际使用的配置,直接放在.claude/settings.json:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_MODEL": "你的模型ID" }, "hooks": { "SessionStart": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "echo \"[session] branch=$(git branch --show-current) node=$(node -v)\" && exit 0" } ] } ], "PreToolUse": [ { "matcher": "Write|Edit", "hooks": [ { "type": "prompt", "prompt": "File path: $TOOL_INPUT.file_path. Verify: 1) Not .env or credentials 2) Not package-lock.json/yarn.lock 3) No path traversal (..). Return 'approve' or 'deny'." } ] } ], "PostToolUse": [ { "matcher": "Write|Edit", "hooks": [ { "type": "command", "command": "npx prettier --write \"$TOOL_INPUT.file_path\" 2>/dev/null; npx eslint --fix \"$TOOL_INPUT.file_path\" 2>/dev/null; exit 0" } ] } ], "Stop": [ { "matcher": "*", "hooks": [ { "type": "prompt", "prompt": "Review transcript. If code was modified, verify: 1) Tests were run 2) Build succeeded 3) All user questions answered. Return 'approve' or 'block' with reason." } ] } ], "Notification": [ { "matcher": "permission_prompt|idle_prompt", "hooks": [ { "type": "command", "command": "osascript -e 'display notification \"Claude needs attention\" with title \"Claude Code\"' 2>/dev/null; exit 0" } ] } ] }, "permissions": { "allow": ["Edit", "Write", "Bash(npm test:*)", "Bash(npm run build:*)"], "deny": ["Bash(rm -rf:*)", "Bash(git push --force:*)"] } }这套配置做了四件事:写文件前用 LLM 检查是否碰敏感文件;写文件后自动跑 Prettier + ESLint;结束前验证测试和构建;等待时弹桌面通知。
3.3 三个必踩的坑
坑一:改了配置没反应。Hooks 在会话启动时加载,改完settings.json必须退出并重启会话。调试用claude --debug,能看到 Hook 的注册和执行日志。
坑二:以为 Hook 按顺序执行。所有匹配的 Hooks 并行执行,不保证顺序,不能假设 Hook A 的输出被 Hook B 读到。需要链式处理就在一个 Hook 内部用;串联命令,或者通过临时文件在 PreToolUse → PostToolUse 之间传状态。
坑三:Hook 脚本忘了exit 0。command 类型退出码 0 表示成功,2 表示阻断(stderr 反馈给 Claude),其他非零码是非阻断错误。脚本可能失败但不想阻断流程,记得兜底exit 0。
4. Skills 与 Agents:把经验沉淀成知识包,把角色拆成并行团队
Hooks 解决了"守规矩",但"应该怎么做"和"谁来做"还得靠 Skills 和 Agents。
4.1 Skills 的三级渐进式加载
CLAUDE.md 能解决"每次交代项目背景",但它是全量加载的,写多了会吃掉上下文窗口。Skills 按需加载,只在需要时把相关知识注入上下文。它的三级加载机制是设计上最聪明的地方:
Level 1 是 Metadata(name + description),始终在上下文中,约 100 words,让 Claude 知道"有这个 Skill 可用"。Level 2 是 SKILL.md body,Skill 触发时才加载,建议 1500-2000 words。Level 3 是 Bundled Resources(scripts/ + references/ + assets/),Claude 按需读取,没有大小限制。
这意味着你可以注册 50 个 Skills,但只有被触发时它的 body 才占上下文,Metadata 这层成本几乎可忽略。
目录结构:
skill-name/ ├── SKILL.md # 必须:YAML frontmatter + Markdown body ├── scripts/ # 可执行脚本(确定性任务) ├── references/ # 按需加载的参考文档 └── assets/ # 模板、图片等资源文件4.2 自定义 Skill 示例:测试生成器
放在.claude/skills/gen-test/SKILL.md:
--- name: gen-test description: This skill should be used when the user asks to "generate tests", "write tests for", "add test coverage", or "create unit tests". Generates tests following project conventions. disable-model-invocation: true --- # Test Generator Generate tests for the file at $ARGUMENTS. ## Process 1. Read the source file and understand its exports 2. Check existing test patterns in [examples/](examples/) 3. Follow the project's testing conventions: - Use Jest/Vitest for unit tests - Use real code, minimize mocks - One behavior per test - Clear test names describing behavior 4. Place test file in appropriate `__tests__/` directory 5. Run tests to verify they pass ## Reference Examples - **`examples/unit-test.ts`** - Standard unit test pattern - **`examples/integration-test.ts`** - API integration test pattern几个关键设计:disable-model-invocation: true让只有用户显式调用才触发,防止 Claude 自作主张;具体步骤放 body(Level 2),示例代码放examples/(Level 3)按需读取;$ARGUMENTS是动态占位符,用户输入/gen-test src/services/user.ts时替换为文件路径。
Skills 还支持动态上下文注入,!command语法会在 Skill 加载前执行命令并替换输出:
## Current State - Branch: !`git branch --show-current` - Status: !`git status --short`这样 Claude 拿到的是实时项目状态,不是静态文档。
4.3 Agents:把角色拆成并行团队
Agents 是你手下的"虚拟团队成员",每个有自己的角色定位、工具权限和思维模型。放在.claude/agents/code-reviewer.md:
--- name: code-reviewer description: Use this agent when code changes are complete and need review. model: sonnet color: blue tools: ["Read", "Grep", "Glob"] --- You are an expert code reviewer specializing in identifying bugs, security issues, and code quality problems. **Your Core Responsibilities:** 1. Review all changed files for correctness 2. Check for security vulnerabilities (OWASP Top 10) 3. Verify error handling completeness 4. Assess code readability and maintainability **Output Format:** - **Summary**: 2-3 sentences on overall quality - **Issues**: Grouped by severity with file:line references - **Verdict**: Approved / Changes Requested关键配置:model: sonnet是性价比最优选择;tools: ["Read", "Grep", "Glob"]遵守最小权限原则,Reviewer 只需要读代码。
模型选择策略:机械实现(改 1-2 个文件,spec 明确)用 haiku,快且便宜;集成判断(多文件协调、接口设计)用 sonnet;架构设计、复杂 Code Review 用 opus;不确定时用 inherit 继承主 Agent 模型。
Subagent 并行派发的前提:2 个以上独立任务无共享状态;每个任务可独立理解;Agent 之间不会编辑同一文件。满足这三条,Claude 会自动分派到不同 Subagent,每个在独立工作空间执行,完成后返回 DONE、DONE_WITH_CONCERNS、NEEDS_CONTEXT、BLOCKED 四种状态之一。
坑一:以为 Subagent 自动继承主 Agent 上下文。这是最常见的误解。Subagent 启动时是干净上下文,不会自动获得你之前聊了半小时的会话历史。你需要在派发时把 Subagent 需要知道的所有信息写进 task 描述。这是刻意设计,避免上下文污染。
坑二:给 Agent 太多工具权限。只负责 Review 的 Agent 不需要 Write 和 Bash。工具越多,Agent 越容易"发挥创造力"做你没要求的事。
5. 验证请求与常见报错排查
配置写完,必须验证。这一节给出验证动作和真实报错对照。
5.1 验证 Hooks 是否生效
重启 Claude Code 会话后,用/hooks命令查看已加载的 Hooks 列表。如果列表为空,说明settings.json路径不对或 JSON 语法错误。用claude --debug启动,日志里会打印每个 Hook 的注册信息。
触发一次 Write 操作,观察 PostToolUse 是否跑了 Prettier。如果文件没被格式化,检查$TOOL_INPUT.file_path是否被正确替换——不同版本的变量名可能不同,用claude --debug看实际传入的参数。
5.2 验证 Skills 是否被识别
在会话里输入/看命令补全列表,自定义 Skill 应该出现在里面。如果没出现,检查 SKILL.md 的 frontmatter 格式——name和description是必填,YAML 缩进错了会导致整个 Skill 加载失败。
5.3 验证 Agents 是否可派发
输入@code-reviewer看是否能唤起。如果 description 写得泛泛,Claude 可能永远不会主动派发。必须用第三人称加具体触发短语,把触发场景写死。
5.4 真实报错对照表
| 报错 | 原因 | 解决 |
|---|---|---|
| 401 Unauthorized | key 错误或未注入 | 检查ANTHROPIC_AUTH_TOKEN是否导出,有无多余空格 |
| model not found | 模型 ID 拼写错误 | 去模型对话页面确认可用模型 ID |
| local proxy failed | Base URL 写错或网络不通 | 确认ANTHROPIC_BASE_URL为https://taotoken.net/api |
| reading choices 报错 | 响应格式解析失败 | 检查是否误用了 OpenAI 格式的 endpoint |
| OAuth 相关报错 | 误用了官方登录态 | 走 TaoToken 通道时清掉官方 OAuth 缓存 |
| Hook 不执行 | 未重启会话 | 退出并重启 Claude Code |
| Skill 不触发 | description 太泛 | 改成第三人称加具体触发短语 |
排查顺序建议:先确认通道(curl 最小请求),再确认 Hooks 加载(/hooks),再确认 Skills 识别(/补全),最后确认 Agents 派发(@唤起)。一层一层来,不要跳。
6. 把三层配置真正用起来:从今天开始的三步走
回到开头那个场景:每次开新会话都要重复交代背景、手动盯着 Claude 别碰 lock 文件、改完代码不知道该不该跑测试。这些问题的本质是——你在用一个有记忆能力的工具,却没给它建立记忆。
CLAUDE.md 是它的长期记忆,Skills 是它的专业技能库,Hooks 是它的行为准则,Agents 是它的团队分工。把这四样配好,Claude Code 才算真正"上岗"。
我的建议是分三步走:今天先写一个 CLAUDE.md,30 分钟;明天配好 Hooks 的settings.json,20 分钟;后天按需写第一个 Skill,30 分钟。不用一步到位,但别在"对话式编程"阶段停太久。
通道层面,把 endpoint 和鉴权统一到 TaoToken 之后,主会话、Subagent、Hooks 里的 LLM 判断全部走一条链路,排查问题时只需要盯一个地方。API Key 在https://taotoken.net/api-keys创建,接入文档在https://taotoken.net/doc,模型对话在https://taotoken.net/models,长期编码和 Agent 场景可以看 Coding Planhttps://taotoken.net/coding-plan。
配好之后你会发现,新开会话的第一句话不再是"这是一个 Node.js 项目",而是直接进入正题。这才是 Claude Code 该有的样子。