有奖捉虫:云通信与企业服务文档专题,速来> HOT
随着 ChatGPT 在全球范围的爆火,AI 已成为当下开发者最为关注的焦点,国内各大厂商也纷纷跟进,推出了各自的大模型应用与产品。很多应用都在尝试与AI结合,寻找新的发力点。而新一代大语言模型的强大对话交流能力与各类即时通信场景天然契合,这为 IM 与 AI 结合带来了广阔的想象空间。
在办公场景,用户可以直接通过对话让 AI 辅助自己高效完成工作纪要、文案编写、信息搜集等需求;在客服场景,与 AI 结合的智能客服可以提供真人客服般的会话体验,更有效地引导用户进行购买、使用;在社交场景,AI 聊天机器人可以为用户提供24小时在线的心理咨询和情感陪伴,提升用户粘性……腾讯云即时通信 IM 作为全球领先的通信云服务商,也看到了 AI 在即时通信场景的巨大潜力,快速发布了相关AI能力调用接口。开发者基于腾讯云 IM 提供的通信底座,可以自由调用业内领先的大模型能力,用丰富的AI能力赋能自己,高效实现场景创新。
那具体该如何接入 AI 服务呢?本文将拆解接入 AI 服务的各个步骤,为您详细介绍如何通过腾讯云即时通信 IM 第三方回调功能,将 AI 服务能力引入到 IM 应用中,创建一个可以智能聊天的 AI 机器人,为用户提供真人般对话体验,实现智能客服、创意辅助、工作助手等功能(文中的实践步骤以接入 MiniMax 中文大语言模型为例,类 ChatGPT 服务均可通过文中介绍的方法实现接入)。

准备工作

注册腾讯云 IM 账号

注册并登录腾讯云账号,进入即时通信 IM 控制台,创建应用,并获取应用的 SDKAppID 和密钥(以下称为 IM Key),并创建一个管理员账号 administrator。

注册对应 AI 服务商账号

注册并登录计划接入的 AI 服务商的相应账号并获取 API 密钥(以下称为AI_SECRET_KEY)。

创建腾讯云 IM 机器人账号

通过 REST API 创建一个腾讯云 IM 机器人账号。腾讯云机器人是一种特殊的用户,UserID 以 @RBT# 开头。
curl -d '{"UserID":"@RBT#001","Nick":"MyRobot"}' "https://console.tim.qq.com/v4/openim_robot_http_svc/create_robot?sdkappid= {}&identifier=administrator&usersig={}&random=123456789&contenttype=json"
将上述命令的 sdkappid={} 和 usersig={} 替换成您的 SDKAppID 和使用 IM Key 生成的 Usersig,详情可参见 生成 UserSig。在 Linux 环境运行上述命令后,腾讯云服务器返回:
{"ActionStatus": "OK", "ErrorCode": 0, "ErrorInfo": ""}
表示成功创建了一个昵称为 MyRobot 的机器人@RBT#001。

配置腾讯云 IM 第三方回调

即时通信 IM 第三方回调即云IM后台会在某一事件发生之前或者之后,向 App 的后台服务器发送请求,App 后台可以据此进行必要的数据同步,或者干预事件的后续处理流程。我们将使用“机器人事件回调”监听用户发消息给机器人,或者在群聊中@机器人的事件,并对其做出反应。在腾讯云 IM 控制台中找到“机器人事件回调”,点击开启并保存。

编写 APP 后台服务

以单聊为例,总体上的工作流程如下:
1. 用户 user1 发消息“hello”给机器人@RBT#001;
2. 云 IM 后台发送第三方回调将事件通知 App 后台;
3. App 后台收到事件通知,通知内容包含发送方 user1,接收方 @RBT#001,消息内容 hello 以及其他信息;
4. App 后台调用 AI 服务接口(即MiniMax API),并得到响应回复内容,如 nice to meet you;
5. App 后台调用云 IM REST API接口(单聊为 sendmsg 接口,群聊为 send_group_msg 接口),将回复内容以 @RBT#001 的身份发送给 user1。



以 Golang 为例,App 后台的关键代码可参见下文。
注意:
下文代码仅作为展示用途,省略了大量异常处理代码,不可直接用于生产环境。

分发处理回调命令

我们创建一个监听在80端口的 HTTP 服务,注册一个 url 为 /im 的处理函数 handler,所有发送给 http:///im 的请求都会被 handler 处理。所有云IM发送的回调请求都带有 CallbackCommand 参数,不同的值代表不同的回调命令。在 handler 中,根据云 IM 设置的参数 CallbackCommand 进行对应的处理。
func handler(w http.ResponseWriter, r *http.Request) {
command := r.URL.Query().Get("CallbackCommand")
reqbody, _ := io.ReadAll(r.Body)
var rspbody []byte
switch command {
case "Bot.OnC2CMessage": // 机器人C2C回调命令字
dealC2c(context.Background(), reqbody)
rspbody = []byte("{\\"ActionStatus\\": \\"OK\\", \\"ErrorCode\\": 0, \\"ErrorInfo\\": \\"\\"}")
default:
rspbody = []byte("invalid CallbackCommand.")
}
w.Write(rspbody)
}
func main() { // 注册一个handler,处理发送给App后台的回调命令
http.HandleFunc("/im", handler)
http.ListenAndServe(":80", nil)
}

处理机器人接收到单聊消息事件

