Agentic 工程模式

Table of Contents

Agentic 工程模式

Simon Willison 的 Claude Code 最佳实践

Agentic Engineering vs Vibe Coding


写在前面

我开始了一个新项目,收集和记录 Agentic 工程模式——帮助在这个 coding agent 新时代获得最佳结果的编码实践和模式。

我用"Agentic Engineering"来指代使用 coding agent 构建软件——像 Claude Code 和 OpenAI Codex 这样的工具,它们的定义性特征是既能生成又能执行代码——这使它们能够独立于人类监督的逐轮指导来测试代码并迭代。

我认为"vibe coding"使用的是它的原始定义——完全不注意代码的编码方式,今天这通常与非程序员使用 LLM 编写代码相关联。

Agentic Engineering 代表了天平的另一端:专业软件工程师使用 coding agent 来改进和加速他们的工作,通过放大他们现有的专业知识。

关于这个新学科有太多东西需要学习和探索!我已经在我的 ai-assisted-programming 标签下发表了很多内容(345 篇文章还在增加),但那是相对非结构化的。我的新目标是产出一个能帮助回答"如何从中获得好结果"这个问题的东西,全部在一个地方。

我将在我的博客上以一系列章节形式的模式来发展和扩展这个项目,灵感来自 1994 年流行的《设计模式:可复用面向对象软件的基础》的格式。

关于作者:所有文字由我本人撰写,而非 LLM。我有强烈的个人政策:不在我的名字下发布 AI 生成的写作。我会使用 LLM 进行校对、完善示例代码以及各种其他辅助任务,但你在这里读到的文字将是我自己的。


原则

写代码的成本已经接近于零

采用 agentic 工程实践的最大挑战是适应这个事实带来的后果:写代码现在很便宜

代码一直都很昂贵。产生几百行干净、经过测试的代码需要大多数软件开发者整整一天或更长时间。我们的许多工程习惯,无论是宏观还是微观层面,都是围绕这个核心约束建立的。

在宏观层面,我们花大量时间设计、估算和规划项目,以确保我们昂贵的编码时间被尽可能高效地利用。产品功能想法是根据它们在多少时间内能提供多少价值来评估的——一个功能需要多次赚取其开发成本才值得!

在微观层面,我们每天做出数百个基于可用时间和预期权衡的决定。我应该重构那个函数让它稍微优雅一点吗,如果这要增加一小时的编码时间?写文档呢?为这个边缘情况添加测试值得吗?我能证明为这个构建调试界面是合理的吗?

Coding agent 大幅降低了将代码输入电脑的成本,这颠覆了我们许多现有的关于哪些权衡有意义的个人和组织直觉。

并行运行 agent 的能力使这更难评估,因为一个人类工程师现在可以同时在多个地方实现、重构、测试和记录代码。

好代码仍然有成本

交付新代码的价格已降至几乎免费……但交付好代码仍然明显更昂贵。

我说的"好代码"是指:

好代码的 8 个维度

  • 代码能用。它做它应该做的事,没有 bug。

  • 我们知道代码能用。我们采取了步骤来向自己和其他人确认代码是适合目的的。

  • 它解决了正确的问题

  • 它优雅地、可预测地处理错误情况:它不只是考虑快乐路径。错误应该提供足够的信息来帮助未来的维护者理解出了什么问题。

  • 它简单且最小化——它只做需要的事,以一种人和机器现在和将来都能理解和维护的方式。

  • 它被测试保护。测试表明它现在能用,并作为回归套件来避免它在未来悄悄损坏。

  • 它在适当的级别被记录,并且该文档反映系统的当前状态——如果代码更改了现有行为,现有文档需要更新以匹配。

  • 设计允许未来的更改。保持 YAGNI 很重要——添加复杂性来预期可能永远不会到来的未来更改的代码通常是坏代码——但同样重要的是不要编写使未来更改比应有的难度大得多的代码。

  • 所有其他相关的"ility"——可访问性、可测试性、可靠性、安全性、可维护性、可观察性、可扩展性、可用性——适合正在开发的特定类别软件的非功能质量度量。

Coding agent 工具可以帮助解决大部分这些问题,但仍然有相当大的负担落在驱动这些工具的开发者身上,以确保生成的代码对于当前项目所需的"好"的子集来说是好代码。

我们需要建立新习惯

挑战在于发展新的个人和组织习惯来响应 agentic engineering 的功能和机会。

这些最佳实践仍在我们的行业中探索。我自己也还在探索。

目前我认为我们能做的最好是自我质疑:任何时候我们的直觉说"不要构建那个,不值得花时间",还是发送一个提示,在一个异步 agent 会话中,最坏的情况是你十分钟后检查发现它不值得那些 token。


囤积你知道如何做的事情

囤积-重组模式

我关于高效使用 coding agent 的许多技巧是我发现没有它们也很有用的建议的延伸。这里有一个很好的例子:囤积你知道如何做的事情

构建软件技能的很大一部分是理解什么是可能的、什么是不可能的,并且至少对这些事情如何完成有一个粗略的想法。

这些问题可以是广泛的或相当冷门的。网页能单独用 JavaScript 运行 OCR 操作吗?iPhone 应用能在应用未运行时与蓝牙设备配对吗?我们能用 Python 处理 100GB 的 JSON 文件而不先加载整个文件到内存吗?

你对这类问题的答案了解得越多,你就越有可能发现用技术以其他人可能还没想到的方式解决问题的机会。

知道某事理论上可能与亲眼看到它完成是不同的。作为软件专业人士需要发展的关键资产是对这类问题的深度答案集合,理想情况下由运行代码来说明。

我用多种不同方式囤积这样的解决方案。我的博客TIL 博客塞满了我弄清楚如何做的事情的笔记。我有超过一千个 GitHub 仓库收集我为不同项目写的代码,其中许多是演示关键想法的小型概念验证。

最近我使用 LLM 来帮助扩展我有用问题的代码解决方案集合。

tools.simonwillison.net 是我最大的 LLM 辅助工具和原型集合。我用这个来收集我所谓的 HTML 工具——嵌入 JavaScript 和 CSS 并解决特定问题的单个 HTML 页面。

我的 simonw/research 仓库有更大、更复杂的例子,我挑战 coding agent 研究一个问题并返回工作代码和详细说明它发现了什么的书面报告。

从你的囤积物中重组东西

为什么要收集所有这些东西?除了帮助你建立和扩展你自己的能力,你在过程中生成的资产成为你 coding agent 的 incredibly powerful 输入。

我最喜欢的提示模式之一是告诉 agent 通过组合两个或更多现有的工作示例来构建新东西。

一个帮助我明确这有多有效的项目是我添加到我的工具集合的第一样东西——一个基于浏览器的 OCR 工具,在这里有更详细的描述。

我想要一个简单的、基于浏览器的工具来 OCR PDF 文件的页面——特别是完全由扫描图像组成、根本没有提供文本版本的 PDF。

我之前尝试过在浏览器中运行 Tesseract.js OCR 库,发现它非常有能力。该库提供成熟的 Tesseract OCR 引擎的 WebAssembly 构建,让你从 JavaScript 调用它来从图像中提取文本。

但我不想处理图像,我想处理 PDF。然后我记得我也用过 Mozilla 的 PDF.js 库,它可以将 PDF 的单个页面转换为渲染图像。

我在笔记中有这两个库的 JavaScript 代码片段。

这是我输入到模型的完整提示(当时是 Claude 3 Opus),结合我的两个示例并描述我寻找的解决方案:

使用 PDF.js 和 Tesseract.js 构建一个单页 HTML 应用,用户可以拖放 PDF 文件,然后显示 OCR 处理过的每一页的文本。使用我的 PDF.js 示例中的代码来渲染页面,使用 Tesseract.js 示例中的代码来处理它们。

