Qwen3-4B快速上手集成LangChain实现基于知识的对话1. 从聊天到专家为什么需要知识增强你可能已经体验过Qwen3-4B Instruct-2507的对话能力了。它写代码、翻译文字、回答一般问题都挺流畅的感觉就像和一个聪明的朋友聊天。但如果你问它一些特别具体的问题比如“我们公司最新的产品定价策略是什么”或者“帮我分析这份技术文档的核心要点”它可能就有点力不从心了。不是它不够聪明而是它只能基于训练时学到的知识来回答对于训练数据之外的信息它要么不知道要么就可能开始“编故事”。这就像让一个记忆力超群的人去参加开卷考试却不给他带书——他记得再多也答不出书上才有的具体内容。怎么解决这个问题呢很简单给他“带书”就行了。今天要做的就是给Qwen3-4B配上它的“专属图书馆”。这个技术叫做RAG检索增强生成。它的工作原理很直观建图书馆把你的文档产品手册、技术资料、会议记录等整理好存起来。智能检索当你提问时系统会瞬间从图书馆里找出和问题最相关的几页资料。结合作答把问题和找到的资料一起交给Qwen3-4B让它基于这些“证据”来组织答案。这样一来回答的准确性和专业性就会大幅提升。它不再只是“凭感觉”聊天而是变成了一个“有据可查”的领域专家。本教程会带你一步步在你现有的Qwen3-4B对话应用里集成这套RAG系统。你不用从零开始写复杂的代码我们会用两个强大的工具——LangChain和Chroma——像搭积木一样快速构建出这个增强版的知识问答机器人。2. 准备工作认识你的新工具在动手之前我们先快速了解一下要用到的两个核心工具它们会让整个过程变得非常简单。LangChain是什么你可以把它想象成一个“AI应用乐高套装”。它把大模型调用、文档处理、信息检索这些复杂功能都打包成了一个个现成的、好用的模块。我们不需要自己从头写代码去连接模型、解析PDF格式、计算文本相似度直接用LangChain提供的“积木块”拼装就行。它大大降低了开发门槛。Chroma是什么它是我们用来存放“知识”的智能书架。不过它存的不是文字本身而是文字的“数学指纹”专业叫法是“向量”。当你提问时问题也会被转换成同样的“指纹”然后Chroma能快速找出“指纹”最相似的文档片段。这种基于语义的搜索比单纯的关键词匹配要聪明得多。整个流程可以概括为三个步骤如下图所示它清晰地展示了从文档准备到生成答案的完整过程flowchart TD A[“原始文档brTXT、PDF等”] -- B[“文档加载与分割”] B -- C[“文本向量化br创建数学指纹”] C -- D[“向量数据库存储brChroma”] E[“用户提问”] -- F[“问题向量化”] F -- G[“语义检索br找出最相似的文档片段”] G -- H[“组合提示词br问题相关文档”] D -- G H -- I[“大模型生成brQwen3-4B”] I -- J[“最终答案”]下面我们就开始动手把这些“积木”搭起来。3. 第一步安装必要的工具包打开你的命令行终端进入你的Qwen3-4B项目所在的文件夹然后执行下面的安装命令。这些是构建RAG系统必需的“零件”。pip install langchain langchain-community chromadb pypdf sentence-transformers简单说一下每个包是干什么的langchain: 核心框架提供了搭建AI应用链的各种基础组件。langchain-community: 包含了很多由社区维护的第三方工具集成比如我们等下要用的文档读取器。chromadb: 轻量级的向量数据库用来存储和检索我们文档的“向量指纹”。pypdf: 用来读取PDF文件里的文字内容。sentence-transformers: 里面包含了很多高质量的文本嵌入模型负责把文字转换成“向量指纹”。4. 第二步创建知识库处理核心我们需要新建一个Python文件专门负责处理文档和构建知识库。在你的项目目录下创建一个名为rag_core.py的文件。把下面的代码复制进去。这个KnowledgeBaseBuilder类就是我们的“图书管理员”它负责把上传的原始文档整理、加工然后存进智能书架Chroma。# rag_core.py import os from langchain_community.document_loaders import TextLoader, PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.embeddings import HuggingFaceEmbeddings from langchain.vectorstores import Chroma class KnowledgeBaseBuilder: 知识库构建器加载文档、分割文本、创建向量数据库 def __init__(self, persist_directory./chroma_db): 初始化 Args: persist_directory: 向量数据库保存到本地的文件夹路径 self.persist_directory persist_directory # 初始化文本嵌入模型用于生成向量 self.embeddings HuggingFaceEmbeddings( model_namesentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 ) # 初始化文本分割器把长文档切成小段 self.text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每段文本最多500个字符 chunk_overlap50, # 段与段之间重叠50字符防止上下文断裂 separators[\n\n, \n, 。, , , , , , ] ) def load_documents(self, file_path): 根据文件类型加载文档 if not os.path.exists(file_path): raise FileNotFoundError(f文件不存在: {file_path}) _, ext os.path.splitext(file_path) ext ext.lower() if ext .txt: loader TextLoader(file_path, encodingutf-8) elif ext .pdf: loader PyPDFLoader(file_path) else: # 可以后续扩展支持 .docx, .md 等格式 raise ValueError(f暂不支持的文件格式: {ext}) documents loader.load() print(f[INFO] 已加载文档: {file_path}) return documents def split_documents(self, documents): 将文档分割成小块 if not documents: return [] splits self.text_splitter.split_documents(documents) print(f[INFO] 文档分割完成得到 {len(splits)} 个文本块) return splits def create_vectorstore(self, documents, collection_namemy_knowledge_base): 创建或加载向量数据库 # 如果之前已经构建过就直接加载 if os.path.exists(self.persist_directory): print(f[INFO] 加载已有向量数据库: {self.persist_directory}) vectorstore Chroma( persist_directoryself.persist_directory, embedding_functionself.embeddings, collection_namecollection_name ) else: vectorstore None # 如果有新文档就添加到数据库或新建 if documents and len(documents) 0: print([INFO] 正在创建/更新向量数据库...) vectorstore Chroma.from_documents( documentsdocuments, embeddingself.embeddings, persist_directoryself.persist_directory, collection_namecollection_name ) print(f[INFO] 向量数据库已保存至: {self.persist_directory}) return vectorstore def build_from_file(self, file_path): 从单个文件构建知识库的完整流程 print(f[INFO] 开始处理文件: {file_path}) # 1. 加载 raw_docs self.load_documents(file_path) # 2. 分割 split_docs self.split_documents(raw_docs) # 3. 创建向量库 vectorstore self.create_vectorstore(split_docs) return vectorstore # 快速测试 if __name__ __main__: builder KnowledgeBaseBuilder() print(知识库构建模块加载成功) # 测试时取消下面一行的注释将路径换成你的文档 # vectorstore builder.build_from_file(./你的文档.txt)这个模块的核心工作就三步加载、分割、存储。它会把一篇长文档切成一个个语义完整的小段落然后转换成向量存进Chroma数据库。5. 第三步改造你的对话应用界面接下来我们要修改主程序文件通常是app.py把RAG功能加到原来的Streamlit聊天界面里。主要是增加两个东西一个上传文档的入口和一个切换“聊天模式”与“知识库模式”的开关。由于你的app.py文件可能已经比较长我在这里给出需要添加或修改的关键部分。请在你的代码中找到合适的位置插入。首先在文件开头的导入部分加入新模块# 在原有导入语句附近添加 import streamlit as st from rag_core import KnowledgeBaseBuilder # 导入我们刚写的模块 from langchain.prompts import PromptTemplate然后找到设置侧边栏st.sidebar的代码部分在调节参数的滑块后面加入知识库管理的功能# 假设你的侧边栏原有代码是这样的结构 with st.sidebar: st.header(控制中心) max_length st.slider(最大生成长度, 128, 4096, 1024) temperature st.slider(思维发散度, 0.0, 1.5, 0.7) # ... 你原有的其他控件 ... # --- 从这里开始是新增的RAG功能区域 --- st.markdown(---) st.subheader( 知识库增强 (RAG)) # 模式选择开关 use_rag st.checkbox(启用知识库增强模式, help开启后模型会先从你上传的文档中查找相关信息再生成回答。) # 文件上传器 uploaded_file st.file_uploader(上传知识文档, type[txt, pdf], help支持TXT和PDF格式。上传后会自动处理。) if uploaded_file is not None: # 保存上传的文件 temp_path f./temp_{uploaded_file.name} with open(temp_path, wb) as f: f.write(uploaded_file.getbuffer()) # 显示处理进度 with st.spinner(f正在处理 {uploaded_file.name}构建知识库...): try: builder KnowledgeBaseBuilder() # 调用我们写好的构建器 vectorstore builder.build_from_file(temp_path) # 把构建好的知识库保存到会话状态中方便其他地方调用 st.session_state[vectorstore] vectorstore st.success(f知识库构建成功) except Exception as e: st.error(f处理失败: {str(e)}) finally: # 清理临时文件 if os.path.exists(temp_path): os.remove(temp_path) # 显示当前知识库状态 if vectorstore in st.session_state and st.session_state.vectorstore: st.info(✅ 知识库已就绪) if st.button(清空当前知识库): # 简单处理从会话中移除。实际可添加删除物理文件的逻辑。 st.session_state.vectorstore None st.rerun() else: st.warning(⚠️ 请先上传文档以启用知识库功能)最后也是最关键的一步修改你的对话生成函数。你需要找到原来处理用户输入、调用模型生成回复的函数可能叫generate_response然后根据是否开启RAG模式走不同的逻辑。下面是一个修改思路的示例你需要根据你的实际函数名和参数进行调整# 这是一个新增的函数用于RAG模式下的回答生成 def generate_rag_response(user_input, model, tokenizer, vectorstore): 结合知识库生成回答 if vectorstore is None: return 知识库未加载。, [] # 1. 检索从知识库中找出最相关的3段文本 with st.spinner(正在检索知识库...): relevant_docs vectorstore.similarity_search(user_input, k3) # 2. 组合提示词把问题和检索到的资料拼在一起 context \n\n.join([doc.page_content for doc in relevant_docs]) # 这是一个专门为RAG设计的提示词模板指令模型基于上下文回答 prompt_template 请根据以下提供的参考信息来回答问题。如果信息不足请根据你的知识回答并说明这一点。 参考信息 {context} 问题{question} 请给出回答 from langchain.prompts import PromptTemplate prompt PromptTemplate(templateprompt_template, input_variables[context, question]) final_prompt prompt.format(contextcontext, questionuser_input) # 3. 调用模型生成回答这里复用你原来的模型调用代码 # 注意你需要将 final_prompt 替换掉原来的 user_input 作为模型的输入 # 假设你原来的调用代码是这样的 inputs tokenizer(final_prompt, return_tensorspt).to(model.device) # ... 后续的流式生成代码保持不变 ... # 你需要返回生成的内容和检索到的文档用于显示来源 return generated_text, relevant_docs # 在你的主聊天循环中判断使用哪种模式 if user_input : st.chat_input(请输入问题...): # 显示用户消息 st.chat_message(user).write(user_input) # 准备生成回复 with st.chat_message(assistant): message_placeholder st.empty() full_response # 判断模式 if use_rag and vectorstore in st.session_state and st.session_state.vectorstore: # RAG模式 # 调用新的RAG生成函数 response_text, ref_docs generate_rag_response( user_input, model, tokenizer, st.session_state.vectorstore ) # 显示参考来源可折叠 with st.expander( 查看回答参考的来源, expandedFalse): for i, doc in enumerate(ref_docs): st.caption(f来源片段 {i1}:) # 预览前150个字符 preview doc.page_content[:150] ... if len(doc.page_content) 150 else doc.page_content st.text(preview) # 这里假设你的模型是流式输出我们模拟逐字显示 # 实际情况中你需要将 response_text 以流式方式输出 for chunk in response_text: full_response chunk message_placeholder.markdown(full_response ▌) message_placeholder.markdown(full_response) else: # 原始纯对话模式 # 调用你原来的 generate_response 函数 streamer generate_response(user_input, model, tokenizer) # 这是你原有的函数 for token in streamer: full_response token message_placeholder.markdown(full_response ▌) message_placeholder.markdown(full_response)请注意上面的generate_rag_response函数和主循环中的调用方式是一个逻辑示例。你需要根据你项目中实际的模型调用方式特别是流式输出的部分进行适配和整合。核心思想是在RAG模式下先用vectorstore.similarity_search检索资料然后把资料和问题一起拼成新的提示词再送给模型。6. 运行与体验看看效果如何代码整合好后让我们来实际运行一下看看这个“增强版”的聊天机器人有什么不同。启动应用在终端里运行streamlit run app.py。准备测试文档创建一个简单的test_knowledge.txt文件里面写上几句话比如通义千问是阿里巴巴集团开发的大语言模型。 Qwen3-4B-Instruct-2507是一个专注于纯文本对话的40亿参数模型。 LangChain是一个用于开发大语言模型应用的流行框架。构建知识库在打开的Web界面侧边栏找到新增加的“知识库增强”区域勾选“启用知识库增强模式”然后上传刚才的test_knowledge.txt文件。稍等片刻看到成功提示。开始提问先问一个文档里明确有的问题比如“Qwen3-4B有多少参数”你会看到界面先显示“正在检索知识库...”然后模型会给出回答“根据提供的参考信息Qwen3-4B-Instruct-2507是一个40亿参数的模型。”点击回答下方的“查看回答参考的来源”可以看到模型具体参考了哪段原文。对比模式关掉“启用知识库增强模式”的复选框回到纯聊天模式再问同样的问题。你会发现回答可能变得模糊或者完全是模型自己“想象”的答案与文档内容无关。这个简单的测试能让你立刻感受到RAG的价值它让模型的回答有了“依据”变得可追溯、更可信。7. 让系统更强大进阶技巧与优化基础功能跑通后你可以尝试下面这些方法让你的知识问答系统变得更聪明、更实用。支持更多文档格式rag_core.py里的load_documents函数目前只处理了TXT和PDF。你可以很容易地扩展它。比如想支持Markdown文件可以安装pip install markdown然后使用UnstructuredMarkdownLoader。LangChain社区提供了几十种文档加载器。调整文本分割策略chunk_size块大小和chunk_overlap重叠大小直接影响检索质量。对于技术文档块可以小点300-500字保证精准对于连贯的文章块可以大点800-1000字。重叠部分能防止一个句子被拦腰截断。尝试不同的嵌入模型我们用的paraphrase-multilingual-MiniLM-L12-v2是一个在速度和效果间平衡的通用模型。如果你主要处理中文可以换成BAAI/bge-large-zh-v1.5它在中文语义搜索任务上表现更优。添加多轮对话记忆现在的RAG是“一问一答”每次都是独立检索。你可以集成LangChain的ConversationBufferMemory让系统在连续对话中记住之前问过的问题和检索到的上下文实现更深入的、连贯的问答。设置检索分数阈值有时候用户问的问题知识库里根本没有。你可以检查similarity_search_with_score返回的分数如果最高分低于某个阈值比如0.7就直接告诉用户“知识库里没有找到相关信息”并让模型尝试用自己的知识回答避免胡编乱造。8. 总结通过以上步骤我们成功地为原本只能泛泛而谈的Qwen3-4B对话模型接上了一个强大的“外部大脑”。我们来回顾一下核心收获理解了RAG的价值它通过“检索生成”的模式将大语言模型的通用对话能力与精准的领域知识相结合解决了模型“幻觉”和知识陈旧的问题。搭建了核心流水线利用LangChain和Chroma我们构建了从文档处理、向量化存储到语义检索的完整链路这个过程像搭积木一样清晰。实现了无缝界面集成在原有的、用户体验良好的Streamlit对话界面中我们仅通过侧边栏和模式判断就优雅地融入了RAG功能用户切换毫无障碍。获得了可验证的结果系统能够展示答案的来源片段这不仅增加了可信度也让你能直观地理解模型是如何思考的。现在你的这个应用不再只是一个聊天玩具了。你可以把它变成个人知识管家上传你的学习笔记、读书摘要随时问答。团队文档助手导入项目文档、产品说明书新同事也能快速查询。专业领域顾问喂给它法律条文、医疗指南、金融报告它就能提供基于具体条款的分析。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。