news 2026/8/14 3:17:13

基于LangChain与ChromaDB的RAG应用实战:以《红楼梦》问答为例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于LangChain与ChromaDB的RAG应用实战:以《红楼梦》问答为例

1. 项目缘起:为什么是《红楼梦》与RAG?

最近在折腾大模型应用,发现一个挺有意思的现象:很多朋友一上来就想搞个“万能知识库”,恨不得把公司所有文档、个人所有笔记都喂进去。结果往往是,要么向量化过程卡死,要么召回结果驴唇不对马嘴,最后项目不了了之。我自己的经验是,从一个小而具体的领域切入,把全链路跑通、吃透,远比一开始就铺个大摊子要实在得多

所以这次,我选了《红楼梦》作为实验对象。原因很简单:第一,文本体量适中,全文约73万字,既不会像单篇文档那样过于简单,也不会像海量文档库那样复杂到让人迷失;第二,内容结构清晰,有明确的人物、情节、诗词,非常适合测试问答系统的准确性;第三,文化内涵丰富,很多问题需要结合上下文理解,比如“林黛玉为什么葬花?”、“‘冷月葬花魂’这句诗好在哪里?”,这能很好地检验RAG系统是否真的“理解”了文本,而不是简单的关键词匹配。

这个项目的核心目标,就是手把手带你从零开始,搭建一个能针对《红楼梦》进行高质量问答的RAG应用。我们会用到LangChain这个当今最流行的AI应用框架来组织流程,用轻量高效的ChromaDB作为向量数据库存储知识,最后调用通义千问的qwen-plus模型来生成最终答案。整个过程,我会把每一步的原理、踩过的坑、以及那些官方文档里不会写的调试技巧,都掰开揉碎了讲清楚。无论你是刚接触LangChain的新手,还是想找一个具体项目来深化理解的开发者,相信都能有所收获。

2. 核心组件选型:为什么是LangChain + Chroma + qwen-plus?

在动手之前,我们得先搞清楚手里的“兵器”。市面上框架、模型、数据库那么多,为什么偏偏是这套组合?这背后是经过一番权衡和实际测试的。

2.1 LangChain:不只是“胶水”,更是“脚手架”

很多人把LangChain理解为连接大模型和外部工具的“胶水”,这个说法对,但不全面。在我实际使用中,它更像一个高度模块化、提供了最佳实践范式的“脚手架”。对于RAG应用,它至少解决了三个关键问题:

  1. 文档加载与处理的标准化:一本《红楼梦》的txt文件,你怎么读?LangChain提供了TextLoaderUnstructuredFileLoader等一大堆文档加载器,能处理PDF、Word、HTML等多种格式。更重要的是,它内置了文本分割(RecursiveCharacterTextSplitter)的逻辑,这是RAG的基石。你自己写分割逻辑,很容易切碎一个完整的句子或诗词,而LangChain提供的分割器已经考虑到了中英文的标点、换行等特性,开箱即用,省心不少。

  2. 流程编排的抽象化:RAG的核心流程“检索 -> 增强 -> 生成”是一个固定范式。LangChain将其抽象为RetrievalQA链。你只需要配置好检索器(Retriever)和大模型(LLM),它就能自动帮你完成“将用户问题转化为向量 -> 去向量库检索 -> 将检索到的上下文和问题组合成Prompt -> 发给LLM生成答案”这一整套流程。这避免了我们在业务逻辑里写大量胶水代码,让开发更聚焦于核心优化点。

  3. 生态与扩展性:LangChain有极其丰富的集成生态。今天我们用Chroma,明天想换Milvus或Pinecone,可能只需要改一行代码。想给检索结果加个重排序(Re-ranking)模块?也有现成的接口可以接入。这种设计保证了项目的可迭代性。

注意:LangChain的版本迭代很快,API有时会有变动。建议在项目开始时就用pip freeze > requirements.txt锁定核心库的版本,避免后续跑不通。本项目基于langchain==0.1.0langchain-community==0.0.10进行。

2.2 Chroma:轻量且开发者友好的向量数据库

