1. openclaw 图片输入报错的真实场景与排查起点
如果你正在用 openclaw 接本地大模型,并且已经跑通了纯文本对话,那么下一步大概率会踩到图片上传这个坑。我自己在把 llama.cpp 启动的 qwen3.5 多模态模型接进 openclaw gateway 时,就遇到了一个很典型的报错:
parseMessageWithAttachments: 1 attachment(s) dropped — model does not support images这句话翻译过来就是:附件被丢弃了,因为模型不支持图片。但问题是,我本地跑的 qwen3.5 明明是支持图片输入的多模态模型,用 open-webui 连接同一个 llama-server 时,上传图片完全正常。这说明模型本身没问题,问题出在 openclaw 这一层的配置上。
openclaw 是一个开源的 AI 网关/代理工具,它的核心作用是统一管理多个模型 provider,让前端(比如 gateway 的聊天页面、各种客户端)通过一个标准接口去调用不同的后端模型。它支持 OpenAI 兼容接口、Anthropic 接口等多种协议,也支持自定义 provider。对于本地大模型玩家来说,openclaw 的价值在于:你不需要在每个客户端里单独配置本地模型的地址和参数,只要在 openclaw 里配一次,所有接入 openclaw 的客户端都能用。
但 openclaw 对多模态能力的判断,不是自动探测的,而是依赖配置文件里显式声明的input字段。如果你在 provider 的模型定义里没有写"image",openclaw 就会认为这个模型只支持文本,上传图片时直接丢弃附件,然后抛出上面那个报错。这就是问题的根源。
这个场景适合几类人:一是已经在本地用 llama.cpp、ollama 或其他方式跑起了多模态模型,想通过 openclaw 统一管理的开发者;二是希望把本地模型和云端模型混用,用一个网关统一调度的人;三是遇到了图片上传报错,想搞清楚 openclaw 配置逻辑的人。接下来我会从环境准备、endpoint 配置、图片输入参数、验证请求、报错排查几个方面,把整条链路讲清楚。
2. TaoToken 前置准备:统一通道与鉴权配置
在动手改 openclaw 配置之前,先把 TaoToken 这一层准备好。TaoToken 在这里扮演的角色是一个统一的 API 通道,你可以把它理解成一个“模型调用的统一入口”。它的好处是:不管你后端接的是本地 llama.cpp 还是其他模型服务,前端只需要认 TaoToken 的 endpoint 和 Key,切换后端时不用改客户端配置。
首先你需要拿到 API Key。访问 TaoToken 的 API Keys 管理页面:
https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite在这个页面创建一个新的 Key,复制保存好。这个 Key 后面会填到 openclaw 的 provider 配置里,作为apiKey字段的值。注意不要把它提交到公开仓库,建议用环境变量或者本地配置文件管理。
TaoToken 的 API 基础地址是:
https://taotoken.net/api这个地址不加 UTM 参数,直接作为 Base URL 使用。如果你用的是 OpenAI 兼容协议,那么完整的请求路径就是https://taotoken.net/api/v1/chat/completions。openclaw 在配置 provider 时,baseUrl填https://taotoken.net/api即可,openclaw 会自动拼接后续路径。
关于模型 ID,你需要在 TaoToken 的模型列表里确认你要用的模型名称。如果你是把本地模型通过 TaoToken 转发,那么模型 ID 就是你本地服务注册时用的名称。如果你直接用 TaoToken 提供的云端模型,模型 ID 以文档里的为准。接入文档在这里:
https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite如果你只是想先验证一下模型对话是否正常,可以打开模型对话页面直接测试:
https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite在这个页面里选好模型,发一条带图片的消息,看看返回是否正常。这一步的目的是确认 TaoToken 通道本身没问题,把问题范围缩小到 openclaw 配置层。
如果你后续要做长期的编码任务或者 Agent 开发,可以考虑 Coding Plan:
https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite这个计划适合需要频繁调用模型、跑自动化任务的场景。不过对于本篇的图片输入配置来说,先用按量计费的 Key 就够了。
准备好 Key 和 Base URL 之后,接下来就是改 openclaw 的配置文件。openclaw 的配置分两层:一层是 provider 级别的配置,通常在openclaw.json或者.openclaw/agents/main/agent/models.json里;另一层是模型级别的配置,需要显式声明input支持的类型。下面我会给出完整的配置片段。
3. 可复制配置:openclaw.json 与 models.json 的 endpoint 与图片参数
openclaw 的配置文件位置通常在用户目录下的.openclaw文件夹里。具体路径取决于你的安装方式,常见的位置是:
~/.openclaw/openclaw.json ~/.openclaw/agents/main/agent/models.json这两个文件的分工是:openclaw.json管 provider 的注册和全局设置,models.json管具体 agent 用哪些模型、模型的参数是什么。图片输入的支持声明,主要写在models.json的 provider 配置里。
先看openclaw.json里的 provider 配置。如果你是通过 onboard 命令添加的 provider,openclaw 会自动生成一段配置。你需要确认baseUrl指向 TaoToken 的 API 地址,api字段是openai-completions,apiKey填你从 TaoToken 拿到的 Key。一个完整的 provider 配置片段如下:
{ "providers": { "taotoken": { "baseUrl": "https://taotoken.net/api", "api": "openai-completions", "apiKey": "sk-你的TaoToken密钥", "models": [ { "id": "qwen3.5-35b-a3b", "name": "Qwen3.5 35B A3B", "input": ["text", "image"], "contextWindow": 131072, "maxTokens": 8192 } ] } } }这里的关键字段是input。它是一个数组,声明这个模型支持哪些输入类型。只写["text"]就是纯文本模型,加上"image"才支持图片输入。很多人踩坑就是因为这里只写了text,或者根本没写input字段,openclaw 默认按纯文本处理,上传图片时直接丢弃。
如果你用的是本地 llama.cpp 启动的模型,并且希望通过 TaoToken 转发,那么baseUrl仍然填 TaoToken 的地址,模型 ID 填你在 TaoToken 里注册的本地模型名称。如果你直接连本地 llama-server,不走 TaoToken,那么baseUrl填http://127.0.0.1:8080,apiKey填"local"或者任意非空字符串。但本篇的重点是统一走 TaoToken 通道,所以推荐用上面的配置。
接下来看models.json里的 agent 配置。这个文件决定了 main agent 用哪个 provider 的哪个模型。一个完整的配置片段如下:
{ "agents": { "main": { "model": "taotoken/qwen3.5-35b-a3b", "providers": { "taotoken": { "baseUrl": "https://taotoken.net/api", "api": "openai-completions", "apiKey": "sk-你的TaoToken密钥", "models": [ { "id": "qwen3.5-35b-a3b", "name": "Qwen3.5 35B A3B", "input": ["text", "image"], "contextWindow": 131072, "maxTokens": 8192 } ] } } } } }注意model字段的格式是provider名/模型ID。这里的taotoken就是上面 providers 里的 key,qwen3.5-35b-a3b是模型 ID。两者必须对应上,否则 openclaw 找不到模型。
如果你之前用的是本地 provider,比如llama-cpp,那么配置可能是这样的:
{ "providers": { "llama-cpp": { "baseUrl": "http://127.0.0.1:8080", "api": "openai-completions", "apiKey": "local", "models": [ { "id": "qwen3.5-35b-a3b", "name": "Qwen3.5 35B A3B", "input": ["text", "image"], "contextWindow": 131072, "maxTokens": 8192 } ] } } }这个配置里apiKey填的是"local",因为本地 llama-server 通常不校验 Key。但如果你要走 TaoToken 通道,就把baseUrl改成https://taotoken.net/api,apiKey改成你的 TaoToken Key,provider 名字改成taotoken。
改完配置后,需要重启 openclaw gateway 让配置生效。重启命令取决于你的启动方式,如果是用 systemd 管理的,执行:
systemctl --user restart openclaw-gateway如果是手动启动的,先 Ctrl+C 停掉,再重新运行启动命令。重启后打开 gateway 的聊天页面,尝试上传一张图片。如果配置正确,图片不会再被丢弃,模型会正常接收并处理。
还有一个容易忽略的点:llama.cpp 启动时必须带上mmproj参数,否则模型本身不具备图片编码能力。启动命令参考:
llama-server -fa on -t 8 \ -ngl 99 \ -c 131072 \ -mm /path/to/mmproj-BF16.gguf \ -m /path/to/Qwen3.5-35B-A3B-UD-IQ3_XXS.gguf-mm指定多模态投影文件,没有这个文件,模型只能处理文本。这个参数和 openclaw 的配置是两回事:llama.cpp 负责让模型具备图片编码能力,openclaw 负责让网关知道这个模型支持图片输入。两者都配好,图片输入链路才能通。
4. 验证请求:发送带图请求与返回结果对照
配置改完之后,不要急着在 gateway 页面里点来点去,先用命令行发一个带图片的请求,确认整条链路是通的。这样出问题时容易定位是配置问题还是前端问题。
TaoToken 的 API 兼容 OpenAI 的 chat completions 格式,图片输入用的是image_url类型的内容块。一个完整的 curl 请求如下:
curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer sk-你的TaoToken密钥" \ -H "Content-Type: application/json" \ -d '{ "model": "qwen3.5-35b-a3b", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "这张图片里有什么?请描述主要物体和颜色。" }, { "type": "image_url", "image_url": { "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..." } } ] } ], "max_tokens": 512 }'如果你不想用 base64,也可以传图片的公开 URL:
{ "type": "image_url", "image_url": { "url": "https://example.com/test-image.png" } }但注意,如果图片在本地,必须转成 base64 或者用可访问的 URL。本地文件路径直接填进去,模型是读不到的。
发送请求后,正常的返回结果应该包含模型对图片的描述。返回结构大致如下:
{ "id": "chatcmpl-xxx", "object": "chat.completion", "created": 1712345678, "model": "qwen3.5-35b-a3b", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "这张图片里有一只橘色的猫,趴在灰色的沙发上,背景是白色的墙壁..." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 1024, "completion_tokens": 128, "total_tokens": 1152 } }如果你收到的返回里content是空的,或者返回了类似model does not support images的错误,说明配置还没生效。这时候先检查models.json里的input字段是否包含"image",再检查 openclaw gateway 是否重启过。
验证通过后,再回到 openclaw gateway 的聊天页面,上传同一张图片,看看返回是否一致。如果命令行通了但页面不通,问题可能出在 gateway 的前端配置或者 agent 的模型选择上。检查 gateway 当前使用的 agent 是不是 main,main agent 的 model 是不是指向了正确的 provider。
还有一个验证技巧:在 openclaw 的日志里搜索parseMessageWithAttachments。如果这个报错消失了,说明图片附件已经被正确传递。如果还在报,说明配置没生效或者改错了文件。openclaw 的日志通常在~/.openclaw/logs/目录下,可以用tail -f实时查看:
tail -f ~/.openclaw/logs/gateway.log | grep -i attachment这个命令会过滤出和附件相关的日志行,方便你确认图片是否被正确处理。
5. 本篇常见错排查:401、local proxy failed、reading choices 与 OAuth
配置过程中最容易遇到的几个报错,我逐个拆解一下原因和排查路径。
401 Unauthorized
这个报错说明鉴权失败。如果你走的是 TaoToken 通道,检查apiKey字段是否填了正确的 Key,Key 是否过期,请求头里的Authorization格式是否是Bearer sk-xxx。如果你走的是本地 llama-server,apiKey填"local"通常不会报 401,但如果 llama-server 启动时加了--api-key参数,就需要填对应的值。还有一种情况是 openclaw 的 provider 配置里apiKey字段为空字符串,openclaw 可能不会发送 Authorization 头,导致 401。
local proxy failed
这个报错通常出现在 openclaw 尝试连接本地服务但连不上的时候。检查baseUrl是否写对,本地 llama-server 是否在运行,端口是否被占用。如果你把baseUrl改成了 TaoToken 的地址,但本地服务没启动,openclaw 不会报这个错,因为它连的是 TaoToken。反过来,如果你以为自己在走 TaoToken,但配置里baseUrl还是http://127.0.0.1:8080,而本地服务挂了,就会报 local proxy failed。排查方法是先用 curl 直接请求baseUrl,确认服务可达。
reading choices 报错
这个报错通常是 openclaw 在解析模型返回时,发现返回结构里没有choices字段,或者choices是空的。原因可能是模型返回了错误信息而不是正常的 completion 结构,也可能是api字段配错了。比如你把api写成了openai-completions,但实际后端用的是 Anthropic 协议,返回结构不匹配,就会报这个错。检查api字段是否和后端协议一致。TaoToken 的 OpenAI 兼容接口用openai-completions,Anthropic 接口用对应的协议名。
OAuth 相关报错
如果你在 openclaw 里配置了需要 OAuth 的 provider,但 OAuth 流程没走完或者 token 过期,会报 OAuth 错误。对于本地模型和 TaoToken 的 API Key 方式,通常不涉及 OAuth。如果你同时配了多个 provider,检查当前 agent 用的是哪个,别把 OAuth provider 和 API Key provider 搞混了。
图片仍然被丢弃
如果配置里input已经加了"image",但图片还是被丢弃,检查以下几点:一是models.json和openclaw.json里的 provider 配置是否一致,openclaw 可能读的是其中一个;二是模型 ID 是否匹配,model字段里的 ID 和models数组里的id必须完全一致;三是 openclaw 版本是否有变化,某些版本对input字段的解析逻辑可能不同,可以查看对应版本的文档或源码。
Codex auth.json 相关
如果你在用 Codex 或者类似的工具,并且配置了auth.json,注意auth.json里的 Base URL 和 Key 要和 openclaw 里的配置保持一致。三件套是:Base URL 填https://taotoken.net/api,Key 填 TaoToken 的 Key,Model ID 填你要用的模型名称。这三者缺一不可,任何一个不对都会导致请求失败。
排查的时候,建议按这个顺序:先用 curl 直接请求 TaoToken 的 API,确认通道本身没问题;再检查 openclaw 的配置文件,确认baseUrl、apiKey、api、input四个字段;最后重启 gateway,看日志里parseMessageWithAttachments是否消失。这样一层层缩小范围,比盲目改配置高效得多。
6. 统一通道后的模型调用与长期使用建议
把 openclaw 的 endpoint 改到 TaoToken 之后,最大的好处是配置统一了。以前你可能需要在 openclaw、open-webui、各种客户端里分别填本地模型的地址和端口,现在只需要认 TaoToken 一个入口。本地模型、云端模型、不同协议的模型,都可以通过 TaoToken 这一层来调度。切换模型时,改 openclaw 里的model字段就行,不用动其他客户端。
对于图片输入这个场景,核心就是两个地方:llama.cpp 启动时带mmproj,openclaw 配置里input加"image"。这两个都对了,图片链路就通了。如果后续要加新的多模态模型,比如支持视频或者音频的模型,也是同样的逻辑:在input数组里加上对应的类型声明,openclaw 就会把相应的附件传给模型。
长期使用的话,建议把配置拆成两部分:一部分是 provider 的通用配置,放在openclaw.json里;另一部分是 agent 的模型选择,放在models.json里。这样改模型的时候只动models.json,不会影响其他 agent。另外,TaoToken 的 Key 建议用环境变量管理,不要硬编码在配置文件里。openclaw 支持从环境变量读取apiKey,具体写法可以参考接入文档:
https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite如果你需要频繁调用模型做编码或者 Agent 任务,可以看看 Coding Plan 的额度:
https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite最后说一个实际经验:openclaw 的配置文件改动后,一定要重启 gateway,而且要用tail -f看日志确认配置加载成功。我遇到过改完配置但 gateway 没重启,折腾半天以为配置写错了的情况。日志里会打印当前加载的 provider 和模型列表,对照一下就能确认配置是否生效。图片输入链路通了之后,你可以在 gateway 页面里连续上传多张图片测试,看看上下文窗口是否够用,contextWindow和maxTokens这两个参数根据实际模型调整就行。