实践 | 即时通信IM如何接入AI服务,搭建聊天机器人

随着ChatGPT在全球范围的爆火,AI已成为当下开发者最为关注的焦点,国内各大厂商也纷纷跟进,推出了各自的大模型应用与产品。很多应用都在尝试与AI结合,寻找新的发力点。而新一代大语言模型的强大对话交流能力与各类即时通信场景天然契合,这为IM与AI结合带来了广阔的想象空间。

那即时通信IM该如何接入AI服务呢?本文将拆解接入AI服务的各个步骤,为您详细介绍如何通过腾讯云即时通信IM第三方回调功能,将AI服务能力引入到IM应用中,创建一个可以智能聊天的AI机器人,为用户提供真人般对话体验,实现智能客服、创意辅助、工作助手等功能。(文中的实践步骤以接入MiniMax中文大语言模型为例,类ChatGPT服务均可通过文中介绍的方法实现接入)

准备工作

注册账号

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

注册对应AI服务商账号

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

创建即时通信IM机器人账号

通过REST API创建一个机器人账号。机器人是一种特殊的用户,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的生成可以参考官网文档(https://cloud.tencent.com/document/product/269/32688)。在Linux环境运行上述命令后,云服务器返回:

{"ActionStatus":"OK","ErrorCode":0,"ErrorInfo":""}

复制

表示成功创建了一个昵称为MyRobot的机器人@RBT#001。

配置即时通信IM第三方回调

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

编写APP后台服务

以单聊为例,总体上的工作流程如下:

用户user1发消息“hello”给机器人@RBT#001;

云IM后台发送第三方回调将事件通知App后台;

App后台收到事件通知,通知内容包含发送方user1,接收方@RBT#001,消息内容hello以及其他信息;

App后台调用AI服务接口(即MiniMax API),并得到响应回复内容,如nice to meet you;

App后台调用云IM REST API接口(单聊为sendmsg接口,群聊为send_group_msg接口),将回复内容以@RBT#001的身份发送给user1。


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

分发处理回调命令

我们创建一个监听在80端口的http服务,注册一个url为/im的处理函数handler,所有发送给http://<your.domain.com>/im的请求都会被handler处理。所有云IM发送的回调请求都带有CallbackCommand参数,不同的值代表不同的回调命令。在handler中,根据云IM设置的参数CallbackCommand进行对应的处理。

funchandler(w http.ResponseWriter, r *http.Request) {  command := r.URL.Query().Get("CallbackCommand")  reqbody, _ := io.ReadAll(r.Body)varrspbody []byteswitchcommand {case"Bot.OnC2CMessage":// 机器人C2C回调命令字dealC2c(context.Background(), reqbody)    rspbody = []byte("{\"ActionStatus\": \"OK\", \"ErrorCode\": 0, \"ErrorInfo\": \"\"}")default:    rspbody = []byte("invalid CallbackCommand.")  }  w.Write(rspbody)}funcmain() {// 注册一个handler,处理发送给App后台的回调命令http.HandleFunc("/im", handler)  http.ListenAndServe(":80", nil)}

复制

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

处理单聊消息时,我们先检查发送方是不是机器人(一般不会出现这种机器人发送消息给机器人的情况),以防止无限的回调循环。接着,我们解析消息体,拿到用户发送给机器人的消息内容text,将发送方UserID保存到context中以方便后续调用REST API回复,最后调用askAI请求AI服务。

funcdealC2c(ctx context.Context, reqbody []byte) error {  root, _ := simplejson.NewJson(reqbody)  jFromAccount := root.Get("From_Account")  fromAccount, _ = jFromAccount.String()// 检查发送方ID,不处理机器人发送给机器人的请求,防止无限循环ifstrings.HasPrefix(fromAccount,"@RBT#") {returnnil  }  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)ifmsgType !="TIMTextElem"{continue}    msgContent, _ := msgBody["MsgContent"].(map[string]interface{})    text, _ := msgContent["Text"].(string)    ctx = context.WithValue(ctx,"from", fromAccount)    ctx = context.WithValue(ctx,"to", toAccount)    goaskAI(ctx, text)  }returnnil}

复制

调用AI服务接口

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

typeMiniMaxRspstruct {Replystring`json:"reply"`}// 请求MiniMax并得到回复funcaskAI(ctx context.Context, prompt string) {  url :="https://api.minimax.chat/v1/text/completion"varreqData = []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请求funcdoRestAPI(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)iferr != 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,回复用户funcreply(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"] =2rsp["MsgLifeTime"] =60*60*24*7rsp["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在服务端和MiniMaxAI开放平台的单聊对接,接入其他AI服务商也可参照上述步骤,仅需将askAI函数替换成其他AI服务商的对应API调用即可。对于群聊机器人,开发者仅需补充实现Bot.OnGroupMessage回调命令处理即可。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容