最近在做一个智能客服项目时,我尝试了市面上多个AI对话接口,最终选择了DeepSeek。原因很简单:它的响应速度快、上下文理解能力强,而且API设计非常友好。Vue3作为当前最流行的前端框架之一,与DeepSeek的结合能快速打造出流畅的智能对话体验。
DeepSeek的API支持流式响应,这意味着用户不需要等待整个回答生成完毕就能看到部分内容。在实际项目中,这种即时反馈能显著提升用户体验。我测试过,从发送请求到收到第一个字符响应,平均只需要200-300毫秒,这在对话场景中几乎感觉不到延迟。
另一个重要优势是DeepSeek支持长文本上下文记忆。在传统对话系统中,开发者需要自己维护对话历史,而DeepSeek可以自动处理多轮对话的上下文关联。我在一个电商客服项目中实测,即使用户连续问了5-6个相关问题,AI也能保持很好的连贯性。
首先确保你的开发环境已经安装了Node.js(建议版本16+)。打开终端,运行以下命令创建一个新的Vue3项目:
bash复制npm init vue@latest vue-deepseek-chat
进入项目目录并安装必要依赖:
bash复制cd vue-deepseek-chat
npm install
我推荐使用Vite作为构建工具,它的热更新速度比传统webpack快很多。在项目创建时选择TypeScript支持会让代码更健壮,特别是处理API响应时类型检查很有帮助。
DeepSeek官方提供了JavaScript SDK,安装非常简单:
bash复制npm install openai
注意这里虽然包名是"openai",但完全兼容DeepSeek的API规范。我在多个项目中验证过这个包的稳定性,特别是在处理流式响应时表现很可靠。
前往DeepSeek官网注册账号并获取API Key。安全起见,我建议将API Key存储在环境变量中。在项目根目录创建.env文件:
env复制VITE_DEEPSEEK_API_KEY=你的API密钥
然后在vite.config.js中配置环境变量:
javascript复制export default defineConfig({
// ...其他配置
define: {
'process.env': process.env
}
})
在src/utils/chat.js中创建API客户端:
javascript复制import OpenAI from 'openai'
const openai = new OpenAI({
baseURL: 'https://api.deepseek.com',
apiKey: import.meta.env.VITE_DEEPSEEK_API_KEY,
dangerouslyAllowBrowser: true
})
export const createChatCompletion = async (messages) => {
return openai.chat.completions.create({
model: 'deepseek-chat',
messages,
stream: true
})
}
这里有几个关键点需要注意:
dangerouslyAllowBrowser必须设为true,因为我们在浏览器端直接调用APIstream: true开启流式响应创建一个ChatWindow.vue组件:
vue复制<script setup>
import { ref } from 'vue'
import { createChatCompletion } from '@/utils/chat'
const messages = ref([])
const inputMessage = ref('')
const isLoading = ref(false)
const handleSend = async () => {
if (!inputMessage.value.trim()) return
const userMessage = { role: 'user', content: inputMessage.value }
messages.value.push(userMessage)
const assistantMessage = { role: 'assistant', content: '' }
messages.value.push(assistantMessage)
isLoading.value = true
inputMessage.value = ''
try {
const response = await createChatCompletion(messages.value)
for await (const chunk of response) {
const content = chunk.choices[0]?.delta?.content || ''
assistantMessage.content += content
}
} catch (error) {
assistantMessage.content = '抱歉,出现了一些问题,请稍后再试。'
console.error('API调用失败:', error)
} finally {
isLoading.value = false
}
}
</script>
这个实现有几个亮点:
for await...of处理流式响应为了提升对话连贯性,我们需要妥善管理对话历史。创建一个独立的store:
javascript复制// stores/chat.js
import { ref } from 'vue'
import { defineStore } from 'pinia'
export const useChatStore = defineStore('chat', () => {
const history = ref([])
const MAX_HISTORY = 10 // 限制历史记录条数
const addMessage = (message) => {
history.value.push(message)
if (history.value.length > MAX_HISTORY) {
history.value.shift() // 移除最旧的消息
}
}
return { history, addMessage }
})
然后在聊天组件中使用这个store:
vue复制<script setup>
import { useChatStore } from '@/stores/chat'
const chatStore = useChatStore()
// 发送消息时
chatStore.addMessage(userMessage)
chatStore.addMessage(assistantMessage)
</script>
为了让消息显示更自然,可以添加打字机动画:
vue复制<template>
<div class="message" v-for="(msg, index) in messages" :key="index">
<div v-if="msg.role === 'assistant' && index === messages.length - 1 && isLoading">
<span v-for="(char, i) in msg.content" :key="i" class="char" :style="{ animationDelay: `${i * 0.05}s` }">
{{ char }}
</span>
</div>
<div v-else>
{{ msg.content }}
</div>
</div>
</template>
<style>
.char {
display: inline-block;
opacity: 0;
animation: appear 0.1s forwards;
}
@keyframes appear {
to { opacity: 1; }
}
</style>
使用localStorage保存对话历史:
javascript复制// stores/chat.js
const loadHistory = () => {
const saved = localStorage.getItem('chatHistory')
if (saved) history.value = JSON.parse(saved)
}
const saveHistory = () => {
localStorage.setItem('chatHistory', JSON.stringify(history.value))
}
// 在addMessage中调用saveHistory
javascript复制import { debounce } from 'lodash-es'
const debouncedSend = debounce(handleSend, 300)
javascript复制const controller = new AbortController()
try {
const response = await createChatCompletion({
...options,
signal: controller.signal
})
// ...
} finally {
controller.abort()
}
vue复制<template>
<button :disabled="isLoading">
{{ isLoading ? '思考中...' : '发送' }}
</button>
</template>
在实际集成过程中,我遇到过几个典型问题:
问题1:跨域错误
解决方案:确保在DeepSeek客户端配置中设置了dangerouslyAllowBrowser: true。如果使用代理,需要在vite.config.js中配置:
javascript复制server: {
proxy: {
'/api': {
target: 'https://api.deepseek.com',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '')
}
}
}
问题2:流式响应中断
可能原因:网络不稳定或API限制。我的解决方案是:
问题3:长响应超时
DeepSeek处理复杂问题时可能需要较长时间。我添加了以下优化:
javascript复制const TIMEOUT = 30000
const timeoutId = setTimeout(() => {
controller.abort()
assistantMessage.content = '响应超时,请尝试简化您的问题。'
}, TIMEOUT)
// 在finally中清除定时器
clearTimeout(timeoutId)
当你的智能对话应用开发完成后,可以考虑以下几种部署方案:
方案1:静态站点部署
适用于纯前端实现:
bash复制npm run build
将生成的dist目录上传到任何静态托管服务(Vercel、Netlify等)
方案2:结合后端服务
如果需要保护API密钥,可以:
性能监控建议:
我在实际项目中发现,使用Vercel的边缘函数部署前端+API路由的方案性价比最高,全球访问速度快,而且能很好地保护API密钥。