阿里面试官:“你说你的项目用了RAG,不就一行代码的事?”,我怼回去:“向量存储、混合检索、文档引用都直调API吗?”
AI应用开发中最常见的两个业务场景,一个是RAG,另外一个是Agent。
如果你的简历上既有RAG,又有Agent,基本上就很无敌了。
可能有些同学会认为有了SpringAI,开发RAG就一行代码的事,但其实不然,向量 chunk、向量存储、相似度检索、Prompt拼装、文档引用其实都大有学问。

我就拿派聪明RAG项目为例,给大家拆解一下RAG中文档引用的实现思路,以及怎么在面试中把这个点讲透。
这是一位同学在面试中遇到的真实场景。

原贴地址:https://t.zsxq.com/HA2LX
01、问题背景
在派聪明RAG项目里,我们采用的引用格式是这样的:
(来源#数字: 文件名)
比如RAG检索到了文档,LLM生成的回答里就会出现这样的引用:
项目定位:PaiFlow 被描述为“类似 Dify、工作流引擎”的项目,
旨在支持 AI 时代的应用开发
(来源#2: ✅PaiFlow能让大家学到什么?.docx)。
核心机制:其工作流引擎基于“DSL 驱动 + 节点执行器解耦 + 变量池隔离”的设计,通过解析前端生成的 JSON DSL(描述节点和边的 DAG 图)来驱动执行流程
(来源#4: ✅PaiFlow能让大家学到什么?.docx)。用户点击这个引用,前端就会发起下载请求,后端根据文件名去数据库里查找对应的文档,然后返回给用户。
但这里存在一个漏洞。
比如说用户2月1日上传了一个叫“test1.txt”的文件,内容是关于沉默王二上树的。系统给这个文件生成了一个唯一的MD5哈希值,假设叫AAA。

2月2日,他又上传了一个也叫“test1.txt”的文件,但这次是沉默王二这周又上树的。系统生成了另一个MD5哈希值BBB。
然后他问系统:"王二上树了吗?"
RAG系统很准确地从文件AAA和文件BBB里检索到了相关内容,LLM给出了答案,末尾加了引用:"(来源#1: test1.txt)"。
这时候就会乱套。
02、解决思路
问题出在哪?
后端收到下载请求后,解析出fileName是 test1.txt,然后执行findByFileName("test1.txt")。数据库里有两个同名文件,因为数据库的内部排序和findFirst()的不确定性,可能会返回文件AAA,也可能会返回文件BBB。
这个问题的根源在于,我们只用了fileName这个可能重复的字段去查找文档,而不是使用唯一的ID。
解决方案的核心思路是:在整个“检索-生成-引用”的链条中,始终传递文件的唯一标识符,而不是可能重复的fileName。
这个唯一ID可以是文件的MD5哈希,也可以是数据库自增的fileId。
具体怎么做呢?
第一步,改造RAG检索与Prompt构建。
当HybridSearchService检索到相关文档分片时,不仅要获取分片的文本内容,还要获取该分片所属文件的唯一ID和文件名。
在构建喂给LLM的Prompt时,上下文格式要改成这样:
[来源1, ID: 'BBB', 文件名: '项目周报.pdf']
研发部上周的主要工作是完成了支付模块的重构,包括...第二步,修改对LLM的指令。
在System Prompt里,对LLM生成引用的指令要更新为:
当你引用来源时,你必须严格使用以下格式:(来源#数字: 文件名, ID: 唯一ID)。
例如:(来源#1: 项目周报.pdf, ID: 'BBB')第三步,改造后端的引用解析和下载逻辑。
当LLM返回包含新格式引用的答案时,后端的解析逻辑要升级。不再只是匹配(来源#数字: 文件名),而是要匹配(来源#数字: 文件名, ID: 唯一ID)。
解析后,同时得到fileName(用于前端显示)和fileId(用于后端查找)。
用户点击下载链接时,前端把唯一的fileId发给后端。
后端下载接口从findByFileName(fileName)改成findById(fileId)。
这样就不会再找错文档了。
03、如何写到简历上?
那这个技术点,我们该怎么写到简历上呢?
项目名称:派聪明RAG - 企业级智能问答系统
项目描述:基于RAG(检索增强生成)技术的企业知识库问答系统,支持文档上传、向量化存储、语义检索和智能回答,提供文档溯源引用功能,确保AI回答的可验证性和准确性。
核心技术栈:Java 17、Spring Boot 3.x、SpringAI、MyBatis-Plus、Redis、Milvus向量数据库、Vue 3
核心职责:
- 设计并实现基于唯一标识符的文档引用机制,解决了同文件名文档的引用歧义问题,确保用户点击引用链接时能准确下载到原始文档
- 改造RAG检索链路,在向量检索结果中同时返回文件唯一ID(MD5)和文件名,并在Prompt构建阶段将ID信息传递给LLM
- 优化LLM的System Prompt,规范引用格式为
(来源#数字: 文件名, ID: 唯一ID),确保引用信息的完整性和可追溯性 - 重构后端引用解析逻辑,使用正则表达式匹配新格式引用,并基于fileId而非fileName进行文档查询,避免了同名文件导致的下载错误
面试话术:
在派聪明RAG项目中,我负责文档引用功能的设计和实现。最初我们使用文件名作为引用标识,但发现当用户上传多个同名文件时,会出现引用错误的问题。比如两个不同的'项目周报.pdf',系统可能会返回错误的那一个。
为了解决这个问题,我设计了一套基于唯一标识符的全链路方案。从RAG检索阶段就开始传递文件的MD5哈希值,在构建Prompt时把ID信息嵌入到上下文里,同时修改LLM的生成指令,让它按照固定格式输出引用。后端解析时提取fileId,用它来查找文档,而不是用可能重复的fileName。
04、面试中常见的追问
追问一:为什么不在文档上传时就禁止同名文件?
答:这在企业场景下不现实。不同部门可能会生成同名的文档,比如都叫"项目周报.pdf",强制改名会影响用户使用体验。所以我们的方案是允许同名,但通过唯一ID来区分。
追问二:如果文件内容更新了,MD5会变,之前的引用怎么办?
答:我们目前的处理是,文件更新后重新上传会生成新的MD5,旧文档的引用会失效。如果要彻底解决,可以考虑引入版本号机制。
追问三:引用解析的正则表达式怎么写的?
答:我们用的正则是\(来源#(\d+):\s*([^,]+),\s*ID:\s*'([^']+)'\),这个正则可以匹配#后面的数字作为引用序号,捕获文件名和唯一ID。实际使用中还做了容错处理,比如空格、大小写这些。
ending
就这个文档引用的问题,表面上看是个小BUG,但背后其实涉及到数据一致性、唯一性设计、全链路传递这些工程化的思考。
这些都是课本上学不到的,只有真正做过项目、踩过坑,才会有体感。
「真正能让你在面试中脱颖而出的,不是那些花哨的名词,而是你对细节的把控和对问题的深入思考。」
这也是我一直在星球里强调的,项目不要只做表面,要深入到每个细节,理解为什么这么做,还有没有更好的方案。
一个人可以走得很快,但一群人才能走得更远。二哥的编程星球已经有 11500 多名球友加入了,如果你也需要一个优质的学习环境,戳链接 🔗 加入我们吧。这是一个 简历精修 + 编程项目实战(RAG 派聪明 Java 版/Go 版本、技术派、微服务 PmHub)+ Java 面试指南的私密圈子,你可以阅读星球专栏、向二哥提问、帮你制定学习计划、和球友一起打卡成长。
最后,把二哥的座右铭送给大家:没有什么使我停留——除了目的,纵然岸旁有玫瑰、有绿荫、有宁静的港湾,我是不系之舟。共勉 💪。
