1.简述
最近看到新闻,说是百度、字节、商汤、百川、智普等几家企业及机构所发布的生成式大语言模型,通过了《生成式人工智能服务管理暂行办法》,成为首批获得官方备案的大语言模型服务提供商。虽然一直在使用包括文心一言、chatglm这些大语言模型的,但这次好像用着合法合规,有了保障的感觉。
关于百度的文心一言,也是继chatgpt发布以来国内首发跟进,发布的大语言模型了。从文心一言的官方应用上,并没有找到api的使用入口,让我一度以为百度没有开放相关的接口服务。文心一言官方传送门:
https://yiyan.baidu.com/https://yiyan.baidu.com/ 直到有一天下午接到百度AI开放平台的客户回访,顺便咨询了一下文心一言的API相关的问题,才了解到,在百度的千帆大模型平台上,是有提供针对百度自研模型的API服务的。所以简单看了一下千帆大模型平台,果然是有大语言模型的API入口,不止提供有百度的文心一言大模型,也提供了几个主流大语言模型的公共服务。所以,就将百度文心大模型的API服务集成到我的AI二次元姐姐项目里,这样大家又多了一个国内合法的选择了,百度智能云平台传送门:
https://cloud.baidu.com/https://cloud.baidu.com/ 接下来,我将介绍一下如何在百度智能云平台上,开通大语言模型服务,以及如何使用我的AI工具包,在Unity上部署实现AI二次元小姐姐聊天应用。
2.开通大语言模型应用
2.1 千帆大模型平台
使用百度文心大模型应用,首先我们需要注册一个百度账号,这里就不再赘述了。注册账号后,根据上节内容中提到的百度智能云平台,点击链接进入到官方站点。
进入到官方平台页面后,我们可以在顶部的菜单栏里找到【产品->AI开发平台->文心千帆大模型】,从这个入口就可以找到我们需要的文心大模型服务了。
点击文心千帆大模型平台,进入到大模型平台页面,这里我们可以查看文心千帆大模型所提供的各种能力。
能够提供的大语言模型,根据官方文档我们可以了解到,千帆大语言模型平台支持的生成式AI模型包括百度自研的文心一言、文心一格,也包含了多个第三方大模型,如chatGLM、Llama、RWKV,也支持stable diffusion图片生成模型,总体上看还是很强大的。
这里,我们需要的是利用文本生成模型来驱动我们的AI数字人的,所以只需要使用文本生成模型就可以满足我们的需求。百度智能云平台提供了若干种大语言模型的公共服务,我们可以直接使用,包括文心大模型以及一些第三方模型。可支持的大语言模型可详细查看官方文档。
2.2 创建大模型应用
在使用文心大模型之前,我们首先需要创建一个大模型应用,只需要点击文心大模型主页上的【立即使用】按钮,就可以跳转到控制台界面(请先登录账号),在控制台页面中,找到“应用接入”,点击进入到应用创建的页面。
在应用创建视图下,点击“创建应用”,进入到应用创建页面。根据平台的提示,填写应用名称和描述信息,可用的大模型公共服务,平台默认全部勾选了,可以不用管,直接提交创建,这样我们就完成了应用的创建操作。
应用创建成功之后,就可以在控制台界面中找到应用的api key以及secret key这两个密钥,妥善保管好,后面我们会用到。
2.3 开通模型付费
平台所提供大语言模型公共服务,需要我们开通付费后,才能使用。百度千帆大模型平台的模型服务采用的是,按量计费模式,我们先开通模型服务付费之后,再根据使用的token数量,计算费用。我们可以在控制台界面的上方,找到计费管理按钮,点击就可以进入到计费开通界面了。
平台提供的公共模型服务的价格,可以在视图中查看,100万token的价格在几块钱至十几块钱不等,可以根据自己的需求,选择模型进行开通即可。
开通模型付费后,咱们就可以使用相应的模型服务了,接下来,咱们就可以在unity端,进行API对接的代码实现了。
3.API服务对接
千帆大模型平台的API对接流程,和百度AI开放平台的其他服务对接的流程是类似,首先,需要使用应用创建后,拿到的api key以及secret key,通过百度的鉴权api,拿到授权token,这个access token的有效期是30天,可以根据需要更新即可。获取到token后,在大语言模型API对接流程中,我们需要根据所选择的语言模型的访问地址,将token拼接到url中,再进行服务的访问。
接下来,我们来看看详细的对接过程的代码实现吧。
3.1 鉴权接口
百度应用服务的鉴权接口访问,需要提供应用的api key以及secret key,这两个密钥在我们创建应用后,可以在控制台找到。获取access token的api地址如下:
https://aip.baidubce.com/oauth/2.0/tokenhttps://aip.baidubce.com/oauth/2.0/token
代码示例:
using Newtonsoft.Json.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class BaiduSettings : MonoBehaviour
{
#region 参数定义
/// <summary>
/// API Key
/// </summary>
[Header("填写应用的API Key")] public string m_API_key = string.Empty;
/// <summary>
/// Secret Key
/// </summary>
[Header("填写应用的Secret Key")] public string m_Client_secret = string.Empty;
/// <summary>
/// 是否从服务器获取token
/// </summary>
[SerializeField] private bool m_GetTokenFromServer = true;
/// <summary>
/// token值
/// </summary>
public string m_Token = string.Empty;
/// <summary>
/// 获取Token的地址
/// </summary>
[SerializeField] private string m_AuthorizeURL = "https://aip.baidubce.com/oauth/2.0/token";
#endregion
private void Awake()
{
if (m_GetTokenFromServer)
{
StartCoroutine(GetToken(GetTokenAction));
}
}
/// <summary>
/// 获取到token
/// </summary>
/// <param name="_token"></param>
private void GetTokenAction(string _token)
{
m_Token = _token;
}
/// <summary>
/// 获取token的方法
/// </summary>
/// <param name="_callback"></param>
/// <returns></returns>
private IEnumerator GetToken(System.Action<string> _callback)
{
//获取token的api地址
string _token_url = string.Format(m_AuthorizeURL + "?client_id={0}&client_secret={1}&grant_type=client_credentials"
, m_API_key, m_Client_secret);
using (UnityWebRequest request = new UnityWebRequest(_token_url, "GET"))
{
request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
yield return request.SendWebRequest();
if (request.isDone)
{
string _msg = request.downloadHandler.text;
TokenInfo _textback = JsonUtility.FromJson<TokenInfo>(_msg);
string _token = _textback.access_token;
_callback(_token);
}
}
}
/// <summary>
/// 返回的token
/// </summary>
[System.Serializable]
public class TokenInfo
{
public string access_token = string.Empty;
}
}
3.2 大语言模型API对接
3.2.1 请求参数说明
获取到access token之后,我们就可以根据文心大模型的api文档,进行接口对接了。不同模型的接口地址略有差异,我们可以通过查阅API文档,获取到各个模型的访问地址,API文档地址如下:
https://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzuhttps://cloud.baidu.com/doc/WENXINWORKSHOP/s/Nlks5zkzu 通过文档查阅,我们可以发现,千帆大模型平台提供的公共模型服务的访问地址,前面的地址是一样,只有模型名称的差异,注意这点就可以了,我们具体看一下接口的要求。
请求地址(示例):
https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/根据模型而定
名称 | 值 |
---|---|
Content-Type | application/json |
关于access token,我们将token拼接在url里即可,以下是url示例:
https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/根据模型而定?access_token=token值
需要发送的报文结构
名称 | 类型 | 必填 | 描述 |
---|---|---|---|
messages | List(message) | 是 | 聊天上下文信息。说明: (1)messages成员不能为空,1个成员表示单轮对话,多个成员表示多轮对话 (2)最后一个message为当前请求的信息,前面的message为历史对话信息 (3)必须为奇数个成员,成员中message的role必须依次为user、assistant (4)最后一个message的content长度(即此轮对话的问题)不能超过2000个字符;如果messages中content总长度大于2000字符,系统会依次遗忘最早的历史会话,直到content的总长度不超过2000个字符 |
temperature | float | 否 | 说明: (1)较高的数值会使输出更加随机,而较低的数值会使其更加集中和确定 (2)默认0.95,范围 (0, 1.0],不能为0 (3)建议该参数和top_p只设置1个 (4)建议top_p和temperature不要同时更改 |
top_p | float | 否 | 说明: (1)影响输出文本的多样性,取值越大,生成文本的多样性越强 (2)默认0.8,取值范围 [0, 1.0] (3)建议该参数和temperature只设置1个 (4)建议top_p和temperature不要同时更改 |
penalty_score | float | 否 | 通过对已生成的token增加惩罚,减少重复生成的现象。说明: (1)值越大表示惩罚越大 (2)默认1.0,取值范围:[1.0, 2.0] |
stream | bool | 否 | 是否以流式接口的形式返回数据,默认false |
user_id | string | 否 | 表示最终用户的唯一标识符,可以监视和检测滥用行为,防止接口恶意调用 |
message说明
名称 | 类型 | 描述 |
---|---|---|
role | string | 当前支持以下: user: 表示用户 assistant: 表示对话助手 |
content | string | 对话内容,不能为空 |
3.2.2 响应参数说明
以下是后台响应的报文结构
名称 | 类型 | 描述 |
---|---|---|
id | string | 本轮对话的id |
object | string | 回包类型 chat.completion:多轮对话返回 |
created | int | 时间戳 |
sentence_id | int | 表示当前子句的序号。只有在流式接口模式下会返回该字段 |
is_end | bool | 表示当前子句是否是最后一句。只有在流式接口模式下会返回该字段 |
is_truncated | bool | 当前生成的结果是否被截断 |
result | string | 对话返回结果 |
need_clear_history | bool | 表示用户输入是否存在安全,是否关闭当前会话,清理历史会话信息 true:是,表示用户输入存在安全风险,建议关闭当前会话,清理历史会话信息 false:否,表示用户输入无安全风险 |
ban_round | int | 当need_clear_history为true时,此字段会告知第几轮对话有敏感信息,如果是当前问题,ban_round=-1 |
usage | usage | token统计信息,token数 = 汉字数+单词数*1.3 (仅为估算逻辑) |
usage说明
名称 | 类型 | 描述 |
---|---|---|
prompt_tokens | int | 问题tokens数 |
completion_tokens | int | 回答tokens数 |
total_tokens | int | tokens总数 |
注意 :同步模式和流式模式,响应参数返回不同,详细内容参考示例描述。
- 同步模式下,响应参数为以上字段的完整json包。
- 流式模式下,各字段的响应参数为 data: {响应参数}。
3.2.3 代码示例
以下是访问大语言模型API服务的完整代码示例
/// <summary>
/// token脚本
/// </summary>
[SerializeField] private BaiduSettings m_Settings;
/// <summary>
/// 历史对话
/// </summary>
private List<message> m_History = new List<message>();
/// <summary>
/// 选择的模型类型
/// </summary>
[Header("设置模型名称")]
public ModelType m_ModelType = ModelType.ERNIE_Bot_turbo;
/// <summary>
/// 初始化
/// </summary>
private void OnInit()
{
m_Settings = this.GetComponent<BaiduSettings>();
GetEndPointUrl();
}
/// <summary>
/// 发送消息
/// </summary>
/// <returns></returns>
public override void PostMsg(string _msg, Action<string> _callback)
{
base.PostMsg(_msg, _callback);
}
/// <summary>
/// 发送数据
/// </summary>
/// <param name="_postWord"></param>
/// <param name="_callback"></param>
/// <returns></returns>
public override IEnumerator Request(string _postWord, System.Action<string> _callback)
{
stopwatch.Restart();
string _postUrl = url + "?access_token=" + m_Settings.m_Token;
m_History.Add(new message("user", _postWord));
RequestData _postData = new RequestData
{
messages = m_History
};
using (UnityWebRequest request = new UnityWebRequest(_postUrl, "POST"))
{
string _jsonData = JsonUtility.ToJson(_postData);
byte[] data = System.Text.Encoding.UTF8.GetBytes(_jsonData);
request.uploadHandler = (UploadHandler)new UploadHandlerRaw(data);
request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
yield return request.SendWebRequest();
if (request.responseCode == 200)
{
string _msg = request.downloadHandler.text;
ResponseData response = JsonConvert.DeserializeObject<ResponseData>(_msg);
//历史记录
string _responseText = response.result;
m_History.Add(new message("assistant", response.result));
//添加记录
m_DataList.Add(new SendData("assistant", response.result));
//回调
_callback(response.result);
}
}
stopwatch.Stop();
Debug.Log("chat百度-耗时:" + stopwatch.Elapsed.TotalSeconds);
}
/// <summary>
/// 获取资源路径
/// </summary>
private void GetEndPointUrl()
{
url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/" + CheckModelType(m_ModelType);
}
/// <summary>
/// 获取资源
/// </summary>
/// <param name="_type"></param>
/// <returns></returns>
private string CheckModelType(ModelType _type)
{
if (_type == ModelType.ERNIE_Bot){
return "completions";
}
if (_type == ModelType.ERNIE_Bot_turbo)
{
return "eb-instant";
}
if (_type == ModelType.BLOOMZ_7B)
{
return "bloomz_7b1";
}
if (_type == ModelType.Qianfan_BLOOMZ_7B_compressed)
{
return "qianfan_bloomz_7b_compressed";
}
if (_type == ModelType.ChatGLM2_6B_32K)
{
return "chatglm2_6b_32k";
}
if (_type == ModelType.Llama_2_7B_Chat)
{
return "llama_2_7b";
}
if (_type == ModelType.Llama_2_13B_Chat)
{
return "llama_2_13b";
}
if (_type == ModelType.Llama_2_70B_Chat)
{
return "llama_2_70b";
}
if (_type == ModelType.Qianfan_Chinese_Llama_2_7B)
{
return "qianfan_chinese_llama_2_7b";
}
if (_type == ModelType.AquilaChat_7B)
{
return "aquilachat_7b";
}
return "";
}
#region 数据定义
//发送的数据
[Serializable]
private class RequestData
{
public List<message> messages = new List<message>();//发送的消息
public bool stream = false;//是否流式输出
public string user_id=string.Empty;
}
[Serializable]
private class message
{
public string role=string.Empty;//角色
public string content = string.Empty;//对话内容
public message() { }
public message(string _role,string _content)
{
role = _role;
content = _content;
}
}
//接收的数据
[Serializable]
private class ResponseData
{
public string id = string.Empty;//本轮对话的id
public int created;
public int sentence_id;//表示当前子句的序号。只有在流式接口模式下会返回该字段
public bool is_end;//表示当前子句是否是最后一句。只有在流式接口模式下会返回该字段
public bool is_truncated;//表示当前子句是否是最后一句。只有在流式接口模式下会返回该字段
public string result = string.Empty;//返回的文本
public bool need_clear_history;//表示用户输入是否存在安全
public int ban_round;//当need_clear_history为true时,此字段会告知第几轮对话有敏感信息,如果是当前问题,ban_round=-1
public Usage usage = new Usage();//token统计信息,token数 = 汉字数+单词数*1.3
}
[Serializable]
private class Usage
{
public int prompt_tokens;//问题tokens数
public int completion_tokens;//回答tokens数
public int total_tokens;//tokens总数
}
#endregion
/// <summary>
/// 模型名称
/// </summary>
public enum ModelType
{
ERNIE_Bot,
ERNIE_Bot_turbo,
BLOOMZ_7B,
Qianfan_BLOOMZ_7B_compressed,
ChatGLM2_6B_32K,
Llama_2_7B_Chat,
Llama_2_13B_Chat,
Llama_2_70B_Chat,
Qianfan_Chinese_Llama_2_7B,
AquilaChat_7B,
}
4. Unity端数字人配置
项目的源码已经发布到Github了,我们可以直接下载,并导入到unity中使用,要求unity版本在2020.3.44及以上。导入工具包之后,可以在Scene文件夹下,找到示例场景,在场景中找到LLM->chatBaidu对象,这里就维护了百度文心大模型的驱动脚本。
在unity编辑器端,选择chatBaidu对象之后,在属性面板里填写前面创建的应用密钥,并且选择好已经开通付费的大语言模型。
配置一下聊天服务脚本,将AI驱动的脚本改成百度文心大模型的脚本。如果不需要使用语音服务的话,可以在配置栏里,关掉语音服务,这样就可以填写语音服务相关的东西了。
上述配置完成,我们就可以使用百度文心大模型来驱动AI二次元小姐姐了。
5.结束语
这次的文章简单介绍了百度文心大模型平台API的对接流程,并针对接口对接的流程进行了介绍,包括接口的鉴权、以及发送报文、响应报文的结构说明,并提供了针对全流程在unity端的实现代码示例。通过上述的代码实现,我们就可以在unity引擎中,使用百度文心大模型的api来驱动AI二次元小姐姐的对话交互。完整的代码工程可以从我的开源项目下载使用,项目包含了针对多种GPT应用的集成工具,以及语音服务的集成,对我这个项目感兴趣的朋友,可以上我的B站号查看,我也做有详细的教程,相关源码可以在的哔哩哔哩主站找到相关视频,在视频介绍以及评论区获取。
【Unity+文心一言】文心大模型API驱动AI小姐姐,Unity开源工具包,打造AI二次元小姐姐~
项目地址传送门:
AI二次元老婆开源项目(unity-AI-Chat-Toolkit):
Github地址:https://github.com/zhangliwei7758/unity-AI-Chat-Toolkit
Gitee地址:https://gitee.com/DammonSpace/unity-ai-chat-toolkit