☰
《我的世界》成AI新「考场」?用MC-Bench给DeepSeek-R1跑一次基准测试
2026/9/26 10:39:37 网站建设 项目流程

1. 为什么我想在《我的世界》里给 DeepSeek-R1 跑一次基准测试

你可能已经看过那个新闻:一位高三学生做了个叫 MC-Bench 的网站,让不同的大模型在《我的世界》里按同一句提示词造建筑,然后由网友投票选谁造得更好。结果出来,Claude 3.7 Sonnet 排第一,DeepSeek-R1 位列第三。这件事有意思的地方不在于排名本身,而在于它换了一种评测思路——不再让模型做数学题、写代码片段,而是让它在三维空间里“动手盖东西”。

传统基准测试有个老问题:模型很容易在训练时见过类似的题,分数高不代表真实能力强。但《我的世界》里的建筑任务不一样,它要求模型理解空间关系、规划方块摆放顺序、处理材质和结构,最后还要生成可执行的建造代码。这比做选择题难多了,也更接近“真实干活”的感觉。

我自己对 DeepSeek-R1 一直挺好奇,它在推理任务上表现不错,但放到需要空间想象和代码生成的场景里会怎样?MC-Bench 给了个现成的框架,但如果你想自己复现一次跑测、记录结果、甚至接入自己的模型通道,就需要一套可操作的配置流程。这篇内容就是把我实际跑通的过程拆开,给你一份能直接抄的 config.toml 骨架和任务配置,顺便说说中间容易卡住的地方。

适合谁看:想自己搭一套模型评测环境的人、对 DeepSeek-R1 实际表现好奇的开发者、以及手里有统一 API 通道想接进 MC-Bench 任务流的同学。不需要你精通 Minecraft 模组开发,但得能看懂基本的 TOML 配置和 Python 请求代码。

2. 前置准备:用统一 Key 通道接入 DeepSeek-R1 等模型

MC-Bench 本身是个公开网站,你可以直接上去投票,但如果你想自己跑一套评测、把模型输出记录下来做对比,就需要一个能稳定调用多个模型的 API 通道。我试过用 TaoToken 的统一 Key 来管理模型访问,好处是不用为每个模型单独申请账号、单独配环境变量,一个 Key 就能切换 DeepSeek-R1、Claude 系列、GPT 系列等。

先明确你要拿什么:一个 API Key,以及对应的接入地址。TaoToken 的 API 地址是https://taotoken.net/api,注意这个地址不带任何查询参数,直接作为 base_url 用。Key 的获取在控制台里完成,登录后进 API Keys 页面创建一个新 Key,复制出来存到本地环境变量里,别直接写进代码提交到仓库。

如果你还没注册,可以从官网入口进:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。注册完先别急着跑 MC-Bench,拿一个最简单的对话请求验证通道是否通,这一步能帮你排除掉大部分低级错误。

模型选择上,MC-Bench 当前主要测试基础建造能力,DeepSeek-R1 在推理链上比较强,适合处理“先规划结构再生成方块序列”这类任务。你可以在配置里把模型名写成deepseek-r1,具体名称以你控制台里看到的为准。如果你还想对比 Claude 3.7 Sonnet,就再建一个配置块,用同一个 Key 切换模型名即可。

这里有个细节:MC-Bench 的任务本质是让模型生成一段可执行的建造代码(通常是 Python 或 JavaScript 脚本,调用 Minecraft 的 API 来放置方块)。所以你的请求不是简单的聊天,而是要把任务提示词、可用方块列表、坐标范围等约束一起发给模型。统一 Key 通道的好处是,你换模型时只需要改一个字段,不用动请求逻辑。

3. 可复制配置:config.toml 骨架与 MC-Bench 任务参数

下面这份 config.toml 是我实际跑通后整理出来的骨架,你可以直接复制到本地,把 Key 和模型名替换成自己的。注意 TOML 对缩进不敏感,但字符串必须用双引号,布尔值用小写 true/false。

