0Pricing
AI Prompt Engineering · 课时

跨模型更新的回归测试

从 GPT-4 升级到 GPT-4o,或从 Claude 3 升级到 3.5 时运行测试套件。

跨模型更新的回归测试 是 CoddyKit 上的免费 AI Prompt Engineering 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 AI Prompt Engineering 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 AI Prompt Engineering 课程共包含 4 节课。

模型更新为何会破坏提示词

LLM 提供商会定期更新模型:GPT-4 → GPT-4o → GPT-4o-2024-11-20,Claude 3 → Claude 3.5 → Claude 3.7。每次更新都会改变模型的行为——通常会改善大多数任务,但偶尔会使某些提示词的表现退化。

没有测试套件时,回归问题只有在用户报告后才会被发现。有了测试套件,您可以在模型更新后的几分钟内检测到回归。

模型更新问题

模型更新可能导致三种变化:

  • 改进:之前失败的测试用例现在通过了——这是好事
  • 中性变化:行为没有改变——大多数测试都属于此类
  • 回归:之前通过的测试用例现在失败了——必须进行调查

即使 1% 的回归率也很重要:如果您有 200 个测试用例,模型更新后其中 2 个开始失败,那么这 2 个可能正是最关键的使用场景。

MODEL_HISTORY = [
    {'model': 'gpt-4', 'deployed': '2023-03-14', 'pass_rate': 0.87},
    {'model': 'gpt-4-turbo', 'deployed': '2023-11-06', 'pass_rate': 0.91},
    {'model': 'gpt-4o', 'deployed': '2024-05-13', 'pass_rate': 0.93},
    {'model': 'gpt-4o-2024-11-20', 'deployed': '2024-11-20', 'pass_rate': None},  # to be measured
]

# Goal: measure pass_rate for the new model before deploying to production

在新模型上运行测试套件

宣布新模型版本后,请同时针对旧模型和新模型运行完整测试套件。比较通过率,并确定哪些具体测试用例的行为发生了变化。

import openai
client = openai.OpenAI(api_key='sk-...')

def run_suite_on_model(test_cases, system_prompt, model):
    results = []
    for test in test_cases:
        resp = client.chat.completions.create(
            model=model,
            messages=[
                {'role': 'system', 'content': system_prompt},
                {'role': 'user', 'content': test['input']}
            ],
            temperature=0
        )
        output = resp.choices[0].message.content
        passed = test['evaluator'](output)
        results.append({'id': test['id'], 'passed': passed, 'output': output})
    pass_rate = sum(r['passed'] for r in results) / len(results)
    return results, pass_rate

old_results, old_rate = run_suite_on_model(TEST_CASES, PROMPT, 'gpt-4o')
new_results, new_rate = run_suite_on_model(TEST_CASES, PROMPT, 'gpt-4o-2024-11-20')
print(f'Old: {old_rate:.1%} | New: {new_rate:.1%} | Delta: {(new_rate-old_rate):+.1%}')

比较不同模型版本的结果

运行两个测试套件后,找出状态发生变化的用例:通过 → 失败(回归)以及失败 → 通过(改进)。

def diff_results(old_results, new_results):
    old_by_id = {r['id']: r for r in old_results}
    new_by_id = {r['id']: r for r in new_results}

    regressions = []
    improvements = []

    for test_id, new_r in new_by_id.items():
        old_r = old_by_id.get(test_id)
        if old_r is None:
            continue
        if old_r['passed'] and not new_r['passed']:
            regressions.append({'id': test_id, 'old_output': old_r['output'], 'new_output': new_r['output']})
        elif not old_r['passed'] and new_r['passed']:
            improvements.append({'id': test_id})

    print(f'Regressions: {len(regressions)}')
    print(f'Improvements: {len(improvements)}')
    for reg in regressions:
        print(f'  REGRESSED: {reg["id"]}')
        print(f'    Old: {reg["old_output"][:60]}')
        print(f'    New: {reg["new_output"][:60]}')
    return regressions, improvements

regressions, improvements = diff_results(old_results, new_results)

在测试日志中跟踪模型版本

