文章摘要
文章围绕编码代理的Harness工程展开,指出为提升对大语言模型生成代码的信任需构建该体系。介绍了前馈与反馈、计算型与推理型机制,强调质量左移原则;还阐述了调节类别、Harnessability等内容,最后提及人类角色及待解决问题。

当基于大语言模型的编码代理真正融入团队的代码开发流程时,开发者们普遍面临一个核心挑战:如何建立对AI生成代码的信任。大语言模型本身具有非确定性,无法完全理解项目上下文,仅基于token序列进行预测,因此我们需要一套系统化的方法来提升对其输出的信任度。本文所探讨的harness工程,正是将上下文工程与现有harness工程的实践概念结合,构建一套完整的信任建立体系。

通常来说,harness 指代模型之外的所有组件,即 Agent = Model + Harness。针对编码代理的使用场景,我们可以将其进一步收窄:一部分harness由编码代理的开发者内置,比如系统提示词、代码检索机制甚至复杂的编排系统;而作为编码代理的使用者,我们还可以在外层为特定项目和系统构建自定义的harness。

前馈与反馈

要为编码代理构建有效的harness,需要结合两种核心机制:前馈引导(Guides)和反馈感知(Sensors)。前馈引导的作用是预判可能出现的不良输出,在代理执行操作前就对其进行引导,提升代理一次生成合格结果的概率;而反馈感知则是在代理完成操作后,对结果进行监测并帮助其自我纠正。比如优化后的自定义代码检查工具,不仅能报告错误,还能直接附带自动修复的指令,这本质上是一种正向的prompt注入。

单独使用其中任何一种机制都会存在缺陷:仅依赖反馈会让代理反复重复相同的错误,而仅依赖前馈则会让代理固化规则,但无法验证规则的实际效果。

计算型与推理型

前馈引导和反馈感知可以分为两种执行类型:

  • 计算型:由CPU运行,确定且快速,比如代码测试、语法检查器、类型检查工具和结构分析工具,这类工具通常在毫秒到秒级即可完成,结果可靠可控。
  • 推理型:依赖GPU或NPU运行,包括语义分析、AI代码审查、“LLM作为裁判”的校验,这类操作速度更慢、成本更高,结果也更具非确定性。

计算型的前馈引导可以通过确定性工具提升优质结果的出现概率,且计算型的感知器足够便宜高效,可以在每次代码变更时随代理一起运行。推理型控制虽然成本更高且非确定,但可以提供更丰富的引导和语义判断,在使用适配任务的强模型时,推理型感知器能有效提升我们的信任度。

以下是不同场景的示例:

示例 方向 计算型 / 推理型 实现示例
编码约定 feedforward 推理型 AGENTS.md、技能规范
新项目启动说明 feedforward 两者兼有 带说明和启动脚本的技能模块
代码批量修改 feedforward 计算型 支持OpenRewrite规则的工具
结构测试 feedback 计算型 pre-commit钩子或代理钩子,运行ArchUnit测试检查模块边界违规
代码审查说明 feedback 推理型 技能规范

时机:让质量左移

持续集成团队一直面临一个经典挑战:如何根据成本、速度和重要性,将测试、代码检查和人工审查分布在整个开发时间线上。当我们追求持续交付时,理想状态是每个提交的代码都可以直接部署,因此我们需要尽可能将质量检查左移,也就是在代码提交到集成流程之前就完成更多校验,因为发现问题的时间越早,修复成本越低。反馈感知器,包括新兴的推理型感知器,都需要按照这个原则分布在整个开发生命周期中。

我们可以将前馈和反馈控制分布在变更生命周期的不同阶段:

  • 哪些操作足够快速,可以在集成前甚至创建commit前运行?比如代码风格检查、快速测试套件、轻量的代码审查代理。
  • 哪些操作成本更高,因此只应该在集成之后的流水线中运行,作为快速检查的补充和验证?比如变异测试,或更全面的、能考虑更大图景的代码审查。

此外,还需要持续监测代码库中的持续漂移和系统健康状态:

  • 哪些类型的漂移会逐渐积累,应该由持续运行在代码库上的感知器监控,而非仅在变更生命周期内?比如死代码检测、测试覆盖质量分析、依赖漏洞扫描。
  • 代理可以监控哪些运行时反馈?比如观察服务的SLO是否恶化并提出改进建议,或者让AI裁判持续抽样检查响应质量,标记日志中的异常情况。

