【Agents】自定义子代理进阶:沙盒隔离

​ 上一篇你已经会造子代理了。但用过几次就会发现一个问题:子代理直接改你的工作区,改崩了没有后悔药。

​ 你让一个子代理"试试用策略模式重构这段 switch-case",它要是改崩了,你的代码也崩了。你得盯着它每一步操作,随时准备撤销。想让它放手大胆试?你不敢。

isolation: worktree 解决的就是这件事,给子代理一个沙盒,改坏了扔掉就行,你的主工作区纹丝不动。

​ 上图是整篇文章的核心对比。左边是基础模式:子代理直接在你的工作区里改文件,你得盯着,改崩了就是你的事。右边是进阶模式:子代理在隔离的沙盒里工作,你不用等也不用担心,完成后收到通知再决定要不要合并。

一、沙盒模式:isolation: worktree

1.1 为什么需要沙盒

​ 先看一个真实场景。你在做一次性能优化,数据库查询层有两个方案可选:方案 A 是给现有查询加缓存,方案 B 是换用批量查询重写整个模块。你不确定哪个更好,想让 Claude 两个都试一下,跑跑基准测试再决定。

​ 如果没有沙盒,你只能串行试:先让 Claude 改成方案 A,跑测试,看结果,然后 git stashgit checkout 恢复现场,再试方案 B。更糟的情况是方案 A 改到一半你发现思路不对,现在代码处于一个"半成品"状态,回退都不利索。

沙盒模式让每个子代理在独立的 Git Worktree 中工作。 它有自己的工作目录、自己的分支,和你当前的代码物理隔离。子代理可以大刀阔斧地改,改成什么样都不影响你的主工作区。满意了就合并,不满意就丢弃。就像在草稿纸上画方案,不满意揉了扔掉,正稿纹丝不动。

​ 上图展示了沙盒隔离的核心结构。上层是你的主工作区(main 分支),下层是子代理的沙盒(worktree 分支)。两者拥有相同的文件结构,但物理上是不同的目录,子代理在下层怎么改都不影响上层。它们共享同一个 .git 对象库,所以磁盘开销很小,不是完整 clone。

1.2 怎么配置

​ 在项目根目录的.claude/agents目录下创建refactor-explorer.md文件,只需要在子代理的 frontmatter 中加一行:

markdown 复制代码
---
name: refactor-explorer
description: 探索性重构方案,在沙盒中独立尝试不改动主工作区
model: sonnet
isolation: worktree
tools:
  - Read
  - Glob
  - Grep
  - Edit
  - Bash
---

你是一个重构探索员。收到重构需求后:

1. 先分析当前代码结构和依赖关系
2. 提出重构方案并直接实施
3. 修改完成后运行现有测试,确保不破坏功能
4. 如果测试失败,分析原因并修复
5. 最后给出改动摘要:改了哪些文件、为什么这么改、测试结果

大胆尝试,不需要保守------你在沙盒中工作,不会影响主工作区。

​ 关键就是 isolation: worktree 这一行。有了它,这个子代理每次被调用时,都会自动在独立的 Git Worktree 中运行。

前置条件:项目必须是 Git 仓库。 沙盒模式基于 git worktree,如果你的项目还没有初始化 Git(没有 .git 目录),子代理启动时会直接报错。确保至少执行过 git init 并有一次提交。另外,worktree 要求当前不能处于 rebase 或 merge 冲突状态,Git 需要一个干净的基点来创建新的工作树。

二、生命周期:从创建到清理

​ 当主对话调用一个 worktree 隔离的子代理时,背后会经历五个阶段:

​ 上图展示了 worktree 隔离子代理从创建到清理的完整过程。

2.1 创建 Worktree

​ 子代理启动时,Claude Code 自动执行 git worktree add,在 .claude/worktrees/ 下创建一个新的工作目录,并从当前分支(通常是 main)拉出一个新分支。整个过程对你完全透明------你不需要手动操作任何 Git 命令。

​ 新创建的 worktree 是当前仓库的完整副本 ,但和主工作区物理隔离。它们共享同一个 .git 对象库,所以磁盘开销很小,不是 git clone,不会复制历史记录。

2.2 子代理在沙盒中工作

​ 子代理的所有文件操作,例如Read、Edit、Bash都发生在 worktree 目录中。它看到的文件树和你的主工作区一模一样(因为是从同一个 commit checkout 出来的),但它做的任何修改都不会影响你的主目录。

​ 这意味着你可以在提示词里写"大胆尝试",因为试错成本为零。子代理可以删文件、重写模块、改配置,怎么折腾都行。

