model-compare

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Model Compare — Blind Side-by-Side Multi-Model Testing

Model Compare — 盲态多模型并行测试

Send one prompt to multiple models simultaneously, present responses anonymously, let the user pick a winner, then reveal which model is which.
Inspired by the Compare feature in PewDiePie's Odysseus project, adapted for Hermes's multi-provider architecture (OpenRouter, NVIDIA, Ollama Cloud, any OpenAI-compatible endpoint).
将同一个提示词同时发送给多个模型,匿名展示响应结果,让用户选出最优结果后,再揭晓对应模型的身份。
灵感来自PewDiePie的Odysseus项目中的对比功能,适配了Hermes的多提供商架构(OpenRouter、NVIDIA、Ollama Cloud以及任何兼容OpenAI的端点)。

When to use

适用场景

  • "Compare these models on..."
  • "Which model is better for [task]?"
  • "A/B test [model1] vs [model2]"
  • "Blind comparison of..."
  • "Test how different models handle this prompt"
  • User wants to evaluate models before committing to one for a workflow
  • Prompt engineering — seeing how different models interpret instructions
  • "Compare these models on..."
  • "Which model is better for [task]?"
  • "A/B test [model1] vs [model2]"
  • "Blind comparison of..."
  • "Test how different models handle this prompt"
  • 用户希望在将模型用于工作流之前先评估模型
  • 提示词工程——查看不同模型对指令的解读方式

When NOT to use

不适用场景

  • Benchmarking (MMLU, GSM8K, etc.) → use
    evaluating-llms-harness
    skill
  • Cost analysis → just check provider pricing pages
  • Single model test → just switch model and ask directly
  • Multi-source research synthesis → use
    deep-research
    skill (iterative research loop, not model comparison)
  • 基准测试(如MMLU、GSM8K等)→ 使用
    evaluating-llms-harness
    技能
  • 成本分析→ 直接查看提供商定价页面即可
  • 单模型测试→ 直接切换模型提问即可
  • 多源研究合成→ 使用
    deep-research
    技能(迭代研究循环,而非模型对比)

Architecture

架构

Four comparison modes, all driven by
scripts/compare.py
:
ModeFlagWhat it doesAPI feature
simple
--mode simple
(default)
One prompt → one responseBasic chat completion
tools
--mode tools
Multi-turn tool calling with real web_search/web_extract + sandboxed run_python/read_file/write_file. 10-turn max (configurable per-test via
max_turns
in TEST_BANK). Tracks full trace.
tools
array in request, multi-turn messages
coding
--mode coding
Test bank coding prompts (LRU cache, concurrent fetch, debug merge sort, retry decorator)Basic chat completion
review
--mode review
Code review prompts with planted bugs (SQL injection, clean code, race condition, float-for-money)Basic chat completion
User prompt + model list
  → Step 1: Resolve models to provider endpoints (free providers first)
  → Step 2: Send prompt to all models in parallel
     ├─ simple/coding/review: one-shot chat completion
     └─ tools: multi-turn loop (Think→Search→Extract→Execute→Synthesize→Stop, max 10 turns by default, per-test configurable)
  → Step 3: Quality check responses (handle errors/empty)
  → Step 4: Present anonymously (shuffle + label A/B/C/D)
  → Step 5: Efficiency table (tokens in/out, turns, tool calls — auto for tools mode)
  → Step 6: User votes OR judge model evaluates
  → Step 7: Reveal identities + show mapping
  → Step 8 (optional): Save to JSON file
四种对比模式,均由
scripts/compare.py
驱动:
模式标识功能API特性
simple
--mode simple
(默认)
一个提示词→一个响应基础对话补全
tools
--mode tools
多轮工具调用,支持真实web_search/web_extract + 沙箱化run_python/read_file/write_file。最多10轮(可通过TEST_BANK中的
max_turns
按测试配置)。追踪完整调用轨迹。
请求中的
tools
数组,多轮消息
coding
--mode coding
使用测试库中的编码提示词(LRU缓存、并发请求、归并排序调试、重试装饰器)基础对话补全
review
--mode review
包含预设问题的代码评审提示词(SQL注入、代码整洁性、竞态条件、浮点数处理金额)基础对话补全
用户提示词 + 模型列表
  → 步骤1:将模型解析为提供商端点(优先免费提供商)
  → 步骤2:并行向所有模型发送提示词
     ├─ simple/coding/review:单次对话补全
     └─ tools:多轮循环(思考→搜索→提取→执行→合成→停止,默认最多10轮,可按测试配置)
  → 步骤3:响应质量检查(处理错误/空响应)
  → 步骤4:匿名展示(打乱顺序 + 标记为A/B/C/D)
  → 步骤5:效率表格(输入/输出token数、轮次、工具调用数——tools模式自动生成)
  → 步骤6:用户投票 或 评审模型评估
  → 步骤7:揭晓模型身份 + 展示对应关系
  → 步骤8(可选):保存到JSON文件

Script:
scripts/compare.py

脚本:
scripts/compare.py

The primary interface — a standalone CLI tool (no pip dependencies, pure stdlib + urllib). See
references/provider-tool-support.md
for which models support tool calling. For empirical model behavior findings from 16 head-to-head tests (GLM 5.2, MiniMax M3, HY3, Laguna), see
references/model-behavior.md
. (Running the test suite under
tests/
needs
pytest
— see
requirements-dev.txt
; the skill itself needs nothing installed.)
Tool-mode environment dependency:
--mode tools
runs real
web_search
. That needs either
SEARXNG_URL
set to a SearXNG instance or the
ddgs
CLI available on
PATH
(the fallback). Neither is a Python import dependency, but one of them must be present for live search; without both,
web_search
returns an error result. The other three modes (
simple
,
coding
,
review
) need neither.
bash
undefined
核心交互接口——独立CLI工具(无pip依赖,纯标准库 + urllib)。查看
references/provider-tool-support.md
了解哪些模型支持工具调用。关于16组一对一测试(GLM 5.2、MiniMax M3、HY3、Laguna)得出的模型行为实证结果,请查看
references/model-behavior.md
。(运行
tests/
下的测试套件需要
pytest
——详见
requirements-dev.txt
;该技能本身无需安装任何依赖。)
工具模式环境依赖:
--mode tools
会运行真实的
web_search
。需要要么设置
SEARXNG_URL
指向SearXNG实例,要么在
PATH
中可用
ddgs
CLI(作为备选方案)。两者都不是Python导入依赖,但必须存在其中一个才能实现实时搜索;如果两者都没有,
web_search
会返回错误结果。其他三种模式(
simple
、
coding
、
review
)无需这两者。
bash
undefined

Simple 2-model blind comparison

简单双模型盲态对比

python3 scripts/compare.py --prompt "Explain X" --models "ollama-cloud:glm-5.2" "ollama-cloud:kimi-k2.5"
python3 scripts/compare.py --prompt "Explain X" --models "ollama-cloud:glm-5.2" "ollama-cloud:kimi-k2.5"

Reasoning-effort A/B: SAME model, two effort levels (native syntax)

推理强度A/B测试:同一模型,两种强度级别(原生语法)

Registers a virtual provider per arm; judge can also take an effort suffix.

为每个分支注册虚拟提供商;评审模型也可添加强度后缀。

python3 scripts/compare.py --mode review --test H7
--models "ollama-cloud:@medium:glm-5.3-flash" "ollama-cloud:@high:glm-5.3-flash"
--judge "ollama-cloud:@medium:glm-5.3" --reveal
python3 scripts/compare.py --mode review --test H7
--models "ollama-cloud:@medium:glm-5.3-flash" "ollama-cloud:@high:glm-5.3-flash"
--judge "ollama-cloud:@medium:glm-5.3" --reveal

Tool calling with test bank prompt A + judge + reveal

使用测试库提示词A进行工具调用 + 评审模型 + 揭晓结果

python3 scripts/compare.py --mode tools --test A --models "ollama-cloud:glm-5.2" "ollama-cloud:kimi-k2.5" --judge "ollama-cloud:glm-5.2" --reveal
python3 scripts/compare.py --mode tools --test A --models "ollama-cloud:glm-5.2" "ollama-cloud:kimi-k2.5" --judge "ollama-cloud:glm-5.2" --reveal

Coding test J with efficiency table

带效率表格的编码测试J

python3 scripts/compare.py --mode coding --test J --models "ollama-cloud:glm-5.2" "ollama-cloud:qwen3-coder:480b" --efficiency
python3 scripts/compare.py --mode coding --test J --models "ollama-cloud:glm-5.2" "ollama-cloud:qwen3-coder:480b" --efficiency

Code review test O with judge

带评审模型的代码评审测试O

python3 scripts/compare.py --mode review --test O --models "ollama-cloud:glm-5.2" "ollama-cloud:kimi-k2.5" --judge "ollama-cloud:glm-5.2"
python3 scripts/compare.py --mode review --test O --models "ollama-cloud:glm-5.2" "ollama-cloud:kimi-k2.5" --judge "ollama-cloud:glm-5.2"