# MC-Bench 本地跑测配置骨架 # 用途:通过统一 API 通道调用 DeepSeek-R1 等模型完成建筑任务 [api] # TaoToken API 地址,不要加末尾斜杠 base_url = "https://taotoken.net/api" # 从控制台 API Keys 页面获取,建议用环境变量注入 api_key = "${TAOTOKEN_API_KEY}" # 请求超时,建筑任务生成代码较慢,建议不低于 120 秒 timeout_seconds = 180 # 失败重试次数 max_retries = 2 [model] # 当前跑测的模型名称,切换模型只改这里 name = "deepseek-r1" # 温度参数,建筑任务需要一定创造性但别太飘 temperature = 0.6 # 最大输出 token,建造代码可能较长 max_tokens = 4096 [bench] # MC-Bench 任务提示词文件路径 prompt_file = "./prompts/build_tasks.jsonl" # 结果输出目录 output_dir = "./results/deepseek-r1" # 每个任务重复跑几次,用于观察稳定性 runs_per_task = 3 # 是否记录模型原始输出 save_raw_output = true [minecraft] # 评测用的 Minecraft 版本,MC-Bench 当前基于 1.20+ version = "1.20.4" # 建筑区域边界,避免方块超出范围 build_area = { x_min = -32, x_max = 32, y_min = 0, y_max = 64, z_min = -32, z_max = 32 } # 允许使用的方块类型,限制范围能减少模型乱用不存在的方块 allowed_blocks = [ "minecraft:stone", "minecraft:oak_planks", "minecraft:glass", "minecraft:red_wool", "minecraft:white_wool", "minecraft:gold_block", "minecraft:water", "minecraft:sand" ]

任务提示词文件build_tasks.jsonl每行是一个 JSON 对象,包含任务 ID、提示词和参考建筑描述。MC-Bench 官网上的任务比如“晶莹剔透的酒杯装满了深红色的葡萄酒”,你可以直接拿来用,也可以自己写。格式如下:

{"task_id": "wine_glass_001", "prompt": "Build a crystal clear wine glass filled with deep red wine, reflecting beautiful light. Use glass blocks for the cup and red wool or red concrete for the wine. The glass should have a stem and a base.", "reference": "A wine glass shape with a bowl, stem, and base, wine level about 60% of the bowl height."} {"task_id": "snowman_002", "prompt": "Build a snowman on a flat snowfield. It should have three stacked snow blocks, two coal block eyes, a carrot nose, and stick arms.", "reference": "Three snow blocks stacked vertically, decreasing in size, with facial features on the top block."}

配置里的allowed_blocks很重要。如果你不限制方块类型,模型可能会生成一些当前版本不存在的方块 ID,导致建造脚本执行失败。我踩过的坑是:DeepSeek-R1 有时会输出minecraft:red_concrete,但我的测试环境里没启用混凝土,结果方块放置请求被服务端拒绝。后来把允许列表写清楚,失败率明显下降。

另外build_area的边界也要设好。MC-Bench 的评测是在一个固定大小的区域里进行的,如果你不限制坐标,模型可能把建筑盖到区域外面,投票时看不到完整作品。我一般把 y 轴上限设在 64,因为大多数建筑不会超过这个高度,再高的话渲染和截图都会变慢。

4. 跑一次完整评测:从请求到结果校验

配置写好后,跑测流程分四步:加载任务、构造请求、执行建造、记录结果。下面是一个最小可运行的 Python 脚本,你可以把它保存为run_bench.py,和 config.toml 放在同一目录。

