今天咱们撸起袖子,整一个“只能瞪眼、不能动手”的代码审查小助手。

为啥先玩“只读款”?

因为给权限画红线,是子代理的“保命符”。代码审查这活儿就像监考:你可以把卷子翻个底朝天,但要是敢偷偷帮考生改答案,那就不是监考,是共犯!要是审查工具一边“哦我看懂了”,一边顺手把 bug 抹平,那还审个啥?直接改名叫“代码整容师”得了!

项目场景1:代码审查

一个后端开发项目中,我们刚刚好写完了一段认证逻辑,想让 Claude Code 帮你审查一下有没有安全问题。

你在主对话中说:“帮我检查一下 auth.js 的安全性”。

Claude 完成这个任务当然不在话下,它读了你的代码,发现了硬编码的密钥,然后顺手帮你改成了环境变量读取。等等,发现哪里不对了么?你只是想让它看看有没有问题,并没有让它改啊!而且,它的“好心修复”可能引入了新的问题——比如你根本不想配置任何环境变量。

这就是为什么我们需要只读型子代理:

1
2
3
代码审查员的职责边界:
✅ 可以做:读取代码、分析问题、输出报告
❌ 不可做:修改文件、执行可能有副作用的命令

从工程痛点到子代理设计:一种思维方式的转变

在我们动手写配置之前,先停下来想一个问题:我们为什么要创建这个子代理?

这个问题的本质

1
工程痛点 → 分析缺什么能力 → 设计职责边界 → 选择工具组合 → 配置子代理
1
2
3
4
5
6
7
8
9
code-reviewer/
├── src/
│ ├── auth.js # 认证模块(包含安全问题)
│ ├── database.js # 数据库模块(包含 SQL 注入风险)
│ └── api.js # API 模块(包含不良实践)
├── .claude/
│ └── agents/
│ └── code-reviewer.md # 代码审查子代理配置
└── README.md

1、创建代码审查子代理

首先是创建.claude/agents/ 目录,然后在其中创建代码审查子代理的配置文件code-reviewer.md:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
---
name: code-reviewer
description: Review code changes for quality, security, and best practices. Proactively use this after code modifications.
tools: Read, Grep, Glob, Bash
model: sonnet
---

You are a senior code reviewer with expertise in security and software engineering best practices.

## When Invoked

1. **Identify Changes**: Run `git diff` or read specified files
2. **Analyze Code**: Check against multiple dimensions
3. **Report Issues**: Categorize by severity

## Review Dimensions

### Security (Critical Priority)
- SQL injection vulnerabilities
- XSS vulnerabilities
- Hardcoded secrets/credentials
- Authentication/authorization issues
- Input validation gaps
- Insecure cryptographic practices

### Performance
- N+1 query patterns
- Memory leaks
- Blocking operations in async code
- Missing caching opportunities

### Maintainability
- Code complexity
- Missing error handling
- Poor naming conventions
- Lack of documentation for complex logic

### Best Practices
- SOLID principles violations
- Anti-patterns
- Code duplication
- Missing type safety

## Output Format

