摘要
AI 辅助开发正在把功能实现压缩到分钟级,但生产系统并不只在理想条件下运行。数据库会中断,网络会超时,请求会重复,发布会停在中间状态,操作人员也会犯错。许多 AI 生成的系统因此呈现出同一种反差:功能上完整,运行上天真。
可靠性不是上线之后再补的一层基础设施,而是一组从需求阶段就必须写清楚的行为:失败如何被发现,影响如何被限制,服务如何降级,数据如何保持可恢复,人如何安全地介入。AI 有能力实现这些机制,但只有人先把失败定义为设计输入,它才更可能交付一个真正适合生产的系统。
功能需求说明系统在顺利时应该做什么;可靠性需求说明系统在不顺利时仍然必须守住什么。
第一部分 · 把失败放回设计之中
01功能完整,运行天真
过去两年,AI 辅助开发深刻改变了软件构建的速度。过去需要数小时才能完成的接口、数据模型、前端组件和自动化测试,现在往往几分钟就能得到一份相当像样的实现。真正值得警惕的并不是这些代码不能工作,而是它们通常只证明了一件事:在我们预先安排好的正常路径上,它们能够工作。
生产环境不会长期停留在正常路径。数据库会短暂不可用,第三方接口会在最忙的时候变慢,同一个订单会因为客户端重试被提交两次,发布可能只完成一半,一次看似无害的配置变更也可能绕过所有代码测试。
于是,评审一个订单创建 API 时,真正有区分度的问题不再只是“请求能否写入数据库”,而是:
- 客户端没有收到响应并再次提交时,会不会创建两个订单?
- 库存扣减成功、支付调用超时后,系统处于什么状态?
- 下游持续变慢时,线程、连接池和队列会不会被耗尽?
- 新版本只在部分实例上启动成功时,旧新数据结构能否共存?
- 值班人员如何知道故障发生在哪里,又如何安全恢复?
这些不是“高级优化”,而是功能在真实世界里的另一半。一个系统若只定义成功路径,实际上还没有定义完整。
02可靠性不是几个 9
可用率是可靠性最常见的表达,却不是它的全部。99.9% 告诉我们某个时间窗口内允许多少失败,却没有单独回答:失败是否集中伤害了关键客户,数据有没有损坏,故障能否被快速发现,恢复是否依赖某位熟悉内幕的工程师。
更实用的观察方式,是同时看四个相互关联的问题:
| 观察面 | 它追问什么 | 常见证据 |
|---|---|---|
| 可用性 | 用户能否在承诺的时间与质量下访问服务 | SLI、SLO、错误预算 |
| 韧性 | 局部故障发生时,系统能否继续或降级运行 | 故障隔离、限流、冗余、降级测试 |
| 可恢复性 | 超出韧性边界后,能否回到已知正确状态 | MTTR、RTO、RPO、恢复演练 |
| 可维护性 | 团队能否理解、修改并安全操作系统 | 变更失败率、回滚能力、Runbook |
在一个简化的可修复系统模型中,可用性常被写成:
Availability ≈ MTBF ÷(MTBF + MTTR) MTBF 关注故障间隔,MTTR 关注恢复速度。这个近似式最有价值的地方,不是计算一个漂亮数字,而是提醒我们:减少故障和加快恢复同样重要。
Google 的 SRE 实践还强调,可靠性不是无限追求 100%。不同业务流的失败代价不同,工程投入应当服从风险与用户体验,而不是服从“9”越多越好的抽象竞赛。对于部分可用的分布式系统,以成功请求比例观察可用性,也往往比只计算整站停机时间更接近用户实际感受。[1]
03失败不是异常,而是输入条件
墨菲定律之所以在工程里经久不衰,不是因为悲观,而是因为它迫使我们诚实面对规模:一件事即使单次发生概率很低,只要组件足够多、运行时间足够长,它终究会进入日常运营。
磁盘会损坏,进程会崩溃,证书会过期,网络会抖动,云服务会中断,外部接口会改变行为。人的操作也一样不可能永远正确。可靠性设计并不试图把这些事实从世界里删除,而是提前决定它们发生之后的系统行为。
成熟的系统不是没有失败,而是失败发生时,结果仍然在设计之内。
这个视角会把问题从“如何阻止一切失败”改写为:什么必须继续工作,什么可以暂停,错误能扩散多远,哪些状态可以重建,谁拥有恢复决定。Azure Well-Architected Framework 也把业务要求、韧性、恢复、运行和简单性放在同一组可靠性原则里;它特别要求区分关键路径与可降级组件,并分析故障范围,而不是给所有组件堆上同样的保护。[2]
第二部分 · 把可靠性花在真正重要的地方
04先找到不能丢失的业务承诺
并不是所有组件都值得同样级别的保护。商品推荐暂时不可用,用户仍然可以下单;订单创建重复执行一次,却可能带来扣款、库存和客服成本。报表晚到十分钟通常可以接受,交易清算丢失一条记录则可能产生合规与资金风险。
可靠性的二八法则,不是机械地寻找 20% 的代码,而是识别少数不能被破坏的业务承诺:
只有先回答这些问题,冗余、审计、对账、补偿事务、跨区部署和增强监控才有成本依据。Google SRE 用不同数据的重要性说明同一个原则:关键隐私数据和可选体验数据不应被给予相同的存储保证。[1]

