当前位置: 首页 > article >正文

DeepSeek之高并发架构设计

一、背景

        前面根据学习DeepSeek与运维相关的结合之后,我们发现针对GPU、Ollama或者大模型本身需要做到很多监控项进行管理,才能保证大模型的高可用运行。随之而来的思考就是,应用层怎么在面对高并发、高流量情况下,保证整个应用的高可用性、可扩展性呢?

        接下来和大家分享一下这个过程中,传统的Web架构与融合了大模型的应用的Web架构有什么区别的地方, 并且如何来实现这个高可用、高性能的架构。

二、传统Web架构与大模型思考

1、传统Web架构

        传统Web架构我们知道,如果使用了负载均衡器在前面进行负载,那么首先要考虑的问题是session会话的问题。 

1、session共享(nfs、redis)等

        要么我们的后端采用session共享机制, 可以通过nfs挂载到同一个盘,后端都能读取session信息,或者把所有的session存储到同一个地方,如redis等介质。

        为的就是实现session读写都在同一个地方,就不会造成session混乱或者丢失的情形。 

2、后端服务改造为"无状态服务",使用jwt

        还有一种方式就是,改造我们的服务,从有状态改为无状态。 每次传递jwt的令牌,令牌里面有登录会话的信息,例如user_id、个人简单信息等等,每次调用接口都是验证token是否合法,从中获取当前登录用户的信息进行处理。

        这种无状态的机制,方便了我们进行负载均衡,并且也不需要像第一种方法一样,专门找一个介质要么nfs,要么redis要么数据库等等,将所有后端产生的session信息存储到同一个地方。提高了服务的可用性,也降低了引入第三方服务的成本.

2、大模型是无状态服务

        首先,大模型的对话是属于有状态还是无状态呢?  基于前面的传统Web架构,我们首先得明确这个问题。  这样后续的架构才能设计出来。

        相关资料如下:

        大语言模型,如 Transformer 架构的模型,在训练时,是基于大量文本数据进行学习,以预测下一个单词或标记。在每次处理输入文本时,模型根据输入的序列数据进行计算,其本身并不天然 “记住” 之前处理过的输入内容,从这个意义上说,它是无状态的。例如,在训练完成后,单独输入一段文本,模型只是对这段文本进行处理,生成相应的输出,不涉及对之前其他输入的记忆。

        总结来说,大模型本身基本是无状态的,不过可以通过特定的输入组织方式等,让它在对话等应用场景中呈现出有状态的效果。

         大模型没有所谓传统Web的session或者cookie机制,每次你的对话对于它都是"新的",是无状态的服务。 都是基于你给的上下文,然后给你一个回复,就这么简单的逻辑。

         大模型之所以理解你的对话上下文, 是因为每次你问他一个新的问题的时候,都需要将之前的回答历史记录传递给它, 它在基于这个历史问答上下文,去给你的最新的问题,做一个回答。

 3、问答上下文 Token

        在大语言模型的语境中,“上下文 Token” 包含两个关键概念,即 “上下文” 和 “Token”:

  • Token:Token 是对文本进行处理时划分的基本单元。由于大语言模型无法直接处理文本数据,需要将文本转化为模型能够理解的数字形式,这一过程就涉及到对文本进行分词,划分成一个个 Token。例如,对于英文文本,Token 可能是一个单词、一个词缀甚至是一个字母;对于中文文本,Token 可以是一个字、一个词等。比如句子 “我喜欢苹果”,可能被切分成 “我”“喜欢”“苹果” 三个 Token。模型在处理输入和生成输出时,都是基于这些 Token 进行计算和操作的。
  • 上下文 Token:“上下文” 指的是与当前处理的文本相关的前后文信息。“上下文 Token” 就是构成这些上下文信息的所有 Token 集合。在对话或处理连续文本时,模型为了准确理解当前输入的含义并生成合适的回复或输出,需要考虑之前出现的文本内容(历史对话、前文等),这些文本内容被转化为 Token 后,就组成了上下文 Token。例如在多轮对话中,前面几轮的对话内容所对应的 Token,与当前输入的 Token 一起,构成了模型处理当前输入时的上下文 Token。模型会基于这些上下文 Token 来捕捉文本之间的语义关联和逻辑关系,从而更好地完成任务,比如回答问题、生成连贯的文本等。

        简单来说,上下文 Token 就是模型在处理当前文本时所依赖的、由前后文及当前文本转化而来的基本单元集合。

        上面第二点提到的每次需要传递,对话历史记录就是上下文token。 并且每个模型针对上下文的token长度, 也就是这个大模型"记忆能力"的一个体现。  能记录的上下文token越多,那么它的"记忆越长",能根据你整个提问记录进行更好地回答。

        上下文 Token 数量限制会影响模型对长文本的理解和处理能力,更多的上下文 Token 意味着模型能考虑更多前文信息,在处理长篇文档、多轮复杂对话时更具优势。随着技术的发展,各模型也在不断探索如何突破现有限制,提高上下文处理能力。  不同的模型,支持的上下文token长度不一样。

三、大模型Web架构思考

1、思路

        通过我们的学习,原来大模型的会话的input输入、output输出是这么个玩意啊。 就是每次你的提问,以及模型的回复都要记录下来,作为下一次你进行新问题提问的参数,这个参数叫对话上下文context。每次都是如此,并且呢token长度是有限制的,理论上你问到token超出上下文,应该是有问题的。

        例如为了保证token不超出模型的理解范围,可以针对将之前时间比较旧的删除,还有一种就是滑动窗口的方式,每次都从前往后滑,保证了token的长度不超出范围,并且尽量传递最新的上下文信息。

        既然大模型的对话是无状态的,那么结合传统Web架构,我们做一些应用层的改造即可了,还是负载均衡、集群那套东西,往上应用即可。架构设计如下.

2、架构图

        我们在Ollama集群前面,可以设置Nginx做反向代理。因为Ollama部署的DeepSeek大模型是无状态的,无论流量到了哪个Ollama根据上下文token推断,进行回答,提高了并发能力。

        我们的应用层可以采用Python、Golang、Java等编程语言进行实现,重点还是看Ollama提供了哪些编程语言的SDK, 理论上来讲,只要Ollama提供官方支持的对应语言的SDK,那么都能很好支持我们去做应用后端。

        每次应用后端需要将对话记录存入Redis,每次得到结果也要存入Redis, 整个就是一个context上下文的内容,只要还在这个对话,就需要传递整个上下文token给Ollama集群,才能获取到更优质的回答。实现大模型"有状态"的回答效果。

3、Ollama SDK后端相关代码demo

针对context上下文存储代码demo:   可以结合redis,存储到redis

import ollama

# 初始化上下文管理器
class ConversationContext:
    def __init__(self, max_context_length=10):
        self.context = []  # 保存对话历史
        self.max_context_length = max_context_length  # 最大上下文长度

    def add_message(self, role, content):
        """添加消息到上下文"""
        self.context.append({"role": role, "content": content})
        # 如果上下文过长,移除最早的消息
        if len(self.context) > self.max_context_length:
            self.context.pop(0)

    def get_context(self):
        """获取当前上下文"""
        return self.context

    def clear_context(self):
        """清空上下文"""
        self.context = []

# 初始化对话上下文
conversation = ConversationContext(max_context_length=10)

每次对话传递context上下文给到Ollama, Ollama负责传递给大模型:

def chat_with_model(user_input):
    # 将用户输入添加到上下文
    conversation.add_message("user", user_input)

    # 获取当前上下文, 上下文数组
    messages = conversation.get_context()

    # 调用 Ollama 模型
    response = ollama.chat(
        model="your-model-name",  # 替换为你的模型名称
        messages=messages    #传递上下文数组,  最后的一个元素应该是你的最新问题
    )

    # 获取模型回复
    model_reply = response["message"]["content"]

    # 将模型回复添加到上下文
    conversation.add_message("assistant", model_reply)

    return model_reply

四、总结

        市面上看到的这些大模型,无外乎就是使用了Python的很多机器学习框架做出来的东西。所以结合到我们的Web开发,只要理解怎么部署模型、调用模型、提高模型并发、高流量就行,本质上也那么复杂。

        重点的复杂和有核心技术难度的是模型怎么训练的、复杂的算法、算法优化等等才是大模型的核心,Web只是大模型向外暴露的intput、output方式罢了,本质和console控制台没多大区别。并且大模型最大的一个特点就是,整个问答其实是无状态的,这一点很重要。


http://www.kler.cn/a/551756.html

相关文章:

  • Qt开发③Qt的信号和槽_概念+使用+自定义信号和槽+连接方式
  • 突破平面限制:低空经济激活城市土地“立体生长力”
  • Perl语言的系统运维
  • IntelliJ配置Maven
  • 黑神话悟空风格事务解读snapshot
  • Flutter CupertinoNavigationBar iOS 风格导航栏的组件
  • 【Java】泛型与集合篇(四)
  • C++ Primer 类的其他特性
  • 关于Flutter前端面试题及其答案解析
  • 【Go语言快速上手】第二部分:Go语言进阶之数据库操作
  • 【设计模式】【结构型模式】代理模式(Proxy)
  • Node.js 中 cors 依赖详解
  • MVTEC数据集笔记
  • 【C++】Basic Data Types and Operators
  • C# 适合做什么项目?全面解析 C# 的应用领域与优势
  • C语言——指针基础知识
  • 六、敏捷开发工具:项目管理工具
  • Ubuntu22.04系统安装使用Docker
  • 【个人总结】7. Linux 工作三年的嵌入式常见知识点梳理及开发技术要点(欢迎指正、补充)
  • 从零开始构建一个小型字符级语言模型的详细教程(基于Transformer架构)之二模型架构设计