ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

李飞飞团队新作 ESI-BENCH 拆解:用 TaoToken 统一 Key 复现感知-行动回路基准

李飞飞团队新作 ESI-BENCH 拆解:用 TaoToken 统一 Key 复现感知-行动回路基准 1. 从被动看图到主动探索ESI-BENCH 到底在测什么如果你最近在关注具身智能大概率刷到过李飞飞团队的新作 ESI-BENCH。它的全称是 Embodied Spatial Intelligence Benchmark中文可以理解为“具身空间智能基准”。和以往那些只让模型看一张图、回答一个空间问题的数据集不同ESI-BENCH 的核心命题是只有任务导向的主动观测才是空间推理的关键。换句话说它测的不是模型“视力”好不好而是模型会不会为了拿到证据去主动转头、移动、拾取、倾倒。这件事为什么重要因为过去两年多模态大模型在 VSR、BLINK、3DSRBench 这类基准上分数越刷越高但它们几乎都建立在一个隐含前提上模型拿到的输入已经是“最优视角”。真实世界里没有这种好事。一个杯子是不是在柜子里你得走过去、换个角度、甚至打开柜门才能确认一个物体能不能放进另一个物体你得比较容积、看遮挡关系。ESI-BENCH 就是要把这个“感知-行动回路”闭合起来用 10 大类、29 子类、3081 个任务实例逼着智能体自己决定下一步看哪里、动哪里。它适合谁我认为有三类开发者值得关注。第一类是做空间推理、VLM 评测的研究者想找一个比传统静态基准更接近真实交互的测试集第二类是做机器人、具身 Agent 的工程师想看看当前模型在“选动作”这件事上到底有多弱第三类是想复现论文结果、跑通评测流程的开发者尤其是需要统一管理多个模型 Key、避免在环境配置上反复踩坑的人。我自己在复现这类基准时最头疼的往往不是算法而是不同模型供应商的 Base URL、鉴权方式、模型 ID 各不相同脚本里到处硬编码换一个模型就要改一堆配置。这篇就围绕“怎么把 ESI-BENCH 的评测流程跑通”来写顺带把 TaoToken 作为统一 Key 网关的配置方式讲清楚让你能把精力放在空间推理指标本身而不是环境变量上。需要先说明的是ESI-BENCH 本身依赖 OmniGibson 仿真器和 BEHAVIOR-1K 场景完整跑通需要 GPU 和 Isaac Sim 环境。本文的重点不是教你装仿真器而是演示评测侧的调用链路如何用统一的 Base URL 和 Key 去请求模型如何构造一次基准任务请求以及如何校验返回结果里的空间推理字段。这样即使你暂时没有仿真环境也能先把模型接入和结果解析这一段跑通。2. TaoToken 前置统一 Key 与 Base URL 的接入准备在复现 ESI-BENCH 这类基准时评测脚本通常要调用多个 MLLM 做零样本测试比如 GPT 系列、Gemini 系列甚至 3D 增强模型。每个供应商的接入方式都不一样有的用Authorization: Bearer有的用x-api-key有的还要额外的anthropic-version头。如果你在脚本里为每个模型写一套请求逻辑维护成本会非常高而且一旦 Key 泄露或额度用尽排查起来很麻烦。TaoToken 在这里扮演的角色是一个统一的模型接入网关。你只需要在官网注册后拿到一个 API Key然后把所有模型的请求都指向同一个 Base URL就能用同一套鉴权方式调用不同模型。对复现基准来说这带来的直接好处是评测脚本里的模型配置可以抽成一个字典切换模型只改model字段不用动请求代码。先把关键地址列清楚方便你复制官网入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI Base URLhttps://taotoken.net/api模型对话用于快速验证模型是否可用https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteAPI Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteCoding Plan长期编码/Agent 场景https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite这里要强调一点TaoToken 是合规的模型接入服务不是所谓的“中转”或灰色通道。它的接口遵循 OpenAI 兼容格式所以你用openai这个 Python 包就能直接请求不需要额外装奇怪的 SDK。对于 ESI-BENCH 这种需要批量跑任务的场景OpenAI 兼容格式意味着你可以复用大量现成的评测代码。接下来是环境变量配置。我建议把 Base URL 和 Key 都放在环境变量里不要写死在脚本中。这样在 CI 或不同机器上跑评测时只需要改环境变量不用改代码。下面是我实际用的.env片段你可以直接复制# TaoToken 统一接入配置 export TAOTOKEN_BASE_URLhttps://taotoken.net/api export TAOTOKEN_API_KEYsk-你的实际Key # 评测用的模型 ID按需替换 export ESI_MODEL_IDgpt-4o如果你用的是python-dotenv可以在脚本开头load_dotenv()然后通过os.getenv读取。注意 API Key 不要提交到 Git建议把.env加进.gitignore。对于 Claude Code 这类需要 Anthropic 协议的工具TaoToken 也提供了对应的接入方式。如果你要在 Claude Code 里做代码润色或辅助分析Base URL 同样指向https://taotoken.net/apiKey 用同一个模型 ID 填 Claude 系列即可。具体路径可以参考接入文档里的 ClaudeCodeAnthropic 章节。这里不展开因为本文主线是 ESI-BENCH 评测。还有一个容易被忽略的点模型 ID 的命名。不同供应商对同一个模型的命名可能不同比如gpt-4o、gpt-4o-2024-08-06、gemini-1.5-pro等。在 TaoToken 的模型对话页面可以查到当前支持的模型列表建议先在那里确认你要用的模型 ID再写进评测脚本。否则很容易遇到model not found这类报错。3. 可复制配置把 ESI-BENCH 评测脚本接到统一网关这一节是全文的核心我会给出一个可以直接跑的 Python 配置片段把 ESI-BENCH 的评测请求接到 TaoToken 上。为了让配置更清晰我分成三部分客户端初始化、任务请求构造、结果解析。你可以把这三段拼成一个完整的脚本。先看客户端初始化。因为 TaoToken 兼容 OpenAI 格式所以直接用openai包import os from openai import OpenAI client OpenAI( base_urlos.getenv(TAOTOKEN_BASE_URL, https://taotoken.net/api), api_keyos.getenv(TAOTOKEN_API_KEY), ) MODEL_ID os.getenv(ESI_MODEL_ID, gpt-4o)这段代码的关键是base_url指向 TaoToken 的 API 地址api_key从环境变量读取。这样你切换模型时只需要改ESI_MODEL_ID不用动客户端。接下来是任务请求构造。ESI-BENCH 的任务本质上是给模型一段观测描述或图像加一个问题要求模型输出答案和置信度。在真实评测中观测来自 OmniGibson 渲染的图像在没有仿真环境时我们可以用文本描述模拟一次“感知-行动回路”的请求验证调用链路是否通。下面是一个模拟请求def build_esi_prompt(task_type, observation, question): system_prompt ( 你是一个具身空间智能评测助手。 你需要根据当前观测回答空间推理问题 并给出 0 到 1 之间的置信度。 如果证据不足请明确说明需要哪种动作来获取更多信息。 ) user_prompt f 任务类型{task_type} 当前观测{observation} 问题{question} 请按以下 JSON 格式输出 {{ answer: 你的答案, confidence: 0.0, needed_action: 如果需要更多信息填写建议动作否则填 none }} return system_prompt, user_prompt system_prompt, user_prompt build_esi_prompt( task_typeocclusion_counting, observation你看到一个架子上层有3个盒子下层被一个挡板遮住只能看到部分区域。, question架子上总共有多少个盒子, ) response client.chat.completions.create( modelMODEL_ID, messages[ {role: system, content: system_prompt}, {role: user, content: user_prompt}, ], temperature0, ) print(response.choices[0].message.content)这段代码里task_type对应 ESI-BENCH 的任务大类比如occlusion_counting遮挡计数、rigid_containment刚性容纳、spatial_distance空间距离等。observation是当前视角能看到的信息question是任务问题。要求模型输出 JSON是为了后续能程序化解析answer和confidence方便和 Ground Truth 对比。如果你要跑真实图像输入可以把messages里的content改成多模态格式messages [ {role: system, content: system_prompt}, { role: user, content: [ {type: text, text: user_prompt}, {type: image_url, image_url: {url: data:image/png;base64,你的图像base64}}, ], }, ]注意图像 base64 不要太大否则请求体可能超限。实测下来OmniGibson 渲染的 512x512 图像转 base64 后大约几百 KB是可以接受的。再给一个 TOML 配置片段方便你把评测参数外置。如果你用tomllib或toml包读取可以这样写[taotoken] base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY [esi_bench] model_id gpt-4o temperature 0 max_tokens 512 task_types [occlusion_counting, rigid_containment, spatial_distance]这样评测脚本读 TOML 就能拿到所有配置切换模型或任务类型不用改代码。对于需要跑多个模型对比的实验这个结构会省很多事。最后提醒一点如果你在脚本里用了requests而不是openai包记得请求头是Authorization: Bearer key路径是/v1/chat/completions。TaoToken 的 Base URL 是https://taotoken.net/api所以完整地址是https://taotoken.net/api/v1/chat/completions。这个路径在接入文档里有说明建议对照确认。4. 验证请求与结果校验一次基准任务的完整调用配置写好后下一步是实际发一次请求确认返回结果符合预期。这一节我会演示完整的调用过程并给出结果校验的代码。校验的重点是模型是否返回了合法 JSON、answer字段是否可解析、confidence是否在 0 到 1 之间、needed_action是否合理。先跑一次请求。假设你已经设置好环境变量执行上面的脚本你会看到类似下面的输出{ answer: 无法确定因为下层被挡板遮挡需要移动视角或移除挡板才能计数。, confidence: 0.35, needed_action: move_backward }这个结果说明调用链路是通的。模型没有瞎猜一个数字而是识别出遮挡导致信息不足并建议了一个动作move_backward。这正好对应 ESI-BENCH 强调的“主动探索”逻辑模型应该知道自己缺什么证据而不是过早承诺答案。接下来做结果校验。我写了一个validate_response函数把返回内容解析成字典并检查字段import json def validate_response(content): try: data json.loads(content) except json.JSONDecodeError: return False, 返回内容不是合法 JSON required_fields [answer, confidence, needed_action] for field in required_fields: if field not in data: return False, f缺少字段{field} confidence data[confidence] if not isinstance(confidence, (int, float)) or not (0 confidence 1): return False, fconfidence 不合法{confidence} if not isinstance(data[answer], str) or not data[answer].strip(): return False, answer 为空 return True, data ok, result validate_response(response.choices[0].message.content) if ok: print(校验通过, result) else: print(校验失败, result)这段代码会检查 JSON 合法性、字段完整性、置信度范围、答案非空。对于 ESI-BENCH 的批量评测你可以把每个任务的返回都过一遍这个校验统计通过率。如果某个模型经常返回非法 JSON说明它的指令遵循能力有问题这本身就是一个值得记录的指标。再进一步你可以把校验结果和 Ground Truth 对比计算准确率。ESI-BENCH 的任务大多有明确的正确答案比如遮挡计数是整数、刚性容纳是布尔值、空间距离是选项。下面是一个简单的对比逻辑def compare_with_ground_truth(prediction, ground_truth): pred_answer prediction[answer].strip().lower() gt_answer str(ground_truth).strip().lower() return pred_answer gt_answer对于数值型答案你可能需要先做归一化比如把“三个”转成“3”。对于选项型答案直接字符串匹配即可。实测下来模型在计数任务上经常输出“无法确定”这时候准确率会很低但这恰恰反映了 ESI-BENCH 论文里提到的“行动失明”问题模型不知道该怎么动只能保守回答。还有一个校验动作是检查needed_action是否在合法动作空间内。ESI-BENCH 的动作空间包括移动前后左右、上下、感知左右转头、上下俯仰、操作拾取、放置、注水、倾倒、终止提交答案。你可以定义一个合法动作集合检查模型建议的动作是否在其中VALID_ACTIONS { move_forward, move_backward, move_left, move_right, move_up, move_down, turn_left, turn_right, look_up, look_down, pick_up, place_on, place_in, pour, fill, submit } def validate_action(action): return action in VALID_ACTIONS or action none如果模型频繁输出不在集合里的动作说明它对动作空间的理解有偏差。这个指标在论文里对应“行动失明”的量化分析你可以自己跑一批任务统计一下。最后把一次完整调用的日志记下来包括请求时间、模型 ID、任务类型、返回内容、校验结果。这样在排查问题时能快速定位是模型问题还是配置问题。我习惯把日志写成 JSONL每行一条记录方便后续用 pandas 分析。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth复现评测时报错是难免的。这一节我整理了几个高频错误对照真实报错信息给出排查路径。这些错误大多和接入配置有关而不是 ESI-BENCH 本身的问题。401 Unauthorized。这是最常见的错误通常有三种原因。第一API Key 没设置或设置错了。检查TAOTOKEN_API_KEY环境变量是否为空或者 Key 是否复制时多了空格。第二请求头格式不对。如果你用requests确认是Authorization: Bearer sk-xxx注意Bearer后面有一个空格。第三Key 被禁用或额度耗尽。这时候去 API Keys 页面确认 Key 状态。我踩过的坑是在.env里写了export但用python-dotenv读取时export会被当成值的一部分导致 Key 变成export sk-xxx。解决办法是.env里不要写export直接写TAOTOKEN_API_KEYsk-xxx。local proxy failed。这个报错通常出现在你本地设置了 HTTP 代理但代理不可用或配置冲突。注意这里说的代理是系统层面的网络代理设置不是让你去用什么特殊工具。排查方法是检查环境变量HTTP_PROXY、HTTPS_PROXY是否指向了一个不可用的地址。如果你在公司内网可能需要走内网代理那就确认代理地址和端口是否正确。如果不需要代理直接unset HTTP_PROXY HTTPS_PROXY再跑一次。另外有些 Python 库会读取ALL_PROXY也一并检查。reading choices 报错。这个错误通常表现为AttributeError: NoneType object has no attribute choices或者KeyError: choices。原因是 API 返回的结构和你预期的不一样。可能的情况有请求失败但没抛异常返回体里是error字段而不是choices或者你用的 SDK 版本和接口不兼容。排查方法是先把原始返回打印出来print(response.model_dump_json(indent2))如果是error里面会有具体错误信息比如model not found、invalid api key、rate limit exceeded。如果是model not found去模型对话页面确认模型 ID 是否正确。如果是rate limit exceeded说明请求太频繁加个time.sleep(1)或降低并发。OAuth 相关报错。如果你在用 Claude Code 或某些需要 OAuth 的工具可能会遇到OAuth token expired或invalid_grant。这类错误通常和工具本身的登录态有关不是 TaoToken 的问题。解决办法是重新走一遍工具的登录流程或者在配置里改用 API Key 方式而不是 OAuth。对于 Claude Code接入文档里有专门的 ClaudeCodeAnthropic 配置说明建议对照检查 Base URL 和 Key 是否填对。除了这些还有一个容易忽略的问题模型返回的 JSON 被 Markdown 代码块包裹。比如模型输出json {answer: 3, confidence: 0.8, needed_action: none}这时候 json.loads 会失败因为前面有 json。解决办法是在解析前先剥离代码块标记 python def strip_code_block(content): content content.strip() if content.startswith(): lines content.split(\n) lines lines[1:] if lines and lines[-1].strip() : lines lines[:-1] content \n.join(lines) return content这个坑我在跑批量评测时遇到过模型有时候会加代码块有时候不加导致解析逻辑要兼容两种情况。建议在validate_response里先调用strip_code_block。最后如果你在 ESI-BENCH 的仿真环境里跑还可能遇到 OmniGibson 渲染失败、GPU 显存不足等问题。这些和模型接入无关建议先单独跑通仿真器的示例脚本再接入模型评测。分阶段排查比一上来就端到端跑要高效得多。6. 把评测流程跑通之后统一 Key 带来的复现效率写到这里评测链路基本讲完了。从环境变量配置、客户端初始化、任务请求构造到结果校验和报错排查这套流程可以让你在没有完整仿真环境的情况下先把模型接入和结果解析这一段跑通。等你有了 OmniGibson 环境只需要把文本观测替换成渲染图像其余逻辑不用大改。回到 ESI-BENCH 本身它最有价值的地方不是又刷了一个榜而是把“感知-行动回路”这个命题摆到了台面上。论文里的几个结论——主动探索有效、行动失明大于感知失明、瑕疵 3D 比 2D 更坑、元认知是核心差距——都在提醒我们空间智能不是单纯的视觉问题而是一个决策问题。模型需要知道什么时候该动、动哪里、动完之后怎么修正判断。这个思路对做 Agent 的开发者同样有启发不要只优化单步感知要把动作选择纳入评测。对于想复现这个基准的开发者我的建议是先把评测脚本的模型接入层抽象出来。用 TaoToken 这样的统一网关把 Base URL 和 Key 收敛到一处模型 ID 做成配置项。这样你在对比 GPT、Gemini、Claude 时只需要改一个字段不用重写请求逻辑。实测下来这种结构能省掉大量重复劳动尤其是在跑几十个任务、多个模型的批量评测时。如果你还没有 Key可以去官网注册一个然后在 API Keys 页面生成。生成后先别急着跑批量任务用模型对话页面发一条简单请求确认 Key 和 Base URL 都通。这一步花两分钟能避免后面很多 401 报错。接入文档里有完整的请求示例包括 curl 和 Python 两种方式建议对照跑一遍。最后留一个实用技巧在批量评测时给每个请求加一个唯一 ID把请求参数、返回内容、校验结果、耗时都记到 JSONL 里。这样当某个任务失败时你可以直接根据 ID 定位到原始请求和返回不用在一堆日志里翻。这个习惯在复现任何基准时都很有用尤其是当你要对比不同模型在同一任务上的表现时结构化日志能让分析效率提升一个量级。
返回列表