1
2
模型应用
新人贴
在海光 K100AI 上落地 Qwen3.5 与 RAG:一次从“先微调”到“先交付”的实践复盘
2026-06-13 09:24:30
244
做大模型项目,很多团队一开始都会有一个非常自然的想法: 先微调,再上线。 看起来这条路顺理成章: 业务数据整理好,模型调一轮,效果更贴近场景,然后再部署推理服务,最后接入业务系统。 但真正落到工程现场,情况往往没这么理想。 最近我们围绕一个“行业知识服务平台”做了一轮完整实践:目标是基于手册、规章、说明文档、流程资料等内容,构建一个具备问答、检索、引用追溯能力的知识服务系统。模型选型上,前期重点验证了 Qwen3.5,硬件环境则放在 海光 K100AI 上。 这篇文章不讲概念,不讲愿景,只讲一个问题: 当“大模型 + 行业知识库”真正落到国产算力环境时,哪些路径能更快形成可用结果?又有哪些看起来正确的路线,实际上会在工程上卡住? 我们的阶段性结论是: 现阶段,推理 + RAG 比“硬上微调”更容易形成可交付能力。 ⸻ 一、项目目标:不是聊天,而是知识服务 这个项目从一开始就不是做通用聊天机器人,而是要做一个行业知识服务平台。 它要解决的其实是几类非常典型的问题: * 文档太多,人工检索效率低 * 问题表述不标准,传统关键词搜索不稳定 * 需要基于资料回答,而不是模型“凭感觉生成” * 回答后最好还能指出参考来源,方便核验 * 长文档、多片段、多规则场景下,需要更强的上下文整合能力 所以,从需求本质上看,这不是“让模型会聊天”,而是: 让模型在知识约束下更好地理解、检索、组织和回答。 ⸻ 二、第一步:先把推理链路跑通 在任何大模型项目里,最容易被低估的一件事,就是基础环境适配。 这次在海光 K100AI 上,我们优先做的不是业务问答,而是: * 容器内识别 DCU * PyTorch 识别设备 * vLLM 服务启动 * OpenAI 兼容接口打通 * /v1/models、/v1/chat/completions 返回正常 我们实际使用的容器启动方式 为了把项目目录、模型目录和驱动环境都挂进去,我们使用了类似下面的容器启动命令: docker run -it --name qwen-rag-dev \ --network host \ --ipc=host \ --shm-size=64g \ --group-add video \ --cap-add=SYS_PTRACE \ --security-opt seccomp=unconfined \ --privileged \ --device=/dev/kfd \ --device=/dev/dri \ --device=/dev/mkfd \ -v /sys/kernel/debug:/sys/kernel/debug:ro \ -v /opt/hyhal:/opt/hyhal:ro \ -v /opt/dtk-26.04:/opt/dtk-26.04:ro \ -v /volumes/oss0:/volumes/oss0 \ -v $(pwd):/workspace \ -w /workspace \ harbor.sourcefind.cn:5443/dcu/admin/base/custom:vllm018-ubuntu22.04-dtk26.04-gemma4-0413 \ /bin/bash 一个非常重要的经验是: -v /sys/kernel/debug:/sys/kernel/debug:ro 这一项不要省。 它不一定直接提升性能,但能显著改善 KFD / HW queue 等底层调试能力,否则很多关键信息根本看不到。 ⸻ 三、微调不是不能做,但未必适合作为第一优先级 最初我们也做了 LoRA 微调验证,而且第一轮其实是成功的: * 训练可以启动 * checkpoint 能保存 * LoRA merge 能完成 * 合并后模型也能被加载推理 从表面看,这条路好像已经通了。 但很快问题就暴露出来了: * HIPBLAS_STATUS_INTERNAL_ERROR * rocBLAS error * Invalid address access * VMFault 这些错误一旦出现,说明问题已经不再是“脚本参数调一调”能解决的,而是进入了: 模型结构 + 框架实现 + 驱动栈 + 底层 kernel 适配 的复杂交叉区。 因此,虽然“第一轮能跑通一次”,但并不代表“持续训练可以稳定复现”。 从工程视角看,这种情况就不适合继续把“微调优先”当成当前阶段主路线。 ⸻ 四、RAG 为什么成了现阶段更实际的方案 当微调链路出现不稳定以后,一个很现实的问题就摆在面前: 项目是继续等训练稳定,还是先想办法把系统做出来? 我们的答案是后者。 因为对于知识服务场景来说,当前最重要的,不是“模型是否被训练过”,而是: * 能不能基于资料回答 * 能不能检索到相关依据 * 能不能处理长文档 * 能不能给出可追溯结果 * 能不能真正上线给人用 而这些能力,RAG 恰恰非常适合。 ⸻ 五、最小可用 RAG:不是先服务化,而是先跑通链路 很多团队在做 RAG 时,一上来就想: * 上向量数据库 * 上服务化 embedding * 上独立 reranker * 上复杂编排框架 * 上完整前后端 结果常常是系统越搭越复杂,但最基本的“问一个问题能不能回答出来”反而迟迟没有闭环。 这次我们走的是另一条路: 先做最小闭环 1. 文档抽取 2. 文本切片 3. 本地 embedding 4. 本地 FAISS 建索引 5. 问题检索 6. 检索结果拼接 7. 交给大模型回答 实际执行顺序非常简单 python3 scripts/rag/extract_docs.py python3 scripts/rag/chunk_docs.py python3 scripts/rag/build_faiss.py python3 scripts/rag/search_faiss.py python3 scripts/rag/rag_query.py 这条链路非常朴素,但价值很高,因为它能最快回答一个问题: 这套方案到底能不能工作? 答案是:能。 ⸻ 六、知识库处理链路:从文档到索引 为了快速跑通链路,我们先把原始文档做抽取、切片和本地索引。 目录结构大致是这样: qwen35_full_bundle/ ├── docs/ ├── knowledge/ │ ├── raw/ │ ├── chunks/ │ ├── index/ │ └── cache/ ├── scripts/ │ └── rag/ 1)抽取文档文本 支持 .pdf、.txt、.md 等原始文件抽取。 python3 scripts/rag/extract_docs.py 2)切片 把长文档切成适合检索的小片段。 python3 scripts/rag/chunk_docs.py 3)构建本地向量索引 embedding 模型我们采用本地加载,避免运行时联网: EMBED_MODEL_NAME = "/volumes/oss0/bge-small-zh-v1.5" 构建索引命令: python3 scripts/rag/build_faiss.py 4)检索测试 先验证召回是否正常: python3 scripts/rag/search_faiss.py 这一步成功的标志不是“回答多漂亮”,而是: * embedding 模型能加载 * FAISS 索引能建立 * 问题能召回到相对相关的片段 ⸻ 七、Qwen3.5 服务启动:几个关键参数比模型本身更重要 在部署 Qwen3.5 时,我们踩过不少坑,最后比较稳定的一组经验是: 1. 不要只靠客户端关思维链 如果希望模型只输出最终答案,不展示 thinking,不能只靠客户端 prompt,而是要在服务端启动时就关掉: --default-chat-template-kwargs '{"enable_thinking": false}' 否则经常会出现: * content 和 reasoning_content 混乱 * 明明要求不要思维链,结果还是输出 * 前端展示异常 2. 如果要支持工具调用,需要显式开启 例如: --enable-auto-tool-choice --tool-call-parser qwen3_coder 不加的话,客户端传 tool_choice: "auto" 会直接报 400。 3. 一套实际启动命令示例 我们后来实际使用的启动方式大致如下(已脱敏): export HIP_VISIBLE_DEVICES=0,1 export VLLM_LOGGING_LEVEL=INFO export VLLM_SPEC_DECODE_EAGER=1 export VLLM_MLA_DISABLE=0 export VLLM_USE_FLASH_MLA=1 export VLLM_RPC_TIMEOUT=1800000 export VLLM_NUMA_BIND=1 export VLLM_RANK0_NUMA=0 export VLLM_RANK1_NUMA=1 vllm serve \ --served-model-name Qwen3.5-27B \ --tensor-parallel-size 2 \ --max-model-len 4096 \ --enable-prefix-caching \ --gpu-memory-utilization 0.75 \ --port 8000 \ --trust-remote-code \ --default-chat-template-kwargs '{"enable_thinking": false}' \ --enable-auto-tool-choice \ --tool-call-parser qwen3_coder \ --api-key ⸻ 八、RAG 问答调用:先检索,再生成 索引建好以后,rag_query.py 负责做两件事: 1. 本地检索最相关片段 2. 把这些片段拼成“参考资料”,再调用 Qwen 生成答案 最小调用方式 python3 scripts/rag/rag_query.py 如果要直接用 curl 调试模型服务,也可以这样: curl http://127.0.0.1:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer " \ -d '{ "model": "Qwen3.5-27B", "messages": [ { "role": "system", "content": "你是一个知识助手,只输出最终答案,不要输出思考过程。" }, { "role": "user", "content": "请解释某个问题" } ], "temperature": 0.2, "max_tokens": 256 }' ⸻ 九、一个非常现实的问题:显卡不是只给一个模型准备的 很多时候,业务方看到大模型项目会问: 为什么需要这么多显卡?为什么还要扩内存? 如果只看“一个问答模型”,这个问题似乎不好回答。 但如果看完整链路,其实很容易理解。 显卡不是只给主模型用的 在一个完整知识服务系统里,可能同时存在: * 主大模型推理 * embedding 向量化模型 * reranker 重排模型 * 工具调用或辅助模型 * 并发请求调度 如果所有东西都抢同一张卡,结果一定是: * 延迟高 * 资源争抢 * 抖动大 * 难排障 内存也不是“可有可无” RAG 本身很吃内存,因为它涉及: * 文档切片 * 索引加载 * 检索缓存 * 上下文拼接 * 中间数据组织 所以在这种场景里: 显卡解决的是算力问题,内存解决的是知识链路问题。 两者缺一不可。 ⸻ 十、现阶段的最终判断 如果把这次实践浓缩成一句话,那就是: 在当前环境下,先把推理 + RAG 做成,比坚持“微调优先”更有工程价值。 这不是说微调没意义,而是说: * 当前阶段,推理已经能跑通 * RAG 已经能形成知识服务闭环 * 微调暂时不够稳定,不适合作为首要交付路径 所以更合理的路线应该是: 当前阶段 * 推理服务优先 * RAG 落地优先 * 知识源整理优先 * 输出质量和引用能力优先 后续阶段 * 继续预研更适合训练的模型基座 * 再评估 LoRA / 微调是否回归主线 * 把 RAG 和微调能力结合起来 ⸻ 十一、最后一点经验:先做成,再做优 很多时候,项目最大的风险不是“模型不够强”,而是路线过于理想化。 如果一开始就把目标定成: * 模型必须先微调成功 * 上线前必须全部能力齐备 * 性能、效果、架构一次到位 那很可能会在工程现实里反复打转。 反过来,如果先问自己一句: 什么路径最有可能在当前条件下先形成可用结果? 很多决策反而会清晰很多。 而对这次项目来说,当前答案已经很明确: 先把 Qwen 推理 + RAG 跑稳,再逐步迭代。 这条路,不一定最理想,但很可能是现阶段最正确的。
Z100
Z100L
全部评论(1)
只看楼主
H
huml
1楼
可以试下https://dap.sourcefind.cn/
6/13
没有更多内容了
--
楼主
Level.1
0 帖子
楼主热帖
暂无数据