掘金 人工智能 06月11日 10:53
AI 组件库-MateChat × 大模型:DeepSeek、OpenAI 和 阿里通义问 (Qwen)的全流程接入实战(三)
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文介绍了如何使用MateChat前端框架,通过简单的配置和代码调整,实现DeepSeek、OpenAI和阿里通义千问(Qwen)等不同大模型的快速切换。文章详细阐述了环境准备、依赖安装、环境变量配置、通用模型适配器Hook的实现,以及如何通过Hooks实现模型的动态切换。此外,还提供了常见问题的解决方案,帮助开发者轻松应对。

🔑 MateChat通过解耦推理逻辑,允许开发者通过修改API Key、BASE_URL和model名称,即可在DeepSeek、OpenAI和阿里通义千问(Qwen)之间自由切换,无需改动MateChat核心代码。

⚙️ 环境准备阶段,需要安装openai NPM包,并配置环境变量,针对不同的模型,设置不同的VITE_LLM_URL、VITE_LLM_MODEL和VITE_LLM_KEY。

🛠️ 核心在于通用「模型适配器」Hook,通过OpenAI SDK进行流式请求,并统一解析不同厂商的增量字段,简化了不同模型之间的调用差异。

🔄 通过配置package.json中的脚本,以及使用Hooks,可以实现模型的快速切换。例如,在App.vue中,通过选择不同的模型提供商,即可动态地切换到不同的模型。

MateChat × 大模型:DeepSeek、OpenAI 和 阿里 通义问 (Qwen)的全流程接入实战

一、MateChat 为何能“一键切换”多种模型?

MateChat 并不内置任何推理逻辑,而是把 “请求大模型 → 拆解响应 → 填充 messages” 这一段完全交给业务方。

只要你的模型 遵循 OpenAI-兼容的 Chat Completion 协议,改 3 行代码就能完成切换。

DeepSeek、OpenAI、阿里百炼的 通义千问 (Qwen) 都额外提供了 OpenAI-兼容的 Chat Completion 协议——

只要你换 API Key、BASE_URL、model 名称,MateChat 侧无需变动,即可来回切。

二、环境准备与包安装

依赖描述
openai NPM 包官方 SDK,DeepSeek 同样使用它
pnpm add openai         # 或 npm / yarn 官方 SDK,可同时调用 DeepSeek / OpenAI / Qwen

三、环境变量

将密钥写入环境变量最安全;在浏览器侧演示时可暂时放到 .env.*,但务必做好打包替换/代理。

.env.* 按模型划分:

# .env.deepseekVITE_LLM_URL=https://api.deepseek.comVITE_LLM_MODEL=deepseek-reasonerVITE_LLM_KEY=<DeepSeek-Key># .env.openaiVITE_LLM_URL=https://api.openai.com/v1VITE_LLM_MODEL=gpt-4oVITE_LLM_KEY=<OpenAI-Key># .env.qwen          VITE_LLM_URL=https://dashscope.aliyuncs.com/compatible-mode/v1  # 官方 BASE_URL  [oai_citation:1‡help.aliyun.com](https://help.aliyun.com/zh/model-studio/compatibility-of-openai-with-dashscope)VITE_LLM_MODEL=qwen-max                                         # 支持列表见文档  [oai_citation:2‡help.aliyun.com](https://help.aliyun.com/zh/model-studio/compatibility-of-openai-with-dashscope)VITE_LLM_KEY=<DashScope-API-Key>

四、通用「模型适配器」 Hook

1. Hook 代码

// hooks/useChatModel.tsimport OpenAI from 'openai';import { ref } from 'vue';// ★ 1. 用环境变量决定当前供应商export const client = new OpenAI({  apiKey:   import.meta.env.VITE_LLM_KEY,  baseURL:  import.meta.env.VITE_LLM_URL,  dangerouslyAllowBrowser: true});export function useChatModel(messages) {  async function send(question: string) {    messages.value.push({ from: 'user', content: question });    const idx = messages.value.push({ from: 'model', content: '', loading: true }) - 1;    // ★ 2. 发起流式请求——DeepSeek / OpenAI / Qwen 三选一,由 env 决定    const stream = await client.chat.completions.create({      model:    import.meta.env.VITE_LLM_MODEL,     // deepseek-reasoner / gpt-4o / qwen-max …      messages: [{ role: 'user', content: question }],      stream:   true                                // 非流式时设 false    });    messages.value[idx].loading = false;    // ★ 3. 不同厂商的增量字段完全一致 → 统一解析    for await (const chunk of stream) {      messages.value[idx].content += chunk.choices[0]?.delta?.content || '';    }  }  return { send };}

2. Hooks 使用

// App.vue (片段)const messages = ref([]);const { send } = useChatModel(messages);function onSubmit(text: string) {  if (!text) return;  send(text).catch(console.error);}

五、模型配置与切换

1. package.json 配置

{  "scripts": {    "dev:deepseek": "vite --mode deepseek",    "dev:openai":   "vite --mode openai",    "dev:qwen":     "vite --mode qwen",    "build:deepseek": "vite build --mode deepseek",    "build:openai":   "vite build --mode openai",    "build:qwen":     "vite build --mode qwen"  }}

2. 命令执行

执行命令Vite 会自动加载的文件(优先级从低到高)
vite --mode deepseek.env → .env.local → .env.deepseek → .env.deepseek.local
vite build --mode qwen.env → .env.local → .env.qwen → .env.qwen.local
无 --mode 参数 (vite dev).env → .env.local → .env.development → .env.development.local

