Swan 如何将 Cygnet 从一个需要手动 @ 的 Slack 智能体,演进为具备自动缺陷检测、分诊和修复能力并在关键节点引入人工审核的全自主流水线。
AI translation, not an official translation. Refer to the original for technical details.
Adapted from @skwp# Swan 的自主软件工厂:Cygnet 进化版 将本文收藏,并把这些思路喂给你的智能体,用来搭建你自己的技术栈。 两年前,Swan 没有任何自主提交。如今,我们绝大多数代码都由自主或人工驱动的智能体生成,并由自主安全与质量保障流水线提供支撑。 今年三月,我曾撰文介绍 Cygnet——我们内部的自主协作伙伴:Slack 线程搭档、Linear 项目经理,以及无人值守的代码流水线。最初版本是一个需要在 Slack 中 @ 才会响应的智能体。此后,我们将其升级为能够自行发现缺陷、分析根因,并在任何人提出要求之前就构建好供人工审阅的修复方案。我们还添加了例程、报告器和流水线,帮助我们更快、更准确地交付产品。(https://x.com/skwp/status/2034332391301361742?s=20) 下面来看看 Cygnet 今天的实际运作: 7 月 9 日,一个合作伙伴的 webhook 开始向我们的数据库发送海量事件,导致任务失败、重试、再次失败。一个 Cygnet 任务自动查询了 Datadog,发现了这次流量峰值,并创建了一张工单,其中包含它所执行的查询、版本号、时间窗口以及对原因的推测。 第二个任务拿起这张工单,派出三名"调查员"。每一名都重新执行了查询、统计了符合该特征的事件数量,并提出了各自的假设。其中两名得出了相同的结论,第三名持有异议,三份分析报告连同这份异议一并附上了工单。随后,另一组智能体设计了修复方案。一名工程师阅读了生成的规格说明,并通过添加标签的方式批准了该方案。 当天下午,流水线创建了一个 PR 并尝试验证修复是否有效。验证运行失败,于是智能体将该 PR 移交给一名人类工程师。该工程师在本地容器中复现了缺陷,确认修复方案有效,推送了测试,获得第二次审批,并合并了变更。部署后的例程通过自动审查日志并汇报结果,验证了修复已生效。 三月时,每次运行都需要有人在工单上 @ Cygnet 才能启动。团队中任何人现在仍然可以这样做,但 Cygnet 现在所做的大多数工作都是自行发起的。一个发现任务会为生产环境错误创建工单;多个"投喂"任务将这些工单依次推进分诊、规格说明、实现和审阅等阶段;在需要人工监督的阶段,系统会 @ 相应的人员介入。 Cygnet 现在还运行一套自动化工作流,涵盖:每周领域瞭望塔、每日发布检查、不变量检查、安全新闻预警(判断 Swan 是否处于爆炸半径之内),以及我们称为"梦境"的夜间知识循环。较小的任务负责处理杂务,例如刷新产品 Wiki、更新知识库以供缺陷流水线持续自我改进。 ## 缺陷修复流水线 我们原有的代码流水线通过单个任务将工单一路推进到 PR。缺陷修复流水线的设计则引入了更多人工介入,原因在于缺陷分诊过程本身是自动化的,因此我们使用工单标签作为状态机的追踪器。每个阶段认领一张工单,完成其负责的工作,然后通过写入下一阶段所等待的标签来退出。 发现阶段由 GitHub Actions 驱动的定时任务运行。分诊、规格说明、实现和审阅阶段在工单就绪后被分派执行。如果某个环节卡住,一个恢复任务会重试几次,若仍未成功则将工单停放到人工可见的位置。被取消或超时的任务会将其工单放回队列。过期标签会从已关闭的工单上清除,错误诊断也会被清理,以免干扰下一阶段的判断。 错误工单会附带相关证据,通常包括一个监控器、一个错误特征码以及一个时间窗口。三名调查员并行运行,每人将该证据重新与实时数据比对,独立得出根本原因,并返回一份结构化裁决,内容涵盖证据是否成立、其认为的原因,以及置信度评分。 一个脚本读取这些裁决并决定工单的流向。如果两名或两名以上调查员认为证据无效,工单将被取消。如果根本原因以高置信度达成一致,调查结果将被合并,工单推进至下一阶段。介于两者之间的情况则连同相互竞争的候选方案一并提交给人工处理,以便接手者无需重复调查。 规格生产阶段的运作方式相同,由三名修复方案设计员参与。每人对照代码验证根本原因,提出修复方案,并回答变更是否真正可发布:哪些标志位控制该路径、每个文件是否属于发布构建,以及受影响的版本。缺少该部分内容的提案将在此阶段被拒绝。如果提案存在分歧,或无法确定可达性,工单将提交给人工处理,即便最初的修复看起来很简单。通过共识机制来确定修复方案,有助于防止我们用简单的修复掩盖更深层的问题——这是 AI 维护系统时常见的弊病。 一旦流水线开始自动开启 PR,你就需要一个数字来衡量它的准确率。每个 PR 都会收到人工审查者给出的单一裁决:修复正确、根本原因有误,或并非真实存在的缺陷。精确率的计算方式为正确修复数除以总数,这是我们在构建流水线时重点关注的指标,以避免产生过多 AI 噪音,同时也能提升人工审查者的置信度。 修复被接受后,诊断结果将根据标签进行统计。但这并不总能告诉我们诊断是否高效得出,或者最终合并的内容是否与建议存在细微差异。为弥补这一不足,另一个作业负责调查实际合并的内容,将记录在案的诊断与合并后的差异及审查意见进行比对。这有助于我们了解最终代码相较于原始诊断是否经过了调整。若发现差距,我们会在产品知识库中添加一条经验教训,以避免日后犯下类似错误。这些知识随后会被加载到未来的共识循环中。 ## Automated Proof of Work and PR Response 在将变更发布到生产环境之前,我们会提供一份工作证明,通常以单元测试输出、截图、视频或其他可证明功能正常运行的构件形式呈现。我们过去一直手动完成这项工作,但近来越来越多地尝试将其自动化。 工作证明阶段会启动一个离线环境,通过真实浏览器驱动变更流程,截取截图,并将其发布到工单上。任何人都可以从任意 PR 指向同一工作流。后端变更通常进行快速冒烟测试,而 UI 变更则进行较慢的基于浏览器的测试。并非所有工作证明都具有同等效力,有时智能体可能难以生成它。7 月 9 日就出现了这种情况,我们自动将该工单标记为需要人工跟进。 我们的 PR 会经过多个审查系统,其中包括一条多阶段确定性 QA 流水线,涵盖从安全到语义共约九个不同类别。错误修复审查阶段会响应这些评论:它修复失败的 CI,并落实每一条可操作的评论;只有当某条评论有误或超出范围时才会拒绝,并回复说明原因。它会关闭已处理的讨论线程,审查完整的差异,然后发布一个最终结论:是否已准备好由人工合并,并附上理由。 ## Slack 反应与 Cygnet Dreaming 运行 Cygnet 几个月后,我们提出了一些改进。现在,一个没有关联 Linear 工单的自由格式请求会自动创建一个工单,启动一个探索代码库并编写规范的智能体,并允许该智能体在线程中反向提问。 我们新增了反应功能。绿色勾选会告知 Cygnet 直接从 Slack 构建它在工单中提出的计划。踩的反应会让机器人开一张描述出错内容的工单。垃圾桶反应会撤回机器人的消息,以防它生成了敏感内容。 "记住这个"会写入一条记忆页,该操作需要经过审批——须有人工回复方可通过,并且会硬性拦截任何看起来像密钥的内容。我们希望对记忆写入进行人工审批,是因为记忆投毒可能导致安全问题,一旦写入错误记忆,后果可能更为严重。实时记忆索引存在于聊天提示中,因此某人上周教给它的内容,本周对所有人都处于上下文中。 会话以 Slack 线程为键,这样 Cygnet 在与多个线程中的多人交谈时就不会丢失上下文。每个会话结束时都会对该线程进行简短的回顾,这些回顾后续会在 Dreaming 周期中用于知识构建。 Dreaming 是对当天大量运行所包含的原始经验进行消化的过程,这些经验包括:回顾记录、已纠正的线程、已取消的工单、已加载后又被推翻的技能。它在夜间使用更大的模型运行,并预先拉取大量 Slack 记录、工单、技能遥测数据以及自身的观察日志。它收集信号、校验矛盾、归类候选项、编写 wiki,并记录其"梦境"以供我们检视该周期。 大多数观察都是噪声,存储在一个只追加的日志中。一条观察若固化为规则,就会成为一条记忆页,每个周期都会追加支持或反驳该规则的证据。当一个区块积累了来自足够多来源的足够证据后,它就会被提升为技能——通过一个工单和一个由人工审查的 PR。技能对大量智能体和人类产生影响的潜力最大,因此我们谨慎对待技能更新,以避免投毒。 每次技能加载都会被记录,并与其所在的线程相关联。如果加载了技能且会话成功,我们就保持不动。如果加载了技能但人工纠正了结果,说明内容有误。如果没有任何技能加载而人工不得不介入,说明触发条件过窄。如果加载了错误的技能,说明触发条件过宽。一次人工纠正就足以创建一个区块,因为当有人说"不,不是这样"时,我们无需等待同样的情况再次发生。每个技能都存在于一个归属地——即其所服务领域的代码仓库。每小时同步一次,将其发布到一个插件中,智能体和人工智能体会话均可按需加载。 当 Dreaming 不确定时,它会在 Slack 摘要中提出问题。一旦人工回复,下一个周期就会读取整个线程。被取消的 Dreaming 工单视为负面证据,因为有人审视过这个想法并予以否决。 ## 报告器与例行任务 自从我们将 Cygnet 作为按需协作伙伴推出以来,我们对其进行的重大升级之一,便是引入了例行任务(routines)与报告器(reporters)的概念。我们使用 GitHub Actions 来触发这些任务,并构建了一个框架,使添加新作业就像编写一个 YML 文件一样简单——而这正是 AI 智能体非常擅长的事情。以下是我们经常使用的几个示例: 瞭望塔(Watchtowers)每周一早晨采集特定领域的数据,一小时后由一个编排器将这些数据行汇总成一份高管摘要。例如,它们可能会查看新用户流水线或交易活动,以确保一切运行顺畅。它们帮助我们借助来自 Datadog 及其他工具的实时数据,发现各业务领域中的异常与趋势,撰写报告,并在 Slack 频道中以色码摘要的形式呈现,供各团队跟进调查。 发布监控(Shipwatch)负责验证近期上线的工单在生产环境中是否真正正常运行,并能对该变更原本打算验证的假设进行测试。 安全新闻告警(Security News Alerts)是事件驱动的,基于安全资讯订阅源运作。它对安全新闻进行分级处理,评估相关内容是否可能影响 Swan 的技术栈,并在认为需要进一步关注时,将该新闻条目标记以供人工审查。 我们还在尝试一种智能体化的安全响应机制:智能体可从数十个安全系统中采集安全信号,调查其中的模式,并结合已有知识对报告进行深度补充。这为人工节省了大量搜集上下文以调查安全告警的时间。 ## 智能体化是一段旅程 我们从 2025 年 4 月开始推进业务的智能体化,并发现:工具链越可靠,人们就越愿意使用它来创造业务价值。 我们还发现,提升基础体验——例如立即接入一个 Slack 智能体——赋予了更多人自主解决问题的能力。举例来说,我们观察到客户服务团队的人员开始直接向 Cygnet 提问,而不再像过去那样 @ 运营人员。他们能更快获得答案,且附带更多背景信息,从而能更及时地为客户提供正确的解决方案。 那些过去扮演"中间人"角色的人员(例如运营人员)如今越来越多地开始自主构建工具,以实现工作自动化。为帮助人们向工程方向转型,我们设立了一个名为 Wingspan 的项目,将有经验的工程师与新晋的智能体代码编写者配对。使用大语言模型构建原型看似轻而易举,但要让其达到通过 Swan 安全编码标准审核、并在其安全编码环境中稳定运行的水平,则是另一回事。过去两年间,我们从零个使用 AI 标记提交的贡献者,发展到整个工程团队都在借助智能体交付代码,另有十名来自公司各部门、此前毫无工程经验的人员也加入其中。 拥有一个有指导性的配对项目,对于那些考虑赋能几乎没有或完全没有工程经验的人员通过LLM来交付代码的组织而言,至关重要。这个项目帮助我们对那些为自身构建内部工具的人员进行教育并提供相应资源,同时也为高级工程师和有经验的工程师腾出更多时间,让他们真正去构建管道、护栏和工具,从而使更多人能够交付成果。 我们知道市面上有越来越多的开箱即用企业级智能体系统,但每家企业都各有不同,构建一套契合自身公司形态的系统具有很大的价值。这也使我们得以保持独立,不过度依赖前沿实验室或第三方供应商,避免将过多基础设施直接建立在某家可能提价或发生故障的公司之上。我们建议借鉴本文中的一些思路,来搭建属于自己的智能体系统并加以探索实践。 构建的成本如今已经很低,但安全仍然困难且昂贵,因此我们将不成比例的大量时间投入到确保系统安全上。如果您刚刚开始这方面的工作,请参阅我们此前的一些文章: 供应链安全:针对 Shai-Hulud 级攻击的加固措施(https://x.com/skwp/article/2060154464913273079) 使用确定性编排的 PR 审查流水线(https://x.com/skwp/status/2085475419386519875)