4. 基本推理:使用 main 命令加载模型进行对话与文本生成

既然咱们已经把 llama.cpp 编译好了,也拿到了量化后的模型文件,接下来就该让它真正跑起来了。这一章我带你手把手地用 main 这个命令行工具完成最基本的推理——说白了就是让模型开口说话。

我个人习惯把 main 称为 llama.cpp 的“瑞士军刀”。它能加载模型、处理 prompt、控制生成参数,甚至还能开启交互模式跟你聊天。我们一步一步来。

4.1 main 命令长什么样?

先别急着敲命令。我们看看 main 的基本调用结构:

./main [选项] -m 模型路径 -p "你的提示词"

绝大多数参数都有默认值。你最少只需要指定 -m 和 -p 就能跑一句生成。但如果你想做点有质量的事,下面的参数你必须熟悉。

参数作用我的常用值
-m模型文件路径./models/qwen2-3b-q4_k_m.gguf
-p初始提示词"请写一首关于春天的诗"
-n生成的最大 token 数512
--temp温度(随机性)0.7
--top-p核采样概率阈值0.9
--top-k保留最高概率的 K 个 token40
--repeat-penalty重复惩罚系数1.1
--ctx-size上下文窗口大小2048
-i交互模式(可连续对话)无默认值
我的小技巧: 首次测试时先用 -n 128 限制一下输出长度,确认模型加载无误再放开。这样能快速排查路径问题或模型兼容性问题。

4.2 第一次对话:生成文本

假设你现在有一个 Qwen2-3B 的 GGUF 文件,放在 ./models/ 目录下。我通常会这样测试:

./main -m ./models/qwen2-3b-q4_k_m.gguf -p "你好,请用一句话介绍你自己。" -n 128 --temp 0.7

你会看到终端开始刷 log:加载模型、分配内存、然后模型开始“思考”。几秒后输出文本。嗯,这里要注意——第一次加载可能因为内存不足而报错,尤其是当你用 7B 以上模型时。我做项目时遇到过一次机器只有 8GB 内存,结果直接 OOM 了。后来我改用 --mlock 并限制 --ctx-size 1024 才勉强跑起来。

输出格式默认长这样:

...
你好!我是 Qwen,一个基于 Transformer 架构的语言模型。我可以帮助你回答问题、写作、编程等。
...

看到模型回复了?恭喜,你的 llama.cpp 基本推理已经通了。

4.3 对话模式:用 -i 实现多轮交互

光跑一次可不够。真正的对话需要多轮上下文。llama.cpp 的 -i 参数开启交互模式:

./main -m ./models/qwen2-3b-q4_k_m.gguf -i --interactive-first -n 512 --temp 0.8

加上 --interactive-first 之后,程序启动后不会立即生成,而是等待你输入第一句话。输入后回车,模型回复;然后继续等你下一句。退出用 Ctrl+C。

交互模式背后其实是一次性把历史对话拼接成 prompt 送给模型。所以上下文越长,推理越慢。我建议你在多轮对话时手动增加 --ctx-size,比如 4096,否则历史会被截断。

我曾经踩过一个坑: 在交互模式下忘记加 --ctx-size,结果聊到第 5 轮以后模型突然失忆,回答完全跑偏。后来才发现默认上下文只有 512,根本装不下几轮对话。把 --ctx-size 设为 2048 或更大就正常了。

4.4 控制生成质量的几个关键参数

你可能会发现同样的 prompt,每次输出都不一样。这是因为采样参数在起作用。下面这三个我几乎每次都会调:

  • --temp(温度):低温度(0.2~0.5)让输出稳定、可预测,适合代码生成;高温度(0.8~1.2)让输出更有创意,适合写故事。我个人写文案时喜欢用 0.9。
  • --top-p:动态调整候选词的数量。设置成 0.9 意味着只保留累积概率达到 90% 的那些词。通俗地讲,它像一把“滤网”,把那些极其不靠谱的词过滤掉。
  • --top-k:只从概率最高的 K 个词里采样。我一般保持 40,如果你发现模型重复太多,可以降到 20。

你可以把它们组合调试。比如:

./main -m model.gguf -p "写一段关于夏天的比喻" -n 200 --temp 0.9 --top-p 0.92 --top-k 50

效果会比默认的 --temp 0.8 --top-p 0.95 更奔放一些。

4.5 避坑指南与效率小建议

  • 模型加载慢?试试 --mlock 将模型锁在物理内存中,能减少 I/O 抖动。
  • 输出全是乱码?检查模型文件是否完整,或者 --seed 是不是设成了固定值导致采样异常。
  • 显存不够?使用 -ngl 0 把 GPU 卸载,纯 CPU 运行——虽然慢但至少能跑。
  • 想要流式输出?--stream 参数可以从终端实时看到 token 一个接一个吐出来,体验很好。

4.6 核心推理流程图

下面这张图把 main 命令发起一次完整推理的流程串了起来。你站在高处看一遍,心里就有底了。

main 命令推理流程 用户输入 prompt 解析参数 -m, -p, -n 等 加载 GGUF 模型 Tokenize + 拼接历史 采样(temp, top-p, top-k)→ 生成 token 交互模式 循环等待用户输入

你看,整个流程很直白:从我敲下命令到模型给出回复,中间经过了参数解析、模型加载、token 化、采样生成这几个主要步骤。交互模式不过是在生成完一次后,重新回到“用户输入”那个节点而已。

4.7 完整示例:让模型写一份周报

最后给你一个能直接运行的组合示例。假设你想让模型帮你写周报:

./main \
  -m ./models/qwen2-3b-q4_k_m.gguf \
  -p "帮我写一份本周工作总结周报,包含以下内容:\n1. 完成需求评审\n2. 修复线上 bug\n3. 搭建测试环境" \
  -n 300 \
  --temp 0.5 \
  --top-p 0.9 \
  --ctx-size 4096 \
  --repeat-penalty 1.1

等它输出完,你就能看到一份格式工整的周报。如果觉得太死板,把 --temp 调高到 0.8 再跑一次,语气就会更自然。

记住: main 命令是学习 llama.cpp 的基石。后期你接触 server 模式、绑定库、batch 推理时,这些参数和概念都会反复出现。所以这一章的基础一定要打牢。

好了,拿起你的终端,选一个模型,跑一句试试看。有问题不要紧,多试几次参数,慢慢就摸清脾性了。