IBM Bob

充分发挥 Bob 的最大效用

一套源自构建 Bob 以及与一线从业者合作中总结出的核心概念——涵盖结构、上下文,以及在长期项目中改善成果的构建模块。

充分发挥 Bob 的最大效用

作者

IBM Bob Team

发布时间

分类

guide

分享

Agentic 编程正以科技界前所未有的速度发生变革。网上现有的教程和资源大多只涵盖简单全新场景下的个别功能。

在构建 Bob 以及与各行各业无数一线从业者交流的过程中,我们总结出了一套有助于提升使用 Bob 的效率和体验的概念。

这些概念同样适用于采用非主流技术的复杂项目。


概念 1:循环——探索、规划、实现、验证

探索、规划、实现、验证循环,外层循环用于持续改进指南和传感器

在 Agentic 软件工程中最常见的失败模式是缺乏结构。对话的连贯性常常伪装成结构,让我们忍不住把实现的所有步骤都塞进同一个聊天对话中。会话过程看似高效,但其代价往往在审查时才暴露出来。

以往手写代码本身就自带一种结构。因为实现成本高昂,所以在实现前先进行规划显得合情合理。理解会在打字的过程中不断积累,错误的假设也极有可能在此过程中浮出水面。 AI Agent 消除了这种阻力。如今编写代码的成本极其低廉,这也同时带走了我们对结构的直觉。曾经作为“行动缓慢”之副产品的结构,现在必须刻意去建立。

刻意运用这个循环可以提供所需的结构:

  • 探索(Explore)产生理解
  • 规划(Plan)产生决策
  • 实现(Implement)产生代码
  • 验证(Verify)产生证据。

遵循这个循环有助于你保持专注、富有结构,并更快、更稳定地达成目标。

单次完整循环可能耗时 20 分钟或 3 天。单次运行中还可以包含子循环,各个阶段之间的时间分配也会根据任务的不同而大相径庭。

有关该循环的详细剖析,请参见下文的深入探讨:运行该循环


概念 2:Context Window 是稀缺资源

对 Context Window 保持审慎是回报最高的习惯。

什么是 Context Window?

模型是无状态的。聊天并不是带有记忆的持续运行会话:每一轮对话都会重新发送之前的所有消息,并将新回答追加到末尾。Context Window 是模型在其中一轮中所能接收的最大输入量。在 Bob V2 中,这一限制为 270k tokens(context window 管理)。

在发出第一条消息之前,窗口就已经在被占用了:

  • 预先加载: Bob 的系统提示词(system prompt)、当前模式的描述、repo 的 agents.md,以及每个已连接 Model Context Protocol (MCP) 工具的描述(Bob 中的 MCP)。
  • 在会话期间隐式添加: 文件读取、工具返回结果、Bob 调用的 skill 文件、子 agent 输出。

Context Window 被填满并压缩成摘要

当窗口填满时,Bob 会压缩对话。Bob 会用摘要替换迄今为止的对话,然后继续工作。这可以保持会话继续进行,但这种机制在设计上是有损的。Bob 会自动决定保留哪些细节,而丢失的细节不会有任何标记。经历过两次压缩的会话实际上是运行在摘要的摘要之上。

单次 MCP 调用可能会返回数万个 token,而连续的文件读取会稀释会话早期讨论的内容。模式描述、规则文件和 MCP 服务器则会更缓慢且更隐蔽地占用窗口。Bob 按来源拆解了窗口占用情况,随着配置规模的扩大,非常值得重新查看该明细。

Bob 的 Context Window 指示器,展开显示按来源拆解的当前会话