处理单聊消息时,我们先检查发送方是不是机器人(一般不会出现这种机器人发送消息给机器人的情况),以防止无限的回调循环。接着,我们解析消息体,拿到用户发送给机器人的消息内容 text,将发送方 UserID 保存到 context 中以方便后续调用 REST API 回复,最后调用 askAI 请求 AI 服务。
func dealC2c(ctx context.Context, reqbody []byte) error {
root, _ := simplejson.NewJson(reqbody)
jFromAccount := root.Get("From_Account")
fromAccount, _ = jFromAccount.String()
// 检查发送方ID,不处理机器人发送给机器人的请求,防止无限循环
if strings.HasPrefix(fromAccount, "@RBT#") {
return nil
}
jToAccount := root.Get("To_Account")
toAccount, _ := jToAccount.String()
msgBodyList, _ := root.Get("MsgBody").Array()
for _, m := range msgBodyList {
msgBody, _ := m.(map[string]interface{})
msgType, _ := msgBody["MsgType"].(string)
if msgType != "TIMTextElem" {
continue
}
msgContent, _ := msgBody["MsgContent"].(map[string]interface{})
text, _ := msgContent["Text"].(string)
ctx = context.WithValue(ctx, "from", fromAccount)
ctx = context.WithValue(ctx, "to", toAccount)
go askAI(ctx, text)
}
return nil
}

调用 AI 服务接口

在这一步我们使用第三方AI服务公司 MiniMax 实现智能聊天的功能,您可以将 MiniMax 服务替换成任意的其它 AI 服务。需要注意的是这里演示的是简单的 completion 接口,没有保存对话的上下文,其他接口可按需查阅 MiniMax 文档。
type MiniMaxRsp struct {
Reply string `json:"reply"`
}

// 请求MiniMax并得到回复
func askAI(ctx context.Context, prompt string) {
url := "https://api.minimax.chat/v1/text/completion"
var reqData = []byte(`{
"model": "abab5-completion",
"prompt": prompt
}`)
request, _ := http.NewRequest("POST", url, bytes.NewBuffer(reqData))
request.Header.Set("Content-Type", "application/json; charset=UTF-8)
request.Header.Set("Authorization", API_SECRET_KEY)
client := &http.Client{}
response, _ := client.Do(request)
defer response.Body.Close()
body, _ := ioutil.ReadAll(response.Body)
rsp := &MiniMaxRsp{}
json.Unmarshal(body, rsp)
reply(ctx, rsp.Reply) // 将AI回复的内容发送给用户
}

将 AI 返回的结果返回给用户

从 AI 服务得到回复之后,我们只需调用云 IM 的 REST API 接口 sendmsg,制定消息发送方为@RBT#001,接收方为 user1,模拟机器人回复用户。
// 发送一个REST API请求
func doRestAPI(host string, sdkappid int, admin, usersig, command, body string) {
url := fmt.Sprintf("https://%s/v4/%s?sdkappid=%d&identifier=%s&usersig=%s&random=%d&contenttype=json",
host, command, sdkappid, admin, usersig, rand.Uint32())
req, _ := http.NewRequest("POST", url, bytes.NewBufferString(body))
req.Header.Set("Content-Type", "application/json")
cli := &http.Client{}
rsp, err := cli.Do(req)
if err != nil {
log.Printf("REST API failed. %s", err.Error())
return
}
defer rsp.Body.Close()
rsptext, _ := io.ReadAll(rsp.Body)
log.Printf("rsp:%s", rsptext)
}

// 调用腾讯云IM的REST API,回复用户
func reply(ctx context.Context, text string) {
rsp := make(map[string]interface{})
msgbody := []map[string]interface{}{{
"MsgType": "TIMTextElem",
"MsgContent": map[string]interface{}{"Text": text},
}}
// GenUserSig 的实现可以参考腾讯云文档
usersig, _ := GenUserSig(IM_SDKAPPID, IM_KEY, "administrator", 60)
rsp["From_Account"] = ctx.Value("to").(string) //"@RBT#001"
rsp["To_Account"] = ctx.Value("from").(string)
rsp["SyncOtherMachine"] = 2
rsp["MsgLifeTime"] = 60 * 60 * 24 * 7
rsp["MsgSeq"] = rand.Uint32()
rsp["MsgRandom"] = rand.Uint32()
rsp["MsgBody"] = msgbody
rspbody, _ := json.Marshal(rsp)
doRestAPI("console.tim.qq.com", IM_SDKAPPID, "administrator", usersig, "openim/sendmsg", string(rspbody))
}

效果展示

使用腾讯云 IM 的 demo 实现,最终的效果展示如下:



通过以上步骤,我们便实现了腾讯云 IM 在服务端和 MiniMaxAI 开放平台的单聊对接,接入其他 AI 服务商也可参照上述步骤,仅需将 askAI 函数替换成其他 AI服务商的对应 API 调用即可。对于群聊机器人,开发者仅需补充实现 Bot.OnGroupMessage 回调命令处理即可。

常见问题:

如何实现机器人欢迎语?(打开机器人聊天对话,机器人自动发送欢迎消息)

客户端可以在用户打开机器人聊天对话框时,客户端发送一条静默的自定义消息,设置 onlineUserOnly 为 true(设置该 flag 表示不存漫游),App 后台通过回调接收到此自定义消息后,调用 REST API 发送欢迎消息。