前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
返回 AI 情报前线
All News · 全部资讯9850
  • AI Agent生产失败元凶:状态管理而非模型
  • LangGraph 多智能体编排:像画流程图一样编排 AI Agent
  • 摩尔线程发布 S5000 白皮书:Prefill/Decode 解耦破解长上下文推理成本困局
  • 在NES和N64上跑真实Transformer:古老硬件上的LLM推理
  • Harness Engineering全攻略:让AI Agent从「能跑」到「可靠」
  • Agentic Ledger:防止AI Agent无限循环烧钱$47000的飞行记录仪
  • 免费模型+免费CI:fuzzing发现14个单元测试漏掉的off-by-one
  • AI 编程时代,Go 语言的可验证性优势凸显
  • 为什么提示词防御治不了注入
  • Qwen Code 0.22安全更新要点
  • 删除错误上下文仍无法修正LLM幻觉结果
  • 157次Agent运行验证:规划优于执行
  • AI原生开发实战:一个远程转录功能的完整复盘
  • 12个前沿VLM对比:本地开源模型在大规模测试中反超付费API
  • 视觉模型RL微调:99% token准确率下模型实际无效的教训
  • 独立开发者用低延迟AI伴侣系统玩《上古卷轴5》
  • 前沿模型从参考文献还原研究思路仅3-15%
  • Devin背后Cognition估值400亿美元背后的实质
  • Agentic SDLC模型选型:27倍成本差异实验
  • Copilot Agent将Docker镜像从912MB优化至108MB
  • Windows上跑并行编码Agent的工程实践
  • AI Harness安装≠激活:Codex生命周期验证实践
  • C++缓存代理减少73%免费层模型调用
  • DeepMind Pandora Router:模型路由成本降至 0.075
  • 2026 年 8 月 AI 编程工具排行:Claude Code 扳平 Codex
  • 无值守 Agent 的五大调度铁律
  • 会话关闭不等于清理完成:进程泄漏的隐蔽陷阱
  • 夜间 Agent 误删已提交代码的根因分析
  • 一个目录实现跨项目 Agent 任务共享
  • Agent 规则为何总被违反:结构化决策记录实践
  • AI通宵写完功能白天被重写:人机协作中的信息同步失效
  • 从单一昂贵模型迁移到任务路由 + LLM fallback 的经验
  • 安卓端230M模型持续学习:端侧微调新范式
  • 多Agent并行抢文件?用声明机制解决冲突的实战经验
  • 纯CMake实现的GPT-2:用构建工具从零跑通大模型
  • MCP 服务器工具投毒攻击实战检测指南
  • LangGraph 生产故障:静默失败导致流水线空跑
  • 强化学习在量化交易中的实战:状态-动作-奖励框架详解
  • AgentCheck:验证AI编程代理实际改动了哪些文件
  • 多租户语音转文本API的流量控制与成本分账设计
  • 让语言模型远离计算:Invoice Assistant的工程实践
  • PyRIT已归档:LLM红队工具替代方案
  • LLM应用抗Prompt注入五大工具横评
  • AI Agent安全:必须防御的四大数据泄露面
  • Ramp 7 万企业账单数据:Opus 4.8 占据 Anthropic 付费榜首
  • 多Agent系统生产落地实战指南
  • AI编程Agent能否自行修复错误
  • WebCodecs+WebGPU实现浏览器端零延迟视频处理
  • Fable高价时代:LLM选型与成本策略思考
  • 5种高效Prompt框架超越95%的基础用法
  • Muninn开源:从零构建记忆系统挑战Mem0/Tencent排名
  • 已加载 51 / 9850
8.0
热点
AI SCORE
编程提效2026-08-24 06:50

Windows上跑并行编码Agent的工程实践

dev.to · AI#Coding Agent#Windows#工程实践
Editor brief · 编辑速览

在Windows环境下并行运行多个编码Agent需要解决HOME路径、配置隔离、日志归属、失败清理四大问题,提供了具体方案。

文章思维导图
Knowledge map
拖拽缩放
Full translation

完整中文译文

有人在上一篇文章的评论区留了一句评论,骨架比文章本身还清晰:

并行 Agent 只有在工作区边界无聊且明确的情况下才实用。尤其在 Windows 上,与其关心启动技巧,不如多关注隔离、日志、文件所有权和失败后的清理。

说这话的是 Alex Shev,他是对的。四个 Agent 放在窗格网格里只是截图效果。他列出的这四个问题,才决定你一个月后还会不会继续用这套方案。

我从事 NestMux 的工作,所以这事跟我有利益关系。以下大部分内容就是普通的 Windows 和普通的 git,不管你用不用 NestMux 命令都一样跑。我会在描述我们所做的决策时明确说明,也会说明哪里还存在不足。

