ChatGPT是一种基于GPT-3.5架构的强大自然语言处理技术,该技术由OpenAI开发,为开发者和企业提供高质量的自然语言交互能力。GPT-4.0 模型在性能方面超越了其前代模型,表现出增强的语言理解和生成能力,为用户带来更精确、更有吸引力的响应。
该模型还能够学习和适应各个领域特定的语言,使其适用于不同的行业和用例。
利用 ChatGPT API,开发人员可以将强大的自然语言处理技术无缝集成到他们的应用程序中。
API 的常见用例包括聊天机器人、智能客户服务、自然语言搜索引擎和自动语言翻译工具等。这些应用可以为用户提供更加自然、流畅、智能的体验,最终提升用户满意度和效率。
API介绍
本文主要介绍如何与OpenAI的API集成,使您能够利用GPT-3.5模型快速创建聊天演示。
当然,习惯于自行探索官方 API 文档的经验丰富的程序员当然可以实现这一目标。这样做的目的是降低使用OpenAI服务的准入门槛,帮助每个人更好地理解和有效利用它们。
官方API文档可参见:
platform.openai.com/docs/api-re...
1. API 密钥。
当您想要使用 OpenAI 的 API 时,第一步是创建您自己的 API Key。所有请求都需要使用 API 密钥进行身份验证。
登录
platform.openai.com/并访问地址: https: //platform.openai.com/account/api-keys创建您自己的API密钥。如图所示:
创建密钥时,请务必立即复制并保存,因为密钥信息只会显示一次,您将无法再次看到密钥详细信息。
2.发出请求
实现聊天功能实际上非常简单。您只需要向此 API 发出 POST 请求:
api.openai.com/v1/chat/com... 这是最简单的例子:
vbnet
curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [{"role": "user", "content": "Hello!"}]
}'
可以看到需要在请求标头中配置OPENAI_API_KEY,就是上一步生成的api秘钥
请求体中,有两个参数:
- model:本次对话使用的模型是gpt-3.5-turbo。
- message:本次对话的消息。
最初使用 ChatGPT 时,我很困惑后端如何能够记住这么多轮对话,并在切换到不同交互时无缝地延续上下文。
后来了解到,在每次查询期间,整个对话历史记录都会发送到后端,从而使 ChatGPT 能够分析所有聊天信息中的上下文,并相应地提供后续响应。
在进行 API 调用时,其工作原理是相似的。请求messages中的 是一个JSON数组,其中包含正在进行的对话的所有消息。这确保了对话上下文的连贯性,使模型能够理解并生成与对话历史一致的响应。
数组中的每个值都有两个属性:
-
role:代表消息发送者的角色,可以是system、user、assistant或function。
-
content:包含各自角色发送的文本内容。
参数中role各个值代表的含义如下:
-
system:表示对话的系统级指令或上下文。
-
user:代表用户发送的消息。
-
assistant:代表 ChatGPT 助手生成的响应。
这些角色有助于定义对话中参与者的角色,并指导模型根据每个角色提供的上下文生成相关响应。所有这些属性都有助于构建对话结构并为从模型生成适当的响应提供上下文。
因此,经过几轮对话后,请求参数messages应该如下所示:
vbnet
curl https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [{"content":"你是谁","role":"user"},
{"content":"我是ChatGPT,OpenA开发的人工智能语言模型","role":"assistant"},
{"content":"你能做什么","role":"user"},
{"content":"我可以回答问题、提供信息、聊天","role":"assistant"}]
}'
有关messages的更多信息,可以访问官方文档:
platform.openai.com/docs/guides...
3.其他重要的输入参数
上面只是最基本的例子,只包含两个必填参数:model和messages。
除了这些之外,API 还接受其他参数。
这里我重点介绍几个常用的参数:
- temperature:该参数控制生成文本的随机性,取值范围为0到2。较大的值会导致更随机的输出,而较小的值会导致更可预测的输出。通常,值设置在0.5和之间1。
- max_tokens:生成文本的最大长度,以词汇标记来衡量。该参数控制生成文本的长度。
- stop:用于控制生成文本的停止条件。该参数是一个字符串数组,当数组中的任何字符串出现在生成的文本中时,API将停止生成。
- frequency_penalty和presence_penalty:这两个参数用于控制生成文本的多样性,其值范围为-2.0到2.0。frequency_penalty控制生成文本中重复词汇的数量,同时presence_penalty影响生成文本中的单词与输入文本中的单词之间的相似度。通常,这两个参数的值应介于0和 之间1。
4. 响应参数
API 响应示例如下:
json
{
"id": "chatcmpl-6p9XYPYSTTRi0xEviKjjilqrWU2Ve",
"object": "chat.completion",
"created": 1677649420,
"model": "gpt-3.5-turbo",
"usage": {
"prompt_tokens": 56,
"completion_tokens": 31,
"total_tokens": 87
},
"choices": [
{
"message": {
"role": "assistant",
"content": "你好"
},
"finish_reason": "stop",
"index": 0
}
]
}
响应的choices的内容为当前交互生成的消息。
通过解析此消息,您可以检索消息的内容和角色以完成对话。这使您可以保持对话的上下文和连续性以进行进一步的交互。
响应中的usage部分提供有关当前请求的令牌消耗的信息。以下是它的每个部分代表的含义:
- prompt_tokens:请求中提供的提示消息中使用的token数量。
- completion_tokens:生成的消息中使用的token数量。
- Total_tokens:prompt_tokens和completion_tokens的总和,代表请求中使用的token总数。
- max_tokens:请求中允许的最大token数,如请求中所指定。
此信息可以跟踪令牌使用情况并在计划的令牌限制内有效管理您的 API 调用。
token是什么?
GPT 和嵌入模型以称为标记的块的形式处理文本。标记代表常见的字符序列。例如,字符串"tokenization"被分解为"token"和"ization",而像"the"这样的短而常见的单词则被表示为单个token。请注意,在句子中,每个单词的第一个标记通常以空格字符开头。查看我们的标记生成器工具来测试特定字符串并查看它们如何转换为标记。根据粗略的经验,1 个标记大约相当于 4 个字符或英文文本的 0.75 个单词。
要记住的一个限制是,对于 GPT 模型,提示和生成的输出之和不得超过模型的最大上下文长度。对于嵌入模型(不输出标记),输入必须短于模型的最大上下文长度。每个 GPT 和嵌入模型的最大上下文长度可以在模型索引中找到。
摘自:简介------OpenAI API
实现对 OpenAI 的 GPT-3.5 模型的基本 API 调用
其实代码实现并不难。核心逻辑涉及调用 OpenAI 的 API 并缓存每个对话的消息。同时参数要可配置,并考虑多用户并发使用时的隔离。
该项目是用Java开发的,使用JDK版本1.8,并使用Spring-Boot版本2.7.9构建。HTTP请求使用OkHttp3处理,缓存使用Guava缓存组件实现。
1. 请求头
typescript
private Map getGPTHeader() {
Map header = Maps.newHashMap();
// 你的APIkey
header.put("Authorization", "Bearer " + baseConfig.getChatGptApiKey());
header.put("Content-Type", "application/json");
return header;
}
2.请求体
less
private Map getGPTRequestBody(List msgs) {
Map body = Maps.newHashMap();
body.put("model", "gpt-3.5-turbo");
body.put("messages", msgs);
body.put("max_tokens", baseConfig.getMaxTokens());
body.put("temperature", baseConfig.getTemperature());
return body;
}
3.发送请求
ini
Map header = getGPTHeader();
List msgs = getMsgs(text, fromUser);
Map body = getGPTRequestBody(msgs);
MediaType mediaType = MediaType.parse("application/json;charset=utf-8");
RequestBody requestBody = RequestBody.create(JSON.toJSONString(body), mediaType);
ini
String response;
try {
response = OkHttpUtil.post(COMPLETION_URL, requestBody, header);
} catch (Exception e) {
return "异常";
}
发出请求后解析响应中的数据,主要关注处理JSON格式的数据。这样,我们就可以检索ChatGPT返回的结果。
缓存的设计
缓存的目的是保存每次对话的历史聊天记录,保证以后对话的流畅性和承接。
在这里,只在用户层面设计了差异化,这意味着每个用户只有一组对话。我们将此对话的消息列表保存在缓存中。
当然,如果需要支持每个用户拥有多组对话的可能性,可以相应地添加另一层。
swift
public class CacheUtil {
/ 会话缓存,其中键是用户名,值是一组会话的历史消息列表。
private static final Cache<String, List<GPTMessageDTO>> CHAT_GPT_CACHE;
}
scss
static {
CHAT_GPT_CACHE = CacheBuilder.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES).build();
}
public static void setGptCache(String userName, List<GPTMessageDTO> gptMessageDtos) {
CHAT_GPT_CACHE.put(userName, gptMessageDtos);
}
// 获取用户的消息列表
public static List<GPTMessageDTO> getGptCache(String userName) {
List<GPTMessageDTO> messageDtos = CHAT_GPT_CACHE.getIfPresent(userName);
if (CollectionUtils.isEmpty(messageDtos)) {
return Lists.newArrayList();
}
return messageDtos;
}
// 清除相应用户的会话缓存。
public static void clearGptCache(String userName) {
List<GPTMessageDTO> messageDtos = CHAT_GPT_CACHE.getIfPresent(userName);
if (CollectionUtils.isNotEmpty(messageDtos)) {
messageDtos.clear();
}
}
}
参数配置
将API调用所需的参数放在配置文件中,方便修改:
ini
chatgpt.apiKey=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
chatgpt.maxTokens=1024
chatgpt.temperature=0.8
chatgpt.maxChatNum=15
chatgpt.isContinuous=true
代码:
kotlin
@Configuration
@Getter
public class BaseConfig {
@Value("${chatgpt.apiKey}")
private String chatGptApiKey;
@Value("${chatgpt.maxTokens}")
private int maxTokens;
@Value("${chatgpt.temperature}")
private double temperature;
@Value("${chatgpt.maxChatNum}")
private Integer maxChatNum;
@Value("${chatgpt.isContinuous}")
private boolean isContinuous;
}
在controller层提供一个 POST 接口
less
@RestController
@Slf4j
public class ChatGptController {
@Autowired
private ChatGPTService chatGptService;
@PostMapping("/chat")
public String receiveMsgFromDd(@RequestBody ChatRequestVO chatRequestVO) {
return chatGptService.chatToGPT(chatRequestVO.getContent(), chatRequestVO.getUserName());
}
}
怎么省钱?
当会话生成多条消息时,每个请求将消耗大量token。
token就是钱!
所以,降低成本的方法就是避免过度的token消耗。我们可以使用以下方法来优化对话:
限制对话长度:您可以设置对话的最大长度,以避免生成过多的文本。在生成下一个响应之前,请检查对话历史记录的长度是否超出限制。如果是这样,您可以选择结束对话或清除历史记录并重新开始。
优化对话历史记录:尽可能避免在对话历史记录中包含不相关或冗长的文本。由于不确定文本的长度,因此您可以使用固定大小的队列来存储消息。这意味着仅保留最新消息作为请求的一部分,从而提供受控数量的上下文信息。
如果喜欢这篇文章,点赞支持一下,微信搜索:京城小人物,关注我第一时间查看更多内容,最近需要面试的同学,可以点击面试笔记获取面试笔记!感谢支持!