首页
/ 用 Opik 公平评测代码生成大模型:Code Model Comparison 实战指南

用 Opik 公平评测代码生成大模型:Code Model Comparison 实战指南

2026-09-08 21:47:28作者:薛曦旖Francesca

本指南围绕 ai-engineering-hub 仓库中的 code-model-comparison 应用展开。该应用面向"代码生成大模型选型"这一真实需求:把 GitHub 仓库代码作为上下文,让两款前沿模型并行、流式生成同一段代码,再用 Opik 的 G-Eval 自动化指标对"正确性 / 可读性 / 最佳实践"三维度打分并可视化对比。读完本文,你将掌握从仓库摄入、双模型并行对比到基于 LLM-as-a-Judge 的代码质量评估全流程的实现思路,并能直接在本地运行这套工具。

技术栈与模块全景

code-model-comparison 是一个基于 Streamlit 的对比评测应用,其技术分工十分清晰,README 与 pyproject.toml 中声明的依赖一一对应:

技术 在项目中的职责 对应源码
Streamlit Web UI、会话状态管理、双列展示 app.py
LiteLLM 统一调用多家模型(OpenRouter 路由),流式异步补全 model_service.py
Gitingest 将 GitHub 仓库整体摄取为文本上下文 code_ingestion.py
Opik 可观测性平台 + G-Eval(LLM-as-a-Judge)评估指标 code_evaluation_opik.py
Plotly / Pandas 评测结果的条形图与明细表渲染 app.py

整个数据流为:用户在侧边栏填入 GitHub 仓库 URL → Gitingest 摄取仓库 → 同一 prompt 分发给两个模型流式生成 → 两份代码并行送入 Opik G-Eval → 得分可视化对比。四个模块各司其职,模块边界清晰,便于替换模型供应商或评估策略。

环境准备与安装

项目要求 Python 3.12 或更高版本(见 pyproject.toml 中的 requires-python = ">=3.12"),依赖通过 uv 统一管理:

uv sync

pyproject.toml 声明了核心依赖:litellm>=1.71.1(模型编排)、opik>=1.8.13(评估)、gitingest>=0.1.4(代码摄取)、streamlit>=1.45.1(UI),以及 anthropicplotlypandaspython-dotenv 等支撑库。

密钥与 Opik 配置

复制 .env.example.env 并填写密钥。仓库中的 .env.example 内容如下:

OPENROUTER_API_KEY=
OPENAI_API_KEY=
  • OPENROUTER_API_KEY:模型统一走 OpenRouter 网关调用,这是运行所必需的。若缺失或无效,model_service.py 会给出 "Invalid or missing API key" 之类的明确报错。
  • OPENAI_API_KEY:为评测阶段的评估大模型预留(评估打分由 LLM 作为评判者完成)。

Opik 的凭据不是写在 .env,而是放在仓库根目录的 .opik.config 中(README 中"Look for the .opik.config file in the root directory"所指即此文件):

[opik]
url_override = https://www.comet.com/opik/api/
workspace =
project_name = Code Evaluation
api_key =

其中 url_override 默认指向 Comet Opik 云端 API 端点,project_name 默认为 Code Evaluation(评测运行会归档到该 Opik 项目),请将 api_keyworkspace 填为你在 Opik/Comet 控制台的实际值。若使用自托管 Opik,将 url_override 改为自建服务地址即可。

启动与使用流程

配置完成后启动:

streamlit run app.py

七个核心操作步骤

README 给出的使用流程可直接对应到 app.py 的界面实现:

  1. 选择待对比的模型:页面上方两列下拉框各选一个模型(Model 1 / Model 2)。可选项来自 model_service.pyAVAILABLE_MODELS 字典。
  2. 输入 GitHub 仓库 URL:位于左侧边栏的 "GitHub Repository URL" 文本框。
  3. 点击 "Ingest Repository" 摄取仓库:成功后把返回的上下文写入 st.session_state.context
  4. 在聊天框输入代码生成 prompt
  5. 并排查看两模型生成的代码:两个模型各自以流式输出渲染在左右两栏。
  6. 点击 "Evaluate Code" 触发评估:两个模型的生成代码会分别进入 Opik 评测管线。
  7. 查看对比指标:页面底部展示双模型的分维度条形图与明细表。

有参考答案(Ground Truth)时的对比

侧边栏还提供了一个可选输入 "Reference Code":当你手里有期望实现的"标准答案"代码时填入其中,评估时会将其作为 EXPECTED_CODE 一并送入评判器,使正确性打分更有依据。这一能力在 code_evaluation_opik.py 中实现——上下文由 ACTUAL_CODE(模型生成代码)和可选的 EXPECTED_CODE(参考代码)拼接而成。

