定义任务、完成状态与非目标

选择可验证且无真实副作用的任务

推荐任务是“根据版本化政策片段生成结构化处理建议,并可选提出只读订单查询”。它同时覆盖 Context、引用、结构化输出、Tool 提案和模型差异,又不连接真实退款、支付或外发系统。输入包含政策版本、订单摘要和用户请求,输出包含建议类型、理由、引用 ID、风险级别与是否需要人工。

选择任务的原则是结果能够独立验证。纯创意写作难以给出清晰 Golden Answer;真实退款又会引入权限和副作用。教学实验应在足够真实与可安全重复之间取平衡。

completed、refused、incomplete、failed 与 cancelled

completed要求传输完整、结构与领域验证通过;refused保留模型明确拒答;incomplete表示输出被长度或连接中断;failed表示已知不可恢复错误;cancelled表示取消被确认。若 Tool 是否执行无法确认,进入 unknown/人工恢复,而不是伪装为 failed。

用 ADR 固定边界

ADR 记录为什么使用受约束 Workflow:模型负责政策解释和候选建议,代码负责事实读取、Schema、领域规则和终态;为什么暂不开放动作工具;哪些指标只是本地实验;哪些依赖 Provider 当前版本。明确 Why Not 纯规则、开放 Agent 和多 Agent,防止实验过程中范围漂移。

搭建可替换的 TypeScript 主链

Prompt Builder、Adapter、Reducer、Validator、Trace 与 Metrics

Application 只依赖内部 ModelRequest 和 ModelResult;Prompt Builder 组合指令与版本化输入;Provider Adapter 映射请求和事件;Reducer 建立唯一终态;Validator 依次检查完整、语法、Schema 与领域;Trace 保存脱敏事件和状态变化;Metrics 记录质量、延迟、Usage 与失败层。

实验主链与证据流:每个组件都产生可回放证据
Dataset版本化输入与预期
Prompt模板和依赖摘要
Adapter真实或 Mock Provider
Reducer事件与唯一终态
Validator结构、领域与引用
EvidenceTrace、指标与 Scorecard

ModelRequest、ModelEvent、ModelResult 与 CapabilitySnapshot

interface ProviderAdapter {
  capabilities(): Promise<CapabilitySnapshot>
  stream(request: ModelRequest, signal: AbortSignal): AsyncIterable<ModelEvent>
}

type ModelResult =
  | { status: 'completed'; value: Decision; evidence: EvidenceRef[]; usage: Usage }
  | { status: 'refused'; reason?: string }
  | { status: 'incomplete' | 'failed' | 'cancelled' | 'unknown'; error?: NormalizedError }

CapabilitySnapshot 记录目标模型是否支持所需模态、工具、Schema、状态和事件语义。Provider 特性通过显式扩展保留;不兼容时拒绝运行或换候选,不能静默退化成自由文本。

AbortSignal 驱动的 AsyncIterable 主链

async function runCase(testCase: EvalCase, adapter: ProviderAdapter, signal: AbortSignal) {
  const request = promptBuilder.build(testCase)
  const state = createState(request.id)
  for await (const event of adapter.stream(request, signal)) {
    reducer.apply(state, event)
    trace.append(testCase.id, event, state.snapshot())
  }
  const result = finalize(state)
  return result.status === 'completed' ? validators.accept(result) : result
}

代码是主线骨架,项目交付必须补齐所有被调用函数、测试和错误类型,不能把这段节选本身称为可运行仓库。取消信号从测试或 HTTP 入口向下传播,Adapter 负责映射 Provider 取消;取消是否成功仍由最终状态确认。

先用 Fixtures 固定可观察行为

正常、拒答、截断、超时、未知、重复、晚到与 Tool 提案序列

用 JSON 或 NDJSON 保存事件 Fixture。每条记录包含 Provider、API/SDK、模型快照、录制时间、脱敏状态和预期 Reducer 结果。至少覆盖正常文本、结构化响应、拒答、首事件超时、JSON 截断、未知事件、重复 Delta、终态后晚到事件和只读 Tool 提案。

