章节13 / 14
  1. 01AI Harness 不是测试脚本,而是 AI 系统的质量控制台
  2. 02先写任务协议,再谈评测指标
  3. 03Golden Dataset:把“感觉不错”变成可回归样例
  4. 04评测不是一个分数:判分器、断言和人工复核怎么组合
  5. 05结构化输出 Harness:先挡住形状错误,再处理业务错误
  6. 06Tool Harness:模型只能提议动作,执行权必须被隔离
  7. 07RAG Harness:先评检索,再评回答
  8. 08Agent Harness:把多步智能体变成可暂停、可恢复、可审计的状态机
  9. 09红队与安全 Harness:把提示注入当成常规回归项
  10. 10观测 Harness:trace 里该看见什么,不该记录什么
  11. 11CI 回归门禁:让 Prompt、模型和检索改动都要过关
  12. 12线上反馈回流:用户反馈怎样变成下一版样例
  13. 13模型路由与发布 Harness:灰度、回滚和成本风险一起看
  14. 14综合项目:交付一个 AI Harness Engineering 蓝图
本文目录12
  1. 模型升级的“非对称风险”:为什么它不仅仅是替换一个 API 字符串
  2. 多维联合路由表的设计:模型、Prompt、RAG 与 Tool 的统一配置
  3. 灰度发布控制:如何科学控制模型切换的爆炸半径
  4. 影子测试与双写监测:无痛评估生产环境的模型表现
  5. 动态成本监控与预算熔断:防止失控的 Token 账单
  6. 异常指标定义与一键回滚 Checklist
  7. 1. 触发回滚的红线指标 (Metrics Redlines)
  8. 2. 紧急回滚操作 Checklist
  9. 实战演练:构建基于 GitHub Actions 与 Promptfoo 的 CI/CD 评测门禁
  10. 步骤 1:在代码库根目录下创建 Promptfoo 配置文件 `promptfooconfig.yaml`
  11. 步骤 2:创建 GitHub Actions 工作流配置文件 `.github/workflows/ai-eval-ci.yml`
  12. 来源核验与时效性复核说明
13

模型路由与发布 Harness:灰度、回滚和成本风险一起看

为 AI 应用设计模型、Prompt、RAG 检索及工具版本的联合路由机制,结合灰度发布、影子测试、动态成本监控与回滚 Checklist,构建高可靠的 AI 持续发布 Harness。

前置基础
  • 完成前序单元的练习或理解对应 harness 概念
  • 掌握基本的 YAML 配置语法和基础的 GitHub Actions 工作流概念
学习结果
  • 设计出一套支持模型、Prompt、RAG 和工具的多维联合路由配置表
  • 制定一份可执行的模型/提示词升级紧急回滚 Checklist
  • 编写出基于 GitHub Actions 和 Promptfoo 的自动化回归评测门禁配置文件

模型升级的“非对称风险”:为什么它不仅仅是替换一个 API 字符串

在传统的软件开发中,升级一个依赖包通常意味着更快的性能或已知 Bug 的修复。但在 AI 应用中,把代码里的 gpt-4o-mini-2024-07-18 换成新发布的模型,或者微调一个 Prompt,其性质更像是在没有充分交通标志的情况下,在繁忙的十字路口重新规划行车线。它不仅仅是替换一个字符串,而是一次需要严密评测、实时观测和随时准备回滚的生产发布。

大语言模型的更新往往伴随着非对称的质量漂移:

  1. 格式退化:新模型可能在逻辑推理上得分更高,但却突然不再严格输出你所要求的 JSON 格式,导致下游解析器崩溃。
  2. 提示词失效:老模型中运作良好的 Prompt,在新模型上可能因为指令遵循强度的变化,产生完全不符合预期的输出。
  3. 检索不匹配:当你升级了 RAG 的向量嵌入模型或检索 Top-K 策略时,原本准备好的上下文可能会被无关杂讯淹没,从而诱发模型产生幻觉。