import json import os import time import tomllib import requests # 读取配置 with open("config.toml", "rb") as f: config = tomllib.load(f) api_base = config["api"]["base_url"] api_key = os.environ.get("TAOTOKEN_API_KEY") model_name = config["model"]["name"] timeout = config["api"]["timeout_seconds"] headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } # 加载任务 tasks = [] with open(config["bench"]["prompt_file"], "r", encoding="utf-8") as f: for line in f: if line.strip(): tasks.append(json.loads(line)) # 构造系统提示词,约束模型输出格式 system_prompt = """You are a Minecraft building assistant. Given a task description, output a JSON array of block placement commands. Each command has fields: x, y, z (integers), block (string, must be in allowed list). Do not output any explanation, only the JSON array.""" allowed = config["minecraft"]["allowed_blocks"] area = config["minecraft"]["build_area"] results = [] for task in tasks: user_prompt = f"""Task: {task['prompt']} Allowed blocks: {', '.join(allowed)} Build area: x from {area['x_min']} to {area['x_max']}, y from {area['y_min']} to {area['y_max']}, z from {area['z_min']} to {area['z_max']}. Output only the JSON array of block commands.""" payload = { "model": model_name, "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_prompt} ], "temperature": config["model"]["temperature"], "max_tokens": config["model"]["max_tokens"] } for run_idx in range(config["bench"]["runs_per_task"]): try: resp = requests.post( f"{api_base}/v1/chat/completions", headers=headers, json=payload, timeout=timeout ) resp.raise_for_status() data = resp.json() content = data["choices"][0]["message"]["content"] results.append({ "task_id": task["task_id"], "run": run_idx, "model": model_name, "raw_output": content, "timestamp": time.time() }) print(f"Task {task['task_id']} run {run_idx} done, output length: {len(content)}") except Exception as e: print(f"Task {task['task_id']} run {run_idx} failed: {e}") results.append({ "task_id": task["task_id"], "run": run_idx, "model": model_name, "error": str(e), "timestamp": time.time() }) # 保存结果 os.makedirs(config["bench"]["output_dir"], exist_ok=True) out_path = os.path.join(config["bench"]["output_dir"], "raw_results.jsonl") with open(out_path, "w", encoding="utf-8") as f: for r in results: f.write(json.dumps(r, ensure_ascii=False) + "\n") print(f"Results saved to {out_path}")

跑之前先确认环境变量已设置:

export TAOTOKEN_API_KEY="你的Key" python run_bench.py

成功的话你会看到类似输出:

Task wine_glass_001 run 0 done, output length: 842 Task wine_glass_001 run 1 done, output length: 791 Task wine_glass_001 run 2 done, output length: 815 Task snowman_002 run 0 done, output length: 623 ... Results saved to ./results/deepseek-r1/raw_results.jsonl

接下来是结果校验。模型输出的 JSON 数组不能直接信任,得先解析、检查方块是否在允许列表里、坐标是否越界。我写了一个校验脚本validate.py:

import json import tomllib with open("config.toml", "rb") as f: config = tomllib.load(f) allowed = set(config["minecraft"]["allowed_blocks"]) area = config["minecraft"]["build_area"] def validate_output(raw): try: blocks = json.loads(raw) except json.JSONDecodeError: return False, "JSON parse error" if not isinstance(blocks, list): return False, "not a list" for b in blocks: if b.get("block") not in allowed: return False, f"block not allowed: {b.get('block')}" if not (area["x_min"] <= b.get("x", 0) <= area["x_max"]): return False, f"x out of range: {b.get('x')}" if not (area["y_min"] <= b.get("y", 0) <= area["y_max"]): return False, f"y out of range: {b.get('y')}" if not (area["z_min"] <= b.get("z", 0) <= area["z_max"]): return False, f"z out of range: {b.get('z')}" return True, f"ok, {len(blocks)} blocks" with open("./results/deepseek-r1/raw_results.jsonl", "r", encoding="utf-8") as f: for line in f: r = json.loads(line) if "raw_output" not in r: print(f"{r['task_id']} run {r['run']}: request failed") continue ok, msg = validate_output(r["raw_output"]) print(f"{r['task_id']} run {r['run']}: {'PASS' if ok else 'FAIL'} - {msg}")