Bobcoin 主要是按 token 计费的。因此,对话的成本随着其长度呈二次方增长。长对话比短对话要消耗多得多的 Bobcoin!(Bobcoins 文档

顺应 Context Window 工作,而非与其对抗

  • 将工作拆分到不同的独立对话中。 一个任务,一个会话。这与代码中的单一职责原则如出一辙。一个对话应该只有一个存在的理由,例如“绘制组件 X 的架构图”或“为功能 Y 创建实现计划”。Context Window 中的所有内容都会影响后续生成,包括那些行不通的方法。陷入困境的会话往往会一直卡住,因为失败的尝试仍然留在里面,模型会把它们当作关于该任务形态的依据(上下文污染)。
  • 回滚而不是与 Bob 争论。 当对话偏离预期行为时,回滚到最后一条正常消息,修改该消息,然后从那里继续。这还会撤销 Bob 在本地所做的所有更改,从而保持 Context Window 小巧且干净(回滚)。
  • 任何值得保留的内容都保存在文件中,而不是留在聊天中。 计划、发现和决策属于文件。同事可以审查 Markdown 文档并将其交给全新的会话;而聊天记录两者都做不到。
  • 子 agent 可以避免大量杂务占用 Context Window。 Bob 会决定何时运行子 agent,并且只有结论会返回。当某个任务会产生无需人工阅读的输出时,直接请求子 agent 也很有效(子 agent)。
  • 注意进入 Context Window 的内容以及它是否带来价值。定期检查你的指南和传感器(如下文所述),并花时间对其进行改进。

概念 3:两类构建模块——指南与传感器

在长期项目中,代码库是变好还是变坏,与 Bob 本身的关系较小,而更多取决于塑造其工作和检查其输出的机制。目前有许多可用的构建模块:规则(rules)、技能(skills)、模式(modes)、钩子(hooks)、子 agent、外部 linter 以及审查 agent。它们几乎都承担以下两项工作之一:

  1. 指南在 Bob 工作之前或工作期间引导它(前馈 / Feedforward)。 规则、技能和模式都属于指南。
  2. 传感器在 Bob 行动之后报告反馈(反馈 / Feedback)。 测试、linter、类型检查器、交互式浏览器会话以及审查 agent 都属于传感器。

一名坐在笔记本电脑前的人将箭头指向 Bob,Bob 将箭头指向代码。标有“指南”的箭头从上方进入 Bob,附带 rules、skills 和 modes 的注释。标有“传感器”的箭头从代码返回 Bob,附带 tests、linters 和 review agents 的注释。

1. 指南

任何提供给 Bob 用来引导其工作的机制都是指南。有三个主要的构建模块可以帮助你做到这一点,它们的作用机制是在你输入的 prompt 之外将文本放入 Context Window。它们的区别在于这些文本何时进入以及由什么触发。

规则始终处于活动状态,模式由用户激活,技能由 Bob 激活

  • **规则(Rules)**始终处于活动状态。 repo 根目录下的 agents.md 是最主要的规则文件,关于它的核心建议是保持简短。每一行内容在每一轮对话中都会竞争注意力,因此冗长的规则文件反而会导致 Bob 难以遵循其中的某条具体规则(规则)。
  • **模式(Modes)**由用户激活。 内置模式包括:Ask 为只读模式。Plan 推进规划流程并将结果交给负责执行行动的 Agent 模式。你可以轻松添加自定义模式(模式添加自定义模式)。
  • **技能(Skills)**由 Bob 在判定相关时自动激活。 只有简短的技能描述始终保持活动状态。技能的主体内容仅在按需时才会加载到上下文中。这使得技能具有极高的 token 使用效率(技能)。

规则文件中的所有内容无论在当前轮次中是否需要,都会在每一轮消耗 token,因此请保持其精简,让其余内容在适用时再加载。

2. 传感器

任何向 Bob 反馈工作产生成果的机制都是传感器。哪些信号有用取决于代码库和技术栈,因此值得保留的配置组合因项目而异,需要投入精力去搭建。最有价值的传感器是可由机器运行并在实现阶段由 Bob 执行的传感器。传感器可以分为两类:

  • 计算型传感器是确定性的:测试、linter、类型检查器、编译器。判定结果精确且可重复,成本足够低廉以供 Bob 频繁运行。覆盖范围取决于团队构建和维护的系统。
  • 基于 AI 的传感器灵活且非确定性。审查 agent 会阅读代码意图,并检查 linter 没有规则涵盖的内容。其输出是评判而非量度。它在不同运行之间存在差异,成本和耗时限制了其使用的频率(代码审查)。

接入它们有几种方式,大致按阻力从低到高排列:

  • **钩子(Hooks)**是阻力最小的确定性选项。检查会在固定节点运行,每次都会执行,无论 Bob 是否判定其相关。参见 hooks 文档
  • **技能(Skills)**通常用作指南,但运行审查的技能则是传感器,这是添加非确定性检查阻力最小的方式。参见 skills 文档
  • **持续集成(CI)**将审查 agent 置于流水线中,针对每次 pull request 运行,面向整个团队而非单个开发者。参见 PR 审查 agent 实战演示

深入探讨:运行该循环

各阶段的边界也是上下文的边界,这也是将它们保持独立的实际原因:探索阶段的闲聊不应该出现在编写代码的对话中。

1. 探索

探索活动会根据你的角色和当前任务而有很大差异。它可以指熟悉一个新代码库,也可以是评估重大重构的影响范围。一些示例:

  • 在更改任何系统之前,让 Bob 生成现有系统的架构图。 参见生成架构图教程对应的视频演示
  • 从两个角度请求定制的上手指南:一次作为浏览产品的用户,一次作为浏览代码的开发者。提供关于你的专业知识和任务的信息有助于定制该文档(检查代码库)。
  • 在 IBM Z 和 IBM i 上使用平台专用选项。 这些系统上的探索问题有所不同,并且能极大地受益于高级包中提供的专门工具。参见 Premium Package for Z文档)以及 Premium Package for IBM i文档)。

