大模型测评实战:从零跑通 Kev,给“概率模型”做 4 类自动化测试

简介: 本文介绍如何将Kev——一种类型化决策AI模型——作为可测试服务进行验证。它不生成文本,而是针对结构化问题(noul/choice/score)返回概率化答案。重点在于:建立本地HTTP服务、编写接口契约测试、验证多题隔离与选项顺序稳定性、开展概率校准,并构建可回归的冻结样本集。核心理念:把AI当被测对象,而非黑盒顾问。(239字)

这两年,测试工程师接触的大模型,大多都在“写”:写用例、写脚本、写日志总结、写缺陷分析。

Kev 这类模型反过来。它不负责组织一段看起来很有道理的话,而是给你一份状态和几个固定问题,返回每个选项的概率。

比如一条测试执行记录,你可以问它:这个失败是不是环境波动?该归给前端、服务端还是测试数据?问题影响属于什么等级?它不会写一大段解释,直接给出结构化结果。

很多同学看到这里,第一反应是:那不就是一个“AI 判断器”吗?

是。但从测试的角度,更重要的第二反应应该是:既然它是一个判断器,那我要怎么测它?

这篇不聊怎么把它接进发布审批,更不教你拿一个 0.8 的概率直接替人做决定。我们只做一件事:把 Kev 当成一个本地 HTTP 服务,跑通并验证四类最基础、也最容易被忽略的测试。

你最后会得到一套能复用的最小测试资产:

  • 一条真实的 state + questions 请求;
  • 一组 API 契约断言;
  • 一组“多问题会不会串、选项换序会不会翻”的行为测试;
  • 一个能跟着模型版本、问题文案和温度参数一起回归的冻结样本集。

1. 先理解:它不是聊天接口,而是类型化决策接口

普通大模型接口返回的是文本。你要么让人读,要么再找一个模型读,很容易变成“模型评模型”。

Kev 的输入有两部分:

  1. 状态(state):一段模型需要读取的事实,可以是文本,也可以是结构化对象;
  2. 问题(questions):多个带类型的判断题。

它支持三类问题:

问题类型 适合测什么 你要断言什么
noul 是否满足、是否异常、是否需要升级 返回的是 true 的概率,必须在 0~1 之间
choice 故障归属、工单路由、缺陷类别 候选项集合不能丢,概率和应接近 1
score 风险等级、严重程度、规则满足度 分数对应有序等级,不能把它当成天然的 1~5 分

这也是它和“让大模型评价一句话好不好”的根本区别:问题、选项和返回形状都可以被测试代码固定下来。官方接口约定就是把一份 state 和多道类型化问题送入 /v1/systemone,返回每个问题的概率结果。
image.png

2. 第一步:先把本地服务跑起来

准备 Python 3.12 或 3.13,以及 uv。进入项目目录后执行:

git clone https://github.com/jaredpalmer/kev.git
cd kev
uv sync --extra serve
uv run --extra serve python -m kev.serve --run jaredpalmer/kev-4b --port 8008

服务启动后,先别急着做微调。测试同学的第一件事应该是确认:服务能不能稳定返回、返回结构是否符合你后续要依赖的契约。

提醒一句:本地能启动,不等于生产可用。模型大小、设备、输入长度和并发都会影响耗时;这一步的目标只是建立一个可重复调用的被测对象。

3. 第二步:发出第一条“可测试”的决策请求

下面不用虚构一个完整业务故事,就取一条测试执行记录。重点不是模型给出的归属到底对不对,而是你从此拥有了一条可以重复跑、可以写断言的请求。

import httpx

BASE = "http://127.0.0.1:8008"

REQUEST = {
   
    "model": "kev-latest",
    "state": {
   
        "case": "订单取消后,库存没有在 30 秒内回补",
        "observed": "接口返回 200;库存查询仍为原值;重试后恢复",
        "facts": [
            "库存回补由异步消息触发",
            "压测环境消息积压 4 分钟",
            "该用例过去两周出现过 3 次"
        ]
    },
    "questions": {
   
        "is_flaky": {
   
            "type": "noul",
            "instructions": "根据现有事实,这次失败是否更像环境波动而非功能缺陷?"
        },
        "fault_owner": {
   
            "type": "choice",
            "instructions": "当前最该由哪个方向先排查?",
            "criteria": {
   
                "service": "服务逻辑或异步消费异常",
                "environment": "测试环境或基础设施异常",
                "test_data": "测试数据或前置条件异常"
            }
        },
        "impact_level": {
   
            "type": "score",
            "instructions": "按当前证据评估影响等级。",
            "criteria": ["可观察", "需要跟进", "需要立即处理"]
        }
    }
}

