XSwitch CherryGPT 接口(草稿)

CherryGPT 是一个聊天机器人接口和应用程序,一端连接 XSwitch 及 PSTN/VoIP 平台,一端连接 ChatGPT,可以实现电话与 ChatGPT 语音聊天。

ChatGPT 是聊天机器人的巅峰,XSwitch 也很快开发了与 ChatGPT 的接口,用户只需要填入自己的 ChatGPT Token 就可以与 ChatGPT 轻松对接。

另外,为了支持更多聊天机器人开发,CherryGPT 也扩展了 ChatGPT 协议,可以与很多不同的 GPT 类聊天机器人连接,实现丰富的对话场景。AI 开发者也可以参考该协议实现自己的聊天机器人。

综述

CherryGPT 通过XCC协议连接 ChatGPT。架构图如下:

交互流程时序图如下:

CherryGPT 可以支持如下功能:

  • 与 ChatGPT 对接,来电直接与 ChatGPT 对话。
  • 对接 ASR/TTS 平台(阿里、讯飞、百度、思必驰、MRCP 等)做语音识别和语音合成。
  • 对接其他类似 ChatGPT 协议的机器人。
  • 对 ChatGPT 协议扩展,支持更多的对话功能。

ChatGPT 协议简介

CherryGPT 主要使用 ChatGPT 的 chat completions 协议,参考:https://platform.openai.com/docs/api-reference/chat

ChatGPT 协议有两种方式,一种是普通的 HTTP 请求响应协议,另一种是 Server-sent events(SSE)协议,分别对应stream参数的falsetrue

ChatGPT 有三种 role(角色),分别是systemassistantuser

role

  • system:系统角色,用于系统设定,如给 AI 系统一个人设:“你是一个 AI 客服助理,你的名字叫小樱桃”。
  • assistant:助理角色,指聊天机器人(ChatGPT)生成的信息。
  • user:用户产生的信息,如用户说的话。

ChatGPT 本身是无状态的,也就是说 ChatGPT 本身没有对话上下文的概念,所有的上下文信息都在客户端侧(此处是 CherryGPT)维护。在每次请求时携带相应的上下文信息。如:

第一次请求:

"messages": [
    {"role": "system", "content": "你是一个AI客服助理,你的名字叫小樱桃"},
    {"role": "user", "content": "你好,今天天气怎么样?"}
]

ChatGPT 返回结果:

"choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "今天天气晴,适合写代码。你想问点什么呢?",
    },
    "finish_reason": "stop"
}]

后续请求:

messages: [
    {"role": "system", "content": "你是一个AI客服助理,你的名字叫小樱桃"},
    {"role": "user", "你好,今天天气怎么样?"},
    {"role": "assistant", "今天天气晴,适合写代码。你想问点什么呢?"},
    {"role": "user", "帮我写个快速排序程序"}
]

这样,ChatGPT 就可以根据上下文信息生成更加合理的回复。

普通 HTTP

比较简单的用法是使用普通的 HTTP 协议。在连接真实 ChatGPT 服务时延迟比较大(因为 ChatGPT 生成结果比较慢),但如果你基于该协议构建自己的聊天机器人时,可以考虑使用这种模式。

curl 示例:

curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

参数:

{
  "model": "gpt-3.5-turbo",
  "messages": [{ "role": "user", "content": "Hello!" }]
}

返回值:

{
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "created": 1677652288,
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "\n\nHello there, how may I assist you today?"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 12,
    "total_tokens": 21
  }
}

SSE

ChatGPT 使用 Server-sent events 协议,也就是 SSE 协议,这个协议是基于 HTTP 的,所以可以使用 HTTP 的工具来连接 ChatGPT。

SSE 协议会渐近地返回结果,因而延迟不是很大,完全可以用于实时的对话。

关于 SSE 的文档,可以参考:https://developer.mozilla.org/zh-CN/docs/Web/API/Server-sent_events/Using_server-sent_events

注意 Event Stream 在 Nginx 上有个 Bug:https://jvns.ca/blog/2021/01/12/day-36--server-sent-events-are-cool--and-a-fun-bug/

关于 ChatGPT 的协议文本更多可参见:https://github.com/openai/openai-cookbook/blob/main/examples/How_to_stream_completions.ipynb

Todo: 在 htts://git.xswitch.cn/xswitch/xcc-examples/sse/ 上有各种语言的服务器的例子。

快速上手

前提条件:

要连接 ChatGPT,你首先要有一个 Token,将 Token 配置到环境变量里,就可以启动 CherryGPT。

export GPT_TOKEN=.....
./CherryGPT

如果你没有 ChatGPT Token,也可以使用如下方法连接“你自己写的 ChatGPT 服务”,具体协议可以参见上一节的例子。

export GPT_TOKEN=.....
export GPT_URL=http://localhost:8080

如果你还没有自己的 ChatGPT 服务,在 htts://git.xswitch.cn/xswitch/xcc-examples/sse/ 上有各种语言的例子,可以下载测试使用。

以下是一个在线的 ChatGPT 服务器,可以直接使用:

export GPT_TOKEN=demo
export GPT_URL=https://demo.xswitch.cn/api/hello/cn/chat/completions
./CherryGPT

你也可以使用curl命令测试:

export GPT_TOKEN=demo
export GPT_URL=https://demo.xswitch.cn/api/hello/cn/chat/completions
curl $GPT_URL \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $GPT_TOKEN" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

或:

export GPT_TOKEN=demo
export GPT_URL=https://demo.xswitch.cn/api/hello/cn/completions
curl $GPT_URL \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $GPT_TOKEN" \
  -d '{
    "streaming": true,
    "model": "gpt-3.5-turbo",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