因此,我们需要一套模型路由与发布 Harness,在上线前通过 CI/CD 拦截低质量变更,在上线时通过灰度分流控制影响范围,并在生产中实时监测成本与响应延迟,建立随时可以退回安全地带的“救生索”。


多维联合路由表的设计:模型、Prompt、RAG 与 Tool 的统一配置

要安全地管理 AI 应用的各个变体,就不能把模型名称和 Prompt 文本硬编码在代码中。我们必须建立一个支持多维联合配置的路由表。一个完整的 AI 运行状态由四个核心维度构成:模型版本 (Model)提示词版本 (Prompt)检索配置 (RAG) 以及工具集版本 (Tools)。这一组维度的特定组合,我们称之为一个执行上下文变体 (Variant)

以下是一个设计良好的联合路由配置示例(routing_manifest.yaml):

yaml
version: "1.2.0"
active_routes:
  - route_id: "prod_stable_customer_service"
    percentage: 90
    config:
      model:
        provider: "openai"
        name: "gpt-4o-mini-2024-07-18"
        temperature: 0.1
      prompt:
        id: "prompt_customer_service_v2"
        version: "2.4.1"
      rag:
        knowledge_base_id: "kb_faq_v1"
        top_k: 3
        score_threshold: 0.75
      tools:
        version: "tools_stable_v1"

  - route_id: "prod_canary_customer_service"
    percentage: 10
    config:
      model:
        provider: "openai"
        name: "gpt-4o-2024-08-06"
        temperature: 0.1
      prompt:
        id: "prompt_customer_service_v2"
        version: "2.5.0-beta.1" # 包含了针对新模型微调的 Prompt
      rag:
        knowledge_base_id: "kb_faq_v1"
        top_k: 4 # 灰度变体尝试获取更多检索上下文
        score_threshold: 0.70
      tools:
        version: "tools_stable_v1"

在代码中,网关或中台中间件需要解析此配置文件,并根据 percentage 字段的权重将传入的会话分配到相应的 route_id。这样,每次模型、Prompt、RAG 的任意变化,都是通过修改路由表、更新路由比例来完成,无需改动业务逻辑代码。


灰度发布控制:如何科学控制模型切换的爆炸半径

除非已经完成了基于黄金数据集(Golden Dataset)的回归评测,否则绝对不要直接在生产环境对 100% 用户发布新的 Prompt 版本,因为微小的提示词调整极易引发不可预测的结构化输出破坏。科学的灰度发布必须遵循分阶段、逐步放量并设置阻断点(Gates)的流程。

根据微软 Azure AI Foundry 评估指南(Evaluate generative AI apps)的思路,评估生成式 AI 应用不仅要关注传统的质量指标,更要关注安全性。因此,当我们的发布路由将 10% 流量切向新模型时,灰度监控 Harness 必须包含安全 Evaluator 的准入控制。

我们推荐以下三阶段灰度策略:

text
[ 开发/测试分支 ] -> CI 自动化回归 (Promptfoo) -> [ 通过门禁 ]
                                                    |
                                                    v
[ 灰度阶段 1: 影子测试 (Shadowing) ] -------------> 100% 生产流量双写,但不返回给用户结果
                                                    |
                                                    v
[ 灰度阶段 2: 灰度测试 (Canary 5%-10%) ] ---------> 真实用户分流,注入质量、安全与成本监控
                                                    |
                                                    v
[ 灰度阶段 3: 全量上线 (100% Prod) ] -------------> 持续观测,更新基线
  1. 影子测试阶段(Shadowing):新版路由接收全部请求的镜像副本,但在后台默默运行。系统不对外返回影子路由的结果,仅收集性能、成本与异常率数据。
  2. 有限灰度阶段(Canary):先切入 5% 流量,只对内部测试账号、或不敏感的客群开放。在这期间,系统自动计算新老路由的质量评分差异。
  3. 渐进式放量阶段:若 5% 流量运行 24 小时后各项业务指标与技术指标无劣化,再逐步扩大到 20%、50% 乃至 100%。

影子测试与双写监测:无痛评估生产环境的模型表现

影子测试是降低发布风险最有效的手段。它将真实的线上请求克隆一份,发送给新版模型路由,然后丢弃新模型的返回结果(或将其记录于日志),仅将老模型的响应返回给用户。

如果采用双写影子测试,应当将影子请求的超时时间设为极低值且异步执行,不要让影子链路的异常阻塞主业务线程的正常返回。否则,新模型的性能抖动或超时直接就会导致线上真实用户遭遇体验下降。

以下是一个简单的异步双写影子测试逻辑示例(Python 伪代码):

python
import asyncio
import logging

logger = logging.getLogger("shadow_harness")

async def call_llm_service(route_config, user_input):
    # 模拟实际调用 LLM 的过程
    await asyncio.sleep(0.1) 
    return {"text": "LLM Response", "tokens": 150}

async def handle_request_with_shadow(user_input):
    # 1. 正常的主业务流程(老路由)
    primary_route = {"model": "gpt-4o-mini-2024-07-18", "temperature": 0.1}
    primary_response = await call_llm_service(primary_route, user_input)
    
    # 2. 异步启动影子路由(新路由)
    shadow_route = {"model": "gpt-4o-2024-08-06", "temperature": 0.1}
    
    # 创建影子任务,不阻塞主流程返回
    asyncio.create_task(
        run_shadow_and_log(shadow_route, user_input, primary_response)
    )
    
    return primary_response

async def run_shadow_and_log(shadow_route, user_input, primary_response):
    try:
        # 给影子调用设置极低的超时时间(例如 1.5 秒),避免拖累系统资源
        shadow_response = await asyncio.wait_for(
            call_llm_service(shadow_route, user_input), 
            timeout=1.5
        )
        # 记录对比日志以供线下评估
        logger.info({
            "event": "shadow_comparison",
            "primary": {"tokens": primary_response["tokens"]},
            "shadow": {"tokens": shadow_response["tokens"]},
            "comparison_needed": True
        })
    except asyncio.TimeoutError:
        logger.warning("Shadow request timed out. New route might be too slow.")
    except Exception as e:
        logger.error(f"Shadow request failed: {str(e)}")

通过这种异步双写,你可以收集到新模型在真实业务负载下的 Token 消耗、耗时分布以及报错频率,从而在决定是否真正放量前,获得最真实的成本与稳定性预判。


动态成本监控与预算熔断:防止失控的 Token 账单

在评估发布时,除了考虑模型输出质量,还要结合业务场景综合权衡成本。如果新模型的语义相似度指标上升但长文本召回的延迟超过了业务阈值,必须立即中断灰度并回滚路由,因为在实时对话场景中,响应延迟的增加会直接导致用户流失。同样的,高昂的 Token 账单也可能直接吞噬掉业务的微薄利润。

根据 AWS Bedrock Evaluation 或 MLflow 的监控理念,监控不能只停留在单次调用的延迟上,必须建立以下关键指标的生产观测:

  1. 每百万 Token 成本(Cost per 1M Tokens):实时计算每万次调用的实际账单。
  2. 输出文本膨胀率(Output Token Inflation Rate):新旧模型对同一 Prompt 的响应长度可能大不相同。如果新模型倾向于写冗长、礼貌的废话,即使它的输入 Token 单价降低了,总体账单也可能因为输出 Token 暴增而翻倍。
  3. 延迟百分位数(Latency P95/P99):首字延迟(Time to First Token, TTFT)和总延迟必须在可控范围内。

预算熔断设计: 在灰度阶段,为灰度路由设置硬性上限(如:该灰度路由在当前小时内的 Token 消耗不得超过 $50 )。一旦触发,路由 Harness 必须自动将 100% 流量静默切换回备用的老路由。这一防御措施对于防止因 Prompt 陷入死循环或外部恶意并发攻击造成的财务损失至关重要。


异常指标定义与一键回滚 Checklist

一个高水平的模型发布 Harness,必须配备一份无需思考、纯由指标驱动、可在 60 秒内无损执行的紧急回滚 Checklist

1. 触发回滚的红线指标 (Metrics Redlines)

