Skip to content

[ENHANCEMENT] 引用系统重构:按消息 ID 精确引用,替代按内容模糊反查 #214

Description

@Tosd0

背景

当前引用链路有两个结构性问题,已有的 bug(学格式、张冠李戴、翻译模式空引用、双语截断)都是它们的下游症状:

  1. 引用是"按内容模糊反查",不是"按身份精确引用"。 模型输出引文文本,applyAssistantPostProcessing.tsresolveQuoteTargetincludes/前缀匹配反猜目标消息。文本匹配天然脆弱(翻译、双语、复述、截断都会失败),失败后兜底到"最近一条用户消息"。同时它只搜 role === 'user'AI 引用自己的话会被静默地错挂到用户最近一条消息上
  2. 模型输出格式与它在历史里看到的格式不一致(round-trip 不保真)。 模型写 [[QUOTE:]],落库后历史被 chatPrompts.ts buildMessageHistory 渲染成自然语言头 [xx引用了xx说的「…」,并回复了 ↓]——模型在 few-shot 层面只见过后者,会模仿它输出错误格式。

第 2 点的解析端兜底已落地(见关联 commit:自然语言格式也被识别为合法引用并剥离),但那是止血,不是治本。

方案:按 ID 引用

  • 历史渲染:最近 N 条(30–50 条即可,引用几乎总指向近期消息)在现有 [时间戳] 头部旁加短 ID,如 [#482]
  • 输出格式:系统提示改为 [[QUOTE: #482]],语义变为"引用任意一条历史消息"——天然支持 AI 引用自己/图片/转账等。
  • 解析:三级降级——① ID 精确查表(确定性)→ ② 现有文本模糊匹配(兼容旧输出,本次落地的自然语言兜底也在这层)→ ③ 最近一条用户消息。
  • 历史渲染(AI 侧):AI 自己的引用消息原样回放 [[QUOTE: #N]]\n正文,round-trip 保真,模仿变成自我强化。用户侧保留自然语言渲染不动(那是 1db5ea5 针对"模型只看引用不看回复"的注意力修复,且用户引用存在「你之前说的/自己说的」消歧需求,见 6d0054d)。
  • 顺手项:引用块点击跳转原消息——基建全部现成(replyTo.id 已存、DOM 有 chat-msg-${id}handleJumpToMessageInChat 已被搜索跳转使用),ID 方案落地后 replyTo.id 变可靠,把 MessageItem.tsx 引用块的 onClick 接上即可;注意原消息被删除时优雅降级。

代价 / 注意点

  • Token 开销:每条历史多 ~4 token,只给近期消息编号可控制在数百 token。
  • 模型会回声 [#N] 头部标签(现有 sanitize 剥 4 种时间戳格式即是先例),需在 sanitize 加确定性剥离 [#\d+]
  • QUOTE 相关正则散在 4 处需同步:utils/applyAssistantPostProcessing.tsutils/sanitize.tsutils/chatParser.tscomponents/chat/MessageItem.tsxutils/sanitize.ts 被打进 instant-push worker bundles,改完需 pnpm build:workers 重打包。
  • 双语/翻译边界 case 有既有测试锁定(chatPrompts.quote.test.tsquoteReplyBilingual.test.ts),改渲染格式时需扩测。
  • 迁移成本为零:replyTo 本就存 id,存量数据与旧格式输出经 ②③ 层继续兼容。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions