Vue3 + AI 流式输出实战:像“打字机”一样与大模型对话!

183 阅读6分钟

🚀 Vue3 + AI 流式输出实战:像“打字机”一样与大模型对话!⌨️✨


你有没有想过,当你在和 ChatGPT 或通义千问聊天时,那些文字是一个字一个字“蹦”出来的?就像有人在键盘上现场敲给你看一样——这可不是魔法,而是现代 Web 的一项酷炫技术:流式输出(Streaming Response)

今天,我们就用 Vue3 搭建一个超有趣的 AI 对话应用,实现「边生成、边显示」的丝滑体验,让你的网页也能拥有“打字机”般的 AI 互动效果!🖨️💨

准备好了吗?Let’s go!


🎯 为什么要做流式输出?

想象一下这个场景:

你问 AI:“讲个喜羊羊与灰太狼的故事,200 字。”
普通方式:你点提交 → 等 5 秒 → “唰”一下全文弹出。
流式输出:你点提交 → 马上看到“从前,在青青草原上……”一个字一个字冒出来,仿佛 AI 正在思考并书写。

💡 用户体验差在哪?

  • 普通请求像是“寄信”:发出去,等回信,期间干不了啥。
  • 流式请求更像是“打电话”:对方一边说,你一边听。

所以,流式输出 = 更快感知反馈 + 更强交互沉浸感。用户不会觉得“卡住了”,而是感觉“正在发生”。


🔧 技术栈一览

我们这次要用到的技术非常精简但强大:

  • Vue3 + <script setup> —— 现代前端开发首选
  • ref 响应式系统 —— 数据一变,视图自动更新
  • Fetch API + ReadableStream —— 实现流式读取的核心
  • TextDecoder —— 解码二进制流为可读文本
  • DeepSeek API —— 国产优秀大模型平台(免费可用!)

💬 提示:本文代码已完整可运行,复制即用,记得配置你的 API Key 哦!


🧱 第一步:初始化项目

npm init vite

选择:

  • Framework: Vue
  • Variant: JavaScript

然后安装依赖、启动项目:

cd your-project-name
npm install
npm run dev

Vite 快如闪电⚡,几秒内就能看到欢迎页面!


🧩 三明治结构:.vue 文件的秘密

Vue 单文件组件(SFC)就像一份三明治🥪:

<script setup>     <!-- 馅料1:逻辑 -->
  // JS 代码写这里
</script>

<template>         <!-- 馅料2:模板 -->
  <div>我是页面</div>
</template>

<style scoped>    <!-- 馅料3:样式 -->
  div { color: red; }
</style>

今天我们只聚焦核心功能:让 AI 的回答像打字机一样“打”出来。


🔁 响应式数据:ref() 是灵魂

Vue 的精髓在于——你不用手动操作 DOM

比如我们要展示一个问题和它的回答:

import { ref } from 'vue'

const question = ref('讲个喜羊羊的故事')
const content = ref('')

这里的 ref() 创建的是“响应式对象”。当 .value 改变时,模板会自动刷新!

举个🌰:

setTimeout(() => {
  content.value = '我是一只快乐的小羊~'
}, 2000)

两秒后,页面上的 {{ content }} 就会自动更新!是不是很神奇?🧠


🤖 调用 AI 大模型:开启智能之旅

我们使用 DeepSeek API,它支持 stream: true 模式,非常适合做流式输出。

先设置请求参数:

const endpoint = 'https://api.deepseek.com/chat/completions'
const headers = {
  "Authorization": `Bearer ${import.meta.env.VITE_DEEPSEEK_API_KEY}`,
  "Content-Type": "application/json"
}

⚠️ 别忘了在 .env 文件中添加你的密钥:

VITE_DEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

🌊 核心突破:如何处理“流式响应”?

这才是本文最精彩的部分!🔥

普通的 await response.json() 是等全部结果回来才解析。但我们想要“边来边显示”。

这时候就要用到 HTML5 的 ReadableStream

const reader = response.body.getReader()
const decoder = new TextDecoder()
let buffer = ''
let done = false

while (!done) {
  const { value, done: doneReading } = await reader.read()
  done = doneReading

  const chunk = buffer + decoder.decode(value)
  buffer = ''

  // 处理 SSE 格式:data: {...}
  const lines = chunk.split('\n').filter(line => line.startsWith('data: '))
  
  for (const line of lines) {
    const raw = line.slice(6) // 去掉"data: "
    if (raw === '[DONE]') {
      done = true
      break
    }

    try {
      const data = JSON.parse(raw)
      const text = data.choices[0]?.delta?.content
      if (text) {
        content.value += text // 逐段追加!
      }
    } catch (err) {
      buffer = line // 解析失败就暂存
    }
  }
}

