☰
Claude Code Hook 系统详解与 Hello World 实操:用 TaoToken 统一 Key 跑通 settings.json 配置
2026/10/9 17:01:05 网站建设 项目流程

1. 为什么要在 Claude Code 里折腾 Hook

Claude Code 用久了你会发现一个尴尬:它每次调用工具、每次提交 prompt、每次结束响应,你都是「事后才知道」。想加个日志、想在git commit前自动跑 lint、想在它改文件前拦一道,默认情况下没有入口。

Hook 就是补上这个入口的机制。简单说,Hook 是 Claude Code 在特定运行时事件上自动执行你自定义脚本的能力。事件发生时,harness 把上下文通过环境变量塞给你的脚本,脚本爱干嘛干嘛——写日志、跑检查、发通知、拦命令都行。

我习惯用嵌入式打比方:Claude Code 像一块 BMC 芯片,harness 是跑在上面的 RTOS 内核,而 Hook 就是注册进去的中断服务例程。事件来了,内核跳转到你的 ISR,执行完再回来。区别只是这里的「中断」是PreToolUse、PostToolUse、UserPromptSubmit、Stop这些。

这篇要解决三件事:一是把 Hook 的 6 种事件和 matcher 匹配机制讲清楚;二是给一份能直接复制的settings.json和脚本模板,跑通 Hello World;三是把模型调用通道用 TaoToken 统一起来,避免 Key 散落各处。适合已经在用 Claude Code、想往工程化方向走一步的人。

2. TaoToken 前置:把 Key 和 Base URL 统一掉

在写 Hook 之前,先把模型调用这条链路理顺。Claude Code 默认走官方通道,但很多团队希望 Key 集中管理、按项目隔离、方便审计。TaoToken 提供的就是这样一个统一入口:一个 Key、一个 Base URL,Claude Code、Codex、Cline 这些工具都能接。

官网入口在这里:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。API 地址是 https://taotoken.net/api ,注意这个不带 UTM 参数,配置里直接写它。

你需要准备三样东西,我称之为「三件套」:

  • Base URL:https://taotoken.net/api
  • API Key:在控制台生成,形如sk-...
  • Model ID:比如claude-sonnet-4-5这类具体模型标识

生成 Key 的入口在控制台:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API Keys 管理页在 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。

Claude Code 侧的配置有两种常见方式。第一种是环境变量,写进 shell 的 profile:

export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_API_KEY="sk-你的Key" export ANTHROPIC_MODEL="claude-sonnet-4-5"

第二种是写进 Claude Code 的配置文件。如果你用 Claude Code 的 settings 体系,可以在~/.claude/settings.json里加env字段:

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的Key", "ANTHROPIC_MODEL": "claude-sonnet-4-5" } }

这里有个坑要提前说:settings.json里env和hooks是并列的顶层字段,别把hooks塞进env里,也别覆盖已有字段。很多人第一次配就是在这里把 permissions 弄丢了。

配完之后,Claude Code 的所有模型请求都走 TaoToken 通道。Hook 脚本本身不直接调模型,但它记录的事件日志里会带上工具名、输入参数,配合统一通道,排查问题时能对上号。

如果你更习惯用 Coding Plan 做长期编码任务,入口在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。想先在网页里验证模型是否通,可以用模型对话:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。

3. 可复制配置:settings.json + Hook 脚本模板

这一节是核心,直接给能跑的东西。先建目录结构:

mkdir -p .claude/hooks

然后创建脚本.claude/hooks/hello_hook.sh:

#!/bin/bash # Hello World Hook —— 演示 Claude Code Hook 系统的基本用法 # 环境变量 CLAUDE_TOOL_NAME / CLAUDE_TOOL_INPUT / CLAUDE_PROJECT_DIR 由 harness 自动注入 LOG_FILE="$CLAUDE_PROJECT_DIR/.claude/hooks/hook_log.txt" TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') EVENT=${1:-"unknown"} case "$EVENT" in UserPromptSubmit) echo "[$TIMESTAMP] 用户提交了 Prompt" >> "$LOG_FILE" ;; Stop) echo "[$TIMESTAMP] Claude 响应结束" >> "$LOG_FILE" ;; PreToolUse) echo "[$TIMESTAMP] 即将调用工具: $CLAUDE_TOOL_NAME" >> "$LOG_FILE" ;; PostToolUse) echo "[$TIMESTAMP] 工具执行完毕: $CLAUDE_TOOL_NAME" >> "$LOG_FILE" ;; *) echo "[$TIMESTAMP] 事件触发: $EVENT | 工具: ${CLAUDE_TOOL_NAME:-none}" >> "$LOG_FILE" ;; esac

