Qwen3-235B与OpenClaw协议对齐实战:Tool Calling结构化解析方案

发布时间:2026/6/21 8:22:09
Qwen3-235B与OpenClaw协议对齐实战:Tool Calling结构化解析方案 1. 项目概述这不是一次简单的模型接入而是一场协议层的硬核对齐“我花几周把 Qwen3-235B 接入 OpenClaw踩了 22 个坑全记录在这里”——这个标题里藏着三个关键信号Qwen3-235B是当前开源大模型中参数量级最高、推理能力最强的中文基座之一OpenClaw不是普通 API 网关而是专为 Tool Calling 场景设计的轻量级智能体调度框架核心价值在于协议抽象与工具生命周期管理而“踩了 22 个坑”绝非夸张修辞它直指一个被多数教程刻意回避的事实Qwen3-235B 的原生输出格式、函数调用协议、流式响应结构与 OpenClaw 默认期望的OpenAI-compatible Tool Calling 协议存在系统性错位。这不是改几个 config 就能解决的适配问题而是从 tokenizer 输出解码、function call JSON Schema 校验、tool response 回传时机、到 streaming token 分块边界全链路需要重新锚定。我实际操作中发现OpenClaw 官方文档里那句“支持主流开源模型”的背后隐含着一个关键前提模型必须严格遵循{name: xxx, arguments: {...}}这一固定 schema且 arguments 字段必须是合法 JSON 字符串——而 Qwen3-235B 在tool_call模式下默认输出的是带缩进、含注释、甚至混有中文标点的“类 JSON”OpenClaw 的 JSON 解析器直接抛出JSONDecodeError: Expecting property name enclosed in double quotes。这第一个坑就卡住了整个流程。适合谁来看如果你正在用 Qwen3-235B 做本地智能体开发想接入飞书/微信/钉钉等平台做自动化服务或者正被 OpenClaw 的tool not found、invalid function call、streaming hang这类报错反复折磨这篇就是为你写的实战手记。它不讲大道理只记录每一个让 CPU 温度飙升的瞬间以及最终落地的、可直接复制粘贴的修复方案。2. 整体设计思路为什么不能“直接跑”而必须重写协议桥接层2.1 核心矛盾的本质Qwen3-235B 的 Tool Calling 是“语义驱动”OpenClaw 是“结构驱动”很多人以为接入大模型就是改个 model path换行命令的事。但当你真正把 Qwen3-235B 的qwen3-235b-instruct模型加载进 OpenClaw 后会立刻发现模型明明识别出了用户要查天气也生成了类似{name: get_weather, arguments: {\city\: \北京\}}的文本OpenClaw 却报错No tool named get_weather。问题不在模型也不在 OpenClaw 的 tool registry而在于两者对“函数调用指令”的理解范式完全不同。Qwen3-235B 的推理过程是语义优先的它先在内部构建一个工具调用意图再用自然语言生成一段“看起来像 JSON”的字符串作为输出而 OpenClaw 的设计哲学是结构优先它要求输出必须是语法绝对严谨、字段名和值都用双引号包裹、无任何多余空格或换行的纯 JSON 对象。这种差异不是风格问题而是工程实现层面的根本分歧。Qwen3-235B 的 tokenizer 在 decode 阶段会将\n、\t、中文逗号等字符原样输出而 OpenClaw 的json.loads()函数在解析时遇到中文引号“”或单引号就直接崩溃。我实测过Qwen3-235B 在温度0.1、top_p0.95 的严格设置下仍有约 17% 的 tool call 输出包含非法 JSON 字符——这个概率足以让一个生产环境的智能体服务每小时失败数次。所以绕过协议桥接层直接硬连等于在高速公路上用自行车轮胎跑F1赛道表面能动实则随时爆胎。2.2 为什么放弃“前端正则清洗”而选择重写 Output Parser初期我也试过最省事的方案在 OpenClaw 的model.py里加一段正则替换把中文引号换成英文引号删掉所有换行再用json.loads()强转。代码很短import re import json def clean_qwen_json(text): text re.sub(r“|”, , text) # 中文引号 text re.sub(r‘|’, , text) # 中文单引号 text re.sub(r\s, , text) # 多空格变单空格 text text.strip() return json.loads(text)但上线测试不到两小时就崩了。原因在于 Qwen3-235B 的输出存在一种“嵌套陷阱”当 arguments 里本身包含 JSON 字符串比如一个 base64 编码的图片模型会把它当成普通字符串处理导致外层 JSON 的引号被错误闭合。例如真实输出是{name: upload_image, arguments: {\image_data\: \data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...\}}正则清洗后变成{name: upload_image, arguments: {image_data: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...}}这已经不是 JSON而是语法错误的字符串。更致命的是Qwen3-235B 在流式输出streaming模式下会把一个完整的 JSON 对象切成多段 token 发送比如第一段是{name: get_weather, argu第二段是ments: {\city\: \北京\}}。正则清洗无法处理这种跨 chunk 的结构强行拼接会导致JSONDecodeError: Unterminated string starting at。因此必须放弃“文本后处理”的思路转向“协议层拦截结构化解析”的方案。我的最终设计是在 OpenClaw 的ModelAdapter类中插入一个专用的Qwen3ToolParser它不依赖json.loads()而是基于状态机state machine逐字符扫描输出流精准识别{、}、的匹配关系并在完整对象闭合时才触发解析。这个 parser 能容忍任意空白、中文标点、甚至部分缺失的字段只要核心结构完整就能提取出name和arguments。这才是真正鲁棒的解决方案。2.3 架构选型为什么选择“中间件式桥接”而非修改 OpenClaw 源码OpenClaw 的源码结构清晰理论上可以直接修改openclaw/core/model.py里的call_tool方法。但我没有这么做原因有三第一OpenClaw 是一个活跃更新的项目每次pip install --upgrade openclaw都会覆盖你的修改维护成本极高第二直接改源码会破坏其“开箱即用”的设计哲学后续给同事交接或部署到新服务器时极易遗漏 patch 文件第三也是最关键的一点Qwen3-235B 的协议问题不是孤立的它代表了一类“强语义、弱结构”模型的共性挑战。未来如果要接入 Yi-Coder、DeepSeek-Coder 等同样以自然语言生成为特色的模型你将面临几乎相同的协议错位。因此我选择了“中间件式桥接”的架构在 OpenClaw 的ModelAdapter和底层模型之间插入一个独立的Qwen3Bridge类。这个类完全遵循 OpenClaw 的接口规范generate,stream_generate对外暴露标准方法对内封装所有 Qwen3-235B 的特殊逻辑。它的初始化只需要传入原始模型实例和 tokenizer无需侵入 OpenClaw 任何一行代码。部署时只需在配置文件里把model_type从qwen改成qwen3_bridgeOpenClaw 就会自动加载这个桥接器。这种设计让协议适配逻辑彻底解耦既保证了 OpenClaw 的纯净性又为未来扩展留足了空间。我后来把这个Qwen3Bridge抽成了一个独立 PyPI 包qwen3-openclaw-bridge现在团队里新成员接入 Qwen3-235B只需要pip install qwen3-openclaw-bridge然后改一行配置5 分钟就能跑通。3. 核心细节解析22 个坑里这 8 个最致命也最易复现3.1 坑 #1Tokenizer 的 decode 行为差异——Qwen3-235B 的skip_special_tokensFalse是默认陷阱Qwen3-235B 的 tokenizer 有一个反直觉的默认行为decode()方法在skip_special_tokensFalse时会把|tool_call|、|tool_response|这类特殊 token 原样输出为字符串。而 OpenClaw 的ModelAdapter在处理流式输出时会把每个 token 的 decode 结果直接拼接到response_text变量里。结果就是你在日志里看到的不是干净的 JSON而是一堆乱码|tool_call|{name: get_weather, arguments: {\city\: \北京\}}|eot_id|OpenClaw 的 JSON 解析器当然不认识|tool_call|这种 tag。这个问题的根源在于Qwen3-235B 的官方推理脚本里skip_special_tokens默认是True但 OpenClaw 的ModelAdapter并没有显式设置这个参数它调用的是 tokenizer 的默认 decode 行为。解决方案非常简单但在Qwen3Bridge.generate()方法里必须强制指定# 错误写法使用默认 decode decoded self.tokenizer.decode(token_ids, clean_up_tokenization_spacesTrue) # 正确写法必须 skip special tokens decoded self.tokenizer.decode( token_ids, skip_special_tokensTrue, # 关键跳过所有特殊 token clean_up_tokenization_spacesTrue )这个参数看似微小却决定了整个输出流的“洁净度”。我踩这个坑花了整整一天因为日志里|tool_call|的 tag 颜色和普通文本一样肉眼根本看不出异常只能靠print(repr(decoded))才发现开头多了 12 个字符。经验心得所有涉及 Qwen3-235B tokenizer 的 decode 操作第一行必须写上skip_special_tokensTrue把它当成肌肉记忆刻进本能里。3.2 坑 #2Function Call 的 Schema 校验——OpenClaw 的tool_schema必须与 Qwen3-235B 的 system prompt 严格对齐OpenClaw 要求每个注册的 tool 都提供一个tool_schema通常是 OpenAI 格式的 JSON Schema。例如天气查询工具{ type: function, function: { name: get_weather, description: 获取指定城市的实时天气, parameters: { type: object, properties: { city: {type: string, description: 城市名称如北京、上海} }, required: [city] } } }这个 schema 会被 OpenClaw 用来校验模型输出的name和arguments是否合法。但问题来了Qwen3-235B 的tool_call模式其行为高度依赖 system prompt。如果你的 system prompt 里写的是 “请用 JSON 格式调用工具”模型可能输出{name:get_weather,arguments:{\city\:\北京\}}但如果你的 prompt 里写的是 “请严格按照以下 JSON Schema 调用工具{...}”它就可能输出更严格的格式。我最初用的 system prompt 是 HuggingFace 上 Qwen3-235B 的示例 prompt里面有一句 “You are a helpful assistant that can use tools.”结果模型在arguments里总是多加一个{city: 北京, unit: celsius}而我的tool_schema里unit字段是 optionalOpenClaw 却因为arguments字符串里包含了未声明的字段直接判定为invalid arguments。排查路径是打开 OpenClaw 的 debug 日志找到tool_call_raw_output这一行把原始输出复制出来用在线 JSON Schema 验证器如 jsonschemavalidator.net手动验证。最终解决方案是重写 system prompt明确限定arguments字段只允许出现tool_schema中required和optional显式声明的 key并在Qwen3Bridge里增加一层arguments字段白名单过滤。这让我意识到system prompt 不是“辅助说明”而是协议契约的一部分必须和tool_schema同步维护。3.3 坑 #3Streaming 的 Token 边界错乱——Qwen3-235B 的eos_token_id与 OpenClaw 的stop_sequences冲突这是导致“OpenClaw 为什么会延迟”的最常见原因。OpenClaw 的流式响应依赖于模型在生成完一个完整 tool call 后主动输出一个stop_sequence如|eot_id|来通知客户端“这段结束了”。但 Qwen3-235B 的generate()方法里eos_token_id默认是|eot_id|的 ID而 OpenClaw 的stop_sequences参数也设为了[|eot_id|]。这就造成了双重终止模型自己遇到|eot_id|就停了OpenClaw 又在等待这个 token结果就是响应卡住CPU 占用 100%日志里不断刷waiting for stop sequence。根本原因是Qwen3-235B 的generate()在streamingTrue模式下其内部的next_token_logits计算和stop_sequences检查是异步的当eos_token_id被采样出来时stop_sequences的检查可能还没执行到导致流式输出被阻塞。解决方案是在Qwen3Bridge.stream_generate()里完全禁用 OpenClaw 的stop_sequences机制改为监听模型输出的eos_token_id。具体做法是在for token_id in stream_output:循环里加入判断if token_id self.eos_token_id: # 主动结束流式不再等待 stop_sequences yield {finish_reason: stop, content: } break同时在 OpenClaw 的配置文件里把stop_sequences设为空列表[]。这个改动让流式响应的延迟从平均 8.2 秒降到了 1.3 秒以内用户体验提升巨大。实操心得永远不要同时启用模型自身的 eos 和框架的 stop_sequences选一个且只选一个。对于 Qwen3-235B选eos_token_id更可靠。3.4 坑 #4Tool Response 的回传格式——Qwen3-235B 要求tool_responsetoken 必须前置当 OpenClaw 调用完get_weather工具拿到返回结果{ temperature: 25, condition: sunny }后需要把这个结果喂给模型让它生成最终回复。Qwen3-235B 的协议规定这个tool_response必须以|tool_response|token 开头后面紧跟 JSON 字符串最后以|eot_id|结尾。但 OpenClaw 的默认tool_response_template是|tool_response|{tool_response}|eot_id|问题在于Qwen3-235B 的 tokenizer 对|tool_response|这个 token 的 encode 结果是[151645]而|tool_response|{tool_response}这个字符串的 encode 结果和单独 encode|tool_response|再拼接tool_response的结果并不相等。这是因为 tokenizer 的 subword 分词机制在处理混合 token 时会产生不同的 byte-pair 编码。结果就是模型收到的输入 embedding 是错的它无法正确理解“这是工具返回的结果”从而胡言乱语。解决方案是在Qwen3Bridge里必须用 tokenizer 的encode()方法分别 encode|tool_response|和tool_response字符串然后手动拼接 token ids 列表再 feed 给模型。代码如下# 获取 tool_response token id tool_resp_id self.tokenizer.convert_tokens_to_ids(|tool_response|) eot_id self.tokenizer.convert_tokens_to_ids(|eot_id|) # 分别 encode再拼接 tool_resp_ids [tool_resp_id] self.tokenizer.encode(tool_response, add_special_tokensFalse) full_input_ids input_ids tool_resp_ids [eot_id]这个细节在 Qwen3-235B 的官方文档里提都没提完全是靠print(tokenizer.encode(xxx))对比出来的。踩过的坑所有涉及特殊 token 的字符串拼接必须用 token ids 拼接而不是字符串拼接。这是 Qwen3-235B 的铁律。3.5 坑 #5Batch Inference 的 Padding 陷阱——Qwen3-235B 的pad_token_id必须显式设置当 OpenClaw 启用 batch inference批量处理多个用户请求时它会把不同长度的 prompt token ids 用pad_token_id补齐到同一长度。Qwen3-235B 的 tokenizer 默认没有pad_token_idtokenizer.pad_token_id返回None。OpenClaw 在调用model.generate()时如果pad_token_idNonePyTorch 会报错pad_token_id must be set when using batched generation。这个问题在单请求测试时完全不会暴露只有压测时才会突然爆发。解决方案是在初始化Qwen3Bridge时必须显式设置pad_token_id。Qwen3-235B 的推荐做法是用eos_token_id兼任pad_token_idself.tokenizer.pad_token_id self.tokenizer.eos_token_id # 同时确保模型的 pad_token_id 也一致 self.model.config.pad_token_id self.tokenizer.pad_token_id但这里有个隐藏雷Qwen3-235B 的eos_token_id是|eot_id|ID 为151643而有些老版本的 transformers 库在generate()里会对pad_token_id做额外校验如果pad_token_id eos_token_id会警告Using eos_token_id as pad_token_id is not allowed。所以最终方案是创建一个 dummy pad token。在 tokenizer 加载后添加一个新 tokenself.tokenizer.add_special_tokens({pad_token: |pad|}) self.model.resize_token_embeddings(len(self.tokenizer)) self.tokenizer.pad_token_id self.tokenizer.convert_tokens_to_ids(|pad|)这个 dummy token 的 ID 是安全的不会和任何功能 token 冲突。经验总结batch inference 是性能优化的必选项但 Qwen3-235B 的 padding 必须手工干预不能依赖默认值。3.6 坑 #6CUDA Out of Memory 的隐性消耗——Qwen3-235B 的kv_cache在 OpenClaw 中未被复用Qwen3-235B 的 235B 参数量意味着巨大的显存占用。我在 A100 80G 上单卡跑qwen3-235b-instructmax_new_tokens512时显存占用稳定在 72GB。但当我把 OpenClaw 的并发数从 1 提到 4显存瞬间飙到 85GBOOM 报错。nvidia-smi显示显存被占满但torch.cuda.memory_allocated()却只显示 68GB。问题出在 OpenClaw 的ModelAdapter每次generate()都会新建一个past_key_values用于 KV Cache。而 Qwen3-235B 的 KV Cache 单次推理就要占用约 8GB 显存。4 个并发就是 4 份独立的 KV Cache白白浪费了 24GB 显存。解决方案是在Qwen3Bridge里实现 KV Cache 的跨请求复用。具体做法是维护一个 LRU cachekey 是prompt_hashprompt token ids 的 SHA256value 是past_key_values。当新请求的 prompt 和缓存中的某个 prompt 相似度 95%用编辑距离计算就复用它的past_key_values只生成新 token。这个优化让 4 并发下的峰值显存从 85GB 降到了 76GB成功避免了 OOM。关键提示Qwen3-235B 的 KV Cache 是显存杀手任何框架接入它都必须考虑 cache 复用策略否则并发就是自杀。3.7 坑 #7Tool Calling 的超时熔断——OpenClaw 的tool_timeout与 Qwen3-235B 的max_time冲突OpenClaw 为每个 tool call 设置了tool_timeout默认 30 秒超时则中断并报错。但 Qwen3-235B 的generate()方法也有自己的max_time参数。当tool_timeout30而max_time45时会出现诡异现象OpenClaw 认为 tool call 已超时抛出ToolTimeoutError但模型其实还在后台运行45 秒后才真正结束导致 GPU 资源被无效占用。更糟的是如果max_time tool_timeout模型提前结束OpenClaw 却还在傻等造成响应延迟。解决方案是在Qwen3Bridge.generate()里统一max_time和tool_timeout。读取 OpenClaw 传入的timeout参数直接赋值给generate()的max_timeoutput self.model.generate( inputsinput_ids, max_new_tokensmax_new_tokens, max_timetimeout, # 关键与 OpenClaw 的 timeout 严格同步 ... )同时在 OpenClaw 的配置文件里把tool_timeout设为一个略大于模型 P95 延迟的值我设为 25 秒。这样超时控制权完全交给模型层OpenClaw 只负责接收结果或异常逻辑更清晰资源更可控。实测数据统一超时后tool call 的失败率从 12.7% 降到了 0.3%且无资源泄漏。3.8 坑 #8Docker 部署的 CUDA 版本错配——nvidia/cuda:12.1.1-devel-ubuntu22.04是唯一兼容镜像最后这个坑发生在生产环境部署阶段。我在本地 Ubuntu 22.04 CUDA 12.1 环境下一切正常但用nvidia/cuda:12.2.0-devel-ubuntu22.04构建 Docker 镜像后Qwen3-235B 的generate()方法在第一次调用时就报CUDA error: device-side assert triggered。nvidia-smi显示 GPU 正常nvcc --version显示 CUDA 12.2一切看起来都没问题。排查了两天最终发现是 Qwen3-235B 的flash_attn依赖。Qwen3-235B 的官方 wheel 包是用 CUDA 12.1 编译的它内部链接的libcudnn.so.8版本是8.9.2而 CUDA 12.2 镜像里预装的是libcudnn.so.8.9.5。虽然都是 8.9.x但 minor version 的微小差异导致了 ABI 不兼容。解决方案是严格锁定基础镜像为nvidia/cuda:12.1.1-devel-ubuntu22.04并在Dockerfile里显式安装 cudnnFROM nvidia/cuda:12.1.1-devel-ubuntu22.04 # 安装与 Qwen3-235B wheel 包完全匹配的 cudnn RUN apt-get update apt-get install -y \ libcudnn88.9.2.26-1cuda12.1 \ libcudnn8-dev8.9.2.26-1cuda12.1 \ rm -rf /var/lib/apt/lists/*这个镜像选择是经过 7 次 build-test 循环才确定下来的。血泪教训Qwen3-235B 的 Docker 部署CUDA 版本不是“向下兼容”而是“精确匹配”。任何版本浮动都会在 runtime 爆出无法 debug 的 CUDA assert。4. 实操过程从零开始一步步搭建可运行的 Qwen3-235B OpenClaw 系统4.1 环境准备与依赖安装避开那些“看起来没问题”的坑部署 Qwen3-235B OpenClaw第一步不是写代码而是构建一个“纯净、可控、可复现”的环境。我强烈建议放弃conda全程使用venvpip因为 conda 的包管理在处理 CUDA 相关依赖时经常引入不可控的版本冲突。以下是我在 A100 80G 服务器上验证通过的完整步骤操作系统与驱动Ubuntu 22.04 LTSNVIDIA Driver Version 535.129.03这是 CUDA 12.1 的官方推荐驱动不要用更新的 550.x它和 flash_attn 有兼容问题。Python 环境Python 3.10.12Qwen3-235B 的官方测试版本3.11 有少量 typing 兼容问题。创建虚拟环境python3.10 -m venv /opt/qwen3-openclaw-env source /opt/qwen3-openclaw-env/bin/activateCUDA 与 cuDNN绝不使用apt install nvidia-cuda-toolkit它安装的是系统级 CUDA版本混乱。而是直接下载 NVIDIA 官方 runfilewget https://developer.download.nvidia.com/compute/cuda/12.1.1/local_installers/cuda_12.1.1_530.30.02_linux.run sudo sh cuda_12.1.1_530.30.02_linux.run --silent --override --toolkit安装完成后export PATH/usr/local/cuda-12.1/bin:$PATHexport LD_LIBRARY_PATH/usr/local/cuda-12.1/lib64:$LD_LIBRARY_PATH。关键依赖安装顺序顺序极其重要错一步就前功尽弃。# 1. 先装 torch必须指定 CUDA 12.1 pip3 install torch2.3.0cu121 torchvision0.18.0cu121 torchaudio2.3.0cu121 --extra-index-url https://download.pytorch.org/whl/cu121 # 2. 再装 flash-attn必须用源码编译确保 CUDA 版本匹配 pip3 install ninja pip3 install flash-attn --no-build-isolation # 3. 最后装 transformers 和 openclaw pip3 install transformers4.41.2 pip3 install openclaw0.3.1 # 注意不要 pip install qwen2Qwen3-235B 是独立模型用 huggingface_hub 下载 pip3 install huggingface-hub0.23.2提示flash-attn --no-build-isolation是关键。它会强制 pip 使用你本地的 CUDA 12.1 编译而不是下载预编译的 wheel。预编译 wheel 很可能链接了错误的 cudnn 版本。4.2 模型下载与量化235B 模型的存储与加载策略Qwen3-235B 的原始 FP16 模型大小约为 470GB这对于绝大多数服务器都是不可承受之重。我们必须进行量化。但 Qwen3-235B 官方只提供了 AWQActivation-aware Weight Quantization格式的 4-bit 量化模型而 AWQ 的推理引擎autoawq对 OpenClaw 的集成支持并不友好。我的最终方案是使用llm-awqtransformers的原生 AWQ 加载方式它不需要额外的推理引擎直接在transformers的 pipeline 里运行。下载模型从 Hugging Face Hub 下载 AWQ 量化版。注意不是Qwen/Qwen3-235B而是Qwen/Qwen3-235B-AWQ。huggingface-cli download Qwen/Qwen3-235B-AWQ --local-dir /models/qwen3-235b-awq --revision main加载模型在Qwen3Bridge的__init__方法里使用AutoAWQForCausalLMfrom awq import AutoAWQForCausalLM from transformers import AutoTokenizer self.model AutoAWQForCausalLM.from_quantized( model_path/models/qwen3-235b-awq, fuse_layersTrue, # 关键开启 layer fusion提升 20% 速度 trust_remote_codeTrue, safetensorsTrue, device_mapauto, # 自动分配到多卡 use_cacheTrue ) self.tokenizer AutoTokenizer.from_pretrained( /models/qwen3-235b-awq, trust_remote_codeTrue )存储优化AWQ 模型的safetensors文件虽然只有 118GB但加载到内存后由于fuse_layersTrue会额外占用约 15GB 显存。为了快速启动我创建了一个model_loader.py脚本它在服务启动前就将模型预加载到 GPU并保存一个model_state_dict的 checkpoint。OpenClaw 启动时直接从这个 checkpoint 加载跳过耗时的from_quantized过程冷启动时间从 3 分钟缩短到 42 秒。4.3 OpenClaw 配置与 Qwen3Bridge 注册让框架认识你的模型OpenClaw 的配置是 YAML 格式核心在于model部分。你需要告诉 OpenClaw“嘿我有一个叫qwen3_bridge的新模型类型它的实现类在哪儿”。创建 Bridge 类将前面提到的Qwen3Bridge类保存为/opt/qwen3-openclaw-env/lib/python3.10/site-packages/qwen3_openclaw_bridge/bridge.py。编写配置文件config.yaml# OpenClaw 核心配置 server: host: 0.0.0.0 port: 8000 workers: 4 # 模型配置 model: type: qwen3_bridge # 这里指向你的自定义类型 path: /models/qwen3-235b-awq # 模型路径 # 以下参数会透传给 Qwen3Bridge.__init__ max_new_tokens: 1024 temperature: 0.7 top_p: 0.95 # OpenClaw 的 tool calling 配置 tool_timeout: 25 stop_sequences: [] # 空列表由 bridge 内部处理 # Tool 配置 tools: - name: get_weather description: 获取指定城市的实时天气 schema: type: function function: name: get_weather description: 获取指定城市的实时天气 parameters: type: object properties: city: type: string description: 城市名称 required: [city] # 实际的 Python 函数 implementation: tools.weather.get_weather # 日志 logging: level: DEBUG注册模型类型OpenClaw 通过entry_points机制发现自定义模型。在qwen3_openclaw_bridge包的setup.py里添加setup( nameqwen3-openclaw-bridge, # ... other fields entry_points{ openclaw.models: [ qwen3_bridge qwen3_openclaw_bridge.bridge:Qwen3Bridge ] } )然后pip install -e .安装这个包。这样OpenClaw 在启动时就会自动扫描entry_points发现qwen3_bridge类型并