可控 Mock Provider

Mock 接受故障脚本,例如第 N 个事件前延迟、重复某事件、插入未知类型、截断输出或忽略取消。它证明应用状态机对已建模序列的行为,不证明真实 Provider、网络、SDK 默认值和服务能力正确。

真实 Provider 录制、脱敏与回放

在允许的测试环境调用目标 Provider,录制脱敏 typed event,随后加入 Fixture 回放。真实集成测试验证鉴权、能力、事件映射、Usage、取消与错误头;回放用于稳定回归。录制内容不得包含凭据、真实 PII 或禁止入库的模型数据。

把业务任务变成可复现评测

输入、输出、风险、延迟与完成定义

“比较客服模型”粒度过粗。将任务拆为政策引用、字段抽取、处理建议、风险判断和只读 Tool 选择;记录语言、长度、噪声、政策版本、错误损失、延迟目标和人工升级条件。每个能力单元可有不同指标和候选。

正常、边界、失败、对抗和高风险样本

最小评测集不追求大,而追求覆盖责任:典型成功样本建立主流程;边界样本覆盖金额阈值、政策时间与缺失字段;失败样本来自已知模型错误;对抗样本包含不可信文本指令和伪引用;高风险样本单独报告。保存来源、纳入原因、期望和争议处理。

结构、领域、引用、Tool、拒答与任务成功指标

确定性指标包括可解析率、Schema 通过率、字段准确率、引用 ID 存在和 Tool 参数合法;领域指标判断政策结论和风险级别;拒答拆成正确与错误拒答;端到端任务成功必须同时满足关键条件。运行指标记录 TTFT、总延迟、Usage、超时、重试和单位成功成本。

固定变量、多次运行与第二轮针对性优化

第一轮固定 Prompt、Context、Tool、Schema、预算和环境,比较模型本身;第二轮允许为各模型调整 Prompt 和推理预算,比较各自系统前沿。每个样本多次运行并保存原始输出、快照、参数、时间和评分器版本。两轮回答不同问题,不能把 A 的最佳配置与 B 的默认配置直接排名。

OpenAI 当前评测实践强调任务特定 Eval、日志、持续评估及人工与自动评分组合;Anthropic 的 Agent Eval 实践也将完整消息/工具轨迹作为评估对象。它们提供方法参考,本文仍须按本任务重建指标。OpenAI Evaluation best practices,Anthropic Demystifying evals。

从平均分进入失败切片

平均分会被高频简单样本抬高。至少按任务单元、风险、语言、长度、政策版本和数据来源切片,再将错误分为事实、推理、引用、格式、Tool、拒答、协议与性能失败。高风险假阳性即使数量少,也可能直接阻断迁移。

差异接近评分器波动或样本量不足时,结论是“尚未证明更好”,而不是宣布新冠军。主观评分使用盲评或 Pairwise 时要检查评分指南和一致性;LLM Judge 需要用人工样本校准,不得循环地让同一模型证明自己。

先守门槛,再比较效率前沿

用强候选建立质量上限和失败类型

先用能力最强且满足数据、合规条件的候选建立可达到的质量上限。如果它仍无法达到任务门槛,应重新设计任务、Context、Tool 或流程,而不是过早用多模型路由掩盖能力缺口。

质量、风险、合规与可运营性门槛

只有过线候选才进入延迟和成本比较。门槛包括关键质量、不可接受错误、数据地域、安全能力、快照稳定性、限额与可观测字段。随后比较 Pareto 前沿:不存在另一个候选同时更好质量、更低延迟和更低单位成功成本。

Model Selection Policy

type ModelSelectionPolicy = {
  policyId: string
  evidenceSnapshot: string
  taskClass: string
  primary: string
  compatibleCandidates: string[]
  requiredCapabilities: string[]
  qualityFloor: Record<string, number>
  budget: { deadlineMs: number; maxUnitCost: number }
  forbiddenDegradations: string[]
}