隔离不是改一个 HOME 变量就完事了

两个 Agent 用同一个 Windows 账户运行,会共享 ~/.claude、~/.codex、~/.gemini。配置共享,更重要的是认证会话也共享。如果你想两个 Claude 账户并行,就得用不同的主目录。

在 Windows 上,HOME 不是那个能把你带到目标位置的变量。它是 POSIX 规范,有些工具认它,但 Windows 本身不认。只设 HOME 的话,得到的是一个半吊子的重定向 Agent:CLI 把配置写到新位置,而 git 把 .gitconfig 写到旧位置,你直到两个窗格开始共享同一个 git 身份才会发现不对劲。每个进程实际需要的是:

HOME       = <accountDir>
USERPROFILE= <accountDir>
HOMEDRIVE  = C:
HOMEPATH   = \path\to\accountDir

Gemini CLI 除此之外还需要 GEMINI_CLI_HOME 指向它自己的子目录。

如果你在写启动器(而不是用现成的)有一个坑:Node 的 os.homedir() 在 Windows 上并不能可靠地反映你 spawn 时注入的 USERPROFILE。如果你的应用读取 homedir() 来决定自己的存储位置,同时又为子进程重定向了 USERPROFILE,这两者就会不一致。我们最后给存储专门弄了一个 env 变量,又写了一个单独的函数来处理"新 shell 应该从哪里启动",因为把它们合并意味着每次新建终端都会跑到 Agent 配置目录里去。

那些你其实想共享的配置

没人想要完全隔离。CLAUDE.md、settings.json 和 skills 在每个窗格里应该是一样的。所以它们被链接回全局副本,而不是复制一份。

在 Windows 上这个链接比听起来更麻烦。mklink 做文件符号链接需要提权或者开开发者模式。 junctions 不需要,所以目录没问题。对于文件,备选方案是硬链接。

这个备选方案有个隐患。硬链接不是符号链接,所以 lstat().isSymbolicLink() 对它返回 false。如果你后来提供一个"将此账户从共享配置中断开"按钮,实现方式是"把符号链接替换成真实副本",硬链接的文件会被跳过,然后这个账户就继续悄悄编辑你的全局配置,而 UI 还在显示它已经分离了。要检测它们就得比较文件 id:

const a = lstatSync(src,  { bigint: true })
const b = lstatSync(dest, { bigint: true })
const sameFile = a.dev === b.dev && a.ino === b.ino && a.ino !== 0n

bigint: true 很关键。在某些 Windows 配置下,普通的 ino 会返回 0,这就导致每一对文件看起来都像同一个文件。

Windows 上的文件所有权意味着打开的句柄

这是产生技术支持问题的那个点,而且错误信息还指向了完全错误的方向。

建一个带 worktree 的仓库,然后在其中一个目录里放一个把真实工作目录作为当前目录的进程:

git -C C:\dev\repo worktree add C:\dev\feat -b feat
Start-Process cmd -WorkingDirectory C:\dev\feat -ArgumentList '/c','timeout /t 60'
git -C C:\dev\repo worktree remove C:\dev\feat --force
error: failed to delete 'C:/dev/feat': Permission denied

这跟权限一点关系都没有。Windows 不会删除某个进程的当前目录,而 git 把这个拒绝上报为权限错误。在 Linux 上同样的删除会成功,所以这个问题通常先作为 bug 报告到达 Windows 用户手里,而没人能复现。

有两件事我只有通过尝试写可靠的拆除逻辑才发现:

PowerShell 的 Set-Location 不会复现这个问题。PowerShell 的 location 是叠加在进程之上的 provider 概念。底层的工作目录停留在进程启动时的位置。所以 Start-Process powershell -Command "Set-Location C:\dev\feat; ..." 会让删除成功,你就会以为问题不是真实的。用 -WorkingDirectory,或者用 cmd,或者任何能设置真实 cwd 的方式。

杀 shell 不够。在上面的运行中我杀掉了 cmd.exe,删除仍然失败。持有者是 timeout.exe,一个继承了工作目录且活得比父进程更久的子进程。你需要的是进程树,不是一个进程。

对于任何管理 worktree 的东西的实际后果:在你碰文件系统之前,你得知道哪些窗格正坐在那个目录里。这意味着在 spawn 时记录每个窗格的 cwd,然后用路径前缀来杀进程(需要规范化,因为在 Windows 上同一个 worktree 会根据是谁写的路径而呈现为 C:\dev\feat 或 C:/dev\feat 两种形式)。

失败后的清理是状态变得奇怪的地方

这是我没想到的部分。一次失败的 git worktree remove 不是空操作。续上面的失败:

