
构建基于Phi-3-mini-128k-instruct的微信小程序智能聊天机器人开发1. 引言当轻量级大模型遇上微信小程序最近在捣鼓一些AI应用落地的项目发现一个挺有意思的组合把微软开源的轻量级大模型Phi-3-mini-128k-instruct塞进微信小程序里做一个能聊天的智能助手。你可能要问了为什么选这个组合我自己的体会是Phi-3-mini这个模型虽然“小”但能力不弱特别适合在手机端这种资源有限的环境里跑。而微信小程序大家天天用不用下载安装点开就能聊体验很轻快。把这两者结合起来做个聊天机器人无论是用来当个解闷的伙伴还是处理一些简单的问答都挺实用的。这篇文章我就想跟你分享一下怎么从零开始把这个想法变成现实。咱们不聊那些复杂的理论就一步步来看看怎么搭界面、怎么连后台、怎么让机器人不仅能看懂文字还能“听”会说。整个过程我会尽量用大白话讲清楚就算你之前没怎么接触过小程序开发或者AI模型调用跟着做下来应该也能搞出个像模像样的东西。2. 项目准备理清思路与备好工具动手之前咱们先把要做的事情和需要的东西理清楚。这样后面敲代码的时候心里才有谱。2.1 我们要做一个什么样的小程序简单来说就是一个聊天界面。你在这头输入文字或者直接说话小程序把内容传给后端的Phi-3模型模型理解后生成回复再传回小程序显示出来甚至可以用语音念给你听。拆开来看主要包含这几块一个聊天窗口能显示你和机器人的对话记录像微信聊天那样上下排列。两种输入方式除了打字最好还能支持语音输入按着说话那种。两种输出方式文字回复肯定要有如果还能把回复用语音读出来体验就更好了。一个“大脑”也就是后端的Phi-3-mini模型负责理解问题并生成回答。连接桥梁小程序前端怎么把问题发给“大脑”又怎么把答案拿回来。2.2 需要准备哪些东西一个微信小程序账号去微信公众平台注册一个拿到小程序的AppID这是开发的“门票”。代码编辑器微信官方推荐的开发者工具就行它集成了代码编辑、调试和预览用起来方便。后端服务这是关键。Phi-3模型需要运行在服务器上。你有两个主要选择方案A使用云函数。比如微信云开发、或者各大云厂商的Serverless函数。这种方式不用自己管服务器比较省心适合快速验证想法。你需要把模型部署到云函数能调用的地方比如另一台服务器或容器服务或者使用一些平台提供的预置模型API。方案B使用自有服务器。如果你有服务器资源可以在上面部署Phi-3模型并提供一个HTTP API接口。这样控制权更全但需要自己维护服务器和网络。 考虑到简便性下文会以“通过一个API接口调用模型”为核心思路无论这个接口是云函数提供的还是你自己服务器提供的调用方式大同小异。Phi-3-mini模型从Hugging Face等开源平台获取模型文件并准备好运行它的环境比如用Ollama、vLLM等工具来部署和提供API。思路理清了工具备齐了接下来我们就从最直观的部分——小程序界面——开始动手。3. 搭建小程序聊天界面打开微信开发者工具新建一个小程序项目。咱们先来把用户看得见、摸得着的部分做好。3.1 设计基础的聊天布局小程序页面的结构主要在.wxml文件里写样式则在.wxss文件里定义。我们先搭一个简单的聊天室框架。!-- pages/chat/chat.wxml -- view classchat-container !-- 聊天消息区域 -- scroll-view classmessage-list scroll-y scroll-into-view{{scrollToView}} scroll-with-animation block wx:for{{messageList}} wx:keyid !-- 用户消息 -- view wx:if{{item.role user}} classmessage-row user-message view classmessage-bubble user{{item.content}}/view /view !-- 机器人消息 -- view wx:elif{{item.role assistant}} classmessage-row assistant-message view classavatarAI/view view classmessage-bubble assistant{{item.content}}/view /view /block /scroll-view !-- 底部输入区域 -- view classinput-area !-- 语音输入按钮 -- button classvoice-btn bind:taptoggleVoiceMode wx:if{{!isRecording}} image src/images/voice.png modewidthFix/image /button button classvoice-btn recording bind:touchstartstartVoiceInput bind:touchendendVoiceInput wx:else 松开结束 /button !-- 文本输入框 -- input classtext-input placeholder{{isVoiceMode ? 按住说话 : 输入消息...}} disabled{{isVoiceMode}} bind:inputonInput bind:confirmsendTextMessage value{{inputText}} / !-- 发送按钮 -- button classsend-btn bind:tapsendTextMessage disabled{{!inputText.trim()}}发送/button /view /view对应的样式让它看起来舒服点/* pages/chat/chat.wxss */ .chat-container { height: 100vh; display: flex; flex-direction: column; background-color: #f5f5f5; } .message-list { flex: 1; padding: 20rpx; box-sizing: border-box; } .message-row { display: flex; margin-bottom: 30rpx; } .user-message { justify-content: flex-end; } .assistant-message { justify-content: flex-start; align-items: flex-start; } .avatar { width: 80rpx; height: 80rpx; border-radius: 10rpx; background: #07c160; color: white; display: flex; align-items: center; justify-content: center; font-size: 28rpx; margin-right: 20rpx; flex-shrink: 0; } .message-bubble { max-width: 70%; padding: 20rpx 30rpx; border-radius: 10rpx; line-height: 1.5; font-size: 32rpx; word-break: break-word; } .user { background-color: #95ec69; color: #000; } .assistant { background-color: #fff; color: #333; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.1); } .input-area { display: flex; align-items: center; padding: 20rpx 30rpx; background: #fff; border-top: 1rpx solid #eee; } .voice-btn { width: 80rpx; height: 80rpx; margin-right: 20rpx; padding: 0; background: transparent; border: none; display: flex; align-items: center; justify-content: center; } .voice-btn image { width: 50rpx; height: 50rpx; } .voice-btn.recording { background: #f5222d; color: white; border-radius: 50%; } .text-input { flex: 1; height: 80rpx; padding: 0 30rpx; background: #f7f7f7; border-radius: 40rpx; font-size: 32rpx; } .send-btn { margin-left: 20rpx; height: 80rpx; line-height: 80rpx; padding: 0 40rpx; background: #07c160; color: white; border-radius: 40rpx; font-size: 32rpx; } .send-btn[disabled] { background: #cccccc; }这样一个基础的聊天界面就有了雏形。上面显示历史消息下面可以切换文字或语音输入。3.2 实现消息管理与滚动界面有了接下来用JavaScript.js文件让它可以交互。主要是管理消息列表、处理发送逻辑。// pages/chat/chat.js Page({ data: { messageList: [], // 存储所有消息 inputText: , // 输入框内容 isVoiceMode: false, // 是否为语音模式 isRecording: false, // 是否正在录音 scrollToView: , // 控制滚动到底部 }, onLoad() { // 可以在这里加载本地存储的历史对话 const history wx.getStorageSync(chatHistory) || []; this.setData({ messageList: history }); // 稍后滚动到底部 setTimeout(() this.scrollToBottom(), 100); }, // 输入框内容变化 onInput(e) { this.setData({ inputText: e.detail.value }); }, // 发送文本消息 async sendTextMessage() { const text this.data.inputText.trim(); if (!text) return; // 1. 清空输入框并添加用户消息到列表 this.setData({ inputText: }); const userMessage { id: Date.now(), role: user, content: text }; const newList [...this.data.messageList, userMessage]; this.setData({ messageList: newList }); this.scrollToBottom(); // 2. 显示“机器人正在思考”的加载状态 const thinkingMsg { id: Date.now()1, role: assistant, content: 思考中... }; this.setData({ messageList: [...newList, thinkingMsg] }); this.scrollToBottom(); try { // 3. 调用后端API获取回复 const reply await this.callPhi3API(text, newList); // 需要实现callPhi3API方法 // 4. 替换加载消息为真实回复 const finalList this.data.messageList.slice(0, -1); // 移除“思考中” const assistantMessage { id: Date.now()2, role: assistant, content: reply }; this.setData({ messageList: [...finalList, assistantMessage] }); // 5. 保存对话历史到本地 wx.setStorageSync(chatHistory, this.data.messageList); // 6. 可选调用文本转语音 // this.textToSpeech(reply); } catch (error) { console.error(调用API失败:, error); // 替换“思考中”为错误提示 const finalList this.data.messageList.slice(0, -1); const errorMsg { id: Date.now()2, role: assistant, content: 抱歉我好像出错了请稍后再试。 }; this.setData({ messageList: [...finalList, errorMsg] }); } this.scrollToBottom(); }, // 滚动到底部 scrollToBottom() { if (this.data.messageList.length 0) { const lastMsgId this.data.messageList[this.data.messageList.length - 1].id; this.setData({ scrollToView: msg_${lastMsgId} }); } }, // 切换语音/文本输入模式 toggleVoiceMode() { this.setData({ isVoiceMode: !this.data.isVoiceMode }); }, // 开始语音输入需要用户授权录音 startVoiceInput() { this.setData({ isRecording: true }); // 这里应调用wx.startRecord API开始录音 console.log(开始录音); // 实际开发中需要处理录音授权、开始录音的逻辑 }, // 结束语音输入并识别 endVoiceInput() { this.setData({ isRecording: false }); console.log(结束录音); // 这里应调用wx.stopRecord并获取临时文件路径 // 然后将录音文件发送到语音识别服务如微信的语音识别或第三方API // 识别出文字后调用sendTextMessage发送 // 模拟识别结果 const recognizedText 这是语音识别出来的文字; // 此处替换为真实识别结果 this.setData({ inputText: recognizedText }); this.sendTextMessage(); }, // callPhi3API 和 textToSpeech 方法将在下一节实现 });到这里一个静态的、能管理消息的聊天界面就完成了。接下来我们要解决最核心的问题怎么让小程序和Phi-3模型“说上话”。4. 连接AI大脑调用Phi-3模型API前端界面是“脸面”后端的模型才是“大脑”。这一步我们让小程序能把用户的问题发送给Phi-3模型并把模型的回答拿回来。4.1 理解Phi-3模型的对话格式Phi-3-mini-instruct这类对话模型通常期望接收特定格式的数据。它不是一个简单的“一问一答”而是需要你提供完整的对话历史上下文这样它才能理解当前的对话情境做出连贯的回复。常见的格式是一个消息Message列表每条消息标明角色user或assistant和内容。例如当我们发起一次新的请求时需要把之前所有的对话记录都传过去{ messages: [ {role: user, content: 你好}, {role: assistant, content: 你好有什么可以帮你的吗}, {role: user, content: 今天的天气怎么样} // 这是最新的问题 ] }模型会根据整个列表生成下一条assistant角色的回复。4.2 实现API调用函数在刚才的chat.js中我们预留了callPhi3API方法。现在我们来完善它。假设你的Phi-3模型已经部署好并提供了一个HTTP API接口地址是https://your-api-server.com/v1/chat/completions。// 在 pages/chat/chat.js 中继续添加方法 Page({ // ... 之前的 data 和 onLoad, sendTextMessage 等方法 ... // 调用Phi-3模型API的核心方法 async callPhi3API(newQuestion, fullHistory) { // 1. 构建符合模型要求的消息列表 // 通常我们不需要传递全部历史可以截取最近N轮对话以防止上下文过长 const recentHistory this.getRecentHistory(fullHistory, 10); // 获取最近10轮对话 const messages recentHistory.map(msg ({ role: msg.role, content: msg.content })); // 加入最新的用户问题 messages.push({ role: user, content: newQuestion }); // 2. 准备请求参数 const requestData { model: phi-3-mini-128k-instruct, // 根据你的后端配置调整 messages: messages, max_tokens: 512, // 控制回复的最大长度 temperature: 0.7, // 控制回复的随机性0.0-1.0越高越有创意 stream: false // 是否使用流式输出小程序处理起来稍复杂这里先设为false }; // 3. 发起网络请求 // 注意需要在微信小程序管理后台配置request合法域名你的API服务器域名 const response await wx.request({ url: https://your-api-server.com/v1/chat/completions, // 替换为你的真实API地址 method: POST, header: { Content-Type: application/json, // 如果需要API密钥在这里添加 // Authorization: Bearer YOUR_API_KEY }, data: requestData, timeout: 30000 // 超时时间设置为30秒 }); // 4. 处理响应 if (response.statusCode 200) { // 假设后端返回格式为 { choices: [{message: {content: ...}}] } const replyContent response.data.choices[0]?.message?.content; if (replyContent) { return replyContent.trim(); } else { throw new Error(API返回格式异常); } } else { console.error(API请求失败:, response); throw new Error(请求失败: ${response.statusCode}); } }, // 辅助函数从完整历史中截取最近N轮对话 getRecentHistory(history, maxRounds) { // 简单实现直接返回最后 maxRounds*2 条消息因为一轮对话包含user和assistant两条 const startIndex Math.max(0, history.length - maxRounds * 2); return history.slice(startIndex); }, });重要提示域名配置微信小程序要求网络请求的域名必须在小程序管理后台的“开发设置”-“服务器域名”中配置否则无法请求。安全性如果你的API需要密钥切勿将密钥硬编码在小程序前端代码中这极易泄露。更安全的做法是使用云函数作为中转由云函数保管密钥并调用你的模型API小程序只调用云函数。错误处理网络请求可能失败模型API也可能返回错误务必做好用户提示。4.3 使用云函数中转更安全的方案鉴于前端直接调用模型API的安全和配置问题更推荐使用云函数。这里以微信云开发为例简述思路创建云函数在小程序项目中创建一个云函数例如callPhi3。在云函数中调用模型API将上面callPhi3API函数中的请求逻辑移到云函数里。云函数运行在微信的服务器上可以安全地存储你的API密钥。小程序调用云函数修改小程序前端的callPhi3API方法改为调用这个云函数。// 云函数 callPhi3/index.js const cloud require(wx-server-sdk); cloud.init(); const axios require(axios); // 需要安装axios依赖 exports.main async (event, context) { const { messages, max_tokens, temperature } event; try { const response await axios.post(https://your-api-server.com/v1/chat/completions, { model: phi-3-mini-128k-instruct, messages, max_tokens, temperature, stream: false }, { headers: { Content-Type: application/json, Authorization: Bearer YOUR_SECRET_API_KEY // 密钥放在这里安全 }, timeout: 30000 }); return { success: true, reply: response.data.choices[0]?.message?.content?.trim() || }; } catch (error) { console.error(云函数调用模型失败:, error); return { success: false, error: error.message }; } };然后小程序前端调用就简化为// 修改后的 callPhi3API 方法在小程序前端 async callPhi3API(newQuestion, fullHistory) { const recentHistory this.getRecentHistory(fullHistory, 10); const messages recentHistory.map(msg ({ role: msg.role, content: msg.content })); messages.push({ role: user, content: newQuestion }); try { const result await wx.cloud.callFunction({ name: callPhi3, // 你的云函数名 data: { messages: messages, max_tokens: 512, temperature: 0.7 } }); if (result.result.success) { return result.result.reply; } else { throw new Error(result.result.error); } } catch (error) { console.error(调用云函数失败:, error); throw error; } }这样我们就安全地建立起了小程序与AI模型之间的桥梁。模型可以理解问题并生成回复了。接下来我们为这个机器人加上“耳朵”和“嘴巴”。5. 功能增强语音输入与输出纯文字聊天已经不错但如果能语音交互体验会提升一个档次。微信小程序提供了比较完善的录音和音频播放能力。5.1 实现语音输入录音与识别语音输入包含两步录音和语音识别。微信小程序有录音API但语音识别需要借助第三方服务如微信同声传译插件或各大云平台的语音识别API。这里以使用微信的语音识别API需要用户授权为例展示一个简化的流程// 在 pages/chat/chat.js 中完善语音输入方法 Page({ // ... 之前的 data ... // 开始录音 async startVoiceInput() { // 1. 检查并获取录音权限 const authStatus await this.checkRecordAuth(); if (!authStatus) { wx.showToast({ title: 需要录音权限, icon: none }); return; } this.setData({ isRecording: true }); // 2. 开始录音 wx.startRecord({ success: (res) { // 录音成功res.tempFilePath 是临时音频文件路径 console.log(录音文件路径:, res.tempFilePath); this.recognizeVoice(res.tempFilePath); // 调用识别函数 }, fail: (err) { console.error(录音失败:, err); wx.showToast({ title: 录音失败, icon: none }); this.setData({ isRecording: false }); } }); // 3. 设置最长录音时间自动结束 setTimeout(() { if (this.data.isRecording) { wx.stopRecord(); // 自动停止录音 this.setData({ isRecording: false }); } }, 60000); // 最长60秒 }, // 结束录音用户松开按钮时 endVoiceInput() { if (this.data.isRecording) { wx.stopRecord(); // 停止录音会触发 startRecord 的 success 回调 this.setData({ isRecording: false }); } }, // 检查录音权限 checkRecordAuth() { return new Promise((resolve) { wx.getSetting({ success: (res) { if (!res.authSetting[scope.record]) { // 未授权发起授权请求 wx.authorize({ scope: scope.record, success: () resolve(true), fail: () { wx.showModal({ title: 提示, content: 需要您授权使用麦克风进行语音输入, success: (modalRes) { if (modalRes.confirm) { wx.openSetting(); // 引导用户去设置页打开 } resolve(false); } }); } }); } else { resolve(true); } } }); }); }, // 语音识别这里需要接入实际的语音识别服务 async recognizeVoice(tempFilePath) { wx.showLoading({ title: 识别中... }); // 注意微信小程序暂无直接可用的免费长语音识别API。 // 方案一使用微信的语音识别仅支持短语音且需插件或特定接口限制较多。 // 方案二使用第三方云服务如百度、阿里、腾讯云的语音识别API。 // 以下是一个调用第三方API的示例框架 // 1. 上传音频文件到云存储或直接传给API需根据API要求处理 // const uploadRes await wx.uploadFile({ ... }); // 2. 调用语音识别API // const recognizeRes await wx.request({ // url: YOUR_SPEECH_RECOGNITION_API_URL, // method: POST, // header: { ... }, // data: { audio_data: ... }, // }); // 3. 获取识别文本 // const text recognizeRes.data.result; // 模拟识别结果 setTimeout(() { wx.hideLoading(); const simulatedText 这是模拟识别出来的语音内容; // 替换为真实识别结果 this.setData({ inputText: simulatedText }); this.sendTextMessage(); // 自动发送 }, 1500); }, });5.2 实现文本转语音输出让机器人“说话”我们需要文本转语音TTS功能。同样微信小程序没有内置TTS需要借助第三方API。这里以调用一个假设的TTS API为例// 在 pages/chat/chat.js 中添加文本转语音方法 Page({ // ... 之前的代码 ... // 文本转语音 async textToSpeech(text) { if (!text) return; // 调用TTS API获取音频文件URL或二进制数据 try { const ttsResponse await wx.request({ url: https://your-tts-api.com/synthesize, // 替换为你的TTS服务地址 method: POST, header: { Content-Type: application/json }, data: { text: text, voice: xiaoyan, // 选择音色 speed: 1.0, format: mp3 }, responseType: arraybuffer // 重要接收二进制音频数据 }); if (ttsResponse.statusCode 200) { // 将二进制数据保存为临时文件并播放 const fs wx.getFileSystemManager(); const tempFilePath ${wx.env.USER_DATA_PATH}/temp_audio.mp3; fs.writeFile({ filePath: tempFilePath, data: ttsResponse.data, encoding: binary, success: () { this.playAudio(tempFilePath); }, fail: (err) console.error(保存音频文件失败:, err) }); } } catch (error) { console.error(TTS请求失败:, error); // 失败时静默处理不影响主流程 } }, // 播放音频 playAudio(tempFilePath) { const innerAudioContext wx.createInnerAudioContext(); innerAudioContext.src tempFilePath; innerAudioContext.play(); innerAudioContext.onError((res) { console.error(音频播放失败:, res.errMsg); }); }, });记得在sendTextMessage方法中成功获取回复后取消注释// this.textToSpeech(reply);这一行即可启用语音回复功能。6. 总结与展望走完上面这些步骤一个具备基础聊天、支持文字和语音交互的微信小程序机器人骨架就搭起来了。你可以输入文字或者按住说话它就能调用后端的Phi-3模型进行思考并回复甚至还能把回复读出来。实际开发中还有很多细节可以打磨。比如对话历史的管理可以更智能只保留最近有效的上下文以节省tokenUI交互可以更流畅在语音识别和TTS播放时给出更明确的反馈错误处理要更完善网络不好或者服务出错时给用户友好的提示。如果用户量上来还需要考虑后端模型的性能优化和成本控制。这个项目更像一个起点展示了如何将前沿的轻量级大模型与普及的微信小程序生态结合。Phi-3-mini这样的模型让在移动端部署智能应用成为可能而小程序提供了触达用户的便捷途径。你可以基于这个基础把它扩展成学习助手、专业问答工具、或者有趣的聊天伙伴可能性还有很多。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。