【斯坦福 AI 编程课 05】错误处理与恢复——Agent 的“自我修复”能力

【斯坦福 AI 编程课 05】错误处理与恢复——Agent 的"自我修复"能力

CS146S: 现代软件开发学习笔记系列第五篇

上一篇我们聊了上下文管理——Agent 如何"记住"之前做的事。

但还有一个关键问题:Agent 犯错了怎么办?

如果 Agent 写的代码有 bug,它会一直错下去吗?还是能自己发现并修复?

这就是今天要聊的话题:错误处理与恢复

为什么错误处理很重要?

Agent 也会犯错

很多人以为 AI Agent 是完美的,但实际上:

Agent:我来修复这个登录bug
(修改代码...)

测试:❌ 登录失败
Agent:哦,我改错了,让我重新修复
(又修改代码...)

测试:❌ 还是失败
Agent:让我再试试...

Agent 和人类一样,也会犯错。关键区别是:

  • 人类:犯3次错就放弃了
  • Agent:可以尝试100次,直到成功

但如果没有好的错误处理机制,Agent 就会:

  1. 重复同样的错误
  2. 浪费大量 token
  3. 甚至把代码改得更糟

真实案例

Claude Code 的错误处理:

# 第一次尝试
def calculate_average(numbers):
    return sum(numbers) / len(numbers)

# 测试失败:空列表导致除零错误
# Claude Code 自动修复:

def calculate_average(numbers):
    if not numbers:
        return 0  # 添加边界检查
    return sum(numbers) / len(numbers)

# 测试通过 ✅

Claude Code 会:

  1. 运行测试,发现错误
  2. 分析错误原因
  3. 修复代码
  4. 重新测试
  5. 直到通过

这就是"自我修复"能力。

错误处理的四个层次

第1层:语法错误(最容易)

特点

  • 代码无法运行
  • 错误信息明确
  • 容易定位

示例

