localaiforum
登录
指南 › 使用模型

提示词与对话模板

你发的每条消息在模型看到之前都被包进标记。对话模板把你带角色标签的消息变成一条扁平的词元字符串、而模型受训读的正是那条字符串——不是你整洁的 API 对象。信封弄对、3B instruct 模型举止得体;弄错、70B 模型吐词汤。

信封:一次对话、三种方言

你的 API 暴露角色:system、user、assistant。模型看到特殊词元。同一场两条消息的对话、三种渲染方式。

ChatML——Qwen 家族模型和 Hermes 血统微调:

<|im_start|>system
You are a concise assistant.<|im_end|>
<|im_start|>user
Summarize this file.<|im_end|>
<|im_start|>assistant

Llama 2 风格——系统标记嵌在第一条指令里:

<s>[INST] <<SYS>>You are a concise assistant.<</SYS>>

Summarize this file. [/INST] The file implements a tokenizer... </s>

Gemma 风格——没有 system 角色;指令骑在第一条 user 轮上、助手叫 model:

<bos><start_of_turn>user
You are a concise assistant.

Summarize this file.<end_of_turn>
<start_of_turn>model

同一场对话、三个不兼容的信封。在 ChatML 上训练的模型不会“琢磨出”Llama 标记——它把杂散标记当普通文本、并以同样的方式回应。

引擎从模型文件读模板

GGUF 元数据内嵌 chat_template(一段 Jinja 片段)。llama.cpp、Ollama、LM Studio 和 Open WebUI 读它并自动渲染你的消息、这就是为什么聊天对一个正经 GGUF 开箱即用。两个经典陷阱:裸补全端点(/completion)跳过模板、把裸文本递给模型——用聊天端点;以及 GGUF 可能带着缺失或错误的模板发布——显式传一个(llama.cpp 的 --chat-template、Ollama 的 Modelfile)或从弄对了的来源抓同一模型的另一个量化。

错模板的症状

  • 瞬间空回复——渲染出的提示词已经像一场完成的对话、模型立即发 EOS。
  • 角色渗漏——输出读作 user: sure thing! assistant:——模型模仿信封而不是回答。
  • 垃圾——一小时前还聊得好好的模型产出基座式词汤、因为你换了文件没换模板。

诊断时、转储渲染后的提示词——llama.cpp 服务器详细记录它、OLLAMA_DEBUG=1 让 Ollama 显示它。然后修模板或文件:故障排查。

系统提示词与优先级

system 角色设定持久行为:人设、语言、输出格式、安全姿态。它是上下文、不是固件——长对话能把它冲掉、小模型对它的加权低于你的希望。两条实用规则:把任何承重的东西(语言、格式契约、硬约束)放进系统提示词并在最后的用户消息里重述;离生成最近的指令赢。

零样本 vs 少样本

零样本开口要;少样本做给它看。用 3B 模型从 bug 报告抽结构化字段、零样本——"Extract the title, component, and severity as JSON"——大约三分之二的时间得到有效、键一致的 JSON、键名漂移(这轮 severity、下轮 priority)。

少样本:同模型、两个示例、第三份报告留空:

Report: "Login button does nothing on Safari 17."
{"title": "Login button unresponsive", "component": "auth", "severity": "medium"}

Report: "App crashes when uploading 4K video."
{"title": "Crash on 4K upload", "component": "upload", "severity": "high"}

Report: "Dark mode makes settings text unreadable."

示例承载格式契约、于是采样器选择内容而不是发明 schema。在这类任务上、格式失败率通常从 ~30% 掉到几个百分点。两三个示例是曲线的膝;再往后你在付上下文词元。严格 schema 就完全别猜:结构化输出。

在小模型上活下来的模式

模式 为什么有效
每条提示词一个任务 任务争夺注意力;输家被丢掉
显式输出格式(“含键 a、b、c 的 JSON”) 把格式变成近乎确定的选择
编号步骤(“1) 定位 2) 解释 3) 打补丁”) 链条在轨道上而不是游荡
示例胜过描述 模型模仿得好过服从散文
简短的元指令 每条多余规则稀释其他每条规则

上下文中段是指令死亡之地

注意力在提示词的开头和结尾最强——“迷失在中段”效应、跨模型家族稳定。实用摆放:目标和格式契约在顶、待处理文档在底、长文档在载荷之后再补一行指令重复。位置与内容同样承重——而上下文每多一轮都花内存:KV 缓存。

停止序列

当模型发出它的 EOS 词元时生成结束——模板定义那是哪个词元。额外停止序列(llama.cpp 服务器和 OpenAI 兼容 API 上的 stop 参数)改为在字符串处截断:当话痨模型开始写你的下一条用户轮时有用。选只能意味着“轮次结束”的停止串(ChatML 模型上的 \n<|im_start|>)、绝不用出现在合法回答里的字符串——裸换行会把多行代码拦腰截断。

~7B 以下简洁胜过冗长

小 instruct 模型对 40 词指令的遵循好过 400 词的评分细则:它们有限的注意力摊在你递过去的一切上。结构和示例替代散文规则。长文提示词留给大模型;只有它们逐行读。

可复用片段模板

抽取:

从下面的文本中抽取:人名、日期、金额。
返回一个 JSON 数组,每项一个对象,键:name、date、amount。
JSON 前后不要有任何文字。
Text: {text}

摘要:

恰好用 3 个要点总结,每个不超过 15 个词,
写给错过会议的人。最重要的决定放最前。
Text: {text}

代码审查:

审查下面的 diff。最多列出 5 个发现,按严重程度排序。
每条格式:[severity] file:line — 问题 — 建议修法。
跳过称赞和总结。Diff: {diff}

相关: 词元 · 结构化输出 · 引擎参数 · 故障排查