前端实现AI对话:使用SSE技术提升实时交互体验

更新日期: 2025-09-20阅读: 74标签: SSE

在现代前端开发中,AI智能对话功能越来越常见。实现这类功能时,关键是要让用户能够实时看到AI返回的内容,而不是等待全部生成完毕才显示。Server-Sent Events(SSE)技术为此提供了一种高效且易于实现的解决方案。


什么是SSE?

SSE是一种基于HTTP的服务器向客户端实时推送数据的技术。它与WebSocket不同,SSE是单向通信,只支持服务器向客户端发送数据。这种特性使得SSE特别适合AI对话场景,因为通常只需要服务器持续向客户端推送AI生成的文本内容。

SSE有几个重要特点:

  • 基于HTTP协议,无需额外协议

  • 内置自动重连机制

  • 支持文本数据格式

  • 浏览器原生支持EventSource api


基础使用方法

最简单的SSE请求可以通过浏览器原生的EventSource实现:

const eventSource = new EventSource('/api/chat/stream');

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  // 将内容显示在界面上
};

eventSource.onerror = (error) => {
  console.error('连接出错:', error);
  eventSource.close();
};

但这种方法有局限性:无法自定义请求头、只能使用GET方法、数据格式受限。因此在实际项目中,我们通常需要更灵活的解决方案。


更实用的实现方式

使用fetch API配合ReadableStream可以更好地处理SSE流:

async function handleAIStream(prompt) {
  const response = await fetch('/api/chat/stream', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer your_token'
    },
    body: JSON.stringify({ message: prompt })
  });

  if (!response.ok) {
    throw new Error('请求失败');
  }

  const reader = response.body.getReader();
  const decoder = new TextDecoder();

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

    const chunk = decoder.decode(value);
    const lines = chunk.split('\n');

    for (const line of lines) {
      if (line.startsWith('data: ')) {
        const dataStr = line.slice(6).trim();
        if (dataStr === '[DONE]') break;
        
        try {
          const data = JSON.parse(dataStr);
          // 更新界面显示
          updateUI(data.content);
        } catch (e) {
          console.warn('解析数据失败', e);
        }
      }
    }
  }
}

这种方法支持POST请求、自定义请求头,并且可以灵活处理各种数据格式。


封装可复用的工具函数

为了提高代码复用性,我们可以将流式请求封装成独立函数:

export async function createAIStream(url, options) {
  const { 
    prompt, 
    onMessage, 
    onError, 
    onComplete,
    token 
  } = options;

  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': token ? `Bearer ${token}` : ''
      },
      body: JSON.stringify({ message: prompt })
    });

    if (!response.ok) {
      throw new Error(`请求失败: ${response.status}`);
    }

    const reader = response.body.getReader();
    const decoder = new TextDecoder();

    while (true) {
      const { done, value } = await reader.read();
      if (done) {
        onComplete?.();
        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.slice(6).trim();
          if (dataStr === '[DONE]') {
            onComplete?.();
            return;
          }
          
          try {
            const data = JSON.parse(dataStr);
            onMessage?.(data);
          } catch (e) {
            console.warn('解析JSON失败', e);
          }
        }
      }
    }
  } catch (error) {
    onError?.(error);
  }
}

使用这个函数时:

createAIStream('/api/chat/stream', {
  prompt: '你好,请介绍SSE技术',
  token: 'your_token',
  onMessage: (data) => {
    // 处理每条消息
    appendToChat(data.content);
  },
  onError: (error) => {
    showError(error.message);
  },
  onComplete: () => {
    setLoading(false);
  }
});


优化用户体验

为了让AI对话体验更好,可以考虑以下优化措施:

  1. 实现打字机效果:逐字显示内容,而不是一次性显示整段文字

  2. 添加中断功能:允许用户停止正在进行的对话

  3. 处理网络异常:实现自动重连机制

  4. 管理对话历史:保持多轮对话的连贯性

使用AbortController可以实现请求中断:

const controller = new AbortController();

// 在fetch选项中添加
fetch(url, {
  signal: controller.signal
});

// 需要中断时
controller.abort();


react项目中的实现

在React项目中,可以使用自定义Hook来管理AI流式对话:

import { useState, useCallback } from 'react';

export function useAIStream() {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const startStream = useCallback(async (url, options) => {
    setLoading(true);
    setError(null);
    
    const controller = new AbortController();
    
    try {
      const response = await fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': options.token ? `Bearer ${options.token}` : ''
        },
        body: JSON.stringify({ message: options.prompt }),
        signal: controller.signal
      });

      // 处理响应流...
      
    } catch (err) {
      setError(err.message);
      options.onError?.(err);
    } finally {
      setLoading(false);
    }
    
    return () => controller.abort();
  }, []);

  return { startStream, loading, error };
}


总结

SSE技术为前端实现AI对话功能提供了简单有效的解决方案。通过fetch API和ReadableStream,我们可以灵活地处理流式数据,实现良好的用户体验。

关键要点:

  • SSE适合服务器向客户端推送数据的场景

  • 使用fetch比原生EventSource更灵活

  • 适当封装可以提高代码复用性

  • 考虑用户体验优化,如中断功能、错误处理等

选择SSE而不是WebSocket的原因主要是:AI对话通常只需要单向数据流,SSE基于HTTP协议更简单,且不需要额外的协议升级处理。

通过合理的实现和优化,前端可以高效地处理AI流式对话,为用户提供流畅的交互体验。


本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!

链接: https://fly63.com/article/detial/12925

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!