\```markdown
## Code Review Report

### Critical Issues
- [FILE:LINE] Issue description
- Why it matters
- Suggested fix

### Warnings
- [FILE:LINE] Issue description
- Recommendation

### Suggestions
- [FILE:LINE] Improvement opportunity

### Summary
- Total issues: X
- Critical: X | Warnings: X | Suggestions: X
- Overall risk assessment: HIGH/MEDIUM/LOW

### Guidelines
- Prioritize security issues
- Be specific about locations (file:line)
- Provide actionable fix suggestions
- Focus on the changes, not existing code (unless security-critical)
- Keep explanations concise

解释一下这个子代理配置的设计:

name:code-reviewer - 这是一个用户和 Claude 都能直观理解的简洁、语义化的名字。

description:Review code changes for quality, security, and best practices. Proactively use this after code modifications.(审阅代码变更,把控质量、安全与最佳实践。每次改动代码后,建议主动执行。)

  • 说明做什么:审查代码质量、安全、最佳实践。
  • 说明什么时候用:代码修改后主动使用。
  • “Proactively” 关键词则告诉 Claude 可以主动调用。

tools 包括 Read,Grep,Glob,Bash 四种,此处是代码审查子代理最为关键的设计决策部分。

Claude_Code_tools_usage

model:选择 sonnet,这是根据模型的能力和任务的特点权衡而定的。

  • sonnet 代码审查需要较强的分析能力✅
  • haiku 可能漏掉细微的安全问题❌
  • opus 对于审查任务来说成本太高

2、运行代码审查

有两种调用方式:

显式调用

直接进入项目目录,在 Claude Code 中输入:

1
让 code-reviewer 审查 src/ 目录下的所有代码

code-reviewer 子代理被自动激活,或者更具体一些:

1
用 code-reviewer 审查 src/auth.js 文件

自动调用

当我们按照上面的结构在项目中配置好子代理之后,不需要显式指定 code-reviewer。Claude 会自动选择使用 code-reviewer:

1
用子代理帮我看看代码有没有安全问题

但是下面这样说,有可能无法触发子代理:

1
2
审查一下最近的改动 (因为没有明确提子代理)
检查一下代码质量(因为没有明确提子代理)

运行审查后,你会得到类似这样的报告:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
## Code Review Report

### Critical Issues

- [auth.js:7-8] Hardcoded credentials in source code
- SECRET_KEY and API_KEY are exposed in plain text
- These should be loaded from environment variables
- Anyone with code access can see these secrets

- [auth.js:68] Use of eval() with user input
- processUserConfig() uses eval() which allows code injection
- Attacker could execute arbitrary code
- Use JSON.parse() instead for config parsing

- [database.js:21-23] SQL Injection vulnerability
- findUser() directly concatenates username into SQL query
- Attacker could input: `' OR '1'='1` to bypass authentication
- Use parameterized queries instead

- [database.js:27-34] Multiple SQL Injection points
- searchProducts() has two injection points
- Both searchTerm and category are directly interpolated

- [auth.js:24-27] Plain text password comparison
- checkPassword() compares passwords as plain strings
- Passwords should be hashed with bcrypt/argon2

### Warnings

- [auth.js:11-14] Weak password validation
- Only checks length >= 6
- Should require complexity (uppercase, numbers, special chars)

- [auth.js:50] Password included in response
- login() returns user.password in the response object
- Sensitive data should never be sent to client

- [database.js:54-55] Sensitive data logging
- createUser() logs the entire userData including password
- Passwords should never appear in logs

### Suggestions

- [auth.js:58-62] Missing token expiration check
- verifyToken() doesn't validate timestamp
- Tokens should have TTL (time-to-live)

### Summary
- Total issues: 11
- Critical: 5 | Warnings: 3 | Suggestions: 3
- Overall risk assessment: **HIGH**

有的时候,我会在交互过程的提示语中,告诉 Claude:“请把整理好的分析报告以 Markdown 的格式保存“,或者”生成分析日志并按照时戳命名后保存。”—— 你也可以增强子代理的配置文件让它直接这样做。

3、验证权限边界

现在,让我们验证审查器确实无法修改代码。在 Claude Code 中说:

1
让 code-reviewer 修复 auth.js 中的硬编码密钥问题

你会看到类似这样的响应:

1
2
code-reviewer 只有读取权限,无法修改文件。
如需修复问题,请使用其他方式或直接请求修改。

4、扩展审查维度

你可以根据项目需求扩展到其它的审查维度,例如你的项目使用react,可以在配置中添加框架特定检查:

1
2
3
4
5
6
### React Specific
- Missing key props in lists
- Unnecessary re-renders
- Direct state mutation
- Missing cleanup in useEffect
- Prop drilling anti-pattern

还可以添加如下项目规范审查标准:

1
2
3
4
5
### Team Conventions
- File naming: should use kebab-case
- Export style: should use named exports
- Import order: third-party → internal → relative
- Max file length: 300 lines

也可以添加如下合规性检查标准:

1
2
3
4
5
### Compliance
- PII data handling
- GDPR consent checks
- Audit logging requirements
- Data retention policies

项目场景2:真实工程场景延伸

至此我们已经掌握了代码审查子代理的创建和使用,但如果你以为“只读型子代理”就只能做代理审查,那就把它想窄了。 接下来就看一个真实线上事故场景:

他让 AI 按照 SDD 设计了存量系统中一个老功能的链路迭代,代码开发完成并上线了。但在线上,用户端 7 秒拿不到操作结果——爆雷了。原因是什么?AI 并不知道这条链路上的改动会影响到哪些下游服务,也不知道端用户的体验 SLA 是多少。代码本身没有 bug,但全链路的影响面被忽略了。

这个案例的本质是什么?不是 AI 写错了代码,而是 AI 没有被赋予“在设计阶段审视影响面”的职责和上下文。

把工程经验翻译成子代理设计
现在,让我们用前面学到的“痛点驱动设计”思维来分析这个场景:

Claude_Code_paint_point_drive

设计一个影响面分析子代理

基于上述分析,我们可以设计这样一个子代理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
---
name: impact-analyzer
description: Analyze the impact scope of code changes on the full call chain. Use this before submitting technical designs or PRs for existing systems.
tools: Read, Grep, Glob, Bash
model: sonnet
permissionMode: plan
skills:
- chain-knowledge # 链路拓扑和 SLA 约束
- recent-incidents # 近期事故记录(如有)
---

You are a senior system architect specializing in impact analysis for legacy/existing systems.

## Your Mission

When code changes are proposed for an existing system, analyze:
1. Which call chains are affected by this change
2. What downstream services may be impacted
3. Whether any SLA/performance constraints could be violated
4. What edge cases the change author might not have considered

## Analysis Process

1. **Read the changed files** to understand the modification
2. **Trace call chains**: Use Grep to find all callers of modified functions/APIs
3. **Check integration points**: Look for HTTP calls, message queue producers/consumers, database queries that touch affected tables
4. **Cross-reference with preloaded chain knowledge**: Use the chain topology and SLA constraints that have been loaded into your context at startup
5. **Assess SLA impact**: Flag any path where added latency or changed behavior could affect user-facing response times

## Output Format

~~```markdown
## Impact Analysis Report

