跳到内容 跳到主导航 跳到页脚

流式问答对话

流式问答对话是模仿打字机效果的对话方式,大模型可以在很短时间内就开始输出,体验更好。推荐在任何支持流式输出的场景中使用这种方式进行对话。

发起请求

  • 请求方法: POST
  • 请求 URL: /v1/ctai/query_text_chat

请求参数

{
    "query_text": "你好,请问2路汽车在哪里乘坐",
    "ctdoc_id": "test_doc_id",
    "session_id": "test_id",
    "enable_citation": "1",
    "enable_followup": "1",
    "smart_temp": "0",
    "lang":"en",
    "context": "test_context",
    "stream": "1",
}

请求参数

参数类型必需参数说明
query_textstring问题文本,例如:你好。
ctdoc_idstring文档 id,多个用英文逗号分隔,如果指定了文档 id 则只从指定的文档中思考,如果不指定则从全部文档中思考。
session_idstring会话 id,用于串连多轮聊天的会话 id,相同会话 id 的多次问答才能形成多轮问答。不能超过 64 字节,只允许数字英文和 -_. 字符。
enable_citationstring是否返回引文,默认返回。0:否 , 1:是。
enable_followupstring是否返回推荐问题,默认返回。0:否 , 1:是。
smart_tempstringAI 创造性等级,取值是 0-10。0 为最保守等级,10 为最大限度自由发挥等级。
langstring语言,如果没有指定会根据 query_text 自动检测语言。指定只可提高回复语音准确性
可选值有:zh_CN / en_US / ko_KR / ja_JP / th_TH。
contextstring默认是空。外部传入的上下文, 字符串类型,会被当作一个完整的检索出来的片段,放入给大模型的prompt中的[参考资料]中
enable_elaboratestring是否启用详细阐述,默认是启用。0:关闭 , 1:启用。其中这个功能可以让AI适当发挥写出更丰满的文字,但适当发挥也可能导致它产出一些错误答案
streamstring是否以流式输出, 默认是非流式,0: 否 ,1: 是。流式会话问答,填1
categorystring用什么方式聊天
doc_chat:基于知识库聊天(默认值)
tpl_chat:创作中心
ctprofile_idstring聊天人设选择。
当category为doc_chat时,这个值不用传。在项目设置中设置啥人设,就是啥人设
当category是tpl_chat是,有如下两个选择:
– creator:无历史记录的创作者中心专用人设。
– writer:有历史记录的创作中心专用人设(默认值)。

流式应答

流式应答使用 SSE(Server-Sent Events)协议;且暂不支持接收 Last-Event-Id Header,也就是暂不支持通过包 id 恢复中断的 SSE 连接;

流式应答分包规则为“中间包”和“结束包”两种,分包的最后一个包为结束包,除结束包外其他分包均为中间包,所有分包送出完毕之后会主动关闭连接。他们分别如下:

  • 中间包的规则如下:
    • 中间包仅包含当前包中内容的引文的文档列表和推荐问题列表;
    • 中间包的 event 字段为空串;
  • 结束包的规则如下:
    • 结束包不包含任何实际 answer 内容,也就是说结束包是在所有 answer 全部输出完成之后(通过中间包输出),额外单独附加的一个特殊包;
    • 结束包的 event 字段为 stop;
    • 结束包中包含了本次 query 的整体 answer 的全部引文的文档列表和推荐问题列表;

应答 Header

  • Content-Type : text/event-stream

注意

应答header不再是返回json,所以在发起请求时不能添加accept为json的header。

应答示例

这里以应答“你好”为例,它可能被拆成两个数据包传输,并且在最后附加一个结束标志包(event为stop)。最终应答一共三个数据包。

id: test_id_1
data: {"ret":"0","data":{"msg_id":"test_id_1","msg_sn":"0","event":"","answer_text":"你"}}

id: test_id_2
data: {"ret":"0","data":{"msg_id":"test_id_2","msg_sn":"1","event":"","answer_text":"好"}}

id: test_id_3
data: {"ret":"0","data":{"msg_id":"test_id_3","msg_sn":"2","event":"stop","answer_text":""}}

具体每一个数据包的数据包格式化后是这个样子:

{
    "ret":"0",
    "msg":"",
    "data":{
        "msg_id": "test_id",
        "msg_sn": "1",
        "event": "stop",
        "answer_text": "你",
        "ref_doc_list": [],
        "follow_up_list": [],
        "illegal_status": "0",
        "extend_info": {
            "ialgo_extend_info": { 
                "return_type": "intervention_return", 
                "doc_score": [ 
                    {
                        "doc_id": "", 
                        "score": "1.233"
                    },
                    // 其他文档分值信息
                ]
            }
        },
    }
}
参数类型参数说明
retstring结果代码,字符串类型,成功是 0,失败是非 0,具体错误详见附录以及具体接口说明。
msgstring错误信息,如果成功是空串。
dataobject业务参数信息对象。
msg_idstring每个分包的唯一 id,每个分包 id 都是全局唯一的
msg_snstring每个分包的序号,从 0 开始,每个包 +1
eventstring当前流式分包的 event,event=为空串表示中间包,event=stop 表示最后一个包
answer_textstring与非流式接口的同名参数一致。每个引文的文档 id 块和 follow up 块会整体返回,不会被拆分成多个包返回。
ref_doc_listarray文档引用列表,与非流式应答的同名参数一致。
follow_up_listarray推荐问题列表,与非流式应答的同名参数一致。
extend_infojsonobject扩展信息字段,与非流式应答的同名参数一致。

前端使用流式应答API

如果是JavaScript前端使用SSE,我们推荐微软的库:FetchEventSource。 这个库封装得很好,下面是一个使用的示例:

import { EventSourceMessage, fetchEventSource } from '@microsoft/fetch-event-source';
fetchEventSource(url,{
    method: 'POST',
    headers,
    body: JSON.stringify(d),
    openWhenHidden:true,
    onmessage:(ev:EventSourceMessage) => {
      try {
        const res = JSON.parse(ev.data);
        console.log('【SSE】',res);
        const {ret,data,msg} = res;
        if (ret === '0') {
          if (data.ref_doc_list && data.ref_doc_list.length > 0) {
            doc_list = doc_list.concat(data.ref_doc_list)
          }
          data.ref_doc_list = doc_list;
          result += data.answer_text;
          onMessage && onMessage(result,data);
        } else {
          const error = getErrorInfo(ret,msg);
          if (result) {
            result += "\n"+error
          } else {
            result = error;
          }
        }
      } catch (error) {
        console.log('【chat-error】',error);
      }
    },
    async onopen(response) {
      console.log('SEE-open',response.status);
      if (response.status === 200) {
        return;
      }
  },
  onclose() {
    console.log('SEE-close');
      return;
  },
  onerror(err) {
    console.log('SEE-e',err);
  }
  }).then(()=>{
    console.log('最终答案',result);
    return {
      text:result,
      ref_doc_list:doc_list,
    } 
  }).catch(e=>{
    console.log('query-catch',e);
    return {
      text:result,
      ref_doc_list:doc_list,
    } 
  })

这篇文章是否有帮助?

相关文章