跳到主要内容OpenVINO 本地部署 DeepSeek-R1 量化大模型:前端交互与后端服务 | 极客日志PythonAI算法
OpenVINO 本地部署 DeepSeek-R1 量化大模型:前端交互与后端服务
综述由AI生成介绍基于 OpenVINO 本地部署 DeepSeek-R1 量化大模型的前端交互与后端服务实现。内容涵盖前端 HTML 页面开发、Flask 后端接口搭建及 OpenVINO GenAI 推理引擎集成。通过示例代码展示了健康检查、对话生成及模型信息获取等核心功能,并分析了 CPU 和内存的资源占用情况,为本地化运行大模型提供参考方案。
黑客帝国27 浏览 一、前言
基于上一章的环境准备和模型转换,本章专注于后端服务器的部署以及前端页面的启动。
整个后端服务器是依赖于 OpenVINO 的,不过只要你的设备可以使用 OpenVINO,理论上就可以使用这个后端,如果你有 intel 的独立显卡,只需要把代码中 device 更改为对应的设备即可运行在 GPU 上。
self.pipeline = ov_genai.LLMPipeline(self.model_path, device)
二、前端交互界面
chat_interface.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DeepSeek-R1 智能对话</title>
<link rel="icon" type="image/svg+xml" href="logo.svg">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: linear-gradient(135deg, #667eea , ); : ; : ; }
{ : ; : auto; : white; : ; : (,,,); : hidden; : flex; : column; : ; }
{ : ; : white; : ; : center; }
{ : ; : ; : solid ; : flex; : space-between; : center; : ; }
{ : ; : ; : bold; }
{ : ; : ; }
{ : ; : ; }
{ : ; : auto; : ; : ; }
{ : ; : flex; : flex-start; }
{ : flex-end; }
{ : flex-start; }
{ : ; : ; : ; : ; }
{ : ; : white; : ; }
{ : white; : ; : solid ; : ; }
{ : ; : ; : ; }
{ : none; : ; : italic; : ; : ; }
{ : ; : white; : solid ; }
{ : flex; : ; }
{ : ; : ; : solid ; : ; : none; : ; }
{ : ; }
{ : ; : ; : white; : none; : ; : pointer; : ; : background ; }
() { : ; }
{ : ; : not-allowed; }
{ : center; : ; : ; : ; : ; : ; : ; }
🤖 DeepSeek-R1 智能对话
基于 OpenVINO 本地部署
服务状态:检测中...
模型加载中
系统正在初始化,请稍候...
DeepSeek 正在思考中...
发送
0%
#764ba2
100%
min-height
100vh
padding
20px
.chat-container
max-width
900px
margin
0
background
border-radius
15px
box-shadow
0
10px
30px
rgba
0
0
0
0.2
overflow
display
flex-direction
height
90vh
.chat-header
background
#2d3748
color
padding
25px
text-align
.status-bar
background
#f7fafc
padding
10px
20px
border-bottom
1px
#e2e8f0
display
justify-content
align-items
font-size
14px
.status-indicator
padding
4px
12px
border-radius
12px
font-weight
.status-loading
background
#fed7d7
color
#c53030
.status-ready
background
#c6f6d5
color
#276749
.chat-messages
flex
1
overflow-y
padding
20px
background
#f7fafc
.message
margin-bottom
15px
display
align-items
.user-message
justify-content
.bot-message
justify-content
.message-bubble
max-width
70%
padding
12px
18px
border-radius
18px
line-height
1.4
.user-message
.message-bubble
background
#4299e1
color
border-bottom-right-radius
5px
.bot-message
.message-bubble
background
color
#2d3748
border
1px
#e2e8f0
border-bottom-left-radius
5px
.message-time
font-size
12px
color
#718096
margin-top
5px
.typing-indicator
display
color
#718096
font-style
margin
10px
0
padding
0
20px
.chat-input-container
padding
20px
background
border-top
2px
#e2e8f0
.chat-input
display
gap
10px
#messageInput
flex
1
padding
12px
15px
border
1px
#cbd5e0
border-radius
25px
outline
font-size
16px
#messageInput
:focus
border-color
#4299e1
#sendButton
padding
12px
25px
background
#4299e1
color
border
border-radius
25px
cursor
font-size
16px
transition
0.3s
#sendButton
:hover
:not
:disabled
background
#3182ce
#sendButton
:disabled
background
#a0aec0
cursor
.system-message
text-align
color
#718096
font-size
14px
margin
10px
0
padding
8px
background
#edf2f7
border-radius
8px
</style>
</head>
<body>
<div>
<h1>
</h1>
<p>
</p>
</div>
<div>
<span>
<span id="statusText">
</span>
</span>
<span id="modelStatus">
</span>
</div>
<div id="loadingMessage">
</div>
<div id="thinkingMessage">
</div>
<div class="chat-container">
<div class="chat-messages" id="chatMessages">
</div>
<div class="chat-input-container">
<div class="chat-input">
<input type="text" placeholder="输入您的问题..." autocomplete="off" disabled id="messageInput">
<button disabled id="sendButton">
</button>
</div>
</div>
</div>
<script>
const API_BASE = 'http://localhost:5000';
const chatMessages = document.getElementById('chatMessages');
const messageInput = document.getElementById('messageInput');
const sendButton = document.getElementById('sendButton');
const typingIndicator = document.getElementById('typingIndicator');
const statusText = document.getElementById('statusText');
const modelStatus = document.getElementById('modelStatus');
async function checkServerStatus() {
try {
const response = await fetch(`${API_BASE}/health`);
const data = await response.json();
if (data.status === 'ready') {
statusText.textContent = 'OpenVINO 服务就绪';
modelStatus.textContent = 'CPU 加速就绪';
modelStatus.className = 'status-indicator status-ready';
messageInput.disabled = false;
sendButton.disabled = false;
messageInput.placeholder = "输入您的问题...";
if (chatMessages.querySelector('.system-message')) {
chatMessages.innerHTML = '';
addMessage('您好!我是基于 OpenVINO GenAI 优化的 AI 助手,现在运行在 CPU 上,为您提供高效的本地推理服务。', false);
}
return true;
} else {
statusText.textContent = 'OpenVINO 模型加载中...';
modelStatus.textContent = '优化中';
modelStatus.className = 'status-indicator status-loading';
messageInput.placeholder = "OpenVINO 模型优化加载中,请稍候...";
return false;
}
} catch (error) {
statusText.textContent = 'OpenVINO 服务未连接';
modelStatus.textContent = '离线';
modelStatus.className = 'status-indicator status-loading';
messageInput.placeholder = "无法连接到 OpenVINO 服务,请检查服务器状态";
return false;
}
}
function getCurrentTime() {
return new Date().toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
}
function addMessage(content, isUser = false) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${isUser ? 'user-message' : 'bot-message'}`;
messageDiv.innerHTML = `<div>${content.replace(/\n/g, '<br>')}<div>${getCurrentTime()}</div></div>`;
chatMessages.appendChild(messageDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
function showTypingIndicator() {
typingIndicator.style.display = 'block';
chatMessages.scrollTop = chatMessages.scrollHeight;
}
function hideTypingIndicator() {
typingIndicator.style.display = 'none';
}
async function sendMessage() {
const message = messageInput.value.trim();
if (!message) return;
addMessage(message, true);
messageInput.value = '';
sendButton.disabled = true;
showTypingIndicator();
try {
const response = await fetch(`${API_BASE}/chat`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: message, max_tokens: 512 })
});
if (!response.ok) {
throw new Error(`HTTP 错误!状态码:${response.status}`);
}
const data = await response.json();
if (data.status === 'success') {
hideTypingIndicator();
addMessage(data.response, false);
} else {
throw new Error(data.error || '未知错误');
}
} catch (error) {
hideTypingIndicator();
addMessage(`抱歉,出现了错误:${error.message}`, false);
console.error('API 调用错误:', error);
} finally {
sendButton.disabled = false;
messageInput.focus();
}
}
sendButton.addEventListener('click', sendMessage);
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage();
}
});
async function init() {
const checkInterval = setInterval(async () => {
const isReady = await checkServerStatus();
if (isReady) {
clearInterval(checkInterval);
}
}, 5000);
await checkServerStatus();
}
window.onload = init;
</script>
</body>
</html>
主要实现了几个简单控件,输入条,发送按钮和状态栏,需要后端提供三个接口:
const response = await fetch(`${API_BASE}/health`);
const response = await fetch(`${API_BASE}/model_info`);
const response = await fetch(`${API_BASE}/chat`);
三、后端模型服务器
OpenVINO 为生成式 AI 优化提供了推理引擎:OpenVINO GenAI。
OpenVINO GenAI 提供简洁的 API 接口,支持 Python 和 C++ 两种编程语言,安装容量不到 200MB。
以我本次使用的 DeepSeek-R1-0528-Qwen3-8B 为例,流水线使用 LLMPipeline。
pip install Flask Flask-CORS openvino-genai
openvino_server.py
import openvino_genai as ov_genai
from flask import Flask, request, jsonify
from flask_cors import CORS
import threading
import logging
from typing import Dict, Any
from pathlib import Path
class OpenVINOBackend:
def __init__(self, model_path: str):
self.model_path = model_path
self.pipeline = None
self.is_ready = False
self.init_lock = threading.Lock()
def initialize_model(self, device: str):
with self.init_lock:
if self.is_ready:
return
logger.info("正在加载 OpenVINO 模型...")
try:
self.pipeline = ov_genai.LLMPipeline(self.model_path, device)
self.is_ready = True
logger.info("OpenVINO 模型加载完成!")
except Exception as e:
logger.error(f"模型加载失败:{str(e)}")
self.is_ready = False
def generate_response(self, message: str, max_tokens: int = 512, temperature: float = 0.7, do_sample: bool = True) -> Dict[str, Any]:
if not self.is_ready or self.pipeline is None:
return {"status": "error", "error": "模型未就绪"}
try:
config = ov_genai.GenerationConfig()
config.max_new_tokens = max_tokens
config.temperature = temperature
config.do_sample = do_sample
self.pipeline.start_chat()
response = self.pipeline.generate(message, config)
self.pipeline.finish_chat()
return {
"status": "success",
"response": response,
"tokens_generated": len(response.split())
}
except Exception as e:
return {"status": "error", "error": str(e)}
def create_app(backend: OpenVINOBackend) -> Flask:
app = Flask(__name__)
CORS(app)
@app.route('/health', methods=['GET'])
def health_check():
return jsonify({
"status": "ready" if backend.is_ready else "loading",
"backend": "openvino_genai",
"device": "CPU"
})
@app.route('/chat', methods=['POST'])
def chat_endpoint():
data = request.json
if not data or 'message' not in data:
return jsonify({"status": "error", "error": "缺少 message 参数"})
message = data['message']
max_tokens = min(max(int(data.get('max_tokens', 512)), 1), 2048)
result = backend.generate_response(message, max_tokens)
return jsonify(result)
@app.route('/model_info', methods=['GET'])
def model_info():
return jsonify({
"backend": "openvino_genai",
"status": "ready" if backend.is_ready else "loading",
"device": "CPU",
"optimization": "int4_quantization"
})
return app
def initialize_backend(backend: OpenVINOBackend, device: str='CPU'):
def init_task():
backend.initialize_model(device)
thread = threading.Thread(target=init_task, daemon=True)
thread.start()
def main(model_path: str = "./converted_ov_model"):
logging.basicConfig(
level=logging.INFO,
format='-- %(levelname)s - %(message)s',
force=True
)
global logger
logger = logging.getLogger(__name__)
logger.info("Starting OpenVINO GenAI server...")
p = Path(model_path)
if not p.exists():
logger.error(f"路径不存在:{model_path}")
return
if not p.is_dir():
logger.error(f"请传入模型文件夹:{model_path}")
return
backend = OpenVINOBackend(model_path)
app = create_app(backend)
initialize_backend(backend, "CPU")
logger.info(f"启动 OpenVINO GenAI 服务器,模型路径:{model_path}...")
app.run(host='0.0.0.0', port=5000, debug=False)
if __name__ == '__main__':
path = "./DeepSeek-R1-0528-Qwen3-8B_openvino_int4"
main(path)
为了启动方便,我将模型路径写进了 py 文件,读者可以根据自身情况改为从命令行传参。后端也是主要实现三个接口,以及模型的初始化和推理。
为了适配长期运行环境,启用了 logger 和局域网服务器,并且关闭了 Flask 的 debug,防止 Werkzeug 的自动重载机制(reloader),出现一些莫名的情况。
四、资源占用
启动后端服务是不占用资源的,开始对话以后才会明显占用 CPU 和内存。
可以看到,OpenVINO 优化以及 INT4 量化后的 DeepSeek-R1-0528-Qwen3-8B,内存占用约 10G,CPU 也在可接受范围,每次推理大约需要 40 秒。
根据缩略图情况,启动后内存不会释放,直到后端服务器关闭。目前对话是单次输入输出,也就是每次对话只会有一次请求和回复,因此消息没有逐字生成的效果,未来有机会再继续优化,并且现在有字符上线限制,主要是因为我的设备性能有限,如果能将逐字显示完成,使用体验应该可以流畅很多。
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
- 随机西班牙地址生成器
随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online
- Gemini 图片去水印
基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
- curl 转代码
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online