报错是这么冒出来的。长文档入库时为省 token,先把每篇 8000 字压成 200 字摘要再算向量,检索命中的是摘要,模型只拿到摘要作答,用户问具体报销比例时答不出数字。
中间走过弯路,把「原文被清理策略按 30 天删掉了,摘要还在」当成主因,改完现象没变。
把日志和配置对完,能解释这个现象的基本就这几处。索引里只存了摘要,原文只留在源目录里没有回表逻辑。也可能是摘要与原文分在两个集合,缺少 id 映射。
少数情况下是引用字段记录的是摘要 id,前端据此只能展示摘要。
动手时先确认命中记录的字段里有没有原文 id
python -c "import chromadb;r=chromadb.PersistentClient('./chroma').get_collection('sum').get(ids=['d1']);print(r['metadatas'])"
给摘要补上 doc_id 与段落区间两个字段
python -c "print({'doc_id':'doc-88','span':'1200-2400'})"
接着检索命中后按 doc_id 回原文表取段落
python -c "print(open('corpus/doc-88.md').read()[1200:2400])"
剩下的就是把回表拿到的原文拼进上下文再交给模型
curl https://api.openai.com/v1/chat/completions -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"根据以下原文回答:<原文>"}]}'
别只看报错消失,验证要多做一步。问“报销比例是多少”时答案里出现原文的 70% 和 90% 两档,引用定位到具体段落,摘要只作为召回入口。
提醒一点。摘要适合做召回,不适合做证据,检索层和证据层要分开存,中间用 doc_id 加偏移量连起来,否则引用永远对不上原文。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