每次测试运行的日志都必须包含确切的模型标识符——不能只记录“gpt-4o”,而要记录完整的版本字符串“gpt-4o-2024-11-20”。OpenAI 和 Anthropic 经常在不更改别名名称的情况下更新别名背后的模型(例如“gpt-4o”),因此日志对于调试历史行为至关重要。

import openai, json
from datetime import datetime, timezone

client = openai.OpenAI(api_key='sk-...')

def run_test_with_version_tracking(test, system_prompt, model_alias):
    resp = client.chat.completions.create(
        model=model_alias,
        messages=[
            {'role': 'system', 'content': system_prompt},
            {'role': 'user', 'content': test['input']}
        ],
        temperature=0
    )
    output = resp.choices[0].message.content
    return {
        'test_id': test['id'],
        'model_alias': model_alias,
        'model_actual': resp.model,  # The exact versioned model ID returned by the API
        'timestamp': datetime.now(timezone.utc).isoformat(),
        'output': output,
        'passed': test['evaluator'](output)
    }

调查回归问题

发现回归后,请先进行调查,再更新提示词。请思考:是提示词变差了,还是模型以一种改变行为的方式变得更好了?

例如,GPT-4o 的后继模型可能会更严格地遵循格式指令,导致某个测试失败,因为旧测试预期的是略微不合规的输出。在这种情况下,是模型得到了改进,需要更新的是测试,而不是提示词。

def investigate_regression(test_id, old_output, new_output, prompt, user_input):
    # Step 1: check if old behavior was actually wrong
    judge_prompt = (
        f'Given this task prompt: {prompt}\n'
        f'And this user input: {user_input}\n\n'
        f'Which output is better?\n'
        f'A) {old_output}\n'
        f'B) {new_output}\n\n'
        'Reply with A or B and one sentence explanation.'
    )
    resp = client.chat.completions.create(
        model='gpt-4o',
        messages=[{'role': 'user', 'content': judge_prompt}],
        temperature=0
    )
    verdict = resp.choices[0].message.content
    print(f'Judge verdict for {test_id}: {verdict}')
    # If judge says B (new output) is better: update the test, not the prompt

何时更新提示词,何时更新测试

调查回归问题后,请选择以下三种操作之一:

  • 更新提示词:新模型需要不同的指令措辞,才能实现相同的行为
  • 更新测试:旧的预期输出错误或不够理想;新输出实际上更好
  • 接受回归:新模型无法可靠地完成此任务;在此使用场景中采用旧模型别名
REGRESSION_ACTIONS = {
    'prompt_updated': {
        'when': 'New model ignores instruction the old model followed. Same behavior needed.',
        'action': 'Add stronger/rephrased instruction. Re-run tests on new model.'
    },
    'test_updated': {
        'when': 'New model output is objectively better but fails old test criteria.',
        'action': 'Update expected output in test. Document the improvement.'
    },
    'model_pinned': {
        'when': 'New model cannot perform this task reliably despite prompt changes.',
        'action': 'Pin the model alias to the old versioned ID for this endpoint.'
    }
}

固定模型版本

当模型更新导致无法接受的回归时,请在调查期间将模型固定到之前的版本化 ID。不要在生产环境中使用别名(例如“gpt-4o”),始终使用具体版本。

# Bad practice: alias can point to different model versions over time
client.chat.completions.create(
    model='gpt-4o',  # could be any version at any time
    messages=[...]
)

# Good practice: pin to a specific version for production
client.chat.completions.create(
    model='gpt-4o-2024-11-20',  # guaranteed behavior
    messages=[...]
)

# Track in config
MODEL_CONFIG = {
    'sentiment_classifier': 'gpt-4o-2024-11-20',
    'code_generator': 'gpt-4o-2024-11-20',
    'summarizer': 'gpt-4o-mini-2024-07-18',
}

持续集成中的自动回归测试

当配置中的模型版本发生变化时,自动运行回归测试套件。使用 GitHub Actions 或类似的持续集成工具,在部署前检测回归问题。

