Phi-3 Forest Laboratory 微信小程序开发集成打造个人AI知识库小程序你是不是也想过要是能把一个聪明的AI助手装进微信小程序里随时随地都能问它问题、让它帮你整理知识那该多方便比如在通勤路上用语音问它“帮我总结一下今天AI行业有什么新动态”或者把读到的文章片段丢给它让它帮你提炼核心观点。今天我就来手把手带你实现这个想法。我们将一起把Phi-3 Forest Laboratory的智能对话能力完整地集成到一个微信小程序里打造一个属于你自己的、支持语音和文字的“口袋AI知识库”。整个过程从微信开发者工具配置开始到前后端联调结束我会把每一步的代码和踩过的“坑”都分享给你保证你跟着做就能跑起来。1. 项目准备理清思路与搭建环境在动手写代码之前我们先花几分钟把整个项目的脉络理清楚。我们要做的小程序核心功能就三块文本对话、语音输入、历史记录管理。用户通过文字或语音提问小程序把问题发给后端的Phi-3模型拿到回答后再展示给用户同时把这一问一答保存下来。听起来不复杂对吧但这里面有几个关键点需要提前准备好前端微信小程序负责界面交互、收集用户输入文本或语音、展示对话历史、调用后端接口。后端Phi-3 Forest Laboratory API提供AI模型的计算能力接收问题返回智能回答。你需要确保你的Phi-3服务已经部署好并且有一个可以访问的API地址。通信桥梁小程序通过网络请求wx.request与后端API对话。由于小程序有严格的域名安全要求你需要将后端API地址配置到小程序的合法域名列表中。环境与工具清单微信开发者工具这是必须的去微信公众平台官网下载最新版。一个已经申请好的微信小程序AppID没有的话可以先使用测试号。一个可访问的Phi-3 Forest Laboratory API服务假设它的接口地址是https://your-phi3-api.com/v1/chat/completions。代码编辑器比如VSCode用来看代码会更舒服。准备好了吗我们打开微信开发者工具创建一个新的小程序项目项目名称就叫“我的AI知识库”吧。创建时记得填入你的AppID或使用测试号并选择不使用云服务本文不涉及云开发。2. 核心能力封装网络请求与状态管理项目创建好后我们先不急着画界面而是把最底层、最核心的通信模块和状态管理搭好。这就像盖房子先打地基。2.1 封装网络请求模块在小程序里我们不会每次调用API都写一遍wx.request那样代码又乱又难维护。我们把它封装成一个独立的工具函数。在项目根目录下新建一个utils文件夹然后在里面创建api.js文件// utils/api.js const API_BASE_URL https://your-phi3-api.com/v1; // 替换成你的真实API地址 const API_KEY your-api-key-here; // 如果API需要鉴权请替换 /** * 统一的网络请求方法 * param {string} endpoint - 接口路径例如 /chat/completions * param {string} method - 请求方法GET 或 POST * param {object} data - 请求体数据 * returns {Promise} 返回Promise对象 */ function request(endpoint, method POST, data {}) { return new Promise((resolve, reject) { wx.request({ url: ${API_BASE_URL}${endpoint}, method: method, data: data, header: { Content-Type: application/json, Authorization: Bearer ${API_KEY} // 按需添加 }, success(res) { if (res.statusCode 200 res.statusCode 300) { resolve(res.data); } else { reject(new Error(请求失败: ${res.statusCode})); wx.showToast({ title: 服务异常请稍后重试, icon: none }); } }, fail(err) { reject(err); wx.showToast({ title: 网络连接失败, icon: none }); } }); }); } /** * 专门用于调用对话补全接口 * param {Array} messages - 对话消息历史格式[{role: user, content: 你好}] * returns {Promise} 返回AI的回答内容 */ export function chatWithPhi3(messages) { // 这里根据你的Phi-3 API实际需要的参数进行调整 const requestData { model: phi-3, // 模型名称根据实际情况修改 messages: messages, stream: false, // 我们先使用非流式响应更简单 // 可以添加其他参数如 temperature, max_tokens 等 }; return request(/chat/completions, POST, requestData) .then(res { // 解析响应这里需要根据你API返回的实际数据结构调整 // 假设返回结构为 { choices: [{ message: { content: ... } }] } const reply res.choices?.[0]?.message?.content || 抱歉我没有理解你的问题。; return reply; }) .catch(err { console.error(调用AI接口失败:, err); return 哎呀AI助手暂时无法响应请检查网络或稍后再试。; }); } export default { request, chatWithPhi3 };重要提示API_BASE_URL和请求参数格式必须根据你实际部署的Phi-3 Forest LaboratoryAPI 文档进行调整。在微信小程序后台的“开发管理”-“开发设置”-“服务器域名”中需要将你的API域名添加到request合法域名列表中。2.2 实现对话状态管理我们需要一个地方来集中管理所有的对话记录、当前输入状态等。在小程序里我们可以用页面的data对象但对于稍复杂的交互更好的做法是抽象一个管理类。这里为了直观我们先在页面的data中管理。打开项目首页对应的index.js我们先初始化数据// pages/index/index.js Page({ /** * 页面的初始数据 */ data: { // 对话历史列表每条记录包含角色user/assistant和内容 conversationHistory: [ { role: assistant, content: 你好我是你的AI知识库助手可以回答你的问题也可以帮你整理信息。试试问我点什么吧 } ], // 用户当前的输入文本 userInput: , // 是否正在请求AI用于显示加载动画 isLoading: false, // 是否正在录音 isRecording: false, }, // 其他生命周期函数和方法将在后面添加... })3. 构建用户界面聊天窗口与交互地基打好了现在我们来盖房子的主体——用户界面。微信小程序的界面主要在.wxml和.wxss文件中定义。3.1 编写页面结构 (index.wxml)这个界面主要分为三部分顶部的标题栏、中间的聊天记录展示区、底部的输入工具栏。!-- pages/index/index.wxml -- view classcontainer !-- 标题栏 -- view classheader text classtitle我的AI知识库/text text classsubtitlePowered by Phi-3/text /view !-- 聊天内容区域 -- scroll-view classchat-container scroll-y scroll-into-view{{scrollToView}} scroll-with-animation view classchat-list block wx:for{{conversationHistory}} wx:keyindex !-- 根据角色判断消息是用户还是AI -- view classmessage-row {{item.role user ? user-row : assistant-row}} !-- AI头像和消息 -- view wx:if{{item.role assistant}} classmessage-assistant image classavatar src/images/ai-avatar.png/image view classbubble bubble-assistant text classcontent{{item.content}}/text /view /view !-- 用户头像和消息 -- view wx:if{{item.role user}} classmessage-user view classbubble bubble-user text classcontent{{item.content}}/text /view image classavatar src/images/user-avatar.png/image /view /view /block !-- 加载动画 -- view wx:if{{isLoading}} classmessage-row assistant-row view classmessage-assistant image classavatar src/images/ai-avatar.png/image view classbubble bubble-assistant loading text classcontent思考中/text text classdot./text text classdot./text text classdot./text /view /view /view /view /scroll-view !-- 底部输入工具栏 -- view classinput-toolbar !-- 语音输入按钮 -- button classbtn-voice {{isRecording ? recording : }} bindtaptoggleVoiceInput image wx:if{{!isRecording}} src/icons/voice.png modewidthFix/image view wx:else classrecording-indicator/view /button !-- 文本输入框 -- input classinput-box value{{userInput}} bindinputonInputChange placeholder输入问题或长按语音按钮... confirm-typesend bindconfirmsendMessage focus{{inputFocus}} / !-- 发送按钮 -- button classbtn-send bindtapsendMessage disabled{{!userInput.trim() !isRecording}} 发送 /button /view /view3.2 添加页面样式 (index.wxss)样式可以让我们的界面看起来更舒服。这里提供一个基础的样式你可以根据自己的喜好调整颜色和布局。/* pages/index/index.wxss */ .container { height: 100vh; display: flex; flex-direction: column; background-color: #f5f5f5; } .header { padding: 20rpx 30rpx; background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%); color: white; text-align: center; } .title { font-size: 38rpx; font-weight: bold; display: block; } .subtitle { font-size: 24rpx; opacity: 0.8; display: block; } .chat-container { flex: 1; padding: 20rpx; box-sizing: border-box; overflow: hidden; /* 由scroll-view控制滚动 */ } .chat-list { min-height: 100%; } .message-row { margin-bottom: 30rpx; display: flex; } .message-user { justify-content: flex-end; } .message-assistant, .message-user { display: flex; align-items: flex-start; max-width: 85%; } .avatar { width: 80rpx; height: 80rpx; border-radius: 10rpx; flex-shrink: 0; } .message-assistant .avatar { margin-right: 20rpx; } .message-user .avatar { margin-left: 20rpx; } .bubble { padding: 20rpx 25rpx; border-radius: 18rpx; line-height: 1.5; word-break: break-word; box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.1); } .bubble-assistant { background-color: white; color: #333; border-top-left-radius: 0; } .bubble-user { background-color: #0084ff; color: white; border-top-right-radius: 0; } .bubble.loading .dot { animation: blink 1.4s infinite both; } .bubble.loading .dot:nth-child(2) { animation-delay: 0.2s; } .bubble.loading .dot:nth-child(3) { animation-delay: 0.4s; } keyframes blink { 0%, 100% { opacity: 0.2; } 50% { opacity: 1; } } .content { font-size: 32rpx; } .input-toolbar { display: flex; align-items: center; padding: 20rpx 30rpx; background-color: white; border-top: 1rpx solid #eee; } .btn-voice { width: 80rpx; height: 80rpx; border-radius: 50%; background-color: #f0f0f0; display: flex; align-items: center; justify-content: center; padding: 0; margin-right: 20rpx; border: none; } .btn-voice image { width: 40rpx; height: 40rpx; } .btn-voice.recording { background-color: #ff4444; } .recording-indicator { width: 40rpx; height: 40rpx; border-radius: 50%; background-color: white; animation: pulse 1s infinite; } keyframes pulse { 0% { transform: scale(0.8); opacity: 0.8; } 50% { transform: scale(1.1); opacity: 1; } 100% { transform: scale(0.8); opacity: 0.8; } } .input-box { flex: 1; height: 80rpx; padding: 0 25rpx; background-color: #f8f8f8; border-radius: 40rpx; font-size: 32rpx; } .btn-send { margin-left: 20rpx; height: 80rpx; line-height: 80rpx; padding: 0 35rpx; border-radius: 40rpx; background-color: #0084ff; color: white; font-size: 32rpx; border: none; } .btn-send[disabled] { background-color: #cccccc; color: #999; }别忘了在images目录下准备ai-avatar.png和user-avatar.png两张头像图片以及在icons目录下准备voice.png语音图标。4. 实现核心逻辑对话、语音与历史记录界面有了现在让它“活”起来。我们需要在index.js中实现所有交互逻辑。4.1 文本对话功能首先实现最基础的文本发送和接收AI回复的功能。// pages/index/index.js import { chatWithPhi3 } from ../../utils/api.js; // 导入我们封装的API方法 Page({ data: { conversationHistory: [...], // 同上 userInput: , isLoading: false, isRecording: false, scrollToView: , // 用于控制滚动到底部 }, // 监听输入框变化 onInputChange(e) { this.setData({ userInput: e.detail.value }); }, // 发送消息点击发送按钮或键盘回车 async sendMessage() { const inputText this.data.userInput.trim(); if (!inputText !this.data.isRecording) { return; // 没有输入内容且不在录音则不发送 } let finalInput inputText; // 如果是语音识别结果这里可以处理我们先处理文本 if (!finalInput) { wx.showToast({ title: 请输入内容, icon: none }); return; } // 1. 将用户消息加入历史 const newUserMsg { role: user, content: finalInput }; const updatedHistory [...this.data.conversationHistory, newUserMsg]; this.setData({ conversationHistory: updatedHistory, userInput: , // 清空输入框 isLoading: true }); // 滚动到底部查看新消息 this.scrollToBottom(); try { // 2. 调用AI接口 const aiReply await chatWithPhi3(updatedHistory); // 传入整个历史记录让AI有上下文 // 3. 将AI回复加入历史 const newAiMsg { role: assistant, content: aiReply }; this.setData({ conversationHistory: [...updatedHistory, newAiMsg], isLoading: false }); // 再次滚动到底部查看AI回复 this.scrollToBottom(); } catch (error) { console.error(发送消息失败:, error); this.setData({ isLoading: false }); wx.showToast({ title: 发送失败请重试, icon: none }); } }, // 滚动到最新消息 scrollToBottom() { // 使用scroll-view的scroll-into-view属性 // 给最后一条消息或一个锚点元素设置id const lastIndex this.data.conversationHistory.length - 1; // 简单实现设置一个动态的viewIdscroll-into-view会指向它 // 更稳健的做法是在wxml中动态设置最后一个消息气泡的id // 这里采用一个简单技巧用setTimeout确保渲染完成后再滚动 setTimeout(() { this.setData({ scrollToView: msg-${lastIndex} }); }, 100); }, // ... 其他方法 })同时需要更新index.wxml给每条消息绑定一个动态ID以便scroll-into-view工作!-- 在 index.wxml 的 block 循环中修改 -- view classmessage-row {{item.role user ? user-row : assistant-row}} idmsg-{{index}} !-- ... 内部内容保持不变 ... -- /view4.2 语音输入功能微信小程序提供了强大的语音识别API我们可以很方便地集成。// 在 pages/index/index.js 的 Page 对象内继续添加方法 // 切换语音输入状态 toggleVoiceInput() { if (this.data.isRecording) { this.stopVoiceInput(); } else { this.startVoiceInput(); } }, // 开始录音 startVoiceInput() { const that this; // 首先获取录音权限 wx.authorize({ scope: scope.record, success() { // 权限已获得开始录音 that.setData({ isRecording: true }); wx.startRecord({ success(res) { // 录音成功拿到临时文件路径 const tempFilePath res.tempFilePath; // 识别语音 that.recognizeVoice(tempFilePath); }, fail(err) { console.error(录音失败:, err); that.setData({ isRecording: false }); wx.showToast({ title: 录音失败, icon: none }); } }); }, fail() { // 用户拒绝了授权引导用户去设置页打开 wx.showModal({ title: 提示, content: 需要您的授权才能使用语音功能, confirmText: 去设置, success(res) { if (res.confirm) { wx.openSetting(); } } }); that.setData({ isRecording: false }); } }); }, // 停止录音长按结束或主动停止 stopVoiceInput() { wx.stopRecord(); // 停止录音 this.setData({ isRecording: false }); }, // 识别语音内容 recognizeVoice(tempFilePath) { wx.showLoading({ title: 识别中... }); wx.uploadFile({ url: https://api.weixin.qq.com/cgi-bin/media/voice/translatecontent?access_tokenYOUR_ACCESS_TOKEN, // 注意这里需要后端服务或使用微信同声传译插件此处为示例流程 filePath: tempFilePath, name: voice, formData: { lfrom: zh_CN, lto: zh_CN }, success(res) { wx.hideLoading(); const result JSON.parse(res.data); if (result result.text) { // 将识别到的文本填入输入框 that.setData({ userInput: result.text }); // 可选自动发送 // that.sendMessage(); } else { wx.showToast({ title: 识别失败请重试, icon: none }); } }, fail() { wx.hideLoading(); wx.showToast({ title: 识别请求失败, icon: none }); } }); },重要说明上述语音识别直接调用了微信的接口但这个接口需要access_token且通常需要后端服务器中转或使用微信提供的同声传译插件。对于个人开发者或快速原型一个更简单的方法是使用微信的wx.startRecord配合wx.onVoiceRecordEnd获取录音文件后调用你自己的后端服务该服务可以集成如百度、阿里云的语音识别SDK进行识别。本文为简化流程展示了前端调用逻辑你需要根据实际情况实现后端识别接口。4.3 历史记录管理历史记录我们已经保存在conversationHistory中。为了持久化我们可以利用小程序的本地存储wx.setStorageSync。// 在 pages/index/index.js 中添加 // 保存对话历史到本地 saveHistory() { try { wx.setStorageSync(ai_conversation_history, this.data.conversationHistory); } catch (e) { console.error(保存历史记录失败:, e); } }, // 从本地加载对话历史 loadHistory() { try { const history wx.getStorageSync(ai_conversation_history); if (history Array.isArray(history)) { // 可以加一个判断避免加载过旧的格式 this.setData({ conversationHistory: history }); } } catch (e) { console.error(加载历史记录失败:, e); } }, // 在onLoad生命周期中加载历史 onLoad() { this.loadHistory(); // 可以在这里初始化一些数据 }, // 每次更新历史后自动保存可以在sendMessage成功后的setData回调中调用 // 例如在sendMessage的setData成功后 // this.setData({...}, () { this.saveHistory(); });为了更好的体验我们还可以在页面上增加一个清空历史的按钮在wxml的标题栏附近添加!-- 在 index.wxml 的 header 部分添加 -- view classheader text classtitle我的AI知识库/text text classsubtitlePowered by Phi-3/text button classbtn-clear sizemini bindtapclearHistory清空/button /view// 在 index.js 中添加清空方法 clearHistory() { wx.showModal({ title: 确认清空, content: 确定要清空所有对话记录吗, success: (res) { if (res.confirm) { const initMsg [{ role: assistant, content: 你好历史已清空。我可以重新为你服务。 }]; this.setData({ conversationHistory: initMsg }); this.saveHistory(); wx.showToast({ title: 已清空, icon: success }); } } }); },5. 项目优化与扩展思路走到这一步一个基本的、能跑通的AI知识库小程序已经完成了。你可以真机扫描预览体验文本对话和基础的UI交互。但要让这个小程序更健壮、更好用这里还有几个可以继续深化的方向性能与体验优化流式输出目前我们是等AI全部生成完再显示。可以改造API调用支持Server-Sent Events (SSE) 或 WebSocket实现像ChatGPT那样一个字一个字打出来的效果体验会好很多。这需要后端API也支持流式响应。本地缓存图片如果AI返回的内容包含图片链接可以使用wx.downloadFile和wx.saveFile进行本地缓存加速二次加载。对话分页加载当历史记录非常多时一次性渲染可能卡顿。可以实现分页加载每次只显示最新的N条向上滑动加载更多。功能扩展多模态输入除了文字和语音可以增加图片上传功能。利用Phi-3的视觉能力让AI“看懂”图片并回答问题。这需要调用支持图片输入的API端点并使用wx.chooseImage和wx.uploadFile。知识库检索增强现在的对话是基于模型的通用知识。你可以增加一个“上传文档”功能将你的PDF、TXT文件通过后端解析并向量化存入向量数据库。当用户提问时先检索相关文档片段再连同问题和片段一起发给Phi-3让它基于你的私有资料回答真正成为“个人知识库”。对话分享允许用户将某一段有趣的对话生成图片或链接分享给好友。UI主题切换增加深色模式保护夜间使用的眼睛。工程化建议使用状态管理对于更复杂的应用可以考虑引入像mobx-miniprogram这样的小程序状态管理库让数据流更清晰。错误监控集成像Sentry这样的错误监控平台收集小程序运行时的错误便于排查问题。安全加固API密钥不要硬编码在前端。最佳实践是使用小程序云函数或自己的后端服务器做一层代理由后端持有密钥并转发请求防止密钥泄露。整体做下来你会发现将像Phi-3这样的AI模型集成到微信小程序里核心难点其实不在前端交互而在于稳定的后端API服务和合规的网络请求配置。一旦打通了这个链路前端所能实现的交互想象空间是非常大的。这个小程序项目就像一个骨架你已经完成了从0到1的搭建。接下来是给它增加血肉更丰富的功能和灵魂更智能的交互的时候了。不妨就从增加一个图片问答功能开始尝试吧获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。