微信小程序接入DeepSeek|实现智能对话
前言
随着AI越来越火热,越来越多的产品都接入了DeepSeek,今天我们就来尝试在微信小程序中集成国产顶尖大模型DeepSeek,解锁智能对话|实时翻译|长文本生成三大核心场景。
准备工作
- 注册一个微信小程序账号,并且创建本地小程序工程项目
- 小程序基础库需要在
3.7.1
及以上版本,具备 wx.cloud.extend.AI 对象 - 小程序需要开通「云开发」,可在小程序开发工具中点击工具栏里的「云开发」按钮进行开通,并创建环境(PS:对于首次使用云开发的用户,第一个月套餐免费)
开发,调用大模型
以上工作完成后,我们会得到一个云开发环境ID,接下来我们可以正式接入 DeepSeek API。这里我使用的是Taro
框架,开发过程中会遇到一些坑点,一起往下看看都是如何解决的。
初始化云开发环境
if(process.env.TARO_ENV === \'weapp\') { Taro.cloud.init({ env: \'cloud1-6gxxxxxxxxxxxx\' })}
- 1.
- 2.
- 3.
- 4.
- 5.
创建AI模型
const init = async () => { model = Taro.cloud.extend.AI.createModel(\"deepseek\"); // 创建模型实例,这里使用 DeepSeek 大模型}
- 1.
- 2.
- 3.
- 4.
调用生成文本
const userInput = ref(\'\') // 用户输入内容const messageList = ref([]) // 对话列表const send = async () => { const res = await model.streamText({ data: { model: \"deepseek-r1\", // 指定具体的模型 messages: [ { role: \"user\", content: userInput.value }, ], }, }) // push 用户输入的消息到消息列表 messageList.value.push({ role: \'user\', content: userInput.value, }) userInput.value = \'\' // 清空输入框 if(res.textStream) { // 先push一条空内容,表示ai返回内容 messageList.value.push({ role: \'ai\', content: \'\', }) // 接收大模型的响应 // 由于大模型的返回结果是流式的,所以我们这里需要循环接收完整的响应文本。 for await (let str of res.textStream) { messageList.value[messageList.value.length - 1].content += str; } }}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
整个基本对话流程就好了,我们来看看效果,UI部分代码就不贴了,比较简单(一个输入框一个列表)
可以看到,这样我们就完成了AI对话的基本交互,但是有一个问题,AI思考过程时间比较长,用户对这个过程无感知,容易产生无响应的错觉,所以我们需要优化一下大模型思考等待过程的提示交互。
model.streamText
除了可以传入data数据,也可以传入一些事件监听,需要吐槽一下微信开发文档,写的太粗糙了,事件里面的参数及数据一个也没介绍,完全需要自己调试摸索...
const isGenerating = ref(false)const send = async () => { console.log(\'发送消息\', userInput.value) if(isGenerating.value) { Taro.showToast({ title: \'正在生成中,请稍后再试\', icon: \'none\', }) return } isGenerating.value = true // 将系统提示词和用户输入,传入大模型 const res = await model.streamText({ data: { model: \"deepseek-r1\", // 指定具体的模型 messages: [ { role: \"user\", content: userInput.value }, ], }, onEvent: (event: any) => { console.log(\'event\', event); // 处理事件流 if(event.delta) { // 开始返回内容 console.log(\'开始返回内容\', event.delta); messageList.value[messageList.value.length - 1].status = 2; }else if(event.data === \'[DONE]\') { // 结束返回内容 console.log(\'结束返回内容\'); messageList.value[messageList.value.length - 1].status = 3; } }, onFinish: (event: any) => { console.log(\'finish\', event); // 处理完成事件 messageList.value[messageList.value.length - 1].status = 3; }, }); // push 用户输入的消息到消息列表 messageList.value.push({ role: \'user\', content: userInput.value, status: 3 }) userInput.value = \'\' if(res.textStream) { messageList.value.push({ role: \'ai\', content: \'\', status: 0, }) // 由于大模型的返回结果是流式的,所以我们这里需要循环接收完整的响应文本。 for await (let str of res.textStream) { messageList.value[messageList.value.length - 1].content += str; } } isGenerating.value = false}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
通过事件监听为每条消息加上了一个status
状态
status: number // 0: 发送中 1: 思考中 2: 回答中 3: 回答完成
- 1.
<view v-if=\"item.status 思考中💭...
- 1.
- 2.
- 3.
- 4.
再来看看此时的效果:
处理markdown
由于大模型返回的内容可能会含有markdown语法,所以我们不值简单的直接将大模型返回的内容直接进行渲染,这样就无法还原大模型吐出的排版
比如:
这些markdown语法都没有按预期排版进行渲染,为了排版更加好看,我们还需要处理markdown语法。
小程序虽然支持渲染富文本,但是如何渲染 Markdown 是一个问题。经过调研,我找到了 towxml第三方组件,它除了支持基本的 Markdown 语法,还支持下面三种格式的渲染:
- 支持 echarts 图表(3.0+)
- 支持 LaTex 数学公式(3.0+)
- 支持 yuml 流程图(3.0+)
⚠️需要注意的是:Towxml 是纯微信小程序组件,所以想要在taro项目中使用,还是有点麻烦的。
构建 Towxml
- 下载Towxml源码
git clone https://github.com/sbfkcel/towxml.git
- 1.
- 安装依赖,进入项目根目录找到
config.js
,根据配置文件构建自己需要的功能
npm install
- 1.
由于我只需要markdown部分的处理,所以对于echarts、laTex、yuml我都注释掉了,可以减小产物体积
- 打包,并且将产物放入taro项目中,修改
decode.json
组件引入路径
npm run build
- 1.
使用Towxml组件
产物挪到项目后,就可以使用了,由于是小程序原生组件,所以需要在配置文件中进行引入
export default definePageConfig({ usingComponents: { towxml: \"./components/towxml/towxml\" }})
- 1.
- 2.
- 3.
- 4.
- 5.
调用towxmlParse方法处理markdown
import towxmlParse from \'./components/towxml/index\'const send = async () => { // ... let content = \'\' for await (let str of res.textStream) { // messageList.value[messageList.value.length - 1].content += str; content += str; messageList.value[messageList.value.length - 1].content = towxmlParse(content, \'markdown\'); } // ...}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
打开微信开发者工具,你会发现控制台有警告,组件也不能正常渲染
原因是 Vue 把它当做 Vue 组件来解析,我们可以修改 VueLoader 的编译配置 compilerOptions.isCustomElement
,把此组件声明为原生组件。
plugins: [ [ \'@tarojs/plugin-framework-vue3\', { vueLoaderOption: { compilerOptions: { isCustomElement: (tag) => tag.includes(\'towxml\'), whitespace: \'preserve\', // ... }, reactivityTransform: true, // 开启vue3响应性语法糖 }, }, ], ],
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
再重启项目来看看效果:
可以看到此时的markdown渲染就正常了。