今天在 Web 摘要页看到一条把我逗乐又警觉的摘要:「我向自己咨询关于系统中退货单产品编辑列不可编辑的设置问题」。这句话逻辑是矛盾的——如果「我」是对话主人,怎么可能「向自己咨询」?这就是视角漂移:摘要把主人(我)当成了对话里的第三方。
根因:第一人称的识别依赖一个可能为空的名字
摘要函数 summarize_conversation 原本靠 agent.user_name 来判断「哪条消息是主人说的」。它会把 sender_name == user_name 的消息标成「我」,其余标成对方名字或「对方」,再交给 LLM 总结。这套机制在正常自动链路里没问题——运行时 current_user_name 是正确注入的。
但那次手动补生成今日摘要时,临时脚本构造的假 agent 没传 user_name。于是主人自己发的消息就以原名原样进了 prompt,LLM 看了误以为对话里有两个人(同事 A、我),便自作主张把「我」安到了对方头上,写出了矛盾的第三人称视角。
修复:把「谁是主人」显式钉死,prompt 加硬约束
两件事一起做:
- 显式参数:
summarize_conversation新增owner_name参数,调用方可以明确说「主人就是我」。不传时回退到agent.user_name,两者皆空则告警,绝不静默生成错误视角。 - prompt 硬约束:系统提示里写明「对话主人的名字/身份是 {owner_name},标注为『我:』的就是主人自己」「凡是主人的消息,摘要中统一用『我』指代;严禁出现『我向{owner_name}…』『{owner_name}向我…』这类把主人当成第三方的矛盾描述」「对方称呼主人为具体称谓或昵称,仍用『我』指代,不要切换视角」。
这样视角不再依赖模型自己猜——它有了明确的锚点,也收到了明确的禁区。
一次修复,四类链路全生效
周期性摘要(滚动调度器)、补跑机制、主动触达推送、Web 摘要页,这四条生成链路共用同一个 summarize_conversation。所以这次加固不只是修掉手动脚本的偶发事故,而是把正常自动链路的视角稳定性也一起焊死了。改完把今日三条摘要重新生成了一遍,清一色「同事 A 向我咨询…」「同事 B 问我…」「同事 C 向我询问…」,干净。
升级注意:纯逻辑修复,无新增配置项;改动需重启 Linkora 服务生效。
完整变更见 CHANGELOG,代码在 GitHub。下一步打算把 RAG 分块按语义边界切分、max_len 改成软上限,避免句中硬截断拉低召回。