昌江黎族自治县网站建设_网站建设公司_搜索功能_seo优化
2025/12/22 20:04:32 网站建设 项目流程

一、任务背景

在信息检索与智能问答场景中,大语言模型(LLM)常面临“知识时效性不足”“无法结合私有数据”等问题。检索增强生成(RAG)技术通过将“向量数据库检索私有数据”与“LLM生成回答”相结合,既能利用LLM的语言理解能力,又能让回答基于指定的私有数据(如本地文档),有效解决上述问题。

本代码基于LangChain框架,整合智谱GLM大模型、智谱免费Embedding模型与LanceDB向量数据库,实现了一个本地RAG问答系统:从本地文本文件中提取信息,通过向量数据库检索与用户问题相关的内容,最终由GLM大模型基于检索结果生成精准回答。

常见向量数据库介绍

  1. Chroma
    特点:开源的向量数据库,支持本地和云环境部署
    优势:灵活的部署选项使其既可以在本地运行也可以在云端运行
    适用场景:适用于那些希望保持数据本地化但又不想牺牲云灵活性的项目
  2. FAISS
    特点:Facebook 开发的一个高效相似度搜索库
    优势:特别适合处理大规模的数据集
    适用场景:当处理大量文本数据时,FAISS 是一个不错的选择
  3. Qdrant
    特点:开源的向量数据库,支持云托管
    优势:提供了便捷的云托管服务,简化了运维工作
    适用场景:对于那些希望专注于核心业务逻辑而不是基础设施管理的开发者来说非常适合
  4. Pinecone
    特点:提供托管服务的向量数据库
    优势:高性能且易于使用,无需担心后端的维护工作
    适用场景:适用于那些需要快速上线且不想花费太多时间在数据库配置上的项目
  5. Milvus
    特点:开源的向量数据库,支持多种向量类型
    优势:除了文本向量外,还可以存储其他类型的向量数据
    适用场景:当项目涉及到多种类型的向量数据时,Milvus 是一个很好的选择
  6. LanceDB
    特点:开源的知识图谱和向量数据库
    优势:支持多种数据类型,可以构建复杂的关系图谱
    适用场景:适用于需要存储和检索具有复杂关系的数据集

二、核心任务逻辑

  1. 数据预处理:读取本地文本文件,按指定规则分割为小块文本(chunk),确保文本长度适配Embedding模型和LLM的输入限制;
  2. 向量存储:使用智谱免费Embedding模型将分割后的文本块转换为向量,存储到LanceDB本地向量数据库中,建立文本与向量的映射;
  3. 检索匹配:用户输入问题后,将问题转换为向量,在LanceDB中检索与该向量最相似的文本块(即相关上下文);
  4. 生成回答:将检索到的相关上下文与用户问题一起传入GLM大模型,由模型基于上下文信息生成回答,确保回答仅依赖检索到的私有数据。

三、RAG执行流程总览

graph TD A[本地文本文件 test.txt] --> B[TextLoader读取文件] B --> C[RecursiveCharacterTextSplitter分割文本块] C --> D[智谱Embedding-3模型生成文本向量] D --> E[LanceDB向量数据库存储向量+文本] F[用户输入问题] --> G[Embedding模型生成问题向量] G --> H[LanceDB检索相似文本块(上下文)] H --> I[将上下文+问题传入GLM-4模型] I --> J[生成并输出回答]

四、代码分块详解

1. 依赖库导入

代码块

importosimportlancedbfromlangchain_community.document_loadersimportTextLoaderfromlangchain_community.vectorstoresimportLanceDBfromlangchain_core.output_parsersimportStrOutputParserfromlangchain_core.promptsimportChatPromptTemplatefromlangchain_core.runnablesimportRunnableParallel,RunnablePassthroughfromlangchain_openaiimportChatOpenAIfromlangchain_text_splittersimportRecursiveCharacterTextSplitter# 关键:导入智谱GLM的Embedding类(无需额外安装依赖)fromlangchain_community.embeddingsimportZhipuAIEmbeddings

功能说明

  • 基础库:os用于环境变量读取和路径处理,lancedb用于连接LanceDB向量数据库;
  • LangChain核心组件:
    • 文档加载:TextLoader用于读取本地文本文件;
    • 向量存储:LanceDB用于将文本向量与LanceDB集成;
    • 提示词模板:ChatPromptTemplate定义LLM的输入格式;
    • 流水线组件:RunnableParallel(并行处理)、RunnablePassthrough(透传参数)用于构建检索-生成流水线;
    • 输出解析:StrOutputParser将LLM的输出转换为字符串;
    • 文本分割:RecursiveCharacterTextSplitter用于分割长文本;
  • 智谱相关:ZhipuAIEmbeddings(智谱Embedding模型)、ChatOpenAI(适配智谱GLM大模型的调用类)。

2. 本地文本读取与分割

代码块