### Changed Components
- [FILE:LINE] Description of change

### Affected Call Chains
- Chain 1: ServiceA → ServiceB → **ChangedModule** → ServiceC → UserEndpoint
- SLA risk: The added DB query may add ~200ms to a chain with 3s SLA budget
- Current budget usage: ~2.5s (estimated)
- Remaining headroom: ~500ms → may be insufficient after change

### Downstream Impact
- [Service/Module] How it's affected
- Severity: HIGH/MEDIUM/LOW

### Unreviewed Dependencies
- Components that depend on the changed interface but were not analyzed
- Reason: outside current repo / insufficient context

### Recommendations
- [ ] Verify SLA headroom with load test
- [ ] Notify downstream team X about interface change
- [ ] Add timeout/circuit breaker for the new external call

##Important Constraints
- You are READ-ONLY. Never suggest running modifications.
- If you lack information about the full chain, explicitly say so. Don't guess.
- Always flag when your analysis is incomplete due to missing cross-service context.

配合 Skill 沉淀链路知识

对于存量系统,有时候维护一个你的接口在整个链路如何串联起来的知识库,这样 AI 去改动现有代码的时候,就知道帮你排查这个改动影响了什么链路。

这就是 Skill 的用武之地 —— 把链路知识结构化沉淀下来。 注意看 impact-analyzer 配置中的 skills 字段:

1
2
3
skills:
- chain-knowledge # 链路拓扑和 SLA 约束
- recent-incidents # 近期事故记录(如有)

子代理启动时,Claude Code 会把对应 Skill 的完整内容注入到子代理的上下文中。子代理不需要在分析过程中“去读”某个文件,链路知识在它“开始工作之前”就已经在脑子里了。

对比下面两种实现方式:

子代理不会自动继承主对话中可用的 Skill。你必须在 skills 字段中显式列出需要的 Skill 名称,它才会被注入。

下面是 chain-knowledge Skill 的内容示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# .claude/skills/chain-knowledge.md

## 用户下单链路
用户端App → API Gateway (SLA: 5s) → OrderService.createOrder() (SLA: 2s) → InventoryService.reserve() (SLA: 500ms) → PaymentService.preAuth() (SLA: 1s) → NotificationService.push() (async, 不阻塞主链路) → 返回订单确认

## 关键 SLA 约束

| 链路 | 端到端 SLA | 备注 |
|------|-----------|------|
| 用户下单 | 5s | 超时则展示"处理中"兜底页 |
| 商品搜索 | 1s | P99 要求 |
| 支付回调 | 30s | 异步可容忍 |

## 最近事故记录

- 2024-12: OrderService 增加风控调用,链路增加 800ms,触发 5s SLA 告警
- 根因:风控服务未配置超时,极端情况 3s+
- 修复:增加 500ms 超时 + 降级策略

这样,当 impact-analyzer 子代理启动时,上述知识已经通过 skills 字段注入到上下文中。子代理可以直接:

  1. 引用链路拓扑判断改动影响的路径
  2. 根据 SLA 约束判断改动是否可能超时
  3. 参考历史事故避免重蹈覆辙

这就是 SubAgent + Skill 的组合威力:子代理通过 skills 字段获得领域知识,通过工具获得分析能力。 知识注入是系统级的(不依赖 prompt 提示),分析能力是工具级的(受 tools 和 permissionMode 约束)。两者结合,才会让 AI 既知道又能做。

工程决策:什么时候该创建子代理?

创建子代理是有成本的——需要设计、维护、调试,我来给你提供一个实用的决策框架。

该创建子代理的场景

  • 任务需要“只读”或“只写”限制:需要创建子代理,权限隔离是子代理的核心价值。
  • 输出噪声很高(日志、测试结果):需要创建子代理,子代理可在独立上下文中过滤噪声。
  • 任务需要领域专家角色:视情况而定,如果 prompt 很长且复用频繁,子代理优于每次手写。
  • 任务需要跨服务、跨仓库:子代理可以被赋予特定的全局分析上下文。

只是想在特定事件触发时执行,Hook 更合适。

不该创建子代理的场景

  • 一次性任务:直接在主对话中完成即可。
  • 简单的 prompt 模版:直接用 Skill 文件,不需要独立上下文和工具隔离。
  • 自动化触发动作:用 Hook,不需要 AI 分析判断。