脚本通过$1接收事件类型,case分支写不同格式的日志。$CLAUDE_PROJECT_DIR由 harness 注入,指向项目根目录,所以日志路径是稳定的。给执行权限:

chmod +x .claude/hooks/hello_hook.sh

接着是.claude/settings.json。如果你已经有这个文件,把hooks作为顶层字段加进去,和permissions、env并列:

{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的Key", "ANTHROPIC_MODEL": "claude-sonnet-4-5" }, "hooks": { "PreToolUse": [ { "matcher": "", "hooks": [ { "type": "command", "command": "bash \"${CLAUDE_PROJECT_DIR}/.claude/hooks/hello_hook.sh\" PreToolUse" } ] } ], "PostToolUse": [ { "matcher": "", "hooks": [ { "type": "command", "command": "bash \"${CLAUDE_PROJECT_DIR}/.claude/hooks/hello_hook.sh\" PostToolUse" } ] } ], "UserPromptSubmit": [ { "hooks": [ { "type": "command", "command": "bash \"${CLAUDE_PROJECT_DIR}/.claude/hooks/hello_hook.sh\" UserPromptSubmit" } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "bash \"${CLAUDE_PROJECT_DIR}/.claude/hooks/hello_hook.sh\" Stop" } ] } ] } }

字段含义对照一下:

字段含义
hooks.<事件名>事件类型,支持 PreToolUse / PostToolUse / UserPromptSubmit / Stop / Notification / SubagentStop
matcher匹配器,""匹配该事件所有实例,也可写"Edit"、"Bash"或正则
type执行类型,"command"为 shell 命令,还支持"prompt"注入提示词
command要执行的命令,${CLAUDE_PROJECT_DIR}由 harness 替换为项目根目录

matcher 是这里最值得琢磨的。空字符串是「全匹配」,写"Edit"只对 Edit 工具生效,写"Bash"只对 Bash 生效。更细的玩法是用正则匹配命令内容,比如"Bash(git commit.*)"这种形式,只在 git commit 时触发。注意UserPromptSubmit和Stop这类事件没有工具名,matcher 通常留空。

注意:settings.json必须是合法 JSON,多一个逗号都会导致整个配置不生效,而且 Claude Code 不一定报错,只是静默忽略。改完用python -m json.tool .claude/settings.json验一下。

4. 验证请求:跑一轮对话看日志

配置写完,重启 Claude Code,然后随便发一句话,比如「读一下 README 文件」。等它响应完,去看日志:

cat .claude/hooks/hook_log.txt

正常输出长这样:

[2026-05-17 14:30:01] 用户提交了 Prompt [2026-05-17 14:30:02] 即将调用工具: Read [2026-05-17 14:30:02] 工具执行完毕: Read [2026-05-17 14:30:05] Claude 响应结束

这四行对应了完整的数据流:用户发消息触发UserPromptSubmit,Claude 思考后调用 Read 工具,触发PreToolUse,工具执行完触发PostToolUse,最后响应结束触发Stop。如果中间调用了多个工具,PreToolUse和PostToolUse会成对出现多次。

想验证 matcher 是否生效,把PreToolUse的 matcher 从""改成"Bash",重启后再让它读文件。你会发现 Read 不再记录,只有 Bash 调用才写日志。这就是 matcher 的过滤作用。

再进一步,验证正则匹配。把 matcher 改成"Bash(git status.*)",然后让它执行git status,日志里会出现;执行ls则不会。正则匹配的是命令内容,不是工具名,这点容易搞混。

如果你在验证过程中想确认模型通道是否正常,可以单独用模型对话页面发一条测试:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。通道通了,Hook 日志里的工具调用才会正常出现。

