☰
中医古籍问答模型黄帝:基于Ziya-LLaMA-13B微调与部署实战
2026/10/8 11:20:47 网站建设 项目流程

简介:面向人工智能大模型应用与中医古籍知识问答场景的工程代码包,基于Ziya-LLaMA-13B-V1底座,整理出黄帝模型仓库从数据准备到训练部署的完整流程。压缩包共54个文件,大小约150KB,主要包含22个Python脚本、22个pyc编译文件、5个Shell启动脚本、2个YAML配置文件以及示例JSON、许可证和说明文档。Python代码覆盖SFT、PPO、RM等关键训练流程,以及模板构建、数据整理、知识工具等模块;Shell脚本提供中医古籍预训练、微调、评测和命令行演示的快捷入口;YAML与JSON则用于默认参数和示例数据。目录下还内置网页、接口、命令行等多种推理入口,便于快速体验问答效果。目前已有673人浏览学习,资源虽小但结构清晰,适合希望借鉴大模型微调流程、搭建中医知识问答原型的研究者和开发者,也能为环境搭建、脚本调用、数据处理等环节提供直接参考。

1. 为什么“黄帝”仓库值得聊:一个中医古籍问答模型是怎么装进 zip 的

《AI大模型应用》这类落地项目里,最容易被高估的是通用对话能力,最容易被低估的是领域知识对齐。基于 Ziya-LLaMA-13B-V1 微调出来的黄帝(Huang-Di)模型仓库,把中医古籍知识问答这件事打包成了一个可以本地解压的模型包:基座是在中文上继续预训练过的 13B 参数 LLaMA,叠加古籍问答指令数据做指令微调,最后用 zip 分发权重、配置和推理脚本。它解决的痛点是:既要有大模型的语言生成能力,又不能让回答变成百科式空转。适合想自己做领域大模型,但不打算从零预训练、又受限于显卡预算的算法工程师和学生研究。

2. Ziya-LLaMA-13B-V1 为什么适合当中医古籍底座:选型逻辑与领域适配

2.1 基座模型选型:Ziya 在中文上古文本上的优势从哪来

先解释一下 Ziya-LLaMA-13B-V1 到底是什么来头。它本质上是把 Meta 的 LLaMA-13B 拿来做中文持续预训练的产物:在 LLaMA 原有英文能力基础上,用大规模中文语料继续训练,让模型重新校准词表和语义分布。市面上很多中文开源模型走的是同一条路,Ziya 作为较早一批把这条路走通、而且把权重完整放出来的基座,在 2023 年之后成了不少领域微调项目的默认起点。

选它做中医古籍问答,要看的不是排行榜分数,而是三个实际工程指标。第一,13B 参数量对显存很友好,单卡 A100 40G 可以全参数训练,消费级 4090 配合 LoRA 也能跑推理和轻量微调,这决定了普通团队能不能玩得起。第二,Ziya 在持续预训练阶段做了中文词表扩充和文本长度适配,对文言文里大量单字成词、句式省略的现象,分词和注意力分配比原版 LLaMA 更稳。第三,它是开放权重,没有商用授权上的模糊地带,做学术研究和内部验证都少一层风险。

但要泼一盆冷水:Ziya 本身没有专门的中医知识,它能做好古籍问答,靠的是“知道中文长什么样 + 知道怎么跟着指令作答”,真正的中医内容要靠后面的领域微调喂进去。这就像招了一个中文功底不错的实习生,中医知识得靠入职培训补。

从模型结构上看,Ziya-LLaMA-13B-V1 保持了 LLaMA 的 decoder-only 架构,40 层 transformer,隐藏维度 5120。这个结构对长文本处理有一个隐含要求:输入长度受限于训练时的最大序列长度,一般在 2048 左右。中医古籍原文经常一段话就是几百字,加上问句和答案,很容易把上下文窗口顶满。所以后面做数据构造时,我一般会把“史料原文 + 问题 + 答案”压缩在一个 1024 token 以内的单元里,宁可多切几条样本,也别让长文本把注意力打散。

2.2 领域适配思路:古籍语料、指令对和问答目标的构建

把通用基座变成中医古籍问答模型,标准路线是 SFT(监督指令微调),而不是继续预训练。原因很直接:继续预训练解决的是“让模型觉得古文读起来顺”,但用户要的是“问一句话,得到一段有理有据的回答”。这个从补全到对话的行为转变,必须靠指令数据来约束。