# 读取本地文本文件loader=TextLoader(r'F:\python测试\智谱-langchain\测试数据\test.txt',encoding='utf8')documents=loader.load()# 文本分割配置text_splitter=RecursiveCharacterTextSplitter(chunk_size=200,# 每个文本块的最大长度(字符数)chunk_overlap=100,# 相邻文本块的重叠长度(确保上下文连贯性)length_function=len,# 长度计算方式(默认按字符数)is_separator_regex=False,# 不使用正则表达式解析分隔符separators=[# 文本分割的分隔符(按优先级排序)"\n\n","\n",".","?","!","。","!","?",",",","," "])# 执行文本分割并输出分割后的文本块数量docs=text_splitter.split_documents(documents)print('=======',len(docs))

功能说明

  • 文本读取:通过TextLoader指定本地文本文件路径和编码(utf8),读取文件内容为LangChain的Document对象;
  • 文本分割核心逻辑:
    • chunk_size=200:限制每个文本块最大200个字符,避免文本过长超出Embedding模型和LLM的输入限制;
    • chunk_overlap=100:相邻文本块重叠100个字符,防止因分割导致上下文断裂(如一句话被拆分到两个块中);
    • separators:按“段落分隔符→换行→标点符号”的优先级分割,确保分割后的文本块语义完整;
  • 输出分割后的文本块数量,用于验证分割效果(如输入文本1000字符,约生成6-7个文本块)。

3. 智谱Embedding模型初始化

代码块

# 从环境变量读取智谱API密钥(推荐方式,避免硬编码)api_key=os.getenv('Zhipu_API_KEY')# 初始化智谱免费Embedding模型embeddings=ZhipuAIEmbeddings(model="embedding-3",# 智谱免费Embedding模型(核心参数,无需付费)api_key=api_key,# 智谱API密钥(与GLM大模型通用)base_url="https://open.bigmodel.cn/api/paas/v4/"# 智谱API请求地址)

功能说明

  • API密钥读取:通过os.getenv从系统环境变量中读取Zhipu_API_KEY,避免将密钥硬编码在代码中,提升安全性;
  • Embedding模型核心参数:
    • model="embedding-3":智谱提供的免费Embedding模型,支持文本向量化,适合中小型RAG场景;
    • base_url:智谱API的固定请求地址,确保能正常调用Embedding服务;
  • 作用:将文本块转换为计算机可理解的向量(Embedding),用于后续向量数据库的检索匹配。

4. LanceDB向量数据库连接与向量存储

代码块

# 连接本地LanceDB向量数据库(存储路径为当前工作目录下的lanceDB文件夹)connect=lancedb.connect(os.path.join(os.getcwd(),'lanceDB'))# 将文本块转换为向量并存储到LanceDB中vectorStore=LanceDB.from_documents(docs,# 分割后的文本块列表embeddings,# 初始化后的智谱Embedding模型connection=connect,# LanceDB连接对象table_name='my_vectors'# 向量表名(自定义,可修改))

功能说明

  • 向量数据库连接:lancedb.connect指定本地存储路径(当前工作目录下的lanceDB文件夹),LanceDB会自动创建该目录并初始化数据库;
  • 向量存储核心逻辑:
    • from_documents:LangChain的封装方法,自动遍历所有文本块,调用Embedding模型生成向量,同时存储“向量+文本块内容+元数据”到LanceDB的my_vectors表中;
    • 优势:LanceDB是轻量级本地向量数据库,无需额外部署服务,适合快速验证RAG原型。

5. 检索器初始化与提示词模板定义

代码块

# 初始化向量数据库检索器(用于后续检索相关文本块)retriever=vectorStore.as_retriever()# 定义LLM的输入提示词模板template="""Answer the question based only on the following context: {context} If the context has no relevant information, reply "未查询到相关信息". Question: {question} """prompt=ChatPromptTemplate.from_template(template)

功能说明

  • 检索器初始化:vectorStore.as_retriever()将LanceDB向量数据库包装为LangChain的Retriever对象,后续可直接通过该对象检索与问题相关的文本块;
  • 提示词模板核心作用:
    • 限制LLM仅基于检索到的context(上下文)生成回答,避免模型编造信息(幻觉);
    • 定义兜底逻辑:若上下文无相关信息,直接回复“未查询到相关信息”,提升回答的规范性。

6. GLM大模型初始化与流水线构建

代码块

# 初始化智谱GLM大模型model=ChatOpenAI(model='glm-4-0520',# GLM-4模型版本(可替换为glm-3-turbo等)api_key=api_key,# 复用智谱API密钥base_url='https://open.bigmodel.cn/api/paas/v4/'# 智谱API请求地址)# 初始化输出解析器(将LLM的输出转换为字符串)output_parser=StrOutputParser()# 构建RAG流水线:检索上下文 → 拼接提示词 → LLM生成 → 解析输出start_retriever=RunnableParallel({'context':retriever,'question':RunnablePassthrough()})chain=start_retriever|prompt|model|output_parser

