OpenRouter模型选型实战:用轻量级LLM Benchmark建立自己的评测流程
发布时间:2026/8/28 4:45:59 作者:尧图编辑部 阅读量:1,286

上个月我给一个内部知识库工具做模型选型OpenRouter 上候选模型有十几个从便宜的开源模型到贵几倍的闭源模型都有。最初我准备按通用排行榜选一个结果发现排行靠前的模型在真实任务里表现并不稳定有的模型回答很完整但输出格式总是多几个字符有的模型速度快但一碰到长文本就开始丢信息还有的模型成本很低却需要反复调 prompt 才能达到及格线。折腾了一晚上最深的感受是OpenRouter 把模型变成了一个可以随时切换的 API 参数但这个“方便”反而让选择变得更难了。后来我换了一个思路不再把时间花在刷榜单上而是用一个轻量级开源评测脚本把自己任务的样本、判断维度、成本预算全部固化下来让模型在这些样本上跑一遍再对比结果。这篇文章想聊的就是这件事为什么在 OpenRouter 上选模型真正值得做的是建立一套属于自己业务的评测流程一个轻量级开源 LLM Benchmark 工具应该解决什么问题以及如何从最小可用脚本开始把它变成一个可以长期复用的决策工具。1. 为什么在 OpenRouter 上选模型不能只靠榜单和价格1.1 OpenRouter 把模型选择变成了一件高频操作过去接一个模型往往意味着绑定一家供应商从 SDK、鉴权到计费模式都要跟着换一遍。OpenRouter 这类聚合服务改变了这个体验它用一个和 OpenAI 兼容的接口把多个模型暴露给开发者。你只需要服务商 key然后在请求体里把model参数换成对应模型的 ID就能切换底层模型。低频选择变成了高频选择。对一个 AI 应用来说今天可能用的是 A 模型明天因为成本、稳定性或任务效果可能要换成 B 模型。这本身是好事但问题也来了如果没有一套固定的评测方法每一次换模型都相当于重新做一轮“凭感觉判断”。你可能会因为某个模型在一次对话里表现得不错就直接切过去结果上线后才发现它在某个边界场景里频繁出错。也就是说OpenRouter 降低了切换模型的技术成本但没有降低“判断哪个模型适合自己”的认知成本。认知成本只能靠评测流程来解决。1.2 通用榜单回答的是一个和你的任务无关的“平均问题”很多人都习惯看公共排行榜。公共评测集通常覆盖知识问答、推理、多轮对话等通用能力给出的分数确实反映了模型在“平均任务”上的水平。但问题是你的业务不一定是一个平均任务。举个例子如果你要做的是合同关键信息抽取你更关心的是模型能不能稳定地理解“甲方”、“乙方”、“违约金比例”这些字段并且把结果输出成指定 JSON 格式。通用榜单里模型“知识量很大”这一点对你这个场景并不是最关键的能力。反过来一个排行榜分数没那么高的模型可能因为指令遵循能力不错反而在你的任务上表现更稳定。通用榜单当然有参考价值它可以帮你快速筛掉一批明显不适合的模型但它不能替你回答“这个模型在我的 prompt 模板、我的输入分布、我的输出约束下表现如何”。要回答这个问题只能用自己的样本跑一轮。1.3 价格和延迟不是附加项而是任务约束很多人在评测时只关心“回答质量”把价格和延迟当成最后看一眼的东西。但在真实项目里这两个指标往往直接决定方案能不能落地。OpenRouter 的计费方式是按输入和输出 token 分别计价不同模型之间差距很大。同样的任务一个模型可能生成 500 个 token另一个模型生成 800 个 token即使单价相同实际成本也不同。如果是一个每天跑十万次任务的批量场景单位任务成本会被放大得很明显。延迟也是类似。同一份 prompt有的模型一两秒就返回有的模型可能要十几秒。对聊天机器人、实时 Agent 这类场景延迟过高意味着用户直接流失对离线分析任务延迟差一点可能还能接受。所以评测不应该只回答“哪个模型回答得最好”而应该回答“在什么成本、什么速度下哪个模型回答得最符合我的要求”。2. 一个轻量级开源 Benchmark 工具真正要解决的是“选择证据”的沉淀2.1 它不是跑分软件而是一套可复用的评测流程很多人一听 Benchmark 工具会以为它像跑分软件一样给模型打一个总分然后排出名次。如果只是这样那它的价值非常有限因为你换一个任务分数顺序可能就变了。真正有长期价值的是那套流程定义任务样本、固定 prompt 模板、统一采样参数、发起请求、记录输出、计算指标、汇总报告。把这些步骤做成一个可重复执行的脚本相当于把一次性的“模型对比”变成了长期资产。以后每次有新的候选模型或者模型版本更新你只需要把模型 ID 加进去重新跑一遍就能看到它在同一组样本上的最新表现。这也是“Benchmark”这个词在真实工作里的含义不是为了给模型贴标签而是为了给决策提供可追溯、可复现的证据。2.2 核心模块只有四层一个轻量级的 LLM Benchmark 工具不需要做得非常复杂。从功能上拆其实只有四层模型接入层通过 OpenRouter 的统一 API 发起请求不同模型只换model参数。任务样本层一组带输入、期望格式、判断规则的样本。这是整个评测里最核心的部分。评测执行层循环调用模型记录原始输出、状态码、延迟、token 消耗等运行信息。结果对比层把质量分、成本、延迟汇总成表方便横向比较。如果你要自己写这四层就是整个脚本的骨架。如果你要选一个开源项目也应该看它在这四层上做得是否清楚模型配置是不是灵活、样本集是不是好维护、输出记录是不是完整、报告是不是直观。2.3 为什么“开源”和“轻量”缺一不可开源意味着你可以审计评测逻辑确认它没有在背后偷偷改 prompt也没有夹带某家模型的偏好。另一个好处是你可以按自己的任务类型扩展打分规则。比如你想加入一个“JSON 合法性”的规则只需要在代码里加一个函数而不需要向平台提需求。轻量同样重要。一个评测工具如果依赖一堆数据库、消息队列和前端界面那么你在真正测模型之前先要花半天时间把环境搭起来。对一个需要频繁验证“新模型 ID 是否值得切换”的开发者来说这不现实。轻量的含义是一个脚本、一个数据目录、一个 CSV 或 JSON 输出文件就能完成一次评测闭环。需要说明的是“轻量”不是“简陋”。它只在自己的适用范围内轻量核心的请求记录、失败重试、成本核算和人工复核环节都应该有。3. 最小可运行版本从 10 条样本开始把 OpenRouter 模型对比跑起来3.1 准备工作API Key、候选模型和代表性样本开始写脚本之前先把三样东西准备好API Key在 OpenRouter 控制台创建注意不要硬编码在代码里建议通过环境变量读取。候选模型列表不要一开始放几十个模型先选 3 到 5 个你真正纠结的候选即可。你只需要对比“眼前这几个”而不是把所有模型都跑一遍。评测样本集至少准备 10 条最好 20 到 30 条。样本要覆盖正常输入、边界输入和容易出错的输入。比如你是做信息抽取的样本里就要包含空字段、超长文本、特殊符号、多个相同字段等场景。我见过很多人跳过样本集的准备随便拿几条 prompt 就开始测。这样得到一个结论后往往不敢真正应用到生产环境因为样本没有代表性结果说服力不足。样本集是一份值得反复打磨的资产。3.2 最小评测流程固定模板、统一参数、记录一切评测最容易被忽略的一点是公平性。如果你给模型 A 的 prompt 是“请完成以下任务”给模型 B 的 prompt 是“你是一个资深专家请高质量地完成以下任务”那结果即使有差异也不能说明模型本身有差异。最小流程里建议固定这几样东西系统提示词所有模型使用同一个 system prompt。用户 prompt 模板只替换需要测试的具体输入。温度参数统一设为同一个值。如果测评的是稳定性可以多个温度各跑几次。最大输出 token统一上限或者明确记录是否发生了截断。执行逻辑也是一样的对每个模型、每条样本发起请求保存响应。不要只保存模型回答文本还要保存耗时、输入 token 数、输出 token 数、HTTP 状态码、异常信息。这些字段在后续计算成本和排查问题时非常有用。3.3 一个足够简单的 Python 脚本骨架下面是一个最简实现思路不是某个开源项目的完整源码而是可以用来理解整个流程的骨架。使用requests直接调用 OpenRouter 的 chat completions 接口import os import time import requests API_KEY os.getenv(OPENROUTER_API_KEY) API_URL https://openrouter.ai/api/v1/chat/completions HEADERS { Authorization: fBearer {API_KEY}, Content-Type: application/json, } def run_one(prompt: str, model: str, temperature: float 0.2): payload { model: model, messages: [{role: user, content: prompt}], temperature: temperature, } start time.time() resp requests.post(API_URL, headersHEADERS, jsonpayload, timeout60) latency time.time() - start resp.raise_for_status() data resp.json() return { model: model, output: data[choices][0][message][content], prompt_tokens: data.get(usage, {}).get(prompt_tokens, 0), completion_tokens: data.get(usage, {}).get(completion_tokens, 0), latency: latency, }实际使用里还要加上异常捕获、失败重试、批量循环和结果落盘。如果你用的是 OpenAI SDK只需要把base_url指向 OpenRouter 的 API 地址然后按 OpenAI 的调用方式传入model参数。选择哪种方式都可以核心是保证不同模型走同一套请求逻辑。3.4 第一轮结果先不要自动打分先人工过一遍第一轮评测跑完后不要急着用规则或者 LLM judge 自动打分。先把不同模型对同一条样本的输出放在一起人工过一遍。这个“过一遍”不是为了给出最终分数而是为了让你发现意料之外的问题。比如弱模型可能在输出末尾多加了一个句号导致 JSON 解析失败或者模型在长文本中间漏掉了一个字段但规则没有被触发又或者一个模型总是在正式回答前增加一段“好的我来帮你处理”导致解析器拿到的是这段废话。这些问题如果不亲眼看一下很难在设计自动打分规则时注意到。第一轮建议只看 20 到 30 条样本规模不大但能让你对整个评测集的“坑”建立起直觉。注意跑第一轮时先不要并发一条一条跑。这样即使某个模型报错你也能立刻定位到是模型 ID 不对、参数不对还是 API 服务暂时不可用。4. 评测指标不要只盯质量要把延迟、成本和稳定性加进来4.1 客观指标成功率、延迟、Token 消耗和单位任务成本客观指标的最大优势是容易量化你只需要在请求记录里统一统计。指标说明使用建议成功率请求是否正常返回是否出现超时、报错、空输出一个模型如果成功率低于 90%再好的回答质量也没意义端到端延迟从发出请求到收到完整响应的时间实时场景看 p95不要只看平均延迟个别慢请求更影响体验Prompt tokens每次请求输入的 token 消耗同样的 prompt 在不同模型下 token 计算可能略有差异Completion tokens每次请求输出的 token 消耗多出内容不等于质量高可能是废话变多单位任务成本输入成本 输出成本再除以任务条数批量任务最重要的经济指标成功率看起来基础但实际很值得关注。模型偶尔因为服务端问题返回 5xx或者因为输入过长直接拒绝这些都会影响生产环境稳定性。一个模型可能某个时刻表现很好但一天内的错误率已经高到不能接受。延迟方面最好记录多个样本的耗时分布而不是只记平均耗时。有时候一个模型平均 2 秒但有 10% 的请求超过 10 秒这对实时场景是灾难。4.2 质量指标按任务类型选不要用一把尺子量所有模型质量评估没有万能指标。适合你任务的才是好的。信息抽取类任务看关键字段的准确率、召回率以及 JSON 输出是否合法。问答类任务看相关性、事实性和完整性必要时引入人工打分。结构化生成任务看输出是否符合预定义 schema比如 JSON Schema、函数调用格式。对话和 Agent 类任务看是否遵循角色约束、是否合理调用工具、是否有多余输出。如果是短文本判断可以用规则打分比如“答案里是否包含期望实体”“输出是否能被json.loads解析”。如果是长文本质量建议用另一组强模型做 LLM judge但 judge 本身也有偏好需要在样本里混入几个标准答案作为校准。可以考虑把质量分拆成多个维度比如“内容相关”、“格式合规”、“不遗漏关键信息”。如果你只有一个总分很难判断模型到底差在哪里。4.3 指标权重不要固死用组合报告代替单一总分一个常见的错误是设计一个总公式把质量、延迟、成本按固定权重合成一个“最终得分”然后按分数排名。问题是权重应该是业务决定的而不是工具决定的。同一个模型在不同场景下的结论可能完全相反离线分析场景质量权重最高成本权重低延迟只要不太离谱就行。实时客服场景延迟和稳定性的权重很高质量达到及格线即可。批量生成场景成本权重显著上升因为生成量大会直接影响预算。所以更适合的方式是输出一份组合报告包含质量分、成功率、延迟分布、平均成本然后由你来决定当前业务更看重哪个维度。工具负责把事实摊开判断仍然留给人。5. 跑完不等于跑对五个最容易让评测结果失真的大坑5.1 一上来就高并发最先等到的不是结果而是 429很多人把评测脚本写完直接设置并发 20想一口气跑完。结果开局就是一批 429 限流错误脚本崩溃还得重跑。OpenRouter 上的不同模型有不同的速率限制如果请求过于密集服务商会返回限流错误。建议先并发 1 或 2跑通一条样本确认无报错。再用较小并发比如 5看观察延迟和成功率。如果出现 429就增加退避时间或者把并发降下来。做评测的目的是拿数据不是为了测试自己脚本的并发能力。稳定的请求节奏比“跑得快”重要得多。5.2 没有固定温度、最大 Token 和 system prompt比较就失真了温度会影响输出的随机性和多样性。如果你在模型 A 上设temperature0.7在模型 B 上设temperature0得到的差异可能来自参数而不是模型本身。最大 token 同理。如果一个模型上限设 200另一个设 2000输出长度不同格式错误率、信息完整性都会受影响。系统提示词也是一样必须使用同一份。在实际业务里如果你本来就打算给不同模型配置不同的 prompt那是业务优化问题。但如果是做 Benchmark 对比控制变量是底线。5.3 输出解析失败会让整个脚本崩掉必须逐样本兜底LLM 输出天然不稳定即使你要求“只输出 JSON”弱模型也可能在 JSON 前后加上解释文字。评测脚本最常见的问题就是没有对每个样本做独立异常处理结果模型在第三条样本上输出解析失败整个循环中断前面的结果也白跑了。正确的做法是每个样本单独记录成功或失败将原始输出原样保存。解析失败就记一个失败原因然后继续跑下一条。最后统计失败率时你能看到是哪些样本、哪些模型更容易输出非法格式。注意不要因为某条样本解析失败就删除这个样本。它恰恰是判断模型稳定性的重要证据。一个强模型和一个弱模型往往就差在这些“不听话”的输出上。5.4 模型本身会变一个模型 ID 在不同时间可能给出不同表现模型不是静态的。OpenRouter 上同一个模型 ID可能今天由供应商 A 托管明天换成供应商 B 托管。量化精度、推理引擎、上下文处理策略都可能不同。也就是说你上个月测出来的分数到下个月可能不再代表当前那个模型。这意味着评测结果一定要打上时间戳和模型 ID有条件的话记录模型提供方信息。如果发现某个模型效果突然变化先检查是不是模型版本或上游供应商变了不要第一时间怀疑自己的代码。这里也涉及大家经常讨论的精度问题fp16、fp32、bf16 这些推理精度会影响输出质量尤其是逻辑类任务。作为 API 使用者我们通常无法直接控制模型在远端的推理精度但要知道这个变量的存在。如果你对精度特别敏感评测时就要注意观察模型版本变化带来的波动。5.5 评测集需要版本管理就像代码一样很多人评测时随手写几个 prompt测完就删下次需要对比新模型时又重新写一遍。这样最大的问题是两次评测的样本不一样结果无法横向比较。评测集是测试集应该有版本。每次修改样本后就把版本号加一并在最终报告里注明使用的是哪个版本。这样做的好处是当你下一次跑新模型时可以先用旧版本评测集跑旧模型验证结果能复现再对比新模型。否则你很难判断差异到底是模型换新导致的还是 prompt 改导致的。一个轻量级开源工具最大的价值就是在你不断更新评测集时依然可以快速重跑历史模型拿到可比较的记录。这是“一次跑通”远远达不到的。6. 什么时候该自己写脚本什么时候该引入更重的评测方案6.1 适合自写轻量脚本的几种情况如果满足这些条件自己写一个轻量级工具可能是最高效的任务类型比较垂直比如只关心 JSON 输出、信息抽取、单轮问答。候选模型数量不大5 到 10 个以内。你已经积累了足够数量的真实业务样本并且知道判断标准。团队没有多人评测协作的需求一个人用脚本就能完成闭环。这种情况下一个 Python 脚本加一份 CSV 文件可能比任何重量级平台都更灵活。因为你不需要抽象通用的评测框架只需要覆盖自己的任务。6.2 需要更重框架的几种情况反过来如果有以下需求建议评估社区成熟的开源评测框架或商业化平台需要大规模回归测试每次代码更新都在 CI 里自动跑模型效果。需要多人参与标注、评审和结果追溯。需要管理大量来自不同来源的数据集并且支持自定义任务模板。需要同时评测本地模型、私有化模型和远程 API 模型统一指标体系。重框架的代价是学习成本和维护成本更高但收益是规范化和自动化。关键是不要从第一天就上重框架而是先跑一轮小脚本确认自己的评测需求值得投入更多工程资源。6.3 一个五分钟判断清单拿不准时可以问自己几个问题我要比较的模型有多少个少于 10 个轻量脚本足够几十个需要并发调度和报告能力。我的任务能靠规则打分吗如果能脚本就很友好如果完全依赖语义判断需要更多人工抽查。我多久评测一次如果一个月一次脚本够用如果每周都要跑建议把评测放进自动化流程。别人需要看到我的评测结果吗如果只是自己选模型一份 CSV 就够了如果要团队评审需要更方便查阅的报告。样本集会不会持续增长会就需要给样本集做好版本管理不会可以写完就跑。这个清单能帮你省下不少盲目建设工具的时间。回到最开始的问题。OpenRouter 让模型切换变得足够便宜和方便但这也意味着你身边永远会不断出现“新模型、更强模型、更便宜模型”。如果每一次都要靠刷榜单和拍脑袋做决定那你会一直处于“好像该换但又不敢换”的状态。真正值得投入的不是找一个“永远最优”的模型而是建立一套低成本、可复用的评测流程。从今天开始准备 20 条代表性样本写一个几十行的脚本选 3 个候选模型跑一遍记录输出、耗时和成本。这个一两个小时就能完成的小实验能给你带来的真实信息量大概率比看一整天的排行榜更多。