将生产环境各类信号(构建失败、webhook 超时、E2E flaky)统一收敛为 Ticket,经 Agent 自动分析并提交修复 PR,无需人工介入。
上周一次构建失败了,然后自己修复了。没有人盯着控制台,没有人会诊。失败自己提交了工单,一个 agent 推送了 PR。那篇帖子最受欢迎的一句话很简单:构建失败 → 缺陷出现 → agent 修复。
这个模式并不特定于构建过程。它就是那个队列本身。
在 Shipeasy,每一个重要的生产信号都会变成一个 agent 可以处理的工单——中间不经过任何人都会诊。
不是一行日志。不是一条刷过去的 Slack 消息。而是一个一等优先级的工作项,进入 ops 队列,分发到 GitHub issue 和 Slack,并有资格被自动修复。
问题——失败没有队列
构建破裂、Webhook 失败、校验 flaky。信号存在,但没有 agent 能捡起它的地方。得有人在控制台看到它、复制日志、写 bug、打标签,然后希望正确的人几小时后能看到。
成本不在于失败本身。而在于那个不存在的队列。
修复方案——所有可能失败的东西共用一个队列
所有外部事件都以同一种形式到达:一张工单。相同字段、相同路由、相同 agent 生命周期。
Cloud Build 失败。一次 flaky 的 E2E 运行。来自小组件的客户报告。一次没有按时运行的定时任务。所有这些都通过 admin API 以 type: "bug" 的形式落地——标题、重现步骤、实际结果 vs 期望结果、优先级、标签——然后平台每次都做同样的事情:打开一个 GitHub issue、ping 正确的 Slack 频道、标记为可以由 AI agent 调查并打开 PR。
主分支构建破裂 → 工单 → agent PR 只是这个模式的一个实例。模式本身才是重点。
设计——故意做得无聊
Source → 已经在一辆总线上(Pub/Sub、Webhook、调度)——无需新基础设施
推送或 POST 到 /webhooks/<source>——验证 token、解码、按 delivery ID 去重
Client → POST /api/admin/ops,type: "bug"——title、stepsToReprodue、actualResult、expectedResult、priority、tags
Shipeasy ops 队列 → 分发到 GitHub issue + Slack → agent 调查 → PR
让这一切成本低廉的原因是:我们没有构建那些本不需要的东西。我们使用的是云已经提供的投递机制和已经运行的服务。粘合代码只有四十行。
实现——一个薄的客户端
每次都用相同的形状:
ShipeasyOps::Client.new.file_bug(
title: "Cloud Build FAILURE on #{branch} — #{sha}",
steps_to_reproduce: "Trigger \"#{trigger}\" reported FAILURE.",
actual_result: "Logs: #{log_url}\n\n#{failure_detail}",
expected_result: "Build completes and deploys.",
priority: "high",
tags: %w[cloud-build ci]
)
这个方法是一次 HTTP 调用的类型化包装:
def file_bug(title:, steps_to_reproduce:, actual_result:, expected_result:, priority:, tags:)
post("/api/admin/ops", {
type: "bug",
title: title,
stepsToReproduce: steps_to_reproduce,
actualResult: actual_result,
expectedResult: expected_result,
priority: priority,
tags: tags,
})
end
def post(path, body)
req = Net::HTTP::Post.new(URI("#{BASE_URL}#{path}"))
req["Authorization"] = "Bearer #{@admin_key}"
req["X-Project-Id"] = @project_id
req["Content-Type"] = "application/json"
req.body = body.compact.to_json
res = Net::HTTP.start(req.uri.host, req.uri.port, use_ssl: true) { |h| h.request(req) }
JSON.parse(res.body)
end
在边缘去重(在 delivery ID 上做 write-if-not-exists),这样至少一次投递不会产生重复工单。
可能走过的弯路
通过标准 flag 评估记录错误:适合异常,但不是带优先级和重现场景的跟踪工作项。
公开工单路径用于应用内反馈:零认证,为"报告问题"小组件设计——对内部信号来说太重了。
通过 admin API 提交正式 bug(选定方案):真正的工作项、带优先级、带标签、可路由、agent 就绪。
收益——从红变绿,无需任何人值班
一次典型失败现在的行程是:从总线到 PR,不惊醒任何人。团队看到一个已经存在的 PR,合并它即可。合并的人不需要知道失败模式。
我们在构建新管道之前使用的规则:如果事件已经在你能订阅的总线上,而且你已经在运行的东西能捕获它,那就提交工单,让 ops 队列做剩下的事情。
Built on Shipeasy——将工作委托给 agent 的 ops 队列。支撑基础设施:flag、kill switch、动态配置。核心循环在队列中,不在 flag 中。免费套餐,无需信用卡;Team 版本 $49/席位/月,无限制。
→ shipeasy.ai · → docs.shipeasy.ai · → github.com/shipeasy-ai/shipeasy