图 1 · 保护承诺,而不是平均保护组件。 砖红色路径代表必须守住的业务结果;缓冲、隔离与冗余围绕它部署,外围能力则允许在故障时有控制地降级。
05简单、依赖与故障边界
AI 生成架构时很容易把“使用了更多模式”误认为“考虑得更完整”。事件驱动、CQRS、分布式工作流、多级缓存和 Service Mesh 都可能合理,但每新增一个活动部件,也会新增状态、契约、监控和恢复负担。
简单并不等于把所有东西塞进一个进程。它意味着:只为已经存在的约束引入复杂度,保持关键路径短,让故障模式能够被团队列举和演练。Azure 的可靠性指南同样把“保持简单”列为设计原则,同时提醒过度简化也可能制造单点故障。[2]
依赖则需要被当作故障边界,而不只是集成接口。每接入一个数据库、队列、身份服务、支付网关或 AI API,都应该回答:
- 调用多久之后必须放弃等待?
- 失败时是降级、排队、读取缓存,还是直接拒绝?
- 重试由哪一层负责,最多几次,是否带退避和抖动?
- 重复执行有没有副作用,幂等键保存多久?
- 延迟升高时,连接池、线程池和上游流量如何被隔离?
- 依赖长期不可用时,有没有替代路径或可恢复的积压?
重试不是免费的可靠性。 无上限、无退避、在多层同时发生的重试,会把短暂故障放大成持续过载。Amazon 的工程实践把超时、有上限的重试、指数退避和随机抖动放在一起讨论;对于会产生副作用的调用,还必须先定义幂等语义。[3][4]
Stripe 的 API 是一个具体例子:客户端为创建或更新操作提供幂等键,连接中断后便可以安全重试,而服务端用同一个键返回第一次执行的结果。[5] 关键不在于照搬某个字段,而在于把“不确定是否成功”从一次临时异常,变成协议明确处理的状态。
冗余也需要同样具体。两个共享同一电源、同一网络路径或同一错误配置的实例,并不构成真正独立的保护。有效冗余要说明它抵御哪一种故障、如何检测主路径失效、如何切换、数据怎样保持一致,以及故障解除后怎样回切。
06可靠性也关乎人
严重事故并不只来自代码缺陷。错误配置、误删数据、权限范围过大、发布步骤遗漏和恢复命令使用不当,都可能把一个局部问题变成业务故障。把原因归结为“操作人员不够小心”,通常只是在回避系统为什么允许一次普通失误造成巨大影响。
好的运行界面和发布系统会主动缩小犯错空间:
- 用清晰命名、类型约束和配置校验提前拒绝无效状态;
- 采用安全默认值,让高风险操作需要显式升级权限;
- 在删除或迁移前展示真实影响范围,而不是只弹出泛化确认框;
- 让变更分阶段进入生产,并设置可观测的停止条件;
- 让回滚、恢复和审计成为日常路径,而不是事故时临时拼装。
这里的目标不是让人远离系统,而是让人的判断被用在真正需要判断的地方。自动化应当消除易错的重复步骤,同时保留清晰的控制权、证据和撤销路径。
第三部分 · 从架构进入运行现场
07可靠性是一条闭环,而不是一张图
架构图可以说明冗余和依赖,却不能证明团队真的能发现并恢复故障。一个成熟的可靠性生命周期,至少要形成下面这条闭环:
- 预防
- 识别关键路径、失败模式和高风险变更。
- 检测
- 用面向用户结果的信号发现异常,而不是等待客户投诉。
- 分析
- 判断影响范围、当前状态与最可能的触发因素。
- 隔离
- 限流、熔断、降级或停止发布,阻止故障继续扩散。
- 恢复
- 回滚、切换、重放、补偿或从备份恢复到已知状态。
- 修复
- 消除触发因素和允许它扩大影响的系统条件。
- 学习
- 通过复盘、演练和可验证行动项更新系统与流程。
这条链上任何一环缺失,可靠性都可能停留在纸面。没有检测,恢复能力不会及时启动;没有隔离,局部故障会在调查期间继续扩散;没有演练,Runbook 很可能只描述了一个从未被验证的愿望;没有行动项的复盘,则只是保存了一次事故故事。
Google 的事故响应实践强调提前建立指挥角色、记录调试与缓解过程,并定期演练;其复盘指南则要求用事实解释影响、恢复和根因,把行动项落实到明确负责人和可验证的结束状态。[6][7]

