你让模型写 “10 条降噪耳机的营销 slogan”。它写了 3 条好的,然后甩出 and here are some more ideas: catchy, focused, premium. 就停了。或者它老老实实写满 10 行,但 7-10 条是 1-3 条的同义改写。或者它写完 10 条又继续写第 11 条,因为它根本没决定在哪停。这是最可预测的 LLM 失败模式之一:一个光秃秃的 list-N 请求没给模型任何可填的东西,它中途想不出新的,于是要么诚实截断、要么注水、要么过头。
最快的修法: 别只报个数字然后听天由命。把槽位摆给模型去填,再用代码把数量卡死。具体三步:(1)预先编好号(1. 到 10.,并写 “do not skip numbers”),(2)加一条 diversity 维度(“each from a different industry”),(3)调用后解析出 items,如果 len(items) < N 就再补一轮缺口。如果你用的是 Gemini API,还能在 schema 层用 minItems/maxItems 直接卡数量(下面细讲)。更根本的修法是:别再把 “给我 10 条” 当成一次生成,而是当成 10 个独立的生成步骤,每步带自己的约束。
先判断你属于哪一种
改 prompt 之前,先看实际输出,对上症状——不同病因,修法不一样。
| 输出里的症状 | 最可能的原因 | 跳到 |
|---|---|---|
| 几条之后以 “…and more” 收尾或直接断掉 | 主题本身就没有 N 个好答案 | 原因 1 |
| 10 条里有 7 条一个味(全是 SaaS、全是 marketplace) | 没给 diversity 维度 | 原因 2 |
| 不管你要 N 多大,总在差不多长度停下 | 软性 “答完了” 长度预算 | 原因 3 |
| 1-3 条详细,4-10 条一句话 | 没有 per-item 模板 | 原因 4 |
| 后面几条为了 “不重复” 做出奇怪的语义跳跃 | 模型在自我去重 | 原因 5 |
在某条中间断掉,finish_reason/stop_reason 不是 stop/end_turn | stop sequence 触发或撞到 max_tokens | 原因 6 |
| 单独跑没事,进了真实 pipeline 就 under-deliver | 指令被埋在长 context 里 | 原因 7 |
常见原因
1. 合理答案的空间比 N 小
你问 “10 unique benefits of drinking water”。真正不同的好处可能就 5 个。第 6-10 条只能是改写或灌水。不是模型的锅。
怎么判断:在看模型回答前先自问,“如果让我自己写,能想到 N 条真正不同的吗?“想不到,就是 prompt 要太多。
2. 没有 diversity 约束
“List 10 startup ideas.”模型会扑向高概率答案(AI for X、marketplace for Y),很快就重复了。这就是有据可查的长尾问题:模型过度采样常见答案、欠采样长尾。没有 “diverse across industries” 或 “each from a different sector”,items 就会收敛。
怎么判断:看模型给的 10 条,7 条是 SaaS 或 marketplace——你没约束 diversity。
3. 模型撞到了软长度预算
即使 max_tokens=4000,模型也有自己的 “答完了” 启发,常常在 400-600 token 左右就开始收尾,不管你要的 N 有多大。它是自然停下,不是 token 预算用光了。
怎么判断:数一下 response 的 tokens。不管 N 多少输出长度都差不多、而且 finish_reason 是 stop(不是 length),那就是软预算,不是硬上限。
4. 没有 item 模板——质量在飘
“List 10 product ideas” 没结构:模型前 3 个写得详细,4-10 草草一句。没有 per-item 模板,深度就漂。
怎么判断:1-3 条各 3 段;4-10 条每个一句话。
5. items 太相似——模型自我去重
写完 “1. Bluetooth connectivity” 后,模型不太愿意再写另一个无线相关的——它 pattern-match 成 “我已经覆盖过 wireless 了”。没明确允许相似,list 就塌缩。
怎么判断:7-10 条的语义跳跃明显比 1-3 大——它在硬撑 “不重复”。
6. stop sequence 或 token 上限提前触发
API 调用里设了 "\n\n" 或 "###" 这种 stop。模型在 items 之间输出了一个,API 就截断。或者你的 max_tokens 设太小,答案在某条中间被切了。
怎么判断:输出在 list 中间断掉。去看 API response 里的结束字段:
- OpenAI Chat Completions 返回
finish_reason。stop= stop sequence 触发或自然结束;length= 撞到了max_tokens上限。 - Anthropic Messages API 返回
stop_reason。stop_sequence= 你设的某个stop_sequences触发了;max_tokens= 撞到上限;end_turn= 模型自然写完了。
如果看到 length/max_tokens,就调高上限。如果看到 stop/stop_sequence 但 list 没写完,那就是 stop sequence 的锅——把 "\n\n" 和 "###" 拿掉。
7. 长 context 里的 list 请求被忽视
8000 tokens 的 context,你的 “give me 10 ideas” 只是最后 20 个 token。模型对埋在长 context 里的短指令系统性低关注。
怎么判断:prompt 单独跑没问题;在你的真实 pipeline 里 under-deliver。把指令挪到 prompt 末尾,并在开头和结尾各重申一次数量要求。
最短修复路径
第 1 步:检查 N 是否现实
自己都列不出 N 条,就改要少一点。封在现实数量。
第 2 步:加 diversity 维度
别只说 “10 different”,指定 axis:
List 10 startup ideas. Each idea must be in a DIFFERENT industry
(no two from the same sector). Span at least 8 of: healthcare,
education, fintech, climate, logistics, agriculture, retail,
entertainment, dev tools, B2B services.
模型现在有 10 个明确的槽要填。
第 3 步:给 per-item 模板
List 10 marketing taglines. For each tagline:
[N]. **<tagline>** (max 8 words)
— Angle: <pain point | aspiration | wit | technical>
— Target: <persona>
模板化的 item 强制全 list 深度一致。
第 4 步:预先把序号摆出来
Fill in items 1 through 10 below. Do not skip numbers. Do not stop early.
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
意外地有效——模型把它当 “填空” 任务,而不是自由生成。
第 5 步:在 schema 层卡数量(Gemini),或在代码里校验(OpenAI/Claude)
如果你能控制 API 调用、想要硬保证,最干净的杠杆是 response schema。截至 2026 年 6 月,各家支持程度不一,按你的 provider 选路子:
- Gemini API(
responseSchema)支持数组上的minItems和maxItems。两个都设成 N,就强制刚好 N 条:
{
"type": "array",
"minItems": 10,
"maxItems": 10,
"items": { "type": "string" }
}
(maxItems 设得很大时有人报过 500 错误,所以 N 保持合理,超过 50 就分批。)
- OpenAI Structured Outputs(
response_format: json_schema)截至 2026 年 6 月不支持minItems/maxItems——这俩关键字会被静默忽略,schema 保证不了数量。你仍能拿到干净的数组结构,但长度得自己校验(见第 7 步)。 - Anthropic Claude 没有原生的
json_schemaresponse format;用 tool-calling 配 input schema 来约束数组形状,然后在代码里校验数量。
第 6 步:N 大时分批生成
N >= 20 就拆:
all_items = []
for batch_start in range(0, 50, 10):
items = call_llm(f"""
Generate items {batch_start+1} through {batch_start+10} of a list of 50.
Already covered: {all_items}
Generate 10 NEW items not in the covered list.
""")
all_items.extend(items)
第 7 步:校验数量、补缺口
这是不挑 provider、不管 schema 支不支持都能用的兜底:
items = parse_list(output)
if len(items) < N:
extra = call_llm(
f"You previously gave {len(items)} items. Give {N - len(items)} MORE "
f"distinct items, none from this list: {items}"
)
items.extend(parse_list(extra))
第 8 步:拉高 max_tokens、删掉激进 stop sequence
短 item 把 max_tokens 设成 N * 80,详细 item 设 N * 200。生成 list 时把 "\n\n" 从 stop sequences 里拿掉。
怎么确认修好了
- 把 prompt 跑 3-5 次(list 是随机的,跑对一次不算数)。
- 每次跑完用代码断言
len(parse_list(output)) == N,别靠肉眼。 - 看结束字段:
finish_reason应该是stop、stop_reason应该是end_turn,而不是length/max_tokens。出现length/max_tokens说明模型还想继续——调高上限。 - 去重后盯一下结尾:如果倒数第 2、3 条几乎重复,要么 diversity 维度太窄,要么 N 本来就太大。
哪些情况不是你操作错了
有些任务确实没有 N 个好答案。逼模型造 7-10 条,比诚实给 6 条、注明 “more would be filler” 更差。在硬性要求 N 之前,先确认下游代码能不能接受变长 list。
容易被误判成 max_tokens 问题
有时确实是。但更多时候模型在远没到 token 上限时就自己收尾了,因为它没新想法了——finish_reason 回来是 stop(不是 length)。先看结束字段和 token 数,再决定要不要调 max_tokens;否则你把上限拉高了,list 照样停在 3 条。
预防建议
- 只问主题能合理支撑的 N。
- 永远带 diversity axis(industry / persona / format / angle)。
- 用 per-item 模板保证深度一致。
- 定长 list 预先编号占位。
- 用代码校验数量、按缺口重试,别信第一次回答。
- N 大就分批、把已覆盖项传进去。
- provider 支持的话(Gemini),把
minItems/maxItems钉死。
FAQ
- 能不能直接说 “as many as you can think of”? 那数量会变得不可预测,而且往往返回更少、更保险的几条。下游只要在乎 N,就明确写 N 并校验数量。
- 加 “high quality” 或 “creative” 有用吗? 边际作用。一条具体的 diversity 维度加 per-item 模板,比堆形容词管用得多。
- 能在 API 层强制刚好 N 条吗? 目前只有 Gemini 能(在
responseSchema里minItems=maxItems= N)。截至 2026 年 6 月,OpenAI Structured Outputs 会忽略这俩关键字,Claude 也没有json_schema格式,所以这两家得靠代码 validate-and-retry。 - 输出在句子中间断掉,是同一个 bug 吗? 不是。句中截断、
finish_reason: length(或stop_reason: max_tokens)是撞到了硬性 token 上限——调高max_tokens。本文讲的是模型在到 N 之前干净地停下,调上限治不了。 - 调高 temperature 好像能多出几条,要这么干吗? 它能提升多样性、减少早期塌缩,但也提高了跑偏或低质 item 的概率。比起猛拉 temperature,优先用明确的 diversity 维度和分批。
相关阅读
- 没指定输出格式
- 一个 prompt 塞太多任务
- AI 回答太空泛
- 没给例子导致输出漂移
- Prompt 范围太宽
- 没定义成功标准
- 模型自己补足缺失细节
- 评估标准含糊
- 输出很漂亮但没法执行
- AI 给列表不给执行
标签: #Prompt 工程 #排查 #llm-output #list-output #structured-output