还有一个实用技巧:Hook 脚本里可以读$CLAUDE_TOOL_INPUT,它是 JSON 格式的工具参数。比如在PreToolUse里加一行:

echo "[$TIMESTAMP] 参数: $CLAUDE_TOOL_INPUT" >> "$LOG_FILE"

这样你能看到每次工具调用的具体入参,排查「它到底改了什么文件」这类问题时特别有用。

5. 本篇常见错排查

报错一:401 Unauthorized或invalid api key

这是模型通道的问题,不是 Hook 的问题。检查ANTHROPIC_API_KEY是否写对,有没有多余空格。如果你用的是 TaoToken,确认 Base URL 是https://taotoken.net/api,Key 是在控制台生成的。三件套缺一不可:Base URL、Key、Model ID。改完环境变量记得重开终端,或者source一下 profile。

报错二:local proxy failed或连接超时

通常是 Base URL 写错,比如漏了/api后缀,或者写成了带 UTM 的完整链接。配置里只写https://taotoken.net/api,不要带查询参数。另外检查网络是否能正常访问该地址,可以用curl -I https://taotoken.net/api快速验证连通性。

报错三:reading choices相关解析错误

这类错误一般出现在响应格式不符合预期时。先确认 Model ID 是通道支持的模型,别写了个不存在的名字。如果换了模型后出现,换回默认模型试试。Hook 本身不解析模型响应,所以这个错和 Hook 无关,是通道配置问题。

报错四:Hook 完全不触发,日志文件不生成

按顺序排查:第一,settings.json是不是合法 JSON,用python -m json.tool验;第二,脚本有没有执行权限,ls -l .claude/hooks/hello_hook.sh看有没有x;第三,${CLAUDE_PROJECT_DIR}是否被正确替换,可以在脚本开头加echo "DIR=$CLAUDE_PROJECT_DIR"调试;第四,改完配置有没有重启 Claude Code,Hook 配置是启动时加载的。

报错五:OAuth相关提示

如果你之前用官方登录方式认证过,环境变量和 OAuth 可能冲突。清掉旧的认证缓存,确保走的是 API Key 方式。检查~/.claude下有没有残留的凭据文件,必要时备份后移除。

报错六:matcher 写了但不生效

matcher 是大小写敏感的,"edit"和"Edit"不一样。正则写法要符合规范,"Bash(git commit.*)"这种形式里括号和点号都有含义。先用空 matcher 确认 Hook 能触发,再逐步收紧匹配条件。

提示:调试 Hook 时,最省事的办法是在脚本第一行加set -x,把执行过程打到 stderr,Claude Code 的日志里能看到。确认没问题再删掉。

6. 把 Hook 用起来:从 Hello World 到真实场景

Hello World 跑通只是起点。真正有价值的是把 Hook 接到你的工作流里。

一个我常用的场景是「提交前自动检查」。用PreToolUse匹配Bash(git commit.*),脚本里跑npm run lint,不通过就返回非零退出码,Claude Code 会感知到并停下来。这样就不会出现「AI 帮你提交了一堆格式错误的代码」这种事。

另一个场景是审计。把所有PostToolUse事件写进结构化日志,记录工具名、参数、时间戳。配合 TaoToken 统一通道,你能把「模型请求」和「工具调用」两条线对上,分析 AI 的行为模式。这在团队协作里很有用,谁改了什么、什么时候改的,一目了然。

再进阶一点,Hook 脚本可以调用外部 HTTP 接口。比如Stop事件触发时,往你的通知服务发一条消息;或者PreToolUse检测到高风险命令(rm -rf、git push --force)时,先发个确认请求。这些都不需要改 Claude Code 本身,全在脚本里完成。

如果你在做长期编码任务,把 Hook 和 Coding Plan 结合起来会更顺:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。统一的 Key 管理加上事件驱动的自动化,基本就是一套轻量的 AI 开发流水线。

最后提醒一句:Hook 脚本里不要写死敏感信息,Key 走环境变量或配置文件。脚本本身建议纳入版本控制,但日志文件记得加进.gitignore。跑通之后,先从一个小场景开始用,别一上来就挂一堆 Hook,出问题不好定位。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询