2.3 提交改动

​ 子代理完成工作后,把改动提交到 worktree 分支上。这个提交只存在于 worktree 的分支里,不会出现在你的主分支上。

2.4 你来决定:合并还是丢弃

​ 这是整个流程中唯一需要你决策的环节。子代理完成后会返回一个摘要,告诉你它做了什么改动、测试结果如何。同时你会拿到 worktree 的路径和分支名。

​ 你有三个选择:

bash 复制代码
# 方案满意,合并到主分支
git merge worktree-refactor-explorer-abc123

# 想看看具体改了什么再决定
git diff main...worktree-refactor-explorer-abc123

# 方案不行,直接丢弃
git branch -D worktree-refactor-explorer-abc123

2.5 自动清理

​ 如果子代理工作过程中没有产生任何改动(比如它分析完发现不需要改),worktree 会被自动清理,目录删除、分支移除,不留任何痕迹。

​ 如果有改动,worktree 会保留,等你 merge 或手动删除后再清理。

三、实战:A/B 方案对比

​ 回到开头的性能优化场景。有了沙盒模式,你可以同时让两个子代理探索两个方案:

复制代码
同时启动两个 refactor-explorer:

方案 A:@refactor-explorer 给 UserRepository 的 findByIds 方法加 Redis 缓存,
缓存 key 用 user:{id},TTL 5 分钟。改完跑 benchmark。

方案 B:@refactor-explorer 把 UserRepository 里所有逐条查询改成批量查询,
用 WHERE id IN (...) 替代循环中的 WHERE id = ?。改完跑 benchmark。	

​ 两个子代理各自在独立的 worktree 中动手改代码、跑测试。你不用等,也不用担心它们互相干扰。等两个都完成后,对比 benchmark 结果,选一个合并,丢掉另一个。

3.1 基线代码

​ 演示用的基线文件是 test-repo/user_repository.py,核心结构如下:

python 复制代码
class UserRepository:
    def find_by_id(self, user_id):
        """单条查询------每次都新建连接、执行一条 SELECT。"""
        conn = self._get_conn()
        try:
            row = conn.execute(
                "SELECT id, name, email, department FROM users WHERE id = ?",
                (user_id,),
            ).fetchone()
            ...
        finally:
            conn.close()

    def find_by_ids(self, user_ids):
        """⚠️ N+1 问题:循环调用 find_by_id,200 个 ID = 200 次建连 + 200 次查询。"""
        results = []
        for uid in user_ids:
            user = self.find_by_id(uid)  # 每个 ID 独立建连 + 查询
            if user:
                results.append(user)
        return results

​ 文件还包含一个 init_db() 函数(初始化 1000 条测试数据)和 benchmark_find_by_ids() 函数(多轮计时 + 统计),两个子代理都会复用这套基础设施来跑 benchmark。

​ 两个子代理拿到的是同一份基线文件,但各自在独立的 worktree 中修改,互不可见。下面是实际跑出来的结果,基线查询 200 个用户 ID,平均耗时约 18ms。

3.2 方案 A 结果:Redis 缓存

​ 子代理 A 的 worktree 路径为 .claude/worktrees/agent-ac47fc19/,分支名 worktree-agent-ac47fc19。它对 user_repository.py 做了以下改动:

  • 新增 FakeRedis / FakePipeline 类(用 dict 模拟 Redis,接口兼容 redis-py,生产环境可直接替换为真实 Redis)

  • UserRepository.__init__ 新增可选参数 redis_client,为 None 时退化为原始 N+1(向后兼容)

  • 重写 find_by_ids:MGET 批量查缓存 → 未命中的查 DB → pipeline 批量写缓存(key user:{id},TTL 300s)

  • 更新 __main__ 块:分别跑基线、冷启动、热缓存三组 benchmark

    Benchmark: BASELINE (N+1 逐条查询,无缓存)
    Avg time : 20.28 ms

    Benchmark: 方案A 冷启动(首次,缓存未命中)
    Avg time : 23.42 ms ← 比基线略慢,额外做了 MGET + JSON 序列化 + pipeline SET

    Benchmark: 方案A 热缓存(后续轮次,全命中)
    Avg time : 0.70 ms ← 28.9x 加速

3.3 方案 B 结果:批量查询 WHERE id IN