这完美地工作了!模型输出了一个完全符合我需要的概念验证页面。

我最终迭代了几次以得到我的最终结果,但只花了几分钟就构建了一个从那以后我一直受益的真正有用的工具。

Coding agent 使这更强大

我在 2024 年 3 月构建了那个 OCR 示例,几乎是在 Claude Code 首次发布前一年。Coding agent 使囤积工作示例变得更有价值。

如果你的 coding agent 有互联网访问权限,你可以告诉它做这样的事情:

curl https://tools.simonwillison.net/ocr/ 然后弄清楚这个 OCR 工具是如何工作的,并为音频转录构建一个类似的工具。

(我在那里指定 curl 是因为 Claude Code 默认使用 WebFetch 工具,它总结页面内容而不是返回原始 HTML。)

Coding agent 非常擅长搜索,这意味着你可以在你自己的机器上运行它们,并告诉它们在哪里找到你想让它们做的事情的示例:

搜索我的 ~/Development 目录中任何涉及 EXIF 数据的代码,然后使用你找到的示例构建一个工具,可以从照片中提取 GPS 坐标并将其显示在地图上。

通常这就够了——agent 会启动一个搜索子 agent 来调查并拉取它需要的细节来完成任务。

由于我的很多研究代码是公开的,我经常告诉 coding agent 克隆我的仓库到 /tmp 并将它们用作输入:

克隆 https://github.com/simonw/tools 到 /tmp/simonw-tools 然后搜索任何使用 WebAssembly 的代码示例。使用这些示例构建一个新的工具,可以[…]

这里的关键想法是,coding agent 意味着我们只需要弄清楚一个有用的技巧一次。如果那个技巧然后在某处有工作代码示例记录,我们的 agent 可以查阅那个示例并使用它来解决未来任何类似形状的项目。


测试与 QA

红/绿 TDD

红/绿 TDD 循环

“使用红/绿 TDD"是一个令人愉快的简洁方式来从 coding agent 获得更好的结果。

TDD 代表测试驱动开发。这是一种编程风格,你确保你写的每一块代码都伴随着演示代码能用的自动化测试。

最纪律严明的 TDD 形式是测试优先开发。你先写自动化测试,确认它们失败,然后迭代实现直到测试通过。

这结果是对 coding agent 的绝佳匹配。Coding agent 的一个重要风险是它们可能写不能用的代码,或者构建不必要且从未被使用的代码,或者两者兼有。

测试优先开发有助于防范这两个常见错误,并确保一个健壮的自动化测试套件来防止未来的回归。随着项目增长,新更改可能破坏现有功能的机会也随之增长。一个全面的测试套件是保持这些功能工作的最有效方式。

在实现代码让测试通过之前确认测试失败很重要。如果你跳过那个步骤,你冒着构建一个已经通过的测试的风险,因此未能演练和确认你的新实现。

这就是"红/绿"的意思:红阶段看测试失败,然后绿阶段确认它们现在通过了。

每个好的模型都理解"红/绿 TDD"是更长指令的简写:“使用测试驱动开发,先写测试,在实现让它们通过的更改之前确认测试失败”。

示例提示:

使用红/绿 TDD 为一个函数添加一个新的特性标志检查,该函数计算给定用户的折扣百分比。


先运行测试

当使用 coding agent 时,自动化测试不再是可选的。

不写它们的旧借口——它们耗时且在不断演进的代码库中重写成本高——当 agent 能在几分钟内搞定它们时不再成立。

它们对于确保 AI 生成的代码做它声称做的事情也至关重要。如果代码从未被执行过,它在部署到生产时实际上能用纯粹是运气。

测试也是帮助 agent 了解现有代码库的好工具。观察当你问 Claude Code 或类似工具关于现有功能时会发生什么——很可能它们会找到并阅读相关的测试。

