AI写的代码上了生产,炸了算谁的?

AI写的代码上了生产,炸了算谁的?

上周三晚上11点,我手机震了。运维群弹了条消息:"支付回调接口502,影响范围:全量用户。"

我打开Grafana,错误率从0.3%飙到47%。翻了下最近的提交记录——3小时前,一个AI Agent自动提的PR,review没拦住,合进了main分支。

改动很小:把一个Redis连接池的max_connections从200改成了20。提交信息写的是"优化连接池配置,减少资源占用"。

200改成20。

这个锅,到底谁背?

先说结论:人背。永远是人背。

不管你用的是Claude、GPT还是自研模型,不管代码是AI生成的还是AI辅助写的,出了事故,背锅的永远是最后一个点"merge"的人。

这不是道德判断,是法律现实。目前全球没有任何一个司法体系承认AI的法律主体地位。代码是你仓库里的,commit是你账号合的,线上是你管的——出了事,就是你的。

但"谁背锅"这个问题太浅了。真正该问的是:怎么让AI写的代码少炸,炸了怎么快速定位。

我们公司的真实数据

我们是做AI Agent研发的,公司日常开发大概60%的代码是AI生成或AI辅助写的。过去半年,线上出了14次P2及以上事故,其中8次跟AI生成的代码直接相关。

这8次事故,我复盘出了3个高频踩坑模式:

坑1:AI不懂你的隐含约束

那次Redis连接池的事故,根因是AI不知道我们的Redis集群配了maxclients 1000,而我们有8个服务实例。200×8=1600,本来就踩着线了,但至少能跑。改成20×8=160,连接数直接不够用,请求排队,超时,502。

AI看的是这一行代码,看不到整个部署拓扑。

解法: 在项目根目录放一个ARCHITECTURE.md,把部署约束、资源限制、关键配置的上下文写清楚。我们强制要求每个项目都有这个文件,AI工具的system prompt里会注入这个文件的内容。

# ARCHITECTURE.md
## Redis集群
- 3主3从,maxclients=1000
- 8个服务实例共享,单实例连接池上限不要超过100
- 生产环境禁止修改连接池配置,必须走运维审批

别小看这几行字。加了这个文件之后,AI改连接池配置的PR从月均3个降到了0。

坑2:AI写的异常处理是"正确的废话"

AI特别喜欢写这种代码:

try:
    result = process_payment(order)
except Exception as e:
    logger.error(f"支付处理失败: {e}")
    raise

看着没问题对吧?日志打了,异常也抛了。但上线之后出问题你搜日志,支付处理失败后面跟的是一坨看不懂的序列化对象,根本定位不了是哪个订单、什么金额、什么支付渠道。

我见过最离谱的一次,AI写的日志把整个request body打了进去,里面有用户的身份证号和银行卡号。生产环境。日志收集系统对接的是ELK。合规同事差点把我桌子掀了。

解法: 写了一个日志规范skill,强制约束AI生成的日志代码:

# 正确的异常处理
try:
    result = process_payment(order_id=order.id, amount=order.amount)
except PaymentChannelError as e:
    logger.error(
        "支付渠道异常",
        extra={
            "order_id": order.id,        # 业务标识
            "channel": order.pay_channel, # 哪个渠道
            "amount": str(order.amount),  # 金额(转字符串防序列化)
            "error_code": e.code,         # 渠道返回码
            "trace_id": get_trace_id(),   # 链路追踪
        },
        exc_info=True,  # 带堆栈,但不打敏感字段
    )
    raise
except Exception:
    logger.critical(
        "支付处理未知异常",
        extra={"order_id": order.id, "trace_id": get_trace_id()},
        exc_info=True,
    )
    raise

关键区别:结构化日志 + 业务标识 + 脱敏 + trace_id。有了这四样东西,出了事5分钟能定位到具体订单。

坑3:AI不会拒绝"看起来对"的需求

这是最隐蔽的坑。产品经理提了个需求:"把用户列表查询的默认排序改成按注册时间倒序。" AI二话不说改了,PR描述写得清清楚楚,代码也没毛病。

上线后,客服电话被打爆——用户说"我的数据不见了"。

实际发生了什么:那个列表页有分页,默认每页20条。改了排序之后,用户习惯翻到第3页找自己的数据,但排序一变,第3页的内容全换了。数据没丢,但用户以为丢了。

更深层的问题:这个接口被3个下游服务依赖,排序逻辑变了,下游的缓存预热全部失效,触发了一波缓存穿透。

AI根本不会问:"这个改动会影响哪些下游?" 它只看你给它的上下文。

解法: 在每个PR的review流程里加了一个环节——AI review AI。我们用另一个Agent专门做impact analysis:

def check_impact(pr_diff: str, codebase_index: dict) -> list[str]:
    """分析PR的影响范围"""
    risks = []
    
    # 1. 检查是否有下游依赖
    changed_apis = extract_api_changes(pr_diff)
    for api in changed_apis:
        consumers = codebase_index.get_consumers(api)
        if consumers:
            risks.append(f"⚠️ {api} 被 {len(consumers)} 个服务依赖: {consumers}")
    
    # 2. 检查排序/分页逻辑变更
    if "order_by" in pr_diff or "sort" in pr_diff:
        risks.append("⚠️ 涉及排序逻辑变更,需确认分页兼容性")
    
    # 3. 检查缓存相关
    if any(kw in pr_diff for kw in ["cache", "redis", "ttl"]):
        risks.append("⚠️ 涉及缓存逻辑,需确认缓存穿透/击穿风险")
    
    return risks

这个Agent不审代码质量,只审影响范围。跑一次大概30秒,但能拦住80%的"看起来没问题但其实影响很大"的PR。

一个反直觉的发现

统计完那8次事故之后,我发现一个有意思的事:AI生成的代码,bug率其实比人写的低。

我们测过,同样功能的代码,AI生成的单元测试覆盖率平均87%,人写的平均62%。AI不会忘记边界检查,不会偷懒跳过异常处理(虽然它写的异常处理是"正确的废话")。

AI真正容易出问题的地方,不是代码质量,是上下文缺失。它不知道你的部署架构,不知道你的下游依赖,不知道你的业务约束。它写的每一行代码都是"局部最优",但串起来可能是"全局灾难"。

所以与其纠结"AI写的代码靠不靠谱",不如花时间做两件事:

  • 把隐含约束显式化。 ARCHITECTURE.md、DESIGN.md、CONSTRAINTS.md,把AI看不到的东西写成它能读的文件。
  • 加一道AI review AI的关卡。 用不同的Agent、不同的prompt、不同的视角去审视同一个PR。人脑review不过来,但Agent可以7×24小时跑。
  • 最后说个真事

    上个月,我们的Agent自动修了一个线上bug——一个日期格式化的问题,时区处理错了。修完之后自动跑了测试、自动提了PR、自动过了CI、自动合了main。全程没人参与。

    第二天早上我看到commit记录,翻了下改动——确实修对了。但提交信息写的是:

    fix: resolve timezone offset in date formatting

    我盯着这条commit看了很久。它修对了,但我后背发凉。

    不是因为AI修错了,是因为它修对了——而我完全不知道它为什么要这么修,依据是什么,有没有副作用。如果它下次修错了呢?我怎么发现?

    代码是AI写的,锅是人背的。但真正的风险不是"AI写错代码",而是"人看不懂AI写的代码就直接上线了"

    共勉。



    关注「安全值班室」公众号

    每天一篇AI安全早报 + 实战攻防案例

    关注安全值班室

    posted on 2026-05-23 09:00  明.Sir  阅读(23)  评论(0)    收藏  举报

    导航