​ 子代理 B 的 worktree 路径为 .claude/worktrees/agent-a4f8ac9d/,分支名 worktree-agent-a4f8ac9d。它对 user_repository.py 做了以下改动:

  • 重写 find_by_ids:用一条 SELECT ... WHERE id IN (?, ?, ...) 替代循环,单连接单查询

  • 新增分批逻辑:IDs 超过 500 个时按 _BATCH_SIZE = 500 分批,防止 SQL 参数超限

  • 提取 _rows_to_dicts 辅助方法,消除 find_by_department 中的重复转换逻辑

  • 更新 __main__ 块:先用原始 N+1 跑基线,再用新实现跑对比

    Benchmark: BASELINE (N+1 逐条查询)
    Avg time : 16.87 ms

    Benchmark: 方案B (WHERE id IN 批量查询)
    Avg time : 0.65 ms ← 25.8x 加速

3.4 对比总结

指标 基线 (N+1) 方案A 冷启动 方案A 热缓存 方案B 批量 IN
平均耗时 ~18 ms ~23 ms 0.70 ms 0.65 ms
加速比 1x 0.8x 28.9x 25.8x
额外依赖 Redis Redis
首次请求 --- 比基线更慢 --- 始终快

​ 两个方案的热路径性能接近,但方案 B 零依赖且首次请求就快,适合大多数场景;方案 A 更适合跨服务共享缓存或读写比极端的场景。

​ 最终选方案 B 的话:

bash 复制代码
git merge worktree-agent-a002bc72    # 合入方案 B
git branch -D worktree-agent-a6e1b7  # 丢弃方案 A

​ 这就是沙盒模式的核心价值:把"要不要试试"的心理负担降到零。

四、和手动 --worktree 的区别

​ 区别在于谁来管理 worktree 的生命周期

手动 --worktree isolation: worktree
创建方式 你手动在终端执行 claude --worktree name 子代理被调用时自动创建
使用场景 你知道要并行做什么,主动开多个终端 写进 agent 定义,每次调用自动隔离
生命周期 你管理(手动 merge、手动清理) 半自动(无改动时自动清理,有改动时等你决定)
适合谁 开发者主动规划并行任务 探索性、破坏性任务,或团队标准化流程

​ 简单说:--worktree你主动开沙盒isolation: worktree让子代理自带沙盒。后者的好处是你不需要每次都想着"这个任务要不要隔离",定义好的子代理天生就是隔离的。

五、总结

​ 沙盒隔离解决的是信任问题 ,你不用再盯着子代理的每一步操作,不用担心它改坏你的代码。isolation: worktree 一行配置,子代理就有了自己的独立工作空间。

  • 核心要点:
    • 沙盒基于 Git Worktree,物理隔离文件系统,共享 .git 对象库,磁盘开销小
    • 子代理在沙盒里可以大胆试错,改崩了扔掉就行
    • 生命周期半自动:无改动自动清理,有改动等你决定合并或丢弃
    • 特别适合 A/B 方案对比、探索性重构这类"试试看"的场景
  • 但你可能还有另一个痛点:子代理跑着的时候你只能干等,没法继续对话。之后会介绍background: true 让子代理在后台跑,你该干嘛干嘛,再加上沙盒 + 后台的组合玩法。
相关推荐
2301_822782822 天前
初识C语言:简介、环境搭建、第一个HelloWorld
开发工具·环境搭建·编译器·helloworld·初识c语言
leo_2325 天前
小数据( small data )& 小数据系统( small data system )PPT(下)
开发工具·企业信息化·smp(软件制作平台)·软件开发工具·应用系统
m0_488633326 天前
Windows环境下编译运行C语言程序,合适工具与方法很关键
c语言·windows·git·开发工具·编译器
leo_2329 天前
“小数据”与大数据(之一)
开发工具·企业信息化·smp(软件制作平台)·应用系统·小数据
2601_9534656117 天前
m3u8live.cn深度解析:一款专为开发者打造的 M3U8 调试工具
java·前端·django·音视频·开发工具
leo_23219 天前
SMP的第一个AI接口应用
人工智能·开发工具·smp(软件制作平台)·应用系统
wefly201719 天前
告别繁琐配置!m3u8live.cn让 M3U8 链接验证变得如此简单
开发语言·前端·python·django·flask·开发工具
wefly201720 天前
无需安装的 M3U8 在线播放器,快速实现 HLS 流预览与调试
java·开发语言·python·开发工具
leo_2321 个月前
EOM的逻辑构架(BIS 业务信息系统和MIS管理信息系统)(之二)--SMP(软件制作平台)语言基础知识之六十八
开发工具·企业信息化·smp(软件制作平台)·应用系统·eom(企业经营模型)