# 语法错误
def greet(name
    print(f"Hello {name}")  # 缺少右括号

# Agent 修复:
def greet(name):
    print(f"Hello {name}")

处理策略

  • 使用 linter 自动检测
  • 编译器/解释器报错
  • Agent 直接修复

成功率:95%+

第2层:逻辑错误(较难)

特点

  • 代码能运行,但结果不对
  • 错误信息不明确
  • 需要测试发现

示例

# 逻辑错误
def find_max(numbers):
    max_num = 0  # 错误:应该初始化为负无穷
    for num in numbers:
        if num > max_num:
            max_num = num
    return max_num

# 测试失败:find_max([-1, -2, -3]) 返回 0

# Agent 修复:
def find_max(numbers):
    if not numbers:
        return None
    max_num = float('-inf')  # 修复:初始化为负无穷
    for num in numbers:
        if num > max_num:
            max_num = num
    return max_num

处理策略

  • 编写测试用例
  • 运行测试,查看失败信息
  • Agent 分析失败原因,修复代码

成功率:70-80%

第3层:集成错误(更难)

特点

  • 单元测试通过,但集成失败
  • 涉及多个模块交互
  • 难以复现

示例

# 模块A
def get_user(user_id):
    return db.query(f"SELECT * FROM users WHERE id = {user_id}")

# 模块B
def process_user(user_id):
    user = get_user(user_id)
    return user.name.upper()

# 集成错误:数据库连接失败时,get_user 返回 None
# process_user 调用 None.name 导致 AttributeError

# Agent 修复:
def process_user(user_id):
    user = get_user(user_id)
    if user is None:
        return "Unknown User"  # 添加错误处理
    return user.name.upper()

处理策略

  • 集成测试
  • Mock 外部依赖
  • Agent 分析调用链,添加错误处理

成功率:50-60%

第4层:设计错误(最难)

特点

  • 代码运行正常,但设计有问题
  • 性能差、可维护性差
  • 需要重构

示例

# 设计错误:N+1 查询问题
def get_users_with_posts(user_ids):
    users = []
    for user_id in user_ids:
        user = db.query(f"SELECT * FROM users WHERE id = {user_id}")
        posts = db.query(f"SELECT * FROM posts WHERE user_id = {user_id}")
        user.posts = posts
        users.append(user)
    return users

# 100个用户 = 201次查询(1次查用户 + 100次查用户 + 100次查文章)

# Agent 重构:
def get_users_with_posts(user_ids):
    # 一次查询获取所有用户
    users = db.query(f"SELECT * FROM users WHERE id IN ({','.join(user_ids)})")

    # 一次查询获取所有文章
    posts = db.query(f"SELECT * FROM posts WHERE user_id IN ({','.join(user_ids)})")

    # 在内存中关联
    user_map = {u.id: u for u in users}
    for post in posts:
        if post.user_id in user_map:
            user_map[post.user_id].posts.append(post)

    return users

# 100个用户 = 2次查询

处理策略

  • 代码审查
  • 性能分析
  • Agent 重构代码

成功率:30-40%

Agent 的错误恢复策略

策略1:重试机制

适用场景

  • 网络请求失败
  • 临时性错误
  • 资源暂时不可用

示例

import time
import random

def fetch_data_with_retry(url, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = requests.get(url, timeout=5)
            return response.json()
        except Exception as e:
            if attempt < max_retries - 1:
                wait_time = 2 ** attempt  # 指数退避
                time.sleep(wait_time)
            else:
                raise e

Agent 的重试逻辑

第1次失败 → 等待1秒 → 重试
第2次失败 → 等待2秒 → 重试
第3次失败 → 抛出错误

策略2:回滚机制

适用场景

  • 代码改坏了
  • 需要恢复到之前的状态

示例

# Git 回滚
git checkout HEAD~1 -- broken_file.py

# 或使用 Agent 的自动回滚
if test_failed:
    agent.revert_last_change()
    agent.try_different_approach()

Agent 的回滚逻辑

1. 修改代码
2. 运行测试
3. 如果失败 → 回滚代码
4. 尝试其他方案

策略3:分支探索

适用场景

  • 不确定哪个方案最好
  • 需要尝试多个方向

示例

Agent 的思考过程:

方案A:修改数据库查询
  → 测试:失败

方案B:添加缓存
  → 测试:成功,但性能提升不大

方案C:重构数据结构
  → 测试:成功,性能提升10倍 ✅

Agent 的分支探索

approaches = [
    "fix_query",
    "add_cache",
    "refactor_structure"
]

for approach in approaches:
    agent.try_approach(approach)
    if test_passes():
        break
    else:
        agent.revert()

策略4:渐进式修复

适用场景

  • 错误很复杂
  • 不能一次性修复

示例

第1步:修复最明显的bug
第2步:添加错误处理
第3步:优化性能
第4步:重构代码

Agent 的渐进式修复

# 初始版本
def process_data(data):
    return data.split(',')

# 第1步:添加错误处理
def process_data(data):
    if not data:
        return []
    return data.split(',')

# 第2步:处理异常情况
def process_data(data):
    if not data:
        return []
    try:
        return data.split(',')
    except Exception as e:
        log_error(e)
        return []

# 第3步:添加类型检查
def process_data(data):
    if not isinstance(data, str):
        raise TypeError("Expected string")
    if not data:
        return []
    try:
        return data.split(',')
    except Exception as e:
        log_error(e)
        return []

实战案例:Claude Code 的错误处理

案例1:修复类型错误

场景

# 用户代码
def calculate_total(items):
    total = 0
    for item in items:
        total += item.price * item.quantity
    return total

错误

TypeError: unsupported operand type(s) for +=: 'int' and 'str'

Claude Code 的修复过程

1. 分析错误:
   - price 或 quantity 是字符串
   - 需要类型转换

2. 第一次修复:
   total += float(item.price) * int(item.quantity)

3. 测试:
   - ✅ 通过

4. 进一步优化:
   def calculate_total(items):
       total = 0.0  # 使用浮点数
       for item in items:
           try:
               price = float(item.price)
               quantity = int(item.quantity)
               total += price * quantity
           except (ValueError, AttributeError) as e:
               log_error(f"Invalid item: {item}, error: {e}")
       return total

5. 最终版本:
   - ✅ 处理类型错误
   - ✅ 添加异常处理
   - ✅ 记录错误日志

案例2:修复性能问题

场景

# 慢查询
def get_active_users():
    all_users = User.query.all()  # 查询所有用户
    active_users = []
    for user in all_users:
        if user.last_login > datetime.now() - timedelta(days=30):
            active_users.append(user)
    return active_users

问题

  • 查询所有用户(可能10万+)
  • 在内存中过滤
  • 非常慢

Claude Code 的优化

1. 分析问题:
   - N+1 查询问题
   - 应该在数据库层面过滤

2. 第一次优化:
   def get_active_users():
       threshold = datetime.now() - timedelta(days=30)
       return User.query.filter(User.last_login > threshold).all()

3. 测试:
   - 性能:10秒 → 0.1秒(提升100倍)

4. 进一步优化(添加索引):
   # 在数据库迁移中添加:
   CREATE INDEX idx_users_last_login ON users(last_login);

5. 最终版本:
   - ✅ 查询速度提升100倍
   - ✅ 添加数据库索引
   - ✅ 代码更简洁

错误处理的最佳实践

1. 编写可测试的代码

❌ 错误示范

def process_file(filename):
    data = read_file(filename)  # 硬编码文件读取
    return parse_data(data)

✅ 正确示范

def process_file(filename, file_reader=None):
    reader = file_reader or default_file_reader
    data = reader.read(filename)
    return parse_data(data)

# 测试时可以注入 mock
def test_process_file():
    mock_reader = MockReader()
    result = process_file("test.txt", mock_reader)
    assert result == expected

2. 使用断言和类型提示

❌ 错误示范

def divide(a, b):
    return a / b  # 如果 b=0 会崩溃

✅ 正确示范

def divide(a: float, b: float) -> float:
    assert b != 0, "Divisor cannot be zero"
    return a / b

3. 记录详细的错误信息

❌ 错误示范

try:
    process_data(data)
except Exception:
    pass  # 吞掉错误

✅ 正确示范

try:
    process_data(data)
except ValueError as e:
    logger.error(f"Invalid data format: {data}, error: {e}")
    raise
except Exception as e:
    logger.error(f"Unexpected error processing data: {e}", exc_info=True)
    raise

4. 提供降级方案

❌ 错误示范

def get_weather(city):
    response = requests.get(f"https://api.weather.com/{city}")
    return response.json()  # 如果API失败,整个功能崩溃

✅ 正确示范

def get_weather(city):
    try:
        response = requests.get(f"https://api.weather.com/{city}", timeout=5)
        return response.json()
    except Exception as e:
        logger.warning(f"Weather API failed: {e}")
        return get_cached_weather(city)  # 降级到缓存

总结:Agent 的"自我修复"能力

核心要素

  1. 检测错误

    • 自动运行测试
    • 分析错误日志
    • 监控性能指标
  2. 分析原因

    • 定位错误位置
    • 理解错误类型
    • 找到根本原因
  3. 修复代码

    • 尝试多种方案
    • 渐进式修复
    • 验证修复效果
  4. 防止复发

    • 添加测试用例
    • 改进错误处理
    • 优化代码结构

Agent vs 人类

能力 人类 Agent
检测错误 ⭐⭐⭐ ⭐⭐⭐⭐⭐
分析原因 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
修复代码 ⭐⭐⭐⭐ ⭐⭐⭐⭐
耐心程度 ⭐⭐ ⭐⭐⭐⭐⭐
创造性 ⭐⭐⭐⭐⭐ ⭐⭐⭐

结论

  • Agent 在检测错误耐心方面超越人类
  • 人类在分析原因创造性方面更强
  • 最佳组合:人类设计,Agent 执行,人类审核

未来展望

随着 Agent 能力的提升,错误处理会越来越好:

现在

  • Agent 能修复大部分语法和逻辑错误
  • 集成错误和设计错误需要人类帮助

未来

  • Agent 能自动重构代码
  • Agent 能预测潜在错误
  • Agent 能从错误中学习

下一篇预告:我们将聊"规划与推理"——Agent 如何像人类一样思考和规划。

参考资料


本系列其他文章:

Views: 5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

Index