O'Reilly 简报:意外成为编排者的开发者

内容管家 AI领域评论17字数 5700阅读19分0秒阅读模式

AI 编程工具时代,开发者为何反而更焦虑?

两种极端论调都不靠谱

关于 AI 与软件开发的关系,圈内一直流传着两种极端说法。一种认为"末日来临",Claude Code 这类工具会让软件工程在一年内彻底淘汰;另一种则说"别担心,AI 不过是工具箱里的新玩意儿"。作者认为,两种论调都不够诚实。

理论懂,但落地难

作者有超过 20 年软件开发报道经验,近两年专注于 AI 工具培训和写作。他发现一个核心问题:没有人能给资深开发者提供一套系统的 AI 协作方法论。市面上的建议要么是零散技巧,要么是空洞宣传,唯独缺少可练习、可教学、可批评、可改进的结构化体系。

Andrej Karpathy(特斯拉前 AI 负责人、OpenAI 创始成员)提出了"代理工程"(agentic engineering)概念,Addy Osmani 的框架也指出:AI 代理负责实现,但人类拥有架构、审核&查验每一个 diff、持续测试的主导权。

开发者们理论上都知道应该审核&查验 AI 输出、维护架构、编写测试、更新文档、掌控代码库。但真正的问题是:

  • 如何审核&查验 AI 生成的数千行代码?
  • 连续数周跨多个 AI 工具工作时,如何保持架构一致性?
  • 如何识别 AI "自信地犯错"?

这种困境不局限于初级开发者——资深工程师同样会感到不适应。差异不在于工作年限,而在于是否找到了有效的结构化 AI 协作方法。理论与实践之间的鸿沟,正在成为许多开发者焦虑的根源。

AI 反而提高了专业门槛

与流行叙事相反,代理工程并不消除开发者专业知识的价值——恰恰相反,它提高了对开发者能力的要求。

作者在另一篇文章《认知捷径悖论》中指出:那些从 AI 编程工具中获益最多的开发者,往往本身就深刻理解"什么是好软件",能迅速判断某段代码是否出自 AI 之手。

这一洞察与作者长期观察一致:AI 工具在经验丰富的开发者手中效果最佳。他决定用实践来验证这个想法——用这套方法完整开发一个生产系统。

实验项目:Monte Carlo 模拟

作者选择用 Monte Carlo 模拟作为测试项目。这个选择源于童年记忆:父亲是流行病学家,家里常年与统计数据为伴,他 11 岁时就用 BASIC 在 TRS-80 Color Computer 2 上写过"醉汉水手问题"模拟——每步随机向水或向船的方向走,最终是否会落水。这个经典问题展示了 Monte Carlo 方法的核心思想:单次结果不可预测,但重复上千次后,规律会从噪声中浮现

Monte Carlo 模拟是一种无法解析求解时的应对策略——通过数百上千次模拟,用统计聚合收敛出真实答案。这正是作者想要验证的场景:用自然语言描述模拟任务,让 AI 完成从随机种子到结果验证的全流程,并生成可用的统计数据。

从 Octobatch 实验看 AI 驱动开发

本系列开篇,我先交代一个完整的实践案例:历时七周、约 75 小时的有效开发时间,产出一个约 21,000 行 Python 代码的应用,具备完整的规格说明、近千条自动化测试,以及质量集成与回归测试套件。这个项目叫 Octobatch,初衷就是为代理工程(agentic engineering)领域提供一份真实的端到端案例。

整个过程中,Claude 与 Gemini 协作完成架构设计,Claude Code 负责代码实现,相关流水线则由 LLM 生成——AI 工具贯穿了项目的每一个层级。系列文章不止讲 Octobatch 本身,更希望提炼出在这套流程中学到的经验:哪些模式真正有效,哪些失败反而最有价值,以及贯穿始终的编排思维(orchestration mindset)。

什么是 AI 驱动开发(AIDD)