调节类别

编码代理的harness就像一个控制论意义上的调速器,结合前馈和反馈机制,将代码库调整到期望的状态。我们可以将这个期望状态拆分为多个维度,根据harness的调节目标进行分类,这种分类方式有助于我们理解不同类别的harness的可适配性和复杂度,也能让原本宽泛的“harness”一词更加精准。目前可以分为以下三类:

可维护性 harness

这类harness主要用于调节代码的内部质量和可维护性,也是目前最容易实现的一类harness,因为我们已经有大量成熟的工具可以使用。计算型感知器可以可靠地捕获结构性问题,比如重复代码、圈复杂度过高、缺少测试覆盖、架构漂移、代码风格违规等,这类检查成本低、成熟度高且结果确定。

而LLM可以部分处理需要语义判断的问题,比如语义重复代码、冗余测试、蛮力修复、过度设计的方案,但这类操作成本较高且具有概率性,不适合在每次提交时都运行。不过还有一些影响更大的问题,两类感知器都无法可靠捕获,比如误诊需求、过度设计和不必要功能、误解用户指令,这类问题有时能被检测到,但还不足以可靠到减少人工监督的程度——如果开发者一开始就没有清晰地说明需求,那么代码的正确性本就不在任何感知器的职责范围内。

架构适应性 harness

这类harness将用于定义和检查应用架构特征的引导和感知器整合在一起,本质上就是“适配函数”。比如,通过技能模块前馈输入性能要求,再通过性能测试反馈代理是否优化或损害了这些要求;或者通过技能模块定义可观测性的编码约定,比如统一的日志标准,再通过调试说明让代理反思当时可用的日志质量。

行为 harness

这是最核心也最具挑战的部分:我们如何确保应用的功能行为符合我们的需求?目前,赋予编码代理较高自主性的团队通常采用两种方式:

  • 前馈:通过功能规格说明,详细程度可以从简短的prompt到多文件的完整描述。
  • 反馈:通过检查AI生成的测试套件是否通过、测试覆盖率是否足够高,部分团队还会使用变异测试来监控测试质量,再结合手工测试。

不过这种方法过于依赖AI生成的测试的质量,目前还不够完善。有同事在使用approved fixtures模式时取得了不错的效果,但这种模式仅在部分领域适用,并非完整的测试质量解决方案。总体来说,我们仍需要大量工作来构建足够优秀的行为harness,让我们有足够的信心减少人工监督和手工测试的工作量。

Harnessability

不是所有的代码库都同样适合构建harness。使用强类型语言的代码库天然拥有类型检查作为感知器;清晰可定义的模块边界可以提供架构约束规则;像Spring这样的框架会抽象掉代理不需要关心的细节,从而隐式提升代理成功的概率。如果没有这些属性,对应的控制机制就很难构建。

环境适配属性

有同事使用“环境适配属性”这个术语,指代代理环境中让harness更容易构建的属性,即“环境本身的结构性属性,使其对于在其中运行的代理来说可读、可导航、可处理”。

“环境本身的结构性属性,使其对于在其中运行的 agents 来说可读、可导航、可处理。”

这种属性在绿地项目和遗留项目中的表现不同:绿地团队可以从项目第一天就将可适配性融入其中,技术决策和架构选择直接决定了未来代码库被治理的难易程度;而遗留项目团队,尤其是存在大量技术债务的应用,面临的挑战更大——越是需要harness的地方,反而越难构建。

Harness 模板

大多数企业的常见服务拓扑可以覆盖80%的业务需求,比如通过API暴露数据的业务服务、事件处理服务、数据看板等。在很多成熟的工程组织中,这些拓扑已经被编码为服务模板。未来,这些模板可能会演变为harness模板:即一组引导和感知器,将编码代理约束在特定拓扑的结构、约定和技术栈中。团队在选择技术栈和架构结构时,也可以部分参考已有的harness模板。

艾什比定律

