那篇《大语言模型快速启动指南(早期发布)》发出之后,不少朋友照着文章里的步骤把模型跑了起来,然后跑来问我几乎一样的问题:模型是能聊了,但怎么感觉不好用?要么回答到一半停下来,要么对话一长就开始胡说,要么换一个请求就报错。我意识到,大多数人缺的不是“启动”这一下,而是从“启动”到“能用”之间的那段经验。这篇“(二)”就是想把这些经验补上。
上一篇解决的是“怎么把模型拉起来”,这篇解决的是“拉起来之后怎么办”。我会尽量少讲重复的基础概念,重点讲启动之后你一定会碰到的选择题:模型到底选哪个规模、量化文件该下哪种格式、引擎参数为什么这么调、上下文太长为什么显存暴涨、怎么让模型在应用里真正稳定输出。适合两类人看:一类是已经跑通官方示例、正准备做真实功能的朋友,另一类是刚下载完模型、正在思考第一步该干什么的初学者。如果你还在准备硬件阶段,建议先读一读第一篇,把基础部署链路搭通,再回来看这篇,效果会顺很多。
1. 启动之后的真问题:能对话,但还没到能用
1.1 从“演示成功”到“稳定可用”之间到底差了哪些事
演示阶段的成功,通常是这样的:在终端里敲了几条命令,一个对话框出现了,输入“你好”,模型回了一段话,大家觉得项目完成。但一旦进入真实使用场景,问题立刻冒出来。
第一个问题是响应不稳定。同样一个问题,早上问和下午问,答案可能差出一大截,有时候甚至同一个问题连问两次结果都不一样。这不是模型坏了,而是采样参数在起作用,后面我会展开讲。第二个问题是长对话失忆。前五分钟还在聊项目背景,后五分钟问它相关细节,它好像完全不记得,这也正常,本地启动时很多人没有把历史消息一起传给模型。第三个问题是资源边界不清晰。我自己见过有朋友在一张 8G 显存的显卡上强行加载一个十几B的模型,机器直接卡死,然后怀疑是下载的模型有问题。其实每一步的资源账都可以提前算清楚。
这三个问题,恰恰不是我这一类启动教程的“bug”,而是整个使用链条里必经的四个环节:选型、启动、调优、封装。任何一环缺了,模型就始终停留在“玩具”阶段。所以这篇指南的结构,也按这四个环节展开。
1.2 这一篇准备帮你解决什么,以及读者的定位
快速启动指南的第二篇,我没有打算做成一本面面俱到的手册,那会把人劝退。我更想做的是把那些“文档里不会写、但实战里天天遇到”的内容讲清楚。
具体来说,看完这篇你可以做到:先算一笔硬件账,知道自己能跑多大的模型;再选一个合适的量化版本,知道为什么同一个模型会有不同文件;然后启动一个带 API 的服务,用 Python 发请求拿到结构化结果;接着把采样参数、上下文长度、并发数这几个关键旋钮调到一个合理位置;最后写一个带记忆的聊天函数和一个简单的本地问答逻辑。
读者的定位我默认得很具体:你不是在研究大模型原理,你是想把手上的这台电脑变成能出活儿的工具。所以公式我会给,但一定给出可以直接套用的简化版;代码我也给,但一定是在真实环境中调通过的最小实现。这一篇的目标只有一个:让你今晚睡觉前,能对着自己跑起来的模型说一句“这玩意儿现在能干活了”。
2. 先把模型的“思考方式”搞清楚,再谈调优
2.1 Token 与自回归生成——模型的每一步是怎么走出来的
很多调参困扰的根源,是不理解模型到底是怎么“想”东西的。简单说,当前主流的生成式大模型,本质是一个自回归模型:它每次只预测下一个片段,把预测出来的片段拼到最末尾,再基于完整的新序列预测再下一个片段,反复循环直到满足停止条件。
这个“片段”在专业领域里叫 Token,你可以把它理解为模型眼中的最小文字单位。一个 Token 不严格等于一个汉字或一个英文单词,可能是某个词根、某个常用词组,甚至一个字。模型看到的不是你输入的整段话,而是一串 Token 编号。所以当有人问“为什么模型有时中文说得不好,有时又很好”,答案往往和 Token 化方式、训练数据分布有关系。
理解了这一点,很多现象就能解释了。为什么模型回答一般比较长?因为模型天然没有“我要简洁”的动机,它的训练目标就是让序列看起来自然,而自然语料本身就是啰嗦的。为什么模型可能“越说越远”?因为每一步都是一次新的预测,早期稍微偏一点,后期就会被放大。
还有一个关键概念叫“上下文窗口”,它表示模型一次性最多能看到多少 Token。超过窗口的内容不会被“记住”,而是直接被截断。所以长对话里模型“失忆”,大概率不是你代码写错了,而是历史消息太多,被窗口截掉了。
2.2 量化与精度:为什么“能跑”和“好用”是两个概念
模型权重在训练完成时通常是高精度的浮点数,最常用的是 FP16,也就是每个参数占 2 字节。一个 7B(70亿参数)的模型,光权重文件就要 14GB 左右。这对普通消费级显卡来说压力很大,于是量化方案出现了。
量化的本质,是把每个权重从高精度“压缩”到低精度。常见路线有 8bit(每个参数 1 字节)和 4bit(每个参数约 0.5 字节)。同样一个 7B 模型,FP16 要 14GB,8bit 约 7GB,4bit 约 4GB 左右。这就是为什么同样一个模型,不同文件大小差好几倍。
这里要打破一个常见误解:模型量化之后,不是“变笨了”,而是“精度有损失但可用性大增”。对于绝大多数文本对话、内容生成、代码辅助场景,4bit 量化后的模型能力损失在可接受范围内。但如果你的任务是对输出质量极其敏感,比如需要严格推理、需要处理结构化数据,那最好留足显存跑更高精度版本。
我自己做过一个粗糙对照,同一个 7B 模型,FP16 和 4bit 在普通问答上几乎看不出差别,但在一些需要严谨依条件判断的任务上,FP16 的错误率确实更低。所以我的建议是:先量化跑通,再根据实际效果决定要不要换高精度。不要还没跑起来就追求“原版”。
2.3 这些底层概念如何决定你的启动参数
理解了 Token 和量化,你会发现自己配置启动参数时不再是瞎猜。
比如启动时最常见的参数是“最大上下文长度”,它直接决定模型能“记住”多少内容。你设 2048 和设 8192,不只是能力不同,显存占用和响应速度都会变化,因为模型需要计算并缓存每个 Token 的相关状态,这个缓存叫 KV Cache。窗口越大,KV Cache 越大。这一点在第五章会专门算账。
再比如“最大生成 Token 数”,它限制模型一次回答最多吐多少 Token。如果你知道模型是逐 Token 生成的,就不难理解为什么输出长文时速度慢——每一次生成都是一次完整的前向计算。这也意味着,如果你的应用只需要短回答,把最大生成数设小一点,能避免它“刹不住车”地长篇大论。
采样参数也是同理。模型每一步会计算一个候选 Token 的概率分布,temperature(温度)控制这个分布的尖锐程度。温度越高,模型越“发散”,越低越“保守”。top_p 则是从累计概率前若干候选里采样。这些参数不是装饰品,它们直接决定模型是像一个谨慎的助理还是像一个话痨。
3. 动手之前:模型、量化格式与推理引擎怎么匹配
3.1 选模型的三个主要维度
很多人第一步就卡在“我该下哪个模型”。这里我建议从三个维度去卡:规模、语言能力、硬件匹配。
规模上,常见的选择大致是 3B/7B/13B/34B 这几档。3B 模型更小、速度快,适合配置一般的机器,或者对响应速度要求高的场景;7B 是黄金平衡点,绝大多数个人项目和轻量级服务首选;13B 需要更充足的内存或显存,但理解能力和生成质量明显好一档;34B 及以上基本需要大显存或者多卡,不太适合入门。
语言能力上,尽量选社区口碑好的中文优化版本,或者中文语料占比高的基座模型。怎么判断?最简单的方式是直接跑几个你熟悉领域的问题,看它对中文表达的理解程度和知识密度。别只看榜单分数,你的实际场景才是最靠谱的评测集。
硬件匹配上,我建议先看你自己有什么,再决定模型规模。一张 6G 到 8G 显存的显卡,老老实实跑 4bit 量化的 7B 模型;16G 显存可以尝试 13B 的量化版本;如果只有内存没有独立显卡,那就走 CPU 推理路线,选小模型加轻量级优化方案。
一个比较实用的参考表:
| 硬件配置 | 推荐模型规模 | 推荐量化级别 | 预期用途 |
|---|---|---|---|
| 16G 内存无独显 | 3B-7B | 4bit/8bit | 个人实验、轻度问答 |
| 8G 显存 | 7B | 4bit | 日常对话、文本总结 |
| 16G 显存 | 13B | 4bit/8bit | 更高质量生成、代码辅助 |
| 24G+ 显存 | 13B-34B | 8bit/FP16 | 严肃项目、推理密集型任务 |
3.2 量化格式与推理引擎的匹配关系
同样是量化,格式之间不互通,这是启动阶段最容易踩的坑。当前主流格式大致可以分成两条路线。
一条偏本地轻量,文件格式后缀常见为 GGUF 一类,这类文件专门为 CPU 推理和消费级显卡优化,可以在低资源环境下跑得挺顺,启动命令也简单,适合个人电脑。另一条偏服务化部署,常见的是 GPTQ、AWQ 这类显存高效的量化格式,它们需要较大的显存环境,但推理速度在批量请求下更有优势,适合做成 API 服务。
怎么选?我的经验是:单机自用选本地轻量路线,文件管理简单,换模型就像换一个文件;准备做成服务、后面可能要接多个客户端,再考虑服务化路线。要注意的是,不同引擎支持的量化格式不尽相同,下模型之前,先确认你的引擎支持什么格式。我就见过有人辛辛苦苦下了几 GB 的模型,启动时报错说格式无法识别,最后发现是格式和引擎不匹配。
选引擎时也别跟风。先看你的操作系统、显卡驱动和显存,再看引擎对量化格式的支持面、是否支持 API、是否有活跃的社区维护。有图形界面就选图形界面版本,喜欢命令行就选命令行版本,原则只有一个:“能让你的实际任务跑起来”的引擎才是合适的。
3.3 我踩过的选型坑与补救方案
第一坑:贪大。我最初想直接跑 13B 模型,觉得 7B 不够看,结果手头 8G 显存跑一遍就爆。那时候不懂 KV Cache 也要显存,以为显存够装权重就行。后来老老实实换 4bit 量化 7B,一切才顺畅。所以记住:显存需求 = 权重大小 + KV Cache + 运行时开销,这中间留的余量至少要有 1-2GB。
第二坑:文件格式和引擎不匹配。下载的时候只看了文件名带“4bit”,没细看格式,结果引擎根本不识别。后来规范了流程:先选引擎,再按引擎支持的格式去社区找对应量化文件。如果社区同时提供几种格式,优先选文件更新日期较近的版本,因为量化工具在持续改进,新文件往往更稳定。
第三坑:乱改参数导致模型胡言乱语。我试过为了追求“有趣”,把温度开到 1.8,结果模型开始输出一堆无意义内容。温度高并不等于“聪明”,它只是让概率分布更平均,更容易选出不太可能的 Token。从那以后,默认值 0.6-0.8 成为了我的安全区。
4. 最小可用的启动与首个API调用实操
4.1 启动前检查清单
正式启动之前,我习惯花两分钟过一遍检查清单,能省掉后面大量的排错时间。
- 显卡驱动和加速环境是否正常,有没有装错版本。
- 磁盘剩余空间是否充足,模型文件常常几十 GB,解压后比你想象中更占地方。
- 下载的模型文件是否完整,最好校验一下文件体积和社区的发布信息一致。
- 端口是否被占用,如果服务要用 8080 端口,先确认没有别的程序占用。
- 路径里不要出现中文和空格,很多本地工具在处理非 ASCII 路径时会莫名其妙地报错。
这份清单看起来琐碎,但我复盘了过往的启动故障,超过一半的问题出在这五条里,其中路径问题尤其阴险——日志里不会直接提示“路径包含中文”,而是报一个让你摸不着头脑的加载错误。
4.2 一个典型的模型服务启动命令
假设你已经准备好一个量化后的模型文件,并装好了一个支持 API 的推理引擎,那么启动一个本地模型服务的命令大致长这样:
./server --model ./models/chat-model-q4.gguf \ --context-length 4096 \ --port 8080 \ --max-tokens 1024逐项解释一下。--model指向模型文件的路径;--context-length设置模型的上下文窗口长度,先设 4096 是万金油,既能支撑常规对话,又不至于让 KV Cache 撑爆显存;--port指定服务监听端口;--max-tokens限制单次生成的最大 Token 数。
启动之后看到日志打印出类似“server started on 0.0.0.0:8080”这样的信息,说明服务就绪。有些引擎还会打印当前显存占用和加载时间,这些数据建议截图留档,后面调优可以做基准参考。
有的朋友希望有图形界面,直接从界面上操作文件选择和参数配置,那也可以,但在参数逻辑上,上面命令行的几个概念同样适用。图形界面只是把参数封装成了按钮,不理解底层含义,照样容易配错。
4.3 用 Python 发起第一个请求
服务跑起来之后,用 Python 发一个请求是最快的验证方式。这里我用标准库实现,不依赖第三方库,复制就能跑:
import urllib.request import json server_url = "http://127.0.0.1:8080/v1/chat/completions" payload = { "model": "local-model", "messages": [ {"role": "system", "content": "你是一个简洁、准确的助手。"}, {"role": "user", "content": "请用一句话解释大语言模型的量化原理。"} ], "temperature": 0.7, "max_tokens": 256, "stream": False } req = urllib.request.Request( server_url, data=json.dumps(payload).encode("utf-8"), headers={"Content-Type": "application/json"}, method="POST" ) with urllib.request.urlopen(req, timeout=120) as resp: result = json.loads(resp.read().decode("utf-8")) print(result["choices"][0]["message"]["content"])如果返回了文字,恭喜,你的模型已经从一个“本地程序”变成了一个“可用服务”。这一步的意义在于:你已经不依赖自带对话框,而是通过标准接口在调用它。这意味着接下来你可以把模型接进任何自己的应用里。
第一次请求可能会比较慢,因为引擎在预热、缓存需要建立,这很正常。如果超过 120 秒还没返回,建议先检查服务日志,看是模型还在加载中,还是请求格式出了问题。
4.4 用三个小实验理解采样参数
模型能响应之后,先别急写业务逻辑,我建议花十分钟做三个小实验,直观感受采样参数的影响。
第一个实验,固定其他参数不变,把temperature分别设为 0、0.7、1.5,问同一个问题。你会看到:温度为 0 时输出稳定,几乎每次答案都一样;0.7 时自然流畅但略有变化;1.5 时开始发散,有时会输出奇怪的内容。
第二个实验,保持temperature为 0.7,把top_p设为 0.3、0.9、1.0。top_p越小,采样的候选集合越少,输出越保守;越大,越有多样性。两者通常配合调整,而不是各自独立工作。
第三个实验,把max_tokens从 256 显著调到 32,你会发现模型开始“说半句就停”。这不是故障,是生成长度到了上限。这个参数要结合你的真实场景来设:短问答 128-256 足够,长文生成再放宽。
做完这三个实验,你基本就掌握了“让模型按你想要的方式说话”的钥匙。后面的所有调优,本质都是在做一个平衡:稳定性和创造性的平衡,速度和质量之间的平衡。
5. 影响速度与稳定的四个隐藏参数
5.1 上下文长度与 KV Cache 的显存账要算清楚
之前提到 KV Cache 会随上下文长度增长,这里把账算清楚,你就知道为什么不能把上下文窗口盲目设大。
简化记忆:KV Cache 的大小约等于“层数 × 注意力头维度 × 2 × 上下文长度 × 每个缓存值的字节数”。具体数字不用背,但要知道量级:同样是 7B 模型,把上下文从 2048 提到 8192,KV Cache 占用的显存可能从几百 MB 涨到几个 GB。如果你把上下文窗口设到 32768,显存占用会非常夸张。
所以启动时不要抱着“越大越强”的念头,要梯级测试。先设 2048 或 4096,确认显存占用在安全范围,再逐步往上加,每次加完跑一个长对话测试。如果看到显存占用已接近上限,就停在那档,别贪。
还要明白一个关系:上下文长度和“输入长度 + 历史记录数 + 最大生成数”有关。你在 API 里发送的历史消息越多,实际占用的上下文空间越大。如果你的应用是客服问答,每次只带最近的几轮对话就够了,不必把所有历史都塞进去。
5.2 并发数并不是越大越好
本机部署时,受限于硬件,并发能力是有明确上限的。很多人在启动参数里看到--parallel之类的并发配置,就试着调大,结果发现服务反而变慢,甚至直接卡死。
原因是:并发请求越多,引擎需要同时维护的生成状态就越多,显存和计算资源被瓜分。当资源不够时,所有请求都在排队等待,单请求延迟会显著变长。我的习惯是:刚开始只允许 1 个并发,跑通后逐步加,观察两个指标——单请求响应时间和是否出现显存溢出错误。
如果你的目标是多人同时使用,不要指望单机无限扛,更合理的做法是采用队列机制:把请求排队,保证每个请求都能拿到稳定的资源。这种方式下,单个请求的速度可能不会最快,但整体服务质量更可控。
5.3 流式输出与首字延迟
用户感知的“快”和引擎实际的“快”不是一回事。模型生成大段文字时,整体耗时不短,但如果你采用流式输出,模型每生成几个 Token 就立即推送给前端,用户的等待感会大幅降低。这就是为什么很多聊天应用看起来“打字机式”输出,体验却很好。
首字延迟(从请求发出到第一个 Token 返回的时间)往往比总生成时间更重要。如果你的场景是实时对话,建议开启流式模式,并在客户端做一个边接收边渲染的组件。哪怕服务端总生成时间没有变化,用户体验也会明显提升。
有一个容易忽略的点:流式对服务端和客户端的连接管理要求更高。如果连接频繁断开,前端会显示内容输出到一半。这时候不要急着怪模型,先检查超时设置和网络稳定性。
5.4 显存、内存与交换区域的边界
当你同时开多个进程或者加载了较大模型时,机器可能开始使用交换空间(也就是把一部分内存数据临时写入磁盘),这时候服务会瞬间变慢,表现是:明明显存还有余量,但每个请求的响应时间都在增长。
排查这事很简单,启动服务前和请求过程中,各看一眼系统资源占用:如果内存几乎被占满,磁盘读写又频繁,那大概率是走交换了。解决办法不太多,最直接的是“关掉其他吃内存的进程”,或者换一个更小规模的模型。如果应用必须保持长上下文,那就只有升级硬件这一条路。
我的经验是,在资源比较吃紧的机器上,启动模型服务之前先把浏览器、大型 IDE 这类程序关掉,收益非常明显,有时响应速度能提升一倍以上。
6. 给模型加上记忆,做出第一个真正能用的应用
6.1 服务端的“无记忆”和客户端的 Memory
模型 API 本身是无状态的:你发一次请求,它根据你提供的消息生成一次回复,不保存任何历史。所以“让模型记住之前的对话”这件事,必须由你自己来实现——把历史消息作为上下文,反复传给服务端。
这个设计初看有点笨,但它其实是优点:服务端不需要维护会话状态,你的应用逻辑完全可控。你可以选择只传最近两轮,也可以选择传完整的摘要,这完全由你的业务需求决定。
最简单的记忆实现,就是在你的 Python 程序里维护一个消息列表,每次请求前把列表作为messages字段一起发送。下一轮对话前,把用户新输入和模型回复追加进去。
6.2 一个带会话记忆的 Python 函数
下面这个函数是我常用的最小实现,它维护一个全局的历史消息列表,并在发送前截断过长的历史:
import urllib.request import json history = [] MAX_HISTORY_TOKENS = 2048 def chat_with_memory(user_input, server_url="http://127.0.0.1:8080/v1/chat/completions"): global history history.append({"role": "user", "content": user_input}) # 简单的截断逻辑:只保留最近 6 条消息,防止上下文无限膨胀 if len(history) > 6: history = history[-6:] payload = { "model": "local-model", "messages": [ {"role": "system", "content": "你是一个可靠的项目助手,回答要简洁、有依据。"} ] + history, "temperature": 0.6, "max_tokens": 512 } req = urllib.request.Request( server_url, data=json.dumps(payload).encode("utf-8"), headers={"Content-Type": "application/json"}, method="POST" ) with urllib.request.urlopen(req, timeout=120) as resp: result = json.loads(resp.read().decode("utf-8")) reply = result["choices"][0]["message"]["content"] history.append({"role": "assistant", "content": reply}) return reply这段代码的价值不只是“跑通”,它展示了一个很关键的思想:记忆的本质是取舍。你不需要把全部历史都带上,只需要带最近的、最相关的部分。截断策略可以很简单,但必须存在,否则一个话痨应用能把自己聊到上下文爆炸。
如果你希望对更长的对话做记忆管理,可以引入摘要机制:每累积一段时间,就让模型把之前的对话浓缩成几句摘要,以后带着摘要继续聊。这种方法牺牲一点细节,但能稳定控制上下文长度。
6.3 加一个系统提示词约束模型的行为
很多人直接空着 system 消息就开始调 API,这很可惜。系统提示词是你对模型最直接的行为约束工具。它可以在每个请求里重复声明,成本极低,收益却很明显。
举个例子,如果你希望模型回答控制在 3 句话以内,在 system 里写“请用不超过三句话回答,直接给结论”比你在 user 里每次重复一遍更稳定。如果你希望模型不做不确定的断言,可以写“如果不确定,请明确说不知道”,这能明显减少模型的“一本正经胡说八道”。
我自己建议把系统提示词拆成几个模块:角色设定、回答风格、输出格式限制、敏感情况处理。每条用简短明确的话写,不要写长篇大论,模型对冗长提示词的理解效率反而不高。
还有一个技巧:把回答格式也在 system 里定义好。比如需要返回 JSON,就写明“只输出 JSON,不要解释”。这比在用户输入里反复强调要可靠得多。
6.4 从对话到简易知识问答:先走关键词检索
应用再往前走一步,就是让模型基于你自己的文档回答问题。网上这类教程往往直接上复杂架构,容易劝退新手。我这里给一个朴素但实用的启动方案:先走关键词检索,再让模型改写。
流程很简单:把你的文档切成若干小片段,每段带上编号;用户提问后,在片段里做关键词匹配,选出最相关的一到三个片段;把片段内容拼接在用户问题前面,作为上下文发给模型;模型基于这些片段给出回答。
这个方案没有向量化、没有知识库系统,准确率当然不如精密方案,但胜在你可以快速理解“给模型喂参考信息”这个概念。跑通之后,你再决定要不要引入语义向量检索,逻辑也是一通百通。
有个细节:给模型喂参考片段后,要在 system 里声明“只能基于提供的参考内容回答,如果参考内容中没有,请明确说明”。否则模型大概率会自由发挥,把没有依据的内容也说得头头是道。
7. 我在这轮启动里踩过的坑,以及你的排查路径
7.1 路径里有中文和空格,模型加载失败
这个坑我踩过不止一次,而且每次报错信息都极具迷惑性。有一次模型加载到 80% 突然失败,日志提示“文件读取异常”,我排查了半天依赖问题,最后发现是文件夹名字里带了一个括号和中文,引擎解析路径出了问题。
解决思路很朴素:把所有模型和工作目录统一放在纯英文、不包含空格的路径下。如果你的用户名本身带中文,也要特别注意,很多默认路径里会包含用户名,需要手动指定一个干净的绝对路径。
7.2 看着显存够,结果还是内存溢出
显存“看着够”是因为只算了权重大小,没算 KV Cache 和运行开销。有一次我加载一个 13B 模型,量化后权重约 7GB,我的显卡显存 8GB,我心想稳了,结果一启动就报显存不足。后来算上 KV Cache 和临时缓冲区,实际需要接近 8.5GB,自然就爆了。
排查方法很直接:启动服务前记住显存空闲值,启动后再看一次,两者的差值就是模型的实际占用。如果这个值已经很接近上限,就别再开其他 GPU 任务了。
7.3 服务“卡住”不一定是模型问题,先看日志和网络
遇到服务无响应,大多数人第一反应是“模型太慢”。但很多时候,问题出在请求本身:端口没通、请求格式不对、超时设得太短。有一次我客户端提示超时,结果服务端日志显示请求根本没到,原因是防火墙拦截了本地端口的访问。
排查顺序我建议固定:先看服务端日志有没有收到请求;再看端口监听是否正常;接着用最简单的命令测一下连通性;最后才去考虑模型推理时长。按这个顺序,大多数“卡住”都能快速定位。
7.4 结果不稳定是正常的,别急着修框架
这一条算心理建设。同一个问题得到不同答案,在 temperature 大于 0 时完全正常。不要一遇到输出变化就怀疑模型文件损坏或者框架有 bug。如果你想验证模型能力,先把 temperature 设为 0 再对比;如果你需要稳定产出,应用层的逻辑就应该设计成接受一定随机性。采样本身是模型生成的一部分,不是故障。
7.5 一组随手可用的定位手段
最后分享几条排障时我会先做的动作:观察 GPU 显存占用情况和内存占用情况;查看服务日志里有没有关键字样的报错;用一个已知能通过的极简请求(比如问“你好”)测试服务是否正常;再到模型文件目录下检查文件体积与社区发布信息是否一致。这几条做完,大部分启动问题都有明确方向了。
写到这里,我其实最想说的是:本地跑一个大模型,真正难的不是跑起来那一下,而是在跑起来之后,能准确判断“下一步该动哪里”。每改一个参数之前,想清楚这个参数改的是什么;每遇到一个报错之前,先分辨它是资源问题、格式问题还是逻辑问题。养成这个习惯,你会发现自己很快就不再需要对照指南了。这套迭代式的排查思路,也是我从一次次踩坑里沉淀下来最值钱的东西。