如果灰度路由激活后,生产环境出现以下任何一种情况,必须立即触发回滚:

  • 技术红线
    • 灰度路由的 API 报错率(5xx, Rate Limit 429)超过 1% 且持续 3 分钟以上。
    • 平均延迟(TTFT)相比老路由增加超过 50%,或 P95 延迟超过 3.5秒
  • 质量红线
    • 实时提取结果的 JSON 格式校验失败率由原本的 < 0.1% 暴增至 > 2%
    • 负向用户反馈率(如用户点击 Dislike 或踩按钮)相比对照组上升超过 15%
  • 成本红线
    • 单次请求平均成本(由输入/输出 Token 动态核算)超出预算基线 30% 以上。

2. 紧急回滚操作 Checklist

  • 步骤一:确认回滚触发源
    • 确定是由于技术报错(如:429限流)、输出质量劣化(如:JSON格式错误)还是成本超出预期触发回滚。
  • 步骤二:修改动态路由配置
    • 打开路由控制器,将异常路由 route_idpercentage 调整为 0
    • 将稳定的老路由 percentage 调整为 100
    • 注意:此变更必须通过配置中心服务(如 Consul, Nacos, GitHub Repo Dispatch)秒级推送到所有生产实例,严禁重启应用容器。
  • 步骤三:生产流量验证
    • 监控业务网关的实时日志,确认无新请求进入被回滚的灰度路由。
    • 确保生产主链路的报错率和延迟指标回落到历史正常水平。
  • 步骤四:保留现场与故障排查
    • 锁定灰度期间新路由产生的所有输入输出日志(注意脱敏),归档到专门的排查存储桶。
    • 将失败用例提取,转化为测试集补充至 CI 自动化测试中,确保未来的版本不再重复此退化。

实战演练:构建基于 GitHub Actions 与 Promptfoo 的 CI/CD 评测门禁

为了将评估流程固化为研发门禁,我们使用开源测试工具 Promptfoo,配合 GitHub Actions 编写自动化 CI 任务。在开发提交 Prompt 或模型版本变更时,触发回归评测,未通过指标阈值的分支禁止合并。

根据 OpenAI 的 Evaluation Best Practices 导引,持续评测(Continuous Evaluation)需要将自动化检测与人审、LLM Judges 结合。因此在我们的发布 Harness 中,我们不能仅仅依赖简单的 Exact Match,而必须配置 LLM-as-a-judge 的断言来捕获语义偏差。

步骤 1:在代码库根目录下创建 Promptfoo 配置文件 promptfooconfig.yaml

本配置声明了对两组提示词在不同模型上的对比,并定义了严格的断言:

yaml
prompts:
  - "file://prompts/customer_service_v2.txt"

providers:
  - id: openai:gpt-4o-mini-2024-07-18
    config:
      temperature: 0.1
  - id: openai:gpt-4o-2024-08-06
    config:
      temperature: 0.1

tests:
  - description: "测试用户申请退款的场景,要求必须包含退款政策链接,且不能给出不合理的承诺。"
    vars:
      customer_input: "我上周买的衣服还没穿,标签也在,请问可以全额退款吗?"
    assert:
      # 断言 1: 输出必须是合法的 JSON(技术格式门禁)
      - type: is-json
      # 断言 2: 输出中必须包含特定核心词(业务政策门禁)
      - type: contains
        value: "https://example.com/refund-policy"
      # 断言 3: 利用 LLM Judge 验证回答质量(避免大模型给出盲目承诺)
      - type: llm-rubric
        value: "回答不能向客户作出绝对退款的承诺,而必须说明需要审核。如果直接承诺了 100% 退款,则评估为不合格。"

步骤 2:创建 GitHub Actions 工作流配置文件 .github/workflows/ai-eval-ci.yml

此工作流将在每次提交 Pull Request 时自动运行 Promptfoo 评测。若评测失败,CI 将报错阻断 PR 合并:

yaml
name: LLM Eval Regression Guard

on:
  pull_request:
    paths:
      - 'prompts/**'
      - 'promptfooconfig.yaml'

