那天下午我打开 OneDrive,右上角的同步图标已经不再转圈了——不是同步完成,而是彻底卡死。点开冲突提示,一整排“WorkBuddy_session_billing_api(1)(2)(3)”的副本整齐地躺在那里,算下来吞掉了 3.2GB 空间。我在删除副本和解除同步之间犹豫了两分钟,最后决定做个更彻底的事:给每个 Agent 会话一个真正属于自己的“家”。
这里的“家”不是个比喻,是一套可落地的目录工作区方案。它把 WorkBuddy 运行期间产生的会话数据、上下文快照、工具调用记录和日志全部按会话隔离存放,同时通过云盘排除规则让 OneDrive 不再插手中间过程,只负责归档最终结果。这套思路大概花了我两个晚上调试,之后一周跑下来,云盘安静了,会话可追溯了,连模型犯错的回溯都顺手很多。如果你是 WorkBuddy 的重度用户、Agent 开发者,或者只是被“会话同步冲突副本”烦过的人,这篇应该对你有用。
1. 焦虑从哪来:Agent 会话的存储模型天生和云盘不对付
先说清一个问题:为什么别的软件放云盘里没什么事,WorkBuddy 这类 Agent 一放进去就出事?答案在于写入模式完全不同。
1.1 一次普通会话到底会产生多少文件
我之前对 Agent 会话的理解是“聊天记录”,以为最多就是一个 JSON 文件。真去翻了工作目录才发现,一次稍微复杂点的任务,大约会经历这样的过程:
- Agent 接收用户指令后,先写一份任务描述快照;
- 每次调用工具前,记录工具名、入参、返回值摘要;
- 中途如果执行了脚本或写了临时文件,这些内容也会落在会话目录附近;
- 模型上下文太长被截断时,会生成历史摘要文件;
- 最后还有完整的 token 消耗统计和会话日志。
也就是说,一次跑通“修复登录接口超时”这样的小任务,最少会生成 30 到 80 个小文件。单个文件通常只有几KB到几十KB,但量大。一个工作日下来,新增上千个文件是常态。
这些文件本身不可怕,可怕的是它们会被云盘客户端逐个“关注”。Windows 上的 OneDrive、macOS 上的 iCloud Drive,底层都依赖文件系统事件监听。文件一变化,客户端就要去比对版本、计算哈希、上传差异。Agent 会话是典型的写密集型负载,频率极高、单文件极小、总数极大,这正好踩在云盘同步引擎最难受的位置。
1.2 云盘同步机制的“三宗罪”
以我在 OneDrive 上的观测,问题集中在这三件事上:
第一,同步队列频繁拥堵。当一个目录里几百个小文件不断被创建和修改,OneDrive 的队列会越排越长,CPU 占用肉眼可见地上升到 20%-30%,风扇开始转,其他文件的同步全部被堵在后面。
第二,冲突副本泛滥。云盘的多端同步基于“最后写入者胜”的朴素逻辑。WorkBuddy 生成的会话文件如果被另一个设备同步下来,本地 Agent 又恰好要回写,双方各自持有一个版本,客户端就会悄悄复制一份,命名为“会话名(1)”。跑一天,目录里能冒出一堆带编号的副本。这个问题的本质是:两个写入源在毫秒级时间内修改同一个文件,而云盘没有合并能力。
第三,隐私和体积的隐性风险。会话文件里往往包含完整的需求描述、代码片段、API 返回结果。把这些内容实时传到云端,本身就是一种不必要的暴露。再加上历史会话只增不减,云盘配额很快就会被撑满。
所以答案很直接:WorkBuddy 的中间产物不应该被云盘同步,只有最终成果才配得上云盘的位置。
2. 为什么每个会话都该有一个“家”:工作区的三层价值
与其给云盘写一堆排除规则,不如换个思路:让会话在本地拥有一个稳定、可识别、结构完整的工作目录。这个决定不只是为了解决同步问题,它更像是给 Agent 的使用方式补上了一块缺失的拼图。
2.1 会话即任务,目录即边界
最早我也是在 WorkBuddy 默认的全局会话目录里跑所有任务,结果就是所有 Agent 的“记忆”混在一起。一周后想找某个需求的相关记录,只能靠关键词全文搜索,效率极低。
后来我意识到,每个会话本质上是一次任务(task),它有明确的起点、过程和终点。既然任务有边界,那它的数据就应该有边界。给每个会话分配一个独立目录,相当于给这次任务划了一个房间:所有上下文、所有产物、所有中间日志都在这个房间里,不会跑到别人家去。
这个做法和软件工程里的“模块边界”是同一个道理。目录一旦成为边界,你就可以对它做任何批量操作:一键归档、一键清理、一键导出,而不用害怕误伤其他任务。
2.2 有了家,才能谈恢复、回滚和清理
当会话数据是散落状态时,所谓“恢复”是不可能的。你会话里的每一步操作都分散在不同文件里,缺少一个统一的入口。
按照会话目录组织之后,三层价值就很清晰了:
- 恢复:WorkBuddy 如果中途崩了,或者你切换了设备,只要把那个会话目录拉回来,就能从最后的状态继续跑,而不是从头再来。
- 回滚:Agent 改坏了一段代码,你可以对比会话目录里的中间版本,凡是改过的文件都有记录,定位是哪一步引入的问题非常快。
- 清理:所有会话目录都按统一模式命名,清理策略可以写成脚本。超过 N 天的目录自动打包归档,彻底告别手动删文件的痛苦。
有人问,这跟 WorkBuddy 自带的会话列表有什么区别?区别在于,会话列表是工具的视角,目录是文件的视角。你操作的是真实存在的文件,可以配合 git、rsync、压缩工具、任意脚本使用。工具可以换,文件结构是自己的。
3. WorkBuddy 会话工作区方案:目录结构、环境变量与初始化脚本
下面是我的完整落地方案。先从目录结构讲起,再讲如何在 WorkBuddy 里配置,最后给出初始化脚本。
3.1 目录结构怎么设计
我在用户目录下建了一个顶层工作区~/workbuddy_workbench,内部结构如下:
~/workbuddy_workbench/ ├── active/ # 进行中的会话,按日期和任务名命名 │ ├── 20241120_fix_auth_timeout/ │ └── 20241120_billing_api_refactor/ ├── archive/ # 已归档的会话,按月份再分一层 │ └── 202411/ ├── exports/ # 可同步到云盘的最终产物 │ ├── 20241120_fix_auth_timeout_summary.md │ └── 20241120_billing_api_refactor_diff.patch ├── workspace/ # 会话共享的工作文件(比如克隆下来的仓库) │ └── billing-service/ └── logs/ # 全局运行日志,排除同步关键设计是三层隔离:
active/是“施工现场”,文件变动最频繁,本地存放,云盘完全排除;exports/是“作品展示区”,只有当你确认一个会话结束时,顺手把总结或补丁丢进去,云盘同步这一层;archive/是“储藏室”,定期把active/里不再使用的目录压缩后移进来。
这样设计之后,云盘同步的对象是稳定且小体积的,而高频次的中间文件永远不会被云端看到。
3.2 WorkBuddy 侧的核心配置
要让 WorkBuddy 真正“住进”这个工作区,只建目录是不够的,还要告诉它“工作区在哪里、会话文件往哪放”。
我做的第一件事是在 WorkBuddy 配置文件里指定工作目录根路径。不同版本的 WorkBuddy 配置方式略有差异,但核心就是设置用户级的工作目录指向~/workbuddy_workbench/workspace,同时把默认会话存储目录指向~/workbuddy_workbench/active。
第二件事是修改启动方式。我不再直接打开 WorkBuddy 后随手发指令,而是给每个新任务先创建独立目录,再在 WorkBuddy 里以此目录为当前工作目录开启新会话。这一步看起来多花了十秒钟,收益却是值得的。
3.3 初始化脚本:用一条命令起一个会话
纯手动建目录太啰嗦,我写了一个wb-new脚本,放在 PATH 里,启动新会话时只需要:
wb-new fix_auth_timeout脚本内容大致如下:
#!/usr/bin/env bash # wb-new: 创建一个新的 WorkBuddy 会话工作目录 # 用法: wb-new <task_name> set -euo pipefail BASE_DIR="$HOME/workbuddy_workbench/active" TASK_NAME="${1:?usage: wb-new <task_name>}" DATE_TAG="$(date +%Y%m%d)" SESSION_DIR="${BASE_DIR}/${DATE_TAG}_${TASK_NAME//[^a-zA-Z0-9_-]/_}" if [ -d "$SESSION_DIR" ]; then echo "会话目录已存在: $SESSION_DIR" exit 1 fi mkdir -p "$SESSION_DIR"/{context,artifacts,tmp,logs} echo "$TASK_NAME" > "$SESSION_DIR/context/task.md" echo "会话目录已创建: $SESSION_DIR"脚本里有几个细节值得解释一下:
- 日期前缀
%Y%m%d保证同名任务不会覆盖,排序时也会按时间自然排列; - 内部四个子目录
context、artifacts、tmp、logs分别存放上下文、最终产物、临时文件、会话日志,这样后续清理策略可以只针对tmp下手,不用顾虑其他文件; //[^a-zA-Z0-9_-]/_是 Bash 的替换语法,可以自动过滤任务名里的特殊字符,避免生成含空格或斜杠的非法目录名。
3.4 自定义指令和 Skill 的配合
WorkBuddy 支持自定义指令,这正好用来固化“会话目录纪律”。我在 WorkBuddy 的自定义指令里加了一行:
每个任务开始前,先确认会话工作目录是否存在。如果不存在,请先创建目录并初始化 context/task.md,再开始执行任务。
这个指令本身很简单,但它让 Agent 在无人监督时也会先落目录、再动手,而不是把文件散落在各处。
如果你用了 WorkBuddy 的 Skill 功能,还可以把“目录初始化”封装成一个 Skill,让 Agent 在识别到新任务时自动调用。本质上,这个 Skill 就是脚本wb-new的 Agent 化版本,传入任务名,返回会话目录路径。目前这类 Skill 的常用做法就是写一个指令模板加一个可执行脚本,门槛不高,但长期收益非常明显。
4. 把云盘从“同步者”变成“归档者”:排除规则与容量控制的实战
目录方案只是第一步。如果没有云盘排除规则,前面的一切都会被同步客户端重新搅乱。这一部分讲讲我排障的过程,以及最终是怎么让云盘只做归档的。
4.1 同步冲突副本的完整排查链路
先回顾一下我当时是怎么定位到“冲突副本是 WorkBuddy 会话文件导致的”:
起初我以为是云盘客户端出了问题,于是先做了三件事:重启 OneDrive、取消并重新关联账号、把“按需文件”关闭再打开。结果是:当时安静了半小时,之后冲突副本继续出现。
然后我开始看 OneDrive 的同步日志,发现冲突的文件路径都在 WorkBuddy 会话目录附近。再对照时间线:每次我让 Agent 跑一个任务,大概几十秒后就开始出现冲突副本。到这里基本可以确认,问题不是云盘故障,而是写入模式不兼容。
触发冲突的典型场景是:Agent 在任务中同时更新了会话摘要文件和当前状态文件,OneDrive 还没来得及上传第一个版本,就收到了第二个变更,而其他设备(比如另一台电脑)如果有旧版本同步记录,就会生成冲突副本。
4.2 云盘排除规则的配置参考
定位问题之后,我做了两处设置:
第一处是把~/workbuddy_workbench/active、logs、tmp目录排除出 OneDrive 同步范围。OneDrive 的排除逻辑是文件夹级别的,我目录设计时就把这些独立建在工作区的顶层,配置起来一条规则就够了。
配置好后,我把 OneDrive 的同步状态从“所有文件”改成了“仅导出目录”,也就是只允许exports/文件夹进入云端。这样 WorkBuddy 的会话数据不会实时上传,只有你手动放入exports/的总结文档、补丁包才会同步,云端扮演的角色也从“实时同步者”降级成了“定期归档者”。
如果你用其他云盘,配置方式类似,只是排除规则的入口名称不同。这里是通用的原则:
| 目录对象 | 是否同步到云端 | 原因 |
|---|---|---|
| active/ 会话现场 | 否 | 高频写入,同步无意义且容易冲突 |
| workspace/ 工作文件 | 按需 | 如果网络足够快可以同步,否则建议只同步 git 仓库 |
| exports/ 最终产物 | 是 | 体积小、变动少、需要跨设备访问 |
| archive/ 归档 | 可选 | 建议本地压缩后再同步,单文件大但数量少 |
| logs/ 日志 | 否 | 内容敏感且变动频繁 |
4.3 容量失控的清理策略
排除同步之后,还剩下一个绕不开的问题:会话目录只增不减,磁盘空间迟早告急。
我的做法是“三步清理法”,已经跑了两周,稳定有效:
第一步,会话结束时手动归档。任务完成后,在 WorkBuddy 里把最终总结写入exports/,把 diff 或关键产物也复制过去,然后在 active 目录里做一次“收尾”。
第二步,tmp目录实时瘦身。WorkBuddy 的中间临时文件全部都落在会话目录的tmp/子目录里。我在脚本里加上了一句find "$SESSION_DIR/tmp" -type f -mtime +1 -delete,意思是删除一天前的临时文件。这一步能省掉一半以上的会话体积。
第三步,每月压缩归档。月底把active/里超过 14 天没有变动的目录打包成 tar.gz 放入archive/,再从 active 里移除。一条 cron 就能定时完成,不用人工介入。
有人可能会担心删除 tmp 文件会影响会话恢复。实际上,会话恢复依赖的是 context 里的状态文件和摘要,临时文件被删顶多意味着某些中间产物无法复现,但任务上下文不会丢。用文件的生命周期管理来换磁盘空间,我觉得是划算的。
5. 落地一周后的真实体感与三个细节补充
方案跑了一周,最直观的变化有三个:
第一,OneDrive 的同步队列不再卡死。因为同步的文件从每天几千次小文件变更降到了个位数,CPU 占用恢复正常,通知栏也再没出现过冲突副本。
第二,会话追溯快了。上周四排查一个线上问题时,我直接进active/20241118_xxx目录,把当时的 tool call 日志和中间产物全部翻出来,对比之后立刻定位到是某次参数变更导致的兼容问题。这在以前是不可想象的,因为我根本不知道那些文件在哪里。
第三,手动清理没有任何心理负担。看到磁盘空间紧张,跑一条清理 tmp 的脚本,过期的临时文件全部清掉,我知道它不会影响任何正在进行的任务。
最后分享三个细节,都是实际用过之后才体会到的。
细节一:会话命名规范和“上下文笔记”的直接关系。WorkBuddy 的上下文恢复质量,很大程度取决于会话目录里存了什么。我建议每个会话启动时都在context/task.md里写清楚任务目标、约束条件、验收标准。这不仅是给 Agent 看的,也是给你自己看的。三周后回看这个文件,能立刻想起来当时这个任务在干嘛。
细节二:云盘同步和 Agent 的“open & read”习惯不冲突。我一开始担心排除了 active 目录之后,其他设备就无法读取会话记录了。后来才意识到,跨设备读取会话本来就不该依赖云盘,而应该依赖 Archive 或者手动导出。会话期间的中间产物,本来就只有正在运行的那台机器需要访问。
细节三:worktree 和会话工作区的配合。如果你的 Agent 要改代码,与其在同一个 git 仓库里反复切换分支,不如让每个会话对应一个独立的 git worktree。这样每个会话目录自带一套完整的代码状态,互不干扰。配合 WorkBuddy 使用后,你会觉得“给会话一个家”这个决定,把 Agent 开发中最头疼的上下文污染问题也一并解决了。
如果你也被 Agent 会话和云盘同步的冲突搞到头大,不妨先试试局部排除:只排除 active 目录、让 exports 参与同步。不用一上来就把整个方案搬走。等你感受到“会话目录化”带来的检索和恢复优势,自然会想把那套初始化脚本也布置上。工具是死的,工作流是活的,把文件结构理顺了,Agent 才能真正成为你手里顺手的工具。