# .github/workflows/prompt_regression.yml (YAML, shown as comment)
# name: Prompt Regression Tests
# on:
#   push:
#     paths:
#       - 'config/models.json'  # triggers when model version changes
#       - 'prompts/*.txt'       # triggers when prompts change
# jobs:
#   test:
#     runs-on: ubuntu-latest
#     steps:
#       - uses: actions/checkout@v4
#       - name: Install dependencies
#         run: pip install pytest openai jsonschema
#       - name: Run prompt test suite
#         run: pytest tests/prompts/ -v --junitxml=results.xml
#         env:
#           OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}

# In Python: read model version from config
import json
with open('config/models.json') as f:
    MODEL_CONFIG = json.load(f)
MODEL = MODEL_CONFIG['sentiment_classifier']

处理跨提供商回归

切换提供商时同样需要进行回归测试:GPT-4o → Claude、Claude → Gemini。同一套测试可以揭示哪些提示词需要根据新提供商的行为差异进行修改。

def cross_provider_test(test_cases, system_prompt, providers):
    all_results = {}
    for provider, config in providers.items():
        results, rate = run_suite_on_model(
            test_cases, system_prompt, model=config['model']
        )
        all_results[provider] = {'rate': rate, 'results': results}
        print(f'{provider}: {rate:.1%}')

    # Find cases that fail on one provider but not another
    for test in test_cases:
        outcomes = {
            p: next(r for r in all_results[p]['results'] if r['id'] == test['id'])['passed']
            for p in providers
        }
        if not all(outcomes.values()):
            failing = [p for p, passed in outcomes.items() if not passed]
            print(f'  {test["id"]}: FAILS on {failing}')

    return all_results

监控通过率趋势

从测试历史日志中读取数据,绘制通过率随时间的变化图。下降趋势表示提示词性能退化或模型发生漂移。突然下降则表示发生了回归事件(模型更新或提示词变更)。

import json

def plot_pass_rate_trend(history_file='test_history.jsonl'):
    runs = []
    with open(history_file) as f:
        for line in f:
            runs.append(json.loads(line))

    runs.sort(key=lambda r: r['run_id'])

    print('Pass rate trend:')
    for run in runs[-10:]:  # last 10 runs
        bar = '#' * int(run['pass_rate'] * 40)
        print(f"{run['run_id'][:10]} {run['model']:30} {run['pass_rate']:.0%} |{bar}|")

    # Detect regression
    if len(runs) >= 2:
        delta = runs[-1]['pass_rate'] - runs[-2]['pass_rate']
        if delta < -0.05:
            print(f'ALERT: pass rate dropped {delta:.0%} since last run!')

plot_pass_rate_trend()

知识检查

当新模型版本导致测试失败,但调查发现新模型的输出实际上比旧输出更好时,正确的操作是什么?

回顾:跨模型更新进行回归测试

模型更新时进行回归测试的主要实践:

  • 在旧模型和新模型上运行完整测试套件——比较通过率,并比较具体的失败用例
  • 跟踪确切的模型版本——在每条测试日志中记录完整版本,而不只是别名
  • 调查每个回归问题:这是提示词问题、测试问题,还是模型能力问题?
  • 在生产环境中固定模型——使用具体的版本化 ID,而不是别名
  • 在持续集成中自动化——在模型配置或提示词文件发生变化时触发

下一课:借助工具支持构建完整的提示词测试套件。

常见问题解答

「跨模型更新的回归测试」课时是免费的吗?

是的 — 「跨模型更新的回归测试」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 AI Prompt Engineering 课程的其余内容,请升级到 CoddyKit PRO。 AI Prompt Engineering 课程共包含 4 节课。

「跨模型更新的回归测试」这节课中我会学到什么?

从 GPT-4 升级到 GPT-4o,或从 Claude 3 升级到 3.5 时运行测试套件。 你通过在浏览器中直接运行的动手代码来练习 AI Prompt Engineering,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 AI Prompt Engineering 需要有经验吗?

无需任何先前经验。CoddyKit 上的 AI Prompt Engineering 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「跨模型更新的回归测试」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 AI Prompt Engineering 课中编写并运行代码吗?

能。每节 AI Prompt Engineering 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 编写提示词测试用例
  2. 基于断言的提示词测试
  3. 跨模型更新的回归测试
  4. 构建提示词测试套件
← 返回 AI Prompt Engineering