六、使用 Hooks 切换

1. 项目结构

src/ ├─ App.vue ├─ constants/ │   └─ llmProviders.ts └─ hooks/     └─ useChatModelDynamic.ts

2. llmProviders.ts 文件

/** * LLM 提供商 */export interface LLMProvider {  label: string  value: 'deepseek' | 'openai' | 'qwen'  baseURL: string  model: string  apiKey: string}/** * LLM 提供商 */export const LLM_PROVIDERS: LLMProvider[] = [  {    label: 'DeepSeek',    value: 'deepseek',    baseURL: 'https://api.deepseek.com',    model: 'deepseek-reasoner',    apiKey: '<DeepSeek_API_Key>'  },  {    label: 'OpenAI',    value: 'openai',    baseURL: 'https://api.openai.com/v1',    model: 'gpt-4o',    apiKey: '<OpenAI_API_Key>'  },  {    label: 'Qwen (通义千问)',    value: 'qwen',    baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',    model: 'qwen-max',    apiKey: '<DashScope_API_Key>'  }]

3. useChatModelDynamic.ts 文件

import { ref, watch } from 'vue'import OpenAI from 'openai'import type { LLMProvider } from '../constants/llmProviders'/** * 聊天消息 */interface ChatMessage {  from: 'user' | 'model';  content: string;  loading?: boolean;}/** * 使用动态的 LLM 模型 * @param messages 聊天消息 * @param provider LLM 提供商 * @returns  */export function useChatModelDynamic(  messages: ReturnType<typeof ref<ChatMessage[]>>,  provider: ReturnType<typeof ref<LLMProvider>>) {  let client = createClient()  watch(provider, () => { client = createClient() })  function createClient() {    return new OpenAI({      apiKey: provider.value?.apiKey,      baseURL: provider.value?.baseURL,      dangerouslyAllowBrowser: true    })  }  const send = async (question: string) => {    if (!messages.value) return;        messages.value.push({ from: 'user', content: question })    const idx = messages.value.push({ from: 'model', content: '', loading: true }) - 1    const stream = await client.chat.completions.create({      model: provider.value?.model || '',      messages: [{ role: 'user', content: question }],      stream: true    })    if (!messages.value) return;        messages.value[idx].loading = false    for await (const chunk of stream) {      messages.value[idx].content += chunk.choices[0]?.delta?.content || ''    }  }  return { send }}

4. App.vue

<template>  <div class="container">    <!-- 顶部:模型切换 -->    <div class="toolbar">      <label>选择模型:</label>      <select v-model="currentValue">        <option v-for="p in PROVIDERS" :key="p.value" :value="p.value">          {{ p.label }}        </option>      </select>    </div>    <!-- MateChat 对话区 -->    <McLayout class="board">      <McLayoutContent class="content">        <template v-for="(m, i) in messages" :key="i">          <McBubble :content="m.content" :loading="m.loading" :align="m.from === 'user' ? 'right' : 'left'"            :avatarConfig="m.from === 'user' ? userAvatar : modelAvatar" />        </template>      </McLayoutContent>      <McLayoutSender>        <McInput :value="input" @change="(v: string) => input = v" @submit="onSubmit" />      </McLayoutSender>    </McLayout>  </div></template><script setup lang="ts">import { ref, computed } from 'vue'import { LLM_PROVIDERS as PROVIDERS } from './constants/llmProviders'import { useChatModelDynamic } from './hooks/useChatModelDynamic'const currentValue = ref<'deepseek' | 'openai' | 'qwen'>('deepseek')const provider = computed(() => PROVIDERS.find(p => p.value === currentValue.value)!)const messages = ref<any[]>([])const input = ref('')const { send } = useChatModelDynamic(messages, provider)function onSubmit(text: string) {  if (!text.trim()) return  send(text).catch(err => alert(err.message))  input.value = ''}const userAvatar = { imgSrc: 'https://matechat.gitcode.com/png/demo/userAvatar.svg' }const modelAvatar = { imgSrc: 'https://matechat.gitcode.com/logo.svg' }</script><style scoped>.container {  max-width: 800px;  margin: 24px auto;  display: flex;  flex-direction: column;  gap: 16px;}.toolbar {  display: flex;  gap: 8px;  align-items: center;}.board {  height: calc(100vh - 150px);  display: flex;  flex-direction: column;}.content {  flex: 1;  overflow: auto;  display: flex;  flex-direction: column;  gap: 8px;}</style>

5. UI

七、常见问题&解决方案

问题可能原因处理方案
401: Authentication failedKey 过期 / 填错检查 VITE_LLM_KEY 是否正确;Qwen Key 请到「百炼控制台 → API Key」重新生成
404: model_not_foundVITE_LLM_MODEL 拼错DeepSeek 用 deepseek-,Qwen 用 qwen-,注意大小写
SSE 一直断线本地 HTTP 或代理剪掉 text/event-stream开启 vite preview --https 或通过自家后端代理
中文 Markdown 乱码未给 McMarkDown 注入高亮器import 'highlight.js/styles/github-dark.css' 并在组件挂载后 hljs.highlightAll()

八、总结

    MateChat + 统一 Hook的一套前端,可随时切换 DeepSeek OpenAI 通义千问 (Qwen)

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

MateChat 大模型 DeepSeek OpenAI Qwen
相关文章