Chapter 8: Subagent — 专业化 Agent 处理复杂工作
你将构建什么
三个从真实仓库中提取的生产级 Agent:
- 架构师 Agent — 分析系统设计,输出权衡分析表(来自 ECC,使用 Opus 模型)
- 安全扫描 Agent — 在真实代码中发现 SQL 注入、XSS、缺失鉴权,带严重程度评级
- 测试编写 Agent — 生成带覆盖率目标的测试并运行验证
这些是 Everything Claude Code(architect、code-reviewer、tdd-guide)和 gstack(CEO/Designer/Engineer 角色 agent)的实际模式。不是玩具示例 -- 这些是那些 148k 和 68k 星的仓库中使用的真实模式。
附录链接:A04 Agent 架构模式 解释了 Subagent 设计背后的 ReAct 和 plan-and-execute 范式。A09 扩展思考 介绍了何时以及如何在 subagent 中使用思考预算进行更深入的分析。
研究说明:本章的多 agent 模式借鉴了 Anthropic 的 Building effective agents 指南,该指南形式化了 Claude Code 用于 subagent 调度的编排者-执行者(orchestrator-worker)架构。
Subagent 工作原理
Subagent 是运行在独立上下文窗口中的 Claude 实例。主会话启动一个 subagent 后,subagent 获得自己的工具、指令和上下文空间。只有最终结果返回。
主会话(你的对话)
|
+---> Subagent: architect
| 独立上下文 (200K)
| 工具: 仅 Read, Glob, Grep
| 读取 40 个文件,分析架构
| 返回: 500 token 的摘要
|
主会话上下文仅增长 ~500 token,而不是 40 个文件的量为什么用 Subagent 而不是在主会话中做所有事
| 主会话 | Subagent | |
|---|---|---|
| 上下文 | 共享 -- 每次文件读取都消耗限额 | 隔离 -- 读取不影响主会话 |
| 工具 | 全部可用 | 限制在你允许的范围内 |
| 模型 | 当前模型 | 可以指定不同模型 |
| 并行 | 只能串行 | 多个可同时运行 |
| 输出 | 对话中全部可见 | 只返回最终结果 |
核心优势是 上下文隔离。没有 subagent,让 Claude 审查 30 个文件会吞噬你的上下文窗口。用了 subagent,这 30 个文件存在于 subagent 的上下文中,你只收到审查报告。
GSD 称之为 "Context Rot"(上下文腐烂)问题 -- 上下文使用超过 50% 后质量下降。Subagent 是避免这个问题的方法。
Agent 定义格式
Agent 是 .claude/agents/ 中的 Markdown 文件:
---
name: my-agent
description: What this agent does
tools:
- Read
- Glob
- Grep
model: claude-sonnet-4-6
---
Agent instructions here.Frontmatter 参考
| 字段 | 类型 | 作用 |
|---|---|---|
name | string | Agent 标识符 |
description | string | 在 agent 列表中显示 |
tools | list | 可用工具白名单 |
model | string | 使用哪个模型(claude-sonnet-4-6、claude-opus-4-6 等) |
maxTurns | number | 最大对话轮数 |
isolation | string | worktree = 在独立 git worktree 中运行 |
memory | boolean | 跨调用保持知识 |
skills | list | 该 agent 可以使用的 skill |
mcpServers | list | 该 agent 可以访问的 MCP 服务器 |
工具限制的重要性
ECC 的 code-reviewer agent 限制为 Read、Glob、Grep -- 只读工具。这不是随意的。一个能 Write 或 Bash 的 reviewer 可能会"修复"代码而不是报告问题,违背了审查的目的。
gstack 用角色限制更进一步:
- CEO agent:只读。评估业务价值,不碰代码。
- Designer agent:只读。审查 UX,不改实现。
- Engineer agent:全部工具。基于 CEO 和 Designer 的反馈实现。
Demo 21: 架构师 Agent
改编自 ECC 的 architect agent -- 使用 Opus 模型进行系统设计分析,输出权衡表。
问题
你接手了一个代码库,或者项目复杂到需要理解全局。哪些模块依赖哪些?耦合热点在哪?如果重构认证系统会影响什么?你可以花一天读代码,或者让架构师 agent 在 2 分钟内完成。
构建
1. 准备真实代码库
mkdir -p ~/claude-demos/demo-21/src/{api,services,models,middleware,utils} && cd ~/claude-demos/demo-21
git init && git branch -M main
# API layer
cat > src/api/routes.js << 'EOF'
import { UserService } from '../services/user.js';
import { OrderService } from '../services/order.js';
import { authMiddleware } from '../middleware/auth.js';
import { rateLimiter } from '../middleware/rateLimit.js';
export function registerRoutes(app) {
app.post('/api/users', UserService.create);
app.get('/api/users/:id', authMiddleware, UserService.getById);
app.post('/api/orders', authMiddleware, rateLimiter, OrderService.create);
app.get('/api/orders', authMiddleware, OrderService.list);
app.delete('/api/orders/:id', authMiddleware, OrderService.delete);
}
EOF
# Services
cat > src/services/user.js << 'EOF'
import { UserModel } from '../models/user.js';
import { hashPassword, comparePassword } from '../utils/crypto.js';
import { sendEmail } from '../utils/email.js';
import { cache } from '../utils/cache.js';
export class UserService {
static async create(req, res) {
const { email, password, name } = req.body;
const existing = await UserModel.findByEmail(email);
if (existing) return res.status(409).json({ error: 'Email exists' });
const hashed = await hashPassword(password);
const user = await UserModel.create({ email, password: hashed, name });
await sendEmail(email, 'Welcome!', `Hi ${name}, welcome aboard.`);
cache.del('users:list');
return res.status(201).json(user);
}
static async getById(req, res) {
const cached = cache.get(`user:${req.params.id}`);
if (cached) return res.json(cached);
const user = await UserModel.findById(req.params.id);
if (!user) return res.status(404).json({ error: 'Not found' });
cache.set(`user:${req.params.id}`, user, 300);
return res.json(user);
}
}
EOF
cat > src/services/order.js << 'EOF'
import { OrderModel } from '../models/order.js';
import { UserModel } from '../models/user.js';
import { calculateTotal } from '../utils/pricing.js';
import { sendEmail } from '../utils/email.js';
import { cache } from '../utils/cache.js';
import { publishEvent } from '../utils/events.js';
export class OrderService {
static async create(req, res) {
const user = await UserModel.findById(req.userId);
const total = calculateTotal(req.body.items);
const order = await OrderModel.create({
userId: req.userId, items: req.body.items, total, status: 'pending'
});
await publishEvent('order.created', { orderId: order.id, userId: req.userId });
await sendEmail(user.email, 'Order Confirmed', `Order #${order.id}: $${total}`);
cache.del(`orders:${req.userId}`);
return res.status(201).json(order);
}
static async list(req, res) {
const cached = cache.get(`orders:${req.userId}`);
if (cached) return res.json(cached);
const orders = await OrderModel.findByUserId(req.userId);
cache.set(`orders:${req.userId}`, orders, 60);
return res.json(orders);
}
static async delete(req, res) {
const order = await OrderModel.findById(req.params.id);
if (!order) return res.status(404).json({ error: 'Not found' });
if (order.userId !== req.userId) return res.status(403).json({ error: 'Forbidden' });
await OrderModel.delete(req.params.id);
await publishEvent('order.deleted', { orderId: req.params.id });
cache.del(`orders:${req.userId}`);
return res.json({ success: true });
}
}
EOF
# Models, middleware, utils (abbreviated but realistic)
cat > src/models/user.js << 'EOF'
import { db } from '../utils/db.js';
export class UserModel {
static findByEmail(email) { return db.query('SELECT * FROM users WHERE email = $1', [email]).then(r => r.rows[0]); }
static findById(id) { return db.query('SELECT * FROM users WHERE id = $1', [id]).then(r => r.rows[0]); }
static create(data) { return db.query('INSERT INTO users (email, password, name) VALUES ($1,$2,$3) RETURNING *', [data.email, data.password, data.name]).then(r => r.rows[0]); }
}
EOF
cat > src/models/order.js << 'EOF'
import { db } from '../utils/db.js';
export class OrderModel {
static findById(id) { return db.query('SELECT * FROM orders WHERE id = $1', [id]).then(r => r.rows[0]); }
static findByUserId(userId) { return db.query('SELECT * FROM orders WHERE user_id = $1', [userId]).then(r => r.rows); }
static create(data) { return db.query('INSERT INTO orders (user_id, items, total, status) VALUES ($1,$2,$3,$4) RETURNING *', [data.userId, JSON.stringify(data.items), data.total, data.status]).then(r => r.rows[0]); }
static delete(id) { return db.query('DELETE FROM orders WHERE id = $1', [id]); }
}
EOF
cat > src/middleware/auth.js << 'EOF'
import { verifyToken } from '../utils/crypto.js';
export function authMiddleware(req, res, next) {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) return res.status(401).json({ error: 'No token' });
try { req.userId = verifyToken(token).userId; next(); }
catch { return res.status(401).json({ error: 'Invalid token' }); }
}
EOF
cat > src/middleware/rateLimit.js << 'EOF'
const requests = new Map();
export function rateLimiter(req, res, next) {
const key = req.userId || req.ip;
const now = Date.now();
const windowMs = 60000;
const max = 100;
const entries = (requests.get(key) || []).filter(t => t > now - windowMs);
if (entries.length >= max) return res.status(429).json({ error: 'Rate limited' });
entries.push(now);
requests.set(key, entries);
next();
}
EOF
cat > CLAUDE.md << 'EOF'
# E-commerce API
- Node.js + Express
- PostgreSQL database
- In-memory cache (should be Redis in production)
EOF
git add -A && git commit -m "feat: initial e-commerce API"2. 创建架构师 Agent
mkdir -p .claude/agents
cat > .claude/agents/architect.md << 'EOF'
---
name: architect
description: Analyzes system architecture with dependency mapping and trade-off analysis
tools:
- Read
- Glob
- Grep
model: claude-opus-4-6
---
You are a senior systems architect. Your job is to analyze the codebase and produce an architectural assessment that a team could use to make refactoring decisions.
## Analysis Process
1. **Map the module structure**: Read every file, identify layers (API, services, models, utils, middleware)
2. **Trace dependencies**: For each module, list what it imports and what imports it
3. **Identify patterns**: What architectural patterns are in use? (MVC, layered, event-driven, etc.)
4. **Find coupling hotspots**: Which modules are imported by the most other modules?
5. **Assess scalability**: What breaks first under 10x load?
## Output FormatArchitecture Assessment
System Map
[ASCII diagram showing module relationships]
Layer Analysis
| Layer | Files | Responsibilities | Dependencies |
|---|---|---|---|
| API | ... | ... | ... |
Dependency Graph
[Which modules depend on which, with counts]
Coupling Hotspots
[Modules that are imported most frequently — these are risky to change]
Trade-off Analysis
| Decision | Current Approach | Alternative | Trade-off |
|---|---|---|---|
| Caching | In-memory Map | Redis | Simple but not distributed |
Scalability Concerns
[What breaks at 10x scale and why]
Refactoring Recommendations
Priority-ordered list with estimated effort (hours, not story points).
## Rules
- Read ALL files before drawing conclusions
- Every claim must reference a specific file
- "I'd recommend" is vague — say exactly what to change and where
- Trade-off tables must include the downside of your recommendation, not just the upside
EOF3. 使用
claudeUse the architect agent to analyze this codebase and produce a full architecture assessment4. 预期终端输出
$ claude
> Use the architect agent to analyze this codebase and produce a full architecture assessment
Claude: I'll launch the architect agent to analyze your codebase.
Spawning agent: architect (claude-opus-4-6)
Tools allowed: Read, Glob, Grep
[architect] Glob: src/**/*.js -> 8 files found
[architect] Read: src/api/routes.js (16 lines)
[architect] Read: src/services/user.js (18 lines)
[architect] Read: src/services/order.js (28 lines)
[architect] Read: src/models/user.js (6 lines)
[architect] Read: src/models/order.js (6 lines)
[architect] Read: src/middleware/auth.js (7 lines)
[architect] Read: src/middleware/rateLimit.js (12 lines)
[architect] Grep: 'import' in src/ -> 24 matches
[architect] Analysis complete. Returning report.
# Architecture Assessment
## System Map
routes.js
|--- UserService --- UserModel --- db.js
| |--- crypto.js, email.js, cache.js
|--- OrderService --- OrderModel --- db.js
| |--- UserModel, pricing.js, email.js, cache.js, events.js
|--- authMiddleware --- crypto.js
|--- rateLimiter (standalone)
## Coupling Hotspots
1. utils/cache.js — imported by 2 services (will break both if changed)
2. utils/email.js — imported by 2 services (no fallback on failure)
3. models/user.js — imported by UserService AND OrderService (cross-domain coupling)
## Trade-off Analysis
| Decision | Current | Alternative | Trade-off |
|-----------------|--------------------|----------------|-------------------------------------|
| Caching | In-memory Map | Redis | Simple but not distributed |
| Rate limiting | In-memory Map | Redis + sliding | Resets on deploy, no cluster support|
| Event publishing| Direct function call| Message queue | Tightly coupled, no retry/replay |
## Refactoring Recommendations
1. Extract cache to Redis adapter (~2h) — highest impact
2. Add error handling to email sends (~1h) — silent failures are dangerous
3. Decouple OrderService from UserModel (~3h) — pass user data in, dont re-fetch
Token usage: ~4,200 tokens (agent context), ~620 tokens returned to main session.刚才发生了什么?
架构师 agent 在自己的上下文中消耗了约 4,200 tokens 读取 8 个文件并分析依赖。你的主会话只收到了约 620 token 的报告。没有 subagent 的话,这 8 次文件读取会直接消耗约 3,500 tokens 的主上下文 -- 而且你还需要自己做分析。
Demo 22: 安全扫描 Agent
问题
你需要在合并 PR 前做安全审查,但团队没有专职安全工程师。标准的"让 Claude 检查安全"方法产出模糊的结果。一个有严格输出格式和置信度过滤的专用安全 agent 能捕获真实问题、忽略噪音。
构建
cd ~/claude-demos/demo-21
cat > .claude/agents/security-scanner.md << 'EOF'
---
name: security-scanner
description: Finds security vulnerabilities with severity ratings and confidence scores
tools:
- Read
- Glob
- Grep
model: claude-sonnet-4-6
---
You are a security engineer performing a vulnerability assessment. You are thorough, precise, and you don't cry wolf.
## Vulnerability Categories
Scan for these specific vulnerability classes:
### Injection (CRITICAL)
- SQL injection: string interpolation in queries
- Command injection: user input in shell commands
- Template injection: user input in template engines
- NoSQL injection: user input in MongoDB queries
### Authentication & Authorization (CRITICAL)
- Missing auth checks on sensitive endpoints
- Weak token generation (predictable, short, no expiry)
- Password stored in plaintext
- Missing rate limiting on auth endpoints
### Data Exposure (HIGH)
- Sensitive fields in API responses (password hashes, tokens, internal IDs)
- Verbose error messages leaking stack traces
- Missing input validation allowing oversized payloads
### Configuration (MEDIUM)
- Hardcoded credentials or API keys
- Debug mode enabled
- CORS misconfiguration
- Missing security headers
## Output Rules
1. **Confidence threshold**: Only report findings with >= 80% confidence
2. **Specific locations**: Always include file:line, never "in the auth module"
3. **Severity levels**: P0 (exploit now), P1 (exploit with effort), P2 (defense-in-depth), P3 (hardening)
4. **Proof of concept**: For P0/P1, include a curl command or input that demonstrates the vulnerability
## Output FormatSecurity Assessment
Executive Summary
- Critical (P0): N findings
- High (P1): N findings
- Medium (P2): N findings
- Scanned: N files
Critical Findings (P0)
[SQLI-001] SQL Injection in user lookup
- File: src/services/user.js:15
- Confidence: 95%
- Vector:
emailparameter from request body interpolated into SQL query - Impact: Full database read/write access
- PoC: curl -X POST /api/users -d '{"email":"' OR 1=1 --"}'
- Fix: Use parameterized queriesjavascript
// Before db.query(`SELECT * FROM users WHERE email = '${email}'`) // After db.query('SELECT * FROM users WHERE email = $1', [email])
...
Passed Checks
[List security measures that ARE in place — this matters for context]
EOF测试
claudeUse the security-scanner agent to scan all files in src/ for vulnerabilities预期终端输出
$ claude
> Use the security-scanner agent to scan all files in src/ for vulnerabilities
Claude: Launching the security-scanner agent to assess your codebase.
Spawning agent: security-scanner (claude-sonnet-4-6)
Tools allowed: Read, Glob, Grep
[security-scanner] Glob: src/**/*.js -> 8 files found
[security-scanner] Read: src/api/routes.js
[security-scanner] Read: src/services/user.js
[security-scanner] Read: src/services/order.js
[security-scanner] Read: src/middleware/auth.js
[security-scanner] Read: src/middleware/rateLimit.js
[security-scanner] Grep: 'password' in src/ -> 4 matches
[security-scanner] Grep: 'req.body' in src/ -> 3 matches
[security-scanner] Grep: 'req.params' in src/ -> 4 matches
[security-scanner] Assessment complete. Returning report.
# Security Assessment
## Executive Summary
- Critical (P0): 0 findings
- High (P1): 2 findings
- Medium (P2): 3 findings
- Scanned: 8 files
## High Findings (P1)
### [AUTH-001] Missing input validation on user creation
- **File**: src/services/user.js:4
- **Confidence**: 92%
- **Vector**: No validation on email format, password length, or name content
- **Impact**: Can create users with empty passwords or invalid emails
- **PoC**: curl -X POST /api/users -d '{"email":"not-an-email","password":"","name":""}'
- **Fix**: Add input validation before processing
### [AUTH-002] Rate limiter not applied to user creation
- **File**: src/api/routes.js:8
- **Confidence**: 88%
- **Vector**: POST /api/users has no rate limiting, only POST /api/orders does
- **Impact**: Brute-force account creation, credential stuffing
- **Fix**: Add rateLimiter middleware to user creation route
## Medium Findings (P2)
### [CACHE-001] In-memory rate limiter resets on restart
- **File**: src/middleware/rateLimit.js:1
- **Confidence**: 95%
- **Vector**: Rate limit state stored in-process Map, lost on deploy/restart
- **Impact**: Rate limiting ineffective across restarts or multiple instances
### [DATA-001] Password hash may leak in user response
- **File**: src/services/user.js:8
- **Confidence**: 82%
- **Vector**: UserModel.create returns all columns including password hash
- **Impact**: Password hash exposed in 201 response body
### [ERR-001] Silent notification failure
- **File**: src/services/order.js:10
- **Confidence**: 90%
- **Vector**: sendEmail failure caught and discarded with .catch(() => {})
- **Impact**: Users never notified of order confirmation, no logging
## Passed Checks
- SQL queries use parameterized queries ($1, $2 placeholders) -- no injection risk
- Auth middleware validates JWT tokens before allowing access
- Order deletion checks ownership (userId match) -- proper authorization
- Sensitive routes protected with authMiddleware刚才发生了什么?
注意 agent 没有报告的内容:它发现了参数化 SQL 查询并正确将其分类为安全的。80% 置信度门槛过滤掉了推测性发现。这就是有用的安全审查和嘈杂审查之间的区别。
ECC 的置信度过滤
这直接来自 ECC 的 code-reviewer agent 模式:低于 80% 置信度的发现被丢弃。这个规则消除了大部分让 AI 代码审查烦人的误报。没有它,你得到 20 个"发现"其中 15 个是噪音。有了它,你得到 5 个都是真实的发现。
Demo 23: 测试编写 Agent
问题
你有没测试的代码。从零开始写测试很枯燥。测试编写 agent 读取代码,识别公开 API,生成覆盖正常路径和错误路径的测试用例,然后运行验证它们通过。
构建
cd ~/claude-demos/demo-21
cat > .claude/agents/test-writer.md << 'EOF'
---
name: test-writer
description: Generates comprehensive tests with coverage targets
tools:
- Read
- Write
- Glob
- Grep
- Bash
model: claude-sonnet-4-6
---
You are a test engineer. You write tests that catch real bugs, not tests that just increase coverage numbers.
## Process
1. **Read the target code** — understand the public API, inputs, outputs, side effects
2. **Identify test scenarios**:
- Happy path (normal usage)
- Edge cases (empty input, boundary values, null/undefined)
- Error paths (invalid input, missing dependencies, network failures)
- Security cases (injection attempts, auth bypass, oversized input)
3. **Write the tests** using the project's test framework (detect from package.json)
4. **Run the tests** to verify they pass
5. **Report coverage**
## Test Quality Rules
- Each `it()` block tests exactly ONE behavior
- Test names describe the behavior, not the implementation: "returns 404 when user not found" not "tests getById"
- Mock external dependencies (database, email, cache) — don't test third-party code
- Include at least one test per public function/method
- Error path tests are not optional — every `catch` and error return must be tested
## Output FormatTest Report
Files Created
- tests/services/user.test.js (12 tests)
- tests/services/order.test.js (15 tests)
Coverage Summary
| Module | Functions | Branches | Lines |
|---|---|---|---|
| UserService | 100% | 85% | 92% |
| OrderService | 100% | 80% | 88% |
Test Results
- Total: 27 tests
- Passed: 27
- Failed: 0
Scenarios Covered
- User creation: valid input, duplicate email, missing fields
- Order creation: valid order, invalid items, unauthorized
- Order deletion: own order, other user's order, non-existent ...
## Framework Detection
Check `package.json` for test framework:
- `vitest` -> use Vitest with `describe/it/expect`
- `jest` -> use Jest with `describe/it/expect`
- Neither -> install Vitest and configure it
If the project has no `package.json`, create one.
EOF测试
# First install a test framework
cd ~/claude-demos/demo-21
npm init -y
npm install --save-dev vitest
claudeUse the test-writer agent to generate tests for src/services/user.js and
src/services/order.js, then run them预期终端输出
$ claude
> Use the test-writer agent to generate tests for src/services/user.js and
src/services/order.js, then run them
Claude: Launching the test-writer agent. This agent has Write and Bash access
so it can create test files and run them.
Spawning agent: test-writer (claude-sonnet-4-6)
Tools allowed: Read, Write, Glob, Grep, Bash
[test-writer] Read: package.json -> vitest detected
[test-writer] Read: src/services/user.js (18 lines)
[test-writer] Read: src/services/order.js (28 lines)
[test-writer] Read: src/models/user.js (dependencies)
[test-writer] Read: src/models/order.js (dependencies)
[test-writer] Write: tests/services/user.test.js (12 test cases)
[test-writer] Write: tests/services/order.test.js (15 test cases)
[test-writer] Bash: npx vitest run --reporter=verbose
stdout | tests/services/user.test.js
UserService
create
+ returns 201 with valid user data (3ms)
+ returns 409 when email already exists (1ms)
+ hashes password before storing (2ms)
+ sends welcome email after creation (1ms)
+ invalidates user list cache (1ms)
getById
+ returns cached user when available (1ms)
+ fetches from database on cache miss (2ms)
+ returns 404 when user not found (1ms)
+ sets cache with 300s TTL on fetch (1ms)
stdout | tests/services/order.test.js
OrderService
create
+ creates order with correct total (2ms)
+ publishes order.created event (1ms)
+ sends confirmation email to user (1ms)
+ invalidates order cache for user (1ms)
list
+ returns cached orders when available (1ms)
+ fetches from database on cache miss (2ms)
+ sets cache with 60s TTL (1ms)
delete
+ returns 404 when order not found (1ms)
+ returns 403 when user does not own order (1ms)
+ deletes order and publishes event (2ms)
+ invalidates order cache after deletion (1ms)
Test Files 2 passed (2)
Tests 20 passed (20)
Duration 0.34s
[test-writer] Complete. Returning report.
# Test Report
## Files Created
- tests/services/user.test.js (9 tests)
- tests/services/order.test.js (11 tests)
## Test Results
- Total: 20 tests
- Passed: 20
- Failed: 0刚才发生了什么?
与只读 agent 的关键区别:测试编写者有 Write 和 Bash 权限,因为它的工作需要创建文件和执行命令。工具限制应该匹配 agent 的角色 -- 不是一律限制。
常见问题排查
Subagent 超出工具白名单
$ claude
> Use the security-scanner agent to fix the SQL injection in user.js
Claude: Launching security-scanner agent...
[security-scanner] Attempted to use tool: Write
Error: Tool 'Write' is not in the allowed list for agent 'security-scanner'.
Allowed tools: Read, Glob, Grep
[security-scanner] I found the SQL injection issue but I cannot fix it directly.
My tools are restricted to read-only access. Here is the finding and
recommended fix for you to apply manually...发生了什么:你让一个只读 agent 做修改。Agent 尝试使用 Write 但工具白名单拦截了。这是设计预期的行为 -- 安全扫描器应该报告问题,而不是修复它们。
修复:自己应用修复,或者使用有写权限的 agent(如测试编写者)来处理需要代码变更的任务。如果你想要一个"安全修复者"agent,单独创建一个在 tools 列表中包含 Write 的。
模型不匹配
$ claude
> Use the architect agent to quickly check if routes.js looks correct
Claude: Launching architect agent...
Spawning agent: architect (claude-opus-4-6)
[architect] Reading src/api/routes.js...
[architect] Reading src/services/user.js...
[architect] Reading src/services/order.js...
[architect] Reading all remaining 5 files...
[architect] Analyzing full dependency graph...
(30 seconds later)
# Full Architecture Assessment
## System Map...
## Layer Analysis...
## Dependency Graph...
[... 800 token detailed report for a simple question ...]发生了什么:你用 Opus 驱动的架构师 agent 来回答一个快速问题。Opus 更慢,产出的分析比需要的更深入。你等了 30 秒才拿到一个快速检查就够了的报告。
修复:为任务匹配合适的模型。快速检查直接问主会话(使用你当前的模型,通常是 Sonnet)。把架构师 agent 留给完整的架构审查。你也可以创建一个轻量级的 quick-review agent 用 Sonnet 来快速回答:
---
name: quick-review
model: claude-sonnet-4-6
tools: [Read, Glob, Grep]
---
Give brief, focused answers. No full reports unless asked.Subagent 超时
$ claude
> Use the architect agent to analyze this monorepo
Claude: Launching architect agent...
Spawning agent: architect (claude-opus-4-6)
[architect] Glob: src/**/*.js -> 847 files found
[architect] Read: src/api/routes/index.js
[architect] Read: src/api/routes/auth.js
[architect] Read: src/api/routes/users.js
... (reading files one by one) ...
Warning: Agent 'architect' reached maximum turns (25). Returning partial results.
# Architecture Assessment (PARTIAL)
## System Map
Only analyzed 120 of 847 files before reaching turn limit.发生了什么:Agent 试图逐个读取大型 monorepo 中的所有 847 个文件,在完成之前就达到了 maxTurns 限制。
修复:如果需要可以在 agent 定义中添加 maxTurns,但更重要的是限定 agent 的任务范围。不要说"分析这个 monorepo",而是说"分析 src/api/ 和 src/services/ 目录"。你也可以更新 agent 指令让它优先广度而非深度:
## For large codebases (>100 files)
1. Glob to map the full structure
2. Read only entry points and high-fan-in modules
3. Use Grep to trace dependencies without reading every file
4. Sample 2-3 files per directory instead of reading allAgent 设计原则
来自 ECC:模型选择
ECC 为不同 agent 使用不同模型:
- Architect:Opus(深度分析、权衡推理)
- Code reviewer:Sonnet(速度快,模式匹配够用)
- TDD guide:Sonnet(迭代式,需要速度而非深度)
匹配模型到任务。不要什么都用 Opus -- 更慢更贵。不要用 Haiku 做架构分析 -- 会遗漏细微差别。
来自 gstack:角色化 Agent
gstack 的角色系统分配不同的 视角,不只是不同的工具:
- CEO 审查:"值得做吗?业务影响是什么?"
- Design 审查:"UX 流程合理吗?可访问性如何?"
- Engineering 审查:"架构合理吗?风险在哪?"
你可以将此应用到自己的 agent 上。上面的安全扫描器是一个"工程审查"agent。你可以添加一个从用户视角评估功能的"产品审查"agent。
Worktree 隔离
对于需要做实验性修改的 agent:
---
name: refactor-experiment
isolation: worktree
tools:
- Read
- Write
- Edit
- Bash
---Agent 在独立的 git worktree 中工作。修改不影响你的工作目录。实验成功就合并,失败就删除 worktree。
练习:构建 3-Agent 审查管线
创建三个从不同视角审查代码的 agent:
- product-reviewer:只读。从用户角度评估。"这个功能合理吗?直觉吗?"
- security-reviewer:只读。使用 Demo 22 的安全扫描模式。
- performance-reviewer:只读。查找 N+1 查询、不必要的分配、缺失缓存。
在同一代码库上运行全部三个。比较发现 -- 应该互补而非重叠。
成功标准
- [ ] 三个 agent 文件存在于
.claude/agents/ - [ ] 每个有合适的工具限制(全部只读)
- [ ] 每个产出结构化报告,带具体 file:line 引用
- [ ] 发现在 agent 之间不显著重叠
- [ ] 可以在单个 Claude 会话中运行并获得组合视图
知识检测
总结
Subagent 让 Claude Code 从单一对话扩展为专家团队。本章的三个模式 -- 架构师、安全扫描、测试编写 -- 覆盖了最常见的需求。
要点:
- 上下文隔离是使用 subagent 的主要原因 -- 避免 GSD 的 "Context Rot"(上下文使用超过 50% 后质量下降)
- 工具限制强制 agent 的角色 -- 能 Write 的 reviewer 不是 reviewer
- 模型选择很重要 -- Opus 用于深度,Sonnet 用于速度
- ECC 的 80% 置信度门槛消除审查中的误报
- Worktree 隔离让 agent 无风险地实验
下一章:Chapter 9: Agent 团队 -- 编排多个 agent 并行处理复杂任务。