功能说明

  • GLM大模型初始化:通过ChatOpenAI类适配智谱GLM模型(LangChain兼容OpenAI API格式,智谱GLM支持该格式),指定模型版本、API密钥和请求地址;
  • 流水线核心逻辑:
    • RunnableParallel:并行处理两个任务:①调用retriever检索上下文;②透传用户输入的question(问题),最终输出一个包含contextquestion的字典;
    • 流水线运算符|:将多个组件按顺序串联,数据从左到右传递:
      1. start_retriever:输出{context: 检索到的文本块, question: 用户问题}
      2. prompt:将上述字典代入模板,生成LLM的输入文本;
      3. model:GLM模型基于输入文本生成回答;
      4. output_parser:将模型输出的结构化数据转换为字符串。

7. 执行问答与输出结果

代码块

# 用户查询问题query='今年长三角铁路春游运输共经历多少天?'# 执行RAG流水线,生成回答res=chain.invoke(query)# 输出结果print(res)

功能说明

  • chain.invoke(query):触发RAG流水线执行,传入用户问题query,自动完成“检索→提示词拼接→生成→解析”全流程;
  • 输出:打印LLM生成的最终回答,回答仅基于本地文本文件中的信息。

五、代码逻辑文字流程总结

  1. 读取本地test.txt文件的文本内容;
  2. 按“最大200字符、重叠100字符”的规则,用标点/换行符分割文本为多个语义完整的小块;
  3. 调用智谱免费Embedding-3模型,将所有文本块转换为向量;
  4. 把“向量+文本块”存储到本地LanceDB向量数据库的my_vectors表中;
  5. 用户输入问题后,将问题转换为向量,在LanceDB中检索最相似的文本块(上下文);
  6. 把“上下文+问题”按指定模板拼接为LLM输入;
  7. 调用GLM-4模型基于输入生成回答,若上下文无相关信息则回复兜底内容;
  8. 输出最终的字符串格式回答。

六、完整代码

importosimportlancedbfromlangchain_community.document_loadersimportTextLoaderfromlangchain_community.vectorstoresimportLanceDBfromlangchain_core.output_parsersimportStrOutputParserfromlangchain_core.promptsimportChatPromptTemplatefromlangchain_core.runnablesimportRunnableParallel,RunnablePassthroughfromlangchain_openaiimportChatOpenAIfromlangchain_text_splittersimportRecursiveCharacterTextSplitter# 关键:导入智谱GLM的Embedding类(无需额外安装依赖)fromlangchain_community.embeddingsimportZhipuAIEmbeddings# 1. 读取本地文本文件loader=TextLoader(r'F:\python测试\智谱-langchain\测试数据\test.txt',encoding='utf8')documents=loader.load()# 2. 文本分割配置text_splitter=RecursiveCharacterTextSplitter(chunk_size=200,chunk_overlap=100,length_function=len,is_separator_regex=False,separators=["\n\n","\n",".","?","!","。","!","?",",",","," "])# 3. 读取智谱API密钥并执行文本分割api_key=os.getenv('Zhipu_API_KEY')docs=text_splitter.split_documents(documents)print('======= 分割后的文本块数量:',len(docs))# 4. 初始化智谱免费Embedding模型embeddings=ZhipuAIEmbeddings(model="embedding-3",# 智谱免费Embedding模型(核心参数)api_key=api_key,# 复用GLM大模型的API Keybase_url="https://open.bigmodel.cn/api/paas/v4/"# 复用智谱API地址)# 5. 连接LanceDB并存储向量connect=lancedb.connect(os.path.join(os.getcwd(),'lanceDB'))# 本地目录存储向量vectorStore=LanceDB.from_documents(docs,embeddings,connection=connect,table_name='my_vectors')# 6. 定义用户查询与检索器query='今年长三角铁路春游运输共经历多少天?'retriever=vectorStore.as_retriever()# 7. 定义提示词模板template="""Answer the question based only on the following context: {context} If the context has no relevant information, reply "未查询到相关信息". Question: {question} """prompt=ChatPromptTemplate.from_template(template)# 8. 初始化GLM大模型model=ChatOpenAI(model='glm-4-0520',api_key=api_key,base_url='https://open.bigmodel.cn/api/paas/v4/')# 9. 构建并执行RAG流水线output_parser=StrOutputParser()start_retriever=RunnableParallel({'context':retriever,'question':RunnablePassthrough()})chain=start_retriever|prompt|model|output_parser res=chain.invoke(query)print('\n======= 回答结果:')print(res)

七、可能的输出结果

情况1:本地文本包含相关信息(如test.txt中存在“今年长三角铁路春游运输自3月10日启动,至4月10日结束,共计32天”)

======= 分割后的文本块数量: 8 ======= 回答结果: 今年长三角铁路春游运输共经历32天。

情况2:本地文本无相关信息

======= 分割后的文本块数量: 8 ======= 回答结果: 未查询到相关信息

情况3:API密钥错误或网络异常

# 典型错误输出(示例) AuthenticationError: Invalid API key. Please check your API key and try again.

(解决方案:检查环境变量Zhipu_API_KEY是否正确配置,确保网络能访问智谱API地址)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询