【wow-rag系列】 task05 Ollama+llamaIndex+流式部署页面

文章目录

  • 1.构建问答引擎
  • 2.构建基于FastAPI的后台
  • 3.构建流式输出的前端

1.构建问答引擎

新建一个engine.py文件

import os
from llama_index.core.node_parser import SentenceSplitter# ---------------------
# step 1.设定key、模型url、推理模型名称以及embedding模型名称
# ---------------------
BASE_IP = "http://localhost:11434"
BASE_URL = BASE_IP + "/api/chat"
MODEL_NAME = "deepseek-r1"# ---------------------
# step 2.设置本地embedding模型与本地大模型
# ---------------------
from llama_index.embeddings.ollama import OllamaEmbeddingembedding = OllamaEmbedding(base_url=BASE_IP, model_name=MODEL_NAME)
from llama_index.llms.ollama import Ollamallm = Ollama(base_url=BASE_IP, model=MODEL_NAME,mperature=0.3,  # 降低随机性system_prompt="你是一个严谨的中文问答助手,严格根据上下文信息回答问题")# 配置全局设置
from llama_index.core import Settings, PromptTemplateSettings.embed_model = embedding
Settings.llm = llm
Settings.node_parser = SentenceSplitter(chunk_size=512)  # 添加文本分块from llama_index.core import VectorStoreIndex, StorageContext, Settings
from llama_index.vector_stores.qdrant import QdrantVectorStore
from llama_index.core import SimpleDirectoryReader
import qdrant_client# load documents
documents = SimpleDirectoryReader(input_files=['./docs/雪山飞狐.txt'],file_metadata=lambda x: {"source": os.path.basename(x)}).load_data()
print('1.SimpleDirectoryReader载入document finish!')
# 连接Qdrant,并保存在本地的qdrant文件夹中
QDRANT_PATH = "./qdrant_storage"  # 修改存储路径避免权限问题qclient = qdrant_client.QdrantClient(path=QDRANT_PATH)
vector_store = QdrantVectorStore(client=qclient, collection_name="wenda",#     enable_hybrid=True  # 启用混合搜索)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
# 创建索引(自动分块+嵌入)
index = VectorStoreIndex.from_documents(documents,storage_context=storage_context,transformations=[Settings.node_parser],  # 应用分块show_progress=True
)
print('2.连接Qdrant,并保存在本地的qdrant文件夹中 finish!')
# 构建检索器
from llama_index.core.retrievers import VectorIndexRetriever# 想要自定义参数,可以构造参数字典
emb = embedding.get_text_embedding("你好呀呀")
dimensions = len(emb)
kwargs = {'similarity_top_k': 8, 'index': index, 'dimensions': dimensions,# 'vector_store_query_mode':"hybrid",  # 混合搜索模式'alpha': 0.5  # 平衡关键词与语义搜索}  # 必要参数
retriever = VectorIndexRetriever(**kwargs)
print('3.构建检索器 finish!')
# 构建合成器
from llama_index.core.response_synthesizers import get_response_synthesizer, ResponseModeqa_prompt_tmpl = ("根据以下上下文信息:\n""---------------------\n""{context_str}\n""---------------------\n""使用{language_name}回答以下问题\n ""问题: {query_str}\n""答案: "
)
qa_prompt = PromptTemplate(qa_prompt_tmpl)
response_synthesizer = get_response_synthesizer(llm=llm, streaming=True,response_mode=ResponseMode.TREE_SUMMARIZE,summary_template=qa_prompt)print('4.构建合成器 finish!')
# 构建问答引擎
from llama_index.core.query_engine import RetrieverQueryEnginequery_engine = RetrieverQueryEngine(retriever=retriever,response_synthesizer=response_synthesizer,
)
print('5.构建问答引擎 finish!')

2.构建基于FastAPI的后台

新建一个main.py文件

import uvicorn # 导入ASGI服务器Uvicorn,用于运行FastAPI应用‌
from fastapi import FastAPI # 导入FastAPI核心类,用于创建Web应用实例‌
from fastapi.middleware.cors import CORSMiddleware # 导入CORS中间件,处理跨域请求‌
from fastapi.responses import StreamingResponse # 导入流式响应类,支持实时数据流传输‌
from engine import query_engine # 从自定义模块导入预构建的查询引擎(已实现流式生成功能)
# 创建FastAPI应用实例,作为Web服务的核心对象‌
app = FastAPI()
# 配置CORS中间件,允许所有来源(*)的跨域请求(适用于开发环境,生产环境需限制域名)
app.add_middleware(CORSMiddleware,allow_origins=["*"])# 定义GET请求路由,端点路径为/stream_chat
@app.get('/stream_chat')
async def stream_chat(param:str = "你好"): # 接收名为param的查询参数,默认值"你好"# 调用查询引擎处理参数response_stream = query_engine.query(param)def generate():"""定义生成器函数,用于逐块产生响应内容‌"""for text in response_stream.response_gen: # 遍历流式生成器的输出yield text # 逐次返回文本片段,实现增量传输# 创建流式响应对象,指定媒体类型为text/event-stream(SSE协议)‌return StreamingResponse(generate(), media_type='text/event-stream')if __name__ == '__main__':# 直接运行Uvicorn服务器,绑定所有网络接口(0.0.0.0),端口5000uvicorn.run(app, host='0.0.0.0', port=5000)

然后python main.py。运行如下所示
在这里插入图片描述

3.构建流式输出的前端

新建一个chat.html

<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"/><!-- 1. viewport确保移动端自适应布局 --><meta name="viewport" content="width=device-width, initial-scale=1.0"/><!-- 2. 外部资源引入 --><link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet"/><link href="https://ai-public.mastergo.com/gen_page/tailwind-custom.css" rel="stylesheet"/> <!-- 定制化Tailwind CSS样式 --><!-- 3. 动画样式定义 --><style id="animation-styles"><!-- 定义渐变背景动画gradient,用于主界面背景的流动效果 -->@keyframes gradient {0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }</style><link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin=""/><link href="https://fonts.googleapis.com/css2?family=Pacifico&display=swap" rel="stylesheet"/><script src="https://cdn.tailwindcss.com/3.4.5?plugins=forms@0.5.7,typography@0.5.13,aspect-ratio@0.4.2,container-queries@0.1.1"></script><script src="https://ai-public.mastergo.com/gen_page/tailwind-config.min.js" data-color="#AC1BF5" data-border-radius="medium"></script><script src="https://cdn.staticfile.org/vue/3.4.5/vue.global.js"></script><script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
</head>
<body><!-- 1.启动页。fixed布局覆盖全屏,黑色背景;使用Pacifico手写字体显示标题;opacity-0配合后续JS实现淡入动画。 --><div id="splash" class="fixed inset-0 bg-black flex items-center justify-center z-50"><h1 class="text-7xl font-[&#39;Pacifico&#39;] text-white opacity-0 transition-opacity duration-1000 animate-bounce">哈哈哈哈,我的RAG from wow-rag</h1></div><!-- 2.主聊天容器 --><div id="app" class="hidden h-screen bg-gradient-to-br from-purple-100 via-blue-100 to-purple-100 bg-[size:400%_400%] relative overflow-hidden"><div class="absolute inset-0 animate-[gradient_10s_linear_infinite] z-0"><div class="animate-pulse absolute w-64 h-64 bg-custom/10 rounded-full -top-32 -left-32"></div><div class="animate-pulse absolute w-96 h-96 bg-blue-200/20 rounded-full -bottom-48 -right-48"></div></div><div class="container mx-auto h-full max-w-4xl px-4 py-6 flex flex-col"><div id="chatContainer" class="flex-1 overflow-y-auto mb-4 space-y-4 h-[calc(100%-120px)] z-20"><div v-for="item in messageList.filter((v) => v.role !== 'system')" class="flex" :class="{ 'justify-start': item.role === 'me', 'justify-end': item.role !== 'me' }"><div class="max-w-[70%] space-y-1"><div class="text-xs text-gray-500">{[ roleAlias[item.role] ]}</div><div class="rounded-lg p-3 shadow-sm" :class="{'bg-custom text-white': item.role !== 'me', 'bg-white': item.role === 'me'}"><p v-html="markdownToHtml(item.content)"></p></div></div></div></div><div class="bg-white/80 backdrop-blur-sm rounded-lg p-4 shadow-lg"><div class="flex items-center space-x-2"><button class="text-gray-500 hover:text-custom"><i class="far fa-smile text-xl"></i></button><textareaid="messageInput"class="flex-1 bg-transparent border-none focus:ring-0 text-gray-800 placeholder-gray-400"placeholder="请输入您的问题..."v-model="messageContent"rows="3"></textarea><button id="sendButton" class="bg-custom text-white px-4 py-2 rounded-lg hover:bg-custom/80 transition-colors !rounded-button" @click="send()"><i class="fas fa-paper-plane"></i></button></div></div></div></div><!-- 3.Vue应用核心逻辑 --><script>// 流式数据渲染async function fetchStream(param) {  const url = `http://127.0.0.1:5000/stream_chat?param=${encodeURIComponent(param)}`;const response = await fetch(url);  const reader = response.body.getReader();  while (true) {  const { value, done } = await reader.read();  if (done) {  statusvue.isTalking = false;  break; }  const text = new TextDecoder("utf-8").decode(value);  let len = statusvue.messageList.length;statusvue.messageList[len-1].content += text; }  }const app = Vue.createApp({//数据模型data() {return {cdata: [1, 0, 0],roleAlias: { "me": "我", "GPT": "小助手", "system": "机器人" },messageList: [{ "role": "system", "content": "你是一个人工智能答疑机器人,擅长借助RAG文档帮助用户进行问题回答" },{ "role": "GPT", "content": "您好!我是WOW-RAG智能助手,很高兴为您服务。" },],isTalking: false,messageContent: "",}},delimiters: ['{[', ']}'],methods: {// 消息发送逻辑send() {const userMessage = this.messageContent.trim();if (!userMessage) return;// 添加用户消息this.messageList.push({ "role": "me", "content": userMessage });const message = document.getElementById('chatContainer');message.scrollTop = message.scrollHeight;// 添加助手消息占位符this.messageList.push({ "role": "GPT", "content": "" });this.isTalking = true;// 发送请求fetchStream(userMessage).then(() => {this.isTalking = false;});this.messageContent = '';},// 新增方法:将 Markdown 转换为 HTMLmarkdownToHtml(markdown) {return marked.parse(markdown);}}})const statusvue = app.mount('#app');// om加载事件document.addEventListener('DOMContentLoaded', () => {const splash = document.getElementById('splash');const app = document.getElementById('app');const splashText = splash.querySelector('h1');const playPauseBtn = document.getElementById('playPauseBtn');const volumeSlider = document.getElementById('volumeSlider');const volumeIcon = document.getElementById('volumeIcon');const messageInput = document.getElementById('messageInput');const sendButton = document.getElementById('sendButton');const chatContainer = document.getElementById('chatContainer');setTimeout(() => {splashText.style.opacity = '1';}, 100);setTimeout(() => {splash.style.opacity = '0';splash.style.transition = 'opacity 1s';setTimeout(() => {splash.style.display = 'none';app.classList.remove('hidden');}, 1000);}, 2000);function updateVolumeIcon(value) {let icon = 'fa-volume-up';if (value == 0) icon = 'fa-volume-mute';else if (value < 50) icon = 'fa-volume-down';volumeIcon.innerHTML = `<i class="fas ${icon}"></i>`;}sendButton.addEventListener('click', () => {const message = messageInput.value.trim();if (message) {statusvue.send();}});messageInput.addEventListener('keypress', (e) => {if (e.key === 'Enter') {sendButton.click();}});});</script>
</body>
</html>

使用方式有两种,一种用浏览器打开。第二种直接部署到静态服务器上也可以,例如在该代码的所在位置打开cmd窗口输入命令:python -m http.server 8080 --bind 0.0.0.0

在这里插入图片描述

太牛了,胡斐的爸爸是苗若兰。我只能说是我在文本加载环节,或者数据分割环节,还有数据检索环节、数据增强环节还有很大的改进空间,导致数据生成成这样。

最后我想说RAG是一个很大的工程,每一个环节做精做强不容易,数据清洗,数据加载,数据分割,数据持久化,数据检索方式,数据怎么增强,都不容易,更不用提与大模型相关的环节.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/43880.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

瑞芯微RKRGA(librga)Buffer API 分析

一、Buffer API 简介 在瑞芯微官方的 librga 库的手册中&#xff0c;有两组配置 buffer 的API&#xff1a; importbuffer 方式&#xff1a; importbuffer_virtualaddr importbuffer_physicaladdr importbuffer_fd wrapbuffer 方式&#xff1a; wrapbuffer_virtualaddr wrapb…

pycharm虚拟环境项目转移后配置解释器

添加解析器提示&#xff1a;无效的 Python SDK 解决方法 在到电脑安装python解析器&#xff0c;复制&#xff1a;python.exe和pythonw.exe 项目虚拟环境venv/Scripts Python解释器添加 项目现有虚拟环境&#xff0c;就可以正常使用

【智能体系统AgentOS】核心九:MCP工具

MCP&#xff08;Master Control Program&#xff09;是计算机控制系统中的核心部分&#xff0c;负责协调和管理整个系统的功能模块。不同的MCP可能会根据具体的应用场景有所不同&#xff0c;但通常有以下几类功能模块&#xff1a; 1. 输入输出&#xff08;I/O&#xff09;模块…

强化学习课程:stanford_cs234 学习笔记(2)introduction to RL

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言5、强化学习课程大纲5.1 课程内容主&#xff1a;5.2 马尔可夫决策过程&#xff1a;5.2.1 马尔可夫性 markov propterty5.2.2 马尔可夫过程 markov process5.2.3…

[Linux]在vim中批量注释与批量取消注释

1.在vim中批量注释的步骤&#xff1a; 1.在normal模式下按Ctrl v &#xff0c;进入V-BLOCK模式 2.按 J 键 或 K 键选择要注释的内容&#xff0c;J向上K向下 我们给第5&#xff0c;6&#xff0c;7行进行注释 3.按住shift i进入插入模式&#xff0c;输入 // 4.点击ESC键&…

16-CSS3新增选择器

知识目标 掌握属性选择器的使用掌握关系选择器的使用掌握结构化伪类选择器的使用掌握伪元素选择器的使用 如何减少文档内class属性和id属性的定义&#xff0c;使文档变得更加简洁&#xff1f; 可以通过属性选择器、关系选择器、结构化伪类选择器、伪元素选择器。 1. 属性选择…

Spring Initializr搭建spring boot项目

介绍 Spring Initializr 是一个用于快速生成 Spring Boot 项目结构的工具。它为开发者提供了一种便捷的方式&#xff0c;可以从预先定义的模板中创建一个新的 Spring Boot 应用程序&#xff0c;从而节省了从头开始设置项目的大量时间。 使用 Spring Initializr&#xff0c;你…

C++中的new、malloc、realloc、calloc——特点?函数原型?释放方式?区别?校招面试常问内容?

作者&#xff1a;求一个demo 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 内容通俗易懂&#xff0c;没有废话&#xff0c;文章最后是面试常问内容&#xff08;建议通过标题目录学习&#xff09; 废话不多…

【字符设备驱动开发–IMX6ULL】(一)简介

【字符设备驱动开发–IMX6ULL】&#xff08;一&#xff09;简介 一、Linux驱动与裸机开发区别 1.裸机驱动开发回顾 ​ 1、底层&#xff0c;跟寄存器打交道&#xff0c;有些MCU提供了库。 spi.c&#xff1a;主机驱动&#xff08;换成任何一个设备之后只需要调用此文件里面的…

Spring AI MCP 架构详解

Spring AI MCP 架构详解 1.什么是MCP? MCP 是一种开放协议&#xff0c;它对应用程序向大语言模型&#xff08;LLMs&#xff09;提供上下文信息的方式进行了标准化。可以把 MCP 想象成人工智能应用程序的 USB-C 接口。就像 USB-C 为将设备连接到各种外围设备和配件提供了一种…

【Java】IO流

一、IO流的定义 二、 字节流 &#xff08;一&#xff09;FileOutputStream 操作本地文件的字节输出流&#xff0c;可以把程序中的数据写到本地文件中。 1、书写步骤 注&#xff1a; &#xff08;1&#xff09;创建字节输出流对象&#xff1a; 参数是字符串表示的路径或者…

Java 大视界 -- Java 大数据机器学习模型在电商商品推荐冷启动问题中的解决策略(160)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

MySQL———作业实验

一、创建数据库表 1.创建数据库 mysql> create database mydb11_stu; mysql> use mydb11_stu; 2.建表 &#xff08;1&#xff09;创建student表 mysql> create table student ( -> id int(10) not null unique primary key, -> name varch…

深度解析衡石科技HENGSHI SENSE嵌入式分析能力:如何实现3天快速集成

嵌入式分析成为现代SaaS的核心竞争力 在当今SaaS市场竞争中&#xff0c;数据分析能力已成为产品差异化的关键因素。根据Bessemer Venture Partners的最新调研&#xff0c;拥有深度嵌入式分析功能的SaaS产品&#xff0c;其客户留存率比行业平均水平高出23%&#xff0c;ARR增长速…

Day17 -实例:利用不同语言不同框架的特征 进行识别

前置&#xff1a;我们所需的web站点&#xff0c;都可以利用fofa去搜索&#xff0c;例如&#xff1a;app"flask"这样的语句去找对应的站点&#xff0c;找到后&#xff0c;我们模拟不知道是什么框架&#xff0c;再根据特征去判断它的框架。 ***利用工具可以再去结合大…

Linux输入系统应用编程

什么是输入系统 Linux 输入系统是处理用户输入设备(如键盘、鼠标、触摸屏、游戏手柄等)的软件架构。在应用编程层面&#xff0c;它提供了与这些输入设备交互的接口。 主要组成部分 输入设备驱动层&#xff1a;直接与硬件交互的驱动程序 输入核心层&#xff1a;内核中的输入子…

【C++初阶】---类和对象(下)

1.再探构造函数&#xff08;初始化链表&#xff09; •之前我们实现构造函数时&#xff0c;初始化成员变量主要使⽤函数体内赋值&#xff0c;构造函数初始化还有⼀种⽅式&#xff0c;就是初始化列表&#xff0c;初始化列表的使⽤⽅式是以⼀个冒号开始&#xff0c;接着是⼀个以逗…

Ubuntu 22.04.5 LTS 设置时间同步 ntp

提示&#xff1a;文章为操作记录&#xff0c;以备下次使用 文章目录 前言一、设置ntp1.1替换国内源1.2 更新源&安装1.3 验证 前言 设置时间同步&#xff0c;环境版本 # cat /etc/os-release PRETTY_NAME"Ubuntu 22.04.5 LTS" NAME"Ubuntu" VERSION_…

飞书电子表格自建应用

背景 coze官方的插件不支持更多的飞书电子表格操作&#xff0c;因为需要自建应用 飞书创建文件夹 创建应用 开发者后台 - 飞书开放平台 添加机器人 添加权限 创建群 添加刚刚创建的机器人到群里 文件夹邀请群 创建好后&#xff0c;就可以拿到id和key 参考教程&#xff1a; 创…

计算机网络——传输层(TCP)

传输层 在计算机网络中&#xff0c;传输层是将数据向上向下传输的一个重要的层面&#xff0c;其中传输层中有两个协议&#xff0c;TCP&#xff0c;UDP 这两个协议。 TCP 话不多说&#xff0c;我们直接来看协议报头。 源/目的端口号&#xff1a;表示数据从哪个进程来&#xff0…