支持哪些模型:OpenRouter 统一网关

model_service.py 中的 AVAILABLE_MODELS 定义了默认候选集,展示名与 OpenRouter 上的真实模型 ID 通过映射关系解耦:

AVAILABLE_MODELS = {
    "Claude Sonnet 4": "openrouter/anthropic/claude-sonnet-4",
    "Qwen3-Coder": "openrouter/qwen/qwen3-coder",
    "Gemini 2.5 Flash": "openrouter/google/gemini-2.5-flash",
    "GPT-4.1": "openrouter/openai/gpt-4.1",
}

四个名字即 UI 下拉框中的选项,值即传给 LiteLLM 的 model 参数。要调整或扩充候选模型,只需修改此字典即可(注意:需保证对应模型确实在 OpenRouter 上开放)。get_model_mapping() 会校验传入的展示名,非法名称会抛出 ValueError 并给出友好提示。

底层调用参数

get_model_response_async 是核心生成函数(见 model_service.py),它使用 LiteLLM 的异步接口:

response = await acompletion(
    model=model_mapping,
    messages=messages,
    api_key=os.getenv("OPENROUTER_API_KEY"),
    max_tokens=2000,
    stream=True,
)

几个关键设计值得注意:

  • max_tokens=2000:限定单次生成的 token 上限,防止长代码输出失控;
  • stream=True + 异步遍历 chunk:逐块产出内容,UI 得以实现打字机式实时渲染;
  • 错误分级处理:根据异常文本特征区分"密钥缺失/鉴权失败""配额或限流""模型不可用"三种常见故障,并向用户展示针对性提示。

并行双模型流式生成的实现原理

为保证对比公平,两个模型接收完全相同的系统指令与用户 query。系统提示在 model_service.py 中固定拼装,要求模型:严格沿用仓库既有模式与命名约定、保持风格一致、写清 docstring、确保与现有组件无缝集成、只输出代码不加解释。

生成阶段的关键在于 get_parallel_responses 返回两个异步生成器,随后由 app.py 通过 await get_parallel_responses(...) 取得,再用 asyncio.gather 并发消费两个流(见 app.py 的 process_model1_stream / process_model2_streamasyncio.gather 调用),实现"同一 prompt、同一时刻、左右并排"的公平对比。

流式渲染时对输出做了一层清理:逐段去除模型可能包裹的 ```python / ``` 代码围栏,再实时刷新到 st.code 容器中。历史会话、最近一次生成结果、评估结果等均持久化在 st.session_state 中;一旦用户中途更换了任一模型,程序会自动清空旧的生成与评估缓存,避免"新模型 + 旧数据"造成误导(见 app.py)。

代码摄取:用 Gitingest 把仓库变成上下文

code_ingestion.py 是摄入模块,逻辑极简但边界清晰:

from gitingest import ingest

def ingest_github_repo(repo_url: str) -> dict[str, str]:
    # 校验 URL 必须是 https://github.com/ 或 http://github.com/ 开头
    ...
    summary, structure, content = ingest(repo_url)
    context = {
        "summary": summary,      # 仓库整体摘要
        "structure": structure,  # 目录结构树
        "content": content       # 源码正文(拼接后作为模型上下文)
    }
    return context

在进入摄取前,它先用前缀校验过滤掉非 GitHub 的 URL;ingest() 产出的三个字段中,content 会被插入到模型系统提示的 "Repository Context" 占位处,让模型"读"到真实的仓库代码风格后再生成本仓库语境下的新代码。此外 app.py 会对摄入结果的类型与 content 字段做防御性校验,结构非法时提示用户重新摄取。

评估机制深度解析:Opik G-Eval 三维度打分

评估模块 code_evaluation_opik.py 是整个项目的灵魂,它基于 Opik 的 GEval 指标(一种 LLM-as-a-Judge / prompt-based 评估方式)实现了三个独立指标。

三个评估维度及判分标准

维度 评估关注点 评估步骤摘要(源码)
Code Correctness 功能正确性、边界处理、完整性 全部功能是否实现;边界是否覆盖;潜在运行时错误;输出是否符合预期
Code Readability 命名、格式、文档、结构 命名是否清晰一致;格式缩进;注释与 docstring;代码逻辑组织
Best Practices 异常处理、安全性、效率、模块化 异常是否正确捕获;安全实践;性能;功能是否拆分为可复用模块

