Qwen3-32B部署实操:Clawdbot网关配置支持OpenTelemetry分布式追踪
1. 为什么需要这套组合:从模型能力到可观测性的闭环
你有没有遇到过这样的情况:Qwen3-32B跑起来了,Chat界面也通了,但一问“为什么响应慢了2秒”,就卡在原地——不知道是模型加载慢、Ollama推理卡顿,还是Clawdbot网关转发延迟?更别说多个请求交织时,根本分不清哪条链路出了问题。
这不是个别现象。大模型服务一旦脱离单机玩具阶段,进入真实业务对接,就立刻面临三个硬需求:能连上、能用稳、能看清。前两者靠部署和代理解决,而“能看清”——也就是知道每个请求在哪个环节耗了多久、经过了哪些组件、哪里出现了错误——正是OpenTelemetry要补上的关键一环。
本文不讲抽象概念,只做一件事:手把手带你把私有部署的Qwen3-32B、Ollama API服务、Clawdbot Web网关、端口代理规则,全部串起来,并让整条链路自动上报调用轨迹,支持在Jaeger或Zipkin里点开一条Trace,清清楚楚看到“请求从浏览器发来 → 进入Clawdbot 8080端口 → 转发到18789网关 → 调用Ollama /api/chat → 加载Qwen3-32B模型 → 返回结果”的完整路径。所有操作基于Linux环境,无需修改模型代码,不侵入业务逻辑。
2. 环境准备与核心组件定位
在动手前,先理清各组件的角色和通信关系。这不是堆砌名词,而是帮你快速定位问题时“该去哪查”。
- Qwen3-32B:本地运行的开源大语言模型,32B参数量,对显存和CPU要求较高,需NVIDIA GPU(推荐A10/A100)或足够内存的CPU模式(性能下降明显)
- Ollama:轻量级模型运行时,负责加载Qwen3-32B并暴露标准REST API(默认
http://localhost:11434/api/chat),它不处理鉴权、限流、追踪,纯“执行层” - Clawdbot:一个可扩展的Web网关服务,提供前端聊天界面、会话管理、后端路由配置。它本身不运行模型,只作代理和粘合剂
- 端口代理:将Clawdbot对外暴露的
8080端口,反向代理到其内部网关监听的18789端口——这是为后续注入OpenTelemetry中间件预留的“拦截点” - OpenTelemetry Collector:独立运行的采集器,接收来自Clawdbot的Span数据,统一处理(采样、过滤、添加标签),再导出到Jaeger等后端
关键提醒:整个链路中,只有Clawdbot这一层需要主动集成OpenTelemetry SDK。Ollama和Qwen3-32B完全无感,它们只按原有方式收发HTTP请求。这意味着你不需要碰模型文件、不改Ollama配置、不重编译任何东西。
3. 分步实操:从零搭建可追踪的Qwen3-32B服务链路
3.1 启动Qwen3-32B与Ollama服务
确保你已安装Ollama(v0.3.0+)并下载Qwen3-32B模型:
# 拉取模型(首次运行较慢,约15-30分钟,取决于网络和磁盘IO) ollama pull qwen3:32b # 启动Ollama服务(默认监听11434端口) ollama serve验证Ollama是否正常工作:
curl -X POST http://localhost:11434/api/chat \ -H "Content-Type: application/json" \ -d '{ "model": "qwen3:32b", "messages": [{"role": "user", "content": "你好"}], "stream": false }'如果返回包含"message":{"role":"assistant","content":"..."}的JSON,说明模型已就绪。
3.2 配置Clawdbot网关与端口代理
Clawdbot需以开发模式启动,并启用自定义代理规则。假设你已克隆Clawdbot仓库(v2.1.0+),进入项目根目录:
- 创建
config/proxy.json,定义从/api/chat到Ollama的转发规则:
{ "proxy": { "/api/chat": { "target": "http://localhost:11434", "changeOrigin": true, "secure": false, "logLevel": "debug" } } }- 修改
package.json中的启动脚本,指定网关端口为18789,并启用代理配置:
"scripts": { "dev": "cross-env NODE_ENV=development PORT=18789 PROXY_CONFIG=config/proxy.json vite --host" }- 启动Clawdbot开发服务器:
npm install npm run dev此时Clawdbot在http://localhost:18789运行,但不直接对外暴露。我们通过Nginx做一层反向代理,将外部请求8080端口转发过去,并在此处注入OpenTelemetry中间件。
3.3 部署OpenTelemetry Collector并配置导出
创建otel-collector-config.yaml,配置接收HTTP/GRPC Span并导出到Jaeger:
receivers: otlp: protocols: http: endpoint: "0.0.0.0:4318" grpc: endpoint: "0.0.0.0:4317" processors: batch: memory_limiter: limit_mib: 512 spike_limit_mib: 256 exporters: jaeger: endpoint: "jaeger:14250" tls: insecure: true service: pipelines: traces: receivers: [otlp] processors: [memory_limiter, batch] exporters: [jaeger]使用Docker一键启动Collector和Jaeger UI:
docker run -d --name otelcol \ -p 4317:4317 -p 4318:4318 \ -v $(pwd)/otel-collector-config.yaml:/etc/otel-collector-config.yaml \ --network host \ otel/opentelemetry-collector:0.105.0 \ --config=/etc/otel-collector-config.yaml # Jaeger UI(访问 http://localhost:16686) docker run -d --name jaeger \ -p 16686:16686 -p 14250:14250 \ --network host \ jaegertracing/all-in-one:1.553.4 在Clawdbot中集成OpenTelemetry SDK
Clawdbot基于Vite + React构建,需在入口文件中初始化Tracer。编辑src/main.tsx:
import { registerOTel } from '@opentelemetry/instrumentation-web'; import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; // 初始化OpenTelemetry registerOTel({ instrumentations: [ getWebAutoInstrumentations({ '@opentelemetry/instrumentation-user-interaction': {}, '@opentelemetry/instrumentation-fetch': { ignoreUrls: [/localhost:11434/, /127.0.0.1:11434/], // 忽略直连Ollama的请求 }, }), ], traceExporter: new OTLPTraceExporter({ url: 'http://localhost:4318/v1/traces', }), });同时,在src/utils/api.ts中,为所有发往/api/chat的请求手动创建Span:
import { trace } from '@opentelemetry/api'; export async function chatWithModel(messages: Message[]) { const tracer = trace.getTracer('clawdbot-web'); return tracer.startActiveSpan('chat.request', async (span) => { try { // 添加自定义属性 span.setAttribute('llm.model', 'qwen3:32b'); span.setAttribute('llm.provider', 'ollama'); const response = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'qwen3:32b', messages, stream: false }), }); const data = await response.json(); span.setAttribute('http.status_code', response.status); span.setAttribute('llm.response_length', data.message?.content?.length || 0); return data; } catch (err) { span.recordException(err as Error); span.setStatus({ code: 2 }); // ERROR throw err; } finally { span.end(); } }); }重新启动Clawdbot:
npm run dev3.5 配置Nginx代理并注入追踪头
最后一步:用Nginx作为最外层网关,监听8080端口,将请求转发至18789,并自动注入W3C Trace Context头:
# /etc/nginx/conf.d/clawdbot.conf upstream clawdbot_backend { server 127.0.0.1:18789; } server { listen 8080; server_name _; location / { proxy_pass http://clawdbot_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 关键:透传并生成Trace Context proxy_set_header traceparent $http_traceparent; proxy_set_header tracestate $http_tracestate; } # 静态资源直接服务 location /static/ { alias /path/to/clawdbot/dist/static/; } }重载Nginx:
sudo nginx -t && sudo nginx -s reload现在,访问http://localhost:8080,即可使用带全链路追踪的Clawdbot界面。
4. 效果验证与典型Trace解读
打开浏览器,访问http://localhost:8080,在聊天框输入“今天天气怎么样?”,发送。
几秒钟后,打开Jaeger UI(http://localhost:16686),在搜索栏选择Service为clawdbot-web,点击“Find Traces”。
你会看到一条Trace,展开后包含至少4个Span:
fetch(前端发起请求):记录从用户点击发送到发出HTTP请求的耗时chat.request(Clawdbot内Span):标记为clawdbot-web服务,含llm.model=qwen3:32b等自定义属性HTTP GET /api/chat(自动捕获的fetch调用):显示目标地址http://localhost:11434/api/chatHTTP POST /api/chat(Ollama返回响应):状态码200,响应体长度可见
重点看时间轴:如果chat.request耗时2.3s,但其子SpanHTTP POST /api/chat只占1.8s,那剩下的500ms就属于Clawdbot内部序列化、日志、UI渲染等环节——这正是传统日志无法区分的盲区。
再试一次,故意输入超长提示词触发Ollama超时,你会在Jaeger中看到该Span状态为ERROR,且exception.message字段明确写出timeout exceeded,无需翻看任何日志文件。
5. 常见问题与稳定性增强建议
5.1 “Trace没出现在Jaeger里”怎么办?
按顺序排查:
- 检查
npm run dev控制台是否输出OTel initialized,确认SDK加载成功 - 打开浏览器开发者工具→Network,找
/api/chat请求,查看Response Headers是否有traceparent字段 - 运行
curl -v http://localhost:4318/v1/traces,确认Collector HTTP接收端口可达 - 查看Collector容器日志:
docker logs otelcol | grep -i error
5.2 如何降低追踪开销?
默认情况下,OpenTelemetry会对所有fetch请求采样。生产环境建议添加采样策略:
import { ProbabilitySampler } from '@opentelemetry/core'; registerOTel({ // 只采样10%的请求 sampler: new ProbabilitySampler(0.1), // 其余配置不变... });5.3 能否追踪Ollama内部耗时?
可以,但需额外步骤:Ollama本身不支持OpenTelemetry,但你可以用otel-cli在调用前后手动打点:
# 替换原curl命令为带追踪的版本 otel-cli exec --service-name ollama-server \ --endpoint http://localhost:4317 \ curl -X POST http://localhost:11434/api/chat \ -H "Content-Type: application/json" \ -d '{"model":"qwen3:32b","messages":[{"role":"user","content":"你好"}]}'此方式适合调试,不建议长期开启。
5.4 多模型共存时如何区分?
在Clawdbot的chatWithModel函数中,动态设置Span属性:
span.setAttribute('llm.model', model); // model变量来自参数 span.setAttribute('llm.context_length', getContextLength(model)); // 自定义函数这样在Jaeger中可按llm.model标签筛选Qwen3-32B专属Trace。
6. 总结:让大模型服务真正“可运维”
部署Qwen3-32B只是第一步,让它稳定、透明、可诊断,才是工程落地的核心。本文完成的不是一次简单的“连通”,而是一套可复用的可观测性基座:
- 零侵入模型层:Qwen3-32B和Ollama保持原生,不改一行代码
- 精准定位瓶颈:从浏览器到GPU显存,每一毫秒归属清晰可见
- 故障即时归因:错误发生时,Trace自带异常堆栈和上下文属性
- 平滑演进路径:未来接入Prometheus监控指标、ELK日志,只需扩展Collector配置
当你下次被问到“为什么这个请求慢”,不再需要凭经验猜,而是打开Jaeger,点开Trace,三秒内给出答案——这才是现代AI服务该有的样子。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。