List available tests

列出可用测试

python3 scripts/compare.py --list-tests
python3 scripts/compare.py --list-tests

List providers

列出提供商

python3 scripts/compare.py --list-providers

Key flags: `--prompt`, `--models`, `--mode`, `--test` (test bank ID), `--judge`, `--efficiency`, `--reveal`, `--output`, `--timeout`, `--list-providers`, `--list-models`.
python3 scripts/compare.py --list-providers

关键标识:`--prompt`、`--models`、`--mode`、`--test`(测试库ID)、`--judge`、`--efficiency`、`--reveal`、`--output`、`--timeout`、`--list-providers`、`--list-models`。

Reasoning-effort A/B (
:@effort
suffix, added 2026-08-29)

推理强度A/B测试(
:@effort
后缀,2026-08-29新增)

Model specs and
--judge
accept an optional effort marker
provider:@effort:model_id
, e.g.
ollama-cloud:@medium:glm-5.3-flash
. Each unique (provider, effort) pair registers a virtual provider (
ollama-cloud@medium
) that clones the base provider's config — same endpoint, same env key, inherited
max_tokens
— and injects
reasoning_effort
into the payload. This enables comparing the SAME model at two reasoning levels in one blind run; the reveal labels the arms
provider@effort
. Findings from the 2026-08-29 glm-5.3-flash A/B (Codex-judged, 8 tests): effort→thinking-token count is non-monotonic; high was ~3x faster median but non-converged on a 12-turn tool-chain test that medium completed; medium won on judged quality overall (8.6 vs 7.8 avg). See
~/.hermes/data/glm53flash_effort_ab/ab_results.jsonl
for full traces.
--max-turns
CLI override (added 2026-07-17):
Pass
--max-turns N
to override the test bank's
max_turns
field at runtime without editing source. If not passed, the test bank default is used. This was added because killing a background run to patch
TEST_BANK["A"]["max_turns"]
in source code is fragile and disrupts parallel execution.
模型规格和
--judge
支持可选的强度标记
provider:@effort:model_id
,例如
ollama-cloud:@medium:glm-5.3-flash
。每个唯一的(提供商,强度)对会注册一个虚拟提供商(
ollama-cloud@medium
),克隆基础提供商的配置——相同端点、相同环境密钥、继承
max_tokens
——并将
reasoning_effort
注入请求体。这使得在一次盲态测试中可以对比同一模型的两种推理级别;揭晓时会将分支标记为
provider@effort
。2026-08-29针对glm-5.3-flash的A/B测试结果(由Codex评审,8组测试):强度→思考token数并非单调递增;高强度版本中位速度快约3倍,但在一个12轮工具链测试中未收敛,而中强度版本完成了测试;中强度版本在评审质量上整体获胜(平均得分8.6 vs 7.8)。完整轨迹请查看
~/.hermes/data/glm53flash_effort_ab/ab_results.jsonl
。
**
--max-turns
CLI覆盖(2026-07-17新增):**传递
--max-turns N
可在运行时覆盖测试库中的
max_turns
字段,无需修改源代码。如果未传递该参数,则使用测试库默认值。新增此功能是因为终止后台运行以修改源代码中
TEST_BANK["A"]["max_turns"]
的方式不够稳定,且会中断并行执行。

Available Providers

可用提供商

