旗下品牌:
石家庄网站开发 石家庄网站开发公司

资讯动态

察而思、思而行、行而后语、知行合一

Vue3 + DeepSeek 实战:从零实现AI流式打字机效果

发布时间:2026-05-09 热度:

前言:为什么需要流式输出?

在传统的软件开发模式中,我们调用后端API时通常采用“请求-等待-响应”的同步模式。但在大语言模型(LLM)时代,模型生成一段300字的回答可能需要5-10秒。如果让用户全程面对白屏等待,体验是灾难性的。

流式输出(Streaming)正是为了解决这一问题而生。它利用HTTP协议的长连接特性,将AI生成的内容以“打字机”效果逐字推送到前端

本文将带你使用 Vue3 的组合式API,结合 DeepSeek 强大的模型能力,全从前端视角(无需后端中转)构建一个高性能的AI对话应用。

一、技术选型与环境搭建

1. 核心技术栈

  • 前端框架: Vue 3.4+,使用 `` 语法糖,配合 refreactive 实现响应式状态管理

  • 网络请求: Fetch API,利用其 ReadableStream 接口处理二进制流,这是实现流式渲染的基石

  • 数据格式: Server-Sent Events (SSE) 或标准的 Stream Chunk,DeepSeek API 完全兼容 OpenAI 接口规范。

  • 富文本渲染: marked.js + highlight.js,用于将Markdown文本和代码块实时渲染为HTML。

2. 获取API Key

前往 DeepSeek 官方平台注册并申请 API Key。由于是前端直接调用,切记不要将API Key硬编码在客户端,但在本地调试或通过服务端代理时,我们需要了解其请求格式:

bash
# 请求示例POST https://api.deepseek.com/v1/chat/completions
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY

二、核心逻辑实现:流式数据的处理

这是本文最关键的环节。我们需要在前端维持一个 ReadableStream 的读取循环,将二进制流逐步解码并追加到页面上。

1. 定义响应式状态

在 Vue3 的 <script setup> 中,我们定义消息列表和当前正在接收的流式内容。

javascript
import { ref, nextTick } from 'vue';const messages = ref([]);       // 存储历史对话const currentResponse = ref(''); // 当前AI正在回复的内容const isLoading = ref(false);    // 加载状态const abortController = ref(null); // 用于中断请求

2. 封装流式请求函数

这是核心逻辑:调用 DeepSeek API,并通过 getReader() 逐块读取数据

