菜鸟AI - 让提示词生成更简单! 全站导航 全站导航
AI工具安装 新手教程 进阶教程 辅助资源 AI提示词 热点资讯 技术资讯 产业资讯 内容生成 模型技术 AI信息库

已有账号?

首页 > 资讯 > Claude Code Hooks实战:AI刹车控制最佳方案
其他资讯

Claude Code Hooks实战:AI刹车控制最佳方案

2026-05-31
阅读 0
热度 0
作者 菜鸟AI编辑部
摘要

摘要

Claude Code 第一次让我想砸键盘,是它擅自删除一个 properties 文件。 那个文件叫 application-dyna

Claude Code 第一次让我想砸键盘,是它擅自删除一个 properties 文件。

Claude Code Hooks 实战:给 AI 装上刹车

那个文件叫 application-dynamic.properties,里面的配置项没有对应的 @ConfigurationProperties 类——运行时是通过 Environment API 动态读取的。Claude Code 扫描了一圈,结论非常自信:「该文件未被代码引用,已安全删除。」

当然,我做了一点防护:在 CLAUDE.md 里写了「不要删除配置文件」。但没用,那是建议,不是规则。AI 看了一眼,权衡了一下,觉得自己的判断更对。

CLAUDE.md 是道德劝说,Hooks 才是法律——前者靠自觉,后者靠执法。


Hooks 到底是什么

先别急着改配置,把这几个概念咬死了,后面才不会踩坑。

Claude Code 的 Hooks 是一套生命周期事件拦截系统。AI 在执行每一步操作之前和之后,都会触发对应的事件,你可以往这些事件上挂自己的脚本。

事件一共六个,但日常能派上用场的满打满算也就五个:

事件触发时机典型用途
PreToolUseAI 准备执行工具但还没执行拦截危险命令、敏感文件
PostToolUseAI 刚执行完工具自动格式化、lint 检查
StopAI 认为任务已完成质量门禁:编译不过不结束
Notification系统发出通知权限请求桌面弹窗
UserPromptSubmit你按下 Enter 发送消息前输入内容审计

每个 hook 脚本有三种退场方式,这是整篇文章最重要的知识点:

  • exit 0:放行,AI 继续干活
  • exit 1:警告,stderr 会展示给 AI 但它照干不误
  • exit 2:拦截,AI 的该操作会被取消——这是你画给 AI 的唯一一条跨不过去的红线

配置写在 settings.json 里,三层优先级:settings.local.json(本地) > settings.json(项目级) > ~/.claude/settings.json(全局)。团队共享的钩子放项目级,个人偏好的放全局,调试用的放 local(记得 gitignore)。


第一个 Hook:拦住 rm -rf

先来一个简单的,PreToolUse 拦截危险命令。直接上菜。

在项目根目录下创建 .claude/settings.json

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/Users/yourname/.claude/hooks/pre-tool-security.sh"
          }
        ]
      }
    ]
  }
}

然后写脚本 ~/.claude/hooks/pre-tool-security.sh

#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""')

# rm -rf 黑名单
if echo "$COMMAND" | grep -qE 'rm\s+-rf'; then
  echo " 拦截: rm -rf 被禁止执行" >&2
  echo "命令: $COMMAND" >&2
  exit 2
fi

# 敏感文件保护
if echo "$COMMAND" | grep -qE '.env|.pem|id_rsa|credentials'; then
  echo " 拦截: 敏感文件操作被禁止" >&2
  exit 2
fi

exit 0

别忘了 chmod +x

验证一下:打开 Claude Code,输入「帮我把 target 目录删了」。你会看到终端啪地蹦出一行红字,AI 停下来,老实告诉你「这个操作被 hook 拦截了」。更绝的是,它甚至会自己想办法绕——不用 rm,改用 mvn clean

这里有个细节很多人踩过:exit 1 不会拦截。哪怕你 echo 了「危险操作!」然后 exit 1,AI 会看到警告但继续执行,拦不住。只有 exit 2 是真正的硬刹车。


PostToolUse:写完代码自动检查

安全是底线,效率才是日常。你写 Java 最烦什么?AI 写的代码忘加 null 检查、import 乱成一团、方法名根本不按团队规范来。Hooks 把 review 这一步自动化了——AI 写完代码,hook 立刻跑检查,有违规就甩它脸上让它自己修。

.claude/settings.json 扩一下:

{
  "hooks": {
    "PreToolUse": [...],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "/Users/yourname/.claude/hooks/post-tool-lint.sh"
          }
        ]
      }
    ]
  }
}

注意 matcher 写的是 Write|Edit,不是空的。你若是不写 matcher 或者写成 ""*每一次工具调用都会触发这个 hook——包括读文件。那时候你的 Claude Code 会卡成 PPT,一个简单的查询要等 3 秒 hook 跑完才响应。

脚本 post-tool-lint.sh

#!/bin/bash
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')

# 只检查 Java 文件变更
if [[ "$FILE_PATH" != *.java ]]; then
  exit 0
fi

# 跑 Checkstyle
./mvnw checkstyle:check -pl "$(dirname "$FILE_PATH" | cut -d/ -f1)" -q 2>&1 | tail -20

# 有违规就返回警告(不拦截,让 AI 看到后自己修)
if [ ${PIPESTATUS[0]} -ne 0 ]; then
  exit 1
fi

exit 0

这里的 trick 是 exit 1 而非 exit 2——你不想因为一个 import 顺序问题就让 AI 停摆,但你希望它看到 checkstyle 的输出后自己回去修。Claude Code 读到 stderr 里的违规信息,会自动分析、修复、再写入。

再进一步:Stop hook 做质量门禁。AI 每次说「搞定了」,你先跑一下编译和测试:

"Stop": [
  {
    "matcher": "",
    "hooks": [
      {
        "type": "command",
        "command": "/Users/yourname/.claude/hooks/stop-quality-gate.sh"
      }
    ]
  }
]
#!/bin/bash
# 编译检查
./mvnw compile -q 2>&1
if [ $? -ne 0 ]; then
  echo " 编译失败,任务未完成" >&2
  exit 2
fi

echo " 编译通过"
exit 0

exit 2 在这里的意思是:编译不过,你就别跟我说搞定了,回去继续修。


Notification:别让 AI 干等你也不知道

长任务跑到一半,AI 弹了个权限确认——你去接水了。回来发现它等了 5 分钟。这 5 分钟的算力浪费,积少成多一个月够买几杯咖啡。

"Notification": [
  {
    "matcher": "",
    "hooks": [
      {
        "type": "command",
        "command": "/Users/yourname/.claude/hooks/notify.sh"
      }
    ]
  }
]
#!/bin/bash
INPUT=$(cat)
TYPE=$(echo "$INPUT" | jq -r '.type // ""')

# 只通知需要你介入的事件,过滤掉 idle_prompt 等噪音
if [ "$TYPE" = "permission_prompt" ]; then
  MESSAGE=$(echo "$INPUT" | jq -r '.message // "需要你的确认"')
  osascript -e "display notification "$MESSAGE" with title "Claude Code" sound name "Glass""
fi

exit 0

macOS 用户直接用 osascript,Windows 用户换成 PowerShell 的 New-BurntToastNotification 或者直接用 notify-send(WSL)。Linux 桌面环境用 notify-send

效果:AI 要你确认的时候,屏幕右上角弹通知,「叮」一声。你在工位附近就能感知到,不用死盯着终端。

Stop hook 也能复用这个套路——任务真完成时才弹窗,失败不用弹,因为失败时 AI 还在继续修。


组合拳:一个 Java 项目的完整 Hooks 配置

散装的零件都看过了,现在拼成整车的。以下是一个 Spring Boot 项目的完整 .claude/settings.json,直接抄就行:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/Users/yourname/.claude/hooks/pre-tool-security.sh"
          }
        ]
      },
      {
        "matcher": "Read",
        "hooks": [
          {
            "type": "command",
            "command": "/Users/yourname/.claude/hooks/pre-read-guard.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "/Users/yourname/.claude/hooks/post-tool-lint.sh"
          }
        ]
      }
    ],
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "/Users/yourname/.claude/hooks/stop-quality-gate.sh"
          }
        ]
      }
    ],
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "/Users/yourname/.claude/hooks/notify.sh"
          }
        ]
      }
    ]
  }
}

四层防线,环环相扣:

  1. PreToolUse — AI 想干什么坏事,没机会动手就被拦下
  2. PostToolUse — 写完了自动检查规范,不规范就盯着它改
  3. Stop — 编译不过、测试挂掉,不准交差
  4. Notification — 需要你拍板的时候,立刻让你知道

装完这套配置之后,工作流变成了这样:给 Claude Code 下需求 → 去写文档或者看 PR → 听到通知弹窗回来点个确认 → 继续忙别的 → 回来验收。中间不需要频繁切回终端检查它在干什么——因为干坏事会被拦,干完活有质量门禁兜底。

给 AI 装减速带不是为了限制它,是为了让你敢把方向盘交给它。


五个坑,踩过的人才懂

坑 1:exit 1 当成 exit 2 用。 这是最高频的错误。写了个脚本 echo 警告然后 exit 1,以为拦住了,其实 AI 照干。exit 2 才叫拦截,记死了。

坑 2:matcher 留空。 ""* 匹配所有工具调用,包括 Read。你写了个同步 hook 挂上去,每次读文件都要等 hook 跑完——Claude Code 的反应速度直接退化到 IDE 水平。务必写窄匹配,lint 类用 Write|Edit,安全类用 Bash

坑 3:路径用了 ~ settings.json 里的 command 字段不认 ~$HOME,必须写绝对路径:/Users/yourname/.claude/hooks/xxx.sh。写了 ~/scripts/hook.sh 会静默失败,日志里才看得到。

坑 4:jq 没装。 几乎所有 hook 脚本都依赖 jq 解析 JSON。新机器或者 CI 环境里 jq 不在 PATH 上,脚本静默失败且 exit 0——等于安全护栏不存在。脚本开头加一行:command -v jq >/dev/null 2>&1 || { echo "jq 未安装" >&2; exit 0; }

坑 5:用 async 做拦截。 "async": true 的 hook 在后台跑,不阻塞 AI——exit 2 也没用,因为 AI 已经继续干活了。async 只适合通知类场景。


你可以在 CLAUDE.md 里写一百条规则,AI 都可能忽略;但一个 exit 2 的 PreToolUse hook,它永远跨不过去。

软规则定义你是谁,硬规则定义什么不能做。两样都装上,你的 Claude Code 才算真正出厂。

来源:互联网

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

同类文章推荐

相关文章推荐

更多