调用返回一半就停住,通常不是模型不会答,而是空间分配或读取环节出了问题。先别急着改提示词,也别急着把输出上限拉满:在返回体里找到停止原因字段,再看输入长度和输出长度各占了多少,两项分开记录,才有依据决定动哪一边。下面按“先归因、再动手、最后固化”的顺序走,每一步都能用日志、配置或页面行为验证。
输出中途断掉时,先看返回里的停止原因:若是 max_tokens 一类的上限取值,优先调大输出上限;若是正常结束,回头查客户端拼接、流式分片或前端截断。再把输入长度和输出长度分开记录,判断上下文空间是否被提示词吃掉。两项数据分开看,改哪一项就有依据;只凭“感觉提示词太长”去删,往往会白改一轮。
在返回结果里定位停止原因字段
停止原因字段的通用名称是 stop_reason 或 finish_reason,具体用哪个名字、有哪些取值,以你所用接口的文档为准。它的作用只有一个:告诉你这次调用是正常结束,还是被某个上限切断。取值含义和处理方向大致可以这样对照。
| 取值方向 | 含义 | 先查什么 |
|---|---|---|
| max_tokens / length 一类 | 输出被上限截断 | 输出上限设置、是否需要调大 |
| end_turn / stop 一类 | 模型正常结束 | 客户端拼接、流式分片读取、前端展示截断 |
| stop_sequence 一类 | 命中了自定义停止词 | stop_sequences 是否误配了常见词 |
| tool_use / function_call 一类 | 转去调用工具 | 正文中断属于预期行为还是流程没接上 |
| 内容安全拦截一类 | 被过滤 | 提示词或输出内容是否触发了策略 |
如果日志里这个字段是空的,或者客户端根本没打印返回体,那第一步就不是调参,而是把原始返回完整落盘。看不到停止原因,后面所有判断都是猜。
分别统计输入长度和输出长度
输入长度在请求发出前记录,用提示词字符数加上对输入 token 的估算;输出长度在响应回来后,从返回体的用量字段(通常是 usage 里的输入、输出 token 计数)读取。两者不要合成一个数看,否则分不清是输入把窗口占满了,还是输出侧被卡住。
同一批输入前后两次调用,建议按下面这张表记录,只改一个变量,其余保持一致。
| 调用 | 提示词字符数 | 输入 token | 输出 token | 停止原因 | 现象 |
|---|---|---|---|---|---|
| 第一次 | |||||
| 第二次(仅改一处) |
判读规则很直接:输入长度接近上下文窗口上限,输出空间就被挤压,该动的是提示词;输入很小、停止原因却仍是上限取值,说明输出上限设小了,该动的是参数。若输入不大且停止原因是正常结束,那就去查客户端的流式读取和拼接逻辑。
把提示词按固定部分和可变部分拆开
拆分的目的不是把提示词写短,而是找出哪些内容根本不必每轮都塞进去。可以按这张清单过一遍:
- 固定部分:角色设定、输出格式约定、通用业务规则、few-shot 示例。
- 可变部分:本次用户问题、检索回来的片段、上一轮对话摘要。
- 适合外移的:长 few-shot、格式模板、业务词典、重复出现的说明段落。
- 适合压缩的:礼貌用语、重复强调、同一规则的多种说法。
外移之后,用拼接的方式在主提示词里留占位,例如把角色和格式约定放在系统提示,把示例按场景按需加载,把可变内容放在最后。示意骨架如下,名字按你自己的项目替换:
system: 角色 + 输出格式 + 通用规则(固定,可缓存)
user: 本次问题 + 检索片段(可变,放最后)
示例:按场景从外部模板读取,不必每轮全带压缩完不要凭感觉验收,用同一批输入重跑,对比输入 token 是否下降、输出是否变得完整。
调大输出上限后重跑同一批输入
这一步只改输出上限,提示词、温度、停止词都保持原样,然后重跑同一批输入。记录方式是把两版输出按段落对齐,标出第一处出现差异的位置。
| 段落序号 | 改前输出 | 改后输出 | 差异位置 |
|---|---|---|---|
| 1 | |||
| 2 | |||
| 3 |
如果调大之后内容接着往下走了,说明原因就是输出上限;如果仍在同一段落附近断,且停止原因不是上限取值,那问题多半在提示词结构或客户端读取,调大上限只是浪费额度。反过来,如果调大后不再截断,也能确认之前的输入长度并没有超窗口,不必再去删提示词。
把验证过的参数固化为默认配置
确认结论后,把它写回默认配置,避免下次重复排查。一份可替换的通用片段如下:
request:
max_output_tokens: <调大后的值>
temperature: <保持原值>
stop_sequences: []
log_fields:
- stop_reason
- input_tokens
- output_tokens
- prompt_chars配上一句检查规则就够了:输入长度接近上下文窗口上限,先怀疑输入;输入很小、停止原因仍是上限取值,先怀疑输出上限;输入不大且正常结束却仍被截断,去查客户端拼接和流式读取。这条规则写在接入层的日志注释里,比记在脑子里可靠。