字段是教学示例。关键是策略携带证据快照、能力要求和禁止降级项;AI Gateway 可结合实时健康和配额执行,但不能自行突破离线确定的质量或合规下限。

明确拒绝迁移的条件

平均分略升但高风险切片回归、收益小于迁移与运营成本、专有能力无法替代、数据政策不满足或回滚链路未验证时,应拒绝切换。模型选型是可逆决策,必须预先定义复测触发器和退出条件。

注入 Demo 最容易隐藏的故障

故障、预期行为和证据
注入系统必须做到留下证据
首事件超时/取消无部分结果提交,确认取消传播超时层、请求 ID、Provider 状态
JSON 中途断流标记 incomplete,不进入业务写入原始终止原因、校验未执行
未知/重复/晚到告警、去重或隔离,不破坏终态Fixture 与 Reducer 断言
Tool 已执行但回注失败先查账本,不重放副作用callId、幂等键、执行回执
Rate Limit/容量按恢复语义退避或降级尝试次数、deadline、最终状态
模型/SDK/Schema 漂移至少一个门禁发现依赖变化能力探测、契约或评测回归

若故意改变依赖后所有检查仍绿,实验没有覆盖真实依赖。故障注入的目标不是制造异常数量,而是证明检测、隔离、恢复和业务不变量能形成闭环。

把模型变化当成一次发布

Fixtures、评测回归与无副作用 Shadow

模型、Prompt、Schema、Tool 或 Adapter 任一变化先重放协议 Fixtures 和评测集。Shadow 在不影响真实结果的情况下运行候选组合,对比输出、失败和成本;涉及敏感数据时仍须遵守数据策略,不能因为“不提交结果”就跳过授权。

Canary、护栏、禁止降级项和停止条件

Canary 逐步放量,监控关键质量、拒答、人工升级、协议失败、延迟和单位成功成本。高风险任务可禁止自动降级到便宜模型。停止条件应在发布前确定,避免指标恶化后临时争论。

恢复模型、Prompt、Schema 与 Adapter 兼容组合

回滚单位不是单独模型名,而是经过验证的兼容组合。演练故意引入字段或质量回归,确认门禁阻断,再恢复旧组合;记录检测时间、定位路径、恢复时间、丢失或重复风险、残余风险和改进 Owner。只写回滚文档而未执行,仍属于假设。

用证据包完成架构评审

最终证据包应使评审者能从任一失败样本回到输入、模型快照、Prompt、事件、校验层和终态,包括:可运行代码与测试;脱敏 Fixtures;正常与失败 Trace;评测集和评分指南;Scorecard 与失败切片;ADR 与 Model Selection Policy;发布和回滚演练。

逐项标记官方事实、教学 Fixture、本地已验证、真实 Provider 已验证和尚未测试。没有生产流量时可以证明工程方法与高保真验证能力,不能宣称生产 SLO、事故恢复或跨团队影响。

主动提取:Mock Provider 全部通过,为什么仍不能证明接入正确?
Mock 只覆盖预设事件。真实 Provider 还包含鉴权、网络、SDK 默认值、能力差异和未建模事件,需要目标版本集成测试与脱敏录制回放。
选型判断:最低单价模型为什么可能有更高成本?
失败、重试、Tool 循环、Fallback、人工复核和返工都会进入单位成功成本;候选还必须先满足质量、风险和合规门槛。

资料与事实边界

以下以官方文档、标准、论文和原始工程资料为主。厂商 API、价格、限额与模型能力会变化,落地时仍需按目标版本做能力探测和回归。

  1. OpenAI:Evaluation best practices — 任务特定评测、日志、持续评估及评分器组合
  2. OpenAI:Model selection — 先建立准确性基线,再在过线候选中优化成本与延迟
  3. Anthropic:Demystifying evals for AI agents — Agent 轨迹、任务、评分器与评测基础设施
  4. Node.js Test Runner — TypeScript/Node 实验的官方测试运行器参考
  5. OpenAI Responses Streaming — 真实 Provider 事件 Fixture 与能力探测参考