计算机视觉数据标注终极指南:CVAT完全解析与实战应用
2026/6/9 23:41:56
在信息检索与智能问答场景中,大语言模型(LLM)常面临“知识时效性不足”“无法结合私有数据”等问题。检索增强生成(RAG)技术通过将“向量数据库检索私有数据”与“LLM生成回答”相结合,既能利用LLM的语言理解能力,又能让回答基于指定的私有数据(如本地文档),有效解决上述问题。
本代码基于LangChain框架,整合智谱GLM大模型、智谱免费Embedding模型与LanceDB向量数据库,实现了一个本地RAG问答系统:从本地文本文件中提取信息,通过向量数据库检索与用户问题相关的内容,最终由GLM大模型基于检索结果生成精准回答。
常见向量数据库介绍
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[生成并输出回答]代码块:
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向量数据库;TextLoader用于读取本地文本文件;LanceDB用于将文本向量与LanceDB集成;ChatPromptTemplate定义LLM的输入格式;RunnableParallel(并行处理)、RunnablePassthrough(透传参数)用于构建检索-生成流水线;StrOutputParser将LLM的输出转换为字符串;RecursiveCharacterTextSplitter用于分割长文本;ZhipuAIEmbeddings(智谱Embedding模型)、ChatOpenAI(适配智谱GLM大模型的调用类)。代码块:
# 读取本地文本文件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:按“段落分隔符→换行→标点符号”的优先级分割,确保分割后的文本块语义完整;代码块:
# 从环境变量读取智谱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请求地址)功能说明:
os.getenv从系统环境变量中读取Zhipu_API_KEY,避免将密钥硬编码在代码中,提升安全性;model="embedding-3":智谱提供的免费Embedding模型,支持文本向量化,适合中小型RAG场景;base_url:智谱API的固定请求地址,确保能正常调用Embedding服务;代码块:
# 连接本地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表中;代码块:
# 初始化向量数据库检索器(用于后续检索相关文本块)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对象,后续可直接通过该对象检索与问题相关的文本块;context(上下文)生成回答,避免模型编造信息(幻觉);代码块:
# 初始化智谱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功能说明:
ChatOpenAI类适配智谱GLM模型(LangChain兼容OpenAI API格式,智谱GLM支持该格式),指定模型版本、API密钥和请求地址;RunnableParallel:并行处理两个任务:①调用retriever检索上下文;②透传用户输入的question(问题),最终输出一个包含context和question的字典;|:将多个组件按顺序串联,数据从左到右传递:start_retriever:输出{context: 检索到的文本块, question: 用户问题};prompt:将上述字典代入模板,生成LLM的输入文本;model:GLM模型基于输入文本生成回答;output_parser:将模型输出的结构化数据转换为字符串。代码块:
# 用户查询问题query='今年长三角铁路春游运输共经历多少天?'# 执行RAG流水线,生成回答res=chain.invoke(query)# 输出结果print(res)功能说明:
chain.invoke(query):触发RAG流水线执行,传入用户问题query,自动完成“检索→提示词拼接→生成→解析”全流程;test.txt文件的文本内容;my_vectors表中;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)test.txt中存在“今年长三角铁路春游运输自3月10日启动,至4月10日结束,共计32天”)======= 分割后的文本块数量: 8 ======= 回答结果: 今年长三角铁路春游运输共经历32天。======= 分割后的文本块数量: 8 ======= 回答结果: 未查询到相关信息# 典型错误输出(示例) AuthenticationError: Invalid API key. Please check your API key and try again.(解决方案:检查环境变量Zhipu_API_KEY是否正确配置,确保网络能访问智谱API地址)