艾什比必要多样性定律也是支持预定义拓扑的一个有趣论据,该定律指出,调节器必须至少拥有与它所治理的系统相同的多样性,且只能调节它拥有模型的部分。基于LLM的编码代理几乎可以生成任意代码,但限定使用特定的拓扑会收窄这个生成空间,让构建全面的harness变得更可行——定义拓扑本身就是一种减少多样性的操作。

当然,我们也会面临和服务模板类似的挑战:一旦团队实例化这些模板,它们就会逐渐与上游的改进脱节。harness模板也会面临同样的版本管理和贡献问题,甚至可能更严重,因为非确定性的引导和感知器更难测试。

人类的角色

作为人类开发者,我们会将自身的技能和经验作为一种隐式的harness带入每个代码库。我们会吸收团队的约定和最佳实践,能感知到复杂代码带来的认知负担,也清楚自己提交的代码需要负责。我们还拥有组织对齐的认知:知道团队的目标是什么,哪些技术债务出于业务原因可以容忍,以及在当前上下文中什么才是“优质”的代码。我们以人类的节奏逐步推进,为经验的触发和应用创造思考空间。

而编码代理则不具备这些特质:它没有社会责任感,不会对300行的函数产生审美上的不适,无法直觉地理解“我们这里不这么做”的团队习惯,也没有组织记忆。它无法分辨哪些约定是支撑系统的核心结构,哪些只是团队的习惯;也无法判断技术上正确的方案是否符合团队当前的目标。

harness的作用正是将人类的开发经验外化、显式化,但它的能力终归有限。构建一套连贯的引导、感知和自我纠正循环成本很高,因此我们必须带着明确的目标进行优先级排序:一个优秀的harness并不需要完全消除人工输入,而是要将人类的精力引导到最重要的环节。

一个起点,以及尚未回答的问题

本文提出的心智模型,描述了实践中已经出现的一些技术,也帮助我们框定了仍需要探索的问题。其目标是将讨论从单个功能组件提升到系统层面,探讨如何战略性地设计一套控制系统,让我们真正信任代理生成的代码。

当前讨论中的一些相关实践案例包括:

  • 某团队通过自定义代码检查工具和结构测试强制分层架构,以及周期性的“垃圾清理”流程,扫描架构漂移并让代理提出修复建议,他们的结论是“现在,我们最困难的挑战集中在设计环境、反馈循环和控制系统上”。
  • 某团队的文章描述了pre-push钩子等机制,这些钩子会基于启发式规则运行相关的代码检查工具,他们强调了将反馈左移的重要性,其蓝图也展示了如何将反馈感知器集成到代理工作流中。
  • 变异测试和结构测试都是计算型反馈感知器的例子,它们过去未被充分使用,如今正在复兴。
  • 开发者们越来越多地讨论将语言服务协议和代码智能集成到编码代理中,这都是计算型前馈引导的例子。
  • 有团队分享了他们同时使用计算型和推理型感知器处理架构漂移的经验,比如结合代理和自定义代码检查工具提升API质量,或者用“代码清理工具组”提升代码质量。

还有很多问题等待解决:随着harness的规模增长,我们如何保持其连贯性,让引导和感知器保持同步而非互相矛盾?当指令和反馈信号指向不同方向时,我们能在多大程度上信任代理做出合理的取舍?如果感知器从未触发,这是说明代码质量很高,还是检测机制存在缺陷?我们需要一套评估harness覆盖率和质量的方法,类似代码覆盖率和变异测试对测试的作用。目前,前馈和反馈控制分散在各个交付步骤中,我们有很大的空间构建工具,将它们作为一个系统来配置、同步和推理。构建外层的harness正在成为一项持续的工程实践,而非一次性的配置工作。


塔猴是一个专注于为用户提供系统学习、内容创作与商业连接的AIGC综合服务平台,致力于为每一位AI探索者打造理想的创作、成长家园。在塔猴,你不仅可以学习众多AIGC类实战课程,获得与时俱进的AIGC技能和视野,还有机会获得长期商业合作和接单机会!点击进入:https://www.tahou.com/

AI生成内容提示:本文由人工智能辅助创作,内容仅供参考,不代表平台观点。请注意核实信息的准确性,并理性判断。

以上内容不代表本平台立场,仅供读者参考