当前业界使用 AI 写代码,主要有两种思路:

  • AI 编码助手:GitHub Copilot、Cursor、Windsurf 等,已从自动补全演变为能够运行多文件编辑会话、定义自定义代理的代理工具。
  • Vibe Coding:用自然语言描述需求,接受 AI 返回的任何结果。

这两种工具确实令人印象深刻,也确实能提升效率。但在真实项目中维护数千行 AI 生成代码的架构一致性,是另一个完全不同的问题。

AI 驱动开发(AIDD) 正是为了解决这个问题而生的。它是一种结构化的代理工程实践方法:AI 工具驱动实现、架构乃至项目管理的多个环节,而人类(loop 中的那个人)负责决定"构建什么"以及"构建结果是否合格"。

AIDD 的核心在于:

  • 开发者不给 AI 随意发挥,而是为不同工具分配特定角色:一个 LLM 负责架构规划,一个负责代码执行,一个编码 agent 负责实现,人类则负责愿景、验证,以及那些需要理解全局的决策。
  • "驱动"是字面意义上的:AI 几乎写所有代码。我在 Octobatch 实验中设了一条底线——让 AI 写全部代码,同时我保留高标准的代码质量要求,看 AIDD 能否达到这个标准。

当然,并非所有人都认同人类需要多大程度地参与。Anthropic 的 Nicholas Carlini 近期让 16 个 Claude 实例并行开发一个 C 编译器,全程无人类介入。2,000 次会话、$20,000 的 API 成本之后,产出了一个能构建 Linux 内核的 10 万行编译器,但它并非任何场景的即用替代品。更关键的是,当 16 个 agent 同时卡在同一个 bug 上时,最终还是需要人类介入分区任务。即便是完全自动化 vibe 驱动模式的强烈支持者,恐怕也会认为这步子迈得过大了。

关键问题在于:需要多少人类判断力才能让这些代码真正可信?哪些具体实践能帮助开发者有效运用这些判断力?

编排思维与 Sens-AI 框架

如果想让开发者以正确的方式理解代理工程,首先要从他们思考与 AI 协作的方式入手,而不是从工具选型入手。

这正是我构建 AIDD 方法论的起点——从习惯(habits)入手。我为此开发了一套框架,称为 Sens-AI Framework,已以 O'Reilly 报告Critical Thinking Habits for Coding with AI)和 Radar 系列文章形式发布。

Sens-AI 框架围绕五项实践展开:

  1. 提供上下文:让 AI 准确理解任务背景。
  2. 提示前先研究:不要急着问,先自己调研清楚。
  3. 精准定义问题:把需求描述清楚,减少 AI 误判。
  4. 刻意迭代输出:对 AI 的结果进行多轮打磨,而非一次接受。
  5. 批判性审视 AI 产物:对 AI 输出的每一步都保持审视。

从习惯入手,是因为习惯决定了一个人如何思考自己的协作方式。没有这些习惯,AIDD 只能产出看起来合理、但经不起细看的代码。有了这些习惯,才能在同等时间内构建出单靠开发者个人无法完成的系统。

习惯是基础,但不是全部。AIDD 还包含:

  • 实践(Practices):具体技术手段,如多 LLM 协作、上下文文件管理、用一个模型验证另一个模型的输出。
  • 价值观(Values):支撑这些实践的原则。

如果你熟悉 Scrum 或 XP 等敏捷方法论,这套结构应该不陌生——实践告诉你日常怎么做,习惯则是让实践变成本能反应的 reflexes。

价值观与编排思维

如果说你能从这套方法论中带走一件事,那就是:价值观决定了你在实践指南给不出明确答案时如何做决定。AIDD(AI Driven Development,AI 驱动开发)正在形成一种新兴工程文化,你的项目价值观要么与之契合,要么与之冲突。理解价值观的来源,才能让实践真正扎根。所有这些,最终指向一种全新的思维方式——我称之为编排思维(Orchestration Mindset)