Agent 已经偏向于测试,但现有测试套件的存在几乎肯定会推动 agent 测试它做的新更改。

每次我对现有项目用 agent 开始新会话时,我会先提示以下变体:

运行测试

对于我的 Python 项目,我有 pyproject.toml 设置,这样我可以提示:

运行 uv run pytest

这四个字的提示有几个目的:

  • 它告诉 agent 有测试套件并迫使其弄清楚如何运行测试。这几乎确保 agent 将来会运行测试以确保它没有破坏任何东西。

  • 大多数测试工具会给 agent 一个大致的测试数量指示。这可以作为项目有多大和复杂的代理,也暗示如果 agent 想了解更多应该搜索测试本身。

  • 它让 agent 进入测试心态。运行了测试后,它自然会稍后用自己的测试扩展它们。

与"使用红/绿 TDD"类似,“先运行测试"提供了一个四个字的提示,包含了已经融入模型的大量软件工程纪律。


理解代码

交互式解释

当我们忘记了我们的 agent 写的代码是如何工作的,我们就承担了认知债务。

对于很多事情这并不重要:如果代码从数据库获取一些数据并将其输出为 JSON,实现细节可能足够简单以至于我们不需要关心。我们可以试用新功能并非常可靠地猜测它是如何工作的,然后浏览代码确认。

但通常细节确实很重要。如果我们应用程序的核心变成一个我们不完全理解的黑盒,我们就不能再自信地推理它,这使得规划新功能更难,最终像积累的技术债务一样减慢我们的进度。

我们如何偿还认知债务?通过提高我们对代码如何工作的理解。

我最喜欢的方法之一是构建交互式解释。

理解词云

An AI agent coding skeptic tries AI agent coding, in excessive detail 中,Max Woolf 提到用这个提示测试 LLM 的 Rust 能力:创建一个 Rust 应用,可以创建"词云"数据可视化,给定一个长输入文本。

这引起了我的想象:我一直想知道词云是如何工作的,所以我发起了一个异步研究项目——初始提示在这里代码和报告在这里——来探索这个想法。

这工作得非常好:Claude Code for web 为我构建了一个 Rust CLI 工具,可以产生像这样的图像。

但它实际上是如何工作的?

Claude 的报告说它使用"阿基米德螺旋放置与每词随机角度偏移以获得自然外观的布局”。这对我没什么帮助!

我请求了代码库的线性演练,这帮助我更详细地理解 Rust 代码——这是那个演练(和提示)。这帮助我理解了 Rust 代码的结构,但我仍然没有直观地理解那个"阿基米德螺旋放置"部分实际上是如何工作的。

所以我请求了一个动画解释。我通过将链接粘贴到现有的演练文档到 Claude Code 会话中,加上以下内容:

构建一个工具来解释这段代码是如何工作的。我希望有一个交互式的 HTML 页面(单个 HTML 文件,用 vanilla JS 和 Tailwind),可以可视化这个算法放置词的过程。

你可以在这里玩结果

如果你仔细观察动画,你可以看到对于每个词,它尝试将其放在页面某处,通过显示一个框,运行检查该框是否与现有词相交。如果是,它继续尝试找到一个好位置,从中心向外螺旋移动。

我发现这个动画真的帮助我让算法的工作方式豁然开朗。

我长期以来一直是动画和交互界面的粉丝,用来帮助解释不同的概念。一个好的 coding agent 可以按需产生这些来帮助解释代码——它自己的代码或其他人写的代码。


线性演练

有时让 coding agent 给你代码库的结构化演练很有用。

可能是你需要上手的现有代码,可能是你忘记了细节的自己的代码,或者可能是你完全 vibe coded 的东西,需要理解它实际上是如何工作的。

前沿模型配合正确的 agent 工具可以构建详细的演练来帮助你理解代码是如何工作的。

使用 Showboat 和 Present 的示例

