SpringBoot项目集成讯飞星火大模型实现微信小程序对话功能
大模型出现很长一段时间了,自己在工作中也已经使用到了。公司中用到的是自己训练的模型,然后我就想能不能在以往的项目中引用大模型接口实现对话呢?在本地跑模型需要的配置挺高的,用在线接口的形式实现是简单方便的。
🌳多平台技术论坛专家博主,全网11W+粉丝
✈️公众号 | 乡下小哥编程 。回复 Java全套视频教程 或 前端全套视频教程 即可获取 300G+ 教程资料及项目实战案例
⭐职场开发经验干货分享、开源项目源码分享
文末有实现对话效果演示~
前言
大模型出现很长一段时间了,自己在工作中也已经使用到了。公司中用到的是自己训练的模型,然后我就想能不能在以往的项目中引用大模型接口实现对话呢?在本地跑模型需要的配置挺高的,用在线接口的形式实现是简单方便的。在最近开发的一个项目微信小程序书籍借阅系统添加一个AI自动对话功能,也算是一个亮点。其它的项目也可以借阅相同的实现来集成这个AI自动对话功能~
具体实现过程
1、申请大模型使用
我这里使用的是讯飞大模型,新用户可以免费申请200万Token。自动注册即可,注册过程省略,根据官网一步一步注册即可。
https://xinghuo.xfyun.cn/sparkapi?scr=price
2、开发文档地址
官方文档说明,可以参考文档来具体实现。里边有不同语言的调用实例,比如:JS、Java、Python、小程序等。
https://www.xfyun.cn/doc/spark/Web.html#_1-接口说明
3、项目集成
3.1 基本说明
说明:这里和大模型通信是通过Websocket的方式来实现,主要是为了数据的实时返回、持续对话、双向通信等能力。几个重要过程:1、鉴权;2、构造请求报文;3、报文发送、响应处理。
3.2 pom文件引入依赖
由于需要使用到websocket和构造json格式的报文体,所以引入如下两个依赖
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
3.3 配置文件
这里的配置在登录讯飞平台后,可以看到。将相关配置写入即可、确保参数写对。
3.5 核心代码部分(报文发送及响应处理)
注意:由于源码长度较长,篇幅有限。这里只给出部分核心源码,完整的前后端项目代码已经上传到Github 、可自行查看。后端核心部分处理,和大模型交互的处理。
public String answer(String text, String uid) {
try {
String authUrl = getAuthUrl();
if (authUrl == null || authUrl.isEmpty()) {
logger.error("authUrl为空,无法建立WebSocket连接");
return "出错啦,请稍后再试...";
}
authUrl = authUrl.replace("http://", "ws://").replace("https://", "wss://");
logger.info("最终 WebSocket URL: {}", authUrl);
Request request = new Request.Builder().url(authUrl).build();
OkHttpClient client = new OkHttpClient.Builder().build();
StringBuilder sb = new StringBuilder();
CompletableFuture<String> messageReceived = new CompletableFuture<>();
String body = buildBody(text, uid);
logger.info("发送消息体: {}", body);
WebSocket webSocket = client.newWebSocket(request, new WebSocketListener() {
@Override
public void onOpen(WebSocket webSocket, Response response) {
logger.info("WebSocket 已连接");
webSocket.send(body);
}
@Override
public void onMessage(WebSocket webSocket, String msg) {
logger.info("收到原始消息: {}", msg);
try {
JSONObject obj = JSON.parseObject(msg);
JSONObject header = obj.getJSONObject("header");
// 服务端返回错误处理
if (header.getInteger("code") != 0) {
logger.error("服务端返回错误: {}", obj.toJSONString());
messageReceived.completeExceptionally(
new RuntimeException(header.getString("message"))
);
webSocket.close(1001, "Error");
return;
}
// 处理 payload 内容
JSONObject payload = obj.getJSONObject("payload");
if (payload != null) {
JSONObject choices = payload.getJSONObject("choices");
if (choices != null && choices.getJSONArray("text") != null
&& !choices.getJSONArray("text").isEmpty()) {
// 遍历每条 text
for (int i = 0; i < choices.getJSONArray("text").size(); i++) {
JSONObject t = choices.getJSONArray("text").getJSONObject(i);
// 优先拼接 content
String content = t.getString("content");
if (content != null && !content.trim().isEmpty()) {
sb.append(content);
}
// 如果想保留 reasoning_content 可另存,不拼接到 sb
// String reasoning = t.getString("reasoning_content");
}
}
}
// status==2 表示完整返回,结束 WebSocket
if (header.getLong("status") != null && header.getLong("status") == 2) {
webSocket.close(1000, "Closing WebSocket connection");
messageReceived.complete(sb.toString()); // 返回拼接后的完整文本
}
} catch (Exception e) {
logger.error("解析返回消息异常: {}", e.getMessage(), e);
messageReceived.completeExceptionally(e);
try {
webSocket.close(1011, "Exception");
} catch (Exception ex) {
logger.warn("关闭 WebSocket 异常: {}", ex.getMessage(), ex);
}
}
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
logger.error("WebSocket连接失败", t);
if (response != null) {
logger.error("失败响应: {}", response);
}
messageReceived.completeExceptionally(t);
}
@Override
public void onClosed(WebSocket webSocket, int code, String reason) {
logger.info("WebSocket已关闭: {} - {}", code, reason);
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
logger.info("WebSocket正在关闭: {} - {}", code, reason);
}
});
// 阻塞等待消息返回,带超时
messageReceived.get(30, TimeUnit.SECONDS);
webSocket.close(1000, "Closing WebSocket connection");
return sb.toString();
} catch (Exception e) {
logger.error("错误信息:", e);
return "出错啦,请稍后再试...";
}
}
前端小程序和后端接口交互
这里可以自己根据前端页面的输入处理,后端接口返回的数据,不同处理实现来取值。这里只是一个简单的演示~ 对应的接口也可以封装处理。
sendMessage() {
const text = this.data.inputValue.trim();
if (!text) return;
// 添加用户消息
let newMessages = [...this.data.messages, {
role: 'user',
text
}];
this.setData({
messages: newMessages,
inputValue: '',
toView: 'msg' + (newMessages.length - 1)
});
// 构造 CognitiveMode 需要的 JSON
const requestData = {
message: {
text: [{
role: 'user',
content: text
}]
}
};
wx.request({
url: 'http://localhost:8282/ai/ask', // 你的 Spring Boot 接口
method: 'POST',
data: {
text: JSON.stringify(requestData),
uid: 'wx-user-001'
},
header: {
'Content-Type': 'application/json'
},
success: (res) => {
try {
console.error("对话返回数据:", res)
// 如果 res.data 是字符串,先转对象
let data = res.data;
if (typeof data === "string") {
try {
data = JSON.parse(data);
} catch (e) {
console.error("返回数据不是 JSON 格式:", data);
return;
}
}
// 健壮取值
const text = data?.data?.returnText ?? "抱歉,未获取到回复";
console.error("对话text返回数据:", text)
const reply = text || '抱歉,我暂时无法回答';
const newMessages = [
...this.data.messages,
{
role: 'ai',
text: reply
}
];
this.setData({
messages: newMessages,
toView: 'msg' + (newMessages.length - 1)
});
} catch (err) {
console.error("success 回调异常:", err);
}
},
fail: (res) => {
console.error("对话异常:", res)
newMessages = [...this.data.messages, {
role: 'ai',
text: '网络错误,请稍后再试'
}];
this.setData({
messages: newMessages,
toView: 'msg' + (newMessages.length - 1)
});
}
});
},
3.6 实现效果
这里用户在下方输入内容,然后调用后台接口,将数据发送到后端,后端接口处理和大模型的交互。然后将大模型处理的结果,返回给前端。前端再将结果渲染到页面。
这里有一些和大模型交互的信息,可以看到相关交互信息。
更多推荐
所有评论(0)