图 2 · 可靠性闭环。 故障检测只是起点。真正降低损失的是从信号到隔离、从恢复到学习的完整路径;AI 可以参与每个环节,但控制目标和验收证据必须先由团队定义。
08可观测性与恢复能力也是产品功能
许多团队在实现功能时投入充足,却把日志、指标、告警、恢复脚本和演练推迟到“上线之后”。结果往往是:系统已经失败,团队却只能从零散日志猜测用户是否受到影响;备份一直在生成,却从未证明能够在目标时间内恢复。
可靠性要求应该像接口行为一样可测试。对每条关键业务流,至少需要写清:
关键路径的可靠性验收
- 成功、失败和性能下降分别由什么用户结果来定义?
- 哪些指标能在用户投诉之前发现偏离?
- 告警到达谁手里,收到后第一步做什么?
- 单个实例、区域、依赖或错误配置的最大影响范围是多少?
- 系统在降级状态下仍然保证什么,又明确放弃什么?
- 恢复依赖哪些数据、权限、工具和人工决定?
- RTO 与 RPO 是否被真实演练验证,而不是只写在文档里?
- 新版本能否安全停止、回滚,并与旧版本短暂共存?
能够回答这些问题,才意味着团队拥有一个可运行的服务,而不只是一个可部署的程序。
第四部分 · 教 AI 思考失败
09从功能提示词升级为生产任务契约
当前的编程助手通常会寻找从需求到可运行实现的最短路径。如果输入只是“实现一个订单处理服务”,Controller、Service、数据库访问、参数校验和单元测试自然会成为主要输出。超时、幂等、故障隔离和恢复流程没有出现,往往不是模型完全不知道这些概念,而是任务从未把它们列为完成条件。
比一串“请考虑可靠性”的提醒更有效的做法,是把失败行为写进任务契约:
实现一个订单处理服务。功能正确只是验收的一部分。 |
这个提示词的关键不是列出了多少术语,而是要求模型把每一种机制连接到故障场景、业务影响和验证证据。否则,“加入熔断器”很容易成为装饰性的架构建议,“增加监控”也可能只产生一堆没人行动的指标。
让 AI 交付证据,而不只是交付代码。 要求它展示重复请求、下游超时、部分发布、依赖过载和恢复演练的测试结果;对于无法证明的保证,明确标记未知,而不是用架构名词填补空白。
10AI 不能替代故障的所有权
AI 可以帮助枚举失败模式、生成故障注入测试、检查配置、起草 Runbook,甚至在约束明确时执行部分恢复动作。它最适合扩展团队寻找反例和重复验证的能力。
但模型不知道一次结算延迟对这家公司的真实代价,也不能独自决定隐私、资金和客户信任之间的取舍。它看到的是需求、代码和可用上下文;工程师面对的则是承诺、组织能力和后果。
因此,人的职责不再只是逐行实现功能,而是建立可靠性的控制面:定义什么不能丢,决定风险预算,限制自动化权限,审查故障边界,要求验证证据,并确保有人能够在凌晨三点恢复系统。
11生而可靠
软件行业花了几十年优化“如何写代码”,AI 又把这个过程推到了新的速度。但生产系统的基本规律没有改变:服务器仍然会失败,网络仍然会失败,人仍然会犯错,依赖仍然会在不合适的时候改变行为。
构建功能的能力正在迅速自动化。预判失败、决定损失边界并为恢复负责,反而因此变得更有价值。
“生而可靠”并不意味着第一次发布就拥有无限冗余,也不意味着系统永远不出故障。它意味着,从第一个需求开始,成功路径和失败路径就拥有同等真实的地位;从第一次上线开始,检测、隔离、恢复和学习就被当作产品的一部分。
可靠性始于我们停止只问“系统能不能工作”,转而追问:“当它不能工作时,哪些承诺仍然必须成立?”
参考资料与延伸阅读
本文以公开的工程实践校准可靠性、重试、幂等和事故响应等概念;具体架构仍需根据业务影响、成本和团队能力做取舍。
- Alvidrez, Marc. “Embracing Risk.” Site Reliability Engineering, Google, 2016.
- Microsoft. “Reliability Design Principles.” Azure Well-Architected Framework.
- Brooker, Marc. “Timeouts, Retries, and Backoff with Jitter.” Amazon Builders’ Library.
- Featonby, Malcolm. “Making Retries Safe with Idempotent APIs.” Amazon Builders’ Library.
- Stripe. “Idempotent Requests.” Stripe API Reference.
- Jones, Stephen, et al. “Incident Response.” The Site Reliability Workbook, Google, 2018.
- Rogers, Daniel, et al. “Postmortem Culture: Learning from Failure.” The Site Reliability Workbook, Google, 2018.