简介这份资源面向希望将大语言模型落地到中文法律场景的开发者与算法学习者围绕法律知识问答、法条理解与指令微调等任务提供了一套可复现的工程实践材料。压缩包共42个文件约3.41MB以Python脚本为主体配合JSON指令与配置数据、Shell训练与推理脚本以及少量图片、说明文档和许可证文件覆盖数据处理、模型微调、推理评估到Web界面演示的完整链路。目录中可见法律词表、罪名数据、指令训练与推理样例等模块便于读者理解法律领域语料的组织方式与训练流程。目前已有120人学习下载。对于想研究领域大模型微调、构建法律问答原型或补充中文法律语料处理思路的读者可借此快速搭建实验环境参考其中的脚本与配置完成训练、合并与推理验证并在此基础上替换自有数据做二次开发。1. 中文法律大模型落地从压缩包到能回答法条的最小闭环你拿到一个叫《AI大模型应用》-基于中文法律知识的大语言模型.zip 的包第一反应大概率是解压之后怎么让它跑起来而不是先读论文。中文法律知识这个场景很特殊它不像通用闲聊用户问的是“民间借贷利率超过多少不受保护”“劳动合同到期不续签要不要赔”答错一个字就是事故。所以这个标题背后真正要解决的是把中文法律语料灌进一个大语言模型让它能按法条口径回答并且你能在本地或内网把它跑通。适合两类人一是想做大模型应用开发但没碰过垂直领域的工程师二是手里有法律问答需求、想先验证可行性再投入的团队。下面按“先立住原理再动手复现最后讲坑”的顺序拆开。2. 中文法律知识怎么进模型三条路线和选型理由2.1 继续预训练、指令微调、RAG 的边界在哪把中文法律知识塞进大语言模型常见做法就三条。第一条是继续预训练continue pretraining拿基座模型在大量法律文本上再跑一遍语言建模目标让模型“见过”法条表述。第二条是指令微调SFT构造“问题-法条答案”对让模型学会按法律问答的格式输出。第三条是检索增强生成RAG把法条库做成向量索引提问时先检索再让模型组织答案。选型理由很直接继续预训练成本最高需要几十 GB 以上法律语料和较多 GPU 时长但能让模型内化法律术语指令微调成本中等几千到几万条高质量问答就能见效适合让模型学会“引用第几条”RAG 成本最低法条更新时只改索引不动模型但依赖检索质量。我一般会建议如果法条会频繁修订优先 RAG如果问答风格要求严格SFT 打底继续预训练只在你有稳定算力和清洗好的语料时才做。三者不互斥常见组合是“基座 SFT RAG”。2.2 从压缩包到可运行环境与目录先理清拿到 zip 后不要急着 pip install。先解压看目录结构典型会包含模型权重目录、配置文件、推理脚本、依赖清单、示例数据。先确认权重格式是 HuggingFace 的 safetensors 还是 GGUF这决定你用 transformers 还是 llama.cpp 系。下面是一段检查目录和依赖的 bash逻辑是先把“有什么”看清楚再决定装什么。# 解压后进入项目根目录先看顶层结构 unzip AI大模型应用-基于中文法律知识的大语言模型.zip -d legal_llm cd legal_llm # 列出目录重点找 config.json、*.safetensors、*.gguf、requirements.txt find . -maxdepth 2 -type f | sort # 看依赖清单里有没有 torch、transformers、peft、sentence-transformers cat requirements.txt 2/dev/null || echo 无 requirements.txt需手动确认依赖参数说明-d legal_llm指定解压目录避免污染当前目录find -maxdepth 2只看两层防止权重文件太多刷屏。如果看到.gguf文件说明作者可能已经做了量化适合本地部署大语言模型如果只有.safetensors那需要完整 PyTorch 环境。这一步的坑是有些包把权重放在子目录里config.json和权重不在同一层加载时会报路径错所以先find确认相对路径。2.3 最小推理脚本让模型先开口环境确认后写一个最小推理脚本目标不是效果好而是先让模型输出中文法律相关句子。下面用 transformers 的 pipeline 做示例逻辑是加载分词器和模型喂一个法律问题看输出是否通顺。from transformers import AutoTokenizer, AutoModelForCausalLM import torch model_path ./legal_llm # 换成实际权重目录 tokenizer AutoTokenizer.from_pretrained(model_path, trust_remote_codeTrue) model AutoModelForCausalLM.from_pretrained( model_path, torch_dtypetorch.float16, # 显存不够改 int8 或换 GGUF device_mapauto, # 自动分配 GPU/CPU trust_remote_codeTrue ) prompt 民间借贷利率超过多少不受法律保护 inputs tokenizer(prompt, return_tensorspt).to(model.device) with torch.no_grad(): outputs model.generate(**inputs, max_new_tokens128, do_sampleFalse) print(tokenizer.decode(outputs[0], skip_special_tokensTrue))逻辑说明trust_remote_codeTrue是因为部分法律模型自定义了模型类torch_dtypetorch.float16是显存和精度的折中7B 模型约需 14GB 显存13B 约 26GB。do_sampleFalse走贪心解码法律问答要稳定不要随机发挥。如果报CUDA out of memory先降max_new_tokens再考虑 4bit 量化。这一步跑通说明权重和依赖没问题接下来才谈效果。3. 把法条问答做准数据构造、微调与检索的实操3.1 法律指令数据的构造格式与清洗要点SFT 的效果八成取决于数据。中文法律问答对常见来源是裁判文书、法条释义、法律咨询记录但原始文本不能直接喂。我一般会整理成 JSONL每行一个样本字段固定为instruction、input、output。instruction写任务input放具体问题output放带法条引用的答案。清洗时重点做三件事去掉当事人真实姓名和身份证号统一“第X条”的写法把口语化问题改写成规范问法。import json, re def clean_sample(q, a): # 脱敏去掉手机号、身份证号 q re.sub(r1[3-9]\d{9}, [电话], q) a re.sub(r\d{17}[\dXx], [身份证], a) # 统一法条引用格式 a re.sub(r第\s*(\d)\s*条, r第\1条, a) return {instruction: 请依据中国法律回答以下问题, input: q, output: a} with open(raw_qa.jsonl, encodingutf-8) as f, open(sft.jsonl, w, encodingutf-8) as out: for line in f: item json.loads(line) out.write(json.dumps(clean_sample(item[q], item[a]), ensure_asciiFalse) \n)参数说明ensure_asciiFalse保证中文不被转义正则里\s*是为了兼容“第 一百 条”这类空格写法。数据量上指令微调一般 5000 到 20000 条能看出风格变化少于 1000 条容易过拟合。注意不要混入与法律无关的通用问答否则模型会“跑题”。3.2 LoRA 微调显存不够时的标准打法全量微调 7B 模型对多数人不现实LoRA 是常见选择。它冻结原权重只训练低秩矩阵显存占用大幅下降。下面用 peft 做 LoRA 微调的核心配置逻辑是让模型在法条问答上调整输出风格而不破坏基座能力。from peft import LoraConfig, get_peft_model, TaskType from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer model AutoModelForCausalLM.from_pretrained(./legal_llm, torch_dtypeauto, device_mapauto) lora_config LoraConfig( task_typeTaskType.CAUSAL_LM, r8, # 秩8 或 16 常见越大容量越强但越易过拟合 lora_alpha32, # 缩放系数通常取 r 的 2~4 倍 lora_dropout0.1, # 防过拟合 target_modules[q_proj, v_proj] # 注意力层的 Q、V 矩阵 ) model get_peft_model(model, lora_config) model.print_trainable_parameters() # 确认可训练参数占比通常 1%参数说明r8是显存和效果的平衡点法律领域术语多可以试r16target_modules不同模型命名不同LLaMA 系是q_proj/v_projChatGLM 系要看实际层名。训练时per_device_train_batch_size设 1 到 4配合梯度累积。跑完保存 adapter推理时用PeftModel.from_pretrained加载。坑在于LoRA 只改风格不注入新法条法条更新还得靠 RAG。3.3 RAG 检索法条库切分与向量召回RAG 的核心是“先找对法条再让模型组织”。法条库切分不能按固定字数硬切要按“条”切一条一个 chunk保留“第X条”作为元数据。下面用 sentence-transformers 建索引并检索逻辑是问题向量化后找最相似的法条。from sentence_transformers import SentenceTransformer import numpy as np # 假设 laws 是 [{id: 民法典第680条, text: 禁止高利放贷...}] model SentenceTransformer(BAAI/bge-base-zh-v1.5) texts [f{x[id]} {x[text]} for x in laws] emb model.encode(texts, normalize_embeddingsTrue) def search(query, topk3): q model.encode([query], normalize_embeddingsTrue) scores (emb q.T).flatten() idx np.argsort(scores)[::-1][:topk] return [laws[i] for i in idx] print(search(借款利息太高怎么办))参数说明normalize_embeddingsTrue让点积等价余弦相似度topk3是召回条数法律问答建议 3 到 5太少漏法条太多干扰模型。检索到的法条拼进 prompt格式如“参考法条…… 问题…… 请依据上述法条回答”。注意向量模型要选中文法律语料微调过的通用模型对“不当得利”“表见代理”这类术语区分度不够。4. 避坑与排查法律大模型最容易翻车的五件事4.1 现象模型编造法条条号。原因SFT 数据里存在错误引用或模型在无检索时自由生成。解决所有输出强制走 RAGprompt 里要求“只依据参考法条回答无依据时回答不知道”并在后处理里校验条号是否在检索结果中。4.2 现象显存溢出加载到一半崩。原因默认 float32 加载或device_map把全部层塞进一张卡。解决显式指定torch_dtypetorch.float16多卡用device_mapauto单卡不够就上 4bit 量化bitsandbytes或改用 GGUF 走 llama.cpp。4.3 现象微调后模型只会背法条不会回答具体问题。原因训练数据里output全是法条原文缺少“问题到结论”的推理。解决数据里加入“结论 法条依据 简要说明”的三段式比例控制在结论和依据各半。4.4 现象RAG 检索召回的法条不相关。原因切分粒度太粗一条 chunk 混了多条法条或向量模型没适配法律术语。解决按“条”切分chunk 里保留条号换用中文法律领域微调的 embedding 模型或加 BM25 关键词召回做混合检索。4.5 现象同一问题两次回答不一致。原因解码用了采样do_sampleTrue且温度高。解决法律问答设do_sampleFalse或temperature0.1top_p0.9以内保证输出稳定可复现。5. 进阶用 SSE 流式输出把法律问答接进应用模型在命令行跑通只是第一步真正投入要接进应用。法律问答用户等 3 秒没反应就会关页面所以流式输出是刚需。常见做法是后端用 FastAPI 起一个 SSE 接口前端用 EventSource 接收配合 AbortController 让用户能中断。下面是一个最小 SSE 服务端逻辑是逐 token 推送前端实时渲染。from fastapi import FastAPI from fastapi.responses import StreamingResponse from transformers import TextIteratorStreamer import torch, threading app FastAPI() app.get(/legal/stream) def stream(q: str): inputs tokenizer(q, return_tensorspt).to(model.device) streamer TextIteratorStreamer(tokenizer, skip_promptTrue, skip_special_tokensTrue) gen_kwargs dict(**inputs, max_new_tokens256, do_sampleFalse, streamerstreamer) thread threading.Thread(targetmodel.generate, kwargsgen_kwargs) thread.start() def event_gen(): for token in streamer: yield fdata: {token}\n\n yield data: [DONE]\n\n return StreamingResponse(event_gen(), media_typetext/event-stream)参数说明skip_promptTrue避免把用户问题再推一遍media_typetext/event-stream是 SSE 标准每条消息以\n\n结尾。前端用new EventSource(/legal/stream?q...)收到[DONE]关闭连接。如果用户中途取消前端调eventSource.close()后端线程会在下一次 yield 时因连接断开而结束。注意生产环境要把模型加载放在启动时不要每次请求都加载否则显存和延迟都扛不住。验证方法上我习惯用一组固定法律问题做回归测试比如“民间借贷利率上限”“试用期最长多久”“交通事故责任认定不服怎么办”每次改完 prompt 或换模型都跑一遍看条号引用是否正确、结论是否稳定。这个习惯帮我省了很多后悔药。希望帮到你。本文还有配套的精品资源点击获取