
搞科研的人最烦什么组里积累了上百篇论文、内部标准、实验记录、代码注释每次想查一个参数或者某个方法的具体出处都要翻半天。通用大模型能聊但不能直接用它不知道你们组的“黑话”更不敢把敏感资料喂到云端。我这两年把课题组私有大模型这条路完整走了一遍国产开源底座选型、领域语料构建、RAG检索增强、LoRA/QLoRA高效微调、知识蒸馏、GPTQ/AWQ量化最后用vLLM把服务拉起来应对多人并发。前后迭代了几个版本才稳定。如果你也在实验室、小团队或项目组里做私有AI这篇把每个阶段的选型和坑都摊开说可以直接当落地清单用。1. 先把“私有AI”这件事拆清楚1.1 为什么最终没有直接调通用大模型API很多人第一反应是把数据往通用大模型API里一传写个Prompt就完事。但在真实课题组里这有几个绕不过去的问题。首先是数据边界。论文初稿、未公开的实验数据、合作单位的内部材料这些东西出了内网就是问题即便你签了保密协议心理上也不踏实。其次是成本API按token计费RAG场景每次要把检索到的长段落塞进上下文一天跑几千次费用肉眼可见地涨。核心问题是可控性通用API的模型行为不可调你没法让它强制输出“基于组内规范”“引用指定文档”也没法在它乱答的时候定位原因。所以私有化不是炫技是被需求逼出来的。课题组的数据量通常不算大几万到几十万条文档但专业术语密度高、领域知识割裂严重。这种情况下与其期待一个大模型“记住”所有内容不如把架构拆成底座模型负责语言理解和生成知识库负责事实供给微调和蒸馏负责行为校准。这样的好处是每一层都能单独替换、评测和回滚。1.2 国产开源模型选型的判断标准我见过太多人一上来就挑最大参数量的模型结果一张卡跑不起来最后改来改去。选型的核心约束其实是三样显存、推理延迟、可微调性。我整理了一个选型表格适合课题组和小团队参考。模型参数量上下文单卡推理显存参考适合场景Qwen2.5-7B-Instruct7B32K-128K16G以上BF16日常问答、RAG基线、LoRA微调Qwen2.5-14B-Instruct14B32K-128K28G以上复杂指令、长文档摘要Qwen3-8B / 30B8B/30B更长上下文32G以上需要更新知识的场景DeepSeek-R1-Distill-Qwen-14B14B32K28G以上数学、推理、代码ChatGLM4-9B9B32K20G左右中文办公、信息抽取选型时我主要看四条。第一中文能力和术语理解不能用跑分掩盖而是拿你自己领域里五十个“黑话”去试。第二许可证是否允许商用和模型权重分发很多国产模型现在都是宽松许可但你要看一下对“输出内容”和“二次分发”的限制。第三生态是否跟得上HuggingFace、ModelScope上有没有量化版PEFT、LLaMA-Factory、vLLM是否直接支持。第四微调和部署的社区案例多少否则遇到问题只能自己啃。我个人的建议是预算有限就从7B/8B开始跑通全链路再往上扩。别小看7B配合优质的RAG和LoRA微调很多场景能接近甚至超越未调优的32B模型而且推理速度快得多。1.3 “底座检索适配”三层架构各干什么活项目推进时我刻意把系统分成了三层避免一开始就把问题揉成一团。底座模型层解决“怎么说话”它决定用词、语法、上下文理解、指令跟随。这一层不要直接承载领域事实因为大模型的强项不是记忆而是语言生成。知识检索层解决“说什么”RAG把用户问题转成向量去知识库捞相关段落再把段落拼接成上下文送给模型。这一层负责事实供给也是后面2、3、4章的重点。行为适配层解决“怎么按你的规矩说话”LoRA微调和知识蒸馏都在这个层面让模型输出风格、格式、引用习惯更贴近课题组需求比如必须给出文档编号、必须承认“未在知识库中找到”。顺序上我强烈建议“先RAG再微调”。因为RAG能快速解决事实缺失微调解决的是风格和行为。如果你什么都没做就微调模型会把训练数据里的片段背下来一旦用户问的问题跨文档它照样幻觉而且你很难判断是知识库没召回还是模型在瞎编。2. 领域语料构建与RAG知识库不是把PDF丢进去就行2.1 语料采集、清洗与解析RAG最容易被低估的是前端语料处理。很多人直接把PDF往向量库里一丢结果召回率惨不忍睹原因往往是文本里混着页眉页脚、参考文献、图表标签甚至扫描件全是乱码。我跑项目时的流程是这样。第一步是采集。把论文PDF、Word文档、实验报告模板、专利文件、内部SOP全部集中到一个目录按来源分类。第二步是格式归一化。PDF用PyMuPDF抽取文本扫描版优先走MinerU或者OCR工具做版面分析把标题、正文、表格分开。Word和Markdown用pandoc转成统一格式。第三步是清洗。去除页眉页脚、连续的参考文献列表、URL、无意义的换行。这里最容易被忽略的是表格PDF里表格跨页后直接抽出来是断的必须做单元格级别的合并。清洗后的文档建议统一转成Markdown或JSON结构保留标题层级关系。这一步看着麻烦但对后面切分和召回非常有帮助因为结构信息比纯文本块更容易被检索模型理解。2.2 Chunk切分、Embedding模型和向量库选型切分策略是RAG召回率最大的影响因素之一。最省事的办法是固定长度切分比如512个token重叠128个token。这个方案适合内容比较零散的内部制度。但论文和报告有明确的章节结构我建议做结构感知切分先按Markdown标题拆成小节再对超长小节做固定长度兜底这样每个chunk都自带“章节上下文”。还有一种进阶方式是“父子chunk”小chunk负责精确召回父chunk保存更大上下文。具体做法是检索时只匹配小chunk返回时把父chunk整体送给模型既保证命中又避免上下文碎片化。Embedding模型方面国产方案现在很能打。BGE-M3是我用得最多的支持中文、英文、长文本也能输出稀疏向量用于混合检索。Qwen3-Embedding-0.6B是后起之秀0.6B参数量很小中文效果不错适合内网离线部署。如果你看到有人讨论“docker vllm/vllm-openai:v0.27.1加载qwen3-embedding-0.6b”这里要提醒一下vLLM主要服务生成模型加载Embedding模型要看镜像版本是否支持Embedding接口如果支持模型名写成qwen3-embedding-0.6b就行如果版本不支持老老实实用FastAPI加sentence-transformers单独起一个服务避免给自己添堵。向量库选型上轻量场景用Chroma或FAISS就够。数据量上了百万级别建议Milvus或者Elasticsearch。我并不迷信高性能向量库因为课题组通常数据量不大关键是把检索链路做对。2.3 RAG的召回瓶颈、命中率与重排RAG最常见的问题是“检索到了但没排到前面”。我用BM25关键词检索和向量检索双路召回然后把两路结果合并再用一个重排模型统一打分效果远比单路向量检索稳。评测指标上最该盯的是Hit Rate和MRR。Hit Rate是“答案所在文档片段是否出现在前N个结果”MRR看的是正确片段排得多靠前。我每次调完切分策略和Embedding模型都会用一组带标准答案的测试题跑一下对比改动前后这两个指标。如果Hit Rate低于0.7说明问题在召回链路不要急着换大模型。还有一个容易被忽视的问题RAG瓶颈往往不在检索而在“上下文被无关内容污染”。假设你取top_k5里面只有一条有用模型要在一堆噪声里找答案能力再强也容易翻车。所以我后来把top_k从5降到了3或者只用重排后的前2条。别贪多相关性比数量重要。2.4 RAG知识库能存图片吗这个问题我被问过很多次。答案是能但要看你想怎么用。文本知识库本身没法“理解”图片路径通常有两种。一种是把图片里的文字提取出来再进入知识库扫描版论文、图表截图先走OCR或版面分析把文字当作正文图片存一个路径链接。这样做的好处是检索结果能对应到原文档读起来有据可查。另一种是真正做多模态检索图片不用转文字而是用多模态模型直接生成图片描述文本描述进入向量库也可以直接用CLIP类模型做图文联合向量用户输入文字就能匹配图片。这个方案适合实验装置照片、质谱图、电路板图等场景。我的建议是如果图片里的关键信息主要是文字就走第一种如果图片传达的是视觉特征再上多模态方案。2.5 知识割裂问题Ontology RAG和GraphRAG普通RAG的问题在于知识割裂。每一条chunk自己是完整的但不同文档之间的关系没有建立起来。比如A文档说“用方法M做了实验”B文档说“方法M的参数是xx”它们各自都能被检索到但模型不知道这两条信息属于同一个实验链条。后来我引入Ontology RAG的思路先建立领域实体和关系清单比如“实验方法”“参数”“仪器”“样本来源”然后把文档里的实体抽取出来链接到知识图谱检索时把关键实体所在的子图数据作为额外上下文一起送给模型。GraphRAG也是类似逻辑用图谱组织社区结构回答跨文档问题明显稳了很多。对课题组来说不需要构建一个庞大本体先把最核心的“实体-关系”做一个几十条的轻量本体就足够改善回答的连贯性了。3. LoRA/QLoRA高效微调用最小显存改变模型行为3.1 LoRA和QLoRA的原理以及为什么能省显存如果你搞过全参微调一定清楚7B模型在BF16下全参微调的显存有多恐怖。LoRA的思路是冻结原模型权重只训练两个低秩矩阵A和B假装用一个小矩阵逼近“权重变化量”。这样训练参数只占原模型的0.1%到1%显存需求骤降。QLoRA在LoRA的基础上更进一步把底座模型量化成4-bit的NF4格式存储同时配合分页优化器把优化器状态放到CPU内存训练时再从CPU换到GPU。以7B模型为例全参SFT可能需要60G以上显存QLoRA在单张24G卡上就能跑。这个“省显存”不是没有代价的训练速度会变慢而且量化损失会在梯度回传时引入噪声。但对课题组来说能在一张卡上完成迭代比追求极致效果重要得多。3.2 微调数据构造质量比数量重要很多人以为微调就是把文档丢给模型“背书”。一旦你这么做模型会变得非常“油嘴滑舌”看似在回答其实是在重复训练语料里的段落。我踩过这个坑后总结了一套数据构造方法。微调数据至少要分三类。第一类是指令问答对一条指令对应一条标准回答回答要干净、不啰嗦、带引用格式。第二类是信息抽取或格式转换任务比如“从这段实验记录中提取反应条件并输出JSON”。第三类是修正样本把模型之前回答错的、跑偏的案例拿回来人工修改后做成negative做纠正。比例上我推荐指令问答占70%格式任务占20%修正样本占10%。构造数据时最核心的原则其实很简单你希望模型上线时怎么回答训练时就给什么样的回答。不要写那种长篇大论没有来源的答案模型学到的就是你交给它的生成范式。3.3 训练参数怎么调rank、alpha、学习率、epoch用LLaMA-Factory或PEFT跑LoRA时我常被问参数怎么设。我的基线做法是lora_rank16lora_alpha32target_modules选q_proj、k_proj、v_proj、o_proj最多再加gate_proj和up_proj学习率用2e-4到1e-5之间递减epoch跑1到3轮。你看到lora_alpha32似乎和rank翻倍没什么关系其实alpha主要控制更新权重缩放固定成rank的两倍只是经验值不必太纠结。上下文长度方面RAG喂进来的段落可能很长微调时建议把max_seq_len设置成1280或2048至少和线上推理长度一致避免“训练时短、推理时长”导致的泛化崩坏。数据量上几千条高质量样本就够看到效果不需要几十万条。有一点要特别提一下LoRA这个缩写在大模型领域是低秩适配但如果你在通信项目里搜“LoRa通信代码”那是另一个完全不同的概念。写代码时注意别混在一起防止拿错库。3.4 过拟合、遗忘和验证方法微调最容易踩的两个坑是过拟合和灾难性遗忘。过拟合的表现是训练集loss很低但验证集和真实问题一塌糊涂。灾难性遗忘更隐蔽模型会做领域问答了但通用能力、代码能力变差。我的做法是每次微调完成后固定跑三组评测领域评测集、通用中文能力小测、上一轮微调前的老样本回归测试。如果领域得分涨了通用分掉了超过5%就降低epoch或者加大lora_rank而不是硬着头皮继续练。另外推荐多保存几个checkpoint用不同的验证集对比不要只看最后一个epoch。还有一个小技巧如果只想提升RAG场景下的回答风格不需要把训练数据里的“知识”喂给模型。给模型一批“带着上下文回答问题”的样本让它学会“只能根据给定段落回答不要展开想象”这比让它背知识点有效得多。4. 知识蒸馏让小模型从大模型身上学4.1 为什么蒸馏通常放在微调之后蒸馏这步经常被忽略。课题组一开始直接上7B模型效果还不错但并发一上来单卡推理吞吐跟不上了。换更小模型比如3B/4B效果又下降。蒸馏就是用来弥补这个差距的用一个更大的教师模型生成领域偏好数据再拿这些数据训练小模型让小模型“继承”教师模型的输出习惯。顺序上我建议先把LoRA/QLoRA微调跑通让模型具备领域基础然后再做蒸馏。因为蒸馏的核心是“教师模型要教得对”如果教师模型本身连你们组的术语都不熟生成的训练数据就是垃圾。顺序反了蒸馏只会放大问题。4.2 蒸馏数据怎么生成教师模型、提示词与清洗我的教师模型选的是一个参数量更大的开源模型比如Qwen2.5-32B或者DeepSeek系列。虽然显存大了点但只做离线生成不跑线上推理所以可控。生成蒸馏数据的提示词模板有几个要点。先给模型一段领域原始文档再给一个问题要求它“只根据文档内容回答不要添加任何外部知识”并且输出格式固定成“结论依据原文位置”。一次生成一条数据后我会跑一个简单的规则校验回答里是否出现了原文的关键字是否包含“我猜测”“可能是”这类模糊表述如果有就标记为候选坏数据。生成完毕后务必做去重和难度筛选。大模型生成相似问题很频繁重复数据会害了小模型让它在同一地方反复过拟合。我建议对生成数据做Embedding去重相似度大于0.95的直接丢弃。4.3 温度、软标签和训练细节知识蒸馏有两种常见姿势。一种是纯“伪标签”方式拿教师模型的输出当硬文本训练学生模型这本质上就是SFT。另一种是更标准的蒸馏教师模型输出每个token的概率分布学生模型用KL散度去逼近这个分布重点照顾高概率候选词。训练时温度T很重要。T太高概率分布被抹平小模型学到的都是些“都差不多”的错误信号T太低软标签退化成硬标签蒸馏就没有意义。我习惯先用T2.0做前几轮再在后续轮次降到1.0或0.5让模型先学粗糙规律再收紧到真实数据。如果你嫌软标签蒸馏实现麻烦可以先跑硬文本伪标签蒸馏效果也不错。关键是生成数据的教师模型质量要高且学生模型必须和教师模型同系列或至少Tokenizer基本一致否则分布差距过大蒸馏损失很难收敛。5. 量化压缩GPTQ/AWQ怎么选以及量化后怎么不掉点5.1 GPTQ和AWQ的本质区别模型训练好后部署前的最后一步是量化。常见的两个方案是GPTQ和AWQ。GPTQ的思路是逐层量化同时最小化“量化后权重和原始权重”之间的误差用一种近似二阶优化的方式把每一层对整体输出的影响考虑进去。AWQ的思路不一样它直接观察激活值的分布找出那些对激活贡献大的重要权重通道量化的过程中为这些通道保留更高精度。简单说GPTQ更关注权重本身AWQ更关注权重在实际输入下的影响力。我自己的经验是AWQ在低比特位4-bit下通常比GPTQ更稳尤其在带领域微调LoRA适配器的模型上。GPTQ在高比特位8-bit或者校准数据足够充足时表现也很好。两者最终效果差别不会特别大真正影响部署体验的是生态支持度vLLM对AWQ和GPTQ都支持但老版本对某些模型的兼容性有差异选之前先看vLLM文档。5.2 量化实操细节校准集、group size和显存量化不是把模型文件改小就完事你还需要一个校准数据集。这个校准集不能随便用几个句子最好从你的领域语料里采样覆盖多种句式和长度让量化过程“看到”线上数据的样子。以AutoAWQ为例我常用参数是--quant_method awq --bits 4 --group_size 128group_size代表每128个权重共享一个缩放因子。group_size越小量化越精细模型质量更高但显存和计算开销也更大。如果硬件紧张可以试试group_size256效果差距不算大。这里有一个经验坑量化后的模型不要在推理时再叠加QLoRA训练时的NF4底座。你没看错QLoRA的底座量化是训练时用的和静态度量化不是一回事。正确做法是先把LoRA适配器融合回全精度或者半精度模型然后再做GPTQ/AWQ量化最后让vLLM加载量化产物。顺序错了模型输出会翻车。5.3 量化真的会掉点吗量化一定会有损失但好的量化流程可以把损失控制在可接受范围。我在量化前后会跑同一组领域测试题分别记录生成结果的BLEU、ROUGE或者更主观的“关键信息是否完整”。如果量化后关键信息丢失说明校准集或者量化参数有问题别硬上。还有量化和蒸馏是可以叠加的。你可以在SFT之后先蒸馏一个更小的模型再做量化最终部署的模型可能只有原始教师模型的几分之一大小但效果仍然不错。这条链路我测下来比较稳不要跳过任何一步。6. 本地化部署与高并发推理vLLM是当前最优解6.1 vLLM为什么快PagedAttention和连续批处理模型有了量化完了下一步是把服务拉起来。如果只给自己一个人用Ollama或LM Studio就够了但课题组里好几个人同时问问题还要接知识库API普通推理框架扛不住高并发。vLLM的核心是PagedAttention把KV缓存切成固定大小的块像操作系统的虚拟内存一样按需分配避免碎片化显存浪费。另一个是连续批处理请求不再等整个批次跑完再切换而是动态插入和挤出GPU利用率高了不少。实测下来7B量化模型在vLLM上比普通HuggingFace管线吞吐至少快两三倍这是很直观的体感。顺带说一句SGLang作为一种竞品方案也有自己的优势但vLLM的社区和生态更成熟遇到问题更容易找到答案。6.2 用Docker快速部署服务部署我用的是Docker加vllm/vllm-openai镜像。最简命令长这样docker run --gpus all \ -p 8000:8000 \ --shm-size8g \ vllm/vllm-openai:v0.27.1 \ --model Qwen/Qwen2.5-7B-Instruct \ --quantization awq \ --served-model-name qwen7b \ --max-model-len 8192 \ --gpu-memory-utilization 0.9参数解释一下。--quantization awq告诉vLLM按AWQ量化权重加载--served-model-name是暴露给客户端的模型名--max-model-len限制最大上下文长度过大会预占KV缓存导致并发上不去--gpu-memory-utilization 0.9表示允许vLLM占用90%显存留一点余量给CUDA上下文和临时张量。如果你的模型是自定义的本地路径把--model参数改成/models/your-model-path并挂载数据卷。如果还想在同一个Docker环境里加载qwen3-embedding-0.6b做Embedding先确认当前vLLM版本支持Embedding接口并把模型名写成qwen3-embedding-0.6b保险起见Embedding服务我还是推荐分开部署别跟生成服务挤在一起。6.3 并发参数调优和接口对接加载完成后本地就有一个兼容OpenAI的API服务跑一个简单请求验证curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d {model:qwen7b,messages:[{role:user,content:把知识库里关于某方法的段落总结成三条要点}]}如果你想压测并发注意监控两个指标TTFT首token延迟和吞吐tokens/s。--max-num-seqs控制并发序列数太低会浪费算力太高会频繁抢占KV缓存。我一般从16开始调观察显存峰值和TTFT曲线。如果TTFT突然飙升说明并发已经撞到显存上限需要降--max-model-len或--max-num-seqs。6.4 Ollama、LM Studio和vLLM/SGLang的适用边界很多人搞不清楚Ollama和vLLM的关系。我的判断是Ollama适合单机快速体验模型管理方便但不适合精细控制并发和上下文也不方便接复杂知识库链路。LM Studio适合没有Linux环境的人做模型预览。vLLM和SGLang才是生产级选择。Java后端团队接入时可以用LangChain4j的Easy RAG功能它把文档解析、向量化、检索和LLM调用串好了能快速把vLLM的OpenAI接口配置进去。我之前帮一个组搭过用LangChain4j的EmbeddingStore和AiServices配置文件里指向http://localhost:8000/v1即可省去自己写RAG管道的功夫。如果模型换成DeepSeek系列vLLM部署方式基本一样只是模型名和分词器不同。需要注意显存DeepSeek的MoE结构虽然参数量大但激活参数小用vLLM部署时配置--max-num-seqs要更保守因为MoE的显存行为跟Dense模型不太一样。7. 常见问题与排查实录7.1 知识库召回不准怎么办我会按这个顺序排查。第一检查切分粒度是不是把一句话劈成了两半建议改成结构切分或父子chunk。第二换Embedding模型BGE-M3和Qwen3-Embedding值得一试。第三加混合检索向量BM25双路召回。第四加重排模型BGE-reranker通常能把正确片段提到前两名。每改一步就重跑一次Hit Rate别凭感觉。7.2 微调后模型乱回答、套话多怎么办套话多说明训练数据里有大量“正确的废话”。把训练数据翻出来看看如果很多回答都是在讲通用原则而不是结合给定上下文模型自然学会敷衍了。建议把RAG场景下的回答改成“先给结论再引用原文编号最后给一句解释”并把这种格式固化到数据集里。乱回答另一个常见原因是训练时没有加系统提示。在LLaMA-Factory里要确保每条指令都带系统提示模板否则模型上线时面对系统提示会手足无措。7.3 部署时显存溢出或吞吐太低显存溢出第一件事看--gpu-memory-utilization留太少会崩开到0.9通常安全。然后看--max-model-len8K看起来不算长但KV缓存会占掉大量显存降到4K试试。如果并发一直上不去考虑加一张卡用--tensor-parallel-size 2做张量并行。吞吐太低先看--max-num-seqs是不是太小再检查是否卡在单个长请求上。长请求会占住连续显存导致后续请求排队。可以用多路短请求压测把平均吞吐调到稳定值。7.4 热词里那些“坑”汇总这段时间搜“RAG知识库能存储图片嘛”的人特别多我在第2.4节已经给了方案图像转文本后入库或者用多模态向量。搜“取得了RAG知识割裂问题”的建议直接上轻量本体/知识图谱方案而不是继续堆更多chunk。搜“LoRA微调”的人容易把LoRA和通信里的LoRa搞混其实两者毫无关系。不要被网上的模型帖子带偏找教程时认准“低秩适配”这个关键词。最后提一句很多社区里流行的绘画类LoRA权重本质是风格迁移和课题组做私有AI的场景差得很远。不需要在这些权重上花时间也别把时间投入任何与学术和项目无关的敏感内容上。专注自己的数据做出来的模型才是真正有用的。8. 我想说的最后一件事这套链路走完我最大的体会是顺序千万别乱。先做好语料清洗和RAG再利用LoRA做行为微调蒸馏负责压缩量化负责部署最后用vLLM扛并发。每一步都有各自的目的跳步或者回头重做成本都很大。很多团队一上来就想微调忽略语料和检索最后模型聊天很顺畅但一问到具体实验记录就露馅。还有的拼命堆参数把rank开到128结果模型只会背训练样本。做私有AI和做科研一样先把评测集建好再谈优化。我给自己的规矩是任何一次改动都要有领域测试集的分数变化做依据没有评测的“感觉变好了”都是假象。接下来如果条件允许我会把每个阶段的脚本和配置整理成一套可直接复用的模板再配合一套自动评测流程让课题组可以快速把新文档加进去。毕竟私有AI的价值不在于模型能聊而在于它真正变成了组内知识的检索助手和写作助手。