每个指标都是独立的 GEval 实例,通过 task_introduction 设定"专家裁判"角色、通过 evaluation_criteria 给出分步评估指令与打分 rubric,name 用于区分指标(见 code_evaluation_opik.py)。

README 中给出的通用分数解读(0-10 分制)如下,且与源码中各 rubric 文本完全一致:

  • 0-2:存在严重问题或代码不可用
  • 3-5:基础实现但有明显缺陷
  • 6-8:良好实现,存在少量小问题
  • 9-10:优秀实现,满足所有标准

以正确性指标为例,其 rubric 原文精确对应这段区间(code_evaluation_opik.py):

Score 0-2: Code is non-functional or has critical errors
Score 3-5: Code works but misses key functionality
Score 6-8: Code is mostly correct with minor issues
Score 9-10: Code is completely correct

打分流程与分数换算

evaluate_code 的执行链路如下:

  1. 拼接上下文:构造 ACTUAL_CODE(生成代码),若传入参考代码则追加 EXPECTED_CODE 块;
  2. 依次打分:三个 GEval 指标分别对同一份 context 调用 metric.score(output=context)
  3. 分数换算:Opik 返回 0-1 区间分,源码将其 * 10 换算为 0-10 便于人读(code_evaluation_opik.py);
  4. 计算总分overall_score = (correctness + readability + best_practices) / 3,即三者的算术平均(README 中"The overall score is calculated as an average of these three metrics"即此实现);
  5. 判定通过阈值passed = overall_score >= 7.0,即 70% 通过线(见 code_evaluation_opik.py)。

返回结构是带 schema 的字典:overall_scoredetailed_metrics(各维度 scorereason)、passed 布尔值;任何异常都会被兜底捕获并返回 error 字段与零分结果,保证上游 UI 不至于崩溃。

评判者模型说明

app.py 的评估结果区域标题注明 "Evaluation results generated with GPT-4o using Opik"(见 app.py),GEval 实例在仓库源码中未显式指定底层 LLM 参数,而是交由 Opik 客户端的环境配置决定评估所用模型——这与 README/.env 要求同时配置 OPENAI_API_KEY、以及 .opik.config 中设置 Opik 凭据的约束相呼应。换言之:OPENROUTER_API_KEY 服务"代码生成",Opik 侧配置的 LLM 服务"代码评判"

结果可视化:一眼看出差距

评估完成后,app.py 负责渲染结果,主要分三层:

  1. 数据组装:把两个模型在 Correctness / Readability / Best Practices / Overall 四项上的得分整理成 Pandas DataFrame;
  2. 分组条形图:用 Plotly Express 的 px.bar(barmode="group") 绘制深色主题对比图,双模型不同配色,直观呈现各维度分差;
  3. 明细表:分别列出每个模型的三个维度得分 + 得分理由(reason),其中 reason 是 G-Eval 裁判给出的"判分依据"文本,可追溯为什么得这个分。

渲染前还会对评估结果的嵌套结构做严格校验(是否含 overall_score、三个指标各自的 score 字段),结构不合法时明确报错而不渲染空图,避免静默失败。

工程细节与踩坑提示

综合 README 与源码,运行与扩展时还有几点经验:

  • 模型换选即重置selected_models 变化时会清空 last_generated_codeevaluation_results,保证对比结果与当前选中的模型始终一致(app.py);
  • 必须先摄取再提问:聊天入口会校验 st.session_state.context,未摄入仓库时给出 "Please ingest a GitHub repository first!" 拦截(app.py);
  • 长代码防溢出:页面级 CSS 对 <pre>/<code> 设置了 white-space: pre-wrap 与自动换行,避免超宽代码块破坏双栏布局(app.py);
  • 双栏流式刷新:使用 st.empty() 占位容器 + 边收边刷,是 Streamlit 下实现"类打字机流式输出"的常用套路;
  • 扩展新评估维度:参照 code_evaluation_opik.py 的写法新增一个 GEval 实例,再在 detailed_metrics 与 UI 组装处同步补充即可。

小结

code-model-comparison 展示了"代码生成模型评测闭环"的完整工程化样板:用 Gitingest 让模型读懂目标仓库、用 LiteLLM + OpenRouter 统一网关实现多模型对拍、用 Opik G-Eval 以 LLM-as-a-Judge 的方式对正确性/可读性/最佳实践三维度 0-10 打分,并用 Streamlit + Plotly 落地为可交互的双栏对比界面。无论你是要做"Claude vs Qwen vs Gemini"式的模型选型实验,还是想为团队沉淀一套可复用的代码质量评估管线,这个应用的结构都值得直接参考。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391