Three providers are wired in (the canonical config is
PROVIDERS
in
scripts/compare.py
):
ProviderEnv VarCostModel familiesEndpoint
Ollama Cloud
OLLAMA_API_KEY
FreeGLM, Qwen, Kimi, Gemini, Gemma
https://ollama.com/v1/chat/completions
NVIDIA
NVIDIA_API_KEY
FreeYi, Llama, Nemotron, …
https://integrate.api.nvidia.com/v1/chat/completions
OpenRouter
OPENROUTER_API_KEY
Paid (per-token)Claude, GPT, Gemini, DeepSeek, Llama, Qwen, Mistral
https://openrouter.ai/api/v1/chat/completions
Model inventories live elsewhere, on purpose. Exact model counts and IDs drift constantly, so they are deliberately kept out of this doc. For the live list run
python3 scripts/compare.py --list-models <provider>
(needs that provider's key);
references/providers.json
holds a curated, count-free snapshot with representative model IDs per provider.
已接入三个提供商(标准配置为
scripts/compare.py
中的
PROVIDERS
):
提供商环境变量成本模型系列端点
Ollama Cloud
OLLAMA_API_KEY
免费GLM、Qwen、Kimi、Gemini、Gemma
https://ollama.com/v1/chat/completions
NVIDIA
NVIDIA_API_KEY
免费Yi、Llama、Nemotron等
https://integrate.api.nvidia.com/v1/chat/completions
OpenRouter
OPENROUTER_API_KEY
付费(按token计费)Claude、GPT、Gemini、DeepSeek、Llama、Qwen、Mistral
https://openrouter.ai/api/v1/chat/completions
**模型清单存放在别处,这是有意为之。**具体模型数量和ID会不断变化,因此特意不包含在本文档中。要查看实时列表,请运行
python3 scripts/compare.py --list-models <provider>
(需要对应提供商的密钥);
references/providers.json
包含每个提供商的精选代表性模型ID快照,不含具体数量。

Cost-aware provider routing (mandatory)

成本感知型提供商路由(强制规则)

When the user does not specify a provider, route to free providers first:
  1. Ollama Cloud — free (GLM, Qwen, Kimi, Gemini, Gemma)
  2. NVIDIA — free (Yi, Llama, Nemotron)
  3. OpenRouter — paid (per-token cost). Only use when:
    • The user explicitly requests an OpenRouter-only model (e.g. Claude, GPT-4o)
    • The user explicitly says to use OpenRouter
    • The free providers don't have a suitable model for the task
Before any OpenRouter call, confirm with the user:
"This comparison will use OpenRouter which has per-token costs. Estimated cost: ~$0.01–0.05 per model per call (varies by model). Proceed?"
Only proceed after explicit confirmation. When in doubt, default to free providers.
To call a model, POST to the provider's
/v1/chat/completions
endpoint with:
json
{
  "model": "<model_id>",
  "messages": [{"role": "user", "content": "<prompt>"}],
  "max_tokens": 8192,
  "temperature": 0.7
}
Header:
Authorization: Bearer <API_KEY>
max_tokens is set to 8192 in both
call_model_simple
and
call_model_with_tools
. The previous default of 4096 caused truncated code output on coding test J (LRU cache) — the model generated so much code it hit the 4096 limit before finishing the decorator section. If a model still truncates, increase the value in the payload dict.
当用户未指定提供商时,优先路由到免费提供商:
  1. Ollama Cloud — 免费(GLM、Qwen、Kimi、Gemini、Gemma)
  2. NVIDIA — 免费(Yi、Llama、Nemotron)
  3. OpenRouter — 付费(按token计费)。仅在以下情况使用:
    • 用户明确请求仅OpenRouter提供的模型(如Claude、GPT-4o)
    • 用户明确要求使用OpenRouter
    • 免费提供商没有适合该任务的模型
在调用任何OpenRouter模型之前,需与用户确认:
"本次对比将使用OpenRouter,该服务按token计费。预估成本:每个模型每次调用约0.01–0.05美元(因模型而异)。是否继续?"
仅在用户明确确认后才继续执行。如有疑问,默认使用免费提供商。
调用模型时,向提供商的
/v1/chat/completions
端点发送POST请求,请求体如下:
json
{
  "model": "<model_id>",
  "messages": [{"role": "user", "content": "<prompt>"}],
  "max_tokens": 8192,
  "temperature": 0.7
}
请求头:
Authorization: Bearer <API_KEY>
max_tokens在
call_model_simple
和
call_model_with_tools
中均设置为8192。之前的默认值4096会导致编码测试J(LRU缓存)的代码输出被截断——模型生成的代码量太大,在完成装饰器部分之前就达到了4096的限制。如果模型仍出现截断情况,请增加请求体中的该值。

Step 1 — Resolve Models

步骤1 — 解析模型

Determine which models to compare. The user may specify:
  • Explicit model names: "compare claude-sonnet-4.6 vs gpt-4o vs gemini-2.5-flash"
  • Provider + model: "compare OpenRouter claude-sonnet-4.6 vs Ollama glm-5.2"
  • Task-based: "which model is best for coding?" → suggest 2-4 candidates
  • All from a provider: "test 3 OpenRouter models" → pick diverse ones
确定要对比的模型。用户可能会指定:
  • 明确的模型名称:"compare claude-sonnet-4.6 vs gpt-4o vs gemini-2.5-flash"
  • 提供商+模型:"compare OpenRouter claude-sonnet-4.6 vs Ollama glm-5.2"
  • 基于任务:"which model is best for coding?" → 推荐2-4个候选模型
  • 同一提供商的多个模型:"test 3 OpenRouter models" → 选择多样化的模型

Model resolution

模型解析规则

Map the user's model names to a
provider:model_id
spec. Free providers (Ollama Cloud, NVIDIA) are preferred. OpenRouter is only used for models not on a free provider (e.g. Claude, GPT) or when the user explicitly asks for it.
The rules, not a hardcoded catalogue (which would rot):
  • Free, leave the prefix off or name an Ollama/NVIDIA model → resolve on a free provider, e.g.
    ollama-cloud:glm-5.2
    ,
    ollama-cloud:qwen3-coder:480b
    ,
    nvidia:meta/llama-3.3-70b-instruct
    .
  • A proprietary model (Claude, GPT, Gemini-Pro, DeepSeek-R1, …) → only OpenRouter carries it, e.g.
    openrouter:anthropic/claude-sonnet-4.6
    ,
    openrouter:openai/gpt-4o
    — paid, confirm first (see routing rule above).
  • Unsure of the exact ID? Run
    python3 scripts/compare.py --list-models <provider>
    for the live list, or see
    references/providers.json
    for a curated set of representative IDs per provider. Don't hand-maintain a model table here.
When user doesn't specify models:
  1. Check if the task type maps to free models (e.g. coding → qwen3-coder, glm-5.2; general → glm-5.2, kimi-k2.5)
  2. Suggest 2-4 free models from Ollama Cloud and NVIDIA
  3. Only suggest OpenRouter models if the user asks for premium models (Claude, GPT-4o) or the free providers lack suitable options
  4. If suggesting any paid models, flag the cost before running
If unsure which provider has a model, check with:
bash
curl -s https://openrouter.ai/api/v1/models -H "Authorization: Bearer $OPENROUTER_API_KEY" | python3 -c "import sys,json; [print(m['id']) for m in json.load(sys.stdin)['data'] if 'KEYWORD' in m['id'].lower()]"
Rules:
  • 2-4 models per comparison (more = unwieldy in chat)
  • If user doesn't specify, suggest a diverse set (different providers/sizes)
  • Always confirm the model list with the user before running
将用户指定的模型名称映射为
provider:model_id
格式。优先选择免费提供商(Ollama Cloud、NVIDIA)。仅当模型未在免费提供商提供(如Claude、GPT)或用户明确要求时,才使用OpenRouter。
以下是规则(而非硬编码目录,避免过时):
  • 免费模型,省略前缀或指定Ollama/NVIDIA模型 → 在免费提供商上解析,例如
    ollama-cloud:glm-5.2
    、
    ollama-cloud:qwen3-coder:480b
    、
    nvidia:meta/llama-3.3-70b-instruct
    。
  • 专有模型(Claude、GPT、Gemini-Pro、DeepSeek-R1等) → 仅OpenRouter提供,例如
    openrouter:anthropic/claude-sonnet-4.6
    、
    openrouter:openai/gpt-4o
    — 付费服务,需先确认(见上述路由规则)。
  • **不确定确切ID?**运行
    python3 scripts/compare.py --list-models <provider>
    查看实时列表,或查看
    references/providers.json
    获取每个提供商的精选代表性ID。请勿在此手动维护模型表。
当用户未指定模型时:
  1. 检查任务类型是否对应免费模型(例如编码→qwen3-coder、glm-5.2;通用任务→glm-5.2、kimi-k2.5)
  2. 从Ollama Cloud和NVIDIA推荐2-4个免费模型
  3. 仅当用户要求使用高级模型(Claude、GPT-4o)或免费提供商没有合适选项时,才推荐OpenRouter模型
  4. 如果推荐任何付费模型,需在运行前告知成本
如果不确定哪个提供商有对应模型,可通过以下命令检查:
bash
curl -s https://openrouter.ai/api/v1/models -H "Authorization: Bearer $OPENROUTER_API_KEY" | python3 -c "import sys,json; [print(m['id']) for m in json.load(sys.stdin)['data'] if 'KEYWORD' in m['id'].lower()]"
规则:
  • 每次对比2-4个模型(数量过多会导致对话界面难以操作)
  • 如果用户未指定,推荐多样化的模型组合(不同提供商/尺寸)
  • 在运行前始终与用户确认模型列表

Step 2 — Send Prompt to All Models

步骤2 — 向所有模型发送提示词

Send the prompt to all models in parallel. The script handles this automatically via
concurrent.futures.ThreadPoolExecutor
— no need for delegate_task or manual parallelism.
并行向所有模型发送提示词。脚本通过
concurrent.futures.ThreadPoolExecutor
自动处理此操作——无需手动并行或委托任务。

Simple / coding / review modes

Simple / coding / review模式

One-shot chat completion per model. All calls fired concurrently by the script.
每个模型执行单次对话补全。所有调用由脚本并发触发。

Tool calling mode

工具调用模式

Multi-turn loop per model (also concurrent across models):
Turn 1: Send prompt + tool definitions → Model returns tool_call(s)
Turn 2: Execute real tool → inject result → Model returns tool_call(s) or answer
Turn 3: ... until final answer or max turns (10 by default, configurable per-test via `max_turns` field in TEST_BANK)
Real tool execution — the script executes
web_search
and
web_extract
for real:
  • web_search
    → SearXNG (self-hosted, via
    SEARXNG_URL
    ) with DDGS fallback
  • web_extract
    → direct HTTP fetch with HTML-to-text conversion (3000 chars/page)
No mock tools, no fake results. Models must formulate good queries, pick the right URLs, and synthesize from real content. A model that generates a bad search query gets bad results and must recover.
Tool definitions passed via the OpenAI
tools
parameter:
  • web_search(query, limit)
    — returns titles, URLs, snippets
  • web_extract(urls)
    — returns page content as text
No terminal tool — we don't have a sandbox. Terminal is not exposed to comparison models for safety reasons.
每个模型执行多轮循环(模型间也并行执行):
第1轮:发送提示词 + 工具定义 → 模型返回tool_call(s)
第2轮:执行真实工具 → 注入结果 → 模型返回tool_call(s)或最终答案
第3轮:... 直到返回最终答案或达到最大轮次(默认10轮,可通过TEST_BANK中的`max_turns`字段按测试配置)
真实工具执行——脚本真实执行
web_search
和
web_extract
:
  • web_search
    → SearXNG(自托管,通过
    SEARXNG_URL
    ),备选方案为DDGS
  • web_extract
    → 直接HTTP请求,将HTML转换为文本(每页最多3000字符)
无模拟工具,无虚假结果。模型必须制定合理的查询、选择正确的URL,并从真实内容中合成结果。如果模型生成错误的搜索查询,会得到错误结果,必须自行恢复。
工具定义通过OpenAI的
tools
参数传递:
  • web_search(query, limit)
    — 返回标题、URL、摘要
  • web_extract(urls)
    — 返回页面文本内容
无终端工具——出于安全考虑,未向对比模型暴露终端功能。

Step 3 — Quality Check

步骤3 — 质量检查

For each response:
  • Empty/error: if a model returns an error or empty response, note it and exclude from the comparison. Tell the user which model failed.
  • Truncated: if response hit max_tokens, note it was truncated
  • Refusal: if a model refused to answer, include it as-is (refusals are valid comparison data)
对每个响应执行以下检查:
  • 空响应/错误:如果模型返回错误或空响应,记录并排除在对比之外。告知用户哪个模型失败。
  • 截断:如果响应达到max_tokens限制,记录响应被截断
  • 拒绝回答:如果模型拒绝回答,原样保留(拒绝回答属于有效的对比数据)

Step 4 — Present Anonymously

步骤4 — 匿名展示

Shuffle the responses and assign neutral labels. Do NOT reveal which model is which.
Shuffle rule: Use a random permutation. Do not always put the same model first. If the user is comparing 3 models, randomly assign A/B/C.
Present as:
🧪 Blind Model Comparison
Prompt: "[truncated to 100 chars...]"

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

📦 Model A:
[full response]

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

📦 Model B:
[full response]

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

📦 Model C:
[full response]

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Vote: Reply with the letter of the best response (A, B, or C), or "tie".
Formatting rules:
  • Full responses, not summaries — the user needs to judge quality
  • Clear visual separation between responses
  • Truncate at ~3000 chars per response for chat readability (note if truncated)
  • If responses are very long (>3000 chars), save full versions to files and present truncated versions in chat with a note
打乱响应顺序并分配中性标签。切勿提前揭晓模型身份。
**打乱规则:**使用随机排列。不要始终将同一模型放在第一位。如果用户对比3个模型,随机分配A/B/C标签。
展示格式如下:
🧪 盲态模型对比
提示词:"[截断至100字符...]"

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

📦 模型A:
[完整响应]

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

📦 模型B:
[完整响应]

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

📦 模型C:
[完整响应]

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

投票:回复最优响应对应的字母(A、B或C),或"tie"(平局)。
格式规则:
  • 展示完整响应,而非摘要——用户需要完整内容来判断质量
  • 响应之间有清晰的视觉分隔
  • 为保证聊天可读性,每个响应最多显示约3000字符(如果截断需注明)
  • 如果响应非常长(超过3000字符),将完整版本保存到文件,在聊天中展示截断版本并注明

Step 5 — User Votes

步骤5 — 用户投票

Wait for the user to vote. Accept:
  • Letter: "A", "B", "C", "D"
  • "tie" or "tie between A and B"
  • "all bad" (valid — none won)
  • Specific feedback: "A is better but B's code is cleaner"
等待用户投票。接受以下形式的投票:
  • 字母:"A"、"B"、"C"、"D"
  • "tie"或"tie between A and B"
  • "all bad"(有效——无获胜模型)
  • 具体反馈:"A更好但B的代码更整洁"

Step 6 — Reveal Identities

步骤6 — 揭晓模型身份

After the vote, reveal the mapping:
🎭 Reveal:

Model A → <actual_model_name> (<provider>)
Model B → <actual_model_name> (<provider>)
Model C → <actual_model_name> (<provider>)

🏆 Your winner: Model <letter> = <actual_model_name>
投票结束后,揭晓标签与模型的对应关系:
🎭 揭晓结果:

模型A → <实际模型名称> (<提供商>)
模型B → <实际模型名称> (<提供商>)
模型C → <实际模型名称> (<提供商>)

🏆 您选出的获胜者:模型<字母> = <实际模型名称>

Step 7 — Synthesis (optional)

步骤7 — 结果合成(可选)

If the user wants the best possible answer, synthesize across all responses:
"Want me to synthesize the best parts of all responses into one?"
If yes, take the strongest elements from each response and produce a unified answer. Note which model contributed each part:
undefined
如果用户想要最优的综合答案,可将所有响应的内容进行合成:
"需要我将所有响应的精华内容合成为一个答案吗?"
如果用户同意,提取每个响应的核心内容生成统一答案,并注明每个部分来自哪个模型:
undefined

Synthesized Answer

合成答案

[merged response]
[合并后的响应]

Contributions

内容来源

  • Section X: primarily from <model_name>
  • Section Y: primarily from <model_name>
undefined
  • 章节X:主要来自<模型名称>
  • 章节Y:主要来自<模型名称>
undefined

Step 8 — Vote History (optional)

步骤8 — 投票历史记录(可选)

For recurring comparisons, log results to a file:
~/.hermes/data/model_compare_history.jsonl
Format:
json
{"timestamp": "2026-06-27T12:00:00", "prompt": "...", "models": ["model_a", "model_b"], "winner": "model_a", "is_blind": true, "feedback": "..."}
This builds up a picture of which models win for which task types over time.
对于重复进行的对比,可将结果记录到文件:
~/.hermes/data/model_compare_history.jsonl
记录格式:
json
{"timestamp": "2026-06-27T12:00:00", "prompt": "...", "models": ["model_a", "model_b"], "winner": "model_a", "is_blind": true, "feedback": "..."}
通过长期记录,可以了解不同模型在各类任务中的获胜情况。

Test Bank (24 tests)

测试库(24组测试)

Use
--test <ID>
to run a pre-built test prompt. The mode is auto-set based on the test domain.
IDDomainPrompt summaryTools?
Atool_callingLatest Python version + top 2 features🔧
Btool_callingFind Odysseus GitHub repo star count🔧
Ctool_callingBest reverse proxy for homelab, then find key feature🔧
Etool_callingSearch LRU cache implementations, then write a better one🔧
H1tool_callingPython 3.14 free-threaded status — find 3 sources, identify authoritative🔧
H2tool_callingNode.js stable version + EOL date, verify against official source🔧
S1tool_callingWrite IPv4 validator, run with test cases, report pass/fail🔧 📦
S2tool_callingWrite CSV to file, analyze averages, run script, report results🔧 📦
S3tool_callingGenerate Fibonacci, save as JSON, read back and verify🔧 📦
S4tool_callingReverse a linked list, run test, verify output, debug if wrong🔧 📦
S5tool_callingCaesar cipher encrypt/decrypt, run and verify round-trip🔧 📦
JcodingImplement LRU cache, O(1), type hints + docstring
KcodingConcurrent URL fetch with per-URL timeout, preserve order
LcodingFix buggy merge sort (off-by-one in merge step)
McodingRetry decorator, 3x, 1s delay, preserve metadata
H3codingThread-safe cache with TTL + LRU eviction
H4codingToken bucket rate limiter, thread-safe, injectable clock
Ocode_reviewSQL injection + unreliable rowcount loop
Pcode_reviewClean code (no bugs) — test false positive rate
Qcode_reviewThread-unsafe cache in production service
Rcode_reviewFloat for money + missing transfer validation
H5code_reviewAsyncio connection pool — inflight leak, missing lock, no timeout
H6code_reviewAuth service — MD5, timing-unsafe, forgeable token, no expiry check
H7code_reviewLogging service — fetchone() called twice per loop iteration
🔧 = uses web_search/web_extract tools. 📦 = uses sandbox tools (run_python/read_file/write_file).
Each test includes evaluation criteria used by the judge. Tool-calling tests also include a
max_turns
field (default 10) that controls the turn cap for that specific test — edit the TEST_BANK entry in
scripts/compare.py
to change it for an individual test. Code review tests include planted issues for objective scoring.
使用
--test <ID>
运行预构建的测试提示词。模式会根据测试领域自动设置。
ID领域提示词摘要是否使用工具?
Atool_calling最新Python版本 + 两大核心特性🔧
Btool_calling查询Odysseus GitHub仓库的星标数量🔧
Ctool_calling适合家庭实验室的最佳反向代理,然后查找其关键特性🔧
Etool_calling搜索LRU缓存实现,然后编写更优版本🔧
H1tool_callingPython 3.14自由线程状态——查找3个来源,确定权威信息🔧
H2tool_callingNode.js稳定版本 + EOL日期,通过官方来源验证🔧
S1tool_calling编写IPv4验证器,运行测试用例,报告通过/失败情况🔧 📦
S2tool_calling将数据写入CSV文件,分析平均值,运行脚本,报告结果🔧 📦
S3tool_calling生成斐波那契数列,保存为JSON,读取并验证🔧 📦
S4tool_calling反转链表,运行测试,验证输出,如有错误进行调试🔧 📦
S5tool_calling凯撒密码加密/解密,运行并验证往返结果🔧 📦
Jcoding实现LRU缓存,O(1)时间复杂度,包含类型提示 + 文档字符串
Kcoding带单URL超时的并发URL请求,保留顺序
Lcoding修复有bug的归并排序(合并步骤中的偏移错误)
Mcoding重试装饰器,最多3次,1秒延迟,保留元数据
H3coding带TTL + LRU淘汰的线程安全缓存
H4coding线程安全的令牌桶限流器,支持可注入时钟
Ocode_reviewSQL注入 + 不可靠的行计数循环
Pcode_review整洁代码(无bug)——测试误报率
Qcode_review生产服务中的线程不安全缓存
Rcode_review浮点数处理金额 + 缺少转账验证
H5code_reviewAsyncio连接池—— inflight泄漏、缺少锁、无超时
H6code_review认证服务——MD5、时序不安全、可伪造令牌、无过期检查
H7code_review日志服务——循环中重复调用fetchone()
🔧 = 使用web_search/web_extract工具。📦 = 使用沙箱工具(run_python/read_file/write_file)。
每组测试包含评审模型使用的评估标准。工具调用测试还包含
max_turns
字段(默认10),控制该测试的最大轮次——可修改
scripts/compare.py
中的TEST_BANK条目来调整单个测试的该值。代码评审测试包含预设问题,用于客观评分。

Tool Calling Mode — How It Works

工具调用模式——工作原理

The
--mode tools
flag enables multi-turn tool calling with real tools (not mocks):
  1. Script defines 5 tools as OpenAI function tools:
    web_search
    ,
    web_extract
    ,
    run_python
    ,
    read_file
    ,
    write_file
  2. Sends prompt + tool defs to each model in parallel
  3. When a model returns
    tool_calls
    , the script executes the real call:
    • web_search
      → SearXNG (self-hosted, via
      SEARXNG_URL
      ) with DDGS fallback
    • web_extract
      → direct HTTP fetch, HTML stripped to text, truncated to 3000 chars/page
    • run_python
      → executes Python code in a per-model sandbox (temp dir, 10s timeout, no network)
    • read_file
      → reads a file from the sandbox directory (path traversal blocked)
    • write_file
      → writes a file to the sandbox directory (path traversal blocked)
  4. Feeds the real result back as a
    tool
    role message
  5. Repeats until final answer or max turns (10 default, configurable per-test via
    max_turns
    in TEST_BANK)
  6. Tracks all turns, tool calls, tokens per turn, convergence status
Sandbox security: Each model gets its own temp directory (
tempfile.mkdtemp
). Path traversal (
../
) and absolute paths are rejected. Python execution has a 10-second timeout. No network access from within the sandbox subprocess. Sandbox is cleaned up after each model's run (in a
finally
block).
Tools exposed:
web_search
,
web_extract
,
run_python
,
read_file
,
write_file
. See
references/provider-tool-support.md
for which models support tool calling.
Judge sees the full tool call trace — what was searched, what was extracted, what code was run and its output, how many turns, whether it converged. This lets the judge evaluate tool selection strategy, not just the final answer.
--mode tools
标识启用多轮工具调用,使用真实工具(而非模拟工具):
  1. 脚本将5个工具定义为OpenAI函数工具:
    web_search
    、
    web_extract
    、
    run_python
    、
    read_file
    、
    write_file
  2. 并行向每个模型发送提示词 + 工具定义
  3. 当模型返回
    tool_calls
    时,脚本执行真实调用:
    • web_search
      → SearXNG(自托管,通过
      SEARXNG_URL
      ),备选方案为DDGS
    • web_extract
      → 直接HTTP请求,剥离HTML转为文本,每页最多3000字符
    • run_python
      → 在每个模型专属的沙箱(临时目录,10秒超时,无网络)中执行Python代码
    • read_file
      → 读取沙箱目录中的文件(阻止路径遍历)
    • write_file
      → 写入文件到沙箱目录(阻止路径遍历)
  4. 将真实结果作为
    tool
    角色消息反馈给模型
  5. 重复执行直到模型返回最终答案或达到最大轮次(默认10轮,可通过TEST_BANK中的
    max_turns
    按测试配置)
  6. 追踪所有轮次、工具调用、每轮token数、收敛状态
