我写了个客服留言的小工具。
提示词里有一句「按下面格式输出」,后面跟着一个 JSON 示例。
第一次跑就报错了。
KeyError: "情绪"
报错的地方不在模型,在我拼字符串的那一行。
模板长这样
四行,70 个字符。
第三行是那个 JSON 示例,一个左花括号,情绪字段,处理建议字段,一个右花括号。
第四行是留言的位置。
在 Python 里这段模板就是个字符串,我用 format 把留言填进去。
问题在于 format 不认 JSON。
它只认花括号。
模板里所有花括号都被当成占位符,于是它去找一个名字叫「情绪」的变量,找不到。

我试了 8 种写法,两种会炸
第一种,format。
报错 KeyError。
第二种,format_map 加一个 defaultdict 兜底。
这是我在网上看到的救法,说法是「缺的键返回空字符串」。
它也没撑住。
抛的是 ValueError,说格式说明符无效,后面跟着一大串引号冒号组成的东西。这个报错比 KeyError 还难懂,因为它连是哪一行都不点明。

后面六种都过了。
转义花括号再 format、百分号格式化、string.Template、str.replace、f-string 拼接、以及把内容里带占位符的情况。
六种成功的输出长度都是 94 个字符。
模板 70,留言 29,中间那个占位符 5 个字符,一减一加刚好。
把花括号转义也能救 format
这是最直接的修法:模板里的 JSON 花括号写成两层,format 看到两层就还你一层。
改完之后 format 正常跑通,JSON 示例原样保住。

replace 有个细节值得说
我把留言内容故意写成「他说{msg}」,看会不会被二次替换。
结果是 72 个字符,占位符原样留着,没有被再替换一遍。
因为 replace 只扫一遍。
这个行为大多数时候是好事,你不用担心用户输入里带花括号会把模板搞乱。
format 其实也是单遍的,它不会递归。
前提是它别先报错。
我的取舍
现在这套工具我改成 replace 了。
理由很实际:模板里一旦出现 JSON 示例,format 就得靠转义才活。
转义这种东西,我自己三个月后未必记得为什么那儿是两层花括号。而且下次改模板,多半是在别人的代码里加一行,很容易忘了转义。
replace 没有这个问题。
它什么花括号都不管,你给它什么它就填什么。
但也别把 format 说死
format 不是坏的。
模板里没有花括号的时候它最好用,尤其是参数少的时候能直接看出哪个槽没填,缺参数会在第一次运行就抛错,而不是悄悄留个空。
replace 填错了不会报错,它只会安静地少填一个。
这是它的代价。
我没试的部分
jinja2 之类的模板引擎没测【本人未实测】。
它们有自己的转义规则,大概率能处理,但我没跑。
f-string 我只测了最简单的拼接,没测嵌套引号那些情况。
这 8 种写法是我在 Python 3.12 上跑的,换个语言结果全变。
一句话
提示词里要不要放 JSON 示例,取决于你用什么方式拼字符串。
放之前先想一下那对花括号会不会被当成占位符。
你那边是把提示词硬编码在代码里,还是单独放文件?
放文件的其实早就绕开这个坑了。