向量数据库是RAG的“记忆体”。选择ChromaDB,主要是看中它的两个特点:

  • 极致简单,内置嵌入:Chroma最大的优势是“开箱即用”。它内置了多种开源的句子嵌入模型(比如all-MiniLM-L6-v2),你甚至不需要单独去申请Embedding API的密钥,就能快速把文本转化为向量。这对于原型验证和中小型项目来说,极大地降低了门槛。它可以直接在内存中运行,也支持持久化到磁盘,部署方式非常灵活。
  • 与LangChain深度集成:Chroma是LangChain官方推荐和深度支持的向量数据库之一,集成度非常高。从创建集合(Collection)、添加文档到构建检索器,都有非常简洁的API。

当然,Chroma不适合海量数据(比如上亿条)的生产环境,它的集群能力和性能优化相比专业的商业向量数据库有差距。但对于我们这个百万字级别的《红楼梦》项目,以及绝大多数个人或中小团队的知识库场景,它都是绰绰有余且最佳的选择。

2.3 qwen-plus:选择闭源大模型的现实考量

模型层,我们选择了通义千问的qwen-plus。这里可能有人会问:为什么不用开源的Llama 3或者Qwen2.5?原因在于项目阶段的务实选择

  1. 稳定性与易用性:在项目搭建和调试阶段,我们最需要的是模型输出的稳定性和API调用的便捷性。闭源模型如qwen-plus、GPT-4,提供了稳定可靠的云端服务,我们无需关心模型部署、显卡资源、推理优化等问题,可以把全部精力放在应用逻辑本身。
  2. 强大的指令遵循与长上下文能力qwen-plus拥有128K的上下文长度,这对于RAG应用非常重要。当我们的检索器返回多段相关文本时,需要模型有能力在长长的Prompt中准确找到并利用这些信息。它的指令遵循能力也经过优化,能更好地理解我们设计的Prompt模板,输出我们想要的格式。
  3. 成本可控:对于《红楼梦》这个规模的问答,调用次数有限,使用qwen-plus的API成本极低,甚至可能在新用户赠额范围内。这比自己去部署一个同等能力的开源模型要经济、省事得多。

一个重要的心法:在项目初期,用钱换时间和稳定性是划算的。先用成熟的闭源API快速跑通流程、验证想法,等到流程稳定、需求明确后,如果成本成为问题,再考虑用开源模型进行替换和优化,这才是更高效的路径。LangChain的模型接口是抽象的,未来切换模型供应商,核心代码几乎不用动。

3. 环境搭建与数据准备:从文本到向量的第一步

理论说再多,不如动手做。我们首先需要一个干净的环境,并把《红楼梦》的原始文本处理成向量数据库能“消化”的格式。

3.1 创建虚拟环境与安装依赖

强烈建议使用虚拟环境来管理依赖,避免包冲突。

# 创建并激活虚拟环境 (以conda为例,venv同理) conda create -n rag-honglou python=3.10 conda activate rag-honglou # 安装核心依赖 pip install langchain==0.1.0 langchain-community==0.0.10 # ChromaDB及其依赖 pip install chromadb # 用于调用通义千问API pip install dashscope # 用于文档加载(处理txt) pip install unstructured # 可选但推荐:用于更准确的文本分割 pip install tiktoken

这里解释一下tiktoken:它是OpenAI开源的BPE分词器,非常高效。LangChain的RecursiveCharacterTextSplitter可以用它来精确地按token数量分割文本,这对于控制上下文长度、优化成本至关重要。即使我们不用OpenAI的模型,这个分词器本身也是一个优秀的工具。

3.2 获取并清洗《红楼梦》文本

你可以在古登堡计划等网站找到《红楼梦》的纯文本版本。下载后,通常需要做一些简单的清洗:

  1. 去除无关信息:删除文件开头和结尾的版权声明、项目介绍等非正文内容。
  2. 处理章节标题:确保章节标题格式统一,例如“第一回 甄士隐梦幻识通灵 贾雨村风尘怀闺秀”。这有助于后续分割时,章节信息能作为一个整体被保留。
  3. 统一换行符:将文本中的换行符统一为\n