jobs:
  evaluate:
    runs-on: ubuntu-latest
    steps:
      - name: Check out repository
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with: 
          node-version: 20

      - name: Install Promptfoo
        run: npm install -g promptfoo

      - name: Run LLM Evaluation Harness
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
        run: |
          # 运行评测,若有断言失败,返回非 0 退出码
          promptfoo eval

      - name: Check Evaluation Results
        if: failure()
        run: |
          echo "[ERROR] 自动化 AI 评测未通过,检测到严重的质量漂移或格式退化!请查看上方 Promptfoo 详细输出。" 
          exit 1

通过上述 CI 门禁,你可以确保任何 Prompt 的修改或模型的换代,都必须通过你预设的“黄金测试集(Golden Dataset)”断言,防止将有瑕疵的配置带到线上灰度阶段。


来源核验与时效性复核说明

本单元所述的模型联合路由、持续评估、影子测试和 CI 门禁设计基于以下业界公认的成熟工程实践:

  • 评估体系:参考了 OpenAI 发布的《Evaluation best practices》中的持续反馈回路与 LLM-as-a-judge 评估设计方法;
  • 质量与安全控制:吸收了 Microsoft Azure AI Foundry 评估指南(Evaluate generative AI apps)关于内置 Evaluator 与安全检测的思想;
  • 实战自动化工具:基于 Promptfoo(2026年5月访问版本)提供的 CLI 断言机制(is-json, llm-rubric 等)及 CI 集成范式;
  • 持续集成基础:依据 GitHub Actions 关于阶段控制与门禁流程的通用标准构建。

复核与重新核验触发条件

  • 当 Promptfoo 废弃现有的局部断言语法或更改 CLI 的退出码逻辑时;
  • 当主流云服务商(如 AWS Bedrock 或 Azure AI Foundry)发布更紧密集成的生产路由网关及内置灰度熔断组件,可简化手写中间件逻辑时;
  • 每年周期性更新黄金测试数据集,以贴合最新的生产流量分布特征。

模型路由与发布Harness:灰度、回滚和成本风险一起看:把判断写进 Harness 证据链

模型路由和灰度发布要和评测、观测、回滚一起设计。本课交付物是 一套模型/提示/检索版本路由表、灰度计划和回滚 checklist,它必须能被复跑、复核、追踪和复盘。

如果 模型路由与发布Harness:灰 还没有对应的输入样例,先不要讨论自动化覆盖率,因为没有样例就无法判断 harness 是否真的抓住问题。 如果一次评测失败会影响发布,应该保留失败输入、模型输出、工具轨迹和判分理由,否则团队只能凭记忆争论。 如果你准备把某个结果自动放行,必须先写清人工复核的例外条件,只有例外条件明确时,门禁才不会变成新的风险源。

成熟度评估不要只看工具数量,要看失败是否能被发现和阻断。围绕 模型路由与发布Harness:灰度、 做排查时,记录步骤、样例、指标、风险、修复动作和复测结果。

Promptfoo 的《Promptfoo documentation》说明:支撑 prompt/model 评测、测试用例、断言、CI 集成和红队用例。;这意味着 模型路由与发布Harness:灰 要把来源转成可执行断言。GitHub 的《Continuous integration with GitHub Actions》提醒:支撑把 AI eval、prompt 回归、schema 测试和红队样例接入 CI 门禁。;因此本课必须写清自动判断和人工判断的边界。OpenAI 的《Evaluation best practices》提供的证据是:支撑目标定义、数据集、指标、连续评测、人审、judge 偏差和 eval harness 设计。;所以当前结论按 2026-05-28 的来源状态使用。

复核触发条件要具体:如果模型 API/SDK、评测工具版本、Agent 框架、RAG 指标、安全规范、合规政策、平台 release/changelog 或关键来源页面变化,需要重新运行本课样例并更新 harness。

练习验收:把 模型路由与发布Harness:灰度、 接入一个最小 AI 应用,提交包含输入样例、评测结果、失败诊断、来源证据、人工复核结论和下一步修复动作的记录。缺少任何一项,都标记为 needs_review。