一次多 Agent 工作流编排实验

在使用 AI 编码工具时,我发现单个长提示词很容易同时混入需求理解、方案设计、编码和检查。模型可能快速给出结果,但中间判断难以追踪,失败后也不知道应该重试哪一步。为了理解多 Agent 是否真的能改善这个问题,我在 LLMStudyLS 仓库中增加了一个 ai-flow 实验。

该子目录第一次提交于 2026 年 1 月 9 日,因此本文使用这个日期,而不是复用整个仓库的创建时间。它是一个命令行原型,重点是验证编排和上下文边界,不是完整的自动改码平台。

为什么把流程写进 YAML

实验把 Agent、角色和工作流阶段放在 YAML 中配置。Agent 配置描述使用哪个 provider、角色提示和能力;工作流配置描述阶段输入、负责 Agent、转换条件、最大迭代次数和错误策略。这样做不是为了追求配置化本身,而是把原本藏在一个巨大提示词里的流程显式化。

当需求变化时,我可以调整阶段关系,而不必改动编排器核心代码;当某个角色输出不稳定时,也能单独检查它接收了什么输入。配置文件因此既是运行参数,也是一份可以阅读的流程说明。不过 YAML 只能表达有限条件,复杂分支仍需要代码,过度配置反而会增加理解成本。

阶段执行与状态转换

Orchestrator 读取配置后,从第一个阶段开始执行。每个阶段根据角色取得 Agent,准备输入,等待结果,再按照转换条件决定下一步。执行日志记录阶段名称、成功状态、输出或错误;失败时根据策略重试,并受最大迭代次数限制,避免工作流无止境循环。

这个模型更像一个小型状态机,而不是几个聊天窗口互相传话。阶段边界让“分析失败”和“实现失败”成为不同问题,也便于加入 dry-run:在不真正调用 Agent 时,只展示即将经过的阶段和转换,用来检查配置是否合理。

上下文不是越多越好

ContextManager 保存需求、文档、工作目录占位信息和各阶段输出。后续阶段可以读取指定来源,也可以取得累计结果。这样能减少每一步重复组装输入,但也带来新的风险:如果所有输出都无差别传递,噪声会越来越多,早期错误还可能被后续 Agent 当成事实。

因此我更关注输入来源,而不是简单增加上下文长度。阶段只声明自己需要的字段;来自用户、自动扫描、某个阶段或累计器的内容需要区分。多 Agent 并不会自动得到更好的答案,真正有价值的是让上下文选择、责任和验收点变得清晰。

Provider 与工具边界

原型提供 Anthropic、OpenAI 兼容接口和 CLI provider 的适配入口,AgentManager 根据配置选择实现。统一接口让编排器不依赖具体模型,但并不意味着不同模型可以无成本替换:提示格式、工具能力、超时和输出结构仍可能不同,需要在 provider 层处理差异。

这里需要主动说明一个命名与实现的差距:当前 scanProjectContext() 只记录工作目录,没有读取文件、解析 package.json 或实现忽略目录规则。因此它只是为未来项目上下文扫描预留的位置,不能算已经完成受控代码扫描。Agent 输出仍被当成建议,不直接拥有任意文件写入权限。

安全模式与当前限制

最重要的限制写在 apply_changes:MVP 会整理候选文件并打印提示,但不会自动写入。也就是说,这个仓库没有完成“Agent 自动修改代码并提交”的闭环。把这一点保留下来,是因为在没有补丁校验、测试、路径限制和回滚前,自动写入带来的风险高于演示价值。

原型目前没有完善的并发调度、持久化执行记录和系统化评测。配置中虽然写了 iterateOversource: iterationpassData,编排器却还没有实现这些语义;进入实现阶段时,必填的 task 无法从迭代上下文取得,所以完整配置流程并不能端到端跑完。当前能够确认的是状态循环、基础来源解析、简单转换、日志和安全模式的骨架,而不是一条已经跑通的自动开发链路。

我得到的结论

这次实验让我对“多 Agent”降温了一些。数量不是目标,可观察的阶段、受控的上下文、明确的失败位置和人工确认才是目标。如果一个任务用单 Agent 加工具就能清楚完成,没有必要强行拆分;只有责任、信息和验证确实不同,分工才有意义。

实验代码和配置可以在 LLMStudyLS / ai-flow 中查看。