第 09 期 | 精准的 Prompt Scoping(作用域边界控制)

更新于 2026/4/5

🎯 学习目标

学完本期你将掌握:

  1. 为什么 Claude 有时会"越界"修改不相关的代码
  2. 如何通过文件路径、目录限定来约束修改范围
  3. Subagent 作用域隔离的进阶用法
  4. --allowedTools / --disallowedTools 的精确控制

📖 核心概念讲解

9.1 问题:Claude 为什么会"越界"?

当你说"修复这个 bug",Claude 可能:

  • ✅ 修改了目标文件 ← 期望行为
  • ❌ 顺手"优化"了其他无关文件 ← 越界
  • ❌ 重构了你没提到的模块 ← 过度自信

这是因为 Claude 默认拥有对整个项目的读写权限。没有明确的边界指令时,它可能"好心办坏事"。

9.2 Scoping 三层控制法

┌─ Layer 1: Prompt 级别 ─────────────────────────┐
│  "只修改 src/auth/login.ts,不要动其他文件"     │
│  → 最简单,适合一次性指令                        │
├─ Layer 2: Settings 级别 ──────────────────────── │
│  .claude/settings.json → permissions.deny       │
│  → 持久化保护,适合团队共享                      │
├─ Layer 3: CLI 级别 ───────────────────────────── │
│  --allowedTools "Read" "Edit(src/auth/**)"      │
│  → 启动时限定,适合脚本化                        │
└──────────────────────────────────────────────────┘

💻 模拟 Claude TUI 交互

场景 1:未限定作用域 — Claude 越界

> 修复用户登录时密码验证的 bug

╭─ Claude ─────────────────────────────────────────────╮
│                                                      │
│  🔍 Tool: Grep ("password" across src/**)            │
│  🔍 Tool: Read (src/auth/login.ts)                   │
│  🔍 Tool: Read (src/auth/register.ts)                │
│  🔍 Tool: Read (src/utils/validation.ts)             │
│                                                      │
│  找到了 bug!密码比对时缺少 await。                   │
│                                                      │
│  ⚙️ Tool: Edit → src/auth/login.ts                   │
│  ╭─ DIFF ─────────────────────────────────────╮      │
│  │ - if (bcrypt.compare(password, user.hash)) │      │
│  │ + if (await bcrypt.compare(password,       │      │
│  │ +     user.hash))                           │      │
│  ╰─────────────────────────────────────────────╯      │
│  ✅ 这是正确的修复!                                  │
│                                                      │
│  ⚙️ Tool: Edit → src/utils/validation.ts             │
│  ╭─ DIFF ─────────────────────────────────────╮      │
│  │ - // TODO: add password strength check     │      │
│  │ + export function checkPasswordStrength(   │      │
│  │ +   password: string): PasswordStrength {  │      │
│  │ +   // ... 40 行新代码 ...                 │      │
│  │ + }                                         │      │
│  ╰─────────────────────────────────────────────╯      │
│  ⚠️ 这个修改超出了你的请求范围!                      │
│                                                      │
│  ⚙️ Tool: Edit → src/auth/register.ts                │
│  ╭─ DIFF ─────────────────────────────────────╮      │
│  │ + import { checkPasswordStrength }         │      │
│  │ +   from '../utils/validation';             │      │
│  │ + // 注册时检查密码强度                     │      │
│  │ + if (checkPasswordStrength(pw)             │      │
│  │ +   === 'weak') { ... }                    │      │
│  ╰─────────────────────────────────────────────╯      │
│  ⚠️ 又改了一个文件!                                  │
│                                                      │
╰──────────────────────────────────────────────────────╯

场景 2:精确限定作用域 — 只动目标文件

> 修复 src/auth/login.ts 中密码验证的 bug。
  只修改这一个文件,不要触碰其他任何文件。

╭─ Claude ─────────────────────────────────────────────╮
│                                                      │
│  🔍 Tool: Read (src/auth/login.ts)                   │
│                                                      │
│  找到问题:第 34 行 bcrypt.compare 缺少 await。      │
│                                                      │
│  ⚙️ Tool: Edit → src/auth/login.ts                   │
│  ╭─ DIFF ─────────────────────────────────────╮      │
│  │ - if (bcrypt.compare(password, user.hash)) │      │
│  │ + if (await bcrypt.compare(password,       │      │
│  │ +     user.hash))                           │      │
│  ╰─────────────────────────────────────────────╯      │
│                                                      │
│  ✅ 修复完成。只修改了 src/auth/login.ts。            │
│                                                      │
│  💡 另外我注意到 validation.ts 中有一个               │
│  TODO 关于密码强度检查,要不要我另起一个              │
│  会话来处理?                                         │
│                                                      │
╰──────────────────────────────────────────────────────╯

💻 代码演示:CLI 级别的精确控制

# 只允许读取和编辑 src/auth/ 目录
claude --allowedTools "Read" "Glob" "Grep" "Edit(src/auth/**)"

# 禁止执行任何 bash 命令(纯编辑模式)
claude --disallowedTools "Bash"

# 限制工具 + 限制轮次(CI/CD 中的安全运行)
claude -p \
  --allowedTools "Read" "Glob" "Grep" \
  --max-turns 5 \
  "审查 src/payment/ 目录的安全性"

# 只允许执行特定 bash 命令
claude --allowedTools \
  "Read" "Glob" "Grep" \
  "Bash(npm test *)" \
  "Bash(npm run lint)"

Settings 文件级别的保护

// .claude/settings.json — 项目级
{
  "permissions": {
    "deny": [
      "Write(.env*)",
      "Edit(.env*)",
      "Write(prisma/migrations/**)",
      "Edit(prisma/migrations/**)",
      "Bash(rm -rf *)",
      "Bash(DROP *)",
      "Bash(sudo *)"
    ]
  }
}

💡 Prompt Scoping 技巧速查

❌ 模糊指令(容易越界):
  "修复登录 bug"
  "优化性能"
  "添加错误处理"

✅ 精确指令(作用域明确):
  "修复 src/auth/login.ts 第 34 行的 bcrypt.compare 缺少 await"
  "只优化 src/api/search.ts 的数据库查询性能,不改其他文件"
  "给 src/routes/payment.ts 的 createOrder 函数添加 try-catch"

🔧 涉及的 CLI Flags

Flag 作用 示例
--allowedTools 白名单限制可用工具 "Read" "Edit(src/**)"
--disallowedTools 黑名单禁用工具 "Bash" "Write"
--max-turns 限制最大执行轮次 --max-turns 3
--add-dir 添加额外目录访问 --add-dir ../shared

📝 本期要点回顾

  1. Claude 默认对整个项目有读写权限,需要 主动限制作用域
  2. Prompt 级别:直接在指令中说明"只修改 X 文件"
  3. Settings 级别:用 permissions.deny 保护敏感文件
  4. CLI 级别:用 --allowedTools 做白名单限制
  5. 好 Prompt 的核心:具体文件名 + 具体行为 + 明确边界

🔗 参考资料