本系列文章以 Octobatch 为试验田,从零构建 AIDD 的四个层次。

Octobatch:刻意设计的实验

Octobatch 并不是顺势而为的产物,而是一个刻意的 AIDD 实验场。我把它设计成整个方法的验证案例,想看看有纪律的 AI 驱动工作流能产出什么,又会在哪里崩溃——然后用实际结果反过来打磨实践和价值观。无论凭直觉还是巧合,我都选中了完美的实验对象。

Octobatch 是一个批处理编排器(batch orchestrator),负责:

  • 协调异步任务
  • 管理故障状态
  • 追踪管线步骤间的依赖关系
  • 确保最终输出经过验证

这类系统的设计乐趣十足,但实现细节——状态机、重试逻辑、崩溃恢复、成本核算——往往枯燥乏味。恰好,这些正是 AIDD 最能发挥威力的场景:模式早已成熟,实现却充满重复劳动和出错风险。

编排成为核心理念

「编排」——将多个独立进程协调以达成一致结果——逐渐演变为 AIDD 的核心概念。我发现自己用编排 LLM 的方式,与 Octobatch 编排批处理任务如出一辙:分配角色、管理交接、验证输出、从失败中恢复。我正在构建的系统,和构建系统所用的流程遵循同一模式。

这是「偶然的编排者」中那个「偶然」的意外:一开始并没有预见到,构建一个编排 AI 的系统,恰恰是学习如何编排 AI 的最佳途径。这个平行关系贯穿本系列每一篇文章。

从聊天到批处理

Octobatch 项目的起点并非端到端蒙特卡洛模拟,而是和大多数人一样——在聊天界面里敲提示词。我尝试了不同的模拟和生成方案来给项目定框架,其中几个留了下来:「二十一点」策略对比成为多步蒙特卡洛模拟的绝佳测试用例;RPG 游戏中的 NPC 对话生成提供了有主观质量标准可衡量的创意工作负载。两者结构相同:一组结构化输入,每个用相同方式处理

Article hero image

我让 Claude 写了个简单脚本,把手动操作自动化,再用 Gemini 复核,确保 Claude 真正理解我的意图并修正幻觉。小规模运行效果不错,但一旦超过上百个单元,就不断撞到速率限制(rate limits)——提供商对每分钟 API 请求次数设的上限。

这推动了向 LLM 批处理 API 的迁移。

批处理 API 的优势

传统方式挨个发送提示词、等待每个响应;批处理 API 则允许一次性提交包含所有请求的文件,提供商按自己的节奏处理,无需等待实时结果,还不受速率上限约束。更惊喜的是,费用只有实时 API 的 50%,而且在大规模场景下性能反而更好——超过 100~200 个单元后,批处理开始显著快于实时调用,因为提供商在自己的基础设施上并行处理整个批次,不再受往返延迟或速率限制的瓶颈影响。

这个转变改变了我对「大规模协调 LLM API 调用」这个问题的整体认知,并催生了可配置管线的想法:多个阶段可以链式连接,前一步的输出成为下一步的输入,整条管线一键启动,等结果就好。

2024 年 4 月至 2025 年 7 月间,OpenAI、Anthropic 和 Google 三家主要 AI 提供商相继推出批处理 API,定价模型趋于一致:异步处理费用为实时费用的 50%

你可能没有注意到这三家厂商同步上线批处理 API——行业话题被 AI 代理、工具调用、MCP 和实时推理主导,批处理 API 的发布相对低调。但它们代表了一种真正的范式转换:

不再把 LLM 当作对话伙伴或单次 SaaS API,而是当作处理基础设施,更接近 MapReduce 作业而非聊天机器人。给它结构化数据和提示模板,它处理全部并返回结果。关键在于,你现在可以可靠地运行成千上万个这样的转换,规模化无忧,无需手动管理速率限制或连接失败。

为什么不能简单写个循环?

