大模型:阿里云百炼 + 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

相关新闻

STM32双ADC模式深度解析:从同步采样到快速交替的实战指南

STM32双ADC模式深度解析:从同步采样到快速交替的实战指南

1. 项目概述:为什么需要双ADC?在嵌入式开发,尤其是基于STM32这类MCU的项目里,ADC(模数转换器)是连接模拟世界和数字世界的桥梁。无论是读取传感器数据(温度、压力、光照)&#xff0c…

2026/10/18 8:56:22 阅读更多 →
C语言运算符与表达式完全指南:从入门到精通,这一篇就够了

C语言运算符与表达式完全指南:从入门到精通,这一篇就够了

摘要: 运算符是C语言的"动词",表达式是C语言的"句子"。本文系统讲解C语言中的语句分类、表达式概念、全部运算符的用法与注意事项,涵盖算术运算、赋值运算、位运算、逻辑运算、比较运算、类型转换、优先级等核心知识点。…

2026/10/19 1:43:34 阅读更多 →
YOLOv5自定义数据集训练实战:从环境搭建到模型部署全流程详解

YOLOv5自定义数据集训练实战:从环境搭建到模型部署全流程详解

1. 项目概述:从零到一掌握YOLOv5自定义训练如果你正在为如何让YOLOv5识别你自己的目标而发愁,比如想让它认出你家后院的猫、工厂流水线上的瑕疵品,或是医学影像中的特定细胞,那么这篇超详细的实战指南就是为你准备的。网上很多教程…

2026/10/20 17:24:46 阅读更多 →

最新新闻

Canvas截取视频首帧作为封面:前端零成本方案与实战避坑

Canvas截取视频首帧作为封面:前端零成本方案与实战避坑

1. 为什么视频封面首帧截取是个高频刚需做过内容平台或者带视频功能的项目的人都知道&#xff0c;视频列表页如果直接放一个<video>标签去加载&#xff0c;页面性能会崩得很难看。几十个视频同时开始加载元数据和首帧&#xff0c;带宽和内存直接爆炸&#xff0c;尤其在移…

2026/10/20 21:34:09 阅读更多 →
Linux权限管理指南:普通用户与root的授权、应急恢复与安全实践

Linux权限管理指南:普通用户与root的授权、应急恢复与安全实践

去年有一次我在测试环境里手滑&#xff0c;用root执行了一条带rm -rf的清理命令&#xff0c;变量没展开&#xff0c;差点把整个/usr目录送走。机器倒是救回来了&#xff0c;但从那以后我给自己立了条规矩&#xff1a;能用普通用户干的活&#xff0c;绝不用root&#xff1b;必须…

2026/10/20 21:34:09 阅读更多 →
Agent工具工程:从调用到契约的可靠性设计

Agent工具工程:从调用到契约的可靠性设计

1. 这不是“AI工具课”&#xff0c;而是一场对工程思维的重新校准“哥伦比亚大学 Agentic Engineering 第 5 讲&#xff1a;221 分钟讲透 Agent 工具”——这个标题刚出现在某技术社区时&#xff0c;我第一反应是点开前先关掉所有通知。不是因为不感兴趣&#xff0c;恰恰相反&a…

2026/10/20 21:34:09 阅读更多 →
RNN十年演进:从LSTM到Transformer再到线性注意力回归

RNN十年演进:从LSTM到Transformer再到线性注意力回归

做序列建模这些年&#xff0c;我是眼看着RNN从主角变成配角&#xff0c;又在最近两年换了一副面孔回到舞台中央的。2014年那会儿&#xff0c;我在一个文本分类项目里用单层LSTM调参&#xff0c;调参基本靠猜&#xff0c;训练基本靠忍&#xff0c;一个模型跑一个晚上是家常便饭。…

2026/10/20 21:34:09 阅读更多 →
MATLAB牛耕法全覆盖路径规划:有障碍物时的区域分解与绕行

MATLAB牛耕法全覆盖路径规划:有障碍物时的区域分解与绕行

简介&#xff1a;本资源面向机器人路径规划初学者与MATLAB仿真开发者&#xff0c;聚焦全覆盖算法中牛耕法在障碍物环境下的实现与回退处理&#xff0c;帮助读者理解如何让作业设备在复杂区域内完成无遗漏覆盖。包内共3个文件&#xff0c;均为m脚本&#xff0c;压缩包约2KB&…

2026/10/20 21:34:09 阅读更多 →
AI平台选型指南:从通用对话到开源自部署的实战策略

AI平台选型指南:从通用对话到开源自部署的实战策略

1. 主流AI平台的全景地图与选型逻辑1.1 为什么现在聊“AI平台”比聊“AI模型”更实际过去一年我接触了不少团队&#xff0c;从几个人的小工作室到上百人的产品线&#xff0c;大家问得最多的问题早就不是“哪个模型最强”&#xff0c;而是“我该把活儿交给哪个平台”。这个转变很…

2026/10/20 21:33:02 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →