通用大模型(General LLM)像是一个博学的本科生,什么都懂一点,但都不精。企业的核心诉求,往往是将其培养成某个垂直领域(如法律、医疗、金融)的博士生。这不仅需要让模型学会“怎么说话”(指令遵循),更要让它真正掌握“行话”和“潜规则”。
这就需要领域知识注入(Domain Knowledge Injection)。
1. 路径之争:CPT vs SFT vs RAG
将知识注入模型,主要有三条技术路线,它们并非互斥,而是互补:
1.1 RAG(检索增强生成)
- 定位:“外挂大脑”。模型本身不记知识,而是学会去图书馆翻书。
- 适用场景:实时性要求高(如今日股价)、数据更新频次高、对幻觉零容忍的场景。
- 局限:受限于Context Window长度,无法处理全库综合分析任务(如“总结过去20年所有判例的趋势”)。此外,检索的准确率直接决定了回答的上限。
1.2 SFT(有监督微调)
- 定位:“纠正习惯”。
- 形式:Q&A 对话数据。
{"input": "合同违约金怎么算?", "output": "根据我司法规..."} - 误区:很多人试图通过SFT注入知识。实际上,SFT 主要用于激发模型的指令遵循能力,教会模型“怎么说话”、“怎么做题”。如果强行用SFT灌输海量事实,模型很容易产生幻觉(Hallucination),因为它只是记住了答案的皮毛,没理解背后的逻辑。
1.3 CPT(增量预训练,Continued Pre-training)
- 定位:“深度阅读”。
- 形式:纯文本数据(Raw Text)。书籍、论文、财报、代码库。
- 作用:这是注入知识的正道。通过海量阅读,模型会调整底层的概率分布,真正“理解”领域内的术语、逻辑和共现关系。
最佳实践路径:
CPT(读书,注入知识) -> SFT(考试,规范行为) -> RAG(查资料,补充细节)
2. 数据准备:密度为王
在CPT阶段,数据的信息密度(Information Density)决定了成败。与其喂给模型1TB的垃圾数据,不如喂给它10GB的教科书。
2.1 数据清洗流水线
企业私有数据通常非常“脏”,直接训练会导致模型性能下降。
- 格式规范化:将PDF、Word、Excel统一转为Markdown。Markdown的结构化信息(标题、列表、加粗)对模型理解文档结构至关重要。
- 去重(Deduplication):
- 精确去重:MD5哈希。
- 模糊去重:使用MinHash + LSH(局部敏感哈希)算法,找出相似度 > 0.8 的文档(如不同版本的合同草稿),只保留一份。
- 隐私脱敏:使用正则或NER模型去除姓名、手机号、身份证号。
2.2 合成数据(Synthetic Data)
对于缺乏高质量语料的领域,可以使用更强的模型(如DeepSeek-V3或GPT-4)将低质量的会议纪要、口语化文档改写成逻辑严密的“教科书风格”文章。这种方法被称为“知识蒸馏”的变体,能显著提升小模型的训练效率。
3. 训练策略:Tokenizer的扩充
很多垂直领域的术语,在通用Tokenizer中是被切碎的。
比如“昇腾910B”,通用分词可能会切成["昇", "腾", "9", "10", "B"](5个Token)。这不仅浪费Context长度,也割裂了语义。
3.1 扩充词表与Embedding初始化
我们应该将高频术语(如“昇腾910B”、“Transformer”、“反向传播”)作为一个整体添加到词表中。
MindSpore 实现思路:Resize Embedding
importmindspore.nnasnnfrommindsporeimportTensor,Parameter,opsimportmindspore.common.dtypeasmstypeimportnumpyasnpdefresize_token_embeddings(model,new_vocab_size):""" 调整模型 Embedding 层的大小以适应新词表 """# 获取旧的 Embedding 表old_embeddings=model.backbone.embedding.word_embedding.embedding_table old_vocab_size,hidden_size=old_embeddings.shapeifnew_vocab_size==old_vocab_size:returnmodelprint(f"Resizing embedding from{old_vocab_size}to{new_vocab_size}")# 创建新的 Embedding 参数,使用正态分布初始化# 注意:更佳的策略是使用旧词表中子词的平均值来初始化新词new_embeddings=Parameter(Tensor(np.random.normal(0,0.02,(new_vocab_size,hidden_size)),dtype=old_embeddings.dtype),name="new_embedding")# 将旧权重复制过去,保证原有能力不丢失ops.assign(new_embeddings[:old_vocab_size],old_embeddings)# 替换模型中的 Embedding 表model.backbone.embedding.word_embedding.embedding_table=new_embeddings# 同样需要调整输出层的 Logit Head(如果它和Embedding不共享权重)ifhasattr(model.backbone,'lm_head'):old_head=model.backbone.lm_head.weight new_head=Parameter(Tensor(np.random.normal(0,0.02,(new_vocab_size,hidden_size)),dtype=old_head.dtype),name="new_head")ops.assign(new_head[:old_vocab_size],old_head)model.backbone.lm_head.weight=new_headreturnmodel扩充的好处:
- 提升推理速度:一个长词现在只是一个Token。
- 增强语义理解:模型将把“昇腾910B”视为一个独立实体,而不是一堆碎片的组合。
4. 评估与迭代:如何知道模型学会了?
领域注入的效果很难用单一的 Loss 来衡量。我们需要构建多维度的评估体系。
4.1 困惑度(Perplexity, PPL)
PPL 衡量的是模型对文本的“惊讶程度”。
PPL=eLoss PPL = e^{Loss}PPL=eLoss
在领域验证集(Held-out Domain Data)上,PPL 应该显著下降。如果 PPL 不降反升,说明模型不仅没学会,反而因为过拟合导致了认知混乱。
4.2 领域能力测试(Domain Benchmarks)
构建类似于LawBench或MedQA的选择题库。
- 方法:在训练过程中,每隔 100 steps 进行一次 Few-Shot 评估。
- 对比:必须与 Base 模型进行对比,确保领域分数有显著提升(通常应提升 10%-30%)。
4.3 结合 2.10 压力测试
虽然 CPT 主要影响模型知识,但词表扩充会略微增加计算量(Logit层变大)。在2.10 压力测试实战中提到的 TPS 指标,可能会因为词表变大而有极其微小的下降(通常可忽略),但如果 RAG 被引入,系统的整体延迟(Latency)将由检索速度主导,这需要重点进行全链路压测。
5. 总结
从通用到专用,DeepSeek的蜕变之旅本质上是企业核心资产(数据)的价值变现。
- 数据清洗是基本功,决定了模型的上限。
- CPT是内功,注入深层知识。
- Tokenizer扩充是招式,优化特定领域的表达。
- RAG是外挂,解决时效性问题。
谁拥有高质量的私有数据,并掌握了高效的注入方法,谁就能在垂直模型的竞争中构建起坚不可摧的护城河。