环境变量

  • GPT_TOKEN:ChatGPT Token,如果没有 Token,可以使用CHATGPT_URL连接自己的 ChatGPT 服务。
  • GPT_URL:可以指向自己服务器的 URL。
  • DB_URL:可以将聊天记录写入自己的数据库。
  • GPT_PUT_CHANVAR_IN_SYSTEM_ROLE:是否将通道变量放入system role 中,默认为false
  • GPT_STREAMING:是否启用流式请求,默认为false(普通 HTTP),改为true可以支持 SSE。
  • GPT_TTS_ENGINE:TTS 引擎名称,如alibaiduhuaweixunfei等,默认为ali
  • GPT_TTS_VOICE:TTS 声音名称,如aixiaxiaoyun等,默认为default
  • GPT_ASR_ENGINE:ASR 引擎名称,默认为ali

CherryGPT 扩展

CherryGPT 对 ChatGPT 协议做了一些扩展,以便支持更多的场景。

扩展的原则是尽量使用 ChatGPT 原有的字段和字段类型。如果需要增加新的字段类型,也需要小心评估。

system role

CherryGPT 会在 system role 中增加当前通话的信息,如:

{
  "model": "gpt-3.5-turbo",
  "messages": [
    { "role": "system", "content": "channel_uuid=12345678-1234-1234-1234-123456789012" },
    { "role": "system", "content": "caller_id_name=小樱桃" },
    { "role": "system", "content": "caller_id_number=1234" },
    { "role": "system", "content": "dest_number=1234" },
    { "role": "user", "content": "Hello!" }
  ]
}

启用该功能需要启用以下环境变量:

GPT_PUT_CHANNEL_VAR_IN_SYSTEM_ROLE=true

常用的通道变量如下:

  • channel_uuid:通道 ID,本次通话的唯一标识
  • caller_id_name:主叫名称
  • caller_id_number:主叫号码
  • dest_number:被叫号码
  • language:语言,可以为autozh-CNzh-TW

system role 也支持 URLEncode 格式,如:

channel_uuid=1234&caller_id_name=小樱桃&caller_id_number=1234&dest_number=5678

启用该功能需要启用以下环境变量:

GPT_PUT_CHANNEL_VAR_IN_SYSTEM_ROLE=true
GPT_PUT_CHANNEL_VAR_IN_SYSTEM_ROLE_URLENCODE=true

params role

为了语义更明确,也可以增加params role,用于传递参数。跟上面的system role 含义相同,如:

{
  "role": "params",
  "content": "channel_uuid=1234&caller_id_name=小樱桃&caller_id_number=1234&dest_number=5678"
}

一次请求中可以有多个params role。

启动该功能需要启用如下环境变量:

GPT_PUT_CHANNEL_VAR_IN_PARAMS_ROLE=true
GPT_PUT_CHANNEL_VAR_IN_PARAMS_ROLE_URLENCODE=true

cookie role

增加一个cookie的 role,该 role 的所有内容会原样返回,类似浏览器的 cookie,用于保存会话信息。

服务端在返回结果集中返回名为cookie的 role:

 "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "\n\nHello there, how may I assist you today?",
    },
    "finish_reason": "stop"
  }, {
    "index": 1,
    "message": {
      "role": "cookie",
      "content": "any string will be echoed back",
    }
  }, {
    "index": 2,
    "message": {
      "role": "cookie",
      "content": "another string a=1, b=2",
    }
  }, {
    "index": 3,
    "message": {
      "role": "cookie",
      "content": "{\"a\":1, \"b\":2, \"c\": \"string\"}",
    }
  }]

下一次请求时 CherryGPT 将会包含:

{
  "model": "gpt-3.5-turbo",
  "messages": [
    {"role": "cookie", "content": "any string will be echoed back"},
    {"role": "cookie", "content": "another string a=1, b=2"},
    {"role": "cookie", "content": "{\"a\":1, \"b\":2, \"c\": \"string\"}"},
    {"role": "user", "content": "Hello!"}
  ]
}

扩展字段

可以在请求和回复中增加扩展字段。目前的设计是增加一个extra对象。需要使用如下环境变量启用。

GPT_PUT_CHANNEL_VAR_IN_EXTRA_OBJECT=true

具体字段中的含义跟上述systemparams role 中一样。

function_call

服务端可以可以返回function_call,用于指示 CherryGPT 执行一个功能。如:

{
  "message": "电话转接中,请稍候...",
  "content": null,
  "function_call": {
    "name": "transfer",
    "arguments": {
      "number": "1001"
    }
  }
}

其中,arguments为函数的参数,可以是一个 JSON 字符串,或者是一个 JSON 对象。具体的函数列表及参数可以参考下面的定义。

function_call 函数列表

目前系统支持的function_call列表如下,更多函数功能可以根据需求继续补充。

transfer

转接。

参数:

  • number:被转接的号码。具体转接规则需要在服务器端配置。

hangup

挂断。

play

  • url:音频文件的 URL。

record

录音。

对通话进行录音。录音文件路径可以通过其他 API 查询(如media_files REST API)。

更多示例

  • CherryGPT 简易版:用 350 行 Go 代码写一个 ChatGPT 聊天机器人:https://github.com/rts-cn/chatgpt
  • CherryGPT 源代码:CherryGPT 使用 Go 语言开发,是上述简易代码的升级版。如果你想扩展更多功能,可以联系我们购买 CherryGPT 源代码并自行扩展。

XSwitch 功能非常强大,如果你有更多的扩展需要,推荐使用更底层的 API,如: