【异地访问本地DeepSeek】Flask+内网穿透,轻松实现本地DeepSeek的远程访问

写在前面:本博客仅作记录学习之用,部分图片来自网络,如需引用请注明出处,同时如有侵犯您的权益,请联系删除!


文章目录


前言

在人工智能技术日新月异的今天,DeepSeek作为一款强大的大语言模型,已经在众多领域中展现出其巨大的应用潜力。然而,对于许多用户而言,在本地服务器或者电脑部署DeepSeek,异地如何访问本地资源,成为了一个值得思考的问题。

本文以内网穿透技术实现公网访问,以期为相关从业者或爱好者提供有价值的参考。本地部署DeepSeek,意味着用户可以在自己的服务器上运行这一大语言模型,从而在一定程度上掌控数据的隐私性和安全性。与此同时,通过内网穿透技术,用户还能将本地部署的DeepSeek实例暴露到公网上,实现远程访问和交互。不仅提高了模型的可用性,还为跨地域、跨团队的合作提供了极大的便利。

然而,本地部署和内网穿透并非没有挑战。硬件成本、维护成本、技术门槛以及安全风险等问题,都是用户在决策过程中需要考虑的关键因素。因此,本文旨在全面分析本地部署DeepSeek并通过内网穿透实现公网访问的必要性,帮助用户权衡利弊,做出最适合自己的选择。


依赖

本地部署: 【DeepSeek本地化部署保姆级教程 】

如果需要创建新环境:conda create -n deepseek python=3.7

  • Window 11
  • Flask
  • markdown2

安装: pip install Flaskpip install markdown2

Flask构建本地网页访问

LM Studio 开启网址访问

确保加载合适的模型(GGUF),然后在开发者选项中确保开启运行,并查看对应的IP和端口,此处http://127.0.0.1:1234,这个区别于OpenAI。


DeepSeek 调用模板

DeepSeek 调用模板:首次调用 API

python 复制代码
# Please install OpenAI SDK first: `pip3 install openai`

from openai import OpenAI

client = OpenAI(api_key="<DeepSeek API Key>", base_url="https://api.deepseek.com")

response = client.chat.completions.create(
    model="deepseek-chat",
    messages=[
        {"role": "system", "content": "You are a helpful assistant"},
        {"role": "user", "content": "Hello"},
    ],
    stream=False
)

print(response.choices[0].message.content)

此处提供了OpenAI的调用方式,由于需要api_key显得比较麻烦或者需要付费,因此直接和LM Studio 的本地网址进行访问。

Flask 访问本地网址

通过上述模板构建本地的API,将Flask构建的网页 的输入框的内容传入到messages中,随后将其传入到LM Studio进行推理,将返回的结果进一步展示到Flask构建的对话框中即可。下面是app.py的逻辑:

python 复制代码
from flask import Flask, request, jsonify, render_template
import markdown2
import requests

API_URL = "http://localhost:1234/v1/chat/completions"

headers = {
    "Content-Type": "application/json"
}

app = Flask(__name__, template_folder='templates',)
app.static_folder = 'static'
@app.route('/')
def index():
    return render_template("index.html")

@app.route('/process', methods=['POST'])
def process():
    data = request.get_json()
    user_input = data['input']
    # user_input = request.form['user_input']

    messages = [
        {"role": "system", "content": "你是一个优秀的人工智能助手"},
        {"role": "user", "content": f"{user_input}"},
    ]

    data = {
        "model": "DeepSeek/7B/DeepSeek-R1-Distill-Qwen-7B-Q6_K.gguf",  # 你的 DeepSeek 模型名称
        "messages": messages,
        "stream": False  # 关闭流式输出
    }

    response = requests.post(API_URL, headers=headers, json=data)

    if response.status_code == 200:
        result = response.json()
    else:
        print("请求失败:", response.status_code, response.text)

    # 将用户输入和脚本输出以对话形式返回
    conversation = [
        {"user": user_input},
        {"script": result["choices"][0]["message"]["content"]}
    ]
    markdown_text = conversation[1]["script"]

    html_content = markdown2.markdown(markdown_text)
    response_message = f"DeepSeek: {html_content}"
    return jsonify({'message': response_message})

if __name__ == '__main__':
    app.run(debug=False)

调试阶段可以使用app.run(debug=True),确定后改为False。

HTML内容

HTML可以使用大模型直接输出,下面是一个示范的提示词:

bash 复制代码
你的任务是使用python、Flask创建一个网页,具体要求如下:
1. 网页需包含两个文本框,一个用于获取用户输入,另一个用于显示Python脚本的返回内容。
2. 输入框需固定于网页中底部并居中,并长度仅为网页宽度50%,发送键位于输入框的右侧,发送键实现将输入框的文本发送给脚本
3. 输出框以对话的形式进行展示,同时位于位于输入框的上方并居中,并长度仅为网页宽度50%,展示用户的输入和脚本的返回内容
4. 网页需要有背景图
5. 只需要一个html和app.py