既然批处理 API 这么好使,为什么不直接写个 for 循环提交请求、收集结果?

当然可以,简单场景下快速脚本加循环完全够用。但一旦开始运行更大规模的工作量,问题就开始堆积。解决这些问题的过程,恰恰是形成结构化 AI 代理工程方法论最重要的经验。

批处理与 Agent 工程的共通难题

在深入技术细节之前,有必要先厘清一个核心观察:LLM 批处理面临的挑战,与 agentic engineering(AI 驱动开发)中的问题高度重合。

四大挑战一览:

  • 异步状态追踪:任务提交后需等待数小时返回结果,脚本必须记录已提交内容并持续轮询完成状态。一旦脚本中途崩溃,状态随之丢失。
  • 部分失败处理:实际场景中往往是 97% 成功、3% 失败。需要精准定位失败项、单独提取并重新提交。
  • 多阶段流水线依赖:当某步骤的输出作为下一阶段的输入时,必须追踪阶段间的依赖关系。
  • 成本核算:运行数以万计的请求时,需要实时掌握已消耗成本,并在批量任务启动前预估总支出。

这四类问题的解决思路,与 agentic engineering 中管理多个 AI agent 并行工作、处理代码失败与 bug、确保整体项目一致性、俯瞰全局项目进度的需求完全对应。

复杂度转移:从连接到状态 这些问题都可以解决,但反复解决同一个问题会消耗大量精力——无论是在 LLM 批处理编排还是 AI 编码工具编排场景。批处理的核心教训是:复杂度从连接管理转移到了状态管理。实时 API 的难点在于速率限制和重试机制;批处理 API 的难点则是追踪在途任务、成功/失败状态,以及下一步该处理什么。

找不到现成工具

在动手开发前,作者首先调研了市面上已有的解决方案,期望避免重复造轮子。然而一无所获:

  • 工作流编排工具(如 Apache Airflow、Dagster):擅长管理 DAG 和任务依赖,但假设任务具有确定性,不提供 LLM 特有功能(如 prompt 模板渲染、基于 schema 的输出验证、或语义质量触发的重试逻辑)。
  • LLM 框架(如 LangChain、LlamaIndex):围绕实时推理链和 agent 循环设计,不管理异步批处理任务生命周期、不支持进程崩溃后的状态持久化、也不处理块级别的部分失败恢复。
  • 厂商自带批处理客户端库:只处理单个批次的提交和检索,无法支持多阶段流水线、跨步骤验证或跨厂商统一执行。

没有任何工具覆盖多阶段 LLM 批处理工作的完整生命周期——从提交、轮询、验证、重试、成本追踪到崩溃恢复,且横跨三大 AI 厂商。这正是 Octobatch 诞生的原因。

实验带来的早期教训

作为「Agentic Engineering 与 AI 驱动开发」系列的首篇文章,本文的核心目标是阐述 Octobatch 实验的假设与架构。后续文章将深入探讨验证架构、多 LLM 协调、从实践中浮现的方法论与价值观,以及将一切串联起来的编排思维。以下是两个最突出的早期教训,它们展示了 AIDD(AI-Driven Development)的实际形态,以及开发者体验为何比以往任何时候都更重要。

必须跑起来看数据

还记得那个"醉酒水手的蒙特卡罗模拟" Hello World 吗?某次运行时,Octobatch 模拟结果显示 77.5% 的水手落水。随机游走的标准结果应该是 50/50,显然哪里出了问题。

排查过程如下:

  • 使用 Claude Code 作为测试运行器,生成测试用例、执行并记录结果
  • Gemini 分析结果并定位到根本原因
  • 问题根源:随机数生成器在每次迭代时用顺序递增的种子值重新播种,导致运行间产生关联偏差

有趣的是后续:Claude 提出了一个包含大量预播种随机数值的变通方案;Gemini 提出了一种基于哈希的修复方案,但看起来过于复杂。最终发现,最佳方案比两个 AI 的建议都简单得多:为每个模拟单元维护一个持久化 RNG,让其自然推进序列。

