Grok 4.6 这类模型在“按格式输出”上跑偏,通常不是模型故意多说话,而是提示词只描述了想要什么,没有把结构边界钉死:字段示例决定它知不知道长什么样,头尾标记决定程序能不能截到有效片段,解析校验决定坏输出会不会流到下游。这三层缺任何一层,多余解释、字段缺失、标记不完整都会以不同形式冒出来。可以先按顺序补,不必一次全加。
遇到格式跑偏,先分清是哪一类:多出解释,就加字段示例和“只输出 JSON”的约束;内容截不干净,就加唯一的头尾标记;字段缺失或类型不对,就在入库前加解析校验,并对缺失字段做一次重试补全。验证方式是固定同一段输入重复执行几次,记录是否出现解释、缺哪些字段、标记是否成对。模型版本、温度或输入长度变化后要重新验证,不要把一次成功当成长期结论。
对比纯文字指令与带字段示例的提示词效果
对比要在同一任务、同一段输入上做,否则分不清是提示词的问题还是输入本身的问题。选一个字段结构清楚的场景,例如把会议记录整理成 JSON,然后写两版提示词。
第一版是纯文字指令:
把下面的会议记录整理成 JSON,包含参会人、议题、待办事项。
<record>
...粘贴会议记录...
</record>
第二版把字段名、类型和一条完整示例写进去:
你是信息抽取器。只输出 JSON,不要写解释,不要用 Markdown 代码块包裹。
字段定义:
- attendees:字符串数组,人名
- topics:字符串数组,每条一个议题
- todos:数组,元素为 {"owner": string, "task": string, "due": "YYYY-MM-DD 或 null"}
输出示例:
{"attendees":["张三","李四"],"topics":["预算"],"todos":[{"owner":"张三","task":"提交预算表","due":null}]}
原文:
<record>
...粘贴会议记录...
</record>
记录方式:两版提示词各重复执行几次,用同一张表记四件事——是否出现解释性文字、缺失了哪些字段、是否带了多余的 Markdown 围栏、去掉标记后能否直接解析。如果带字段示例的版本仍然给出解释,说明只给示例不够,需要下一节的头尾标记;如果示例版本字段齐了但偶尔裹着代码块,问题留给后面两节处理,不必再改字段定义。
在提示词里固定输出头尾标记并测试解析
头尾标记的作用是让程序用字符串查找就能定位有效输出。标记要选正常中文、英文和代码里都不容易自然出现的串,避免用三个反引号、连续横线这类常出现在正文里的符号。
输出必须严格按下面的形式,回复中只有这三部分:
<<<JSON_BEGIN>>>
{...你的 JSON...}
<<<JSON_END>>>
BEGIN 之前和 END 之后不要有任何字符,包括空格、换行和说明文字。
人工检查可以固定成四条:把模型原始回复整段复制到 out.txt,先不要手工删内容;搜索两个标记,确认各出现一次且 BEGIN 在 END 之前;用 sed -n '/<<<JSON_BEGIN>>>/,/<<<JSON_END>>>/p' out.txt 截出中间段,看里面是否只有 JSON;如果标记出现多次,通常是模型把提示词里的示例标记也照抄了,把示例中的标记换成占位写法(例如 <JSON_BEGIN>)再试。END 标记缺失则多半是生成被截断,先检查输出长度上限,而不是继续往提示词里加约束。
对缺失字段的情况设计一次重试补全
字段一旦缺失,下游要么报错中断,要么用空值糊过去留下错数据。比较克制的做法是只补缺失字段,并且只重试一次。
上一轮输出的 JSON 缺少这些字段:["todos[1].due", "topics"]。
请只补上缺失部分,输出一个完整的 JSON 对象,不要解释,不要改动已有字段的值。
原文里确实没有的信息,值写 null,不要推测补写。
原文:
<record>
...和上一轮完全相同的原文...
</record>
几个容易忽略的点:重试请求必须带同一份原文,否则模型只能编;只允许重试一次,第二次仍然缺字段就交给人工或按约定默认值处理,不要写成循环;同时保留两轮的原始输出,方便判断是提示词没覆盖这个字段,还是原文本来就没有这条信息。另外要提前约定“字段缺失”和“值为 null”在业务上的区别,否则补回来的 null 还是会引发歧义。
用正则或解析器验证输出是否可直接使用
把格式要求翻译成可自动判断的条件,顺序是从外到内、从粗到细,任一层不通过就判定为不可直接使用。
- 标记层:确认开始标记与结束标记成对出现且各只出现一次。
- 截取层:取出两个标记之间的字符串,其余内容全部丢弃。
- 语法层:交给 JSON 解析器解析,例如用
python -m json.tool或 jq 这类工具试一遍;解析失败直接判废,不要用字符串切割硬取字段。 - 结构层:检查必填字段是否存在、类型是否为约定的数组/字符串/null、数组元素是否包含约定的子字段。
- 取值层:对日期、枚举类字段做正则或集合校验,例如日期用
^\d{4}-\d{2}-\d{2}$,状态值只能落在允许列表内。 - 结论层:全部通过才进入下游;失败则走一次重试或人工确认。
需要提醒的是,解析器只能证明语法合法,不能证明内容正确。一个字段齐全、格式正确的 JSON 里也可能出现原文没有的人名或日期,所以取值层通常还要做一次“值是否在原文中出现”的检查,人名、金额、日期这类字段尤其值得查。
记录不同任务下最稳定的提示词结构
把每次调好的结构记下来,下次同类任务直接复用,比重新试提示词省事。记录维度建议固定成:任务类型、字段示例是否给出、头尾标记方式、输出稳定性记录、备注。
| 任务类型 | 字段示例 | 标记方式 | 稳定性记录 | 备注 |
|---|---|---|---|---|
| 会议记录转 JSON | 给出完整对象示例 | 头尾标记 | 是否有解释、缺哪些字段、标记是否成对 | 输入越自由越依赖示例 |
| 单标签分类 | 给出标签集合和一个单行示例 | 不标记,要求单行输出 | 是否输出了多个标签 | 枚举值必须写进提示词 |
| 长文摘要加要点列表 | 给出两条要点示例 | 头尾标记 | 条数是否超出上限 | 条数上限和每条字数要写明 |
| 代码或命令生成 | 给出一段可运行示例 | 代码块标记 | 是否混入解释文字 | 解释放到单独字段里 |
| 批量改写 | 给出输入输出对照 | 按行分隔 | 行数是否错位 | 按行解析并核对数量 |
记录时把模型版本、温度等参数一起写下来,它们会直接影响同一提示词的表现。稳定性记录建议按“重复执行若干次里出现的失败类型”来写,而不是只写一句“基本可用”,这样后面排查时能看出是示例不够、标记有冲突,还是输入本身信息不足。模型更新后用同一批记录重新跑一遍,就能判断原有结构是否还适用。