探索还可以包括构建你打算删除的内容。现在实现成本很低,因此小范围的原型是验证某种方案在与代码库接触后能否行得通的最快方式。Kent Beck 在 25 年前将这称为探针实现(spike implementation),其原则是一样的:为了学习而构建,保留学到的知识,抛弃代码。

低成本的实现提高了架构和代码质量的价值,而不是降低它。现在很容易生成大量看似正常但实际错误的代码。

2. 规划

规划阶段是杠杆效应最大的地方。计划中做对的每一件事都会带来双重回报:一次是在实现阶段,另一次是在更改离开作者之手且同事必须审查它时。

一份好的计划需要具备:

  • 既简短又精确。 计划是需要被阅读的。
  • 明确说明预期结果,包括不确定的部分。知道未知的是什么占了大部分工作,找出答案则是剩下的部分。
  • 保存在文件中。 计划不应该留在聊天会话中。

创建计划的方法有很多,但内置的 Plan 模式 是最容易上手的起点(如本教程所示)。 Plan 模式 旨在顺应用户,并倾向于填补空白。虽然这在很多情况下有助于快速迭代,但有时需要更高的严谨性。它可能会围绕一个糟糕的假设制定出一份看似合理的计划,而不会对该假设提出质疑。 使用专门针对计划提出质疑的技能——例如 Matt Pocock 的 grill-me——是在假设变成代码之前进行审查的最经济有效的方式。

关于规范驱动开发(SDD)。 这个术语涵盖很广,而且仍在不断演变。人们往往将其视为非黑即白的二选一决策,但它更像是一个光谱:

  • 规范优先(Spec-first):计划先于实现。这几乎是不容妥协的。
  • 规范针定(Spec-anchored):规范在实现之后予以保留,作为文档以及实现必须满足的标准。
  • 规范即源码(Spec-as-source):规范就是源文件。人类编辑规范;人类不编辑代码。

适合哪个级别取决于团队、代码库的关键程度/成熟度以及所在行业。更高层级的 SDD 所带来的开销可能会对快速迭代造成阻碍。在汽车行业,规范驱动开发比 AI 早了几十年,SDD 与现有的实践非常契合。

3. 实现

实现是直接明了的阶段,Bob 几乎负责处理其中的全部工作。

观察 Bob 工作并适时打断进行澄清是可选的,且通常很有用。将打断的频率视为一种信号:频繁打断意味着问题出在计划中,解决之道是回退重来,而不是不断纠偏。

不要舍不得抛弃整个实现并返回 Plan 模式。代码是成本最低的部分。

4. 验证

验证分为两个不同的类别:自动化验证和手动验证。

自动化验证由 Bob 可用的传感器驱动,或通过钩子强制执行。它们在实现阶段频繁执行,无需人工干预。主要类别及常见示例如下:

  • 有效性(Validity):是否能编译、通过类型检查、解析?
    • 衡量指标:通过/失败、类型覆盖率
    • 工具:tscmypycargo checkjavac
  • 行为(Behaviour):是否执行了正确的操作?
    • 衡量指标:通过率、分支覆盖率
    • 单元测试、集成测试、端到端测试
    • 工具:pytestJestPlaywrightStryker
  • 可维护性(Maintainability):这段代码是否值得保留?
    • 衡量指标:复杂度、重复度、边界违规
    • 工具:ESLint、Ruff、Lizard、ArchUnit
  • 安全性(Security):这段代码是否安全?
    • 衡量指标:按严重性分类的发现项、CVE
    • 工具:Semgrep、CodeQL、gitleaks、npm audit