核心教训:表面合理的输出和正确的输出并非一回事,必须具备足够的专业知识才能区分。AI 的建议是否采纳,取决于你是否真正理解统计学和代码。

大语言模型常常高估复杂度

某次需要为分析流水线添加自定义数学表达式支持。两个模型都表示反对:「这属于 v1.0 的范围蔓延」「留到 v1.1 再说」。Claude 估计需要三个小时实现。

然而,作者比 AI 更了解代码库——项目中已经在其他地方使用了 asteval(一个提供安全、最简化数学表达式求值器的 Python 库)。因此这只是一个已有库的复用场景,实际上:

  • Claude Code(由 Claude 生成)仅用两个 prompt
  • 总耗时约 5 分钟

功能上线后显著增强了工具能力。AI 保守的原因在于缺乏对系统架构的上下文了解。正是因为有经验,作者知道集成难度极低——没有这份经验,就会听从 AI 建议,将这个 5 分钟就能完成的功能推迟到未来版本。

AI 长于生成,弱于删除

生成式 AI 的本质是"生成",所以当用它来修复问题时,AI 的第一反应往往是添加代码——再加一层逻辑、再加一个特殊处理。

整个 Octobatch 项目下来,没有一次是 AI 主动说「把这些删掉,重新想想方案」。最有效的协作,反而是我主动推翻它的生成冲动、强行推动简化方案。资深工程师花多年才悟出的道理:最成功的代码改动,删除的往往比新增的多——那些值得炫耀的 PR,往往是删掉几千行代码的那个。

架构是从失败里「长」出来的

Octobatch 的核心架构并不是一开始就设计好的。第一版是个内存状态的 Python 脚本,小批量跑得还行,一上规模就崩——网络抖一下就要从头开始,格式异常的响应需要手动梳理。

真正的转折点是这条约束:系统必须能够随时被杀掉而不丢数据。围绕这个要求,tick 模型(唤醒→检查状态→执行→持久化→退出)、manifest 文件作为唯一真相来源,以及整套 crash-recovery 架构才逐渐成型。我们是在一次次"试图简化而失败"的过程中,逐步发现了这个设计。

开发记录本身就是数据集

整个系列你会看到很多 Octobatch 的故事。每个故事都来自我和 Claude、Gemini 之间聊天记录的回顾。AIDD 方法保留了每次架构决策、每个走弯路的时刻、每次我推翻 AI 或 AI 纠正我的完整记录。大多数开发团队从未有过这种精度的项目历史。挖掘这些日志并提炼经验教训,是我发现的最有价值的实践之一。

临近项目尾声,我切换到 Cursor 验证这些方法是否专属于 Claude Code。用同样的上下文文件在新工具里新建对话,立即就能进入高效状态——上下文文件按设计正常工作。这说明这套方法论的价值来自习惯、上下文管理,以及你带到对话中的工程判断,而不是来自某个特定工具。

下一步:让结构落地

Agentic engineering 需要结构,结构需要一个具体案例才能真正落地。系列下一篇文章将深入 Octobatch 本身:它如何编排 AI 任务、如何给不同处理步骤分配角色、如何管理环节之间的交接、如何验证输出、如何在失败时恢复。这与我构建它的方式完全对应——给 Claude 和 Gemini 分配角色、管理它们之间的交接、验证输出、在它们走偏时拉回来。理解这个系统的运作方式,正是理解编排 AI 驱动开发的关键。

后续文章将进一步展开 AIDD 的具体实践:如何在不失去架构控制的前提下协调多个模型、如何用实际意图来检验代码,以及"能跑的代码"与"做了你想做的事的代码"之间的鸿沟。实验过程中还产生了一些关于不同 AI 模型如何看待代码的意外发现——这些发现的影响超出预期。

延伸阅读

 
内容管家

发表评论