javascript
const fetchDeepSeekStream = async (query) => {
    try {
        // 建立请求
        const response = await fetch('https://api.deepseek.com/v1/chat/completions', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${import.meta.env.VITE_DEEPSEEK_KEY}`
            },
            body: JSON.stringify({
                model: 'deepseek-chat', // 或者 deepseek-reasoner [citation:5]
                messages: [
                    { role: 'user', content: query }
                ],
                stream: true,          // 开启流式是关键
                temperature: 0.7
            })
        });

        const reader = response.body.getReader();
        const decoder = new TextDecoder('utf-8');
        let buffer = ''; // 缓冲区,用于处理不完整的JSON块

        while (true) {
            const { done, value } = await reader.read();
            if (done) break;

            // 解码二进制流
            const chunk = decoder.decode(value, { stream: true });
            const lines = chunk.split('\n');
			
            for (const line of lines) {
                if (line.startsWith('data: ')) {
                    const dataStr = line.replace('data: ', '');
                    if (dataStr === '[DONE]') {
                        // 流结束
                        isLoading.value = false;
                        break;
                    }
                    try {
                        const json = JSON.parse(dataStr);
                        const content = json.choices[0].delta?.content;
                        if (content) {
                            // 核心:累加响应内容,触发Vue更新视图
                            currentResponse.value += content;
                            // 滚动到最新位置
                            await nextTick();
                            scrollToBottom();
                        }
                    } catch (e) {
                        // 解析失败可能是数据不完整,暂存到buffer,此处简化处理
                        console.warn("Parse error", e);
                    }
                }
            }
        }
    } catch (error) {
        console.error("Stream error:", error);
        isLoading.value = false;
    }};

3. 组件中的交互逻辑

在用户点击发送时,先将用户消息推入列表,再调用流式函数。

html
<template>
  <div class="chat-box">
    <div v-for="msg in messages" class="message">{{ msg.content }}</div>
    <!-- 单独渲染流式输出的消息块 -->
    <div v-if="currentResponse" class="message assistant">
      {{ currentResponse }}      <span class="cursor" v-if="isLoading">|</span>
    </div>
  </div></template>

三、进阶体验:Markdown与代码高亮

AI回答的内容通常包含 Markdown 语法,如果直接显示纯文本,代码块会变得杂乱无章。在跨平台开发(如小程序)或 Web 开发中,我们需要引入解析库。

1. 引入marked与highlight.js

javascript
import { marked } from 'marked';import hljs from 'highlight.js';// 配置marked解析器marked.setOptions({
    highlight: function(code, lang) {
        if (lang && hljs.getLanguage(lang)) {
            return hljs.highlight(code, { language: lang }).value;
        }
        return hljs.highlightAuto(code).value;
    },
    breaks: true});// 在Vue中使用计算属性实时渲染流式内容const renderedMarkdown = computed(() => {
    return marked(currentResponse.value);});

注意:在微信小程序开发中,无法直接使用 v-html,建议使用 mp-html 或者 ua-markdown 这类专用组件来替代 DOM 操作,以达到更好的兼容性

2. 支持深度思考(Reasoner模式)

DeepSeek 提供了 deepseek-reasoner 模型,它会先输出思考链(reasoning_content),再输出最终回答。在前端,我们可以将这两者分开渲染,打造类似 ChatGPT-o1 的体验

javascript
// 数据结构处理if (json.choices[0].delta?.reasoning_content) {
    thinkingText.value += json.choices[0].delta.reasoning_content;} else if (json.choices[0].delta?.content) {
    currentResponse.value += json.choices[0].delta.content;}

四、扩展至小程序与跨端开发

作为一名合格的软件开发工程师,我们通常需要一套代码覆盖多个平台。利用 UniApp 结合 Vue3,可以将上述 Web 逻辑无缝迁移到小程序中

跨端开发的适配要点:

  1. 网络请求差异:

    • Web端:直接使用 fetchaxios

    • 小程序端:UniApp 环境下建议使用 uni.request,但uni.requestReadableStream 的支持不如 Web 完整。如果是小程序,更科学的做法是通过 WebSocket 或者自建云函数来透传流式数据

  2. UI 组件库:

    • 建议使用 uni-ui 配合 uv-ui,它们对 Vue3 和暗黑主题有着良好的支持。

  3. 性能优化:

    • 在App端或高性能Web端,当对话记录非常长时,建议使用虚拟滚动来优化DOM渲染,避免页面卡顿

五、总结与展望

通过以上步骤,我们仅用纯前端技术栈就完成了 Vue3 对 DeepSeek 的流式对接。这套架构不仅适用于 Web 聊天室,稍加改造即可应用于 AI 客服系统智能代码辅助插件甚至是 RAG 知识库问答系统

核心收获:

  1. 掌握流: 理解了 HTTP 的 ReadableStream 是如何在前端被消费的。

  2. 响应式更新: 利用 Vue3 的 ref 特性,currentResponse.value += delta 这一行代码就完成了逐字更新。

  3. 工程化思维: 区分了普通文本传输和 Markdown 渲染的时机,保证了最终界面的美观性。

目前的 AI 应用开发早已不是简单的 API 调用,它考验的是对异步编程数据结构以及用户体验的深度理解。希望这篇文章能帮助你开启 AI 应用开发的下一步。


下一篇:没有了

联系尚武科技
客户服务
石家庄APP开发
0311-83796180
为您提供售前购买咨询、解决方案推荐等1V1服务!
技术支持及售后
石家庄APP开发公司
0311-66682288
为您提供从产品到服务的全面技术支持 !
客户服务
石家庄小程序开发
石家庄小程序开发公司
加我企业微信
为您提供售前购买咨询、
解决方案推荐等1V1服务!
石家庄网站建设公司
咨询相关问题或预约面谈,可以通过以下方式与我们联系。
石家庄网站制作
在线联系:
石家庄Web开发
石家庄软件开发
石家庄软件开发公司
ADD/地址:
河北·石家庄
新华区西三庄大街86号河北互联网大厦B座二层
Copyright © 2008-2026尚武科技 保留所有权利。 冀ICP备12011207号-2 石家庄网站开发冀公网安备 13010502001294号《互联网平台公约协议》
Copyright © 2026 www.sw-tech.cn, Inc. All rights reserved