**沙箱安全:**每个模型拥有独立的临时目录(
tempfile.mkdtemp
)。拒绝路径遍历(
../
)和绝对路径。Python执行有10秒超时。沙箱子进程无网络访问权限。每个模型运行结束后,沙箱会被清理(在
finally
块中执行)。
暴露的工具:
web_search
、
web_extract
、
run_python
、
read_file
、
write_file
。查看
references/provider-tool-support.md
了解哪些模型支持工具调用。
评审模型可查看完整工具调用轨迹——包括搜索内容、提取内容、运行的代码及输出、轮次数量、是否收敛。这使得评审模型可以评估工具选择策略,而不仅仅是最终答案。

Efficiency Analysis

效率分析

The
--efficiency
flag (auto-enabled for tools mode) prints a token comparison table:
📊 Efficiency Comparison
                      Turns  Tools   Tok In  Tok Out  Ratio   Time
✅ ollama-cloud:glm-5.2      5      5     7806      777   0.10  15.3s
✅ ollama-cloud:kimi-k2.5    5      4     5434     1051   0.19  14.8s
✅ ollama-cloud:gemma4:31b   2      1      949      248   0.26   6.5s
Key metrics: turns, tool calls, tokens in (context consumed), tokens out (generated), efficiency ratio (out/in), time. Efficiency without accuracy is waste — a model that uses few tokens but gets the wrong answer is not efficient, it's just wrong fast.
--efficiency
标识(工具模式自动启用)会打印token对比表格:
📊 效率对比
                      轮次  工具调用数  输入token数  输出token数  比率   耗时