假设我们清洗后的文件保存为hongloumeng.txt。一个干净的文本是后续高质量向量化的前提。

3.3 文档加载与智能分割:RAG成败的关键

这是整个流程中技术含量最高、最容易被忽视,也最容易出问题的环节。很多RAG效果差,问题八成出在这里。

from langchain_community.document_loaders import TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter # 1. 加载文档 loader = TextLoader(‘./hongloumeng.txt‘, encoding=‘utf-8‘) documents = loader.load() print(f“原始文档加载完毕,共 {len(documents)} 个文档对象。”) # 通常为1 # 2. 配置文本分割器 text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, # 每个文本块的最大字符数(或token数) chunk_overlap=50, # 相邻块之间的重叠字符数 length_function=len, # 计算长度的方法,这里用字符数。如果用tiktoken,可以换成 `tiktoken_len` separators=[“\n\n“, “\n“, “。“, “;“, “,“, “ “, ““] # 分割优先级列表 ) # 3. 执行分割 split_docs = text_splitter.split_documents(documents) print(f“分割后得到 {len(split_docs)} 个文本块。”)

参数选择的艺术与实战经验

  • chunk_size=500:为什么是500?对于中文古典文学,《红楼梦》单句信息密度高。如果设置太大(如1000),一个块里可能包含多个不相关的情节,导致检索精度下降;设置太小(如200),可能会把一句完整的诗词或对白切断,丢失关键信息。500是一个经过测试的折中点,能较好地容纳一个相对完整的情节片段或人物描写。
  • chunk_overlap=50重叠是必须的!这是为了避免一个关键信息(比如一个人名出现在两个块的边界)被硬生生切开。50个字符的重叠,能确保上下文的连贯性。例如,一段描写结束在“黛玉听了,不觉”,下一段开头是“红了脸”,有了重叠,就能保证“黛玉听了,不觉红了脸”这个完整语义能被检索到。
  • separators列表:这个列表定义了分割的“刀”下在哪里。LangChain的分割器会按列表顺序尝试分割。这里我们把双换行(\n\n,通常表示段落分隔)放在最前面,其次是单换行、句号等。这意味着它会优先保证段落的完整性,其次才是句子。这个顺序对中文文本效果很好。

