
软件工厂设计模式不是指某个具体框架或代码库而是一套把软件开发当成“装配线”来组织的思路。它的关键词落在“可组合部件”需求、代码模板、测试用例、部署脚本、甚至智能体协作节点都被拆成独立单元通过标准接口拼装起来形成一条可以重复运行的交付流水线。这个概念最近重新受到关注很大程度上是因为多 agent 应用开始流行。最新的讨论里经常提到主从模式核心观点是subagent 本质上可以当作另一种 tool 来调用。主 agent 先拆任务再按需拉起子 agent子 agent 把结构化结果返回给主流程。这套逻辑和软件工厂的可组合部件如出一辙——把不是硬编码功能的东西统一当成可插拔部件。这篇文章适合软件架构师、工程效能负责人、AI 应用开发者和正在搭建自动化交付链路的团队阅读。我会按实际落地顺序拆解先讲清楚这个模式解决什么问题再讲部件的边界和契约然后说它和 agent 编排的关系接着给出一条最小可运行流水线最后补上验证方法和生产环境的坑点。1. 软件工厂设计模式到底解决什么问题1.1 工厂思维不是把代码堆在一起而是把交付拆成工序传统开发里“模块化”通常只停留在代码层面。一个 service 拆分几个类各模块通过接口通信就已经被认为做得很好了。但到了交付层面问题立刻变得混乱需求分析是一拨人代码生成是另一拨人测试手工执行部署脚本散落在不同机器上文档靠人肉更新。每个新需求进来都要重新走一遍“找上下文、建环境、改代码、跑测试、打包上线”的步骤。这个过程本质上和手工作坊没有区别。软件工厂设计模式要解决的核心问题就是把“交付”这件事也变成流水线。它借鉴制造业装配线的思路原材料按序进入工位每个工位只负责一道工序输出标准化半成品流转到下一个工位。映射到软件领域原材料是需求描述、领域知识、接口定义、数据样例工位是分析模块、生成模块、检查模块、构建模块、测试模块半成品是需求文档、接口规范、源代码、测试报告、安装包。做到这一步之后你得到的不是一段更好看的代码而是一条可以重复使用的交付路径。任何新需求只要原料合规都能在这条路径上跑一遍而不是让工程师重新手工拼装。1.2 为什么今天又要重提软件工厂有经验的开发者可能会觉得这个想法不新鲜。确实20 多年前 Greenfield 等人提“软件工厂”时核心就是架构模式、领域特定语言和装配线。微软也曾经推出过软件工厂相关实践。但那时候落地阻力很大一个重要原因是装配线中“把需求变成代码”这一步没有足够便宜的执行单元。当时的做法是大量使用代码模板、代码生成器和后期绑定本质上需要团队先投入巨大精力去构建设计资产。对大多数中小团队来说投入产出比并不划算。现在的关键变化是LLM 和多 agent 编排让“需求到半成品”的转换成本大幅下降。你不再需要为每个领域编写一整套代码生成器而是可以用一个可配置的智能体部件把自然语言需求转成结构化产物。这让软件工厂的“可组合部件”第一次有了通用化、低成本的实现方式。今天的软件工厂更像是在说把传统设计模式中的“职责边界、接口约定、依赖注入、模板方法”这些思想迁移到由人、代码、LLM、agent 共同组成的混合流水线上。这是它在 2025 年后重新热门起来的真正原因。注意这个模式适合的是“同一类任务反复出现、需要稳定交付”的场景。如果你的每个项目都是全新探索型、几乎没有重复工序那先不要急着建工厂否则你只是在为抽象写抽象。2. 可组合部件边界、契约与上下文2.1 部件边界输入、输出、副作用真正能放进装配线的部件必须具备三个可判断的特征明确的输入、明确的输出、可控的副作用。输入不能是“放一段文本进去就行”。一个合格部件需要说明数据格式、字段含义、必填项和可选项。比如“需求分析部件”的输入应该是{ task_id: T-2024-001, requirement: 用户可以在个人中心修改头像, context: 项目使用 React Spring Boot }而不是一段语焉不详的对话。输出也要稳定。每一次运行输出的结构都应该一致这样下一个部件才能不加判断地消费。如果输出完全自由那每个下游部件都得先做“结果猜测”装配线就断了。副作用最容易被忽略。这里的副作用指部件是否改写了外部文件、是否调用了数据库、是否发起网络请求、是否消耗了 API 配额。在工厂装配线上部件应该默认无状态尽量把中间结果写到约定目录不跨步骤修改他人数据。如果必须有副作用必须在配置里显式声明。2.2 契约一致是组合能够成立的前提部件之间的连接靠的不是“双方约定好名字”而是显式契约。我在实际项目中一般会先用一个 schema 文件约定所有产物的格式再让每个部件按照 schema 输出。常用做法包括需求解析结果统一写成 Markdown 文件前三行是标题、优先级、验收标准。接口设计统一输出 JSON至少包含endpoint、method、request_schema、response_schema。代码生成结果统一放在src/{module}/下并在artifacts/generated_files.json里登记生成文件列表。为什么要这么在意契约因为在装配线上任何一个部件格式变了一点下游项目可能不再报错但会产生脏数据。你花在排查“为什么接口文档少了字段”上的时间往往比写代码的时间还多。显式契约加上 schema 校验可以把这类问题在进入下一步之前拦截住。2.3 上下文传递和状态所有权工厂流水线里一个常见混淆点是“上下文”。需求信息、项目背景、代码风格、约束条件这些信息从一个部件传到下一个部件很容易变成重复堆叠。今天我见过的最典型做法就是在每个环节的 prompt 里都塞入整份项目说明。这样会导致两个问题token 成本大幅上升下游模型容易被不相干信息干扰。更稳妥的做法是把上下文分为两层。全局上下文只在流水线启动时加载一次包含项目路径、命名规范、技术栈、统一约束。步骤上下文则由当前产物提供每个部件只管自己需要的那一部分。还要明确状态所有权一个文件一旦被某个部件标记为已完成其他部件原则上不能顺手改写如果确实需要变更要走版本化流程生成v1、v2而不是原地覆盖。这个原则放到多 agent 协作里同样成立。subagent 执行完子任务返回的应该是完成结果和引用地址而不是整个项目快照。主 agent 只负责调度和汇总不重复执行已完成的工作。下表列出不同类型部件的组合方式和适用场景方便新手判断自己手里应该用哪种部件类型典型实现组合方式适合场景常见失败原因纯函数型Python 脚本、命令行工具在流水线中直接调用格式转换、文件整理、schema 校验没有做输入校验字段为 null模板生成型代码生成器、脚手架传入参数后渲染模板目录生成、CRUD 代码生成模板版本和依赖版本不一致模型推理型LLM API、本地模型定义输入输出 schema 后调用需求解析、代码生成、测试生成返回格式变化、生成结果过时代理协作型主 agent subagent主 agent 拉起 subagent 并接收结构化结果复杂任务拆解、局部修改、决策建议上下文过大、工具调用链路不透明人机审核型人工确认页面、review bot在关键节点暂停人工审批后放行高风险变更、对外合同、验收流程等待时间过长阻塞后续工序3. 从传统流水线到代理协作主从模式为什么值得重提3.1 主从模式本质上是把 subagent 当作工具调用多 agent 设计中的主从模式常见疑问是subagent 到底是一个独立的“智能体”还是一个“工具”不同团队有不同叫法但就工程实现来看更准确的判断是subagent 是绑定到主流程上的特殊工具。为什么这样说因为一个普通工具函数接收参数、返回结果调用方根据结果继续运行。subagent 在主从模式下也是这样。主 agent 收到用户任务后做任务规划决定调用哪个 subagent给它传 prompt 和上下文subagent 执行自己的工具链最后返回结构化结果。这个过程和“调用一个代码生成函数”在控制流上几乎一致。区别在于subagent 内部可以有自己的推理和多次工具调用它的“入参”和“出参”通常更接近自然语言也更灵活。但从主流程视角看它就是一个函数输入任务描述输出任务结果。这个理解非常重要。一旦你接受这个设定你不需要为 agent 单独设计一套编排系统直接把 subagent 放进流水线节点的抽象里就可以。每个节点可以是脚本、可以是 API 调用、也可以是 subagent。统一由调度器处理输入输出、失败重试、结果记录。3.2 代理协作和经典流水线适用同一个建模思路经典流水线比如 Jenkins pipeline 或 GitHub Actions描述的是串行或并行的任务序列每个任务使用特定工具产物在任务之间传递。这种建模方式稳定、可观测、可回滚。到了多 agent 场景很多团队一开始会脱离这套思维把 agent 做成“自由行动”的形态主 agent 任意调用工具任意修改文件中间过程不透明。这样demo 很好看一旦要做批量任务或生产部署问题立刻出现任务跑了一半不知道黑盒里发生了什么失败时难以定位也无法稳定复现。把 agent 编排建模成流水线就能解决这些问题。你需要做的只有三件事把任务显式拆成步骤不依赖主 agent 随机发挥每个步骤用 schema 约定输入和输出每个步骤允许失败失败后有明确重试或中止逻辑。换句话说在多 agent 设计里subagent 被当作可组合部件看待。主 agent 是装配线管理员subagent 是某个工位上的“柔性机器”。这样既保留了智力能力又恢复了工程可测性。我自己在团队落地时会先把“主 agent 规划”的能力限制在步骤选择上而不是让它可以任意写文件或访问数据库。一个步骤对应一个工具要么是一个脚本要么是一个 subagent不能在中间随意换。这个约束会让配置看起来笨一点但更容易做审计。4. 落一条最小流水线拆任务、定契约、看产物4.1 先挑一条任务拆成三类工序动手搭建时不要一开始就设计完整工厂。找一个真实存在、次数较多、单次需要 10 到 30 分钟手工完成的任务把它拆成三类工序分析类解析需求、整理接口、识别边界输出文本或 JSON。生成类根据分析结果生成代码、文档、测试用例输出到指定目录。验证类运行测试、检查语法、对比 schema输出成功或失败报告。以“为一个新接口模块生成代码”为例可以拆成解析需求描述输出接口列表。根据接口列表生成 OpenAPI 规范。根据规范生成服务端代码骨架。生成对应测试用例。运行测试输出测试报告。这个拆法核心是每一步都有独立产物且产物是下一步的输入。不要把一个步骤做得过大也不要做成“一步生成全部”的黑盒。4.2 定义工件格式和检查点开工前先创建目录结构。比如pipeline_demo/ ├── tasks/ │ └── T-2024-001.md ├── artifacts/ │ ├── 01_api_list.json │ ├── 02_openapi.yaml │ ├── 03_src/ │ ├── 04_tests/ │ └── 05_test_report.json ├── scripts/ │ ├── step1_parse.sh │ ├── step2_gen_spec.py │ └── step3_gen_code.py └── pipeline.json每个产物文件都对应一个步骤。步骤运行后除了产物本身还要生成一份step_meta.json。这个文件至少包含步骤 ID 和版本开始时间、结束时间、耗时输入文件的哈希值输出文件的哈希值模型或工具版本状态成功、失败、跳过这一步看起来繁琐但它会让后续排查快很多。没有元数据时你面对的问题常常是“这个文件是哪个步骤生成的用的什么模型为什么和我预期不一样”有了元数据就能直接回答。4.3 最小执行循环示例配置下面给一个示例pipeline.json实际字段以你的环境为准这里用来演示流水线调度的通用结构{ pipeline: module_gen, working_dir: pipeline_demo, global_context: { project: shop, language: python, framework: fastapi, style: black }, steps: [ { id: parse_req, type: subagent, agent: req_analyzer, input: tasks/T-2024-001.md, output: artifacts/01_api_list.json, retry: 1 }, { id: gen_spec, type: llm, model: gpt-4o-mini, input: artifacts/01_api_list.json, output: artifacts/02_openapi.yaml, retry: 2 }, { id: gen_code, type: command, cmd: scripts/step3_gen_code.py --spec artifacts/02_openapi.yaml --out artifacts/03_src, input: artifacts/02_openapi.yaml, output: artifacts/03_src, retry: 0 }, { id: run_tests, type: command, cmd: pytest artifacts/04_tests -q --junit-xml artifacts/05_test_report.xml, input: artifacts/03_src, output: artifacts/05_test_report.xml, retry: 1 } ] }调度器的执行逻辑很简单按顺序遍历步骤每次读取该步骤配置中的input文件执行对应类型的处理器把输出写到output位置。如果步骤失败按retry次数重试重试仍失败则中止整条流水线保留所有已生成产物。这里不要急着做可视化编排、并行调度。先用顺序执行把链路跑通。4.4 从单条任务到批量任务的两种路径单条任务跑通后再考虑批量。批量处理有两种常见路径。第一种是循环式批量。外部脚本遍历任务目录下的所有需求文件为每条任务调用一次流水线每条任务独立生成一份产物。优点是实现简单适合任务之间没有依赖的场景。缺点是多个流水线同时运行时要小心共享资源比如 API 配额、磁盘空间、同一个仓库目录。第二种是队列式批量。把任务清单写成一个 CSV 或 JSON后台消费者逐条消费。每个任务有独属 ID输出目录按任务 ID 隔离。这种方式适合任务量大、需要长期运行的场景也更容易做失败重试和断点续跑。我建议先做循环式把一个目录里 10 条任务全部跑通再升级队列。因为队列式批量一旦引入你实际上是在做一个小型任务系统需要处理消息确认、日志持久化、并发控制成本和收益要一起算。5. 判断这个流水线跑得好不好验证指标与日志5.1 成功的标准不是“能跑”我第一次搭这种流水线时最大的误判是跑通了就算成功。实际上“能跑”和“能用”之间差着很多。你至少要回答这几个问题每一条任务是否稳定产出符合 schema 的产物产物的质量和人工完成的标准有多大差距连续跑 20 条任务成功率是多少失败集中在哪一步重试后结果一致吗会不会出现同样输入但输出差异很大的情况全流程耗时是否可接受资源占用是否稳定最好用表格记录第一次批量测试的指标。给一个参考模板指标数值判断任务总数20可参考样本量链路成功率18/20低于 90% 时不建议进生产平均单任务耗时82 秒记录本轮环境便于后续对比重试率2/20看分布在哪些步骤产物 schema 通过率19/20低于这个值先修契约不要优化速度平均 token 消耗12000 tokens用来估算成本这些指标没有统一标准要结合你的任务复杂度、模型选择、质量要求来定基线。重点是它必须是可量化的。不要用“效果还不错”这种描述。5.2 输出命名、重试策略和现场日志批量任务最容易踩坑的是输出覆盖。如果所有任务都输出到artifacts/generated_code/第二条任务会把第一条的产物冲掉。这里没有技巧必须强制使用任务 ID 隔离输出目录。推荐的命名方式是artifacts/{pipeline_id}/{task_id}/{step_id}/{output_file}这样每条任务、每个步骤的产物都在独立目录即使任务失败现场也保留着。现场比日志更重要。很多模型生成的代码看起来正常但实际产物有问题如果你不保留现场重试时只能重新生成成本更高。日志方面至少记录三件事调度日志、步骤日志、错误摘要。调度日志记录“什么时间、由哪个调度器、启动了哪个任务”步骤日志记录“每个步骤的输入输出路径、模型版本、结果哈希”错误摘要记录“哪个任务在哪个步骤失败、失败原因、重试了几次”。5.3 资源占用和速度怎么看有很多团队在小规模测试时体验很好一批到 100 条任务就崩了。这通常不是模型问题而是资源管理问题。如果使用 LLM API要关注的是每分钟请求数、token 配额、连接池占用。并发拉满很容易触发限流导致瞬间大量失败。低速开始观察单任务耗时再逐步提高并发找到吞吐和稳定性都不错的平衡点。如果使用本地模型关注的是显存、内存和 CPU/GPU 占用。推理阶段显存涨上去后GC 和模型切换会带来额外延迟。建议先跑一条任务记录显存峰值再跑两条再跑四条。不要一上来就开最大并发。磁盘空间也很容易被忽略。批量任务中间产物通常不会很小尤其当你会生成代码、测试报告、原始日志时。建议每跑完一批任务做一次产物清理或归档保留压缩后的摘要即可。6. 想上生产先要处理哪些边界和坑6.1 上下文窗口有限不要硬塞整份图纸很多 pipelines 在步骤之间传递完整项目代码。这样做非常不经济而且可能让模型忽略关键细节。解决办法是“引用而不是复制”步骤输出只包含关键字段和文件路径下游步骤按需读取文件。如果一个步骤确实需要读取大量文件可以做一个简单的提取器把相关的类签名、数据模型和 TODO 汇总成一个上下文文件。这个上下文文件应该控制在一定规模比如 3000 到 6000 个 token 以内。超过这个量就说明你的工序拆分得不够细。6.2 版本漂移和依赖地狱软件工厂里“版本漂移”是一件非常隐蔽的坑。模型会更新代码生成器会更新模板库会更新测试框架会更新。今天跑通的任务下周可能因为依赖变化产出完全不同的结果。解决办法是把运行环境固化成版本清单。至少包含模型名称和版本、依赖库的requirements.txt或package.json、代码模板库的 commit hash、脚本版本。每条流水线运行时把版本信息写入step_meta.json。这样当产品结果异常时你能够判断是环境漂移导致还是任务本身变化导致。另一个容易踩的是旧模板生成的新代码无法兼容新框架。比如你的代码模板还在用旧版 FastAPI 语法但运行时依赖已经升级。解决方案是在流水线里加一个“版本检查”步骤在生成代码前后都对比一遍模板版本、依赖版本和生成器版本不匹配时直接中止。6.3 自动化边界哪些工序值得自动化哪些不该软件工厂不是把所有环节都自动化而是把“适合自动化的部分”抽出来。判断标准有三个规则是否明确结果是否可以验证出错后是否可以回滚满足这三条的工序比如生成 CRUD 代码、生成接口测试、格式检查、模板填充适合放上流水线。不满足的工序比如最终的用户验收、涉及合同条款的审查、高风险的架构决策应该保留人工审批节点流水线在推进到该节点时暂停。我在多 agent 项目里见过一个常见错误把“决策任务”也交给 subagent 自动完成。比如让 agent 决定“这个模块是否要引入 Redis”然后直接写入代码。这类决策业务影响大、验收标准模糊不应该全自动执行。更稳妥的做法是让 agent 生成“建议方案”和“备选方案”由人来拍板然后把人确认的结果作为下一步输入。6.4 多人协作时工厂模型需要组织配套软件工厂能不能跑起来一半靠技术一半靠组织。流水线一旦建立所有成员都要尊重工件目录、命名规范、质量门禁。否则就出现“我本地改了文件流水线不知道”“我加了新模型没更新 schema”“我不跑测试就提交”的情况。团队里要有一个清晰的“工厂管理员”角色负责维护流水线配置和模板版本其他成员只负责提供任务和检查产物。第一次落地我建议按两周一个迭代来推进。第一周只跑一条任务每天记录成功率和异常第二周把任务量扩大到 20 条再根据指标调整步骤。不要第一周就追求所有任务都能自动化更不要一开始就搭可视化管理页面。先把最小闭环跑稳这些后来都来得及补。注意如果某个步骤连续失败超过三次不要急着加大重试次数。先看日志、看输入、看契约。很多问题是子任务上下文缺少必要信息而不是模型能力不够。最后想说的话软件工厂设计模式真正落地时最需要盯住的三件事是部件契约、产物现场、观察指标。契约让装配线可以组合现场让失败可以定位指标让优化有依据。至于具体用哪个模型、哪个生成器、哪个 runner都可以灵活替换。我个人更建议先把单条任务跑稳再考虑批量和代理协作。当一条流水线稳定处理 20 条同类任务后你会更加清楚哪些步骤应该做成独立服务哪些步骤可以交给 subagent 动态规划哪些步骤永远需要人来判断。到那时候软件工厂才真正从一个概念变成你的工程能力。