✅ ollama-cloud:glm-5.2      5      5     7806      777   0.10  15.3s
✅ ollama-cloud:kimi-k2.5    5      4     5434     1051   0.19  14.8s
✅ ollama-cloud:gemma4:31b   2      1      949      248   0.26   6.5s
关键指标:轮次、工具调用数、输入token数(消耗的上下文)、输出token数(生成内容)、效率比率(输出/输入)、耗时。没有准确性的效率毫无意义——一个使用少量token但答案错误的模型不是高效,只是快速出错。

Use Cases

使用案例

Model selection for a workflow

为工作流选择模型

"I need a model for summarizing legal documents. Compare claude-sonnet-4.6, gpt-4o, and gemini-2.5-flash on this prompt: [legal text]"
"我需要一个用于法律文档摘要的模型。对比claude-sonnet-4.6、gpt-4o和gemini-2.5-flash在以下提示词上的表现:[法律文本]"

Cost vs quality tradeoff

成本与质量权衡

"Compare glm-5.2 (free) vs claude-sonnet-4.6 (paid) on this coding prompt. Is the paid one worth it?"
"对比glm-5.2(免费)和claude-sonnet-4.6(付费)在以下编码提示词上的表现。付费模型是否值得?"

Prompt robustness testing

提示词鲁棒性测试

"Test this prompt on 3 models — I want to see which ones follow my formatting instructions"
"在3个模型上测试这个提示词——我想看看哪些模型能遵循我的格式要求"

Provider comparison

提供商对比

"Compare the same model (llama-4-maverick) on OpenRouter vs NVIDIA — is there a difference?"
"对比同一模型(llama-4-maverick)在OpenRouter和NVIDIA上的表现——是否有差异?"

Provider Health Tracking

提供商健康状态追踪

The
scripts/provider_health.py
module tracks provider endpoint health and implements dead-host cooldown — when a provider fails consecutively, it's marked dead for a cooldown period and subsequent calls skip it automatically.
scripts/provider_health.py
模块追踪提供商端点健康状态,并实现故障主机冷却机制——当提供商连续失败时,标记为故障并进入冷却期,后续调用会自动跳过该提供商。

How it works

工作原理

  • 2 consecutive failures → provider marked dead
  • Cooldown: 15s (Ollama Cloud), 30s (NVIDIA), 20s (OpenRouter)
  • Any success → resets failure counter immediately
  • Cooldown expiry → provider gets another chance
  • State persists to
    ~/.hermes/data/provider_health.json
    across runs
  • 连续2次失败 → 提供商标记为故障
  • 冷却时间:Ollama Cloud为15秒,NVIDIA为30秒,OpenRouter为20秒
  • 任何一次成功 → 立即重置失败计数器
  • 冷却期结束 → 提供商恢复可用
  • 状态持久化到
    ~/.hermes/data/provider_health.json
    ,跨运行会话保留

CLI

CLI命令

bash
undefined
bash
undefined

Check provider health

检查提供商健康状态

python3 scripts/provider_health.py --status
python3 scripts/provider_health.py --status

Reset all providers

重置所有提供商

python3 scripts/provider_health.py --reset all
python3 scripts/provider_health.py --reset all

Reset a specific provider

重置指定提供商

python3 scripts/provider_health.py --reset ollama-cloud
undefined
python3 scripts/provider_health.py --reset ollama-cloud
undefined

Integration in compare.py

在compare.py中的集成

Both
call_model_simple
and
call_model_with_tools
check provider health before making API calls. If a provider is in cooldown, the call is skipped with a
[Provider X in cooldown (Ns remaining) — skipping]
message instead of waiting for a timeout. Successes and failures are recorded automatically.
call_model_simple
和
call_model_with_tools
在发起API调用前都会检查提供商健康状态。如果提供商处于冷却期,会跳过调用并显示
[Provider X in cooldown (Ns remaining) — skipping]
消息,而非等待超时。成功和失败会自动记录。

When it matters

重要性

  • Running comparisons across multiple providers — one flaky provider won't slow down the whole comparison
  • Tool calling mode (10 turns per model) — a dead provider is skipped in seconds instead of waiting 60s × 10 turns = 10 minutes of timeouts
  • Back-to-back comparisons — if a provider went down in a previous run, the next run knows to skip it
  • 在多个提供商间运行对比时——一个不稳定的提供商不会拖慢整个对比过程
  • 工具调用模式(每个模型10轮)——故障提供商在数秒内被跳过,而非等待60秒×10轮=10分钟的超时
  • 连续对比时——如果提供商在上一次运行中故障,下一次运行会自动跳过

Hybrid Mode — CLI Models Alongside API Models

混合模式——CLI模型与API模型并行

The compare script only supports API-based providers (OpenRouter, Ollama Cloud, NVIDIA). When the user wants to include models only accessible via CLI tools (Codex CLI, Cursor CLI), use this hybrid pattern:
对比脚本仅支持基于API的提供商(OpenRouter、Ollama Cloud、NVIDIA)。当用户希望包含仅通过CLI工具访问的模型(如Codex CLI、Cursor CLI)时,可使用以下混合模式:

When to use hybrid mode