> git -C C:\dev\repo worktree list
C:/dev/repo  39ca293 [master]

> dir C:\dev\feat
(empty)

> git -C C:\dev\repo worktree remove C:\dev\feat --force
fatal: 'C:\dev\feat' is not a working tree

> git -C C:\dev\repo worktree prune -v
(nothing)

Git 删除了 worktree 的内容,删除了 .git/worktrees 下的管理目录,并把条目从 git worktree list 里拿掉了。然后它遇到了被锁住的顶层目录就停住了。剩下的东西是一个空文件夹,git 不再认识它、不愿意删除它、也不认为它是悬空的。分支还在那里。prune 没有什么好清理的,因为元数据已经没了。

所以恢复是手动的,而且顺序很重要:

先把持有句柄的东西杀掉,进程树也要算进去。

自己动手删掉目录。

之后运行 git worktree prune,应对的是 git 没有走到清除自己元数据那一步的情况。

先 prune 的话,你可能在清理仍然引用着你即将删除的目录的元数据。

我们在应用里最后定下的规则,是用一次 bug 换来的:如果这两个步骤中任何一个失败了,就保留这个条目并报告失败。诱人的做法是丢弃你自己的记录然后声称已经删除了,毕竟用户要求它消失。然后下一次刷新读取 git worktree list 或者残留的目录,这个 worktree 又出现了,看起来还挺健康。现在它就完全没法通过 UI 移除了,因为移除它的代码路径假设的是它刚刚丢失的那个状态。一次部分删除报成成功,比一个错误信息更糟糕。

同一领域的两件小事:

在读取时做对账。人们会在你的应用外面删除 worktree,用 rm -rf 或者原生的 git。如果你的列表来自你自己的存储,条目就会变陈。每次列清单时对比 git worktree list,把 git 不再认识的东西标出来,删除目录已从磁盘消失的条目。

永远不要在 .git 里面创建 worktree。我们早期有一个版本把一些 worktree 放在了 .git/worktrees 下面,那是 git 自己的元数据文件夹。Git 会创建它,然后拒绝把它当作工作树,所以 git worktree remove 永远失败,唯一的出路是手动删除。如果你是用仓库路径加分支名来构建路径,先检查你即将落地在哪里。

在 Agent 运行前执行的设置命令

大多数并行 Agent 方案在创建 worktree 后会运行一些东西:npm install、复制 .env、一个 build。这是一个失败会被吞掉的地方。

三件值得有的事,都不花哨:

每个命令设置超时。出错的命令没问题,你看得到。让你栽跟头的是那个什么都不打印也永远不退出的命令。等待 stdin 上的输入就会这样。每个命令十分钟,然后 kill 它。

拆除时取消。如果在有人移除 worktree 时设置还在跑,先取消它。不然你就是在删除一个正被活着的 npm install 写入的目录,这就又回到上一节的内容了。

清除敏感信息。设置日志会抓到 env dump 或 verbose install 中的 TOKEN=... 行。如果你保存这些日志,在进去的时候就清除它们,不要等出来再处理。

日志:这是我还没有答案的部分

这是评论击中要害的地方,也是我展示得最少的地方。

NestMux 现有的是每个窗格一份 transcript,可以保存并导出为 markdown,以及每个 worktree 一份设置日志,上限 200 行并清除敏感信息。不存在的是任何统一的东西:跨窗格的一条时间线,带时间戳、退出码,以及每行属于哪个 worktree。

而这恰恰是评论描述的那个场景里你需要的 artifact。一次夜间运行失败了,四个 Agent 在工作,问题是哪一个碰到了什么、按什么顺序碰的。每窗格一份 transcript 让你只能从四个回滚记录里手动重建。

我没有计划发货日期。我把它写成差距而不是计划,因为诚实的状态是每窗格 transcript 容易,跨窗格且正确归属的日志难,尤其是当窗格来来去去的时候。

启动技巧确实是简单的那部分。所有昂贵的东西都在拆除里:谁握着句柄、一次失败的删除留下了什么状态、以及你自己的世界记录在那之后是否还和磁盘一致。在 Windows 上这是不同于 Linux 的另一套失败模式,而且错误信息更糟糕。

如果你在并行运行 Agent,而且你有一个能在失败运行中存活下来的拆除方案,或者一个真能回答"哪个 Agent 干的这事"的日志方案,我想看看。尤其如果它认为这事应该是个脚本而不是一个应用。

Original source

本文由 AI 翻译整理自 dev.to · AI,原文版权归原作者所有。

阅读英文原文
上一篇
Copilot Agent将Docker镜像从912MB优化至108MB
下一篇
AI Harness安装≠激活:Codex生命周期验证实践