一个我踩过的坑:最初我用默认的英文分隔符(如\n\n,\n,“, “. “,“,“,),结果发现很多中文句号被忽略,导致块过大。**务必根据你的文本语言特性调整separators`**。对于中文,加入“。”、“;”、“,”是必要的。

执行完这一步,你会得到上千个文本块(split_docs)。每个块都是一个Document对象,包含page_content(文本内容)和metadata(元数据,如来源)属性。接下来,我们就要把这些块变成向量。

4. 构建向量知识库:让ChromaDB记住《红楼梦》

有了文本块,下一步就是将它们“嵌入”(Embedding)到高维向量空间,并存入ChromaDB。

4.1 初始化嵌入模型与向量数据库

Chroma的一大便利是内置了嵌入模型。我们使用它默认的all-MiniLM-L6-v2模型,这是一个在多语言语料上训练过的轻量级模型,对中文有不错的效果。

from langchain.vectorstores import Chroma from langchain.embeddings import HuggingFaceEmbeddings import os # 定义持久化路径 PERSIST_DIRECTORY = ‘./chroma_honglou_db‘ # 1. 初始化嵌入模型 # 使用HuggingFace上的开源模型 embeddings = HuggingFaceEmbeddings( model_name=“sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2“, model_kwargs={‘device‘: ‘cpu‘}, # 使用CPU,如需GPU可改为 ‘cuda‘ encode_kwargs={‘normalize_embeddings‘: True} # 归一化向量,有利于相似度计算 ) # 2. 创建并持久化向量数据库 vectordb = Chroma.from_documents( documents=split_docs, # 我们分割好的文本块列表 embedding=embeddings, # 使用的嵌入模型 persist_directory=PERSIST_DIRECTORY # 指定持久化目录 ) vectordb.persist() # 显式持久化到磁盘 print(f“向量数据库已创建并保存至 {PERSIST_DIRECTORY}”)

关键点解析

  • HuggingFaceEmbeddings:这里我换成了paraphrase-multilingual-MiniLM-L12-v2,它比Chroma默认的模型对中文的支持更好一些。model_kwargs指定模型运行的设备,encode_kwargs中的normalize_embeddings设置为True非常重要,它会对生成的向量进行归一化处理,使得后续的余弦相似度计算更加准确和高效。
  • Chroma.from_documents:这个方法一次性完成了三件事:将每个文档块通过embeddings模型转换为向量;在Chroma中创建一个集合(Collection);将所有向量和对应的原始文本、元数据存储进去。
  • 持久化:调用persist()后,所有数据会保存到本地目录。下次启动应用时,可以直接加载这个目录,无需重新生成向量,节省大量时间。

这个过程可能会花费几分钟,取决于你的文本块数量和模型速度。完成后,你的目录下会生成一个chroma_honglou_db文件夹,里面就是《红楼梦》的向量化知识库了。

4.2 验证向量库:进行第一次检索测试

在接入大模型之前,我们先验证一下向量库的检索能力是否正常。

# 重新加载持久化的向量数据库 vectordb = Chroma( persist_directory=PERSIST_DIRECTORY, embedding_function=embeddings ) # 定义一个简单的检索测试函数 def test_retrieval(query, k=3): print(f“\n问题:‘{query}‘”) docs = vectordb.similarity_search(query, k=k) print(f“检索到 {len(docs)} 个相关片段:”) for i, doc in enumerate(docs): print(f“\n--- 片段 {i+1} (相似度仅供参考) ---”) print(doc.page_content[:200] + “...“) # 打印前200字符 print(f“来源: {doc.metadata}”) # 测试几个问题 test_retrieval(“林黛玉第一次进贾府是怎样的场景?“) test_retrieval(“‘好了歌‘的内容是什么?“) test_retrieval(“贾宝玉的玉上刻了什么字?“)

运行这段代码,你会看到控制台输出与问题最相关的几个文本片段。这是检验你之前文本分割和嵌入模型是否有效的黄金时刻。

如何判断检索质量?

  1. 相关性:返回的片段是否直接回答了问题?例如,问“黛玉进府”,返回的片段是否确实描述了第三回“接外孙贾母惜孤女”的场景?
  2. 完整性:关键信息是否在一个完整的片段内?比如“好了歌”的全文是否被完整地检索出来,而不是被切成了两半?
  3. 排序性:最相关的片段是否排在第一位?

如果测试结果不理想,大概率要回溯调整文本分割器的参数(chunk_size,chunk_overlap,separators)。这是RAG调优中最重要的一环。

5. 接入大模型与构建问答链:让qwen-plus“开口说话”

知识库准备好了,现在需要请出“大脑”——大语言模型qwen-plus,并用LangChain的链(Chain)把检索和生成两个环节无缝衔接起来。

5.1 配置通义千问qwen-plus模型

首先,你需要前往阿里云百炼平台或灵积平台,创建一个API-KEY。

from langchain.llms import Tongyi import os # 设置你的通义千问API-KEY os.environ[“DASHSCOPE_API_KEY“] = “your-api-key-here“ # 替换成你的真实Key # 初始化qwen-plus模型 llm = Tongyi( model_name=“qwen-plus“, # 指定模型 temperature=0.1, # 温度参数,控制随机性。越低输出越确定。 top_p=0.8, # 核采样参数,与temperature配合使用。 streaming=False, # 是否流式输出,调试时可设为False )

参数解读

  • temperature:在问答任务中,我们通常希望答案确定、准确。因此设置为一个较低的值(0.1-0.3)。如果设得太高(如0.9),模型可能会开始“编造”一些《红楼梦》里不存在的情节。
  • top_p:与temperature一起作用,控制采样范围。0.8是一个常用值,能在保证一定多样性的同时避免跑偏。

5.2 设计Prompt模板:告诉模型如何“答题”

直接给模型“问题”和“上下文”,它可能不知道该如何组织答案。我们需要一个清晰的指令(Prompt Template)来引导它。

from langchain.prompts import PromptTemplate # 定义一个针对我们问答任务的Prompt模板 prompt_template = “““请根据以下提供的《红楼梦》相关上下文片段,回答用户的问题。 如果你在提供的上下文中找不到明确答案,请直接说“根据已知信息无法回答该问题”,不要编造答案。 上下文: {context} 问题:{question} 请给出准确、简洁的答案:””” PROMPT = PromptTemplate( template=prompt_template, input_variables=[“context“, “question“] )

这个模板有几个设计要点:

  1. 明确指令:开头就告诉模型任务是什么。
  2. 设定边界:强调“根据上下文”,并明确要求对于未知信息说“无法回答”。这是控制模型幻觉(Hallucination)的关键一步。没有这个约束,模型很可能会用它的内部知识(可能不准确或与本书不符)来编造答案。
  3. 结构化输入:用{context}{question}作为占位符,LangChain会在运行时自动填充。
  4. 要求简洁:要求“准确、简洁”,避免模型生成冗长的无关内容。

5.3 组装RetrievalQA链:完成最后拼图

现在,把向量数据库检索器、Prompt模板和大模型组装成一条自动化流水线。

from langchain.chains import RetrievalQA # 从向量数据库创建检索器 retriever = vectordb.as_retriever( search_type=“similarity“, # 使用相似度搜索 search_kwargs={“k“: 4} # 每次检索返回4个最相关的片段 ) # 创建RetrievalQA链 qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type=“stuff“, # 最常用的类型,将所有检索到的上下文“塞”进Prompt retriever=retriever, chain_type_kwargs={“prompt“: PROMPT}, # 使用我们自定义的Prompt return_source_documents=True # 非常重要!返回检索到的源文档,便于调试 )

关键参数解释

  • chain_type=“stuff“:这是最简单直接的方式,将所有检索到的文档片段合并成一个长字符串,放入Prompt的{context}中。它的优点是简单,缺点是有上下文长度限制(取决于模型)。对于qwen-plus的128K上下文和我们的4个片段,完全够用。其他还有map_reducerefine等复杂类型,适用于文档极多或需要摘要的场景,但复杂度高,本例不需要。
  • return_source_documents=True务必设置为True。这能让链在返回答案的同时,也返回它参考了哪些原文片段。这是后期调试和优化的生命线。当你发现答案不对时,可以立刻查看模型到底“看”到了什么材料,从而判断是检索出了问题,还是模型理解出了问题。

6. 实战问答与深度调试:从“能用”到“好用”

激动人心的时刻到了,让我们问几个问题,看看这个亲手搭建的系统表现如何。

# 定义一个漂亮的问答函数 def ask_question(question): print(f“\n🤔 用户问题:{question}”) print(“-“ * 50) result = qa_chain({“query“: question}) print(f“🧠 AI答案:{result[‘result‘]}”) print(“\n📖 参考来源:”) for i, doc in enumerate(result[‘source_documents‘]): print(f“ 片段{i+1}: {doc.page_content[:150]}...“) # 打印片段前150字 # 开始提问! ask_question(“贾宝玉和林黛玉是什么关系?“) ask_question(“‘金陵十二钗‘正册里都有谁?“) ask_question(“薛宝钗吃的‘冷香丸‘是怎么制作的?“) ask_question(“贾府最后为什么被抄家了?“)

运行后,你应该能看到模型生成的答案以及它背后参考的原文。现在,才是真正工作的开始——调试与优化。你可能会遇到以下几种典型情况:

6.1 情况一:答案不准确或未命中

问题:问“冷香丸配方”,答案却只说了“薛宝钗从胎里带来一股热毒”,没提具体的药材和制作工艺。排查:立刻看source_documents。如果检索到的片段里根本没有配方细节,那就是检索环节的问题。解决方案

  1. 调整检索数量:将search_kwargs={“k“: 4}中的k调大,比如到6或8,增加命中概率。
  2. 优化检索方式search_type可以尝试从“similarity“(相似度)改为“mmr“(最大边际相关性)。后者会在考虑相关性的同时,尽量让返回的片段多样性更高,避免内容冗余。
    retriever = vectordb.as_retriever( search_type=“mmr“, search_kwargs={“k“: 6, “fetch_k“: 20, “lambda_mult“: 0.5} )
  3. 回溯检查分割:如果调整检索后依然找不到,很可能配方描述被你的chunk_size切碎了。你需要回到第3步,检查相关章节的原文,调整分割策略。对于“冷香丸”这种配方描述,可能需要更小的chunk_size或不同的separators来保证其完整性。

6.2 情况二:答案包含幻觉或无关信息

问题:回答“贾府被抄家的原因”时,模型开始自由发挥,扯上一些历史背景或自己推断的原因。排查:查看source_documents,如果提供的片段里没有明确原因,但模型却给出了答案,这就是模型幻觉解决方案

  1. 强化Prompt指令:在Prompt模板中,把“不要编造答案”的警告写得更严厉、更具体。例如:“你必须严格依据上下文作答。上下文未提及的信息,一律视为未知,绝对不允许自行推断或添加任何外部知识。”
  2. 降低模型“创造力”:将temperature参数进一步调低,比如到0.01,让模型输出更加保守和确定。
  3. 后处理过滤:在代码层面对答案进行校验,如果答案中出现“可能”、“我觉得”、“历史上”等词汇,或者与源文档相关性极低,可以触发一个重答或提示“信息不足”。

6.3 情况三:答案冗长或格式不佳

问题:答案把检索到的几个片段内容几乎原样复述了一遍,没有提炼。解决方案

  1. 优化Prompt:在Prompt中明确要求“用简洁的语言概括”、“直接回答核心问题”、“分点列出”。
  2. 尝试不同的chain_type:虽然stuff简单,但refine链类型可以让模型迭代式地精炼答案。不过这会增加调用次数和复杂度,对于简单问答不一定必要。
  3. 模型层面控制:除了temperature,还可以调整max_tokens来限制答案的最大长度。

一个重要的调试习惯:始终打开return_source_documents=True。任何一次错误的回答,都不要直接去修改模型参数或Prompt,而是先看源文档。90%的问题出在检索(向量化)环节,而不是生成环节。

7. 进阶优化与扩展思路

当基础问答跑通后,我们可以考虑让这个系统变得更强大、更智能。这里分享几个有明确提升效果的进阶方向。

7.1 为文档块添加元数据(Metadata)

我们之前分割的文档块,丢失了重要的章节信息。添加上下文元数据能极大提升检索质量和答案的可解释性。

# 假设我们在分割时,能够知道每个块属于第几回(可以通过解析原文标题实现) # 这里演示如何后补元数据(实际应在分割时处理) for i, doc in enumerate(split_docs): # 这里需要根据你的文本解析逻辑来填充,此处为示例 doc.metadata = {“source“: “hongloumeng.txt“, “chapter“: “第五回“} # 然后使用带元数据的docs创建向量库 vectordb = Chroma.from_documents( documents=split_docs_with_metadata, # 带元数据的文档 embedding=embeddings, persist_directory=PERSIST_DIRECTORY )

在检索时,元数据可以作为过滤器(Filter)使用。例如,用户可以问:“在‘宝玉挨打’那一回里,贾政说了什么?”。我们可以先检索“宝玉挨打”相关的回目元数据,再在该范围内进行相似度搜索,结果会精准得多。

7.2 实现多路召回与重排序(Rerank)

这是工业级RAG系统的常见优化手段。核心思想是:先用简单的检索方法(如关键词BM25)快速召回一批候选文档,再用更精细的模型(交叉编码器)对它们进行重排序,最后把最相关的几篇交给大模型

# 伪代码思路 from rank_bm25 import BM25Okapi from sentence_transformers import CrossEncoder # 1. 关键词召回 (BM25) bm25_index = BM25Okapi([doc.page_content for doc in split_docs]) keyword_candidates = bm25_index.get_top_n(question, split_docs, n=20) # 2. 向量召回 vector_candidates = vectordb.similarity_search(question, k=20) # 3. 合并去重 all_candidates = merge_and_deduplicate(keyword_candidates, vector_candidates) # 4. 使用交叉编码器重排序 model = CrossEncoder(‘cross-encoder/ms-marco-MiniLM-L-6-v2‘) pairs = [[question, doc.page_content] for doc in all_candidates] scores = model.predict(pairs) # 根据scores对all_candidates排序 # 5. 取Top-K作为最终上下文 final_context = top_k_reranked_candidates

这种方法结合了关键词匹配的“字面”相关性和向量匹配的“语义”相关性,能显著提升召回文档的质量。LangChain社区也有相关的ContextualCompressionRetriever等组件可以探索。

7.3 构建Web应用界面

一个命令行工具毕竟不方便。我们可以用GradioStreamlit快速构建一个Web界面。

# 使用Gradio的示例 import gradio as gr def answer_question(history, message): # history是对话历史,这里我们实现单轮问答 result = qa_chain({“query“: message}) answer = result[‘result‘] # 可以附上参考来源 sources = “\n”.join([f“- {doc.page_content[:100]}...“ for doc in result[‘source_documents‘]]) full_response = f“{answer}\n\n**参考来源**:\n{sources}” return full_response # 创建界面 demo = gr.ChatInterface( fn=answer_question, title=“《红楼梦》智能问答助手“, description=“基于RAG技术构建,知识来源于《红楼梦》全文。请提问吧!“, ) if __name__ == “__main__“: demo.launch(share=True) # share=True会生成一个临时公网链接

运行这段代码,一个拥有聊天界面的Web应用就启动了。你可以把它分享给朋友,让他们也来体验一下。

从一行代码没有,到拥有一个能回答《红楼梦》问题的智能应用,这个过程本身就是一个完整的“从0到1”的项目实践。它涉及了数据处理、算法应用、系统集成和交互设计。更重要的是,你亲手摸清了RAG每一个环节的“脾气”,知道了问题可能出在哪里,以及如何去优化。这套方法论和工具链,完全可以平移到你自己的专业文档、公司知识库、甚至是个人笔记的管理上。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/14 3:15:40

GoClaw:基于Go与etcd的云原生分布式任务调度框架设计与实践

1. 项目缘起:从 OpenClaw 到 GoClaw 的旅程作为一名在微服务架构和中间件开发领域摸爬滚打了十多年的老兵,我经手过不少框架,也踩过不少坑。OpenClaw 这个名字,圈内的朋友可能不陌生,它是一个基于 Java 生态构建的、功…

作者头像 李华
网站建设 2026/8/14 3:11:47

从提示工程到驭缰工程:构建安全可控的AI Agent基础设施

1. 项目概述:从“提示”到“驭缰”的工程思维进化最近在AI Agent的开发和落地实践中,我越来越频繁地听到一个词:Harness Engineering,中文可以翻译为“驭缰工程”或“缰绳工程”。乍一听,这似乎是“Prompt Engineering…

作者头像 李华
网站建设 2026/8/14 3:11:45

微软MAI-Image-2.6文生图模型本地部署与测试全指南

微软在文生图领域又放了个大招。这次不是小打小闹的更新,而是直接推出了一个名为 MAI-Image-2.6 的新模型。根据 LMSYS 的 Arena 文生图模型排行榜,这个模型一发布就直接冲到了 第二位 ,仅次于当前公认的顶级模型。这意味着,在…

作者头像 李华
网站建设 2026/8/14 3:11:13

场景化适配+合规审查+技术突破:运营商AI数据分类分级最优解决方案

一、方案概要:智能化落地赋能运营商数据安全与价值双平衡提示:本节聚焦运营商数据治理核心诉求,简述方案技术架构、核心能力与落地价值,明确智能化分级的行业适配优势。数据分类分级是运营商数据安全治理与数字化转型的核心底座&a…

作者头像 李华
网站建设 2026/8/14 3:10:27

GitHub汉化终极指南:5分钟让你的GitHub界面全中文

GitHub汉化终极指南:5分钟让你的GitHub界面全中文 【免费下载链接】github-chinese GitHub 汉化插件,GitHub 中文化界面。 (GitHub Translation To Chinese) 项目地址: https://gitcode.com/gh_mirrors/gi/github-chinese 你是否曾被GitHub的全英…

作者头像 李华