报错是这么冒出来的。报告生成接口的文本总在第三节处断掉,finish_reason 是 length,把 max_tokens 从 1024 提到 4096 后仍断在同一位置,日志里 prompt 只有 600 token。
中间走过弯路,把「客户端流式拼接提前截断,日志里看到的已是残缺内容」当成主因,改完现象没变。
把日志和配置对完,能解释这个现象的基本就这几处。提示词要求输出完整 Markdown,模型按模板续写直到触顶。还有一种是4096 是单次输出上限,服务端另有每请求总 token 限制。
另外,模型对完整的理解是补全结构,不是补全业务内容。
动手时先看 finish_reason 到底是 length 还是 stop
python -c "from openai import OpenAI;r=OpenAI().chat.completions.create(model='gpt-4o-mini',messages=[{'role':'user','content':'写三节'}],max_tokens=64);print(r.choices[0].finish_reason)"
再往下把任务拆成按节生成再拼接
python -c "print(['第一节','第二节','第三节'])"
接着统计每次返回的完成 token 数
python -c "from openai import OpenAI;r=OpenAI().chat.completions.create(model='gpt-4o-mini',messages=[{'role':'user','content':'hi'}]);print(r.usage.completion_tokens)"
剩下的就是检查拼接结果是否都以句号收尾
python -c "print(all(s.endswith('。') for s in ['第一节完。','第二节完']))"
怎么算真的好了,看的是同一批现象。三节都能完整返回,finish_reason 全是 stop,拼接后的文本以句号结尾且没有半截标题。
补一句。长文生成靠调大上限只是治标,按结构拆分才稳,拆完要留一个总装步骤核对前后引用。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。