它们使 Bob 能够在实现阶段发现自己的错误并提升质量。良好的测试覆盖率是防止回归的关键保障:它确保 Bob 没有破坏任何现有功能。

在这个循环中,验证被列为循环末尾的一个单独阶段,这主要指的是手动验证。 手动验证首先从运行修改并比较观察到的行为与计划中指定的行为开始。不匹配通常主要归结为以下两个原因之一:

  • 实现偏离了计划。修复工作在代码中。
  • 计划未能反映你想要构建的内容。计划需要改进。这种情况要常见得多。

因此,手动检查同时测试了计划和实现。

额外的验证应该在 CI/CD 流水线中进行。这是软件工程中成熟的实践,但可以通过使用无头(headless)编程 agent 来进一步提升。例如:针对每次 pull request 运行的自动化审查(通过 Bob Shell 运行)是对人工审查者的增强,而不是替代。参见 PR 审查 agent 实战演示视频以及以非交互方式运行 Bob Shell 的文档

团队协作

前面各节描述的都是单个开发者的内部循环。当更改进入审查队列时,外部循环便开始了。现在每个 diff 生成得更快,附带的推理更少,而审查者需要阅读的内容更多,阅读时的背景上下文却更少。

证据必须与工作成果一同交付。相对于如何做(how),为什么做(why)比以往任何时候都更为重要,因为如何做在产出上不再是成本高昂的部分。

在实践中,这意味着计划会随更改一同流动:团队会将其附加到 pull request 中,或将其与审查意见一起添加回原始 issue 中。具体机制取决于所使用的工具链。

外部循环对团队流程的影响本身就是一个独立的主题,我们将在后续文章中探讨。


关于 Prompt 的一些思考

在过去的几年里,人们非常强调正确 prompt LLM,甚至由此催生了“Prompt 工程师”这一全新职业类别。到了现阶段,大量的 prompt 工作已在 harness 内部处理。专门 prompt 技巧的重要性已经降低,取而代之的是方法论层面的考量。以下是一些指导原则:

  • 迭代优于微调 Prompt。 当 Bob 的输出偏离你的要求时,回滚并重写导致该结果的消息。继续纠偏会将错误的回答、对它的抱怨以及重试全部留在窗口中。
  • 方法论优于微调 Prompt。 Prompt 的作用范围仅限于单次会话。而规则文件或 Bob 可以自行运行的检查,在产生它们的会话之后的每个会话中都会持续生效,这是此处唯一能够持续积累的投资。
  • 给 Bob 资深工程师应有的工作简报。 一个有能力的同事拿到一个模糊的任务时,会询问判定完成的标准是什么以及允许改动什么;Bob 不会主动发问,因此请在消息中把这两点都写明。
  • 说明要做什么,而不是不要做什么。 “不要使用类组件”只排除了一种选项,剩下的空间依然开放,因此 Bob 会从剩下的选项中挑选,这又是一次猜测。直接指明目标——使用 hooks 的函数组件——就能一轮搞定。
  • 给出超过两次的任何指令都应当放入文件中。 这就是 agents.md 和 skills 的用武之地。
  • 更详细的 Prompt 指南可以在编写有效 prompt 教程中找到。

核心要点

  • 缺乏结构是最大的问题。 遵循 探索 → 规划 → 实现 → 验证 的循环有助于你保持专注,更快、更稳定地达成目标。
  • 上下文是稀缺资源,阶段即上下文边界。 不要把探索阶段的闲聊带入实现阶段。
  • 计划是审查的工件。 无论是对作者还是审查者而言,审查计划都优于审查 diff。
  • 任何值得保留的内容都要移出聊天。 计划、决策和发现属于文件。你可以对文件进行 diff、审查、版本控制,并将其交给另一个 agent。
  • 验证应当是机器可运行的,这意味着你必须在规划期间设计验证方案,而不是在事后去摸索。

来源与延伸阅读

IBM Bob 文档与教程: