一、钩子系统整体架构
1.1 架构分层设计
┌─────────────────────────────────────────────────────────────┐
│ 用户交互层 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 用户命令 / Claude响应 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
├─────────────────────────────────────────────────────────────┤
│ 钩子调度层 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ HookScheduler │ │
│ │ • 钩子注册与匹配 │ │
│ │ • 执行时序控制 │ │
│ │ • 上下文管理 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
├─────────────────────────────────────────────────────────────┤
│ 钩子执行层 │
│ ┌──────────┐ ┌───────────┐ ┌──────────┐ │
│ │PreToolUse│ │PostToolUse│ │ Stop │ │
│ │ (前置) │ │ (后置) │ │ (终止) │ │
│ └────┬─────┘ └─────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └──────────────┼─────────────┘ │
│ ↓ │
├─────────────────────────────────────────────────────────────┤
│ 命令执行层 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ CommandExecutor │ │
│ │ • 命令执行 │ │
│ │ • 结果收集 │ │
│ │ • 错误处理 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
├─────────────────────────────────────────────────────────────┤
│ 权限控制层 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ PermissionManager │ │
│ │ • allow/deny列表 │ │
│ │ • 操作授权检查 │ │
│ │ • 安全策略执行 │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
1.2 核心组件设计
java
// 钩子系统核心接口设计
public interface Hook {
String getType();
String getMatcher();
List<HookAction> getActions();
boolean matches(String toolName);
HookResult execute(HookContext context);
}
// 钩子上下文
public class HookContext {
private String toolName;
private String filePath;
private Map<String, String> environment;
private boolean stopHookActive;
// getters/setters
}
// 钩子动作
public interface HookAction {
ActionType getActionType();
String getCommand();
String getPrompt();
ActionResult execute(HookContext context);
}
// 动作类型枚举
public enum ActionType {
COMMAND, // 执行命令
PROMPT // 向Claude提问
}
二、钩子执行时序分析
2.1 完整执行流程
┌─────────────────────────────────────────────────────────────┐
│ 钩子执行时序图 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 用户输入 │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. 权限检查 │ │
│ │ PermissionManager.check() │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 2. PreToolUse钩子 │ │
│ │ • 匹配器检查 │ │
│ │ • 执行前置命令 │ │
│ │ • 决定是否允许继续 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 3. Claude执行工具 │ │
│ │ • Write/Bash/Grep/Glob等 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 4. PostToolUse钩子 │ │
│ │ • 匹配器检查 │ │
│ │ • 执行后置命令(格式化/检查) │ │
│ │ • 返回结果给Claude │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 5. 检查是否说"完成" │ │
│ │ • 是 → Stop钩子 │ │
│ │ • 否 → 继续下一轮 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 6. Stop钩子 │ │
│ │ • 检查stop_hook_active │ │
│ │ • 执行质量门禁命令 │ │
│ │ • 根据结果决定继续或完成 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
2.2 钩子优先级设计
java
// 钩子优先级枚举
public enum HookPriority {
PRE_TOOL_USE(10), // 最高优先级,执行前拦截
POST_TOOL_USE(20), // 中等优先级,执行后处理
STOP(30); // 最低优先级,终止前验证
private final int value;
HookPriority(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
// 钩子调度器
public class HookScheduler {
private Map<HookPriority, List<Hook>> hooks = new EnumMap<>(HookPriority.class);
public void registerHook(Hook hook) {
HookPriority priority = getPriority(hook.getType());
hooks.computeIfAbsent(priority, k -> new ArrayList<>()).add(hook);
}
public List<HookResult> executeHooks(HookPriority priority, HookContext context) {
List<HookResult> results = new ArrayList<>();
for (Hook hook : hooks.getOrDefault(priority, Collections.emptyList())) {
if (hook.matches(context.getToolName())) {
results.add(hook.execute(context));
}
}
return results;
}
}
三、PreToolUse钩子架构
3.1 前置拦截机制
java
// PreToolUse钩子实现
public class PreToolUseHook implements Hook {
private String matcher;
private List<HookAction> actions;
@Override
public HookResult execute(HookContext context) {
HookResult result = new HookResult();
result.setHookType("PreToolUse");
for (HookAction action : actions) {
ActionResult actionResult = action.execute(context);
// 如果动作返回非零退出码,阻止后续操作
if (!actionResult.isSuccess()) {
result.setContinueExecution(false);
result.setMessage(actionResult.getOutput());
return result;
}
// 将命令输出传递给Claude
result.addOutput(actionResult.getOutput());
}
result.setContinueExecution(true);
return result;
}
}
3.2 输入过滤策略
| 过滤类型 | 实现方式 | 示例 |
|---|---|---|
| 文件内容过滤 | 命令管道处理 | `grep -n 'ERROR |
| 操作阻止 | 命令返回非零 | echo 'BLOCKED' && exit 1 |
| 参数校验 | 正则匹配 | 验证文件路径格式 |
3.3 安全拦截规则
java
// 安全规则引擎
public class SecurityRuleEngine {
private List<SecurityRule> rules;
public SecurityRuleEngine() {
rules = Arrays.asList(
new BlockDotEnvRule(),
new BlockRmRfRule(),
new BlockGitPushRule()
);
}
public SecurityCheckResult check(HookContext context) {
for (SecurityRule rule : rules) {
if (rule.matches(context)) {
return SecurityCheckResult.deny(rule.getReason());
}
}
return SecurityCheckResult.allow();
}
}
// 具体规则实现
public class BlockDotEnvRule implements SecurityRule {
@Override
public boolean matches(HookContext context) {
return context.getToolName().startsWith("Write")
&& context.getFilePath().endsWith(".env");
}
@Override
public String getReason() {
return "Cannot write to .env files for security reasons";
}
}
四、PostToolUse钩子架构
4.1 后置处理机制
java
// PostToolUse钩子实现
public class PostToolUseHook implements Hook {
private String matcher;
private List<HookAction> actions;
@Override
public HookResult execute(HookContext context) {
HookResult result = new HookResult();
result.setHookType("PostToolUse");
for (HookAction action : actions) {
// 替换占位符
String command = replacePlaceholders(action.getCommand(), context);
ActionResult actionResult = executeCommand(command);
// 收集所有输出,不阻止执行
result.addOutput(actionResult.getOutput());
}
// PostToolUse钩子不会阻止执行,只是传递结果
result.setContinueExecution(true);
return result;
}
private String replacePlaceholders(String command, HookContext context) {
return command
.replace("$file", context.getFilePath())
.replace("$tool", context.getToolName());
}
}
4.2 自动格式化流程
java
// 代码格式化器
public class CodeFormatter {
private static final String PRETTIER_CMD = "npx prettier --write %s";
private static final String ESLINT_CMD = "npx eslint --fix %s";
public FormatResult format(TypeScriptFile file) {
FormatResult result = new FormatResult();
// 1. 执行Prettier格式化
String prettierOutput = executeCommand(String.format(PRETTIER_CMD, file.getPath()));
result.addStep("prettier", prettierOutput);
// 2. 如果是TSX文件,执行ESLint修复
if (file.isTsx()) {
String eslintOutput = executeCommand(String.format(ESLINT_CMD, file.getPath()));
result.addStep("eslint", eslintOutput);
}
return result;
}
}
4.3 类型检查集成
java
// 类型检查器
public class TypeChecker {
private static final String TSC_CMD = "npx tsc --noEmit 2>&1 | head -20";
public TypeCheckResult check(String filePath) {
String output = executeCommand(String.format(TSC_CMD, filePath));
TypeCheckResult result = new TypeCheckResult();
result.setOutput(output);
// 解析错误数量
long errorCount = output.lines()
.filter(line -> line.contains("error TS"))
.count();
result.setErrorCount((int) errorCount);
result.setSuccess(errorCount == 0);
return result;
}
}
五、Stop钩子架构
5.1 质量门禁机制
java
// Stop钩子实现
public class StopHook implements Hook {
private List<HookAction> actions;
private boolean stopHookActive = false;
@Override
public HookResult execute(HookContext context) {
// 防止循环调用
if (stopHookActive) {
HookResult result = new HookResult();
result.setContinueExecution(false);
result.setMessage("stop_hook_active=true, exiting to prevent loop");
return result;
}
stopHookActive = true;
HookResult result = new HookResult();
result.setHookType("Stop");
try {
for (HookAction action : actions) {
ActionResult actionResult = action.execute(context);
result.addOutput(actionResult.getOutput());
// 检查测试是否通过
if (!actionResult.isSuccess()) {
result.setContinueExecution(true); // 继续修复
result.setMessage("Tests failed, continuing to fix");
return result;
}
}
// 所有检查通过
result.setContinueExecution(false);
result.setMessage("All checks passed, task complete");
} finally {
stopHookActive = false;
}
return result;
}
}
5.2 测试执行流程
java
// 测试执行器
public class TestExecutor {
private static final String TEST_CMD = "npm test 2>&1 | tail -10";
public TestResult execute() {
String output = executeCommand(TEST_CMD);
TestResult result = new TestResult();
result.setOutput(output);
// 解析退出码
Matcher matcher = Pattern.compile("Exit: (\\d+)").matcher(output);
if (matcher.find()) {
int exitCode = Integer.parseInt(matcher.group(1));
result.setExitCode(exitCode);
result.setSuccess(exitCode == 0);
}
return result;
}
}
5.3 自动修复闭环
java
// 自动修复控制器
public class AutoFixController {
private static final int MAX_RETRIES = 3;
private StopHook stopHook;
private TestExecutor testExecutor;
public FixResult runAutoFix(ClaudeAgent agent, Task task) {
FixResult result = new FixResult();
result.setTask(task);
for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) {
result.setAttempt(attempt);
// 1. 执行任务
agent.execute(task.getPrompt());
// 2. 运行测试(通过Stop钩子)
TestResult testResult = testExecutor.execute();
if (testResult.isSuccess()) {
result.setSuccess(true);
result.setMessage("Task completed successfully after " + attempt + " attempts");
return result;
}
// 3. 更新任务提示,让Claude修复
task.updatePrompt("测试失败,请修复:\n" + testResult.getOutput());
}
result.setSuccess(false);
result.setMessage("Failed after " + MAX_RETRIES + " attempts");
return result;
}
}
六、配置解析架构
6.1 配置文件结构
java
// 配置类设计
public class ClaudeConfig {
private PermissionConfig permissions;
private HookConfig hooks;
// 权限配置
public static class PermissionConfig {
private List<String> allow;
private List<String> deny;
private String defaultMode;
}
// 钩子配置
public static class HookConfig {
private List<HookDefinition> preToolUse;
private List<HookDefinition> postToolUse;
private List<HookDefinition> stop;
}
// 钩子定义
public static class HookDefinition {
private String matcher;
private List<ActionDefinition> hooks;
}
// 动作定义
public static class ActionDefinition {
private String type;
private String command;
private String prompt;
}
}
6.2 配置解析器
java
// 配置解析器
public class ConfigParser {
private ObjectMapper objectMapper;
public ClaudeConfig parse(File configFile) throws IOException {
String content = Files.readString(configFile.toPath());
return objectMapper.readValue(content, ClaudeConfig.class);
}
public Hook createHook(HookDefinition definition) {
switch (definition.getType()) {
case "PreToolUse":
return new PreToolUseHook(definition);
case "PostToolUse":
return new PostToolUseHook(definition);
case "Stop":
return new StopHook(definition);
default:
throw new IllegalArgumentException("Unknown hook type: " + definition.getType());
}
}
}
七、企业级扩展架构
7.1 API聚合平台集成
java
// 企业级API客户端
@Configuration
public class EnterpriseApiConfig {
@Bean
public OpenAI enterpriseOpenAIClient(
@Value("${weelinking.api.key}") String apiKey,
@Value("${weelinking.base.url}") String baseUrl) {
return OpenAI.builder()
.baseUrl(baseUrl)
.apiKey(apiKey)
.build();
}
@Bean
public HookConfigService hookConfigService(OpenAI openAI) {
return new HookConfigService(openAI);
}
}
// 配置管理服务
public class HookConfigService {
private OpenAI openAI;
public ClaudeConfig getEnterpriseConfig(String tenantId) {
ChatCompletionResponse response = openAI.chat()
.create(new ChatCompletionRequest()
.model("claude-3-opus")
.messages(List.of(new Message("user",
"根据企业规范生成Claude配置:tenantId=" + tenantId))));
String configJson = response.choices().get(0).message().content();
return new ConfigParser().parseFromString(configJson);
}
}
7.2 团队配置共享
java
// 配置同步服务
public class ConfigSyncService {
private GitClient gitClient;
private String teamConfigRepo;
public void syncTeamConfig() {
// 拉取最新配置
gitClient.pull(teamConfigRepo);
// 合并到本地配置
mergeConfigs(
getLocalConfig(),
getTeamConfig()
);
}
private void mergeConfigs(ClaudeConfig local, ClaudeConfig team) {
// 团队配置优先级更高
if (team.getPermissions() != null) {
local.setPermissions(team.getPermissions());
}
// 合并钩子配置
if (team.getHooks() != null) {
mergeHooks(local.getHooks(), team.getHooks());
}
}
}
八、性能优化架构
8.1 钩子缓存机制
java
// 钩子缓存
public class HookCache {
private Cache<String, List<Hook>> matcherCache;
private Cache<String, HookResult> resultCache;
public HookCache() {
matcherCache = Caffeine.newBuilder()
.maximumSize(100)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
resultCache = Caffeine.newBuilder()
.maximumSize(500)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
}
public List<Hook> getMatchingHooks(String toolName) {
return matcherCache.get(toolName, this::findMatchingHooks);
}
public HookResult getCachedResult(String key) {
return resultCache.getIfPresent(key);
}
public void cacheResult(String key, HookResult result) {
resultCache.put(key, result);
}
}
8.2 并行执行优化
java
// 并行钩子执行器
public class ParallelHookExecutor {
private ExecutorService executor;
public List<HookResult> executeParallel(List<Hook> hooks, HookContext context) {
List<CompletableFuture<HookResult>> futures = hooks.stream()
.map(hook -> CompletableFuture.supplyAsync(
() -> hook.execute(context), executor))
.collect(Collectors.toList());
return futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
}
}
九、总结
Claude钩子系统通过分层架构实现了强大的自动化能力:
| 层级 | 组件 | 职责 |
|---|---|---|
| 用户交互层 | 命令接口 | 用户输入/输出 |
| 钩子调度层 | HookScheduler | 钩子注册与时序控制 |
| 钩子执行层 | Pre/Post/Stop | 具体钩子逻辑 |
| 命令执行层 | CommandExecutor | 命令执行与结果收集 |
| 权限控制层 | PermissionManager | 安全策略执行 |
这套架构的核心价值在于将重复的开发流程自动化,让AI真正学会从错误中学习。
#ClaudeCode #钩子系统 #架构设计 #AI编程
📖 推荐阅读
如果这篇对你有帮助,以下文章你也会喜欢: