Glean 分析 37 个模型在企业任务上的性价比这件事之所以在企业 AI 圈里引起讨论不是因为它列出了一张排行榜而是因为它把模型选型从“谁的分数高”拉回到“谁在真实业务里更划算”。企业场景里无论你是做文档问答、客服工单自动分类还是构建内部知识搜索都会遇到同样的问题几十个模型摆在面前质量、速度、成本、上下文长度都不一样到底该选哪一个本文不依赖 Glean 的内部数据而是从工程实践的角度把这套评估方法拆解成可复现的流程。读完你会得到一套能直接落地的评估框架如何构造企业任务评测集、如何定义质量分、如何算性价比、如何批量跑完几十个模型、如何根据结果做选型。1. 企业任务为什么不能直接照搬公开榜单选模型很多团队选模型时第一反应是打开某个公开基准榜单按分数从高到低选。这种做法在个人项目里没有问题但放到企业任务上往往会在上线第一周就暴露出各种问题。1.1 公开基准和企业任务的目标不一致公开基准如 MMLU、HumanEval、GPQA 等衡量的是模型在知识问答、数学推理、代码生成上的通用能力。这些题目通常有明确答案评测方式也比较直接。企业任务则完全不一样它们是窄而具体的从合同里抽取付款周期把客服工单分到二十个业务类别里从企业知识库中检索再生成一段可发布的摘要甚至在收到用户指令后调用 CRM 系统完成一次查询。这些任务对三件事极度敏感输出格式、业务术语、交互流程。榜单分数高不代表模型能在你的数据上稳定输出合法 JSON也不代表它的延迟能满足客服系统几秒内的体验要求。比如一个模型在通用问答上表现很好但给定一段包含大量公司缩写和内部产品名称的文本时可能把字段名抽错或者把金额和日期混在一起。这类问题只有用真实业务样本才能发现。1.2 性价比评估要同时看四个维度而不是只看价格企业场景里选模型至少要从质量、延迟、成本、上下文与能力边界四个维度一起看。维度含义为什么影响选型质量在评测集上的准确率、可执行率、人工抽检满意度决定业务能不能跑通错误率太高会导致返工和客诉延迟单次请求的响应时间包括首 token 延迟和总耗时决定交互体验、超时配置和并发设计成本输入输出 token 单价、实际消耗量、缓存命中率、重试成本决定预算、毛利和是否可持续上下文与能力边界最大上下文长度、是否支持结构化输出、是否支持工具调用决定能否接入现有业务流程能否处理超长文档这四个维度会互相制约。一个支持 200K 上下文的长文本模型可能价格更高但如果它能一次处理完整合同就省去拆分成多段、多次调用和拼接的工程成本。一个速度快的小模型如果在新术语抽取上频繁出错就会把节省下来的模型成本转移到人工修正上。因此性价比不是“最便宜的模型得分最高”而是“在满足质量阈值和延迟约束的前提下单位成本带来的有效质量提升”。1.3 评测候选集要分层不必一开始就让 37 个模型全部跑完实际评测时先按硬性条件做一轮粗筛能显著节约时间和 API 费用。第一轮按上下文长度过滤输入任务最长的样本超过模型窗口的直接排除。第二轮按结构化输出能力过滤不支持 JSON、工具调用或返回格式不稳定的模型要慎重评估。第三轮按单次调用成本过滤如果某个模型处理单任务的预估成本已经高于人工处理费用除非质量有压倒性优势否则没有必要进入完整评测。粗筛之后通常能剩 10 到 15 个模型再进入完整评测。Glean 这类平台在分析 37 个模型时覆盖范围很大但落到具体业务选型时深度评测的模型数量往往会少很多。用分类筛选代替一次性穷举既可以让结果表格更聚焦也可以让每一笔评测费用都花在真正有希望的候选模型上。2. 准备评测环境和测试集先定义“企业任务”是什么评测环境不需要复杂但数据集和记录字段要提前设计好。否则模型跑完一轮后手里只有一堆原始输出很难继续聚合和分析。2.1 按业务场景拆解评测任务类型同一个模型在不同任务上的表现差异可能很大所以评测集不能只有一种任务。比较常见的任务类型包括文本分类意图识别、工单分类、内容安全审核。信息抽取合同要素抽取、简历字段抽取、实体识别。结构化生成将用户指令转换为 JSON、SQL 或查询条件。问答与检索增强生成基于企业内部知识库回答要求答案有依据。工具调用根据对话内容决定是否调用某个 API并生成正确的参数。文本摘要与改写生成周报摘要、会议纪要和对外回复。实际项目中可以从每个任务类型里抽 30 到 50 条真实样本至少覆盖 5 到 8 个任务类型。样本不足会导致结果波动很大一次跑分跑完换个批次数据结论就变了。不要在一开始追求样本量大先把任务覆盖面做起来。2.2 评测数据集使用 JSONL 格式保持字段可扩展一条评测样本通常包含任务标识、输入内容、期望结果和可选约束。下面是两个示例{task: intent_classification, input: 我要查一下上个月的发票, expected: invoice_query} {task: contract_extraction, input: 合同编号 HT-2025-001甲方为北京某科技有限公司付款周期为收到发票后 30 个工作日, expected: {contract_id: HT-2025-001, payment_terms: 30 work days}}把 expected 字段和 input 字段分开后续可以做自动比对。如果需要判断模型是否遵守格式要求还可以增加required_format字段比如json、plain_text、single_label。评测程序读入这个 JSONL 文件后会按照 task 字段切分数据集再逐个模型运行。2.3 环境准备使用 LiteLLM 统一调用多个模型常见模型接入方式有两种一是针对每个模型单独安装官方 SDK二是使用 LiteLLM 这类统一调用层。推荐后者因为评测脚本可以保持同一套接口切换模型只改配置不用重写代码。环境准备命令如下python -m venv .venv source .venv/bin/activate pip install litellm1.40 pandas python-dotenv创建.env文件把不同服务商的 API Key 放进去LiteLLM 会自动读取OPENAI_API_KEYsk-xxx ANTHROPIC_API_KEYsk-xxx TOGETHER_API_KEYxxx这里要注意一点不同模型提供商的 API 兼容程度不一样即使使用 LiteLLM也需要在评测脚本里记录上报的 usage 字段是否完整。如果某个 provider 不返回 token 数就必须用其他方式补全否则成本计算会失真。2.4 每条评测记录要留下这些字段后面聚合才不返工评测过程中把原始输出和计算指标一起落盘是最容易被忽略的基础设施。推荐每次调用返回后记录以下字段字段示例用途modelgpt-4o按模型聚合taskcontract_extraction按任务类型分析expected{contract_id: ...}质量评分output{contract_id: ...}质量评分和格式检查parse_successtrue/false判断输出是否能被解析prompt_tokens1200计算成本completion_tokens240计算成本latency_ms1800判断是否满足延迟约束error_type空/超时/限流排查稳定性问题把这些字段写入 CSV 或 JSONL 文件后续用 Pandas 聚合时会非常方便。如果一开始只保存 output后面再想统计 token 消耗就不得不重新调用模型既浪费钱又浪费时间。3. 定义质量评分和性价比公式指标先于测试运行跑分之前先定义清楚“好”和“划算”是什么。没有评分标准模型把 JSON 字段抽错、但文本上看起来相似时你无法判断它算对还是算错。3.1 质量评分使用三种方式组合不要只用一种质量评分可以分成自动评分和人工评分两层。对于分类、抽取这类有确定性答案的任务使用精确匹配或规则匹配。def is_exact_match(expected, output): if isinstance(expected, dict): try: parsed json.loads(output) return parsed expected except json.JSONDecodeError: return False return str(output).strip() str(expected).strip()对于摘要、问答这类没有唯一答案的任务可以使用 LLM-as-judge让一个强大的评审模型按评分规则打分。评分 Prompt 需要说明任务定义、期望输出、评分维度和分数范围。你是一个评分员。请根据以下任务定义判断模型输出是否满足要求。 任务从合同文本中抽取合同编号和付款周期。 输出必须是 JSON包含 contract_id 和 payment_terms。 评分规则 - 5分两个字段都正确格式合法 - 3分字段基本正确但格式不完整或值有轻微偏差 - 1分字段缺失或抽取明显错误 - 0分无法解析或完全没有抽取自动评分跑完后每类任务还要抽 20 条左右做人工复核。人工复核的主要目的是检查自动评分是否公平。比如模型输出把“30 个工作日”写成了“30 workdays”自动匹配可能判错但对业务来说可能是可以接受的等价表达。用抽检结果修正评分口径后再回到自动评分脚本里更新规则。3.2 成本计算不能只比单价要比“单次任务的实际成本”模型按 token 计费价格通常以每百万 token 为单位。单次任务成本需要结合输入长度、输出长度、缓存命中和重试次数一起估算。cost_per_task ( (prompt_tokens_avg * input_price completion_tokens_avg * output_price) / 1000000 ) cost_per_1k_calls cost_per_task * 1000为什么用千次调用而不是单次因为单次成本数值太小不同模型之间的差距不够直观。按千次调用计算便于直接对比预算影响。下面是一个价格示例实际价格会随接入渠道和时间变化评测前要以当前账单为准模型示例输入/百万 token输出/百万 token假设单次任务估算gpt-4o$2.5$10约 $0.05claude-3-5-sonnet$3$15约 $0.08llama-3.1-70b$0.6$2.4约 $0.02如果平台提供 prompt 缓存命中缓存的输入 token 单价可能只有普通输入的五分之一。评测脚本里要区分prompt_tokens_cached和prompt_tokens_uncached否则成本可能被高估。重试请求的成本也要计入不能只看成功请求。3.3 性价比公式要包含质量阈值和延迟约束性价比不能直接写成“分数除以价格”然后排序因为一个质量特别差的模型可能因为极低的成本排到第一名。推荐先按业务要求设定质量阈值和延迟阈值再计算性价比。quality_score 100 * correct_cases / total_cases cost_per_1k_calls 实际成本模型聚合结果 latency_p95 对延迟数据取 95 百分位 if quality_score quality_threshold: # 例如 80 value_score 0 elif latency_p95 latency_threshold: # 例如 3000ms value_score 0 else: value_score quality_score / cost_per_1k_calls这个公式把不达标模型的性价比直接置 0避免它们出现在候选列表里干扰决策。质量阈值和延迟阈值需要业务方和研发方一起定不能只由算法团队拍脑袋。质量阈值定低了模型错误会被业务放大阈值定高了可能会排除掉成本优势明显、只需要少量规则兜底就足够好的模型。3.4 关键参数调整对照表参数推荐值调小影响调大影响每类任务样本数30 到 50 条结果波动大换个样本排名就变费用增加评估周期变长质量阈值80 分左右低质量业务上线返工成本高可能排除低成本模型变相提高成本延迟阈值3 秒左右产品交互更紧可用模型变少用户体验下降调用方超时风险增加生成温度0 到 0.2输出更稳定但创造类任务表现弱输出更丰富但评分波动大难复现这些参数不是一次性固定的。随着业务语料变化、模型升级评测参数和阈值需要重新审视。评测本身不是一次性的项目而是一条持续运行的流水线。4. 批量跑懂 37 个模型搭建最小可复现的评测脚本完成数据集和指标定义后接下来是让评测脚本跑起来。核心目标不是写出复杂的分布式框架而是用一个稳定、可复现的脚本完成几十个模型的批量评测。4.1 候选模型清单使用 YAML 管理把候选模型按统一配置文件管理脚本读配置后逐个执行。这样新增模型时不需要改代码只改 YAML。models: - name: gpt-4o provider: openai context_window: 128000 max_output_tokens: 4096 - name: claude-3-5-sonnet provider: anthropic context_window: 200000 max_output_tokens: 4096 - name: llama-3.1-70b-instruct provider: together context_window: 128000 max_output_tokens: 2048这里的模型名称只是示例实际评测时要换成当前可用的模型标识。注意 context_window 和 max_output_tokens 会影响评测策略输入样本不能超过窗口输出上限也不能太小否则长摘要任务会截断。4.2 评测脚本核心实现逐模型、逐样本运行并记录结果Python 脚本核心逻辑如下。它使用 LiteLLM 统一调用自动记录延迟、token 和输出内容。import json import time from pathlib import Path import litellm PROMPTS { intent_classification: 请判断用户的意图只输出一个标签。标签范围invoice_query, refund_request, other。, contract_extraction: 请从合同文本中抽取合同编号和付款周期输出 JSON包含 contract_id 和 payment_terms 两个字段。 } def system_prompt_for(task): return PROMPTS.get(task, 请根据用户输入完成指定任务。) def load_jsonl(path): with open(path, r, encodingutf-8) as f: return [json.loads(line) for line in f if line.strip()] def evaluate_model(model_name, dataset): records [] for sample in dataset: start time.time() try: resp litellm.completion( modelmodel_name, messages[ {role: system, content: system_prompt_for(sample[task])}, {role: user, content: sample[input]}, ], temperature0, max_tokens1024, ) latency_ms (time.time() - start) * 1000 records.append({ model: model_name, task: sample[task], expected: json.dumps(sample[expected], ensure_asciiFalse), output: resp.choices[0].message.content, prompt_tokens: resp.usage.prompt_tokens, completion_tokens: resp.usage.completion_tokens, latency_ms: latency_ms, error_type: , }) except Exception as exc: records.append({ model: model_name, task: sample[task], expected: json.dumps(sample[expected], ensure_asciiFalse), output: , prompt_tokens: 0, completion_tokens: 0, latency_ms: -1, error_type: type(exc).__name__, }) return records这段代码有几个关键点。temperature 固定为 0是为了让评分可复现。latency_ms 是在客户端计算的包含网络和排队时间能比较真实地反映调用体验。error_type 记录异常类型后续可以区分是限流、超时还是 provider 返回错误。实际公司内部评测通常不会一个文件跑全 37 个模型因为耗时太长、成本也高。可以加一个--models参数只跑本轮需要验证的模型集合。推荐把评测脚本做成命令行工具支持传入模型列表、数据集路径和输出路径。4.3 聚合结果计算准确率、成本、延迟和性价比评测得到原始记录后下一步是聚合。Pandas 可以快速完成按模型、按任务的聚合。import pandas as pd def aggregate_results(records, pricing): df pd.DataFrame(records) df[quality_pass] df.apply( lambda r: is_exact_match( json.loads(r[expected]), r[output] ), axis1 ) quality df.groupby(model)[quality_pass].mean() * 100 total_tokens df.groupby(model).agg( prompt_tokens(prompt_tokens, mean), completion_tokens(completion_tokens, mean), ) latency_p95 df.groupby(model)[latency_ms].quantile(0.95) summary pd.DataFrame({ quality: quality, p95_latency_ms: latency_p95, }).join(total_tokens) summary[cost_per_1k_calls] ( ( summary[prompt_tokens] * pricing[input_price] summary[completion_tokens] * pricing[output_price] ) / 1000000 ) * 1000 summary[value_score] summary.apply( lambda r: r[quality] / r[cost_per_1k_calls] if r[quality] 80 and r[p95_latency_ms] 3000 else 0, axis1 ) return summary.sort_values(value_score, ascendingFalse)这段代码里的 is_exact_match 需要根据任务类型做扩展否则 JSON 字段顺序不同就可能误判。聚合结果导出到 CSV再用 Excel 或 BI 工具查看即可。4.4 结果表格怎么读不要只看一个综合排序聚合后你会得到类似下面的结果这里只是说明结构数据是模拟的模型示例综合质量p95 延迟 ms千次成本性价比是否达标model-d9221003.129.7是model-f8722001.272.5是model-a9534005.00延迟超标model-b609000.80质量不达标按照 value_score 排序model-f 排在前面但它的质量只有 87如果业务要求必须在 90 分以上它就不能被选为默认模型。因此结果表要保留质量、延迟、成本三个字段而不是只输出一个性价比列。决策时先根据业务约束把不达标模型删掉再在达标集合里选择性价比最高的。5. 结果分析和选型从 37 个模型收敛到 5 个以内跑完评测只是第一步更关键的是从结果中提炼出可以执行的选型结论。5.1 先设质量红线再按性价比排序推荐做法是画一条质量红线。比如分类任务准确率低于 85% 的模型直接不进入候选抽取任务解析失败率高于 10% 的模型直接不进入候选。通过红线筛选后剩下的模型通常不会太多。这样做的好处是避免“一个综合分数很高的模型在关键字段上偏偏总是抽错”这样的陷阱。在没有质量红线的情况下一个成本极低的模型很容易因为性价比公式排到前面但它可能在 5% 的关键任务上出现严重错误。对企业系统来说5% 的错误率放到每天十万次调用里就是五千次故障会造成大量人工干预或客诉。所以性价比排序只适用于“已经通过质量红线”的模型。5.2 按任务维度分模型避免一刀切单一模型很难在每个任务上都做到最佳。实际评测常常会出现这种情况模型 A 在分类任务上准确率最高模型 B 在抽取任务上格式最稳定模型 C 在摘要任务上人工评分最高。如果只选一个默认模型会导致一部分任务长期运行在次优状态。生产系统可以采用模型路由根据任务类型把请求分发到不同模型。路由规则可以写得很简单先用 YAML 配置支持矩阵再让网关根据 task_type 选择模型。评测的粒度越细路由规则就越有依据。5.3 从 37 个模型得到 5 个候选的典型过程一个典型的收敛路径是初始 37 个模型按上下文长度过滤掉 8 个按结构化输出能力过滤掉 6 个按成本过滤掉 7 个剩余 16 个进入完整评测。完整评测后质量红线筛掉 7 个延迟约束筛掉 3 个最后剩余 6 个。在这 6 个里按性价比排序取前 5 个形成候选池再根据任务维度细分到不同业务线。这个过程说明评测结果不是简单的“第一名赢家通吃”而是给你一份候选池和一套约束条件。最终选型时要结合团队运维能力、模型供应商稳定性、数据合规要求做进一步判断。5.4 长尾任务对综合性价比的影响汇总到模型维度时长尾任务往往会拉低平均分。比如某个模型在主流任务上表现很好但处理几十条样本里只出现一次的特殊格式时结构化输出失败平均分就被拖下来。这时候不要急着否定它而是看长尾任务是否可以通过少量提示词优化或规则修正兜底。如果主流任务带来的成本节省远大于长尾任务的处理成本这个模型仍然有选型价值。反过来如果长尾任务出现在核心链路且没有兜底方案那么即使综合性价比很高也要谨慎使用。6. 常见问题排查评测结果不可信时从哪一层查起模型评测会踩很多坑。这里列出四个高频问题每个问题都按现象、原因、检查方式、解决方案展开。6.1 模型返回格式不稳定JSON 解析经常失败现象是同一个模型有时候返回完整 JSON有时候返回带说明文字的文本导致评测脚本中json.loads报错。原因通常是模型本身能力不足或者是 System Prompt 没有明确指定输出格式又或者温度设置太高导致格式漂移。检查方式是打印原始输出统计解析失败样本看是否集中在某些任务类型上。解决方案是把格式要求写进 Prompt优先使用模型厂商提供的 JSON Mode 或结构化输出能力。评测脚本里还要实现降级解析比如用正则截取第一个{到最后一个}之间的内容尽量提升格式兼容性。6.2 LLM-as-judge 评分不稳定重复评测结果不同现象是同一个模型输出让评审模型连续打两次分分数差异很大。原因通常是评审 Prompt 不清晰或者评审模型 temperature 不为 0。检查方式是固定评审模型版本、温度设为 0再对同一批样本跑两次观察分数波动。解决方案是增加评分尺度的说明提供正面和负面示例并引入多数投票观点。评审模型分数无法作为最终结论时人工抽检就是最后一道防线。6.3 token 统计误差导致成本计算偏低或偏高现象是评测得出的成本与月底账单对不上。原因可能是某些 provider 未返回 usage 字段也可能是 prompt 缓存命中导致实际计费低于普通输入又或者是评测脚本没有统计重试请求。检查方式是打印每个 provider 返回的 usage 原始结构和账单里的 token 消耗对比。解决方案是在代码里区分缓存 token 和普通 token并统一记录所有重试请求。对于不返回 usage 的模型需要在配置中手动估计 token 数或者接入网关侧的统一计量。6.4 评测集泄露或评测集过拟合线上效果不及预期现象是评测时模型分数很高上线后面对真实流量效果明显变差。原因可能是评测样本与训练数据重叠也可能是团队反复用同一批评测样本调 Prompt把指标调到虚高。检查方式是核对评测样本是否来自公开数据集确认是否被反复使用。解决方案是保留一个独立的 hold-out 集只在最终验证时使用一次。生产上线后定期从线上日志抽取新样本回流评测集让评测集持续更新。问题现象常见原因检查方式处理建议JSON 解析失败模型能力或提示词不清晰查看原始输出、统计失败比例使用 JSON Mode增加降级解析评审分数波动评审 Prompt 模糊或温度过高固定温度重复评审两次丰富评分标准增加示例成本估算不准usage 字段缺失或缓存未统计对比账单与本地 token 统计记录缓存 token包含重试请求线上效果差评测集泄露或过拟合检查样本来源使用 hold-out 集定期更新评测集减少重复调参7. 最佳实践与可复用清单7.1 评测上线前检查清单每次启动一轮完整评测前按下面的清单过一遍能避免大多数返工每个任务类型至少准备 20 条真实样本优先从线上日志和业务标注数据中抽取。明确每条样本的expected字段区分精确答案和开放性答案。固定 Prompt 模板和评分规则版本代码仓库里保留配置文件的提交记录。固定生成参数尤其是 temperature、max_tokens。记录原始输出、解析结果、token 数、延迟和异常类型。确认各模型的价格配置与当前账单一致含缓存计费规则。明确质量阈值和延迟 SLA并把它们写进聚合脚本。先在小样本上跑通脚本确认字段完整后再扩展全量任务。7.2 做性价比评估最容易踩的 3 个坑第一个坑是只比较模型单价不看 token 消耗差异。同一个任务模型 A 可能平均输出 300 token模型 B 输出 600 token。模型 B 单价低但输出更长总成本可能反而更高。正确做法是用评测结果里的平均 token 消耗乘以单价计算单次任务实际成本。第二个坑是把平均准确率当成唯一质量指标忽略格式错误率。企业任务里一次 JSON 解析失败意味着需要重试、人工修正或丢弃真实成本远高于一次普通错误。质量指标里必须包含parse_success和execution_success而不是只看内容匹配。第三个坑是评测集太小或分布失衡。只用 10 条样本判断一个模型或者 90% 样本来自同一个任务类型都会让排序结果不可靠。建议每类任务至少 30 条样本并通过多次运行观察模型的分数波动范围。7.3 生产环境模型路由的落地建议评测选型完成后不一定要把全部流量切到一个模型。可以在生产系统中加入简单的模型路由按任务类型分发请求同时保留备用模型。路由配置可以放在 YAML 文件里示例routing: intent_classification: primary: model-f fallback: model-d contract_extraction: primary: model-d fallback: model-f summarization: primary: model-a fallback: model-d路由规则上线前要先对每个路由组合做一次小流量回归确认目标模型的输出格式、延迟和错误率与评测时一致。当主模型发生故障或响应超时时自动切到备用模型。这样可以兼顾质量和成本也可以降低单一模型供应商带来的风险。7.4 从一次性评测升级为持续评测模型能力更新速度很快评测结果的有效期通常只有几个月。建议把评测脚本接入 CI/CD 流水线每当有新的模型版本上线或者新增业务任务时自动跑一轮关键任务评测。评测结果写入内部看板供算法团队和业务方一起决策。持续评测的意义不只是省掉重复劳动更是让模型选型从“凭感觉”变成“看数据”。当系统积累几轮评测结果后你会更清楚哪些模型变化会带来影响以及哪些任务需要设置更高的质量底线。如果下一次又有一个新的模型版本发布或者看到一份新的多模型评测报告完全不需要重头开始。你只需要把新模型加入候选配置跑一遍已经定义好的评测集更新成本单价新的性价比表格就会自动生成所有选型决策也就有了新的依据。