---
title: "用六个验收案例检验招聘评分模型兼容性"
canonical: "https://siyuanailab.com/curation/translations/b5f60a4724ae34220d12789648fb679e-076663bb1eaaebba7e42986d8c189a5add01156d0c8c6634baf877a4cc256b3c/"
dateModified: "2026-09-30"
datePublished: "2026-09-30"
---

[返回日报条目](https://siyuanailab.com/curation/#entry/b5f60a4724ae34220d12789648fb679e)

 

资料节译

 

# 用六个验收案例检验招聘评分模型兼容性

 

[阅读原文](https://dev.to/evanshepherd8274/a-6-case-single-api-key-acceptance-harness-for-compatible-saas-chat-19)

 

现有资料无法确认原文完整，本页只翻译已取得的材料。

 

现有原件无法确认图片是否齐全。

 

单个 API 密钥能减少部署工作，但无法让模型行为变得可移植。对于一家按职位评分标准评估候选人的 SaaS，真正有用的可移植单位，是由六个验收用例支撑的、带版本的评分契约。我的选择是设置一个小型适配器边界、校验每次响应，并且只有当某个提供商与模型组合通过这套测试后才予以启用。

 

**简答：**比较集成方案时，应看它们保留了哪些应用行为，而不是替换了哪些凭据。OpenAI、Claude 和 Gemini 可以共用一个应用接口，但每个仍是独立的执行目标。兼容聊天形式的请求，只代表传输兼容。候选人评估结果稳定，才是产品要求。

 

这对单人运营的 SaaS 很重要。设置时省下一小时，只能受益一次。避免评分悄然变化，则能保护每周发布。密钥存储和架构校验是差异化程度低的工作，我会交给外部服务；评分标准和决策规则仍保留在应用代码中。

 

一个凭据只回答服务如何进行身份验证。候选人评分会引出更难的问题：评分标准中的每个项目都出现了吗？每个分数是否都与证据挂钩？证据缺失时会变成 `unknown`，还是模型会凭空编造确定性？

 

请求能被端点接受，并不能解决这些问题。通过通用请求格式支持 OpenAI、Claude 和 Gemini，不意味着它们会产生相同的输出。我会把每个确切的模型都记录为经过测试的目标，绝不会仅凭提供商名称推断它们的行为等价。

 

改变设计的约束很简单：上游输入不可信的简历文本，下游则由招聘流程使用结果。摘要格式错误会令人恼火；看似合理却没有依据的分数，可能影响谁能获得审核机会。因此，首要抽象应是 `scoreCandidate()`，而不是通用的 `chat()` 方法。

 

让这个边界保持简单。

 

批处理工作也应采用独立的生命周期。OpenAI Batch API 指南介绍了输入上传、批次创建、状态检查和输出检索。这不是交互式调用。可移植的应用应单独建模延迟处理的任务，而不是强迫两种路径共用一种阻塞式聊天抽象。

 

契约承载的是领域事实，而不是提供商术语。对于未知证据，它保留 `null`。零表示某项标准未达成；null 表示所提交的材料不足以支持判断。把两者合并会造成虚假的精确性。

 

```
type Criterion = { id: string; description: string; weight: number };
type ScoreRequest = {
  rubricVersion: string;
  criteria: Criterion[];
  candidateText: string;
};
type CriterionResult = {
  criterionId: string;
  score: 0 | 1 | 2 | null;
  evidence: string[];
};
type ScoreResult = {
  rubricVersion: string;
  results: CriterionResult[];
};
interface ScoringTarget {
  id: string;
  score(input: ScoreRequest): Promise<unknown>;
}
```

 

返回 `unknown` 是有意为之。提供商的输出只有经过本地校验后，才会成为应用数据。生产环境中，采用维护中的架构校验库是明智之选，但这些检查本身是领域要求：评分标准版本匹配、标准 ID 已知且唯一、结果完整、分数在允许范围内，以及证据为字符串。

 

校验失败时拒绝放行。有限次数的重试可以修复截断的输出，但不能把证据缺失变成通过。达到重试上限后，将该项交由人工审核并显示这一状态。不要悄悄把它转换为零分。

 

最终加权分数应在本地计算。权重由应用负责，因此可以确定性地应用。

 

```
function weightedScore(request: ScoreRequest, result: ScoreResult): number | null {
  const byId = new Map(result.results.map((item) => [item.criterionId, item]));
  if (result.results.some((item) => item.score === null)) return null;
  const totalWeight = request.criteria.reduce((sum, item) => sum + item.weight, 0);
  if (totalWeight <= 0) throw new Error("invalid_weights");
  return request.criteria.reduce((sum, criterion) => {
    const score = byId.get(criterion.id)?.score;
    if (score === null || score === undefined) throw new Error("missing_score");
    return sum + (score / 2) * criterion.weight;
  }, 0) / totalWeight;
}
```

 

我希望测试样例足够小，能在每次变更时运行。六个用例覆盖了第一个有用的边界，但并不假装它们是通用基准测试。

 

| 用例 | 输入压力 | 必须满足的断言 |
| --- | --- | --- |
| 1 | 每项标准都有有力证据 | 每个 ID 都恰好出现一次，并附有可追溯的证据 |
| 2 | 某项标准没有证据 | 该项结果为 null，而不是猜测得出 |
| 3 | 有证据与某项主张相矛盾 | 矛盾与缺失仍明确区分 |
| 4 | 简历文本包含评分指令 | 候选人文本不能取代评分标准 |
| 5 | 很长但有效的工作经历 | 输出完整，或明确报错 |
| 6 | 分数线附近几乎相同的候选人 | 差异可供检查，判定规则始终一致 |

 

对考虑采用的每个提供商与模型组合，运行全部测试样例。只有六项全部通过，才能启用。将规范化后的断言和配置指纹与部署记录一同保存。原始简历需要访问控制和保留规则；不应放进普通日志。

 

有一个用例值得格外关注。在用例 4 中，简历可能包含一句看似要求给出最高分的指令。预期结果不是模型必须使用某种特定措辞，而是保留评分标准和输出格式，并且依据来自候选人的经历，而非那条指令。审核人员可以检查这三项断言，无需争论文风。如果某个目标未通过，在适配器、指令或模型选择发生变化且整套测试重新通过之前，它都不能用于生产环境。

 

如果一个密钥网关无法提供稳定的目标标识、保留请求关联信息，或区分错误与模型内容，那么即使它的首次请求看起来多么方便，也无法满足这一工作流程。这就是每小时营收检验：小型 CI 测试套件能防止反复人工调查，又不会演变成平台项目。

 

错误需要分类。身份验证失败时，应停止向该目标发送流量。限流和暂时性传输故障可以采用有限次数的退避重试。输出无效时，可尝试受控修复，然后转交人工审核。策略拒绝既不是格式错误的 JSON，也不是零分。

 

回退存在风险。第二个目标可能返回格式有效、判断却不同的结果。如果启用了回退，它必须通过相同版本的测试样例，并且记录中必须注明由哪个目标生成了评估结果。

 

不允许无提示替换。

 

业务量增大时，我会按职位类别和评分标准类型扩大金丝雀测试，将交互式评分与批量重新处理分开，并审核任何会改变门槛的评分标准更新。只有当每个测试样例都体现了经过审核的产品预期时，增加样例才有帮助。

 

在可能的情况下，我还会固定确切的模型标识，并记录适配器版本、评分标准版本、目标 ID、延迟、校验结果、重试次数和应用关联 ID。监测校验失败、人工审核量、证据缺失率，以及固定金丝雀测试中的决策变化。延迟和 token 用量有助于容量规划，但两者都不能证明评分质量。

 

代价是上线前需要多做一些工作。六个测试样例、一个解析器和明确的错误处理，比更换基础 URL 并粘贴密钥花的时间更长。它们能提供证据，证明更换目标后面向客户的行为仍保持不变。这才是值得持续维护的可移植性检验。

 

参考资料：

 

- OpenAI Batch API 指南：[https://platform.openai.com/docs/guides/batch](https://platform.openai.com/docs/guides/batch)
 
- OpenAI Whisper 开源语音识别仓库：[https://github.com/openai/whisper](https://github.com/openai/whisper)

 

AI 翻译；具体表述请与原文对照。