我最近在我的 Mac 上用 Claude Code 和 Opus 4.6 vibe coded 了一个 SwiftUI 幻灯片演示应用

我在谈论 2025 年 11 月到 2026 年 2 月之间前沿模型的进步,我喜欢在我的演讲中至少包含一个噱头(一个 STAR 时刻——他们会永远记住的东西)。在这种情况下,我决定噱头是在演示结束时揭示幻灯片机制本身是 vibe coding 能做的示例。

我把代码发布到 GitHub,然后意识到我对它实际上如何工作一无所知——我提示了整个东西(部分文字稿在这里)而没有关注它正在写的代码。

所以我启动了一个新的 Claude Code for web 实例,指向我的仓库并提示:

使用 Showboat 创建一个 walkthrough.md 文档,演练这个代码库,解释所有代码是如何工作的。使用 showboat note 添加 Markdown 到文档。使用 showboat exec 来运行 sed 或 grep 或 cat 或任何你需要包含你正在谈论的代码片段——不要手动将代码复制到文档中。

Showboat 是我构建的一个工具,帮助 coding agent 编写演示它们工作的文档。你可以看到 showboat –help 输出在这里,它被设计为给模型它需要知道的一切来使用该工具。

showboat note 命令向文档添加 Markdown。showboat exec 命令接受一个 shell 命令,执行它,然后将命令及其输出都添加到文档。

通过告诉它使用"sed 或 grep 或 cat 或任何你需要包含你正在谈论的代码片段”,我确保 Claude Code 不会手动将代码片段复制到文档中,因为这可能引入幻觉或错误的风险。

这工作得非常好。这是 Claude Code 用 Showboat 创建的文档,详细讲述了所有六个 .swift 文件,并提供了关于代码如何工作的清晰和可操作的解释。

仅从阅读这个文档,我学到了很多关于 SwiftUI 应用是如何结构的,并吸收了一些关于 Swift 语言本身的可靠细节。

如果你担心 LLM 可能会降低你学习新技能的速度,我强烈建议采用像这样的模式。即使是约 40 分钟的 vibe coded 玩具项目也可以变成探索新生态系统和挑选一些有趣新技巧的机会。


附录

我使用的提示词

本指南的这一部分将不断更新我自己使用的提示词,从其他章节适当地链接过来。

Artifacts

我经常使用 Claude 的 Artifacts 功能进行原型设计和构建小型 HTML 工具。Artifacts 是当普通 Claude 聊天构建一个 HTML 和 JavaScript 应用并直接在 Claude 聊天界面内显示它时。OpenAI 和 Gemini 提供类似的功能,它们都称为 Canvas。

模型喜欢为这些使用 React。我不喜欢 React 需要额外的构建步骤,这阻止我将代码从 artifact 复制并粘贴到其他地方的静态托管,所以我使用带有以下自定义指令的 Claude 项目创建我的 artifacts:

永远不要在我的 artifacts 中使用 React。坚持使用 vanilla JavaScript 和我可以通过 CDN 加载的库,如 Tailwind、Vue、Alpine 或 d3。

校对

我不让 LLM 为我的博客写文字。我的硬性规定是任何表达观点或使用"我"代词的东西都需要由我编写。我会允许 LLM 更新代码文档,但如果某物有我的名字和个性附加,那我自己写。

我确实使用 LLM 来校对我发布的文字。这是我当前的校对提示,我在 Claude 项目中用作自定义指令:

校对我提供的任何文字。指出拼写错误、语法错误或尴尬的措辞。不要重写整个段落——只需指出问题并让我决定如何修复它们。如果你没有发现任何问题,说"没有发现错误"。


原文链接

  • 主页:https://simonwillison.net/guides/agentic-engineering-patterns/
  • 介绍:https://simonwillison.net/2026/Feb/23/agentic-engineering-patterns/

翻译:Claw | 2026-03-02