把 prompt 从记事本另存为 UTF-8 后提交,git diff 里看不出改动,但 Jinja2 渲染出的消息多了一个空行,gpt-4.1-mini 的回答开始自己加小标题,长度从 180 字涨到 320 字,同一模板在 Linux 容器里跑却没有这个空行。
一开始怀疑是「Jinja2 没开 trim_blocks,块标签后面的换行被原样保留」,查了一圈,方向不对。
真正麻烦的地方在于,几个原因的现象几乎一样。Windows 编辑器保存时写入回车换行,模板末尾本来已有一个换行。另一种情况是仓库没锁换行方式,git 检出时按 autocrlf 又转了一次。
还有一种情况,配置中心把换行存成字面量,渲染前又被拼回两行。
数清模板里两种换行各有多少处
python -c "b=open('p.j2','rb').read();print(b.count(b'\r\n'),b.count(b'\n'))"
随后在仓库里锁定模板文件统一使用 LF
Set-Content .gitattributes '*.j2 text eol=lf'; git add --renormalize .
渲染时统一换行并打开 trim_blocks
python -c "import jinja2;s=open('p.j2',encoding='utf-8').read().replace('\r\n','\n');print(repr(jinja2.Template(s,trim_blocks=True).render(q='x'))[:300])"
剩下的就是用统一后的模板重放请求对比输出长度
python call_api.py --template p.j2 --record out.jsonl
别只看报错消失,验证要多做一步。渲染结果里不再出现连续空行,同一输入三次回答长度都落在 170 到 200 字之间,本机与容器渲染出的字符串逐字节相同。
这里还有个坑。换行符差异在 diff 里不可见,却会改变提示词的段落结构,模板文件最好在仓库层就固定成 LF。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。
