ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

算能1684x上跑通多模态RAG:Qwen3-VL+WeKnora实践

算能1684x上跑通多模态RAG:Qwen3-VL+WeKnora实践 上周连续调了三天的多模态RAG总算在算能1684x这台卡上把Qwen3-VL和WeKnora完整串起来了。整个过程不少弯路但链路一旦走通后面做内部知识问答、图文资料检索都很顺手。这篇文章我会按照实际部署顺序来讲先说这套组合解决什么问题再把1684x上的模型转换和推理服务讲清楚然后是WeKnora的本地部署与配置最后重点讲两者连接的方法和我在多模态RAG上踩到的一些坑。1. 这套组合到底解决什么问题1.1 为什么是1684x而不是显卡先说我为什么盯上算能1684x。手头项目要求所有数据留在内网模型推理不能走云端API传统思路是买几块消费级显卡但功耗、成本和卡源都得考虑。这时候算能1684x这类国产推理卡就很有吸引力单卡功耗低支持INT8量化推理PCIe插上就能当加速器用模型通过TPU-MLIR工具链转成bmodel格式后跑在自家TPU上。1684x指的是算能的第二代推理芯片市面上常见的是SC系列加速卡性能和一张中端显卡相当但胜在省电、稳定、部署形态简单。如果你的场景是需要把多个模型跑在本地、长期挂着对外提供服务1684x比显卡更合适。它不需要单独接屏没有桌面环境一样跑驱动装好以后在网络层就是一个普通的PCIe设备软件层通过sophon运行时库来调用。但这里有个心理准备整个生态的成熟度和N卡差得很远尤其碰到新模型和新算子时你得给自己留出看文档和改脚本的时间。1.2 Qwen3-VL在这个链路里该承担什么角色Qwen3-VL是阿里的多模态大模型视觉部分能读截图、扫描件、产品图文本部分能做问答和推理。在这套系统里它承担两件事一是作为知识库的生成模型也就是用户问问题后由它根据检索到的资料生成最终答案二是作为图片内容的理解器比如知识库里存了一张架构图用户问这个图里的流程是什么实际干活的是Qwen3-VL。我选的是Qwen3-VL-2B-Instruct版原因非常实际1684x这类推理卡的显存不算大8B模型量化后能跑但并发和首包延迟都不好看。2B在图文理解上已经能处理大部分内部资料场景部署还省心。如果你的知识库问题偏难、对答案质量要求很高可以量化8B但要做好吞吐下降的准备。1.3 WeKnora扮演什么角色WeKnora是腾讯开源的一套RAG知识库平台简单说就是帮你把文档、表格、网页等内容导入进去切分、向量化、建索引然后提供一个问答界面和API。它的核心卖点是多路召回不只是像普通RAG那样只做向量相似度检索而是把关键词匹配、向量检索、知识图谱关系检索混在一起再经过重排最后把最优结果交给大模型。这种设计解决的是RAG召回不全的问题因为只靠向量检索很容易漏掉那些关键词很关键但语义相似度不高的内容。三者连起来以后整条架构是这样的用户通过WeKnora的界面或API提问WeKnora先在本地知识库里做多路召回把命中的文本片段收集起来组装成提示词再发给一个OpenAI兼容的接口。这个接口背后就是跑在1684x上的Qwen3-VL服务。Qwen3-VL拿到提示词和可能的图片内容后生成答案原路返回给WeKnora最后展示给用户。也就是说用户看到的是完整的知识库问答体验而实际推理全部发生在本地的1684x上数据不出内网。2. 1684x部署准备驱动、工具链、模型转换2.1 硬件与驱动这块要做什么先把最容易卡住的硬件环节说清楚。1684x加速卡插上服务器后第一步是装驱动。算能官方提供sophon-driver一般是dkms方式安装。驱动装完用bm-smi命令能看到卡的温度、显存占用和算力状态类似NVIDIA的nvidia-smi。我调试时习惯先跑一条bm-smi确认卡已经被识别再继续后面的步骤否则后面报错容易让人误判成软件问题。需要提醒的是内核版本和驱动的匹配问题比较常见。如果你用的服务器系统是CentOS 7这类老系统内核偏旧装新驱动可能因为头文件不全失败。我的建议是直接用Ubuntu 20.04以上版本省时间。另外多卡机器要注意PCIe带宽1684x走PCIe 3.0就够别插在低速插槽上。2.2 构建Python推理环境驱动只是底层推理还需要sophon运行库。算能当前的命名是libsophon里面包含运行库和Python的sophon包。安装方式有两种一种是官方提供的deb安装包装在宿主机上另一种是用Docker镜像隔离。我实际部署时选的是Docker原因很直接模型转换工具链和运行库版本经常迭代隔离后不会污染宿主机环境。宿主机装驱动容器内装运行库这套模式最稳。创建容器时要把1684x设备映射进去也就是带上/dev/bm*的设备节点同时挂载模型目录和代码目录。Python包建议装在容器里让推理脚本跑在容器内而WeKnora如果另外起一套服务再通过网络连过来。2.3 Qwen3-VL权重选择与bmodel转换这一步是整个部署里最容易被卡住的环节需要提前理解一个概念1684x不认识PyTorch权重也不直接跑HuggingFace格式它只认bmodel这种经过编译的模型格式。所以拿到的Qwen3-VL权重必须走一遍转换流程。转换流程大体是这样的先从HuggingFace下载Qwen3-VL-2B-Instruct的原始权重然后转成ONNX格式再用TPU-MLIR工具链把ONNX模型量化和编译成bmodel文件。TPU-MLIR是算能提供的一套Docker镜像工具链。转换时常见做法是这样model_transform.py \ --model_name qwen3vl_2b \ --model_def qwen3vl_2b.onnx \ --input_shape [[1,3,336,336],[1,seq_len]] \ --pixel_format rgb \ --mlir qwen3vl_2b.mlir model_deploy.py \ --mlir qwen3vl_2b.mlir \ --quantize INT8 \ --calibration_table cali_table.txt \ --chip 1684x \ --output qwen3vl_2b_int8.bmodel两个模型类型/脚本名会因为工具链版本而变示例命令是思路不要照抄。转换时最重要的一个点多模态模型的文本部分和视觉部分要分开处理。Qwen3-VL的视觉编码器接收的是图像分块后的序列文本模型部分接收的是文本token序列。TPU-MLIR对多模态模型的支持这几年已经比较成熟但不同版本对Qwen3-VL的支持程度不一样。建议先查你手上的工具链版本对应的release notes确认支持Qwen3-VL再动手否则会卡在算子不支持上。量化表这一步也值得多说一句INT8量化需要校准数据一般从训练集中抽一批有代表性的样本算好每层激活值的范围。如果校准数据选得不好量化后模型效果会肉眼可见地变差。我用的是公开的COCO数据再混了几十张内部截图出来的效果是可用的。转换完成后得到bmodel文件同时保留原权重。后面如果发现量化后效果不好还能回到FP16重新编译只是占用显存更大。3. 在1684x上把Qwen3-VL跑成一个服务3.1 加载bmodel并写推理循环转换出了bmodel接下来就是写推理脚本。这里用的核心包是sophon的Python运行库通过sail接口加载bmodel并做推理。脚本主体包括初始化引擎、准备输入、执行推理、解析输出四块。对于Qwen3-VL这种自回归模型还要维护一个KV Cache也就是每生成一个token要把历史信息带进去这和普通的目标检测模型差别很大。部署时不太建议从零手写整套生成逻辑直接用官方或社区已经跑通的示例代码再根据自己的bmodel路径和tokenizer路径改配置。我的建议是先把官方推理示例跑通再考虑包一层HTTP接口。示例脚本里一般会有一个model.run类型的调用如果输入是一张图和一段文字它会拼装成模型需要的格式。跑通后你可以通过一段简单的Python请求来验证效果。3.2 命令行先验证一次图文问答接入WeKnora之前先用命令行直接验证模型效果这一步不能跳过。因为后面如果是WeKnora链路出问题排查范围会变大先确保模型本身是好的再往上排查检索和接口思路就清晰。验证时准备一张带文字的截图比如一张产品架构图然后请求它回答问题。我第一次测试用的是这张图里数据流向是什么这类带明显视觉理解需求的问题。如果模型输出的答案和图中内容对得上说明视觉编码、文本生成、tokenizer都工作了。如果输出乱码或答非所问先查tokenizer版本是否和权重匹配再查量化表是否合理。还有一类常见问题是图像输入尺寸不对Qwen3-VL会把图像动态缩放成模型支持的尺寸代码里没做这个预处理的容易报维度错误。3.3 实测性能与部署约束跑通推理后我顺手记录了几组性能数据作为参考。Qwen3-VL-2B在1684x上做INT8推理单次问答输入一张图加一小段文字生成一百个token左右耗时大约在三到五秒区间。如果纯文本问答耗时会更短一些。这个数据供参考实际跟你的输入长度和生成长度强相关。这里要说明一个部署约束并发能力有限。1684x的单卡算力摆在那里如果同时有四五个用户提问请求会排队每个用户等待时间会叠加。因此面向内部小团队使用完全没问题但要作为对外服务大量并发的话需要上多卡并加一层负载均衡或者接受排队。我个人上线时的做法是控制WeKnora侧的最大并发数避免请求暴雨打满板卡导致每个请求都变慢。4. WeKnora本地部署从下载到可用的知识库4.1 选型对比WeKnora、Dify、自研管线先回答一个高频问题既然有Dify这类开源平台为什么用WeKnora我自己的体会是Dify更偏工作流编排和模型管理它的优势是把Agent流程、工具调用、知识库都整合在一个界面里。而WeKnora更专注于检索增强本身在知识库的解析、分块、多路召回、重排这些环节上做得更重。如果你的核心诉求是把一堆文档变成可问答的知识库而不是搭一套复杂的Agent工作流WeKnora更对口。另一个选择是自研RAG管线用LangChain或LlamaIndex写一系列脚本。好处是灵活坏处是解析、切分、召回、重排样样都要自己调像我这种要同时管模型部署的人没精力去维护。WeKnora是把这些能力平台化了开箱即用还带了可视化后台对项目交付很友好。4.2 Docker Compose启动全套依赖WeKnora的部署方式我推荐用Docker Compose因为它依赖的东西比较多Elasticsearch负责存储和检索、向量模型服务负责文本转向量、后端API负责业务逻辑、前端负责管理界面。一条命令全部拉起最省心。Compose文件在项目仓库里有拉下来后主要改两处一是镜像版本二是环境变量里的配置项。启动前要检查一下机器资源WeKnora本身不重但Elasticsearch吃内存建议至少给16G内存。启动后用docker compose ps确认所有容器都进入healthy状态。这一节的关键提示如果用的是内网环境先确认镜像仓库网络是否通畅。拉不下来的镜像可以用离线导出的方式在能联网的机器上docker save再传上去。4.3 初始化知识库与接入文档服务起来以后打开WeKnora的管理界面第一步创建知识库。创建时要选择向量模型WeKnora内置了几个常用的文本嵌入模型比如bge系列的向量模型。这个向量模型需要下载权重如果内网无法访问HuggingFace需要提前准备离线模型文件。向量模型的质量直接决定后面检索效果建议选bge-large这种中等偏上的模型不要因为部署麻烦就选一个很小的。创建完知识库就能上传文档了。我实际测试时上传了Word、PDF和Markdown三类文件WeKnora都能解析。这里面有个很容易被忽略的点文档解析质量。因为RAG的第一环节是把文档切成一段段的文本如果PDF本身是扫描件没有文字层WeKnora需要启用OCR能力否则切出来的全是空文本。我第一次上传一个扫描版PDF问答时什么都检索不到后来才发现是解析环节出了问题。4.4 解析链路与内置多路召回WeKnora之所以比普通RAG框架效果好核心在于多路召回。它不只用向量检索一条路向量检索负责语义相近的召回BM25关键词检索负责术语精确匹配的召回知识图谱检索负责实体关系的召回最后各路结果经过重排序合并。这个设计非常实用因为很多企业文档里充满了专业术语比如设备型号、项目编号语义相似的向量可能找不到完全匹配的token而BM25能精确命中。多路召回用得好不好取决于知识库里的文档是否做了足够的结构化处理。比如表格数据如果只是当成纯文本切分行与列的对应关系会丢失。WeKnora对表格有专门的解析逻辑但前提是源文件本身要清晰。我给团队的建议是上传之前的预处理很重要转成带标题结构的Markdown通常比原始Word文档效果更好。5. 把Qwen3-VL接入WeKnora一次代理就能打通5.1 为什么不用内置Ollama/OpenAI而是加代理WeKnora的可配置性很好模型接入部分它支持OpenAI兼容接口也支持接Ollama这类本地推理服务。但有个现实问题Ollama对1684x没有官方支持你不会想在x86上跑一个Ollama再让它去调1684x那等于绕远路。更直接的方案是让WeKnora认为自己在和一个OpenAI兼容的接口通信而实际上这个接口背后就是我们的Qwen3-VL服务。这就是我引入一层反向代理的原因。Qwen3-VL的原始推理服务并不一定是标准的OpenAI接口格式它可能是socket协议也可能是自定义的HTTP格式。而OpenAI兼容要求的请求体结构是固定的比如messages字段、model字段。加一层代理把两边格式统一起来相当于做了一个协议转换。5.2 写一个OpenAI格式兼容的代理层这个代理非常简单我用FastAPI写了一个小服务。核心逻辑是接收WeKnora发来的OpenAI格式请求去掉或转换其中无法直接映射的字段然后转发给本地Qwen3-VL的推理接口最后把返回结果包装成OpenAI格式。这个过程里最关键的是messages字段转换需要把系统提示词、历史对话、用户问题拼接成Qwen3-VL能理解的完整提示词。代理代码结构类似下面这样from fastapi import FastAPI, Request import httpx app FastAPI() VLM_ENDPOINT http://127.0.0.1:9000/chat app.post(/v1/chat/completions) async def proxy_chat(request: Request): payload await request.json() messages payload[messages] prompt build_prompt(messages) async with httpx.AsyncClient(timeout180) as client: resp await client.post(VLM_ENDPOINT, json{text: prompt}) data resp.json() return { id: chatcmpl-1684x, object: chat.completion, model: payload.get(model, qwen3vl-2b), choices: [{ index: 0, message: {role: assistant, content: data[answer]}, finish_reason: stop }], }build_prompt函数里做的事情是拼接系统提示词和用户问题。这里有一个需要调试的常见坑WeKnora会把检索出来的参考文档也放在提示词里有些平台的提示词模板很长Qwen3-VL有上下文长度限制一旦超出就会截断甚至报错。所以代理层要控制最大输入长度超过部分要截掉或者按重要性裁剪。5.3 在WeKnora里配置模型与回环测试代理服务搭好后到WeKnora的后台配置模型接口。模型类型选OpenAI兼容接口地址填代理服务的地址比如http://your-server:8002/v1/chat/completions同时配置模型名和API Key可以随便填一个代理层不校验。保存后页面右上角就能看到新模型。首次测试建议在WeKnora的问答页面里问一个单纯依靠知识库检索就能回答的问题比如知识库里关于XX项目的介绍是什么。如果答案准确说明检索到生成链路已经通。如果答案明显在瞎编先确认是不是检索没有命中可以去知识库管理页看这个文档的切块情况同时看命中的片段里是否包含正确答案。这一步能帮你区分问题出在检索还是生成。5.4 我的提示词调节心得接入后回答质量直接取决于提示词的设置。我的经验是在代理层拼接提示词时明确告诉模型根据提供的资料回答资料不符就说明无法回答。这能大幅减少幻觉。另一个实用技巧是把检索片段按相关性排序最相关的放前面因为长上下文中模型对中间内容的注意力容易被稀释核心内容放在开头和结尾效果更好。如果发现答案过于简洁可以在系统提示词里加先给出结论再补充理由。如果答案太长则限制生成长度。这些调节不涉及模型微调纯靠提示词就能解决大部分质量问题。6. 多模态知识库实战图片、截图、图表都能问6.1 RAG知识库存图片这件事先说结论很多人问RAG知识库能存图片吗我直接说结论普通的向量RAG知识库存的不是图片本身而是图片解析后的文本内容。文本向量库对图片是无能为力的因为向量模型一般不接收图片输入。要做真正的多模态知识库有两种路径一是用OCR把图片里的文字提取出来存进去这样你问图片里写了什么时实际检索的是OCR文本二是把原始图片作为附件保存真正理解图片语义时调用Qwen3-VL这类视觉模型来处理。我们这套架构实际上两条路都能走WeKnora负责第一条挂上来的Qwen3-VL负责第二条。6.2 上传带图文档与预处理实际测试时我上传了一份包含产品截图、表格和流程图的Markdown文档。WeKnora解析时会先把图片抽取出来。对于含有大量文字的截图建议先做一步预处理用OCR把图片转成文字补充到文档中比如把截图放在图片标签后面紧接着加上截图文字的Markdown说明。这样既保留了图片又让文本检索能命中图片里的内容。还有一个细节是图片分辨率。Qwen3-VL对于过大的图片会自动缩放但过小又难看清细节。建议图片宽度控制在1024像素左右文字内容清晰可读即可。截图类图片不要用太高的分辨率不然图片编码耗时和显存占用都会上升。6.3 多轮对话中带动图片提问在WeKnora的问答页面里如果只靠纯文本提问图片处理能力其实用不上。要让图片真正参与问答可以在提问时引用图片文件。比如用户先上传一张架构图然后问这张图里的模块依赖关系是什么。这个请求到达代理层时需要把图片传给底层的Qwen3-VL。如果你的输入通道只支持文本就在代理层增加一个图片输入字段Base64编码后随请求发给推理服务。实测下来Qwen3-VL对清晰截图的理解能力很强能准确说出图中模块名称和数据流向。但有几个场景效果不佳低清晰度的扫描件、表格线条混乱的截图、复杂的多层架构图。对于这些情况我推荐的做法是引导用户改用文字描述或者提前把图片中的重要信息转成文字摘要入库。6.4 图文混合检索的评估我把这套多模态知识库交给几个同事试用了几天收集到的反馈非常有参考价值。纯文字资料的问答准确率很高基本满足日常使用带图文档的问答效果取决于图片质量和文本检索的配合。如果图片本身是清晰的架构图或界面截图问题针对性又强效果很好。但如果问题是帮我找一下文档里那个红色柱状图对应的数据表这种需求就很依赖文档内部的结构化仅仅靠向量检索很难精确命中。评估结论是多模态RAG不是魔法它的上限取决于知识库的整理质量。建议文档在入库前做一次统一处理图片配文字说明表格保留标题层级标题规范。这样在多路召回阶段就能拿到更高质量的候选片段。6.5 关于知识库类型可以再深一层热搜词里有两个词值得区分知识图谱KG和本体论Ontology。普通RAG知识库存的是文本向量适合模糊查询、语义相近的场景知识图谱知识库存的是实体和关系适合某个实体和另一个实体是什么关系、路径有多长这类问题本体论则更进一步定义概念和概念之间关系规则适合专业领域里严格推理。WeKnora本身就带了知识图谱召回这也是我选它的一个原因。如果以后资料里存在大量强关联的实体关系可以把实体抽取做好利用图谱召回提升精确率。7. 踩坑记录和我的规划建议7.1 五个高频问题排查第一模型服务跑通但WeKnora报超时。多数是代理层没有把超时时间调大Qwen3-VL生成答案要几秒WeKnora默认的请求超时可能只有几秒建议把代理层和WeKnora两端的超时都调到120秒以上。第二检索不到内容。先看文档解析结果确认不是空文本再看切分大小太小的切片信息量不足太大的切片又容易混入无关内容我习惯把切片控制在500到800个字符。第三答案总是我不知道。排除检索问题后大概率是提示词写得太保守可以改成如果资料不足请基于资料给出最可能的推测并说明。很多内部问答场景是允许合理推测的。第四模型答复常见中文乱码或者格式错乱。检查tokenizer版本和部署脚本里是否缺了聊天模板Qwen3-VL对对话格式有要求直接拼接文本容易导致格式错乱。第五多请求并发时卡死。1684x推理是串行的并发上来后任务排队而WeKnora侧如果一直等待就显示卡死实际是正在排队。建议把Qwen3-VL服务做成容器限制最大并发并在代理层加一个排队提示。7.2 针对RAG瓶颈我见过最多的是这几种很多团队把RAG效果不好归因于模型但实际瓶颈更多在召回阶段。常见三类一是文档解析质量差扫描PDF没有OCR表格格式丢失二是切分策略粗糙几行就一刀切得上下文稀碎三是只做向量检索那些专业术语完全依赖语义匹配精准度不够。WeKnora的多路召回能缓解后两个问题但第一个只能靠前期数据处理解决。生成阶段的瓶颈也有就是长上下文下模型容易漏掉关键信息。这个可以靠提示词工程缓解也可以把检索片段压缩后再拼进提示词。我最近在试一个思路先用向量模型做粗召回再用Qwen3-VL对候选片段做一次是否和问题相关的判断把不相关的过滤掉再进生成阶段。这样答案质量和token消耗都会好一些。7.3 后续想做的扩展这套架构跑稳以后后续有几个方向值得投入。一是把文档解析流程自动化新文档进来自动走OCR、切分、向量化、入库的流水线二是增加知识图谱抽取把文档中的实体和关系自动识别出来补强精准召回三是在1684x上再部署一个小一点的Rerank模型专门做重排这样召回效果还能再往上提。另外一个实用方向是接入企业内部的权限体系。目前WeKnora默认是所有人可以看到同一个知识库如果资料涉及不同部门需要利用WeKnora的身份认证配置对接团体自己的OIDC系统。这也是我后续要落地的一步。最后说几句实在话。整个部署过程中最花时间的不是模型转换也不是服务配置而是对多路召回结果做调优。因为Qwen3-VL在你打通链路的那一刻就能给出看起来不错的回答但要想让回答稳定可靠你得反复看检索片段的排序和内容质量。算能1684x在中间扮演的是一个安静的后端角色它稳定跑着不吭声也不炫技。等你把WeKnora的召回调整顺了整套系统就真正可交付了。这套组合对内部知识管理、资料问答、表格和截图查询这一类场景是性价比很高的方案。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进