ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

DeepSeek本地部署与强化学习训练实战指南

DeepSeek本地部署与强化学习训练实战指南 简介面向大模型初学者与技术研发人员的DeepSeek图解手册系统覆盖本地部署、LLM基础理论与强化学习训练。教程以三步法演示本地安装使用Ollama拉取deepseek-r1模型、命令行运行并进入对话交互零成本、低配置门槛。知识部分从LLM概念和Transformer架构出发厘清预训练、监督微调SFT与强化学习三种训练方式的定位重点拆解DeepSeek-R1的构建过程含R1-Zero中间推理模型和通用强化学习两项核心创新并通过Python学习规划等真实问答示例展示模型思考标签与正式回复的差异。资源为单份PDF文件大小2.64MB图片与步骤对照呈现方便边看边操作。已有2199人学习下载适合希望低成本部署大模型、理解新型推理模型训练机制的AI爱好者与研究者参考。1. DeepSeek 本地部署与强化学习训练为什么值得你亲手做一遍把 DeepSeek 这类大模型跑在自己机器上听起来是件折腾事但它是目前少数几条能让你同时摸清大模型推理和训练全链路的路。本地部署解决的是数据不出内网、接口调用成本可控、以及在离线环境里把模型用起来的刚需而强化学习训练则是把模型从「会聊天」推向「会解题、会按规则办事」的关键一步。从业者用这套组合拳可以用较低成本验证 RL 对齐的效果也能在业务场景里拿到不依赖外部 API 的私有模型服务。这篇笔记会带你从硬件选型一路走到训练调参中间提到的每个环节都是我实际踩过、能复现的做法。我见过太多人在第一步就翻车机器配置还没搞清楚就急着下载模型文件跑起来才发现显存不够或者推理速度慢到没法用。所以这里不绕弯子先讲清楚本地部署需要什么底子再给出一套我能稳定跑通的命令和配置最后聊强化学习训练怎么做、坑在哪、以及哪些场景值得投入。2. 本地部署前的硬件账显存、量化与推理引擎怎么选2.1 显存是第一道门槛不同规模模型该配多大显卡本地部署 DeepSeek 这类大模型最先卡住你的不是 CPU 也不是内存而是显卡显存。模型权重有多大加载进显存就要占多大空间还得额外留出一块做推理时的 KV Cache。以 7B 参数的模型为例FP16 精度光权重就要约 14GB 显存这意味着至少需要一张 24GB 显存的卡如 RTX 3090、4090才能舒服地跑起来。如果你想部署的是 32B 甚至 70B 级别的模型单卡基本没戏要么上多卡并行要么走量化路线把精度降下来换取更低的显存占用。一个常被忽略的点是显存不是唯一指标显存带宽决定了生成速度。同样 24GB 显存GDDR6 和 HBM2 的带宽差好几倍token 生成速度会差出数量级。我见过有人用 RTX 3090 跑 7B 模型速度在 20-30 token/s换到 A100 同样的模型能跑到 60 token/s。如果预算有限优先把显卡数量堆够而不是一味追求单卡性能。常见的部署方案里显存不够时优先考虑量化。INT8 可以把 14GB 的 7B 模型压到 7-8GBINT4 能进一步压到 4-5GB但量化带来的精度损失在生成任务里通常不明显在数学推理和代码生成这类强逻辑任务里会有感知。所以我的建议是如果显卡刚好够跑 FP16就不要动量化不够再用量化兜底。2.2 推理引擎横向对比llama.cpp、vLLM、SGLang 怎么挑推理引擎选得对不对直接影响你能跑多大模型、以及跑多快。当前主流的三个开源推理引擎各有侧重我根据实际使用体验整理了一个对比引擎显存占用吞吐量适用场景上手难度llama.cpp最低量化支持好单请求较低单机、边缘设备、CPU 跑小模型最简单vLLM中高PagedAttention多用户并发、线上 API 服务中等SGLang中高RadixAttention多轮对话、结构化输出、复杂 prompting中等偏高llama.cpp 适合个人电脑或小显存环境胜在它能把模型量化到很低的比特数CPU 也能跑但并发能力弱适合一次一两个请求。vLLM 是当前做本地 API 服务的首选它最大的优势是显存管理效率同样一张卡能同时服务更多请求而且兼容 OpenAI 接口格式接入现有代码几乎不需要改。SGLang 在长上下文和多轮对话场景里更快但配置更复杂新手容易被它的各种参数绕晕。如果让我推荐一个起步组合llama.cpp 用来验证模型能不能跑通、效果好不好确认满意之后再切到 vLLM 做正式服务。很多人一上来就上 vLLM结果因为 CUDA 版本、torch 版本的问题折腾两天还没跑起来其实用 llama.cpp 半小时就能验证完。2.3 量化等级怎么选从 FP16 到 INT4 的取舍量化的本质是用更少的比特表示权重换显存和速度。以 DeepSeek 的 7B 模型为例FP16 需要约 14GBINT8 约 7GBINT4 约 4GB。但每次降精度激活值带来的误差会累积具体表现是回答变短、逻辑跳跃、中文表达能力下降。实操里我一般建议这样选显存能装下 FP16 就绝不量化装不下先用 INT8效果还能接受INT4 是最后手段而且要配合温度参数往上调一点比如 0.8 到 1.0用随机性弥补精度损失。量化格式也很重要llama.cpp 里常见的 q4_K_M、q5_K_M、q8_0 分别对应不同的权重分布处理方式其中 q4_K_M 在 4bit 里质量最好q8_0 接近原始精度内存又比 FP16 省一半。一个容易忽略却影响巨大的点量化对生成任务比如写文章、闲聊影响很小但对需要精确计算的任务比如数学题、代码逻辑影响明显。如果你主要是让模型做题或写代码尽量保持高精度如果只是做文本摘要和对话INT4 完全够用。我踩过这样一个坑用 INT4 量化后的模型跑代码生成函数名经常拼错换成 INT8 后问题消失——这个代价用显存换是值得的。3. 部署实操从模型下载到 API 服务跑通的最小命令3.1 用 llama.cpp 跑通本地推理从 GGUF 到第一个输出llama.cpp 是本地跑大模型门槛最低的路径整个过程就三步下载模型、编译工程、启动服务。先说模型下载DeepSeek 的模型权重要转成 GGUF 格式才能在 llama.cpp 里运行。可以从 Hugging Face 上拉取官方权重然后用 llama.cpp 自带的转化脚本转换或者直接下载别人已经转好的 GGUF 文件省去转化的时间。我一般用后者因为没有必要在这上面重复造轮子。接下来是编译和运行。以下命令在 Ubuntu 22.04 CUDA 环境下验证过# 克隆 llama.cpp 并编译启用 CUDA 加速 git clone https://github.com/ggerganov/llama.cpp cd llama.cpp mkdir build cd build cmake .. -DLLAMA_CUBLASON make -j$(nproc) # 启动一个兼容 OpenAI 格式的 API 服务 ./bin/llama-server \ -m /models/deepseek-7b.Q8_0.gguf \ --host 0.0.0.0 \ --port 8080 \ -n 2048 \ --ctx-size 8192 \ --threads 8这条命令里的关键参数说明一下-m指定模型路径--host 0.0.0.0允许局域网访问-n是最大生成 token 数--ctx-size是上下文窗口大小--threads是 CPU 线程数。如果你的机器有显卡确认 LLAMA_CUBLAS 正确启用llama-server 启动日志里会出现 CUDA 相关的初始化信息看不到的话说明推理还在用 CPU 跑速度会差很多。启动成功后用 curl 验证接口是否可用curl http://localhost:8080/v1/chat/completions \ -H Content-Type: application/json \ -d {model: deepseek-7b, messages: [{role: user, content: 用一句话解释什么是强化学习}], max_tokens: 128}返回的 JSON 里会包含模型生成的答案到这里本地推理链路就算通了。注意一个细节llama-server 的/v1/chat/completions端点和 OpenAI 的格式一致这意味着你现在就可以把代码里base_url指向http://localhost:8080/v1无缝切换。3.2 切换到 vLLM并发场景下吞吐量翻倍的部署方式llama.cpp 适合个人验证但如果你要把 DeepSeek 提供给团队内部十个人以上使用vLLM 是更合适的选择。vLLM 用 PagedAttention 技术把显存利用率提高了一个档次同样的 24GB 卡vLLM 能稳定服务十几个并发请求而 llama.cpp 可能两三个就卡住了。vLLM 部署流程相对复杂一些需要先准备 Python 环境和 CUDA 环境建议直接用官方镜像跳过环境地狱# 用 vLLM 官方镜像启动容器映射模型目录和端口 docker run --runtime nvidia --gpus all \ -v /models:/models \ -p 8000:8000 \ vllm/vllm-openai:latest \ --model /models/deepseek-7b \ --served-model-name deepseek-local \ --tensor-parallel-size 1 \ --gpu-memory-utilization 0.9 \ --max-model-len 8192 \ --enforce-eager参数里--tensor-parallel-size指定使用几张卡做并行单卡就是 1--gpu-memory-utilization 0.9表示允许 vLLM 用掉 90% 的显存做模型缓存和 KV Cache这个值可以根据实际情况调--enforce-eager能省掉 CUDA graph 的预热时间首次请求响应更快代价是高并发时吞吐略降。vLLM 启动后同样监听 8000 端口接口路径也是/v1/chat/completions。这里注意一个容易踩的坑vLLM 加载的模型格式必须是 Hugging Face 格式safetensors不是 GGUF。如果你之前只在 llama.cpp 里跑过 GGUF需要回到 Hugging Face 上下载原始权重。我用这个命令跑 7B 模型单卡 A10 上并发 8 个请求时总吞吐能做到约 1500 token/s相比 llama.cpp 的单请求 30 token/s提升非常明显。3.3 接入企业内部系统OpenAI 兼容接口与私有知识库部署完成只是第一步真正的工作在于把模型接进业务系统。因为 DeepSeek 的本地服务接口兼容 OpenAI 格式接入现有项目只需要改base_url和api_key两个配置。以下是一段 Python 调用示例from openai import OpenAI # 本地服务地址api_key 随意填写即可 client OpenAI( base_urlhttp://192.168.1.100:8000/v1, api_keylocal-deepseek ) # 与私有知识库检索结果拼接后一起发给模型 def chat_with_context(user_question: str, retrieved_docs: list[str]): system_prompt 你是企业内部的智能助手回答时优先参考提供的资料。 context \n\n.join(retrieved_docs) response client.chat.completions.create( modeldeepseek-local, messages[ {role: system, content: system_prompt}, {role: user, content: f资料\n{context}\n\n问题{user_question}} ], temperature0.3, max_tokens512, streamTrue ) for chunk in response: if chunk.choices[0].delta.content: print(chunk.choices[0].delta.content, end, flushTrue) chat_with_context(门禁系统报错怎么办, [门禁系统常见故障处理手册...])代码里的关键点在于把检索到的资料放进 user 消息里让模型在回答时优先引用。temperature0.3调低是为了让答案稳定、接近事实如果你做的是文案生成等创意类任务建议调到 0.7-0.9 之间。流式输出streamTrue对用户体感很关键不然长回答会显得卡顿。这种接入方式的好处是业务代码完全不用动只需要把原来指向云端 API 的地址换成本地地址即可。我在实际项目里就这么干过把内网已有的文档检索服务接进本地 DeepSeek再对接到企业微信机器人前后花了一个下午效果比直接让裸模型回答好了不少因为资料是实时的、私域的模型只需要做理解与转述。4. 强化学习训练从基础概念到 DeepSeek 的 GRPO 微调实战4.1 强化学习在大模型里到底在干什么预训练教会模型「说话」指令微调教会模型「听从指令」而强化学习RL是教会模型「在给定规则下把事情做对」。对于 DeepSeek 这类生成式大模型RL 的目标不是让它输出更流畅的文本而是让它学会通过试错来最大化一个可量化的奖励——比如数学题答案的正确性、代码能不能通过测试用例、回答是否符合安全规范。传统强化学习里的 PPO 算法在大模型场景下并不好用主要原因是它需要一个额外的价值网络Critic来估计每个状态的期望收益而价值网络本身和策略网络一样大训练成本翻倍且稳定性难调。DeepSeek 在开源技术报告里公开的 GRPOGroup Relative Policy Optimization直接把 Critic 网络去掉了改用同一组 prompt 生成的多个响应之间的相对优劣来计算优势函数这样做省了一半显存也减少了训练不稳定的问题。当前主流的开源 RL 训练框架比如 TRL 和 verl都已经内置了 GRPO 的实现。在动手训练之前要确认一个认知强化学习不是替代微调而是在微调之后做「对齐」。一般的技术路线是预训练权重 → SFT 指令微调 → RL 强化学习。RL 阶段通常只需要 1000-5000 条带奖励信号的数据训练 1-3 个 epoch模型就会在目标任务上表现出明显的提升。数据量不需要很大但质量要求很高——每条数据必须能明确判断「对」还是「错」否则奖励信号是噪声训练只会让模型学歪。4.2 准备训练环境数据集格式与奖励函数设计RL 训练的数据和 SFT 不一样SFT 需要的是「问题-标准答案」对而 RL 需要的是「问题 可自动判分的规则」。最典型也最好上手的场景是数学题问题给模型模型输出推理过程和最终答案奖励函数只需要判断答案是否和标准答案一致。下面是一个适用于 TRL 框架的 RL 数据格式示例[ { prompt: 一个长方形的长是12厘米宽是8厘米求它的面积。, answer: 96平方厘米, reward_type: exact_match }, { prompt: 三个连续奇数的和是57求这三个数分别是多少, answer: 17、19、21, reward_type: exact_match } ]奖励函数在 RL 训练中是灵魂。exact_match是最简单的方式但实际生成答案里经常会有多余的解释文字导致明明算对了却被判错。更稳的做法是设计一个解析函数从模型输出中提取出答案部分再比对import re import json def extract_answer(text: str) - str: 从模型输出中提取最后一个可能的答案行 # 先尝试提取 \boxed{} 里的内容 boxed re.findall(r\\boxed\{([^}])\}, text) if boxed: return boxed[-1].strip() # 再尝试找最后的数字或中文数字序列 lines [l.strip() for l in text.split(\n) if l.strip()] for line in reversed(lines): nums re.findall(r[\d\.], line) if nums: return 、.join(nums[:3]) return def math_reward(prompt: str, response: str, answer: str) - float: 奖励函数答案正确给 1 分并额外奖励推理过程的完整性 extracted extract_answer(response) if not extracted: return 0.0 # 归一化比较去空格和中文顿号 normalize lambda s: s.replace( , ).replace(, ,).replace(、, ,) if normalize(extracted) normalize(answer): # 给一点过程奖励有推理步骤加 0.1纯答案不加分 has_reasoning len(response) len(extracted) 50 return 1.0 (0.1 if has_reasoning else 0.0) return 0.0这个奖励函数的设计思路是正确是基础分有推理过程再给额外分——引导模型把思考过程写出来而不是直接蒙一个答案。实际训练里你会发现不这样设计的话模型会学会直接输出最终答案来拿分推理能力反而退化。4.3 用 TRL 跑 GRPO 训练参数配置与显存控制TRLTransformer Reinforcement Learning是 Hugging Face 出的 RL 训练库它对 GRPO 的支持比较成熟代码量也很少。以下是一个可运行的 GRPO 训练脚本的完整骨架我以 7B 模型、单卡 24GB 显存为例写下配置from datasets import load_dataset from trl import GRPOConfig, GRPOTrainer from transformers import AutoModelForCausalLM, AutoTokenizer from trl import maybe_apply_chat_template # 加载模型和分词器使用 4bit 量化省显存 model AutoModelForCausalLM.from_pretrained( deepseek-ai/DeepSeek-Coder-7B-Instruct, load_in_4bitTrue, device_mapauto ) tokenizer AutoTokenizer.from_pretrained(deepseek-ai/DeepSeek-Coder-7B-Instruct) # 加载上面示例的自定义数据集 dataset load_dataset(json, data_filesrl_math_data.json, splittrain) dataset dataset.map(lambda x: {prompt: maybe_apply_chat_template(x[prompt])}) training_args GRPOConfig( output_dir./grpo_math_checkpoint, # 模型输出目录 run_namedeepseek_grpo_math, # 这次训练的名字 learning_rate5e-6, # GRPO 对学习率很敏感不要大于 1e-5 adam_beta10.9, adam_beta20.99, weight_decay0.01, warmup_ratio0.1, per_device_train_batch_size4, # 每个 GPU 上同时处理几条数据 num_generations4, # GRPO 的组大小每个 prompt 采样几个响应 max_prompt_length1024, max_completion_length512, num_train_epochs1, gradient_accumulation_steps2, logging_steps10, save_steps100, max_grad_norm0.1, report_towandb ) trainer GRPOTrainer( modelmodel, argstraining_args, train_datasetdataset, reward_funcs[math_reward], # 传入上面定义的奖励函数 ) trainer.train()参数里最关键的是num_generations这个值决定了每个问题要采样多少个回答来组成一个「组」。GRPO 的核心思想就是组内相对比较组越大优势估计越稳定但显存开销也线性增长。24GB 显存跑 7B 模型num_generations4已经接近上限想要更大就得配合梯度累积或直接上多卡。另一点值得说明的是学习率。RL 阶段的学习率必须比 SFT 阶段小一个数量级通常取1e-6到1e-5之间。过大的学习率会让模型快速偏离已经学好的语言能力出现答非所问或重复刷分的情况这也是我实际训练里最容易翻车的地方后面避坑章节会展开说。4.4 训练效果怎么看奖励曲线与生成质量的双重验证训练过程中最直观的信号是 reward 曲线。TRL 默认会上报到 wandb如果你不想用外部服务也可以只关注本地日志里的reward/mean。正常的训练曲线应该是先上升、然后进入平台期如果曲线先升后降说明过拟合了应该提前停止如果从头到尾不涨说明奖励函数有问题数据没问题的话大概率是奖励信号太稀疏拉不动模型。只看 reward 其实不够因为它只能说明模型学会了「刷分」不能证明推理能力真实提升。我一般会在每 100 步保存 checkpoint 后拿一个固定的评测集比如 50 道没训练过的题去跑一遍看正确率变化。这个方法很朴素但有效reward 是训练信号评测集正确率才是真实效果。一段可靠的记录是我的一个数学训练任务在 GRPO 跑到 300 步时训练里 reward 均值到 0.8但评测集正确率只有 0.3继续跑 500 步后 reward 涨到 1.1评测正确率也到了 0.62——这说明模型是真的学会了不是过拟合了训练题。如果评测正确率一直不涨优先检查奖励函数有没有漏洞。比如模型可能学会了输出包含答案的候选列表来确保命中这种「钻空子」行为在 reward 上很好看但推理能力完全没提升。解决方法是给奖励加格式约束比如要求输出必须包含明确的「思考过程」和「最终答案」两个部分思考过程不完整就扣分。5. 部署与训练路上的避坑指南五个高发问题的排错实录5.1 显存溢出OOM但模型明明装得下现象是服务跑起来之后处理几个请求就报 CUDA out of memory模型权重明明只占了 60% 的显存。原因是 KV Cache 在长上下文场景下指数级增长加上没有为并发请求预留空间多个用户同时对话直接把显存打爆。解决方法是给推理框架限制 KV Cache 总量vLLM 里通过--max-model-len和--gpu-memory-utilization一起控制llama.cpp 里把--ctx-size从 8192 降到 4096并且每次请求完主动清掉不需要的上下文。我自己遇到这类问题时通常先看 vLLM 日志里的GPU KV cache size指标数值接近显存总量就可以确认是这里的问题。5.2 GGUF 量化后模型乱说话逻辑能力明显下降现象是同一套 promptFP16 模型回答正常INT4 量化后输出变得冗长、重复、逻辑断裂。原因是量化精度不足激活值误差在深层网络里累积尤其在数学计算和代码生成这类任务上被放大。解决方法是先用 INT8 或 q6_K 级别的量化测试如果显存仍然不够那就把注意力集中在生成参数上调高temperature到 0.8减少top_p到 0.85同时把repeat_penalty调到 1.1 以上。这套组合虽然不能完全恢复能力但能让输出质量从「不可用」提升到「可接受」。切不可为了显存硬上 INT4 然后在生产环境里被用户投诉质量。5.3 显存够但推理速度慢得离谱现象是模型加载成功但生成速度只有每秒钟几个 token连打字都不如。原因大概率是推理没有走 GPUCUDA 没有正确启用——llama.cpp 编译时没有加-DLLAMA_CUBLASON或者 vLLM 容器没有正确挂载 GPU。排查时先运行nvidia-smi确认 GPU 可用再看服务启动日志里有没有devicecuda的字样。llama.cpp 有一个特别容易误导人的地方编译时没启用 CUDA 也不会报错只是静默切回 CPU 推理。另一个隐蔽原因是你用的模型文件是纯 CPU 版而不是 CUDA 版下载 GGUF 时注意文件名里有没有cu标识llama.cpp 官方仓库里两种文件分开放。5.4 GRPO 训练时 reward 波动剧烈、模型越训练越笨现象是 reward 曲线不是平滑上升而是宽幅震荡训练结束后生成质量甚至不如初始化权重。原因是学习率太大或 batch size 太小导致策略更新步长超过了安全范围模型在参数空间里来回跳跃。解决方法是把learning_rate降到 1e-6 到 3e-6把num_generations从 4 提到 8 以稳定优势估计同时配合max_grad_norm0.1做梯度裁剪。如果预算有限的显卡跑不下num_generations8可以把 prompt 长度从 1024 降到 512给响应生成留出空间。还有一个我在实际训练中踩过的坑adam_beta2默认 0.999 对 RL 来说偏大改成 0.99 后训练稳定度明显提升。5.5 模型学会了刷奖励但没有学会真正做事现象是训练时 reward 高达 0.9 以上但评测集上正确率反而比训练前还低。原因是模型找到了奖励函数的漏洞比如把多个答案都写出来、或者输出「答案是 X 或 Y」来增加命中率。这种投机行为在 RL 里很常见解决思路不是加强惩罚而是让奖励函数不可被钻空子。我的做法是同时检查格式要求模型输出必须出现在answer标签内标签外有额外答案直接判零分如果模型总是输出「让我想想」「首先」之类的话来凑字数就在奖励里加一个长度约束——输出超过 512 token 就扣分。每一次发现模型钻空子其实就是一次对奖励函数设计缺陷的暴露迭代几次总能稳定下来。6. 应用场景与落地验证把训练好的模型放进真实业务6.1 值得投入的场景私有知识库问答、代码辅助、数学推理本地部署加强化学习这套组合真正值得做的场景不是那些云端 API 能轻易搞定的通用对话而是对数据安全和输出正确性有硬性要求的业务。私有知识库问答是最典型的企业内部文档不能出内网直接调用公有云大模型是违规操作本地部署是唯一合规路线。在这个基础上你还能用 GRPO 把模型往「引用文档、注明出处、不胡编」的方向强化这是纯 SFT 很难做到的。代码辅助是另一个强场景。DeepSeek 本身在代码任务上有训练优势再用强化学习针对你所在团队的具体代码规范做对齐效果是肉眼可见的。举个例子如果一个团队用 Python 为主你可以构造一批「给定需求 → 输出符合 PEP8 且调用内部工具库的代码」的训练数据GRPO 跑完后生成的代码风格会更加统一。数学推理场景适合做效果验证但未必适合直接做生产应用。原因很简单通用的 DeepSeek 模型数学能力已经不差RL 提升的是特定题型的稳定性。如果业务里确实有大量某种固定类型的题目比如题库判题、竞赛培训那 RL 投入产出比会很高否则不如直接用现成模型。6.2 验证效果好坏的三个手段评测集、对抗样本、人工盲测训练完不能只看 reward 就上线我一般会做三层验证。第一层是固定评测集跑分用一个和训练数据不重叠、覆盖不同难度的题库跑一遍对比训练前后的正确率变化。第二层是对抗样本测试专门构造一些模型容易犯错的输入——比如带陷阱的数学题、语义模糊的指令、包含否定词的句子——看 RL 之后的模型会不会在这些场景下更稳定。第三层是人工盲测这是最容易忽略却最接近真实体感的一步。找几个不参与开发的同学分别用训练前后的模型回答同一组问题让他们打分判断哪个答案更好。因为 reward 和正确答案都是客观指标而实际用户感知的是流畅度、可信度、风格贴合度这些主观维度偏差往往在盲测里才会暴露。我在一次数学训练中就遇到过 RL 后客观正确率涨了 10%但盲测里用户普遍觉得「答案变机械了」原因是我们把温度调太低、回答太简洁丢了表达的自然感。6.3 一个生产可用的评估脚本模板把一个评估流程沉淀成脚本是这个方案能否持续发挥价值的关键。下面是我常用的一个评估脚本骨架跑完会输出正确率、平均回复长度和失败案例列表import json from openai import OpenAI client OpenAI(base_urlhttp://localhost:8000/v1, api_keylocal) def evaluate(eval_set_path: str, model_name: str) - dict: with open(eval_set_path, r) as f: cases json.load(f) correct, total, fail_cases 0, 0, [] reply_lengths [] for case in cases: resp client.chat.completions.create( modelmodel_name, messages[{role: user, content: case[prompt]}], temperature0.1, # 评估时用低温度保证可重复性 max_tokens512 ) answer extract_answer(resp.choices[0].message.content) is_correct normalize(answer) normalize(case[answer]) total 1 correct is_correct reply_lengths.append(len(resp.choices[0].message.content)) if not is_correct: fail_cases.append({prompt: case[prompt], expected: case[answer], got: answer}) return { accuracy: correct / total, avg_reply_length: sum(reply_lengths) / len(reply_lengths), fail_cases: fail_cases[:10] # 只看前 10 个错误案例 } # 训练前先跑一遍基线 baseline evaluate(eval_set_v1.json, deepseek-local) print(baseline accuracy:, baseline[accuracy])这个脚本的价值在于把验证从「看一眼感觉还行」变成「有数字、有记录、可对比」。我工作里的习惯是训练前记录 baseline训练后每保存一个 checkpoint 就跑一次同一份评测集所有数字留在同一个表格里效果是好是坏一目了然。6.4 一个关于部署运维的切身教训最后分享一个我自己的教训。有一段时间我把本地服务部署在一台 4 卡机器上特地为它写了一个自动重启脚本结果某天夜里模型因为显存碎片化导致服务假死自动重启脚本又把同一个有问题的启动命令重新执行了一遍白白宕机了几个小时。现在我学乖了所有重启脚本里都加一个启动前自检——先跑一次最小的推理请求成功再宣告服务就绪。另外模型和服务的版本号记录也是一定要做的因为训练出一个效果更好的模型后你可能需要回滚到旧版本做对比没有版本记录的时候只能瞎猜。这些经验不复杂属于那种踩过一次就再也不想踩的坑希望你看到这里能避开。这个方向目前依然是实践驱动的蓝海从部署到训练再到场景打磨每一步都能做出价值希望帮到你。本文还有配套的精品资源点击获取
返回列表