何时使用混合模式

  • Cost savings — user says "use codex cli for gpt5.6" to avoid OpenRouter per-token costs. Codex ($20/mo) and Cursor Pro+ ($60/mo) include model access without per-token charges.
  • Model availability — some models (e.g.
    cursor-grok-4.5-high
    ) are only available through Cursor CLI, not on any API provider.
  • 成本节约——用户说"use codex cli for gpt5.6"以避免OpenRouter的按token计费。Codex(20美元/月)和Cursor Pro+(60美元/月)包含模型访问权限,无需额外按token付费。
  • 模型可用性——部分模型(如
    cursor-grok-4.5-high
    )仅通过Cursor CLI提供,无法通过任何API提供商访问。

How to run hybrid comparisons

如何运行混合对比

  1. API models → run through
    scripts/compare.py
    as normal (background)
  2. CLI models → run each separately via terminal in parallel:\n - Codex CLI (GPT-5.6):
    codex exec --skip-git-repo-check -m gpt-5.5 "<prompt>" > /tmp/codex_result.json 2>&1
    \n - Cursor CLI (Grok 4.5):
    export PATH="$HOME/.local/bin:$PATH" && export $(grep 'CURSOR_API_KEY=' ~/.hermes/.env | xargs) && agent -p --force --model "cursor-grok-4.5-high" --sandbox disabled "<prompt>" > /tmp/cursor_result.json 2>&1
  3. Merge results — collect API script output + CLI outputs, present all responses anonymously (shuffle together), let user vote, then reveal.
  1. API模型 → 正常通过
    scripts/compare.py
    运行(后台执行)
  2. CLI模型 → 分别在终端并行运行:\n - Codex CLI(GPT-5.6):
    codex exec --skip-git-repo-check -m gpt-5.5 "<prompt>" > /tmp/codex_result.json 2>&1
    \n - Cursor CLI(Grok 4.5):
    export PATH="$HOME/.local/bin:$PATH" && export $(grep 'CURSOR_API_KEY=' ~/.hermes/.env | xargs) && agent -p --force --model "cursor-grok-4.5-high" --sandbox disabled "<prompt>" > /tmp/cursor_result.json 2>&1
  3. 合并结果——收集API脚本输出 + CLI输出,将所有响应匿名展示(打乱顺序),让用户投票,然后揭晓结果。

CLI model specifics

CLI模型细节

CLIBinaryModel flagAuthCost
Codex
codex
-m gpt-5.6-sol
OAuth (hermes auth)$20/mo included
Cursor
agent
--model "cursor-grok-4.5-high"
CURSOR_API_KEY
in .env
$60/mo included
Always run CLI models in background (
background=true
+
notify_on_complete=true
) — they can take 1-5 minutes. Run them in the same tool batch as the API script launch for true parallelism.
Cursor Grok 4.5 High is the heaviest internal tier. For lighter tasks use
cursor-grok-4.5-medium
. See the
cursor-cli
skill for full model selection guidance.
CLI工具二进制文件模型标识认证方式成本
Codex
codex
-m gpt-5.6-sol
OAuth(hermes认证)包含在20美元/月订阅中
Cursor
agent
--model "cursor-grok-4.5-high"
.env中的
CURSOR_API_KEY
包含在60美元/月订阅中
始终在后台运行CLI模型(
background=true
+
notify_on_complete=true
)——可能需要1-5分钟。将其与API脚本启动放在同一工具批次中,实现真正的并行执行。
Cursor Grok 4.5 High是内部最高级别。对于轻量任务,使用
cursor-grok-4.5-medium
。查看
cursor-cli
技能获取完整的模型选择指南。

Pitfalls