response = httpx.post(f"{BASE}/v1/systemone", json=REQUEST, timeout=120)
response.raise_for_status()
print(response.json()["answers"])

image.png

注意一个很容易犯的错误:不要把模型的首个答案当成预期结果。这里的预期结果首先应是协议预期,例如“choice 的候选项没有丢失”“概率分布可用”“score 有对应的等级图例”。语义正确性放到后面的人工标注样本里再验证。

4. 第三步:先写接口契约测试,别一上来只看 HTTP 200

很多 AI 服务的冒烟测试止步于 status_code == 200。对决策模型不够。

下面这组断言不关心本次到底判成“环境”还是“服务”,只检查响应是否仍满足你的依赖约定。它也应该是模型、SDK 或服务版本升级后的第一道回归。

import math
import httpx

def ask(path="/v1/systemone", body=REQUEST):
    resp = httpx.post(f"{BASE}{path}", json=body, timeout=120)
    assert resp.status_code == 200
    assert resp.headers.get("x-typesafe-request-id")
    return resp.json()

def test_decision_response_contract():
    result = ask()
    answers = result["answers"]

    # noul:服务承诺返回“true”的概率
    flaky = answers["is_flaky"]
    assert flaky["type"] == "noul"
    assert 0.0 <= flaky["noul"] <= 1.0

    # choice:候选项齐全、概率可归一、答案来自候选项
    owner = answers["fault_owner"]
    expected = set(REQUEST["questions"]["fault_owner"]["criteria"])
    assert owner["type"] == "choice"
    assert set(owner["probabilities"]) == expected
    assert math.isclose(sum(owner["probabilities"].values()), 1.0, abs_tol=0.03)
    assert owner["choice"] in expected
    assert 0.0 <= owner["confidence"] <= 1.0

    # score:不要只取一个数,等级映射也属于响应契约
    level = answers["impact_level"]
    assert level["type"] == "score"
    assert set(level["legend"]) == set(level["probabilities"])

这里有个测试思路值得记住:模型的答案允许变化,接口承诺不能随便变化。

例如你换了模型权重,fault_owner 从 environment 变成 service,这未必立刻是 Bug;但如果 probabilities 少了一个候选项、noul 被改成了自然语言、分数等级缺失,那后面依赖它的用例分流、报表和脚本都会坏。

5. 第四步:测“多题并发”有没有串题,也测选项顺序会不会影响答案

Kev 的一个核心卖点,是多个问题共享同一份状态,但各自隔离。对测试同学来说,这不是一句架构描述,而是一条可以直接写进自动化的行为要求。

项目服务提供了两个很适合教学和验收的辅助接口:

  • /v1/systemone/separate:把同一批问题拆成多个单独请求;
  • /v1/systemone/permute:把一个 choice 问题的候选项多次换序。

先看隔离。相同状态下,“一问一请求”和“多问一请求”的核心选择不应该无缘无故翻转:

def test_batch_and_separate_are_consistent():
    batched = ask("/v1/systemone")
    separate = ask("/v1/systemone/separate")

    assert (
        batched["answers"]["fault_owner"]["choice"]
        == separate["answers"]["fault_owner"]["choice"]
    )

再测顺序稳定性。这个测试不是要求每次概率小数点后四位完全相同,而是为了抓住“只把选项顺序换了,第一名却翻了”的问题:

def test_choice_order_is_stable():
    body = {
   "request": REQUEST, "question": "fault_owner", "n_perm": 6}
    result = ask("/v1/systemone/permute", body)

    assert result["argmax_stable"], result["runs"]

如果这两个测试失败,先不要急着改阈值。先检查三件事:问题文案是否把多个意图塞到了一道单选题里;候选项是否重叠;你的状态是否缺了决定性的事实。模型“飘”有时确实存在,但更多时候是测试设计把一个不可判的问题伪装成了可判问题。

6. 第五步:概率能不能信,要靠校准测试,不靠直觉

最容易被误用的一句话是:“它给了 0.8,说明有 80% 把握。”

只有当你自己的数据上,模型打到 0.8 左右的样本,最终大约也有八成被人工确认时,这句话才成立。模型准确率高,不代表概率校准得好。

最小做法并不复杂:先准备 30~50 条已经人工裁决过的测试记录,覆盖四类样本:正常、边界、反例、未知。每条记录保留当时的状态、问题、正确选项和人工裁决日期。不要把事后排查结论塞回状态里,否则离线分数会虚高。

下面的 Brier 分数函数就能先跑起来。数值越小,代表预测概率与实际结果的差距越小;它不是唯一指标,却比只看“猜对了多少次”更适合检查概率有没有被高估。

def brier_score(labels: list[int], probs: list[float]) -> float:
    assert len(labels) == len(probs)
    return sum((label - prob) ** 2 for label, prob in zip(labels, probs)) / len(labels)

# labels:人工裁决,1 表示“确实是环境波动”
# probs:答案中 answers["is_flaky"]["noul"] 的概率
print(brier_score(labels, probs))

image.png

所谓“冻结”,不是把 Excel 锁起来不许更新,而是这一批样本一旦作为回归基线,就不能一边调模型一边拿它训练或反复改标注。模型版本、问题文案、候选项、温度参数任一个变化,都重新跑一遍。新样本可以持续补,但要和旧冻结集分开管理。

7. 微调是最后一步,不是第一步

Kev 支持基于自有 JSONL 继续训练,这确实是它的价值之一。但对测试团队而言,微调前至少要先完成两件事:

  1. 用冻结样本集证明:问题定义与标注口径本身是一致的;
  2. 用上面的四层回归证明:服务返回、问题隔离和概率行为没有基础性问题。

否则很容易出现一种假象:模型微调后“准确率提升了”,其实只是它记住了某位同学的标签习惯,或者你的评测样本已经被训练数据污染。

真正适合进入 JSONL 的,不是“这个缺陷很严重”这种散文式总结,而是可复核的记录:当时可见的状态、结构化问题、候选项、人工确认的标签、以及标签依据。这样你以后换模型、换团队成员,仍能解释这条样本为什么这么判。

8. 给测试工程师的最小检查清单

第一次接触这类模型,不需要先造一个庞大的 AI 测试平台。把下面六项跑通,就已经超过大多数“只看演示效果”的接入方式了:

  • [ ] 本地接口能稳定返回类型化答案;
  • [ ] noul、choice、score 都有契约断言;
  • [ ] 多问题和单问题请求的关键结论能对照;
  • [ ] 候选项换序不会导致结果莫名翻转;
  • [ ] 30~50 条人工样本能算出自己的概率质量;
  • [ ] 模型、问题文案或温度参数变化后,会自动重跑冻结集。

Kev 的价值,不是让测试工程师从此相信模型替你判断,而是提供了一种更容易被测试的 AI 接口形态:问题固定、输出固定、概率可记录、行为可回归。

当你把它当作一个被测服务,而不是一个“会给建议的黑盒”,模型才真正开始进入测试工程能够掌控的范围。

相关文章
|
6天前
|
消息中间件 人工智能 缓存
全量跑不动、人肉挑不完:代码量涨8倍之后,测试选择策略该先改哪一步
AI编码爆发正冲击CI根基:Anthropic因Claude贡献80%代码,CI任务半年激增25倍,传统“单写者TIA服务”崩溃。三次线性补丁迅速失效,最终靠“状态上库+无状态写入+滚动归并”重构破局。启示:CI架构须按复利增长设计,状态不可驻留进程——明天就可起步:建append-only测试日志表,迈出自动化TIA第一步。
全量跑不动、人肉挑不完:代码量涨8倍之后,测试选择策略该先改哪一步
|
6天前
|
人工智能 安全 测试技术
同一模型、同一机器、只改一个开关,为什么压测结果仍可能不可信?
本文拆解NVIDIA Blackwell机密推理实验,强调复现实验需严控变量、同步评估吞吐/TPOT/安全状态与输出质量。指出性能数字不可直接外推,提出四维发布门禁(安全、质量、性能、稳定性),倡导测试工程师构建可复现的差分评测体系。(239字)
同一模型、同一机器、只改一个开关,为什么压测结果仍可能不可信?
|
12天前
|
自然语言处理 安全 测试技术
别再只测『答得对不对』:给大模型应用建一套 Prompt 注入红队回归集,把越权/泄密挡在上线前
本文揭示RAG客服应用因缺乏Prompt注入防护而致系统提示词泄露的事故,指出问题根源在于测试只关注“答得对”,却忽视“会不会答不该答的”。提出将注入测试升级为可回归的红队用例集:结构化存于jsonl,覆盖四类注入;用pytest参数化断言输出、工具调用与拒答行为;接入CI自动拦截。安全不是模型天赋,而是靠可执行、可演进的断言守出来的。
别再只测『答得对不对』:给大模型应用建一套 Prompt 注入红队回归集,把越权/泄密挡在上线前
|
1天前
|
人工智能 中间件 测试技术
AI修的补丁单测都过了,模型一加载就挂:真正该拦的是哪一层?
AI补丁常因环境差异导致线上失败:单测通过但真实服务启动报错。本文提出四层验证门——单元、集成、服务冒烟、业务冒烟,强调必须用最小真实服务执行关键请求(如模型加载、健康检查、推理),并留存commit、镜像、日志、Trace等可复盘证据,让AI改动可追溯、可归因。(239字)
AI修的补丁单测都过了,模型一加载就挂:真正该拦的是哪一层?
|
2天前
|
测试技术
决策行 / 缺陷清单 / 复现附录:CI 时代的质量报告,为什么必须分层写
这份质量报告揭示:同一份文档难满足总监(要结论)、开发(要缺陷详情)、测试(要数据口径)三类读者的不同需求。“通用报告”导致低回应率。核心解法是分层叙事——首屏给决策、中段列动作、附录存底稿,同源数据、各取所需,让诚实数字精准触达每类人。
|
2天前
|
JSON 测试技术 数据格式
一次 pytest 跑出三个覆盖率:行、分支、需求,你的报告写的是哪个?
本文揭示覆盖率的三大分母陷阱:行覆盖易被生成代码虚高,分支覆盖难捕业务组合逻辑,需求覆盖最真实却常被省略。提出“三层分母并列报告”法——剔除样板重算行覆盖、按真值表补全分支用例、绑定需求条目审计覆盖,让93.4%不再掩盖81.0%的窟窿,让复盘从归因转向可对账。
|
12天前
|
JSON 人工智能 测试技术
别再给大模型输出写死期望值:Hypothesis + Pydantic + pytest 把非确定性回答测成一组『不变量』
本文揭示大模型测试中“固定值断言”的致命缺陷:因模型输出天然非确定(字段顺序、类型漂移、冗余文本等),`assert == 固定字典` 导致假红或漏检。提出用属性测试(Hypothesis + Pydantic)替代——聚焦守业务不变量(如金额非负、必填字段存在、不泄露提示),而非形态一致。解耦“输出长什么样”与“输出对不对”,让测试真正守住底线。
别再给大模型输出写死期望值:Hypothesis + Pydantic + pytest 把非确定性回答测成一组『不变量』
|
6天前
|
Web App开发 安全 应用服务中间件
网站被浏览器报不安全:HTTPS证书链、安全响应头与Mixed Content的排查记录
客户网站突然被浏览器报不安全,排查发现是HTTPS证书链不完整加安全响应头缺失。本文记录了证书链补全、CSP/HSTS等安全响应头配置和Mixed Content修复的完整过程,以及5个实际踩过的坑。
|
29天前
|
人工智能 安全 API
阿里云Token Plan 个人版Quick Start:最低39 元/月,主流AI工具直接接入,Credits 统一计量
阿里云百炼 Token Plan 个人版是面向个人开发者的 AI 大模型订阅服务,采用 Credits 统一计量,支持在 Claude Code、Cursor、Qwen Code 等主流 AI 编程和智能体工具中使用。目前提供 Lite、Standard、Pro 三档套餐及用量包,限时价格分别为 39 元/月、139 元/月、499 元/月。
阿里云Token Plan 个人版Quick Start:最低39 元/月,主流AI工具直接接入,Credits 统一计量
|
9天前
|
弹性计算 运维 安全
阿里云服务器免费领取最新教程:新用户、学生、个人、企业申领渠道、配置与运维完整实操流程指南(个人新用户3个月、学生1年免费服务器)
整体来看免费ECS权益给学生、个人开发者提供了零成本接触云计算的渠道。个人新用户可以拿到最长3个月免费实例,学生通过高校认证可以拿到代金券实现一年免费使用。整套流程从账号注册、实名认证,再到实例申领、安全配置、命令实操,新手跟着步骤就可以独立完成。但要牢记免费资源存在额度、周期限制,到期及时续费或者释放资源,防止产生不必要账单。拿到实例之后优先做好安全配置,只开放业务必须端口,不要把全部端口对外开放,降低服务器被扫描入侵的风险。利用免费算力多多练习项目部署、运维操作,快速积累云上实操经验。
154 1

热门文章

最新文章