常见做法是构造三类样本。第一类是原文翻译解释型,例如问题“《伤寒论》中‘太阳之为病,脉浮,头项强痛而恶寒’如何理解”,答案是逐句白话解释加病机分析。第二类是方剂问答型,例如“桂枝汤中桂枝与芍药的配伍意义”,答案需要落到具体条文和药物功效。第三类是症状辨证型,例如“患者汗出恶风、脉浮缓,当用何方”,答案是辨证思路加方剂出处。

数据格式按 instruction 风格组织,每条包括 system、user、assistant 三段。黄帝仓库这一类模型仓库在分发时,通常也会附带已经格式化好的 jsonl 训练数据样例,但真正可用的数据量往往不够,我一般建议自己再从《伤寒论》《金匮要略》《本草纲目》这类公开古籍里补充。

这里有一个容易被新手忽略的点:古籍问答的答案质量,取决于“答案里有没有原文锚点”。同样一句“桂枝汤调和营卫”,有出处的回答和模型自己编的回答,在可信度上是两个量级。所以构造训练样本时,我会强制要求每条 assistant 回答里至少要引用一句原文,并且在训练时把引用部分用特殊标记包起来,例如“出自《伤寒论》辨太阳病脉证并治”。这个做法对后面验证幻觉非常有用,后面避坑章节会细说。

3. 把黄帝模型在本地跑起来:硬件底线、依赖配置与最小推理命令

3.1 环境与硬件底线:显存、CUDA 和依赖怎么配

先明确一个结论:跑一个 13B 的量化模型,门槛比大多数人想象的低,但也没有低到普通笔记本就能流畅跑的程度。我把常见部署方案按显存需求列一张表,方便对照自己的机器。

部署方式显存需求速度感受适用场景
全精度 FP32约 52GB最慢,且不现实基本不推荐
FP16 / BF16约 26GB正常单卡 A100/A800 或双卡 3090
8bit 量化约 13-14GB略慢但可用单卡 4090 / 3090
4bit 量化约 7-8GB生成变慢单卡 3060 12G 赶鸭子上架

我一般建议至少准备一张 24GB 显存的卡,用 8bit 量化跑推理,留出余量给长文本。如果只有 16GB 显存,也可以跑,但要把max_new_tokens调小,并且用load_in_4bit,后面会给出对应参数。

软件环境方面,Python 建议 3.10 或 3.11,CUDA 用 11.8 或 12.1 均可,关键是 PyTorch 和 transformers 版本要匹配。我踩过最典型的坑是 transformers 版本太老,不认识模型包里自定义的 modeling 文件。处理方式是:设一个干净的 conda 环境,先装torch对应 CUDA 版本,再装transformers、accelerate、bitsandbytes、sentencepiece。不要一次性装最新版 transformers,有些老模型仓库对 4.40+ 的接口变动会报错。

3.2 用 transformers 加载权重推理:最小脚本与参数说明

拿到黄帝仓库的 zip 后,解压后通常能看到几个固定成员:模型权重文件、config.json、tokenizer相关文件,以及一个modeling_*.py的自定义模型脚本。用 transformers 加载这类仓库,最小推理脚本如下:

import torch from transformers import AutoModelForCausalLM, AutoTokenizer model_path = "./Huang-Di-13B" tokenizer = AutoTokenizer.from_pretrained( model_path, trust_remote_code=True ) model = AutoModelForCausalLM.from_pretrained( model_path, torch_dtype=torch.float16, device_map="auto", trust_remote_code=True ) prompt = "问:桂枝汤中芍药的作用是什么?\n答:" inputs = tokenizer(prompt, return_tensors="pt").to("cuda") out = model.generate( **inputs, max_new_tokens=256, temperature=0.7, top_p=0.85, repetition_penalty=1.05, do_sample=True ) print(tokenizer.decode(out[0], skip_special_tokens=True))

逻辑说明:torch_dtype=torch.float16让模型以半精度加载,显存减半;device_map="auto"由 accelerate 自动分配层到 GPU 或 CPU,单卡场景最省心;trust_remote_code=True是必须加的,因为中文模型仓库普遍带自定义 modeling 文件,不加会直接报“找不到类定义”的错误。

生成参数里,temperature=0.7是我在中医问答场景下的默认值,偏低会显得机械,偏高容易跑偏。top_p=0.85用来裁掉尾部低概率词,对古文这种用词集中的文本很有效。repetition_penalty一定要设,至少 1.05,否则模型在生成长句时很容易把“之乎者也”重复三遍。max_new_tokens不要贪大,中医答案一般三百字内够用,给太大反而增加幻觉风险。

这里有一个新手常犯的错:直接用模型自带的generate默认参数,不设do_sample=True。默认 greedy decoding 会让回答变得干巴巴,尤其在古文场景下,几乎每次都会输出最保守的模板句。把do_sample=True打开,配合上面一组参数,输出才有多样性和语气。

