🌳多平台技术论坛专家博主,全网11W+粉丝
✈️公众号 | 乡下小哥编程 。回复 Java全套视频教程 或 前端全套视频教程 即可获取 300G+ 教程资料及项目实战案例
⭐职场开发经验干货分享、开源项目源码分享
前言
大模型出现很长一段时间了,自己在工作中也已经使用到了。公司中用到的是自己训练的模型,然后我就想能不能在以往的项目中引用大模型接口实现对话呢?在本地跑模型需要的配置挺高的,用在线接口的形式实现是简单方便的。在最近开发的一个项目微信小程序书籍借阅系统添加一个AI自动对话功能,也算是一个亮点。其它的项目也可以借阅相同的实现来集成这个AI自动对话功能~
具体实现过程
1、申请大模型使用
我这里使用的是讯飞大模型,新用户可以免费申请200万Token。自动注册即可,注册过程省略,根据官网一步一步注册即可。
2、开发文档地址
官方文档说明,可以参考文档来具体实现。里边有不同语言的调用实例,比如:JS、Java、Python、小程序等。
3、项目集成
3.1 基本说明
说明:这里和大模型通信是通过Websocket的方式来实现,主要是为了数据的实时返回、持续对话、双向通信等能力。几个重要过程:1、鉴权;2、构造请求报文;3、报文发送、响应处理。
3.2 pom文件引入依赖
由于需要使用到websocket和构造json格式的报文体,所以引入如下两个依赖
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 "出错啦,请稍后再试...";
}
}
- 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.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
前端小程序和后端接口交互
这里可以自己根据前端页面的输入处理,后端接口返回的数据,不同处理实现来取值。这里只是一个简单的演示~ 对应的接口也可以封装处理。
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)
});
}
});
},
- 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.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
3.6 实现效果
这里用户在下方输入内容,然后调用后台接口,将数据发送到后端,后端接口处理和大模型的交互。然后将大模型处理的结果,返回给前端。前端再将结果渲染到页面。

这里有一些和大模型交互的信息,可以看到相关交互信息。



2075

被折叠的 条评论
为什么被折叠?



