调用通义千问大模型实现流式对话

前言

我使用的是硅基流动中通义千问免费的大模型:

我的技术栈使用的 Next14.2 全栈框架。

代码结构

需要使用的库:

bash 复制代码
npm i ai openai

目录结构:

基础测试页面 test-openai/page.tsx:

tsx 复制代码
'use client';

import { useChat } from 'ai/react';

export default function TestDeepseek() {
  const { messages, input, handleInputChange, handleSubmit } = useChat({
    api: '/api/chat/openai',
  });
  
  return (
    <div className="flex flex-col w-full max-w-md py-24 mx-auto stretch">
      <h1 className="text-2xl font-bold mb-4">Deepseek 聊天测试</h1>
      
      {messages.map(message => (
        <div key={message.id} className="whitespace-pre-wrap mb-4 p-3 border rounded-lg">
          <div className="font-bold">{message.role === 'user' ? '用户: ' : 'AI: '}</div>
          <div className="mt-1">{message.content}</div>
        </div>
      ))}
      
      <form onSubmit={handleSubmit} className="mt-4">
        <input
          className="w-full p-2 border border-gray-300 rounded shadow-sm dark:bg-gray-800 dark:border-gray-700"
          value={input}
          placeholder="输入消息..."
          onChange={handleInputChange}
        />
        <button 
          type="submit" 
          className="mt-2 w-full p-2 bg-blue-500 text-white rounded hover:bg-blue-600"
        >
          发送
        </button>
      </form>
    </div>
  );
}

后端接口 app/api/chat/openai/route.ts:

ts 复制代码
import { handleChatRequest } from '@/lib/openai';
import { NextRequest, NextResponse } from 'next/server';
import { MessageRequestBody } from '@/types/chat';

// 设置最大响应时间为30秒
export const maxDuration = 30;

/**
 * 处理POST请求,使用QwQ-32B模型进行聊天
 * 
 * @param request NextRequest请求对象
 * @returns 返回流式响应
 */
export async function POST(request: NextRequest) {
  try {
    // 从请求中获取消息数据
    const { messages } = (await request.json()) as MessageRequestBody;
    
    if (!messages || !Array.isArray(messages)) {
      return NextResponse.json(
        { error: '无效的消息格式' },
        { status: 400 }
      );
    }
    
    // 调用QwQ-32B处理函数并返回流式响应
    return handleChatRequest(messages);
  } catch (error) {
    console.error('处理QwQ-32B请求时出错:', error);
    return NextResponse.json(
      { error: '处理请求时发生错误: ' + (error instanceof Error ? error.message : String(error)) },
      { status: 500 }
    );
  }
}

lib/openai.ts

openai 规范调用大模型可以参考 deepseek文档:api-docs.deepseek.com/zh-cn/

也可以参考硅基流动的文档:docs.siliconflow.cn/cn/userguid...

ts 复制代码
import { Message } from '@/types/chat';
import { NextResponse } from 'next/server';
import OpenAI from 'openai';

// 创建自定义OpenAI实例,使用SiliconFlow API
const openai = new OpenAI({
  apiKey: process.env.SILICONFLOW_API_KEY!,
  baseURL: process.env.SILICONFLOW_API_BASE!,  
});

/**
 * 处理聊天请求的函数
 * 使用SiliconFlow API处理消息并返回流式响应
 * 
 * @param messages 聊天消息数组
 * @returns 流式响应
 */
export async function handleChatRequest(messages: Message[]) {
  try {
    // 检查API密钥是否配置
    if (!process.env.SILICONFLOW_API_KEY) {
      console.error('SiliconFlow API密钥未配置');
      return NextResponse.json(
        { error: '未配置SiliconFlow API密钥,请在.env文件中设置SILICONFLOW_API_KEY' },
        { status: 500 }
      );
    }

    // 检查API基础URL是否配置
    if (!process.env.SILICONFLOW_API_BASE) {
      console.error('SiliconFlow API基础URL未配置');
      return NextResponse.json(
        { error: '未配置SiliconFlow API基础URL,请在.env文件中设置SILICONFLOW_API_BASE' },
        { status: 500 }
      );
    }

    // 将消息格式转换为OpenAI格式
    const formattedMessages = messages.map(msg => ({
      role: msg.role,
      content: msg.content
    }));
    
    // 使用SiliconFlow API创建流式响应
    const response = await openai.chat.completions.create({
      model: 'Qwen/QwQ-32B', // 使用SiliconFlow提供的QwQ-32B模型
      messages: formattedMessages,
      stream: true,
    });
    
    // 创建并返回流式响应
    const encoder = new TextEncoder();
    const stream = new ReadableStream({
      async start(controller) {
        // 处理流式响应
        for await (const chunk of response) {
          const text = chunk.choices[0]?.delta?.content || '';
          if (text) {
            controller.enqueue(encoder.encode(text));
          }
        }
        controller.close();
      },
    });
    
    return new Response(stream, {
      headers: {
        'Content-Type': 'text/plain; charset=utf-8',
        'Cache-Control': 'no-cache',
      },
    });
  } catch (error) {
    console.error('SiliconFlow API调用错误:', error);
    return NextResponse.json(
      { error: '调用SiliconFlow API时发生错误: ' + (error instanceof Error ? error.message : String(error)) },
      { status: 500 }
    );
  }
}

.env

ini 复制代码
# SILICONFLOW API密钥
SILICONFLOW_API_KEY=YOUR_API_KEY
SILICONFLOW_API_BASE=https://api.siliconflow.cn/v1

# 其他环境变量

演示

相关推荐
To_OC4 小时前
LC 128 最长连续序列:别上来就排序,O (n) 解法才是这题的灵魂
javascript·算法·leetcode
葫芦和十三4 小时前
图解 MongoDB 13|WiredTiger 存储引擎:B-tree、页和 checkpoint 三件套
后端·mongodb·agent
葫芦和十三4 小时前
图解 MongoDB 14|Cache 与淘汰:WiredTiger 的内存治理
后端·mongodb·面试
IT_陈寒8 小时前
Vue这个坑我跳了两次,原来问题出在这
前端·人工智能·后端
kyriewen8 小时前
我用 50 行代码重写了 React Router 核心,终于搞懂了前端路由原理
前端·javascript·react.js
ServBay9 小时前
9 个 Python 第三方库推荐,不用 AI 都好像多出一个团队
后端·python
用户8356290780519 小时前
如何使用 Python 添加和管理 Excel 批注(完整示例)
后端·python
WebInfra9 小时前
Rspack 2.1 发布:React Compiler 提速 10 倍!
前端
用户8356290780519 小时前
使用 Python 管理 Excel 工作表:创建、复制、删除与重命名
后端·python
lizhongxuan9 小时前
Agent Tool
后端