LLM Fallback Prompt 把「借来的公司名」写成事实:Identifying Field 必须剥离
做 LLM 生成功能时,有一类 bug 极难自查:明明传给模型的数据"看起来是对的",输出却是错的——具体公司名、地址、法人出现在了完全不该出现的记录里。我在一个内部工作流系统里就踩了这个坑,折腾了好几轮才找到根因。
现象
系统需要对某份结构化记录批量生成一段自然语言描述。部分记录本身没有公司信息(例如个人参保类条目),代码里写了一个 fallback 逻辑:从同一客户的其他记录里借用最近一条有公司的条目,把它的公司字段喂给 LLM,意图是让 LLM"感知行业氛围",生成风格连贯的描述。
问题是:LLM 输出里出现了这样的句子——
"在某某有限公司担任项目经理,负责信息技术相关项目……"
而这条记录本身跟那家公司毫无关系,只是个人参保条目。客户看到直接说"这是胡说",调试者打印 prompt 数据一看——公司名确实传进去了,数据层面是"对的"。
根因
问题出在 prompt 模板的语义引导上。模板长这样:
公司名:${companyName}
所属行业:${industry}
经营范围:${businessScope}
岗位:${jobTitle}
请生成一段工作职责描述。
LLM 看到 公司名:XX 有限公司 这个字段后,会把它当作事实断言直接 echo 进陈述句——这是 LLM 的天然行为,它没有能力区分"这个字段是真实主体"还是"这只是风格参考"。
Fallback 的本意是借用临近实体的行业/经营范围作风格 hint,但若不剥掉 identifying field,LLM 就会把那家公司的名字写进输出,造成张冠李戴。
Prompt 模板里凡是包含专名(公司名、注册地址、法人姓名、统一信用代码等 identifying field),LLM 就会倾向于把它们写进陈述句。即使你在代码注释里写 // NOTE: 这是 fallback 借来的,不要写进输出,LLM 也看不到 JS 注释。
同理,把字段改成 公司名:(参考)XX 公司 也无济于事——LLM 仍会 echo "在 XX 公司"。
正解
按字段语义分两类,fallback 路径只保留 style hint,identifying field 全部清空:
| 类别 | 典型字段 | fallback 时处理 | |---|---|---| | Identifying | 公司名、法人、注册地址、统一信用代码、公司 ID | 清空 | | Style hint | 所属行业、企业类型、经营范围、规模 | 保留 |
效果:LLM 看到 公司名:(空)\n所属行业:信息技术\n经营范围:软件开发、技术服务… 后会输出——
"负责信息技术相关项目管理,统筹软件开发与技术服务工作……"
——风格连贯,且绝不会编造具体公司。
代码层面,主路径和 fallback 路径显式分叉,不要用同一个 generate() 然后在数据里偷偷清字段:
if (mainEntity) {
// 真有公司 · 全字段喂 LLM
return generate({
companyName: period.companyName || mainEntity.name,
jobTitle: title,
companyInfo: {
name: mainEntity.name,
industry: mainEntity.industry,
companyType: mainEntity.companyType,
businessScope: mainEntity.businessScope,
registeredAddress: mainEntity.registeredAddress,
},
})
}
// fallback 模式 · 风格 hint only · identifying field 全空
return generate({
companyName: '',
jobTitle: title,
companyInfo: {
name: '', // ✗ 清空
industry: fallbackEntity?.industry, // ✓ 保留
companyType: fallbackEntity?.companyType, // ✓ 保留
businessScope: fallbackEntity?.businessScope, // ✓ 保留
registeredAddress: '', // ✗ 清空
},
})路径分叉显式,审 PR 的人和未来的自己都能一眼看清意图,不会在下次迭代时"顺手"把公司名加回去。
主路径与 fallback 路径显式分两个调用,而非用同一份数据悄悄清字段。这样意图透明,也防止日后维护时无意中把 identifying field 复原。
如果 LLM 偶尔还是脑补出行业典型公司名(训练数据里的),可在 system prompt 加硬规则:"不要在输出里 mention 任何具体公司名、地址或人名,只描述岗位本职职责。"
排查思路
遇到 LLM 输出里出现"不该有的具名实体",按以下顺序排查:
- 打印完整 prompt(不是业务日志,是真正送给 LLM 的字符串)
- 搜 prompt 里有没有 identifying field —— 有就是根因
- 找 identifying field 是从哪条数据来的 —— 主路径还是 fallback
- 若是 fallback 带来的:剥离 identifying field,只保留 style hint
一句话外卖
Fallback 实体只能贡献「风格」,不能贡献「身份」——送给 LLM 之前,identifying field 必须清空。