1. 为什么要在 Python 里同时跑 Claude 4.5 和 GPT-5
如果你正在做 LLM 应用选型,大概率会遇到一个很现实的问题:单看官方 benchmark 表格,Claude 4.5 和 GPT-5 的分数咬得很紧,但真正落到自己的业务 prompt 上,谁更稳、谁更啰嗦、谁在长上下文里更容易丢信息,只有跑一遍才知道。我最近在做一个合同条款抽取的小工具,同一批 200 条样本分别喂给两个模型,结论和榜单差距不小,这也让我更坚定了一件事——评测必须自己动手。
麻烦点在于,两家模型的 SDK、鉴权方式、返回结构都不一样。Claude 走的是messages.create,返回content数组;GPT-5 走chat.completions.create,返回choices[0].message.content。如果每换一个模型就改一遍调用代码,评测脚本会越写越乱,后面想加第三个模型更是灾难。
所以这篇的做法是:用 TaoToken 作为统一 API 通道,把 Claude 4.5 和 GPT-5 收敛到同一套 OpenAI 兼容接口上,Python 侧只维护一份调用函数,靠model参数切换。这样对比评测的变量就只剩模型本身,而不是 SDK 差异。适合正在做模型选型、想快速搭一套可复现评测流程的开发者,也适合已经有一堆 prompt 想批量对照跑一遍的人。
下面会给出可复制的config.toml骨架、Python 调用示例、验证动作,以及我踩过的几个坑。
2. TaoToken 前置准备:拿 Key 与确认通道
统一通道的核心价值是「一个 base_url + 一个 key,调多个模型」。TaoToken 的 API 入口是https://taotoken.net/api,兼容 OpenAI 的请求格式,所以 Python 里可以直接用openai这个库,不需要为 Claude 单独装 Anthropic SDK。
第一步是拿 Key。打开控制台页面,登录后在 API Keys 区域创建一个新 key,复制出来先存到环境变量里,别硬编码进脚本。控制台地址在这里:
https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=claude45_gpt5_python_eval
创建 key 的直达页:
https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=claude45_gpt5_python_eval
拿到 key 之后,先确认你要用的两个模型名。不同通道对模型标识的写法可能略有差异,建议在模型对话页面先手动发一条消息,确认claude-4.5和gpt-5这类标识能正常返回,再去写脚本。模型对话入口:
https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=claude45_gpt5_python_eval
如果你后面打算把评测脚本接进 CI 或者长期跑批量任务,可以顺带看下 Coding Plan,它在高频调用场景下更省心:
https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=claude45_gpt5_python_eval
环境变量这样设,Linux/macOS 用 export,Windows 用 set:
export TAOTOKEN_API_KEY="sk-你的key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"3. 可复制配置:config.toml 骨架与 Python 调用
3.1 config.toml 配置骨架
把模型名、温度、max_tokens 这些评测变量抽到配置文件里,改参数不用动代码。下面这份可以直接复制:
# config.toml [api] base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" timeout = 120 max_retries = 3 [models.claude] name = "claude-4.5" temperature = 0.0 max_tokens = 2048 [models.gpt5] name = "gpt-5" temperature = 0.0 max_tokens = 2048 [eval] tasks_file = "tasks.jsonl" output_file = "results.jsonl" repeat = 1这里temperature = 0.0是为了让对比尽量可复现,评测场景下不建议开高温度,否则同一 prompt 两次结果差异会干扰判断。max_retries是给网络抖动留的余量,批量跑的时候很有用。
3.2 Python 统一调用封装
核心思路:只用一个openai客户端,通过model参数切换。这样 Claude 4.5 和 GPT-5 走的是同一条代码路径。
# eval_runner.py import os import json import time import tomllib from openai import OpenAI def load_config(path="config.toml"): with open(path, "rb") as f: return tomllib.load(f) def build_client(cfg): api_key = os.environ.get(cfg["api"]["api_key_env"]) if not api_key: raise RuntimeError("未找到 API Key,请检查环境变量") return OpenAI( api_key=api_key, base_url=cfg["api"]["base_url"], timeout=cfg["api"]["timeout"], max_retries=cfg["api"]["max_retries"], ) def call_model(client, model_cfg, prompt): start = time.time() resp = client.chat.completions.create( model=model_cfg["name"], temperature=model_cfg["temperature"], max_tokens=model_cfg["max_tokens"], messages=[{"role": "user", "content": prompt}], ) latency = time.time() - start return { "text": resp.choices[0].message.content, "latency": round(latency, 3), "usage": resp.usage.model_dump() if resp.usage else {}, } def run_eval(): cfg = load_config() client = build_client(cfg) tasks = [json.loads(line) for line in open(cfg["eval"]["tasks_file"], encoding="utf-8")] with open(cfg["eval"]["output_file"], "w", encoding="utf-8") as out: for task in tasks: for key in ("claude", "gpt5"): model_cfg = cfg["models"][key] try: result = call_model(client, model_cfg, task["prompt"]) record = { "task_id": task["id"], "model": model_cfg["name"], "output": result["text"], "latency": result["latency"], "usage": result["usage"], } except Exception as e: record = { "task_id": task["id"], "model": model_cfg["name"], "error": str(e), } out.write(json.dumps(record, ensure_ascii=False) + "\n") print(f"[{task['id']}] {model_cfg['name']} done") if __name__ == "__main__": run_eval()tasks.jsonl每行一个任务,格式如下,方便你把自己的 prompt 批量塞进去:
{"id": "math_001", "prompt": "证明:对所有正整数 n≥3,n^n > n! * 2^n,给出每步依据。"} {"id": "summary_001", "prompt": "对以下合同做结构化摘要,列出甲方权利、乙方义务、违约责任:<正文>"}3.3 对比评测的 prompt 设计要点
同一批任务要保证两个模型收到完全一致的输入,否则对比没意义。我在tasks.jsonl里把 prompt 写死,脚本里不做任何模型相关的分支处理。另外建议给每个任务加一个category字段,比如math、summary、code,跑完统计时能按类别看差异,比只看总分有用得多。
4. 验证请求:跑通一次双模型调用
先别急着批量跑,用一条最小请求确认通道是通的。下面这段可以直接在 Python 交互环境里执行:
import os from openai import OpenAI client = OpenAI( api_key=os.environ["TAOTOKEN_API_KEY"], base_url="https://taotoken.net/api", ) prompt = "用一句话解释什么是注意力机制。" for model in ["claude-4.5", "gpt-5"]: resp = client.chat.completions.create( model=model, messages=[{"role": "user", "content": prompt}], temperature=0, max_tokens=256, ) print(f"=== {model} ===") print(resp.choices[0].message.content) print("tokens:", resp.usage.total_tokens if resp.usage else "N/A")成功的话你会看到两段风格不同的回答,并且各自带 token 用量。如果这里就报错,先看第 5 节的排查表,别往下走。
确认单条通了之后,再跑批量脚本:
python eval_runner.py跑完results.jsonl里每行是一条记录,包含模型名、输出、延迟和 token 用量。我实测下来,同一批 20 条任务,Claude 4.5 在结构化输出上更规整,GPT-5 在开放推理题上给的思路更发散,延迟两者接近,但长文本任务里 GPT-5 的 token 消耗会明显高一些。这些差异只有自己跑一遍才有体感。
5. 本篇常见错排查
| 报错/现象 | 可能原因 | 处理方式 |
|---|---|---|
AuthenticationError401 | key 没设进环境变量,或复制时带了空格 | 重新echo $TAOTOKEN_API_KEY确认,key 前后不要有空白 |
NotFoundError404 model | 模型标识写错,比如把claude-4.5写成claude-4-5 | 去模型对话页面确认实际可用标识 |
RateLimitError429 | 批量跑太快触发限流 | 在循环里加time.sleep(1),或降低并发 |
| 返回内容为空 | max_tokens设太小,被截断 | 调到 1024 以上再试 |
超时APITimeoutError | 长文本任务耗时超过默认超时 | 把timeout提到 180 或 300 |
| 中文乱码 | 写文件没指定encoding="utf-8" | 所有open都加encoding="utf-8" |
| 两个模型结果串了 | 循环里变量复用没重置 | 每次调用独立构造messages,别复用可变对象 |
还有一个容易忽略的点:temperature=0并不保证完全确定性,尤其在长输出里仍可能有细微差异。如果你要做严格的 A/B 对比,建议每个任务重复跑 3 次取多数,config.toml里的repeat字段就是留给这个的。
6. 把评测流程固定下来
跑通之后,建议把config.toml、tasks.jsonl、eval_runner.py三个文件放进同一个 git 仓库,每次换模型或改 prompt 都留一次 commit。这样过两周回头看,能清楚知道结论是在什么配置下得出的,而不是凭记忆。
接入相关的细节和参数说明,可以对照接入文档再核一遍:
https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=claude45_gpt5_python_eval
如果你更习惯在图形界面里先手动对比几轮再写脚本,模型对话页面可以直接切换模型发同一段 prompt,适合快速找感觉:
https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=claude45_gpt5_python_eval
长期要跑批量评测或者把模型接进编码 Agent,Coding Plan 会比按次调用更合适:
https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=claude45_gpt5_python_eval
最后补一句实操经验:评测脚本里最值得加的不是花哨的评分逻辑,而是把每次请求的原始输出、延迟、token 用量都落盘。我一开始只存了模型回答,后来想回头分析「是不是长 prompt 导致延迟飙升」时发现数据不够,只能重跑一遍。落盘这件事,越早做越省事。