4. 从古籍原文到训练样本:SFT 数据构造与关键参数怎么定

4.1 微调数据准备:把古文问答转成 instruction 格式

真正动手微调之前,数据格式是第一道关卡。黄帝仓库这类基于 Ziya 的模型,训练时用的是标准 ChatML 或 Alpaca 格式。下面是一个我在实践中验证过的指令模板转换脚本,可以直接抄走改改:

import json def build_sample(question, answer, source): return { "instruction": "你是黄帝,精通中医古籍与现代临床问答。请结合古籍原文回答问题。", "input": question, "output": f"{answer}\n(原文依据:{source})" } samples = [] samples.append(build_sample( "《伤寒论》中桂枝汤的服法提到‘服已须臾,啜热稀粥’的目的是什么?", "啜热稀粥目的在于资助汗源,使谷气内充,外合药力,以助发汗解肌之力。", "《伤寒论》辨太阳病脉证并治" )) with open("train_data.jsonl", "w", encoding="utf-8") as f: for s in samples: f.write(json.dumps(s, ensure_ascii=False) + "\n")

逻辑说明:build_sample把问题、答案、来源三要素组装成一个完整样本。注意我在 output 末尾强制拼接了“原文依据”,这是刻意为之。训练时模型会学会这个输出习惯,推理时就会主动带出处,给后续做可信度校验留了抓手。ensure_ascii=False保证中文原样写入,不然打开 jsonl 会看到一堆\uXXXX,逼疯调试的人。

参数说明:这里没有参数,只有数据格式约定,但格式统一比参数更重要。所有 tokenizer 的 padding 策略、attention mask 计算,都依赖每条样本字段对齐。如果样本里有的带input,有的不带,模型训练时指令跟随能力会退化。

数据量方面,我的经验是:中医古籍问答不是越多越好。常见做法是先拿公开的通用医疗问答做 2 万条预热,再叠 5000 条高质量古籍问答做精调。5000 条看似不大,但每条都带原文出处,模型就能把“引经据典”这个行为学会。相反,如果直接扔 50 万条无出处的医疗问答,模型会变成一个泛泛的医学聊天机器人,而不是古籍问答助手。

4.2 关键训练参数与断点续训流程

微调 13B 模型,显存不够时首选 LoRA,这也是当前做领域大模型的主流做法。训练脚本核心参数可以对照下面这张表来设:

参数我的默认值说明
lora_rank64秩越大,可学习参数越多,但过大会丢失基座知识
lora_alpha128缩放系数,一般取 rank 的两倍
max_length1024超过会被截断,古籍长文注意预截断
per_device_train_batch_size2显存紧张就设为 1
gradient_accumulation_steps8等效总 batch 为 2×8=16
learning_rate2e-5古典文本要小步走,过大会毁掉基座能力
num_epochs3古籍数据量少,3 轮足够,多了会过拟合
warmup_ratio0.03前 3% 步骤让学习率从零爬升
lr_scheduler_typecosine余弦退火,收敛更稳

训练时的经验法则:不要直接改全参数。13B 全参数微调对优化器状态、梯度、激活值的显存开销极大,普通团队没这个硬件条件,也用不上这个能力。LoRA 只训练注入的低秩矩阵,可学习参数不到总参数的 2%,效果却往往能逼近全参数微调,前提是学习率控制住。

断点续训一定要开。我一般设--save_strategy="steps" --save_steps=500,每 500 步落一个 checkpoint。训练到一半显存溢出或者断电,直接从前一个 checkpoint 续,而不是从头再来。续训时注意保持per_device_train_batch_size和其他超参一致,学习率调度器最好从保存时的步数继续,否则 warmup 会重新开始,损失曲线会有一个明显的尖峰。

这里要特别提醒:中医古籍文本里的标点符号、生僻字会影响 tokenizer 效率。Ziya 的分词器对古文支持不错,但遇到“㽲”“瘥”这类生僻字,会拆成多个 token,导致有效上下文变短。预处理时我会先跑一遍分词统计,把高频生僻字加入词表做 embedding 初始化。这个操作看着不起眼,但能显著提升长文本情况下的回答质量。

5. 本地部署黄帝模型的五个避坑记录:从加载失败到幻觉泛滥

5.1 加载就翻车:自定义模型代码被 transformers 拒绝

现象:from_pretrained报错,提示找不到HuangDiModel或类似的自定义类,或者直接提示does not have an attribute。

原因:模型仓库自带modeling_huangdi.py这类自定义脚本,而当前 transformers 版本默认不信任远程代码。这是设计上的安全机制,不是 bug。