注意事项

  • Revealing identities too early — never let model names leak into the anonymous presentation. Double-check before sending.
  • Always same order — shuffle every time. If model A is always first, the user may develop position bias.
  • Not parallel — send all API calls in the same tool block. Sequential calls waste time.
  • Ignoring failures — if a model errors, tell the user. Don't silently exclude it.
  • Truncating too aggressively — the user needs enough text to judge quality. 3000 chars minimum, full if shorter.
  • Forgetting to reveal — always reveal after the vote. The whole point is knowing which model won.
  • Not confirming model list — always confirm which models before spending API calls. Models cost money.
  • Spending paid API calls without confirmation — OpenRouter is per-token paid. Always confirm with the user before calling OpenRouter models. Default to free providers (Ollama Cloud, NVIDIA) when no provider is specified. Only escalate to OpenRouter when the user explicitly requests a premium model or confirms cost.
  • Using max_tokens too low — 8192 is the current default in compare.py. The previous 4096 caused truncated code on test J (LRU cache decorator cut off mid-function). If a model still truncates, raise the value in the payload dict.
  • Temperature mismatch — use the same temperature (0.7 default) for all models. Different temperatures = unfair comparison.
  • API key leakage — never print API keys in output. Always use env var references in curl commands.
  • Rate limits — OpenRouter and NVIDIA have rate limits. If comparing 4+ models, add a small delay between calls if needed. OpenRouter free-tier models (with
    :free
    suffix) are especially prone to HTTP 429 rate-limiting after just 1-2 calls.
  • OpenRouter free-tier models (
    :free
    suffix) and the cost gate
    — the script conservatively treats ALL OpenRouter models as paid, even
    :free
    suffix models that cost $0. Set
    COMPARE_CONFIRM_PAID=1
    env var to bypass the cost confirmation gate. Example:
    COMPARE_CONFIRM_PAID=1 python3 scripts/compare.py --models "openrouter:tencent/hy3:free" ...
    . No additional cost confirmation needed since the user has already chosen free-tier models.
  • NVIDIA NIM model IDs include the
    nvidia/
    prefix
    — when using NIM via compare.py, pass the full model ID including the org prefix:
    nvidia:nvidia/nemotron-3.5-lightning-30b-a3b
    (provider colon, then full model ID). Passing
    nvidia:nemotron-3.5-lightning-30b-a3b
    (without the
    nvidia/
    prefix) returns HTTP 404 "page not found" — NIM requires the full
    nvidia/...
    model ID in the API payload.
  • Nemotron 3.5 Lightning free tier tool calling — only the OpenRouter
    :free
    suffix and NIM direct support
    tools
    . The OpenRouter paid tier (
    nvidia/nemotron-3.5-lightning
    without
    :free
    , CoreWeave-hosted) returns HTTP 404 on
    tools
    . Use
    nvidia:nvidia/nemotron-3.5-lightning-30b-a3b
    (NIM, free, stable) or
    openrouter:nvidia/nemotron-3.5-lightning:free
    (free, but prone to 502s).
  • NVIDIA model list is stale — the
    /v1/models
    endpoint lists many models but most return 404/410 when called. Only
    meta/llama-3.1-70b-instruct
    ,
    meta/llama-3.3-70b-instruct
    , and
    mistralai/mixtral-8x7b-instruct-v0.1
    were alive as of June 2026. Always verify a model is alive with a simple chat completion before using it in a comparison. See
    references/provider-tool-support.md
    for the current alive list.
  • Assuming tool calling support — not all models support the
    tools
    API parameter. Test with a simple tool-call request first. Models that mention "search" in text but don't emit
    tool_calls
    do NOT support tool calling. See
    references/provider-tool-support.md
    for the tested matrix.
  • Not all models support tool calling —
    deepseek-v3.2
    (Ollama Cloud) mentions "search" in text but does NOT emit
    tool_calls
    .
    mistralai/mixtral-8x7b-instruct-v0.1
    (NVIDIA) returns HTTP 400 on the
    tools
    parameter. Test tool support per model before running
    --mode tools
    . See
    references/provider-tool-support.md
    .
  • Efficiency without accuracy is waste — a model that uses few tokens but gets the wrong answer is not efficient. Always cross-reference efficiency stats with the judge score. gemma4:31b used 949 tokens and 2 turns but said Python 3.13 (wrong); kimi-k2.5 used 5434 tokens and 5 turns but got the correct answer with authoritative sources.
  • Tool calling loop can hit max turns — some models keep searching without synthesizing. The 10-turn default cap (configurable per-test via
    max_turns
    in TEST_BANK) prevents infinite loops, but the result is marked "did not converge." Check the
    converged
    field in the trace. Increasing
    max_turns
    can help models that need more turns to synthesize, but watch for models that loop on the same URLs without converging — more turns won't fix a model that can't synthesize.
  • No
    --max-turns
    CLI override (fixed 2026-07-17)
    — the script used to only support per-test
    max_turns
    in the TEST_BANK dict, requiring source edits to change the turn cap. This forced killing background runs to patch source. Now
    --max-turns N
    overrides at runtime. If the flag doesn't work, check that
    compare.py
    has the
    --max-turns
    argument parser entry.
  • User prefers CLI models to cut costs — when the user says "use codex cli for gpt5.6" or "use cursor-grok-4.5-high", they want to avoid OpenRouter per-token charges. Route GPT-5.6 through Codex CLI and Grok 4.5 through Cursor CLI instead of OpenRouter. See the Hybrid Mode section above. This is a cost preference, not just a one-off request.\n- Codex CLI model version limits —
    codex exec -m gpt-5.6-sol
    fails with "requires a newer version of Codex" on v0.135. Test with a trivial prompt first (
    codex exec --skip-git-repo-check -m <model> "say hello"
    ). Fall back to
    gpt-5.5
    if the newer model is unsupported.\n- Codex CLI needs
    --skip-git-repo-check
    — without it, Codex refuses to run outside a git repo. Always include this flag.\n- Cursor CLI
    --force
    required for web access
    —
    --trust --sandbox disabled
    alone does NOT enable web search in headless mode. Web requests are still blocked. Use
    --force
    (which implies
    --trust
    ) to enable web access. Confirmed across 3 attempts:
    --trust
    → blocked,
    --trust --sandbox disabled
    → blocked,
    --force
    → works.\n- OpenRouter geofenced models — some models (e.g.
    meta/muse-spark-1.1
    ) return HTTP 403 "This model is only available in the United States" when called from outside the US. No workaround without a US proxy. Exclude from comparisons run from non-US locations.
  • SearXNG default engines may return 0 results — Google, DuckDuckGo, Brave, Startpage, and Mojeek engines frequently fail on self-hosted SearXNG (rate limits, CAPTCHAs). Only Bing and Yandex reliably return results. The script's
    execute_web_search
    now passes
    &engines=bing,yandex,duckduckgo,google
    explicitly. If search returns 43-char
    {"results": [], "note": "No results found"}
    on every query, check SearXNG engine health with
    curl -s "http://$SEARXNG_URL/search?q=test&format=json&engines=bing"
    and update the engines list in
    scripts/compare.py
    .
  • DDGS CLI syntax changed — the old
    ddgs --json -q ... -m ...
    syntax no longer works. The new CLI uses
    ddgs text -q ... -m ... -o <file>
    (outputs to file, not stdout). The script's DDGS fallback has been updated to use the new syntax. Verify with
    ddgs text --help
    if fallback fails.
  • SEARXNG_URL not exported to background processes — the env var is loaded from
    ~/.hermes/.env
    by the script's
    load_env()
    function, but if you pass
    --mode tools
    to a background process (e.g. via
    terminal(background=true)
    ), make sure to
    export SEARXNG_URL=http://...
    explicitly in the command. The
    load_env()
    function only sets vars that are NOT already in
    os.environ
    , but background shells start with a minimal environment.
  • compare.py requires 2+ models — the script exits with "Error: need at least 2 models to compare" if you pass only one. To retry a single model after rate limiting, use a direct curl API call instead of the script.
  • Comparing reasoning-effort levels is now native (v1.2.0) — use the
    provider:@effort:model_id
    syntax on
    --models
    and
    --judge
    (see the "Reasoning-effort A/B" section above). The old wrapper-harness pattern (
    /root/.hermes/cache/ab_effort_run.py
    , virtual providers registered in a loader script) still works for multi-test batteries with per-test ground-truth judging; the native syntax covers single-run comparisons. For CLI judges (e.g. Codex gpt-5.6-sol): write the rubric + anonymized responses to a temp file, run
    codex exec --skip-git-repo-check -m gpt-5.6-sol "Read the file <path> and follow the instructions inside"
    , parse JSON from stdout+stderr, shuffle the Response 1/2 order per test. Ground truth for code_review tests comes from TEST_BANK
    evaluation
    +
    planted_issues
    keys (NOT
    evaluation_criteria
    ). Known findings (glm-5.3-flash, 2026-08-29): effort→reasoning-token count is NON-monotonic (high ≠ more thinking); high effort hit a 12-turn non-convergence on long tool chains while medium converged; medium won 4-2-2 on quality (8.6 vs 7.8 avg), high was ~3x faster median.
  • Kimi K3 rate limiting on OpenRouter —
    moonshotai/kimi-k3
    hits HTTP 429 on the shared OpenRouter pool, especially when running multiple tests in parallel. Wait 15-30s and retry, or add a Moonshot API key to OpenRouter (BYOK) for dedicated rate limits.
  • Sandbox tests (S1-S5) need models that support 5 tools — the sandbox tests pass all 5 tool definitions (web_search, web_extract, run_python, read_file, write_file) to the model. Some models may not support tool calling with 5 tools, or may only support 1-2 tools at a time. If a model fails on sandbox tests but passes research tests (A/B/C), it may be overwhelmed by the number of tool definitions. Test with a simpler sandbox prompt first.
  • Sandbox Python execution is not network-isolated — the
    run_python
    tool runs
    subprocess.run([sys.executable, script])
    which can make network calls if the code imports
    urllib
    or
    socket
    . The 10-second timeout limits damage but is not a true sandbox. For production hardening, consider running in a container or seccomp filter. For model comparison purposes, the timeout is sufficient.
  • Sandbox temp files are cleaned up after each model — the
    run_tool_loop
    function creates a temp dir per model and cleans it up in a
    finally
    block. If a model writes a file and then needs to read it back in a later turn, that works (same sandbox dir persists across turns). But if the script crashes mid-run, the
    finally
    block still cleans up.
  • Sandbox output truncated to 2000 chars —
    run_python
    returns stdout and stderr truncated to 2000 chars each. If a model generates a lot of output (e.g. printing a large list), the truncated output may confuse it. Models that format output concisely will perform better on sandbox tests.
  • 过早揭晓模型身份——切勿让模型名称在匿名展示中泄露。发送前务必检查。
  • 始终保持同一顺序——每次都要打乱顺序。如果模型A始终排在第一位,用户可能会产生位置偏见。
  • 未并行执行——在同一工具块中发送所有API调用。顺序调用会浪费时间。
  • 忽略失败情况——如果模型出错,告知用户。不要默默排除。
  • 过度截断——用户需要足够的文本内容来判断质量。最少保留3000字符,若内容更短则完整展示。
  • 忘记揭晓结果——投票后务必揭晓身份。整个对比的核心就是了解哪个模型获胜。
  • 未确认模型列表——在消耗API调用前始终确认模型列表。模型调用会产生成本。
  • 未确认就使用付费API调用——OpenRouter按token付费。在调用OpenRouter模型前始终与用户确认。未指定提供商时默认使用免费提供商(Ollama Cloud、NVIDIA)。仅当用户明确要求高级模型或确认成本时,才使用OpenRouter。
  • max_tokens设置过低——当前compare.py中的默认值为8192。之前的4096会导致测试J(LRU缓存装饰器)的代码被截断。如果模型仍出现截断情况,增加请求体中的该值。
  • 温度设置不一致——所有模型使用相同的温度(默认0.7)。不同的温度会导致不公平对比。
  • API密钥泄露——切勿在输出中打印API密钥。在curl命令中始终使用环境变量引用。
  • 速率限制——OpenRouter和NVIDIA有速率限制。如果对比4个以上模型,必要时在调用间添加短暂延迟。OpenRouter免费层模型(带
    :free
    后缀)在仅1-2次调用后就容易出现HTTP 429速率限制。
  • OpenRouter免费层模型(
    :free
    后缀)与成本确认
    ——脚本保守地将所有OpenRouter模型视为付费,即使带
    :free
    后缀的模型成本为0。设置环境变量
    COMPARE_CONFIRM_PAID=1
    可绕过成本确认。示例:
    COMPARE_CONFIRM_PAID=1 python3 scripts/compare.py --models "openrouter:tencent/hy3:free" ...
    。由于用户已选择免费层模型,无需额外成本确认。
  • NVIDIA NIM模型ID包含
    nvidia/
    前缀
    ——在compare.py中使用NIM时,需传递完整模型ID,包括组织前缀:
    nvidia:nvidia/nemotron-3.5-lightning-30b-a3b
    (提供商冒号,然后是完整模型ID)。传递
    nvidia:nemotron-3.5-lightning-30b-a3b
    (不带
    nvidia/
    前缀)会返回HTTP 404“页面未找到”——NIM要求API请求体中使用完整的
    nvidia/...
    模型ID。
  • Nemotron 3.5 Lightning免费层工具调用——仅OpenRouter带
    :free
    后缀的版本和NIM直接调用支持
    tools
    。OpenRouter付费层(不带
    :free
    的
    nvidia/nemotron-3.5-lightning
    ,由CoreWeave托管)在使用
    tools
    时返回HTTP 404。使用
    nvidia:nvidia/nemotron-3.5-lightning-30b-a3b
    (NIM,免费,稳定)或
    openrouter:nvidia/nemotron-3.5-lightning:free
    (免费,但容易出现502错误)。
  • NVIDIA模型列表过时——
    /v1/models
    端点列出了许多模型,但大多数调用时会返回404/410错误。截至2026年6月,只有
    meta/llama-3.1-70b-instruct
    、
    meta/llama-3.3-70b-instruct
    和
    mistralai/mixtral-8x7b-instruct-v0.1
    可用。在将模型用于对比前,始终通过简单的对话补全验证模型是否可用。查看
    references/provider-tool-support.md
    获取当前可用模型列表。
  • 假设模型支持工具调用——并非所有模型都支持
    tools
    API参数。先通过简单的工具调用请求测试。在文本中提到“搜索”但不返回
    tool_calls
    的模型不支持工具调用。查看
    references/provider-tool-support.md
    获取已测试的模型矩阵。
  • 并非所有模型都支持工具调用——
    deepseek-v3.2
    (Ollama Cloud)在文本中提到“搜索”但不返回
    tool_calls
    。
    mistralai/mixtral-8x7b-instruct-v0.1
    (NVIDIA)在使用
    tools
    参数时返回HTTP 400错误。在运行
    --mode tools
    前测试每个模型的工具支持情况。查看
    references/provider-tool-support.md
    。
  • 没有准确性的效率毫无意义——一个使用少量token但答案错误的模型不是高效。始终将效率统计与评审得分交叉验证。gemma4:31b使用了949个token和2轮次,但给出的Python版本是3.13(错误);kimi-k2.5使用了5434个token和5轮次,但得到了正确答案并引用了权威来源。
  • 工具调用循环可能达到最大轮次——部分模型会持续搜索而不进行合成。默认的10轮次上限(可通过TEST_BANK中的
    max_turns
    按测试配置)可防止无限循环,但结果会标记为“未收敛”。查看轨迹中的
    converged
    字段。增加
    max_turns
    可帮助需要更多轮次合成的模型,但注意部分模型会在相同URL上循环而不收敛——更多轮次无法解决模型无法合成的问题。
  • 无
    --max-turns
    CLI覆盖(2026-07-17已修复)
    ——脚本之前仅支持在TEST_BANK字典中按测试设置
    max_turns
    ,需要修改源代码来调整轮次上限。这会导致必须终止后台运行来修改源代码。现在
    --max-turns N
    可在运行时覆盖该值。如果该标识无效,检查
    compare.py
    是否包含
    --max-turns
    参数解析项。
  • 用户偏好使用CLI模型降低成本——当用户说"use codex cli for gpt5.6"或"use cursor-grok-4.5-high"时,他们希望避免OpenRouter的按token计费。将GPT-5.6路由到Codex CLI,Grok 4.5路由到Cursor CLI,而非OpenRouter。查看上述混合模式部分。这是成本偏好,而非一次性请求。\n- Codex CLI模型版本限制——
    codex exec -m gpt-5.6-sol
    在v0.135版本会失败,提示"requires a newer version of Codex"。先通过简单提示词测试(
    codex exec --skip-git-repo-check -m <model> "say hello"
    )。如果新版本模型不支持,回退到
    gpt-5.5
    。\n- Codex CLI需要
    --skip-git-repo-check
    ——如果没有该标识,Codex会拒绝在git仓库外运行。始终包含该标识。\n- Cursor CLI需要
    --force
    才能启用网络访问
    ——仅
    --trust --sandbox disabled
    在无头模式下无法启用网页搜索。网络请求仍会被阻止。使用
    --force
    (隐含
    --trust
    )启用网络访问。经过3次尝试确认:
    --trust
    →被阻止,
    --trust --sandbox disabled
    →被阻止,
    --force
    →可用。\n- OpenRouter地域限制模型——部分模型(如
    meta/muse-spark-1.1
    )在非美国地区调用时会返回HTTP 403"This model is only available in the United States"。没有美国代理的话无法解决。非美国地区的对比请排除这些模型。
  • SearXNG默认引擎可能返回0结果——Google、DuckDuckGo、Brave、Startpage和Mojeek引擎在自托管SearXNG上经常失败(速率限制、验证码)。只有Bing和Yandex能可靠返回结果。脚本的
    execute_web_search
    现在会显式传递
    &engines=bing,yandex,duckduckgo,google
    。如果每次查询都返回43字符的
    {"results": [], "note": "No results found"}
    ,使用
    curl -s "http://$SEARXNG_URL/search?q=test&format=json&engines=bing"
    检查SearXNG引擎健康状态,并更新
    scripts/compare.py
    中的引擎列表。
  • DDGS CLI语法变更——旧的
    ddgs --json -q ... -m ...
    语法不再生效。新CLI使用
    ddgs text -q ... -m ... -o <file>
    (输出到文件,而非标准输出)。脚本的DDGS备选方案已更新为使用新语法。如果备选方案失败,使用
    ddgs text --help
    验证。
  • SEARXNG_URL未导出到后台进程——脚本的
    load_env()
    函数从
    ~/.hermes/.env
    加载环境变量,但如果将
    --mode tools
    传递给后台进程(如通过
    terminal(background=true)
    ),请确保在命令中显式
    export SEARXNG_URL=http://...
    。
    load_env()
    函数仅设置
    os.environ
    中不存在的变量,但后台shell启动时环境变量很少。
  • compare.py需要2个及以上模型——如果仅传递一个模型,脚本会退出并提示"Error: need at least 2 models to compare"。如果因速率限制需要重试单个模型,直接使用curl API调用,而非脚本。
  • 推理强度级别对比现已原生支持(v1.2.0)——在
    --models
    和
    --judge
    上使用
    provider:@effort:model_id
    语法(见上述“推理强度A/B测试”部分)。旧的包装器工具模式(
    /root/.hermes/cache/ab_effort_run.py
    ,在加载脚本中注册虚拟提供商)仍适用于带每测试基准评审的多测试组;原生语法适用于单次运行对比。对于CLI评审模型(如Codex gpt-5.6-sol):将评分标准 + 匿名响应写入临时文件,运行
    codex exec --skip-git-repo-check -m gpt-5.6-sol "Read the file <path> and follow the instructions inside"
    ,解析标准输出+标准错误中的JSON,每组测试打乱响应1/2的顺序。代码评审测试的基准来自TEST_BANK的
    evaluation
    +
    planted_issues
    键(而非
    evaluation_criteria
    )。已知结果(glm-5.3-flash,2026-08-29):强度→思考token数非单调(高强度≠更多思考);高强度版本在长工具链测试中12轮未收敛,而中强度版本完成了测试;中强度版本在质量上以4-2-2获胜(平均得分8.6 vs 7.8),高强度版本中位速度快约3倍。
  • Kimi K3在OpenRouter上的速率限制——
    moonshotai/kimi-k3
    在OpenRouter共享池中容易触发HTTP 429错误,尤其是在并行运行多个测试时。等待15-30秒后重试,或向OpenRouter添加Moonshot API密钥(BYOK)以获得专属速率限制。
  • 沙箱测试(S1-S5)需要支持5个工具的模型——沙箱测试会向模型传递所有5个工具定义(web_search、web_extract、run_python、read_file、write_file)。部分模型可能不支持同时调用5个工具,或一次仅支持1-2个工具。如果模型在沙箱测试中失败但在研究测试(A/B/C)中通过,可能是因为工具定义过多导致模型负担过重。先使用简单的沙箱提示词测试。
  • 沙箱Python执行未完全隔离网络——
    run_python
    工具运行
    subprocess.run([sys.executable, script])
    ,如果代码导入
    urllib
    或
    socket
    ,可能会发起网络请求。10秒超时限制了风险,但并非真正的沙箱。对于生产环境加固,考虑在容器或seccomp过滤器中运行。对于模型对比目的,超时已足够。
  • 沙箱临时文件在每个模型运行后清理——
    run_tool_loop
    函数为每个模型创建临时目录,并在
    finally
    块中清理。如果模型在某一轮写入文件,后续轮次需要读取该文件,这是可行的(同一沙箱目录在多轮次中保留)。但如果脚本中途崩溃,
    finally
    块仍会清理目录。
  • 沙箱输出截断至2000字符——
    run_python
    返回的标准输出和标准错误会截断至2000字符。如果模型生成大量输出(如打印大型列表),截断的输出可能会让模型困惑。输出简洁的模型在沙箱测试中表现更好。

Related Work

相关工作

Odysseus — PewDiePie's self-hosted AI workspace — includes a "Compare" feature for blind side-by-side model testing with conceptually similar goals (anonymous presentation, evaluation, reveal). This skill takes a different approach: pure-prompt + stdlib scripts with no UI, designed to run inside any agent's tool loop rather than as a standalone web app. Odysseus also reported a fine-tuned Qwen 32B model scoring 39% on the Aider Polyglot benchmark — a useful data point for model comparison calibration.
Odysseus — PewDiePie的自托管AI工作区——包含“Compare”功能,用于盲态并行模型测试,目标与本技能类似(匿名展示、评估、揭晓结果)。本技能采用不同的方法:纯提示词 + 标准库脚本,无UI,设计用于在任何代理的工具循环中运行,而非作为独立Web应用。Odysseus还报告称微调后的Qwen 32B模型在Aider Polyglot基准测试中得分为39%——这是模型对比校准的有用数据点。