简易RAG项目 📅 发布时间:2026/7/12 2:09:59 👁️ 浏览次数: 1.文本上传web服务基于steamlit完成web网页上传服务Streamlit用 Python 写网页应用的工具。基于steamlit完成web网页上传服务 from distutils.command.upload import upload import streamlit as st st.title(知识库更新服务) upload_file st.file_uploader( 请上传文件TXT文件, type[txt], accept_multiple_filesFalse, ) if upload_file is not None: file_nameupload_file.name file_typeupload_file.type file_sizeupload_file.size/1024 st.subhead(f文件名{file_name}) st.write(f格式{file_type} | 大小{file_size}) text upload_file.getvalue().decode(utf-8) st.write(text)上面是生成上传文件的web页面的代码进入该网页的步骤为1.cmd,进入项目所在的盘d:/c:2.cd进入网页代码这个文件佳路径cd 路径3.streamlit run 网页这个py代码2.RAG知识库构建1创建向量数据库目录→创建 Chroma 向量数据库参数一collection_name表明参数二persist_directory数据库存储位置参数三embedding_function文本转换为向量2创建文本分割器使用self.spliter RecursiveCharacterTextSplitter LangChain 的文本分割工具)参数一chunk_size每个文本块最大长度 参数二chunk_overlap文本块之间的重叠参数三separators文本分割优先级 参数四length_function统计文本分割长度3文本上传函数文本上传函数。生成 MD5检查是否存在。4若不存在则判断文本长度太长则切分较短则直接存入。5构建 metadata构建mededata,向量的附加信息。3.连接文件上传和知识库构建1在 Streamlit 会话中创建并保存一个 knowledgeBaseService 实例避免每次页面重新运行时重复初始化。if service not in st.session_state: st.session_state[service]knowledgeBaseService()2对上传的文件调用RAG数据库构建部分的文件对文件内容进行转化、判断、存储。if upload_file is not None: file_nameupload_file.name file_typeupload_file.type file_sizeupload_file.size/1024 st.subheader(f文件名{file_name}) st.write(f格式{file_type} | 大小{file_size}) with st.spinner(载入中): time.sleep(1) text upload_file.getvalue().decode(utf-8) result st.session_state[service].upload_by_str(text,file_name)# 这里 st.success(result)4.加载 Chroma 向量数据库并提供一个基于 embedding 相似度的文本检索接口。当系统需要进行知识检索时它负责加载本地已经保存好的 Chroma 向量数据库并生成一个检索器retriever用于根据用户问题找到最相似的文本内容。class VectorStoreService(object): def __init__(self,embedding): self.embeddingembedding self.vector_storeChroma( #加载向量数据库 collection_nameconfig.collection_name, embedding_functionself.embedding, persist_directoryconfig.persist_directory ) def get_retriever(self): #提供检索器 return self.vector_store.as_retriever(search_kwargs{k:config.similarity_threshold})5.构建链→检索器、提示词、聊天模型链rag开发核心代码部分class RagService(object): def __init__(self): self.vector_service VectorStoreService( #获取检索器 embeddingconfig.embedding ) self.prompt_template ChatPromptTemplate.from_messages( #构建提示词 [ (system,以我提供的已知参考资料为主 简洁和专业的回答用户问题参考资料{context}。), (user,请回答用户提问{input}) ] ) self.chat_model config.chat_model_name #获取聊天模型 self.chain self.__get_chain() #构建链 def __get_chain(self): retriever self.vector_service.get_retriever() #输出是list套ducument def format_document(docs:list[Document]): if not docs: return 无相关资料 formatted_str for doc in docs: formatted_str f文档片段{doc.page_content}\n文档元数据{doc.metadata}\n\n #多个字符串拼接为1个 return formatted_str chain ( { input:RunnablePassthrough(), context:retriever|format_document }|self.prompt_template|self.chat_model|StrOutputParser() ) return chain6.保存长期历史会话记录1根据 session_id会话ID 返回一个聊天历史对象不同用户 / 不同会话→ 对应不同文件def get_history(session_id): return FileChatMessageHistory(session_id,./chat_history)2)自定义聊天历史类class FileChatMessageHistory(BaseChatMessageHistory)只要实现三个方法a加载已有的聊天记录将新的和旧的融合。存储聊天记录时需为字符串形式因为文件存储时必须使用 JSON 可序列化的数据通常是字典/字符串而 LangChain 在进行对话推理时需要的是 BaseMessage 对象。def add_messages(self,messages:Sequence[BaseMessage]) - None: all_messageslist(self.messages) #已有的消息列表 all_messages.extend(messages) #新的和已有的融合成一个list new_messages [] for messages in all_messages: d message_to_dict(messages) #将对话的basemessage格式转换为字典 new_messages.append(d) with open(self.file_path,w,encodingutf-8) as f : json.dump(new_messages,f)b从文件读取历史消息LLM 推理必须使用 Message 对象。这是在第1步读取聊天记录后在通过这个方法转会为message格式模型通过这些进行推理。def messages(self) -list[BaseMessage]: try: with open(self.file_path,r,encodingutf-8)as f: message_data json.load(f) return messages_from_dict(message_data) except FileNotFoundError: return []c通过clear清空聊天记录3把聊天记录通过MessagesPlaceholder(history),插入到会话中让会话具有上下文信息。这里注意插入历史记录后链的输入可能会发生变化。要注意input和每个链的输入比如 #retriever要求输入的是字符串。7.聊天页面开发import time import streamlit as st from streamlit import spinner from rag import RagService import config_data as config #设置一个标题 st.title(智能客服) st.divider() #在 Streamlit 应用中保存用户会话状态让变量在页面重新运行时不会丢失。 if message not in st.session_state: st.session_state[message] [{role:assistant,content:您好请问有什么可以帮您}] if rag not in st.session_state: st.session_state[rag] RagService() for message in st.session_state[message]: st.chat_message(message[role]).write(message[content]) prompt st.chat_input() if prompt: st.chat_message(user).write(prompt) st.session_state[message].append({role:user,content:prompt}) ai_res_list [] with st.spinner(思考中...): #time.sleep(1) def capture(generator,cache_list): #stream的流式输出无法存储在历史中必须转换为字符串 for chunk in generator: cache_list.append(chunk) yield chunk res_stream st.session_state[rag].chain.stream({input:prompt},config.session_config) st.chat_message(assistant).write_stream(capture(res_stream,ai_res_list)) st.session_state[message].append({role: assistant, content:.join(ai_res_list)})
光活化标记试剂 Photobiotin acetate salt,96087-38-6 试剂基本信息中文名称:光敏生物素乙酸盐英文名称:Photobiotin acetate saltCAS号:96087-38-6分子式:C25H39N9O6S分子量:593.70性状:粉末纯度:95%规格:5mg,10mg供应厂家&a… 2026/3/18 16:31:55
学Simulink——基于Simulink的光伏/储能前端三相PWM整流并网控制 目录 手把手教你学Simulink ——基于Simulink的光伏/储能前端三相PWM整流并网控制 一、问题背景 二、系统拓扑与数学模型 1. 主电路结构 2. 并网变流器状态方程(dq 坐标系) 三、分层控制架构设计 1. 外环控制策略 (1)直流母线电压控制(主模式) (2)无功功率控制… 2026/4/26 13:55:14
JDK25新特性 JJDK 25 作为 Java 的下一个长期支持版本(LTS),计划于 2025 年 9 月16日正式发布。该版本聚焦语言表达力提升、性能优化、并发模型革新及安全增强,是继 JDK 21 后的首个 LTS 版本。共18个JEP。 font style"color:rgb(77, 77… 2026/3/18 16:27:40
Linux DeviceMapper框架解析:从原理到实战的存储管理核心 那天下午,我在排查一个存储性能问题时,在服务器上敲下lsblk命令,看到一列/dev/dm-0、/dev/dm-1的设备名。这些设备不像普通的/dev/sda那样直接对应物理磁盘,而是像一层“中间商”,在物理设备和文件系统之间架起了一座桥… 2026/7/12 2:08:05
碧蓝幻想Relink DPS统计工具GBFR-Logs:从新手到专家的完整实战指南 碧蓝幻想Relink DPS统计工具GBFR-Logs:从新手到专家的完整实战指南 【免费下载链接】gbfr-logs GBFR Logs lets you track damage statistics with a nice overlay DPS meter for Granblue Fantasy: Relink. 项目地址: https://gitcode.com/gh_mirrors/gb/gbfr-lo… 2026/7/12 2:04:04
终极RTL8852BE Wi-Fi 6驱动完全指南:从内核兼容到性能优化 终极RTL8852BE Wi-Fi 6驱动完全指南:从内核兼容到性能优化 【免费下载链接】rtl8852be Realtek Linux WLAN Driver for RTL8852BE 项目地址: https://gitcode.com/gh_mirrors/rt/rtl8852be RTL8852BE是一款支持Wi-Fi 6标准的Realtek无线网卡芯片,… 2026/7/12 2:04:04
从电影叙事到技术实践:人性洞察与情感计算的应用 一口气看完4K画质神作《迷失安狄》:中年安狄勇敢活出女性身份,受尽排挤,偶遇流离母子相互取暖,中巨额彩票本盼新生,人性残酷背叛将他推入深渊。这部由李李仁主演的电影《迷失安狄》在2020年上映后引发了广泛讨论。影片… 2026/7/12 2:04:04
Gemini移动端安装指南:安卓iOS双平台实操全解析 1. 项目概述:Gemini 移动端使用,不是玄学,是标准产品操作流程很多人一看到“谷歌Gemini App”几个字,脑子里立刻浮现出一堆问号:国内手机能装吗?要翻墙吗?得买海外手机号注册吗?是不… 2026/7/12 1:56:02
1987年5月12日中午11-13点出生性格、运势和命运 在占星学说与命理学的奇妙世界里,我们常常会试图依据出生的具体时间去探寻一个人的性格特质、运势走向以及命运脉络。1987年5月12日中午11 - 13点出生的人,出生于丁卯兔年乙巳月辛酉日甲午时。从八字来看,辛金生于巳月,得令而身强… 2026/7/12 1:56:02
Git reset 与 revert 深度对比:5个关键差异与 3 种典型应用场景 Git Reset 与 Revert 深度对比:5个关键差异与3种典型应用场景在团队协作开发中,代码版本管理如同行走钢丝——一步失误可能导致整个项目陷入混乱。作为Git进阶用户,你是否曾在深夜面对错误的提交束手无策?是否在强制推送后收到同事… 2026/7/12 0:01:13
GitHub 学生包申请避坑:5个常见失败原因与开发者工具调试方案 GitHub 学生包申请技术排障指南:5个高频失败场景与开发者工具实战方案第一次尝试申请GitHub学生包时,我盯着屏幕上那个不断转圈的加载动画整整15分钟,最终只等来了一行冰冷的错误提示。这可能是许多开发者共同的经历——明明按照教程操作&… 2026/7/12 0:01:13
冒烟测试用例设计规范:5%-10%覆盖率下的3类核心场景与执行标准 冒烟测试用例设计的黄金法则:5%-10%覆盖率下的精准筛选策略在快节奏的敏捷开发环境中,冒烟测试作为质量保障的第一道防线,其重要性不言而喻。当测试资源有限而时间紧迫时,如何从海量测试用例中精准筛选出那关键的5%-10%࿰… 2026/7/12 0:03:14
Git reset 与 revert 深度对比:5个关键差异与 3 种典型应用场景 Git Reset 与 Revert 深度对比:5个关键差异与3种典型应用场景在团队协作开发中,代码版本管理如同行走钢丝——一步失误可能导致整个项目陷入混乱。作为Git进阶用户,你是否曾在深夜面对错误的提交束手无策?是否在强制推送后收到同事… 2026/7/12 0:01:13
GitHub 学生包申请避坑:5个常见失败原因与开发者工具调试方案 GitHub 学生包申请技术排障指南:5个高频失败场景与开发者工具实战方案第一次尝试申请GitHub学生包时,我盯着屏幕上那个不断转圈的加载动画整整15分钟,最终只等来了一行冰冷的错误提示。这可能是许多开发者共同的经历——明明按照教程操作&… 2026/7/12 0:01:13
冒烟测试用例设计规范:5%-10%覆盖率下的3类核心场景与执行标准 冒烟测试用例设计的黄金法则:5%-10%覆盖率下的精准筛选策略在快节奏的敏捷开发环境中,冒烟测试作为质量保障的第一道防线,其重要性不言而喻。当测试资源有限而时间紧迫时,如何从海量测试用例中精准筛选出那关键的5%-10%࿰… 2026/7/12 0:03:14