十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

Claude Code 配 TaoToken:排查 lm-evaluation-harness 跑 Qwen3.5-9B 的 0 分空输出

Claude Code 配 TaoToken:排查 lm-evaluation-harness 跑 Qwen3.5-9B 的 0 分空输出 ollama run qwen3.5:9b在 16G M1 Pro 上跑 Qwen3.5-9B 并不难难的是接上 lm-evaluation-harness 跑 GSM8K 和 DROP 之后Exact Match 直接 0.0模型输出空字符串Hugging Face 还时不时 Timeout。给 Claude Code 配 TaoToken 之前先去 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentclaude_code_lmeval 创建一把 Key后面用它让 Claude Code 读samples_*.jsonl和错误栈把空输出拆成接口类型、2048 Tokens 截断、停止词三类问题。整条链路里 Ollama 和 lm-eval 都不换TaoToken 只负责给 Claude Code 提供模型通道让它帮你对照日志改参数。16G M1 Pro 的内存不算宽裕Qwen3.5-9B 用 4-bit 量化跑推理可以但 lm-eval 的 few-shot 模板很长GSM8K 默认 5-shotDROP 的上下文也不短。如果只看终端最后一行Exact Match 0.0很容易误判成模型能力问题。真正的线索在--log_samples生成的 .jsonl 里在 Claude Code 读得到的resps、filtered_resps、target和错误栈里。下面按排障顺序来先复现空输出再配 Claude Code 的 TaoToken 通道最后回到 lm-eval 改接口类型、max tokens 和 stop 参数。1. 0 分空输出先别怪 Qwen3.5-9B拆开 GSM8K 与 DROP 的报错链1.1 16G M1 Pro 上的复现命令与两个典型现象先把本地链路跑起来。Ollama 拉起 Qwen3.5-9B确认 OpenAI 兼容端点有响应再让 lm-evaluation-harness 通过local-completions或local-chat-completions去请求。常见命令大致是这样模型名和 tokenizer 按你本地实际情况替换ollama run qwen3.5:9b另开一个终端确认端点curl http://localhost:11434/v1/models如果这里返回模型列表说明 Ollama 的兼容层已经起来。接着跑 lm-eval一开始很多人会写成lm_eval \ --model local-completions \ --model_args base_urlhttp://localhost:11434/v1,modelqwen3.5:9b,tokenizerYOUR_TOKENIZER_PATH_OR_NAME \ --tasks gsm8k,drop \ --num_fewshot 5 \ --batch_size 1 \ --output_path ./logs/qwen35_9b_ollama \ --log_samples跑完看到两个典型现象一是 Hugging Face 数据集下载超时任务还没开始就退出二是任务跑完了但 Exact Match 0.0打开 .jsonl 发现resps是空字符串。前者是数据集获取问题后者是请求或生成配置问题不要混在一起查。1.2 Hugging Face Timeout 与空字符串不是同一类错Hugging Face Timeout 通常发生在 lm-eval 首次拉取 GSM8K、DROP 数据集时。如果本地~/.cache/huggingface/datasets已经有缓存可以先用离线模式确认HF_DATASETS_OFFLINE1 HF_HUB_OFFLINE1 lm_eval \ --model local-chat-completions \ --model_args base_urlhttp://localhost:11434/v1,modelqwen3.5:9b,tokenizerYOUR_TOKENIZER_PATH_OR_NAME \ --tasks gsm8k,drop \ --num_fewshot 5 \ --batch_size 1 \ --output_path ./logs/qwen35_9b_ollama_offline \ --log_samples离线模式能跑通说明数据集不是主要矛盾空输出另有原因。空字符串一般来自三种情况请求打到了错误的端点prompt 被 2048 Tokens 截断或者 stop 序列把答案开头直接切掉。这三种都会让resps看起来像模型什么都没说但日志里的doc、filtered_resps、target会留下不同痕迹。注意不要因为空输出就把 Qwen3.5-9B 换成更大的模型。16G M1 Pro 能跑动 9B 量化版已经不容易先把请求格式对齐更划算。2. 让 Claude Code 读 .jsonl把 lm-evaluation-harness 日志变成排查线索2.1 --log_samples 生成的 samples_*.jsonl 里看哪几个字段--log_samples会在输出目录下生成samples_gsm8k_*.jsonl和samples_drop_*.jsonl。每行是一条样本重点看四个字段doc原始题目里面的question和answer能判断 prompt 有多长。filtered_resps实际送给模型的 prompt 或对话消息。如果是 chat 端点这里可能是消息数组。resps模型返回的文本。空字符串就是最直接的 0 分信号。target标准答案。GSM8K 常见形式是#### 数字DROP 是短答案。先不要急着改参数把前 10 条 .jsonl 片段交给 Claude Code。让它做统计而不是让它替你跑评测。Claude Code 可以读本地文件、解释 JSON、对照错误栈但lm_eval命令仍然由你在本地终端执行再把输出贴回对话。2.2 给 Claude Code 的提示词不要写“帮我跑评测”更有效的提示词是限制它只做日志分析读取 ./logs/qwen35_9b_ollama_chat/samples_gsm8k_*.jsonl 的前 10 条记录。 统计 resps 为空字符串的条数。 对每条记录输出 doc.question 的字符数、filtered_resps 的字符数、target 的值。 不要执行 lm_eval不要改文件只根据日志判断 1) 空输出是否集中在长 prompt 样本 2) filtered_resps 里是否出现了聊天模板多余的特殊 token 3) target 是否被 stop 序列提前截断。Claude Code 接上 TaoToken 之后消耗 Token 去读这些 .jsonl 和错误栈比你手动翻几十条记录快得多。它给出的结论不一定全对但能把“空输出”缩小到几个可验证的假设。下一步就是让它对照假设改 lm-eval 的接口类型、max tokens 和 stop 参数。3. 把 Claude Code 接到 TaoTokensettings.json 与最小验证3.1 创建 Key 与模型 ID 以模型广场为准TaoToken 在这里的角色很明确给 Claude Code 提供统一 API 通道。打开 TaoToken 官网 注册并创建 API KeyKey 用占位符YOUR_API_KEY表示。模型 ID 不要凭记忆写去模型广场看当时列表以页面显示为准。填进 Claude Code 的 Base URL 固定用https://taotoken.net/api末尾不要加/v1。提示官网落地页只用来注册、创建 Key、看模型广场和用量真正填进工具的是https://taotoken.net/api。两者不要混。3.2 ~/.claude/settings.json 的 env 写法Claude Code 可以通过环境变量读取 Anthropic 兼容配置也可以写进~/.claude/settings.json的env字段。文件内容像这样{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: YOUR_MODEL_ID } }保存后重开终端或重启 Claude Code让环境变量生效。如果你更喜欢在 shell 里临时导出export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_AUTH_TOKENYOUR_API_KEY export ANTHROPIC_MODELYOUR_MODEL_ID3.3 可选 CLItaotoken cc 直接拉起 Claude Code如果不想手动改 settings.json也可以用 TaoToken CLI。它适合在终端里快速切换 Key 和模型npm install -g taotoken/taotoken taotoken cc -k YOUR_API_KEY -u https://taotoken.net/api -m YOUR_MODEL_ID注意-u后面只写https://taotoken.net/api不要加/v1也不要加任何查询参数。CLI 只是帮你把 Claude Code 的环境变量指过去Ollama 和 lm-eval 完全不受影响。3.4 发一条最小请求确认通道配置改完先在 Claude Code 里发一条最小请求比如输入“只回复 OK”。返回 OK说明 Key、Base URL、模型 ID 三者至少能通。如果返回 401先检查ANTHROPIC_AUTH_TOKEN是不是还留着YOUR_API_KEY如果返回 404检查ANTHROPIC_BASE_URL是不是误写成了https://taotoken.net/api/v1。通道不通就不要急着查 lm-eval先把 Claude Code 的请求调通。4. 回到 lm-eval/v1/chat/completions 与文本续写错位4.1 local-completions 与 local-chat-completions 的区别Ollama 的 OpenAI 兼容层通常提供/v1/chat/completions它接收的是 messages 数组而 lm-eval 的local-completions默认走文本续写思路把 prompt 当成一段纯文本发给/v1/completions。两者错位时Ollama 可能收到不符合预期的 payload返回空内容或直接报错。表现就是任务跑完、请求有记录但resps是空字符串。4.2 改写 lm_eval 命令为 chat 模型如果确认 Ollama 暴露的是 chat 端点lm-eval 侧应改用local-chat-completions并让base_url指向http://localhost:11434/v1。示例命令lm_eval \ --model local-chat-completions \ --model_args base_urlhttp://localhost:11434/v1,modelqwen3.5:9b,tokenizerYOUR_TOKENIZER_PATH_OR_NAME \ --tasks gsm8k,drop \ --num_fewshot 5 \ --batch_size 1 \ --gen_kwargs max_gen_toks512 \ --output_path ./logs/qwen35_9b_ollama_chat \ --log_samples改完再跑同一批任务观察resps是否开始出现正常文本。如果仍然为空继续看下一节的 2048 Tokens 和停止词。把新日志片段贴给 Claude Code让它对比两次运行的filtered_resps通常能看出端点类型改对了没有。5. 2048 Tokens 截断Ollama num_ctx 与 lm-eval max_gen_toks 要一起看5.1 Ollama Modelfile 把 num_ctx 拉到 8192Ollama 默认上下文窗口可能只有 2048 Tokens。GSM8K 的 5-shot prompt 加上 DROP 的长文档很容易超过这个数。prompt 被截断后模型看到的题目不完整输出空字符串或无关内容。用 Modelfile 建一个更大上下文的变体FROM qwen3.5:9b PARAMETER num_ctx 8192 PARAMETER num_predict 512然后创建并运行ollama create qwen3.5:9b-8k -f Modelfile ollama run qwen3.5:9b-8klm-eval 里的model参数也要跟着改成qwen3.5:9b-8k。这一步不替换 Ollama只是把本地模型的上下文设置调大。5.2 lm-eval 的 max_gen_toks 不要留默认值赌运气生成侧也有上限。lm-eval 可以用--gen_kwargs max_gen_toks512给 GSM8K 和 DROP 留出足够的推理步数。太小会导致模型刚写到关键步骤就被切断resps看起来不完整甚至为空。建议先设 512再根据 .jsonl 里resps的长度调整。注意max_gen_toks不是越大越好16G M1 Pro 上生成越长越慢先保证答案能写完。5.3 用 Claude Code 对照 .jsonl 判断是 prompt 截断还是生成截断把新旧两份 .jsonl 的前 10 条贴给 Claude Code提示它对比filtered_resps的字符数和resps的长度。如果filtered_resps在旧日志里明显更短说明 prompt 被截断如果 prompt 完整但resps很短且没有结束标点说明生成上限或 stop 序列在捣乱。Claude Code 只做判断和给出修改建议ollama create和lm_eval仍由你在本地执行。6. Answer: 与 Question: 停止词陷阱GSM8K 和 DROP 的 stop 不能乱加6.1 为什么把 Answer: 加进 stop 会让答案变空GSM8K 的答案格式通常包含#### 数字有些模板会引导模型输出Answer:。如果你为了“干净”把Answer:加进 stop 序列模型刚说出Answer:就被截断后面的数字一个都留不下。DROP 里也可能出现Question:或Answer:开头的格式误加 stop 会让resps变成空字符串。表面看是模型不输出实际是停止词把输出掐掉了。6.2 正确做法保留任务模板只加换行或模型结束符先不要在--gen_kwargs里硬塞untilAnswer:。让 lm-eval 使用任务自带的模板和默认停止条件只通过max_gen_toks限制长度。如果确实需要停优先用换行或模型自己的结束符不要用题目里要求模型写出的关键词。改完命令像这样lm_eval \ --model local-chat-completions \ --model_args base_urlhttp://localhost:11434/v1,modelqwen3.5:9b-8k,tokenizerYOUR_TOKENIZER_PATH_OR_NAME \ --tasks gsm8k,drop \ --num_fewshot 5 \ --batch_size 1 \ --gen_kwargs max_gen_toks512 \ --output_path ./logs/qwen35_9b_ollama_no_stop \ --log_samples6.3 改完再跑一次看 Exact Match 是否变化重新跑 GSM8K 和 DROP然后打开新的samples_*.jsonl。如果resps里开始出现完整的推理和最终数字Exact Match 即使不高也不会再是 0.0 空输出。把新日志给 Claude Code让它统计resps非空比例、平均长度和被截断的比例。到这里接口类型、2048 Tokens、停止词三条线基本能分清。TaoToken 负责的是 Claude Code 读日志、改脚本这一侧不参与 Ollama 本地推理。7. 跑通之后去控制台对一下这次调用7.1 在模型对话里用同一把 Key 复测Claude Code 能正常返回之后去 TaoToken 模型对话 用同一把 Key 发一条测试消息确认模型 ID 和 Base URL 没填错。这一步和 lm-eval 的本地评测互不干扰只是为了确认 Claude Code 消耗 Token 的通道稳定。如果你在 .jsonl 分析里换了模型也顺便在模型广场确认该模型 ID 仍然可用。7.2 看 Coding Plan 与创建 Key如果你准备长期用 Claude Code 分析评测日志、改 lm-eval 脚本可以打开 Coding Plan 看套餐是否够用。Key 仍然在 控制台 API Keys 创建和轮换Claude Code 的环境变量对照可以看 Claude Code 接入文档。回到你刚跑完的那次 lm-eval如果 Claude Code 侧有调用记录说明整条排查链路已经闭环如果记录为空先回头检查ANTHROPIC_BASE_URL是否还是https://taotoken.net/api而不是带/v1或其他路径。
返回列表