跑完校验后,你会得到每个任务每次运行的通过情况。如果某个任务三次都失败,可能是提示词不够明确,或者模型对空间坐标的理解有偏差。这时候可以调整temperature或者把任务描述拆得更细。

5. 本篇常见错排查:请求失败、JSON 解析、方块越界

跑测过程中最容易卡住的地方我列一下,你遇到时可以直接对照。

请求返回 401 或 403:先检查TAOTOKEN_API_KEY环境变量是否真的传进去了。在 Python 里可以临时打印os.environ.get("TAOTOKEN_API_KEY")[:8]看前几位,但别把完整 Key 打出来。如果 Key 没问题,确认base_url写的是https://taotoken.net/api,没有多余斜杠或路径。有些同学会把/v1也写进 base_url,然后在请求时又拼一次/v1/chat/completions,变成/v1/v1/...,直接 404。

请求超时:建筑任务的输出长度可能到几千 token,DeepSeek-R1 的推理链又比较长,180 秒是底线。如果你网络环境一般,可以调到 300 秒。但别无限等,设个上限避免卡死。

模型输出不是纯 JSON:DeepSeek-R1 有时会在 JSON 前后加解释文字,比如“好的,我来生成建造命令:”然后才是数组。我的处理方式是在解析前先做一次清洗,找到第一个[和最后一个],截取中间部分再json.loads。如果截取后还是解析失败,就把这次运行标记为失败,不要强行修。

方块 ID 不在允许列表:前面提过,模型可能输出minecraft:red_concrete而你的列表里只有minecraft:red_wool。解决办法有两个:一是把常用方块都加进allowed_blocks,二是校验失败后自动重试一次,并在重试提示词里强调“只能使用以下方块”。我一般两个都做,重试次数设 2 次。

坐标越界:模型可能把 y 设成 100 以上,或者 x 超出 ±32。校验脚本会拦住,但如果你直接拿输出去执行建造,服务端可能报错。建议先跑校验,通过的才送去执行。另外build_area的 y_min 别设 0,因为 Minecraft 里 y=0 是基岩层,建筑一般从 y=1 开始。

结果文件为空:检查output_dir路径是否存在,脚本里用了os.makedirs(..., exist_ok=True)应该会自动创建。如果还是空,看看是不是所有请求都失败了,打印一下异常信息。

6. 跑完这一轮之后,你可以继续做什么

一次完整的跑测下来,你会得到 DeepSeek-R1 在 MC-Bench 任务上的原始输出、校验通过率、以及每个任务的耗时。这些数据可以拿来做几件事:对比不同模型在同一批任务上的表现、调整提示词看通过率变化、或者把通过的建造命令实际导入 Minecraft 里截图,做人工投票的素材。

如果你想把评测范围扩大,可以在 config.toml 里加一个模型配置块,用同一个 Key 切换模型名,跑同样的任务集。TaoToken 的 API Keys 页面可以管理多个 Key,但跑测时建议一个 Key 对应一个模型,方便追踪用量。接入文档里有更详细的参数说明,遇到请求格式问题时可以对照查。

长期做编码类任务或者 Agent 开发的话,Coding Plan 可能比按量调用更划算,具体可以在控制台里看当前套餐的额度。模型对话入口适合快速验证单个提示词的效果,不用写完整脚本就能看输出。

最后说个实际经验:MC-Bench 的投票机制是盲测,你跑本地评测时也可以模仿这个思路——把不同模型的输出混在一起,先不看模型名,人工判断哪个建筑更符合提示词。这样能避免“知道是 DeepSeek-R1 就下意识觉得它推理强”的偏见。我试过把 DeepSeek-R1 和另一个模型的酒杯建筑截图并排看,结果发现 R1 在杯柄的弧度上处理得更自然,但酒杯的液面高度有点偏低。这种细节,光看排行榜是看不出来的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询