基于 Opik G-Eval 与 OpenRouter 的推理模型对比评测实战:gpt-oss-vs-qwen3 项目全解析
【免费下载链接】ai-engineering-hubIn-depth tutorials on LLMs, RAGs and real-world AI agent applications.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub
本文以 ai-engineering-hub 仓库中的gpt-oss-vs-qwen3项目为主体,系统讲解如何借助 LiteLLM + OpenRouter 同时驱动两套推理模型(默认对比 GPT-oss 与 Qwen3-Thinking),并利用 Comet Opik 的 G-Eval 指标对回答进行四维打分。读完本文,你将掌握一套"双模型并跑 + 实时流式展示 + LLM-as-a-Judge 自动评分 + 可视化对比"的推理能力评测流水线的完整搭建方法,可以直接复用到任意模型对比评测场景。
项目定位与核心思路
推理模型(reasoning model)区别于普通对话模型的关键,在于它会先产出隐藏的"思考过程"(reasoning tokens),再输出最终答案。GPT-oss、Qwen3 等模型均具备该能力,但如何公平、可量化地比较它们的推理质量,一直是实践难点。
gpt-oss-vs-qwen3项目给出的答案是:同一问题双模型并行作答 → 展示各自思考过程与最终回答 → 使用 Opik 的 G-Eval 指标自动评测 → 输出分数与可视化图表。整个流程围绕四个支柱技术构建(见 README):
| 技术 | 在本项目中的职责 |
|---|---|
| LiteLLM | 统一模型编排层,屏蔽不同厂商 API 差异 |
| OpenRouter | 通过单一网关访问 OpenAI GPT-oss、Qwen3 等多个模型 |
| Opik(Comet) | 提供 G-Eval 等评测指标与可观测性 |
| Streamlit | 构建交互式对比 UI |
项目采用uv作为包管理器,依赖声明位于 pyproject.toml,要求python >=3.12。核心依赖包括litellm>=1.71.1、opik>=1.8.13、streamlit>=1.45.1、plotly>=6.1.2、pandas>=2.2.3、python-dotenv>=1.1.0以及nest-asyncio、anthropic等。
快速开始:环境配置与启动
1. 拉取代码并安装依赖
该目录位于 ai-engineering-hub 仓库内,若需独立运行,先克隆仓库并进入目标目录:
git clone https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub cd ai-engineering-hub/gpt-oss-vs-qwen3确保本机安装 Python 3.12 及以上版本,然后用 uv 同步依赖:
uv syncuv sync会依据pyproject.toml与已锁定的 uv.lock 创建虚拟环境并安装全部依赖。
2. 配置环境变量
将项目中的.env.example复制为.env:
cp .env.example .env该文件内容只有两项(见 .env.example):
OPENROUTER_API_KEY=your_api_key OPENAI_API_KEY=your_api_key- OPENROUTER_API_KEY:必需的运行凭据。模型推理调用经 OpenRouter 网关转发,
model_service.py中通过os.getenv("OPENROUTER_API_KEY")读取后传给 LiteLLM; - OPENAI_API_KEY:评测阶段必需。Opik 的 G-Eval 默认以 OpenAI GPT-4o 作为打分模型(app.py 中评测结果区标题即注明 "generated with GPT-4o using Opik")。
3. 配置 Opik
README 要求:在项目根目录查找.opik.config文件并填入你的 Opik 凭据。该文件为 ini 格式,虽然当前目录未附带该文件,但同仓库的minimaxm2-vs-sonnet4-5-vs-kimik2-vs-gemini3等评测项目带有可直接参考的 .opik.config 样例,其结构为:
[opik] url_override = https://www.comet.com/opik/api/ workspace = project_name = <你的 Opik 项目名> api_key = <你的 Opik API Key>其中url_override指向 Opik 托管版(Comet)的 API 端点,api_key从 Comet Opik 控制台获取。若使用自托管 Opik,则将url_override改为自建服务地址。正确配置后,每次评测结果与 LLM 调用轨迹会自动上报到对应project_name下的 Opik 项目,供后续在 Web 控制台审计。
4. 启动应用
streamlit run app.py启动后浏览器默认打开http://localhost:8501。
5. 运行自检脚本(可选)
项目附带 test_system.py,可对模型服务与评测系统做冒烟测试:
uv run python test_system.py需要说明的是:从当前仓库源码看,该测试脚本第 6 行导入的validate_model_name、get_model_mapping并未出现在 model_service.py 中(该文件当前仅提供get_model_response_async、get_parallel_responses、get_all_model_names三个函数),直接运行可能触发导入错误,说明测试脚本可能滞后于模块演进。可将其视为"评测系统预期数据结构"的参考,其中对返回结构detailed_metrics / overall_score / passed的断言(test_system.py)与评测函数实际输出完全吻合。
支持的模型与双模型并行调用机制
内置模型注册表
模型的可用清单集中定义在 model_service.py:
AVAILABLE_MODELS = { "GPT-oss-20B": "openrouter/openai/gpt-oss-20b", "Qwen3-Thinking": "openrouter/qwen/qwen3-235b-a22b-thinking-2507", "GPT-oss-120B": "openrouter/openai/gpt-oss-120b", }| UI 显示名 | OpenRouter 模型标识 | 说明 |
|---|---|---|
| GPT-oss-20B | openrouter/openai/gpt-oss-20b | OpenAI 开源推理模型 20B |
| Qwen3-Thinking | openrouter/qwen/qwen3-235b-a22b-thinking-2507 | Qwen3 235B-A22B Thinking 版 |
| GPT-oss-120B | openrouter/openai/gpt-oss-120b | OpenAI 开源推理模型 120B |
目录名gpt-oss-vs-qwen3点明的正是项目最常见的用法——在 GPT-oss 与 Qwen3-Thinking 之间做同题对比。得益于注册表 + 下拉框设计,任何两个已注册模型都可自由组合。
单模型调用:显式索取"思考过程"
get_model_response_async 是底层调用函数,其关键实现:
response = await acompletion( model=model_path, messages=messages, api_key=os.getenv("OPENROUTER_API_KEY"), max_tokens=2000, reasoning={"effort": "high"}, ) ... if hasattr(message, 'reasoning_content') and message.reasoning_content: reasoning = message.reasoning_content elif hasattr(message, 'reasoning') and message.reasoning: reasoning = message.reasoning三个值得注意的细节:
reasoning={"effort": "high"}:显式要求模型启用高强度的推理模式,以便拿到更完整的思考轨迹;max_tokens=2000:限制单次输出规模,兼顾推理深度与响应时长;- reasoning 内容兼容两种字段:优先读取
message.reasoning_content(OpenAI 系),否则回退到message.reasoning,从而兼容不同模型在 OpenRouter 网关上的返回格式差异。
函数最终返回{"content": 最终答案, "reasoning": 思考过程}结构。错误处理也做了分类:API Key 缺失时提示检查OPENROUTER_API_KEY,配额不足时提示稍后重试(model_service.py)。
双模型并行:真正的同时作答
get_parallel_responses 对同一 prompt 发起两次相互独立的调用并原样返回两个协程:
async def get_parallel_responses(prompt, model1, model2): response1 = get_model_response_async(prompt, model1) response2 = get_model_response_async(prompt, model2) return response1, response2在 UI 层(app.py)通过asyncio.gather将两个协程并发执行,确保两个模型"同时开工",保证对比在相同的负载与时间条件下进行:
final_response1, final_response2 = await asyncio.gather( process_response1(model1_container), process_response2(model2_container), )使用流程:一次完整的对比评测
- 选择模型:页面主体提供两个下拉框
Select First Model/Select Second Model,候选来自get_all_model_names()。切换模型会清空上一轮的响应与评测结果(app.py),避免新旧数据混淆; - 提出问题:在底部
What reasoning question would you like to ask?聊天输入框输入推理题,即可触发双模型并跑; - 并排查看结果:回答区域被等分为两栏(
st.columns(2)),每栏按模型分别渲染。若返回了 thinking 内容,会先展示一个默认折叠的"Thinking process"展开区(可见的reasoning),其下再用粗体标注Final Answer后展示最终答案——这让你能同时对比两个模型的"解题思路"与"最终结论"; - (可选)填写参考答案:左侧边栏的
Reference Answer (Optional)文本域(高 200px)可填入期望的标准答案,用于给评测提供对照基准; - 触发评测:侧边栏点击Evaluate Reasoning Responses按钮。需先确认两个模型均已生成响应,否则会提示 "Please generate responses from both models first"(app.py);评测期间显示 spinner,完成后提示
Evaluation complete!; - 查看对比结果:页面下方输出分组柱状图与两份逐指标明细表(见下节)。
评测指标体系:四维 G-Eval 评分
指标定义
评测层由 code_evaluation_opik.py 实现,入口函数为evaluate_reasoning(generated_response, reference_answer=None)。它用 Opik 的 G-Eval 构建了四个相互独立的打分维度:
| 指标 | 考察内容 |
|---|---|
| Logical Reasoning(逻辑推理) | 逻辑步骤与结论的一致性和有效性;是否识别出逻辑谬误或自相矛盾;结论是否由前提有效推出;整体推理结构与流畅度 |
| Factual Accuracy(事实准确性) | 事实性陈述的正确性;是否含误导或错误信息;主张是否有据可依、论证充分;引用信息来源的可靠性 |
| Coherence(连贯性) | 回答的组织结构与编排;观点与概念间的衔接是否清晰;行文清晰度与可读性;是否遵循逻辑顺序 |
| Depth of Analysis(分析深度) | 分析的深度与充分度;是否体现批判性思维与洞见;是否在恰当之处兼顾多视角;是否超越表面观察 |
0–10 分制与通过阈值
每个指标满分 10 分,分档解释如下:
| 分数段 | 通用解读 |
|---|---|
| 0–2 | 存在重大问题(逻辑谬误、事实错误、结构混乱、分析肤浅) |
| 3–5 | 具备基本能力但存在显著缺口 |
| 6–8 | 表现良好,仅有少量瑕疵 |
| 9–10 | 表现优异,满足全部准则 |
综合得分(overall score)取四个指标的算术平均值,通过阈值(passed)为 7.0 分(即 70%)。该口径同时被三处代码锁定:评测函数内的passed: overall_score >= 7.0(code_evaluation_opik.py)、README 的评分说明,以及 UI 中以/ 7.0 (70% threshold)形式展现。
Rubric 如何在 G-Eval 中生效
每个 G-Eval 指标都由task_introduction(裁判角色设定)+evaluation_criteria(分步评估与打分规则)+name组成。以逻辑推理为例(code_evaluation_opik.py):
logical_reasoning_metric = GEval( task_introduction=( "You are an expert judge evaluating the logical reasoning quality of a response. " "The response to evaluate is under ACTUAL_RESPONSE. " "Assess the logical consistency, validity of arguments, and reasoning flow. " "Use the following rubric to assign scores:" ), evaluation_criteria=( "EVALUATION STEPS:\n" "1. Check for logical consistency throughout the response.\n" "2. Identify any logical fallacies or contradictions.\n" "3. Evaluate the validity of conclusions drawn from premises.\n" "4. Assess the overall reasoning structure and flow.\n\n" "SCORING RUBRIC:\n" "Score 0-2: Response contains major logical fallacies or contradictions\n" "Score 3-5: Response has basic logical structure but with some flaws\n" "Score 6-8: Response demonstrates sound logical reasoning with minor gaps\n" "Score 9-10: Response shows exceptional logical consistency and validity\n\n" "Return only a score between 0 and 10, and a concise reason that references the rubric." ), name="Logical Reasoning", )注意 prompt 中Return only a score between 0 and 10的约束:它让打分 LLM 输出带原因的整数/数值分,随后代码统一做一次尺度换算——Opik 内部对GEval(...).score()返回的value归一化到 0–1,因此实现中把四个result.value各自乘以 10 还原为 0–10 分(code_evaluation_opik.py),再取平均得到overall_score。
评测输入的上下文组装
评测对象不是裸文本,而是把被测回答(与可选的参考答案)包进带标记的上下文字符串,让裁判 LLM 一目了然(code_evaluation_opik.py):
context = f"ACTUAL_RESPONSE:\n```\n{generated_response}\n```" if reference_answer: context += f"\nEXPECTED_RESPONSE:\n```\n{reference_answer}\n```"当reference_answer存在时,四个指标提示词中都会追加一句 "The expected response is under EXPECTED_RESPONSE for comparison.",把"有参考答案"的对照评测与"无参考答案"的纯质量评测区分开。另外,code_evaluation_opik.py 保留了evaluate_code作为兼容旧调用的包装函数,说明该评测层脱胎于代码生成评测场景,后泛化为通用推理评测。
评测结果的呈现与解读
评测完成后,UI 会先对返回结构做严格校验(validate_evaluation_result,检查detailed_metrics是否齐备四个指标及各自score,见 app.py),再渲染两类可视化:
- 分组柱状图:基于 Plotly Express 生成,横轴为 Logical Reasoning、Factual Accuracy、Coherence、Depth of Analysis 及 Overall Score 五项,纵轴为分数,两个模型以不同颜色并列(深色主题下的青色与粉色),便于一眼看出谁在哪一维度占优(app.py);
- 逐模型明细表:每个模型各输出一张
Metric / Score / Reasoning三列的数据表,前三行显示四维分数,末行以 "Final weighted average" 汇总综合得分。其中Reasoning 列是裁判 LLM 给出的文字理由,它引用了 rubric 的具体分档——这是把"打多少分"落到"为什么这样打分"的关键证据,也是复盘模型短板最有价值的信息(app.py)。
所有评测调用与轨迹都会同步上报至 Opik 平台,可回到 Web 控制台按project_name查看历史评测、追踪每次打分调用的输入输出,形成"本地看结论、云端做追溯"的完整闭环。
关键设计经验小结
复盘该项目,以下设计点最值得在同类评测系统中复用:
- "思考过程"与"最终答案"分离展示:推理模型的价值一半在可解释的思考链上。将
reasoning_content折叠展示、content直出,既保留完整信息又不抢占版面; - 并发对称对比:
asyncio.gather保证两模型在同一时间窗内作答,配合统一prompt、统一max_tokens、统一reasoning effort,是"公平对比"的底线; - 评分口径统一:G-Eval 底层 0–1 与业务层 0–10 的换算、四维平均与 7.0 阈值的一致性,被写入评测函数、README 与 UI 三处,避免口径漂移;
- 评测可追溯:G-Eval 每个分数都附带 rubric 引用的 reason,配合 Opik 上报,让自动打分不再是"黑盒数字";
- UI 状态即评测状态机:切换模型即清空旧结果、未生成回答不允许评测、结果结构先校验再渲染——这些守卫逻辑(app.py 会话状态相关实现)保证了交互流不会进入无效状态。
以此四维 G-Eval 框架为基底,你可以仅替换AVAILABLE_MODELS注册表与打分 rubric,便可将同一套流水线迁移到代码生成、文本摘要、数学解题等其他推理评测任务中。若希望进一步深入,可直接查阅该目录下的 app.py、code_evaluation_opik.py 与 model_service.py 三份核心源码,理解每一层的完整实现细节。
【免费下载链接】ai-engineering-hubIn-depth tutorials on LLMs, RAGs and real-world AI agent applications.项目地址: https://gitcode.com/GitHub_Trending/ai/ai-engineering-hub
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考