大模型:阿里云百炼 + FastAPI + Vue3 实现单轮与流式 AI 对话

发布时间:2026/8/4 5:22:13
大模型:阿里云百炼 + FastAPI + Vue3 实现单轮与流式 AI 对话 1. 引言从零打通大模型阿里云百炼 FastAPI Vue3 实现单轮与流式 AI 对话附 CSDN 实战摘要本文是一份完整的全栈开发实战指南详细介绍了如何从零开始构建一个支持单轮与流式对话的 AI 应用。文章以阿里云百炼Bailian作为大模型服务底座使用 FastAPI 构建高效后端 API并采用 Vue3 开发现代化前端界面。内容涵盖技术栈准备、项目结构初始化、后端服务集成、前端界面实现等完整开发流程提供了可直接运行的代码示例和详细的部署指南适合前端、后端及全栈开发者参考实践。在人工智能浪潮席卷全球的今天大语言模型LLM已成为开发者手中最炙手可热的工具。然而如何将强大的模型能力快速、稳定地集成到自己的应用中构建出体验流畅的 AI 对话功能是许多开发者面临的挑战。本文将带你从零开始手把手搭建一个完整的 AI 对话应用。我们将以阿里云百炼Bailian作为大模型服务底座使用FastAPI构建高效、易用的后端 API并采用Vue3开发现代化的前端交互界面。你将学习到单轮对话的实现如何发送请求并接收完整的模型回复。流式对话Streaming的实现如何实现打字机式的逐字输出效果极大提升用户体验。前后端分离架构的实践清晰的分层与通信方式。完整的项目部署与实战提供可直接运行的代码示例和 CSDN 博客同步指南。无论你是前端、后端还是全栈开发者本文都将为你提供一条清晰、可行的技术路径。2. 技术栈与工具准备在开始编码之前请确保你的开发环境已就绪。2.1 后端技术栈 (FastAPI)Python 3.8FastAPI: 现代、快速高性能的 Web 框架用于构建 API。Uvicorn: ASGI 服务器用于运行 FastAPI 应用。阿里云百炼 SDK: 官方 Python SDK用于调用百炼模型。Pydantic: 用于数据验证和设置管理。python-dotenv: 管理环境变量。2.2 前端技术栈 (Vue3)Node.js 18Vue 3与Composition APIVite: 下一代前端构建工具启动极快。Axios: HTTP 客户端用于调用后端 API。Element Plus(可选): 基于 Vue 3 的组件库用于快速搭建 UI。2.3 阿里云百炼准备开通服务访问 阿里云百炼控制台开通百炼服务。获取密钥在控制台创建 AccessKeyAccessKey ID 和 AccessKey Secret并妥善保管。选择模型百炼提供了多种模型如 Qwen、Baichuan 等本文以qwen-max为例你也可以根据需求选择其他模型。2.4 初始化项目结构创建项目根目录ai-chat-demo并初始化如下结构ai-chat-demo/ ├── backend/ # FastAPI 后端项目 │ ├── app/ │ │ ├── __init__.py │ │ ├── main.py # FastAPI 应用入口 │ │ ├── api/ # 路由模块 │ │ ├── core/ # 核心配置 │ │ └── services/ # 业务逻辑如调用百炼 │ ├── requirements.txt │ └── .env.example └── frontend/ # Vue3 前端项目 ├── src/ │ ├── App.vue │ ├── main.js │ └── views/ # 页面组件 ├── package.json └── vite.config.js3. 后端开发FastAPI 集成阿里云百炼3.1 安装依赖进入backend目录创建requirements.txtfastapi0.104.1 uvicorn[standard]0.24.0 alibabacloud_bailian202312291.0.1 pydantic2.5.0 pydantic-settings2.1.0 python-dotenv1.0.0 cors1.0.1运行pip install -r requirements.txt安装。3.2 配置管理创建app/core/config.py使用 Pydantic 管理配置从环境变量读取百炼密钥。frompydantic_settingsimportBaseSettingsclassSettings(BaseSettings):# 阿里云百炼配置BAILIAN_ACCESS_KEY_ID:strBAILIAN_ACCESS_KEY_SECRET:strBAILIAN_AGENT_KEY:str# 代理密钥非必填BAILIAN_MODEL_ID:strqwen-max# 默认使用 qwen-maxBAILIAN_ENDPOINT:strbailian.cn-beijing.aliyuncs.com# 应用配置APP_HOST:str0.0.0.0APP_PORT:int8000DEBUG:boolFalseclassConfig:env_file.envsettingsSettings()创建.env文件参考.env.example并填入你的密钥BAILIAN_ACCESS_KEY_IDyour_access_key_id BAILIAN_ACCESS_KEY_SECRETyour_access_key_secret # BAILIAN_AGENT_KEYyour_agent_key (可选)3.3 创建百炼服务创建app/services/bailian_service.py封装调用逻辑。importjsonfromtypingimportAsyncGeneratorfromalibabacloud_bailian20231229importmodelsasbailian_modelsfromalibabacloud_tea_openapiimportmodelsasopen_api_modelsfromalibabacloud_bailian20231229.clientimportClientasBailianClientfromapp.core.configimportsettingsclassBailianService:def__init__(self):# 初始化百炼客户端configopen_api_models.Config(access_key_idsettings.BAILIAN_ACCESS_KEY_ID,access_key_secretsettings.BAILIAN_ACCESS_KEY_SECRET,endpointsettings.BAILIAN_ENDPOINT,)self.clientBailianClient(config)self.model_idsettings.BAILIAN_MODEL_IDasyncdefcreate_completion(self,prompt:str,stream:boolFalse):创建单轮对话非流式requestbailian_models.CreateCompletionRequest(model_idself.model_id,promptprompt,streamFalse,# 单轮关闭流式parameters{result_format:text,max_tokens:2000,})try:respself.client.create_completion(request)returnresp.body.data.textexceptExceptionase:raiseException(f百炼 API 调用失败:{e})asyncdefcreate_completion_stream(self,prompt:str)-AsyncGenerator[str,None]:创建流式对话requestbailian_models.CreateCompletionRequest(model_idself.model_id,promptprompt,streamTrue,# 开启流式parameters{result_format:text,max_tokens:2000,})try:# 注意SDK 的流式响应可能需要特殊处理这里为示例逻辑respself.client.create_completion_with_options(request,runtimeNone)# 假设 resp 是一个可迭代的流式响应体forchunkinresp:ifhasattr(chunk,data)andchunk.data:yieldchunk.data.textexceptExceptionase:yieldf[流式输出错误:{e}]bailian_serviceBailianService()3.4 创建 API 路由创建app/api/endpoints/chat.py定义对话接口。fromfastapiimportAPIRouter,HTTPExceptionfromfastapi.responsesimportStreamingResponsefrompydanticimportBaseModelfromapp.services.bailian_serviceimportbailian_serviceimportasyncio routerAPIRouter()classChatRequest(BaseModel):message:strstream:boolFalse# 是否使用流式输出router.post(/chat)asyncdefchat_completion(request:ChatRequest):处理聊天请求支持单轮和流式ifnotrequest.message.strip():raiseHTTPException(status_code400,detail消息不能为空)ifrequest.stream:# 流式响应asyncdefstream_generator():asyncforchunkinbailian_service.create_completion_stream(request.message):yieldfdata:{chunk}\n\nyielddata: [DONE]\n\nreturnStreamingResponse(stream_generator(),media_typetext/event-stream,headers{Cache-Control:no-cache,Connection:keep-alive,})else:# 单轮响应try:response_textawaitbailian_service.create_completion(request.message)return{response:response_text}exceptExceptionase:raiseHTTPException(status_code500,detailstr(e))3.5 主应用与 CORS 配置在app/main.py中创建 FastAPI 应用并挂载路由。fromfastapiimportFastAPIfromfastapi.middleware.corsimportCORSMiddlewarefromapp.api.endpointsimportchat appFastAPI(titleAI Chat API,version1.0.0)# 配置 CORS允许前端访问app.add_middleware(CORSMiddleware,allow_origins[http://localhost:5173],# Vite 默认前端地址allow_credentialsTrue,allow_methods[*],allow_headers[*],)# 挂载路由app.include_router(chat.router,prefix/api/v1,tags[chat])app.get(/)asyncdefroot():return{message:AI Chat API is running!}3.6 启动后端服务在backend目录下运行uvicorn app.main:app--reload--host0.0.0.0--port8000访问http://localhost:8000/docs即可查看自动生成的 API 文档并进行测试。4. 前端开发Vue3 实现对话界面4.1 初始化 Vue 项目使用 Vite 快速创建 Vue 项目# 在项目根目录下npmcreate vuelatest frontend# 按照提示选择 Vue 3, TypeScript, Router 等按需cdfrontendnpminstallnpminstallaxios element-plus# 安装所需依赖4.2 创建聊天组件创建src/views/ChatView.vue实现核心聊天界面。template div classchat-container h1 AI 对话助手 (阿里云百炼)/h1 div classchat-box !-- 消息列表 -- div classmessage-list refmessageListRef div v-for(msg, index) in messages :keyindex :class[message, msg.role] div classavatar{{ msg.role user ? : }}/div div classcontent div v-ifmsg.role user{{ msg.content }}/div div v-else !-- 流式输出时显示不断累积的内容 -- span v-ifmsg.isStreaming msg.streamContent{{ msg.streamContent }}/span span v-else{{ msg.content }}/span span v-ifmsg.isStreaming classstreaming-cursor▌/span /div /div /div /div !-- 输入区域 -- div classinput-area el-input v-modelinputMessage typetextarea :rows3 placeholder输入你的问题... keydown.enter.exact.preventhandleSend / div classactions el-checkbox v-modeluseStream启用流式输出/el-checkbox el-button typeprimary :loadingisLoading clickhandleSend {{ isLoading ? 思考中... : 发送 }} /el-button el-button clickclearChat清空对话/el-button /div /div /div /div /template script setup import { ref, computed, nextTick } from vue import axios from axios import { ElMessage } from element-plus const API_BASE http://localhost:8000/api/v1 const inputMessage ref() const useStream ref(true) const isLoading ref(false) const messages ref([]) const messageListRef ref(null) // 发送消息 const handleSend async () { const msg inputMessage.value.trim() if (!msg || isLoading.value) return // 添加用户消息 messages.value.push({ role: user, content: msg, timestamp: new Date() }) inputMessage.value // 添加一个空的 AI 消息占位 const aiMessageIndex messages.value.length messages.value.push({ role: assistant, content: , isStreaming: useStream.value, streamContent: }) isLoading.value true scrollToBottom() try { if (useStream.value) { await handleStreamResponse(msg, aiMessageIndex) } else { await handleNormalResponse(msg, aiMessageIndex) } } catch (error) { console.error(请求失败:, error) ElMessage.error(请求失败 error.message) // 移除失败的占位消息 messages.value.splice(aiMessageIndex, 1) } finally { isLoading.value false scrollToBottom() } } // 处理普通单轮响应 const handleNormalResponse async (userMsg, aiIndex) { const response await axios.post(${API_BASE}/chat, { message: userMsg, stream: false }) messages.value[aiIndex].content response.data.response messages.value[aiIndex].isStreaming false } // 处理流式响应 const handleStreamResponse async (userMsg, aiIndex) { const eventSource new EventSource(${API_BASE}/chat?message${encodeURIComponent(userMsg)}streamtrue) messages.value[aiIndex].isStreaming true messages.value[aiIndex].streamContent eventSource.onmessage (event) { if (event.data [DONE]) { eventSource.close() messages.value[aiIndex].isStreaming false // 将流式内容最终保存到 content messages.value[aiIndex].content messages.value[aiIndex].streamContent return } // 累积流式内容 messages.value[aiIndex].streamContent event.data scrollToBottom() } eventSource.onerror (error) { console.error(EventSource 错误:, error) eventSource.close() messages.value[aiIndex].isStreaming false messages.value[aiIndex].content 流式请求中断。 ElMessage.error(流式连接出错) } } // 清空对话 const clearChat () { messages.value [] } // 滚动到底部 const scrollToBottom () { nextTick(() { if (messageListRef.value) { messageListRef.value.scrollTop messageListRef.value.scrollHeight } }) } /script style scoped .chat-container { max-width: 800px; margin: 0 auto; padding: 20px; } .chat-box { border: 1px solid #dcdfe6; border-radius: 8px; overflow: hidden; } .message-list { height: 500px; overflow-y: auto; padding: 20px; background-color: #fafafa; } .message { display: flex; margin-bottom: 20px; } .message.user { flex-direction: row-reverse; } .message .avatar { width: 40px; height: 40px; border-radius: 50%; background: #409eff; color: white; display: flex; align-items: center; justify-content: center; margin: 0 10px; } .message.user .avatar { background: #67c23a; } .message .content { max-width: 70%; padding: 12px 16px; border-radius: 8px; background: white; box-shadow: 0 2px 8px rgba(0,0,0,0.1); } .message.user .content { background: #e1f3d8; } .input-area { padding: 20px; border-top: 1px solid #dcdfe6; } .actions { display: flex; justify-content: space-between; align-items: center; margin-top: 15px; } .streaming-cursor { animation: blink 1s infinite; } keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } } /style4.3 配置路由与启动在src/router/index.js中配置路由将ChatView设置为首页。import{createRouter,createWebHistory}fromvue-routerimportChatViewfrom../views/ChatView.vueconstroutercreateRouter({history:createWebHistory(import.meta.env.BASE_URL),routes:[{path:/,name:chat,comp