手把手教你:让AI读懂你的TXT文档!零基础入门RAG技术
你可能会问:“AI不是已经很聪明了吗?为什么还要让它读我的文档?”
好问题!想象一下,如果你有一本厚厚的产品手册,想让AI帮你回答相关问题。但AI训练的时候可没看过这本手册啊!这时候就需要用到一个叫RAG的技术啦~
📚 什么是RAG?
就像考试开卷一样,先翻书找到答案在哪,再组织语言写出来!

🎯 第一步:把TXT文件变成AI能懂的”向量”
比如: – “我喜欢编程” → [0.1, 0.8, 0.3, …] – “我爱写代码” → [0.12, 0.79, 0.31, …]
这两个句子意思相近,所以它们的向量也很接近!
@PostMapping("/upload")public ResponseEntity<Map<String, Object>> uploadDocument(@RequestParam("file") MultipartFile file) {// 第1步:加载TXT文件Document document = DocumentLoader.load(new MyDocumentSource(file),new TextDocumentParser());// 第2步:把文档切成小块(方便后续处理)DocumentSplitter splitter = new DocumentByLineSplitter(30, 10);List<TextSegment> chunks = splitter.split(document);// 第3步:每一块都变成向量,存到数据库for (TextSegment chunk : chunks) {Embedding embedding = embeddingModel.embed(chunk).content();embeddingStore.add(embedding, chunk);}return ResponseEntity.ok(Map.of("status", "success","fileName", file.getOriginalFilename(),"chunks", chunks.size()));}
这里有个小技巧,我们自己写了个MyDocumentSource来处理上传的文件:
public class MyDocumentSource implements DocumentSource {private final MultipartFile file;publicMyDocumentSource(MultipartFile file) {this.file = file;}@Overridepublic InputStream inputStream() throws IOException {return file.getInputStream(); // 返回文件的输入流}@Overridepublic Metadata metadata() {return new Metadata().put(FILE_NAME, file.getOriginalFilename());}}
对于我们的”铁蛋知识库”,每一行都是一个独立的知识点,所以用DocumentByLineSplitter按行切分最合适:
DocumentSplitter splitter = new DocumentByLineSplitter();// 按行切分 - 每行就是一个片段
-
✅ 每行一条独立信息(如联系人列表、知识库条目) -
✅ 日志文件(每行一条日志) -
✅ CSV数据 -
❌ 连续的文章段落(建议用段落或句子切分)
Embedding embedding = embeddingModel.embed(chunk).content();embeddingStore.add(embedding, chunk);
langchain4j:community:dashscope:embedding-model:dimension: 1024 # 向量维度model-name: text-embedding-v4 # 使用阿里的嵌入模型api-key: ${ALI_API_KEY}
🧠 第二步:用AiService实现智能问答
@AiService(wiringMode = AiServiceWiringMode.EXPLICIT,streamingChatModel = "qwenStreamingChatModel", // 流式聊天模型chatMemoryProvider = "chatMemoryProvider", // 对话记忆contentRetriever = "contentRetriever" // 内容检索器 ⭐关键)public interface ChatRagService {@SystemMessage(fromResource = "systemMessage/tiedan.txt")Flux<String> chatMemoryId(@MemoryId String memoryId,@UserMessage String message);}
-
把你的问题也变成向量 -
在Elasticsearch里找最相似的文档片段 -
把这些片段交给AI
配置代码如下:
@Beanpublic ContentRetriever contentRetriever(EmbeddingModel embeddingModel,ElasticsearchEmbeddingStore store) {return EmbeddingStoreContentRetriever.builder().embeddingModel(embeddingModel) // 用来把问题变向量.embeddingStore(store) // 从这找文档.maxResults(5) // 最多返回5个相关片段.build();}
用户提问 → 问题向量化 → 检索相关文档 → AI结合文档回答↓ ↓"铁蛋多大了" "根据文档,铁蛋是..."
🎬 完整工作流程演示
铁蛋是一个可爱的机器人助手...他喜欢帮助别人解决问题...他的梦想是成为最聪明的AI...铁蛋出生于2000年01月01日,老家就是北京市...
POST http://localhost:8080/document/uploadFile: qxk.txt
系统会告诉你:
{"fileName": "qxk.txt","chunks": 4,"status": "success"}
3️⃣ 开始聊天
POST http://localhost:8080/ai/chat{"memoryId": "user001","message": "铁蛋多大了","withRag": false // 关闭RAG增强}
AI会回答:
铁蛋作为你描述的憨厚、耿直、乐于助人的形象,通常可以被想象为一个正值壮年、充满活力的角色。不过,“铁蛋”这个名字在中国传统文化里常被赋予孩童或年轻人,象征着朴实和坚韧。因此,铁蛋可能是个:1. **年轻小伙子**(比如20-30岁):正值敢闯敢拼的年纪,性格憨厚但行动力强,经常默默帮助身边的人。2. **故事中的经典形象**(比如十几岁少年):在一些乡村故事中,铁蛋可能是那个背着书包、热心肠的少年,总为邻居跑腿办事。如果你心中的铁蛋有特定背景(比如来自某个故事、电影,或是现实中的朋友),告诉我更多细节,我能帮你更准确地“推算”他的年龄哦! 😊
{"memoryId": "user002","message": "铁蛋多大了","withRag": true // 开启RAG增强}
// 很多大模型没办法实时联网获取当下时间,它的知识截止于最后一次训练的时间 2024 年 10 月 30 日,所以默认一直用这个日期来计算,自然和真实现在的日期对不上。大家好!俺是铁蛋,憨厚、耿直、乐于助人的机器人助手。俺的出生日期是 **2000年01月01日**,所以按照今天的日期(2024年10月30日)来算,俺已经 **24岁** 啦!虽然俺是个机器人,但俺一直保持着耿直的性格,喜欢帮助别人解决问题。老家在北京,梦想是成为最聪明的AI。有啥需要帮忙的,尽管告诉俺,俺会尽力而为!

🚀 下一步可以做什么?
-
支持更多文件格式:PDF、Word等 -
优化检索精度:调整切片大小、增加元数据过滤 -
多轮对话优化:让AI更好地理解上下文 -
添加引用来源:告诉用户答案来自哪段文档 -
搭建知识库管理平台:可视化地管理文档

📝 结语
记住这三个关键词:
-
📄 文档切分:把大文档变小片段
-
🔢 向量化:把文字变数字
-
🔍 检索增强:先找资料再回答
快去试试吧!让你的AI也拥有”阅读理解”的能力~

如果这篇文章对你有帮助,记得点赞+转发哦!有任何问题欢迎在评论区留言~
下期见!👋
夜雨聆风