先把结论甩出来:想让 AI 回答时标出"这句话来自哪份文档、第几段",核心就两步——检索时把命中片段的元数据(文件名+chunk id)一起带出来,生成时让模型在句末挂个 [1] 角标,再在回答底部列出来源。读者点开能核对原文,模型也没那么敢瞎编。下面是我自己踩出来的做法。


起因挺琐碎的。我们组有份四十多页的内部 SOP,新人天天来问我"退款流程第几步要走审批",问烦了我就想塞个 AI 小助手进去自己答。

第一版我是真用了点心,直接把整份 SOP 喂给模型当上下文。结果呢,它答得倒是顺,但有次它跟同事说"满 200 减 30",我翻遍文档根本没这条——它自己编的。那一刻我有点慌,因为同事是真信了。

所以我下定决心:回答必须带出处。不带出处的 AI 答案,在我这儿等于没答。

怎么做的呢。其实不复杂。我把文档切成小块入库(RAG 那一套),关键是切块的时候别只存正文,把来源信息一块儿存进去:

# 入库时,每个 chunk 多带一份元数据
chunk = {
    "text": "退款超过200元需主管审批……",
    "source": "售后SOP_v3.pdf",
    "page": 7,
    "chunk_id": "sop-0042"
}

# 检索回来后,拼 prompt 时把编号和出处显式喂给模型
context = ""
for i, c in enumerate(hits, 1):
    context += f"[{i}] (来源: {c['source']} p.{c['page']})\n{c['text']}\n\n"

prompt = f"""根据以下资料回答,每句话末尾用 [编号] 标出依据的资料。
若资料里没有,就直说没有,不要编。

{context}

问题: {user_question}"""

要点在最后那句系统指令:让模型用 [编号] 标依据,且查不到就明说没有。我加了这句之后,那个"满200减30"的幻觉就再没出现过——它要么标出处,要么老老实实说文档里没写。

前端就更简单了,把回答里的 [1] [2] 渲染成可点击角标,点开浮层显示对应 chunk 原文和文件名。同事自己一对,信不信由他。

说几个我踩过的坑,免得你也栽:

现象

我的应对

切块太大

标了出处但整页飘红,核对累

chunk 控制在 300-500 字

编号对不上

模型标 [3] 但只检回 2 条

prompt 里写死"只能引用上面列出的编号"

第一版太干

答案像念条文

让它先答结论再附引用,别倒过来

要说缺点也有。这套东西它只干"忠实转述+标出处"的杂活,真要做需求推理、跨文档归纳,还是得人再过一遍。而且检索这一环慢,我这边一次问答大概要 1.5 秒才出来,急性子会嫌卡。学习曲线倒不算陡,但第一次配 chunk 大小和检索 topK,我来回试了一下午。

最让我意外的是搭这套压根没怎么写代码。我用的是那种零代码就能拖一拖配一配搭智能体的平台,挂个知识库、勾上"返回引用",发布成一个 API,半天就上线给同事用了。我一个平时主要写后端的,没碰前端也没训模型,居然就把这小助手立起来了。说实话当时有点惊到——原来搭个能用的 AI 助手,门槛已经低到这份上了。

现在新人再问退款,小助手答完底下挂着 [售后SOP_v3.pdf p.7],点开就是原文。我清净了不少。

(模型这块我直接走的讯飞星辰 MaaS,现成 API 调,没自己部署算力,省了一大圈事。)

你们给 AI 回答标出处都用什么招?评论区聊聊,我那个 topK 到底设几合适,到现在还没拿准。

Logo

一站式 AI 云服务平台

更多推荐