🎯 关键点解析:

技术作用
response.body.getReader()获取流读取器
TextDecoder将 Uint8Array 转为字符串
data: {...}Server-Sent Events (SSE) 协议格式
buffer 缓冲区防止数据被截断导致 JSON 解析失败

👉 这样就能做到:AI 每生成一个 token,页面就多显示一个字,宛如现场写作!


💬 实际效果演示

假设你输入:

“讲一个喜羊羊与灰太狼的故事,200字”

你会看到这样的输出过程:

从前,在青青草原上……
住着一群可爱的小羊。
喜羊羊聪明勇敢,总是能识破灰太狼的诡计……
一天,灰太狼又想出了新花样……
他伪装成送快递的……
却被沸羊羊一眼识破!
大家哈哈大笑,灰太狼又一次失败而归。
虽然他总说“我一定会回来的”,但其实……
他已经悄悄喜欢上了红太狼做的蛋炒饭。
故事告诉我们:善良和智慧才是真正的力量!

每个字都像是“打”出来的,体验感拉满!🎥


🛠️ 模板部分也很重要

我们的界面很简单,但足够说明问题:

<template>
  <div class="container">
    <div>
      <label>请输入:</label>
      <input class="input" v-model="question"/>
      <button @click="askLLM">提交</button>
    </div>

    <div class="output">
      <label>启用流式输出</label>
      <input type="checkbox" v-model="stream">
      <div>{{ content }}</div>
    </div>
  </div>
</template>

用了 v-model 实现双向绑定,用户输入实时同步到 question,点击按钮触发 askLLM()

还可以通过勾选 checkbox 控制是否开启流式模式,方便对比体验差异!


🎨 简单美化一下

加点 CSS 让它不那么“程序员风”:

.container {
  padding: 20px;
  font-family: 'Arial', sans-serif;
  max-width: 800px;
  margin: 0 auto;
}

.input {
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

button {
  padding: 8px 16px;
  background: #2d8cf0;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.output {
  margin-top: 20px;
  min-height: 300px;
  white-space: pre-wrap;
  background: #f9f9f9;
  padding: 15px;
  border-radius: 6px;
  border: 1px dashed #ddd;
}

现在看起来是不是专业多了?😎


🚨 注意事项 & 常见坑

  1. API Key 安全性
    不要把 Key 写死在代码里!使用 import.meta.env.VITE_XXX,且不要提交 .env 到 Git。

  2. 流式数据可能断片
    网络传输中 JSON 可能被切开,必须用 buffer 缓存未完成的部分。

  3. 错误处理要到位
    try/catch,避免因一条坏数据导致整个流崩溃。

  4. 关闭流?不需要
    浏览器会自动处理 reader.close(),我们只需关注 done 信号。


🌈 扩展思路:还能怎么玩?

  • ✅ 添加“停止生成”按钮,中断流读取
  • ✅ 支持 Markdown 渲染(用 marked 库)
  • ✅ 历史记录保存(localStorage)
  • ✅ 语音朗读(Web Speech API)
  • ✅ 多轮对话(维护 messages 数组)

未来你可以把它做成自己的 AI 助手面板🤖,甚至接入微信公众号后台!


📝 总结:前端也能玩转 AI!

通过本文,你学会了:

✅ 如何用 Vue3 构建响应式界面
✅ 如何调用 LLM API 并处理 JSON 响应
✅ 如何使用 ReadableStream 实现流式输出
✅ 如何优雅地处理 SSE 数据格式
✅ 如何提升 AI 交互的用户体验

🎉 一句话总结:

“让用户早点看到第一个字,比让他等五秒看到全部更重要。”

这就是流式输出的魅力所在。


📣 最后彩蛋:试试这些有趣的问题!

- “用鲁迅的口吻批评拖延症”
- “如果孙悟空去考公务员,面试题会是什么?”
- “写一首关于前端工程师的诗,藏头‘BUG难改’”
- “让马冬梅和贾宝玉一起破案”

看看 AI 是如何一字一句“表演”出来的吧!🎭

💬 评论区互动:你还想让 AI 怎么“表演”?留言告诉我,下期我们一起实现!


🔖 标签推荐:#Vue3 #AI #流式输出 #前端开发 #DeepSeek #大模型 #WebStream #掘金热门 #CSDN精选