
1. Iris 评测脚本里的 base_url 为什么必须换成 TaoToken如果你正在本地复现小红书 AllSpark 开源的 Search Agent 模型 Iris尤其是 35B 或 397B 版本的评测最先卡住的地方往往不是权重下载而是评测脚本里那个写死的模型接口地址。Iris 这类 Search Agent 的调用链通常分成搜索规划、工具调用/检索、答案汇总三段真正消耗 Token 的是规划与汇总阶段的远端模型 API 调用当脚本里的base_url还指向一个本地端口或旧供应商时你会看到连接拒绝、401、404评测日志中断。先到 TaoToken 官网 拿YOUR_API_KEY再把 OpenAI 兼容调用的base_url设为https://taotoken.net/api回填 Key 后跑评测命令并对照日志整条链路才可复现。AllSpark 把 Iris 的权重和评测代码放出来之后社区里最常见的做法是先用 35B 跑通流程再换 397B 看长链路 Search Agent 的表现。这里有一个很容易被忽略的点Iris 本身的权重负责搜索决策但搜索规划后的外部知识获取、答案汇总、格式整理往往仍然要通过 OpenAI 兼容接口调用模型服务。也就是说评测脚本不是只加载一个本地模型就结束它会在多个阶段发起 API 请求。你看到的openai.OpenAI(base_urlhttp://127.0.0.1:8000/v1)、OpenAI(base_urlhttp://localhost:8080)这类硬编码就是导致评测半途失败的主要原因。为什么要在评测前先把接口切到 TaoToken原因很直接评测要可复现本地端口、临时隧道、旧 Key 都会让第二天重跑时结果不一致。把base_url统一为https://taotoken.net/api日志里记录的请求地址才有对照价值。Token 消耗可见Search Agent 的搜索规划与答案汇总会在usage字段里返回prompt_tokens、completion_tokens、total_tokens。不接管这些调用你很难知道到底是规划阶段耗 Token还是汇总阶段耗 Token。模型切换成本低35B 和 397B 的评测入口通常只差一个模型名或权重路径接口层用 OpenAI 兼容方式统一后切换模型不需要改业务代码。排障路径清晰401、403、404、429、超时这些错误能直接通过请求 URL、模型名、Key、环境变量逐项定位而不是在本地推理服务里找日志。这一篇不会把重点放在“Iris 到底有多强”这种无法只用几行日志证明的结论上而是把可跟做的部分写清楚去 TaoToken 创建 Key配置base_url改造评测脚本跑命令对照日志最后把结果记录成可复现的 JSONL。你按下面的顺序做至少能先把本地评测链路跑通。2. 准备 TaoToken Key从控制台到最小连通性验证第一步不是改 Iris 仓库而是先把模型服务的入口准备好。打开 TaoToken 官网进入控制台后创建 API Key。创建完成后不要直接把 Key 写进评测脚本更不要提交到 Git 仓库。推荐用环境变量保存脚本里只读os.environ。先设置两个基础变量。注意 Base URL 是https://taotoken.net/api不要在后面手工拼接多余的/v1/chat/completionsOpenAI SDK 会按自己的规则补全路径。Key 占位符统一写成YOUR_API_KEY你实际运行时替换成控制台里创建的 Key。export TAOTOKEN_API_KEYYOUR_API_KEY export TAOTOKEN_BASE_URLhttps://taotoken.net/api export TAOTOKEN_MODELYOUR_MODEL_ID然后做一次最小连通性验证。可以用curl先看网络和鉴权是否正常。不同环境下可用的模型列表接口可能不同如果列表接口不可用直接跳到后面的 Python 最小对话请求即可。curl -sS ${TAOTOKEN_BASE_URL}/models \ -H Authorization: Bearer ${TAOTOKEN_API_KEY} \ -H Content-Type: application/json \ | head -c 800更稳的方式是用 Python 发一个只要求回复ok的请求。这样能同时验证 Key、Base URL、模型名和返回结构。import os from openai import OpenAI client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.environ.get(TAOTOKEN_BASE_URL, https://taotoken.net/api), ) model_id os.environ.get(TAOTOKEN_MODEL, YOUR_MODEL_ID) resp client.chat.completions.create( modelmodel_id, messages[ {role: user, content: 只回复 ok不要加其他内容。} ], temperature0, ) print(content:, resp.choices[0].message.content) print(usage:, resp.usage)如果这里返回content: ok并且usage里能看到 token 计数说明接口层已经通了。如果报 401优先检查 Key 是否复制完整、是否有多余空格、环境变量是否在当前 shell 生效。如果报 404检查base_url是否被写成了https://taotoken.net/api/v1或其他拼接形式。如果报模型不存在回到控制台复制模型 ID不要凭记忆写一个近似名称。这一步完成后你手里应该有三个确定值TAOTOKEN_API_KEY从 TaoToken 控制台创建值为YOUR_API_KEY的实际 Key。TAOTOKEN_BASE_URL固定为https://taotoken.net/api。TAOTOKEN_MODEL从控制台模型列表或模型详情页复制不要猜。这三个值会贯穿后面的 Iris 评测脚本、Claude Code 配置、Codex 配置和 CC Switch 配置。不要在不同工具里混用变量名否则排障时很容易把 Anthropic 风格变量塞进 OpenAI 风格的脚本里。3. 改造 Iris 35B/397B 评测脚本OpenAI 兼容调用与阶段日志Iris 评测里真正需要改的地方通常有两类一类是模型加载路径比如 35B 和 397B 的权重目录另一类是 Search Agent 执行链中的远端 API 调用。我们这里重点处理第二类。因为搜索规划和答案汇总往往不是一次调用而是多次调用所以建议不要直接在原始评测文件里到处替换 URL而是包一层iris_eval_with_taotoken.py把远端调用集中管理。下面这个包装脚本展示了核心思路所有 OpenAI 兼容请求都走https://taotoken.net/api每次请求记录阶段、延迟、token 用量和返回内容。这样后面和 Iris 原始评测日志对照时你能清楚看到search_planning和answer_summary分别消耗了多少 Token。import json import os import time from openai import OpenAI client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.environ.get(TAOTOKEN_BASE_URL, https://taotoken.net/api), ) MODEL_ID os.environ.get(TAOTOKEN_MODEL, YOUR_MODEL_ID) LOG_PATH os.environ.get(IRIS_EVAL_LOG, logs/iris_eval_trace.jsonl) def call_stage(stage_name: str, prompt: str, system_prompt: str | None None): messages [] if system_prompt: messages.append({role: system, content: system_prompt}) messages.append({role: user, content: prompt}) start time.time() resp client.chat.completions.create( modelMODEL_ID, messagesmessages, temperature0, ) latency_ms int((time.time() - start) * 1000) row { stage: stage_name, model: MODEL_ID, base_url: os.environ.get(TAOTOKEN_BASE_URL, https://taotoken.net/api), latency_ms: latency_ms, prompt_tokens: resp.usage.prompt_tokens, completion_tokens: resp.usage.completion_tokens, total_tokens: resp.usage.total_tokens, content: resp.choices[0].message.content, } return row def append_log(row: dict): os.makedirs(os.path.dirname(LOG_PATH), exist_okTrue) with open(LOG_PATH, a, encodingutf-8) as f: f.write(json.dumps(row, ensure_asciiFalse) \n) if __name__ __main__: tasks [ { stage: search_planning, system: 你是 Search Agent 的规划模块只输出下一步搜索动作。, prompt: 用户问题是Iris 397B 的评测脚本如何接入 OpenAI 兼容接口请拆成 3 个搜索步骤。, }, { stage: answer_summary, system: 你是 Search Agent 的汇总模块根据已有信息给出可执行结论。, prompt: 已有信息base_url 为 https://taotoken.net/apiKey 使用 YOUR_API_KEY。请汇总配置步骤。, }, ] for task in tasks: row call_stage( stage_nametask[stage], prompttask[prompt], system_prompttask[system], ) append_log(row) print(task[stage], total_tokens, row[total_tokens], latency_ms, row[latency_ms])这段代码里有两个刻意设计base_url从环境变量读取默认值就是https://taotoken.net/api避免写死供应商地址。日志里保存stage这样 Search Agent 的搜索规划和答案汇总不会混在一起。如果你要评测 35B 和 397B不要复制两份脚本。更合理的方式是通过环境变量区分模型 ID或者通过命令行参数传入。例如export TAOTOKEN_MODELYOUR_MODEL_ID_FOR_35B export IRIS_EVAL_LOGlogs/iris_35b_trace.jsonl python iris_eval_with_taotoken.py export TAOTOKEN_MODELYOUR_MODEL_ID_FOR_397B export IRIS_EVAL_LOGlogs/iris_397b_trace.jsonl python iris_eval_with_taotoken.py这里再次强调模型 ID 不能编造。Iris 是开源权重但你在评测脚本里调用的远端模型服务是什么 ID必须以 TaoToken 控制台或模型详情页为准。把模型 ID 写成环境变量是为了让 35B 和 397B 的评测入口保持一致而不是让你去猜一个不存在的名称。改完脚本后先不要跑完整评测集。挑一条最小样本只跑search_planning和answer_summary两个阶段确认logs/iris_eval_trace.jsonl能正常写入。这个日志文件后面会和 Iris 原始评测输出做对照用来判断“结果差异是模型能力问题还是接口配置问题”。4. Claude Code / Codex / CC Switch 三套配置用 TaoToken 辅助读评测代码本地评测 Iris 时除了直接运行 Python 脚本很多人还会用 Claude Code 或 Codex 来阅读仓库、对比日志、生成排障步骤。这些工具本身不替代 Iris 评测但它们会帮你更快定位base_url被写死在哪个文件、usage字段在哪个日志里、不同阶段的 prompt 模板放在哪里。为了让这些辅助工具也走同一套模型入口需要分别配置不要混用 Anthropic 和 OpenAI 风格的变量。4.1 Claude Code用 settings.json 配置 ANTHROPIC_* 变量Claude Code 的配置走settings.json使用ANTHROPIC_*环境变量。下面是一个示例把 Base URL 指向 TaoTokenKey 使用YOUR_API_KEY模型 ID 使用你从控制台复制的值。{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: YOUR_MODEL_ID } }放置到 Claude Code 读取的配置位置后重开终端或重启 Claude Code。你可以让它先执行一个简单任务例如“列出当前仓库里所有包含 base_url 的文件”。如果它正常返回说明 Claude Code 已经通过 TaoToken 访问模型服务。更详细的 Claude Code 接入说明可以看文末的 Claude Code 文档链接。4.2 Codex用 config.toml不要套 ANTHROPIC_*Codex 的配置走config.toml它和 Claude Code 的变量体系不同。不要把ANTHROPIC_*写到 Codex 配置里否则会出现鉴权失败或模型提供方识别错误。下面是一个 OpenAI 兼容风格的配置示例。model YOUR_MODEL_ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY对应环境变量export TAOTOKEN_API_KEYYOUR_API_KEYCodex 启动后同样先用一个读文件任务验证。例如让它读取iris_eval_with_taotoken.py然后告诉你base_url出现在哪一行。验证通过后再用它辅助分析 Iris 评测日志。这里的关键是Claude Code 用ANTHROPIC_*Codex 用config.toml里的model_providers两套配置不要交叉复制。4.3 CC Switch 三件套供应商、Key、模型如果你用 CC Switch 管理多个配置建议只维护三件套供应商 Base URLhttps://taotoken.net/apiAPI KeyYOUR_API_KEY默认模型YOUR_MODEL_ID切换配置后重启终端或重新加载对应工具确保环境变量已经生效。可以用下面命令检查当前 shell 里是否还存在旧变量env | grep -E TAOTOKEN|ANTHROPIC|OPENAI | sort如果同时出现旧供应商的OPENAI_BASE_URL、OPENAI_API_KEY优先清理掉避免 Python 脚本读取到错误值。特别是OPENAI_BASE_URL它可能覆盖你在代码里写的base_url导致日志里记录的地址和实际请求地址不一致。5. 跑评测命令与日志对照定位搜索规划 / 答案汇总的 Token 消耗配置完成后开始跑最小评测。假设你已经把 Iris 仓库克隆到本地并且已经安装了依赖。不要一上来就跑完整测试集先用两条任务验证链路。mkdir -p logs export TAOTOKEN_API_KEYYOUR_API_KEY export TAOTOKEN_BASE_URLhttps://taotoken.net/api export TAOTOKEN_MODELYOUR_MODEL_ID export IRIS_EVAL_LOGlogs/iris_eval_trace.jsonl python iris_eval_with_taotoken.py执行后查看日志cat logs/iris_eval_trace.jsonl你会看到类似下面的 JSONL 结构。这里的内容是示例实际值以你的请求为准。{stage:search_planning,model:YOUR_MODEL_ID,base_url:https://taotoken.net/api,latency_ms:1832,prompt_tokens:356,completion_tokens:128,total_tokens:484,content:1. 搜索 Iris 仓库的 eval 目录2. 定位 base_url3. 替换为 TaoToken。} {stage:answer_summary,model:YOUR_MODEL_ID,base_url:https://taotoken.net/api,latency_ms:2210,prompt_tokens:512,completion_tokens:203,total_tokens:715,content:将 base_url 设置为 https://taotoken.net/api使用 YOUR_API_KEY运行评测命令。}接着把这份日志和 Iris 原始评测输出做对照。对照时至少看四个字段stage确认是search_planning还是answer_summary。total_tokens确认 Token 消耗集中在哪个阶段。latency_ms确认延迟是否因为长 prompt 或模型切换而升高。content确认返回内容是否为空、是否被截断、是否包含多余格式。如果你有原始的 Iris 评测结果文件例如iris_eval_results.jsonl可以用 Python 做一次简单聚合把每个阶段的 Token 消耗汇总出来。import json from collections import defaultdict stats defaultdict(lambda: {calls: 0, total_tokens: 0, latency_ms: 0}) with open(logs/iris_eval_trace.jsonl, r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue row json.loads(line) stage row[stage] stats[stage][calls] 1 stats[stage][total_tokens] row.get(total_tokens, 0) stats[stage][latency_ms] row.get(latency_ms, 0) for stage, item in stats.items(): avg_tokens item[total_tokens] / max(item[calls], 1) avg_latency item[latency_ms] / max(item[calls], 1) print(f{stage}: calls{item[calls]} total_tokens{item[total_tokens]} avg_tokens{avg_tokens:.1f} avg_latency_ms{avg_latency:.1f})对照日志时常见现象有三种第一种search_planning的completion_tokens明显高于answer_summary。这通常说明规划阶段生成了较长的搜索步骤或者 prompt 里带了过多历史信息。可以缩减规划阶段的上下文只保留当前用户问题和必要工具说明。第二种answer_summary的prompt_tokens很高。这通常是因为汇总阶段把全部检索结果拼进了上下文。可以改成先截断、再摘要或者分批汇总。第三种两个阶段都报 429。这说明并发太高或请求频率超过限制。不要直接加并发先加退避重试把评测任务串行化。下面是一个简单的重试封装示例。import time from openai import OpenAI, APIConnectionError, APIStatusError client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.environ.get(TAOTOKEN_BASE_URL, https://taotoken.net/api), ) def create_chat_completion_with_retry(messages, model, max_retries3): last_error None for attempt in range(max_retries): try: return client.chat.completions.create( modelmodel, messagesmessages, temperature0, ) except (APIConnectionError, APIStatusError) as e: last_error e wait 2 ** attempt print(frequest failed, retry in {wait}s: {e}) time.sleep(wait) raise last_error把重试封装用到评测脚本里日志中也要记录第几次重试成功。否则你只看到最终结果无法判断评测耗时是否被重试拉长。6. 常见报错与排查清单接入 TaoToken 跑 Iris 评测时问题通常集中在 Key、Base URL、模型名、环境变量和并发五个位置。下面按报错现象列排查顺序。401 Unauthorized / 403 Forbidden优先检查 Key。执行echo ${TAOTOKEN_API_KEY} | wc -c如果长度明显不对说明变量为空或没有生效。确认 Key 没有空格、换行确认请求头是Authorization: Bearer ${TAOTOKEN_API_KEY}。如果脚本里同时存在OPENAI_API_KEY检查是否被旧变量覆盖。404 Not Found检查base_url。正确值是https://taotoken.net/api不要在代码里再拼/v1。如果你用curl测试路径应该基于 OpenAI SDK 的习惯不要手工拼错。若仍然 404把请求完整 URL 打印出来和日志里的base_url对照。模型不存在 / model not found回到 TaoToken 控制台复制模型 ID。不要写iris-397b这种猜测值除非控制台确实提供这个名称。把它放进环境变量export TAOTOKEN_MODELYOUR_MODEL_ID然后重新运行最小对话请求。只有最小请求通过才继续跑 Iris 评测。429 Too Many Requests降低并发把评测任务改成串行或者加入指数退避。不要通过增加更多 Key 来绕过限制这会让日志和结果更不可复现。重试后如果仍然 429先只跑search_planning暂时不跑answer_summary确认是频率问题还是单次请求过大。请求超时Search Agent 的答案汇总阶段 prompt 可能很长。先设置合理超时再检查是否可以把检索结果分批传入。超时日志里要记录stage和latency_ms否则你不知道是规划阶段慢还是汇总阶段慢。日志里的 base_url 和实际请求不一致检查是否存在OPENAI_BASE_URL等全局环境变量。执行env | grep -E BASE_URL|API_KEY|MODEL | sort清理掉旧供应商变量后重新打开终端。最稳的方式是在评测脚本启动时打印一次最终配置但不要打印完整 Key只打印前几位和后几位。Claude Code 或 Codex 无法连接Claude Code 检查settings.json里的ANTHROPIC_BASE_URL、ANTHROPIC_AUTH_TOKEN、ANTHROPIC_MODEL。Codex 检查config.toml里的model_provider、base_url、env_key。不要在两套配置之间复制变量名。CC Switch 切换后重启工具确保新配置被读取。7. 可复现记录模板与文末 CTA当最小评测跑通后建议把每次 Iris 评测记录成统一模板。这样 35B 和 397B 的结果可以直接对比也能在换机器或换时间后复现。下面是一个 JSON 记录模板字段只保留可核实的信息。{ experiment: iris_search_agent_local_eval, model_scale: 35B_or_397B, model_id: YOUR_MODEL_ID, base_url: https://taotoken.net/api, key_placeholder: YOUR_API_KEY, stages: [search_planning, answer_summary], log_file: logs/iris_eval_trace.jsonl, notes: 记录命令、时间、重试次数、异常现象 }对应的目录结构可以保持简单iris-eval/ ├── iris_eval_with_taotoken.py ├── logs/ │ ├── iris_35b_trace.jsonl │ └── iris_397b_trace.jsonl └── README.local.md在README.local.md里写清楚三件事你用的模型 ID、base_url是https://taotoken.net/api、Key 通过环境变量注入。不要把YOUR_API_KEY替换成真实 Key 后提交。每次评测前先跑一次最小连通性请求再跑完整任务。这样即使评测结果有波动你也能先排除接口配置问题。如果你还没有 Key或者想先验证模型对话是否可用可以按下面的路径操作先打开 TaoToken 模型对话发一条最小请求确认模型服务可用。如果你日常还要用 Claude Code、Codex 等工具辅助读 Iris 仓库和日志可以看 Coding Plan。到 API Keys 创建 Key并用YOUR_API_KEY占位符写入本地环境变量。配置 Claude Code 时参考 Claude Code 文档注意 Claude Code 用ANTHROPIC_*Codex 用config.toml不要混用。更多模型接入方式和控制台入口可以回到 TaoToken 官网 查看。把 Iris 评测脚本里的base_url统一成https://taotoken.net/api用YOUR_API_KEY注入鉴权记录每个阶段的 token 用量再对照日志排查搜索规划与答案汇总的差异这样本地评测才有可复现的基础。