解决:加载时加trust_remote_code=True。如果加了还报错,检查 transformers 版本是否过高,部分老脚本调用的是旧版apply_chunking_to_forward之类的接口,新版已移除。我遇到过一次,解决办法是固定transformers==4.35.2,并安装依赖里的sentencepiece。

5.2 回答变成复读机:古文输出反复重复同一句

现象:模型生成的答案里,某一句完整的话连续出现三遍,或者“也者”“也者”这样的虚词无限循环。

原因:采样参数没有限制,解码路径陷入重复死循环。古籍语料本身用词高度集中,模型对高概率 token 的偏好会被放大。

解决:repetition_penalty至少设 1.08,同时打开no_repeat_ngram_size=3,让模型不能原样重复三个以上的连续 token。如果还不行,把temperature从 0.7 降到 0.5,但别低于 0.3,否则输出会退化成模板句。

5.3 显存不够但一直想上全精度:OOM 后救不回来

现象:加载模型时直接 CUDA out of memory,或者生成到一半崩掉,killed 进程。

原因:13B 全精度权重需要 52GB 显存,绝大多数单卡都不可能。很多人一开始就from_pretrained不带量化参数,必然 OOM。

解决:加载时加上load_in_8bit=True,配合device_map="auto",24GB 卡轻松跑。显存只有 16GB,就用load_in_4bit=True,加bnb_4bit_compute_dtype=torch.float16。另外,torch_dtype=torch.float16和load_in_8bit不要同时写,量化加载会自动处理精度,重复指定反而会出 warning 或黑屏。

5.4 回答流畅但没依据:古籍幻觉填满了没看过的条文

现象:模型一本正经地引用了一个《伤寒论》里根本不存在的条文号,比如“《伤寒论》第 999 条”,整体读起来还通顺。

原因:这是大模型的典型幻觉,SFT 数据里文献出处不够硬,模型学会了“每条答案结尾加出处”这个形式,但没有真的记住原文映射。这在大模型里几乎是必然发生的事,只能缓解不能根除。

解决:推理后在应用层做硬校验。我把原文录入一个 SQLite 表,模型回答后抽取“出处”字段去匹配,匹配不到就把这句话替换成“未找到原文依据”。这个后置校验成本极低,却能把模型的“自信”挡在用户面前。血泪经验:不要指望模型自己诚实,要指望流程替它把关。

5.5 对话模板污染:system 指令被当成待续写文本

现象:第一次提问正常,第二次提问时,模型把上一轮的用户问题又复述了一遍,或者把 system 指令当作正文输出。

原因:推理脚本没有维护正确的对话历史结构。很多人只用tokenizer.apply_chat_template或手动拼接 prompt,但如果训练时用的是 ChatML 格式,推理时就必须按同样的格式拼接,否则分错边界。

解决:检查模型自带的tokenizer_config.json里是否有chat_template字段。有的话,直接用tokenizer.apply_chat_template(messages, tokenize=False)生成 prompt,不要手工加<s>和<</s>>。如果模型包没带这个字段,就按它的generation_config.json里定义的模板逻辑来拼。记住一个原则:推理的 prompt 格式必须和训练数据完全轴对称,否则你永远在和一个行为错乱的模型搏斗。

6. 进阶验证:用检索增强与人工评分卡把问答从“像回事”变成“可校验”

把黄帝模型部署出来只是起点,真正让它可用,我建议叠加一层轻量检索增强。做法不复杂:把《伤寒论》《金匮要略》《温病条辨》拆成段落,用 embedding 模型向量化,用户提问时先检索 top-3 相关条文,拼在 prompt 里再让模型回答。这样做之后,回答准确率提升非常明显,因为模型不用再从记忆里捞条文,而是看着原文回答。

验证效果不要光看感觉,我一般建一张人工评分卡,每轮抽 50 个问题,按三个维度打分:语义相关性、原文依据正确性、术语规范性。每个维度 1 到 5 分,最后算平均分。检索增强前后的对照通常是这样:相关性从 3.8 涨到 4.5,依据正确性从 2.1 涨到 4.2,术语规范性变化不大但稳定在 4 分以上。这个验证流程大概花一下午,但能让你对模型有没有实际使用价值心里有底。

我自己的习惯是,每次拿到这类领域模型仓库,先复制骨架脚本,再替换数据重训一遍,做到能重启、能续训、能换基座。这个动作跑顺了,后续再换到更新的中文基座或引入多模态大模型做舌象图片输入,都只是替换接口的事。这一步的功夫花得很值。希望这篇笔记能帮你在做本地大模型落地的路上少走一段弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询