需要注意,如果无法加载图片,将其放在static文件夹中,配合app.static_folder = 'static'使用

下面是不断调整后的一个html文件的内容:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Flask DeepSeek</title>
    <style>
        body {
            margin: 0;
            font-family: Arial, sans-serif;
            background-image: url("../static/back.jpg");
            background-size: cover;
            background-position: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
        }
        .container {
            width: 55%;
            /*text-align: center;*/
            background-color: rgba(255, 255, 255, 0.8);
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }
        .chat-box {
            height: 400px;
            overflow-y: auto;
            border: 1px solid #ccc;
            padding: 10px;
            margin-bottom: 10px;
        }
        .input-group {
            display: flex;
            justify-content: space-between;
            align-items: center;
            width: 100%;
        }
        .input-group input {
            width: calc(90% - 10px);
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 5px;
        }
        .input-group button {
            width: calc(10% - 10px);
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 10px;
            background-color: #007bff;
        }
        .input-group button:hover {
            background-color: #0056b3;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="chat-box" id="chat-box">
            <!-- 聊天内容将会通过JavaScript动态添加 -->
        </div>
        <div class="input-group">
            <input type="text" id="user-input" placeholder="输入你的消息...">
            <button onclick="sendMessage()">发送</button>
        </div>
    </div>

    <script>
        function appendMessage(message, isUser) {
            const chatBox = document.getElementById('chat-box');
            const messageElement = document.createElement('div');
            messageElement.textContent = message;
            messageElement.style.color = isUser ? 'blue' : 'black';
            messageElement.style.padding = '5px';
            messageElement.style.borderBottom = '1px solid #ccc';
            chatBox.appendChild(messageElement);
            chatBox.scrollTop = chatBox.scrollHeight;
        }

        function sendMessage() {
            const userInput = '用户:' + document.getElementById('user-input').value;
            if (userInput.trim() !== '') {
                const xhr = new XMLHttpRequest();
                xhr.open('POST', '/process', true);
                xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        const response = JSON.parse(xhr.responseText);
                        appendMessage(userInput, true);
                        appendMessage(response.message, false);
                        document.getElementById('user-input').value = '';
                    }
                };
                xhr.send(JSON.stringify({ input: userInput }));
            }
        }
    </script>
</body>
</html>

网页的结构如下:

本地推理

在输入框中输入问题后发送,获取7B模型的返回值,网址:http://127.0.0.1:5000,结果如下

LM Studio中的记录如下:

bash 复制代码
2025-02-28 23:04:32  [INFO] 
[LM STUDIO SERVER] Running chat completion on conversation with 2 messages.
2025-02-28 23:04:33  [INFO] 
[LM STUDIO SERVER] Accumulating tokens ... (stream = false)
2025-02-28 23:05:33  [INFO] 
[LM STUDIO SERVER] [7b] Generated prediction:  {
  "id": "chatcmpl-cc7tk9bfa4b9gb6mhlztg",
  "object": "chat.completion",
  "created": 1740755072,
  "model": "7b",
  "choices": [
    {
      "index": 0,
      "logprobs": null,
      "finish_reason": "stop",
      "message": {
        "role": "assistant",
        "content": "<think>\n好,我现在要介绍重庆。首先,重庆是一个直辖市,在中国南方,连接长江和嘉陵江。地理位置优越,是长江经济带的重要城市。\n\n重庆有很多景点,比如洪崖洞、解放碑、长江索道等,这些都是游客必去的地方。还有火锅和川菜非常有名,尤其是磁器口古镇里的小吃,可以品尝到地道的重庆味道。\n\n重庆的地形多样,既有 flat 的地区,也有山和江。著名的龙舟峡和武隆喀斯特地貌吸引了不少游客。\n\n重庆是一个比较开放的城市,经济繁荣,而且语言相对通用,这对于国际交流很有帮助。\n\n交通方面,重庆有便捷的高铁、地铁和轻轨系统,方便游客出行。\n\n气候温暖湿润,四季分明,适合各种活动。\n\n最后,重庆不仅是一个旅游胜地,也是一座充满活力的城市,有很多现代化的设施和文化活动。总的来说,重庆是一个值得一游的地方。\n</think>\n\n当然!重庆是中国的一个直辖市,位于中国南方,具体位置是在重庆市,地处长江与嘉陵江之间。以下是关于重庆的一些详细介绍:\n\n### 1. **地理位置**\n   - 重庆是中国南方的交通枢纽之一,连接长江和嘉陵江。\n   - 地处长江经济带中心地带,具有重要的战略地位。\n\n### 2. **景点与文化**\n   - **洪崖洞**:以吊脚楼建筑和夜景闻名,是重庆的标志性景点。\n   - **解放碑**:重庆的商业中心之一,拥有众多店铺和商业娱乐设施。\n   - **长江索道**:横跨长江的空中交通工具,提供壮丽的景色观赏。\n   - **磁器口古镇**:以美食和传统手工艺品闻名,是品尝重庆火锅和了解当地文化的好去处。\n\n### 3. **美食**\n   - 重庆火锅是中国最著名的火锅之一,以其麻辣鲜香著称。\n   - 其他特色美食包括小面、酸辣粉、毛血旺等。\n\n### 4. **地形与气候**\n   - 重庆地形多样,既有平坦的地区,也有山脉和河流。武隆喀斯特地貌是世界自然遗产之一。\n   - 气候温暖湿润,四季分明,雨量充沛。\n\n### 5. **经济与开放**\n   - 作为直辖市,重庆在西南地区的经济发展中占有重要地位。\n   - 外贸中心之一,拥有较为自由的市场准入政策。\n\n### 6. **交通**\n   - 运输系统完善,包括高铁、地铁和轻轨,方便游客出行。\n   - 公共交通发达,覆盖范围广。\n\n### 7. **语言与文化**\n   - 汉语以外的主要少数民族有苗族、汉族、土家族等,多元文化交融显著。\n\n总的来说,重庆是一个历史悠久、风景优美且充满活力的城市。无论是自然风光、美食文化还是历史遗迹,都让人流连忘返。"
      }
    }
  ],
  "usage": {
    "prompt_tokens": 15,
    "completion_tokens": 601,
    "total_tokens": 616
  },
  "stats": {},
  "system_fingerprint": "7b"
}

内网穿透访问

内网穿透工具较多,此处使用花生壳为例子。

  • 登录后,选择内网穿透
  • 选择添加映射
  • 填写映射信息
  • 查看公网网址

  • 公网访问

总结

总结: 为了方便本地化部署后,异地调用本地模型进行推理,可以按照以下步骤操作:

  1. 基础环境:在LM Studio官网下载并运行对应的GGUF模型,以及安装对应的python包。
  2. Flask构建网页:Flask结合LM Studio的端口和HTML构建网页,实现网页对话。
  3. 内网穿透:通过花生壳将Flask所开放的端口进行映射,实现异地访问本地的模型。

互动

  • 你觉得上述内容对你有帮助吗?`

欢迎在评论区解答上述问题,分享你的经验和疑问!

当然,也欢迎一键三连给我鼓励和支持:👍点赞 📁 关注 💬评论。


致谢

欲尽善本文,因所视短浅,怎奈所书皆是瞽言蒭议。行文至此,诚向予助与余者致以谢意。


参考

1 DeepSeek API 文档


往期回顾

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 👆 DeepSeek本地化部署保姆级教程👆 | 👆 EfficientTrain++帮你降低网络训练的成本👆 | 👆 PyCharm环境下Git与Gitee联动👆 |

|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 👆 Ping通但SSH连接失败的解决办法👆 | 👆 轻量化设计如何提高模型的推理速度👆 | 👆 正则化与正则剪枝👆 |

相关推荐
love530love3 小时前
LiveTalking 数字人项目 Windows 部署完全指南(EPGF 架构)
人工智能·windows·python·架构·livetalking·epgf
遇事不決洛必達3 小时前
【Python基础】GIL 锁是什么及其对爬虫的影响
爬虫·python·线程·进程·gil锁
星辰徐哥3 小时前
Spring Boot 微服务架构设计与实现
spring boot·后端·微服务
星辰徐哥3 小时前
Spring Boot 数据导入导出与报表生成
spring boot·后端·ui
明夜之约3 小时前
Spring Boot 自动装配源码
java·spring boot·后端
Leaton Lee3 小时前
Spring Boot分层架构详解:从Controller到Service再到Mapper的完整流程
java·spring boot·后端·架构
Micro麦可乐3 小时前
Spring Boot 实战:从零设计一个短链系统(含完整代码与数据库设计)
数据库·spring boot·后端·哈希算法·雪花算法·短链系统
Jinkxs3 小时前
Resilience4j- 与 Spring Boot 快速集成:自动配置与基础注解使用
java·spring boot·后端
毕设源码_郑学姐3 小时前
计算机毕业设计springboot网络相册设计与实现 基于Spring Boot框架的在线相册管理系统开发与应用 Spring Boot驱动的网络影集设计与实践
spring boot·后端·课程设计
辣机小司3 小时前
【踩坑记录:Spring Boot 配置文件读取值不一致?警惕 YAML 的“八进制陷阱”与 SnakeYAML 版本之谜】
java·spring boot·后端·yaml·踩坑记录