微信小程序接入AI API实现智能问答功能(以百度智能云为例)_小程序接入ai问答
1.老规矩,先讲故事
这天我的微信小程序想实现接入一个AI页面实现用户AI智能问答功能,但发现网络上大家都比较吝啬,要么要开会员,要么不分享。导致我走了好多弯路,最后也明白了一些道理,掌握了一些新的知识。
2.AI问答功能的实现
这部分直接上代码吧(主要两个文件,小程序前端页面js文件与服务端云函数index.js文件)
//页面js文件const app = getApp()Page({ data: { chatList: [], inputValue: \'\', loading: false, scrollToView: \'\', loadingText: \'发送中...\' }, onLoad() { // 初始化聊天列表 this.setData({ chatList: [{ role: \'assistant\', content: \'你好!我是徒步小智,有什么我可以帮你的吗?\' }] }) }, onInput(e) { this.setData({ inputValue: e.detail.value }) }, async sendMessage() { if (!this.data.inputValue.trim() || this.data.loading) return const userMessage = this.data.inputValue.trim() this.setData({ chatList: [...this.data.chatList, { role: \'user\', content: userMessage }], inputValue: \'\', loading: true, loadingText: \'正在思考中...\' }) this.scrollToBottom() try { const maxRetries = 2 let retryCount = 0 let success = false while (retryCount <= maxRetries && !success) { try { //wx.cloud.callFunction调用该云函数 const response = await wx.cloud.callFunction({ name: \'aiChat\', data: { message: userMessage } }) if (response.result && response.result.data && response.result.data.result) { this.setData({ chatList: [...this.data.chatList, { role: \'assistant\', content: response.result.data.result }], loading: false, loadingText: \'发送中...\' }) success = true } else { throw new Error(\'无效的响应数据\') } } catch (error) { retryCount++ if (retryCount setTimeout(resolve, 1000)) } else { throw error } } } this.scrollToBottom() } catch (error) { console.error(\'AI API调用失败:\', error) this.setData({ chatList: [...this.data.chatList, { role: \'assistant\', content: \'抱歉,我现在有点忙,请稍后再试。\' }], loading: false, loadingText: \'发送中...\' }) wx.showToast({ title: \'请求超时,请稍后重试\', icon: \'none\', duration: 2000 }) } }, scrollToBottom() { const length = this.data.chatList.length if (length > 0) { this.setData({ scrollToView: `msg-${length - 1}` }) } }})
//云函数/cloudfunctions/aiChat/index.js文件const cloud = require(\'wx-server-sdk\')const axios = require(\'axios\')cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV})//定义一个云函数入口,使用async声明异步函数exports.main = async (event, context) => { //从事件对象中解构出用户输入的message参数 const { message } = event try { //axios({ method: \'POST\', ... })使用axios发起POST请求 const response = await axios({ method: \'POST\', url: \'https://qianfan.baidubce.com/v2/chat/completions\', headers: { \'Content-Type\': \'application/json\', \'Authorization\': \'Bearer bce-v3/xxxxxx/xxxxxx\' }, data: { model: \"ernie-3.5-8k\", messages: [ { role: \"user\", content: message } ] } }) // 从响应数据中提取AI助手的回复内容 const aiContent = response.data.choices[0].message.content return { code: 200, data: { result: aiContent } } } catch (error) { console.error(\'API调用错误:\', error) return { code: 500, error: error.message } }}
3.需要注意的问题
1.跨域问题
先说一下,我使用的是百度智能云千帆大模型服务与开发平台ModelBuilder。这是他的官方api调用示例
curl -X POST \'https://qianfan.baidubce.com/v2/chat/completions\' -H \'Content-Type: application/json\' -H \'Authorization: Bearer bce-v3/ALTAK-*****************/2d7*****************\' -d \'{ \"model\": \"ernie-3.5-8k\", \"messages\": [ { \"role\": \"user\", \"content\": \"你好\" } ] }\'
我在postman上面进行测试,发现上面是完全可行的,但当我页面js文件使用 wx.request()无法实现AI API的调用。这让我十分不解,我也去配置了不检验域名,设置了域名白名单。还是无法解决,后来将调用API放进云函数使用axios网络请求库解决实现了调用。
真相大白
经过我的不蟹探究,最后发现是跨域问题。
一、跨域问题的本质
-
浏览器安全策略:
-
跨域限制(CORS)是浏览器强制的安全机制
-
只存在于浏览器环境(包括小程序)
-
服务端之间的通信没有跨域概念
-
-
错误表现示例:
// 前端直接调用会出现的错误Access to XMLHttpRequest at \'https://qianfan.baidubce.com/...\' from origin \'https://your-domain.com\'has been blocked by CORS policy: No \'Access-Control-Allow-Origin\' header is present on the requested resource
二、两种场景对比
场景1:前端直接调用(失败)
sequenceDiagram participant 浏览器/小程序 as 前端 participant 百度API as 服务端 前端->>服务端: wx.request(带Authorization头) 服务端-->>前端: 响应(无CORS头) 浏览器拦截响应 ❌
关键问题:
-
百度API响应头没有设置
Access-Control-Allow-Origin: *
-
浏览器/小程序引擎拒绝解析响应
场景2:云函数中转(成功)
sequenceDiagram participant 浏览器/小程序 as 前端 participant 云函数 as 服务端 participant 百度API as 服务端 前端->>云函数: wx.cloud.callFunction(安全) 云函数->>百度API: axios请求(服务端到服务端)✅ 百度API-->>云函数: 原始响应(无CORS限制) 云函数-->>前端: 返回清洗后的数据
成功关键:
-
前端与云函数同源(或云函数已配置CORS)
-
云函数到百度API是服务端间通信,不受浏览器策略限制
三、云函数的优势详解
-
网络层面:
-
云函数部署在腾讯云/阿里云等服务器
-
默认拥有公网访问能力
-
无需处理证书、代理等复杂配置
-
-
协议层面:
-
服务端之间使用标准HTTP/HTTPS协议
-
无需处理CORS、OPTIONS预检请求
-
-
安全层面:
-
前端永远看不到API密钥
-
可在云函数做请求限流、内容过滤
-
避免直接暴露API端点
-
在我的例子中,前端wx.request链接https://qianfan.baidubce.com服务端会发生跨域问题使无法正确返回,如果放云函数里使用axios方法就是服务端-服务端,就不会有不会有跨域问题
四、为什么小程序用wx.request失败?
根本原因链:
小程序未配置域名白名单 → 百度API未设置CORS头 → 小程序引擎拦截响应 → 开发者工具Network显示请求被blocked
具体限制:
-
小程序要求所有请求域名必须加入
request合法域名
列表 -
即使你配置了
qianfan.baidubce.com
,百度服务器也不会返回CORS头 -
双重限制下必然失败
五、最终结论
通过云函数中转的本质,是把原本需要浏览器处理的跨域请求,转换为服务端之间的自由通信。这种方案:
-
✅ 彻底规避跨域问题
-
✅ 提升安全性
-
✅ 符合企业级应用规范
这是所有主流应用(如ChatGPT、文心一言官方应用)采用的架构设计,也是唯一符合安全规范的实现方式。
2.超时问题
在我的跨域问题解决后又发生了一个问题:
{\"errorCode\":-1,\"errorMessage\":\"Invoking task timed out after 3 seconds\",\"statusCode\":433}
于是首先我在\\miniprogram\\cloudfunctions\\aiChat\\config.json中设置了
{ \"permissions\": { \"openapi\": [] }, \"timeout\": 60, \"triggers\": [], \"memorySize\": 256}
但发现不起作用,于是,我又在云开发里设置超时时间改为了33s,成功解决了该问题(AI思考时间一般较长,默认3s肯定无法正确返回数据)