实现用户输入打断大模型流式输出:基于Vue与FastAPI的方案

发布于:2025-08-18 ⋅ 阅读:(20) ⋅ 点赞:(0)

在大模型交互场景中,流式输出能显著提升用户体验,但当用户进行新输入时,需要立即中断当前输出。本文将详细介绍两种实现方案(SSE协议与Fetch API),基于Vue前端和FastAPI后端,实现"用户输入打断大模型流式输出"的完整功能。

技术原理概述

大模型的流式输出本质是服务器采用分块传输(Chunked Transfer Encoding) 逐步返回数据。中断机制的核心是:

  1. 前端监测到用户新输入时,立即终止当前连接/请求
  2. 后端检测到连接中断后,停止模型生成并释放资源
  3. 建立新连接处理新输入

两种主流实现方式各有优势:

  • SSE(Server-Sent Events):基于HTTP长连接的服务器推送协议,原生支持流式传输
  • Fetch API:现代AJAX方案,通过ReadableStream处理分块响应,中断机制更灵活

前端实现(Vue)

方案一:基于SSE的实现

SSE通过EventSource对象实现,适合简单的单向流式传输场景:

<template>
  <div class="chat-container">
    <div class="message-list" v-html="messageContent"></div>
    <div class="input-area">
      <input 
        v-model="userInput" 
        @input="handleUserInput" 
        placeholder="输入内容..."
      >
      <button @click="sendMessage">发送</button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      userInput: '',
      messageContent: '',
      eventSource: null,   // SSE连接实例
      debounceTimer: null
    }
  },
  beforeUnmount() {
    this.closeSSEConnection();
  },
  methods: {
    handleUserInput() {
      if (this.debounceTimer) clearTimeout(this.debounceTimer);
      this.closeSSEConnection();  // 中断当前连接
      
      this.debounceTimer = setTimeout(() => {
        if (this.userInput.trim()) this.sendMessage();
      }, 300);
    },
    
    sendMessage() {
      const query = encodeURIComponent(this.userInput.trim());
      this.messageContent = '思考中...';
      
      // 建立SSE连接
      this.eventSource = new EventSource(`/api/sse-stream?query=${query}`);
      
      this.eventSource.onmessage = (event) => {
        this.messageContent = event.data;  // 实时更新内容
      };
      
      this.eventSource.onerror = () => this.closeSSEConnection();
    },
    
    closeSSEConnection() {
      if (this.eventSource) {
        this.eventSource.close();  // 中断SSE连接
        this.eventSource = null;
      }
    }
  }
};
</script>

方案二:基于Fetch API的实现

Fetch通过ReadableStream处理流式响应,中断机制更灵活,适合复杂交互场景:

<template>
  <div class="chat-container">
    <div class="message-list" v-html="messageContent"></div>
    <div class="input-area">
      <input 
        v-model="userInput" 
        @input="handleUserInput" 
        placeholder="输入内容..."
      >
      <button @click="sendMessage">发送</button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      userInput: '',
      messageContent: '',
      abortController: null,  // Fetch中断控制器
      debounceTimer: null,
      reader: null             // 流读取器
    }
  },
  beforeUnmount() {
    this.abortCurrentRequest();
  },
  methods: {
    handleUserInput() {
      if (this.debounceTimer) clearTimeout(this.debounceTimer);
      this.abortCurrentRequest();  // 中断当前请求
      
      this.debounceTimer = setTimeout(() => {
        if (this.userInput.trim()) this.sendMessage();
      }, 300);
    },
    
    async sendMessage() {
      const query = encodeURIComponent(this.userInput.trim());
      this.messageContent = '思考中...';
      
      // 创建新的中断控制器
      this.abortController = new AbortController();
      const { signal } = this.abortController;
      
      try {
        const response = await fetch(`/api/fetch-stream?query=${query}`, { sig

网站公告

今日签到

点亮在社区的每一天
去签到