AI基础入门(应用开发篇)——OpenAI API:LLM编程的事实标准(上)

目录

一、前提二、OpenAI API2.1、示例2.1、Chat Completions(聊天补全)2.1.1、请求2.1.1.1、核心参数2.1.1.2、工程参数2.1.1.3、工具参数2.1.1.4、模型参数


本文来源:极客时间vip课程笔记

一、前提

虽然大模型数量众多,但就编程接口这件事来说,基本上都是大差不差的。以编程的术语来说,虽然实现各有差异,但接口基本上是统一的。只要学习了其中一个,相信其它 API 你也能够很快地上手。既然要学习,我们还是要有一个具体的学习目标,我在这里选择的是 OpenAI API。之所以选择它,自然是因为 GPT 模型给行业带来的影响,后来者多多少少都会参考它的 API 设计。此外,还有一个很重要的原因,它几乎成了行业的事实标准,现在很多项目选择提供兼容 OpenAI API。有一些中间件性质的项目,不管后台接入的是什么模型,给自己的用户提供的都是 OpenAI 兼容的 API。基于这样的现状,如果只学习一个 API,OpenAI API 是理所当然的选择。

二、OpenAI API

2.1、示例

为了让你有一个直观的感受,我们来看一个具体的例子:


curl https://api.openai.com/v1/chat/completions
-H "Content-Type: application/json"
-H "Authorization: Bearer $OPENAI_API_KEY"
-d '{
        "model": "gpt-4o",
        "messages": [
            {"role": "user", "content": "写一首关于AI的诗"}
        ]
    }'

在了解具体内容之前,我们先从整体上看一下这个 API。虽然我们的主要工作是面向大模型进行编程,但 Open AI API 其实提供了许多功能,比如:

Text Generation:生成和处理文本
Embeddings:文本转向量
Speech to Text:语音转文本
Image Generation:生成图像 Vision:处理图像输入
……

这些不同的接口是通过不同的路径进行区分。这里看到的 /v1/chat/completions 就是我们常用的大模型的编程接口。

除了各种强大的功能,OpenAI API 还有两个关键的参数是各个接口统一的,一个是访问地址,一个是 API Key

之所以访问地址要拿出来单独说,因为在实际使用这个 API 时,我们可能并不是直接访问 OpenAI API,也许是别人提供的兼容的 API,也许是通过代理方式提供的访问,总之,我们使用的地址是不同的地址,需要专门配置。

而 API Key 则比较好理解,不同的 Key 用来标识不同的用户。从上面的例子不难看出,这个 Key 是写在 HTTP 访问的头里。如果我们使用的是 OpenAI 提供的程序库,这两个参数可以通过程序设置,也可以通过命令行设置,下面是使用命令行设置的例子:


export OPENAI_API_BASE="your_api_base_here"
export OPENAI_API_KEY="your_api_key_here"

有了这些通用的知识,接下来,我们来具体关注一下最核心的大模型编程接口。

2.1、Chat Completions(聊天补全)

大模型编程接口的路径是 /v1/chat/completions 。其中,v1 是版本号,这个接口起的名字叫聊天补全。补全,这个名字刚好也呼应了我们前面讲的 GPT 的工作原理。其实,OpenAI 最初有个接口就是单纯地补全,只是 ChatGPT 大火之后,聊天的形式成了主流,聊天补全接口成了我们眼中的主力。新旧两种补全 API 之间最大的差异是,旧 API 传入的是一个提示词,而新 API 传入的是一个消息列表。

2.1.1、请求

我们来看看这个接口的具体内容。作为一个 HTTP 请求,它分为请求和应答两个部分。我们先来看请求。请求的参数非常多,我们会做一个通览。有一点需要提示一下,你学习到这篇内容时,可能与最新的 OpenAI API 文档对不上,因为这个 API 本身也在不断的演化过程中,它会不断地增删参数。

为了方便你理解,我把请求参数划分成四类:

核心参数
工程参数
工具参数
模型参数

2.1.1.1、核心参数

我们先来看核心参数,这也是你学习大模型编程几乎一定会碰到的核心概念。最核心的两个已经呈现在上面的例子中:

model,与哪个模型进行沟通,在这个例子里就是 gpt-4o。

messages,发给模型的消息,这里的消息是一个消息列表,你可以简单地把它理解成一个历史的消息列表,为的就是给模型提供更多的上下文信息。每条消息通常包括两个部分:角色(role)和内容(content)。内容最好理解,就是消息本身的内容。对于常规对话而言,角色主要是系统(system)和用户(user),你可以理解开发者设置的就是系统,用户的问题就是用户。有时,我们还会把大模型生成的消息添加进去,比如,聊天历史,它的角色是助理(assistant)。

除了这两个参数,常用参数还有后面这三个。

temperature,温度的概念我们前面讲过,主要是用来设定大模型回复的确定性,值越小,表示确定性越强,值越大,表示随机性越强。

max_completion_tokens,它表示生成应答的最大 token 数。大模型生成内容通常是按照 token 数计费,所以,限制 max_completion_tokens 大小是控制成本的一种好做法。当然,也不能设置得非常大,你可以理解为每个模型内部都有自己最大限制,当你的限制值大于其内部的限制值时,它就会忽略你的设置。这个字段曾经叫 max_tokens,所以,在很多地方,包括参考 OpenAI 设计的一些框架里,你依然可以看到 max_tokens 的影子。

stream,是否需要流式应答。流式应答主要是为了提升聊天的响应速度,这个部分我们会在下一讲详细地讨论。

请注意,对于不同的模型,这些参数的取值范围可能是不同的,比如,不同模型会有自己的 max_tokens,另外,由于很多服务供应商提供了兼容的 OpenAI API,同样的参数也会有取值范围的差异,比如,在 OpenAI API 里,temperature 的取值范围是从 0 到 2,默认值是 1,而对某些兼容模型而言,其取值范围可能会有所不同,需要根据文档确定。

这里我们梳理了最核心的参数,对于常规聊天,大部分情况下,我们调节的就是这些参数。接下来,我们再来看看其它参数。

2.1.1.2、工程参数

在请求参数中,有一部分是出于工程目的提供的:

user,终端用户标识,它是我们作为开发者提供给 OpenAI 的,主要就是用作监控和检测 API 的滥用,监控粒度就到了个体上。

n,为每条输入消息生成多少个回复。虽然看上去可以生成更多内容,但生成内容要计费,所以,如果没有特别需求,就不要额外设置这个参数。

response_format,应答格式。缺省情况下,这个接口只生成文本内容。但对开发来说,我们经常会用到 JSON 格式。我们当然可以用提示词要求大模型返回,也可以通过设置 response_format 让 API 直接返回 JSON 格式,具体做法可以参考 OpenAI 的结构化输出。

这些参数只是可能会用到的,但真正用到的机会也不多,比如,如果某个用户滥用 API,我们并不会把它放给 OpenAI,而是自己就会处理掉。再比如,虽然 OpenAI 支持 JSON 格式输出,但为了模型的兼容性,我们可能还是会选择使用提示词,让大模型直接返回。

2.1.1.3、工具参数

除了常规的聊天,目前大模型还有一种常见用法,就是构建 Agent。Agent 一个很重要的用法就是扩展大模型的边界,让它能做更多的事情,比如,查询天气、搜索网页等等,这些可以做的事情大模型怎样知道呢?

除了常规的聊天,目前大模型还有一种常见用法,就是构建 Agent。Agent 一个很重要的用法就是扩展大模型的边界,让它能做更多的事情,比如,查询天气、搜索网页等等,这些可以做的事情大模型怎样知道呢?

工具参数里最常用的是这两个:

tools,模型可以调用的工具列表。其中的每个工具都会包含 type(类型)和 function(函数)两个部分。目前 type 表示工具的类型,目前只有 function 一个类型。function 主要用来告诉模型函数可以怎样调用,包含 description(函数的描述),name(函数名)以及 parameters(函数参数)。

tool_choice,选择怎样调用工具。参数值为 none 表示不调用工具,auto 表示模型自行选择是生成消息,还是调用工具,required 表示必须调用工具。这个参数值也可以是一个对象,比如,下面这行代码就告诉模型,要调用我指定的这个工具。


{"type": "function", "function": {"name": "my_function"}}
2.1.1.4、模型参数

如果说上面这些参数还是比较好理解的,看参数名就知道是干什么的,还有一大堆参数看上去就比较令人费解了,比如,frequency_penalty。其实,这些参数通常不是给开发应用的工程师用的,你可以理解成它们都是给模型开发者预备的,所以,我把它归入到模型参数的行列里。你可以简单地了解一下,等你哪一天真的要用它,再去深入也不迟。

seed,种子值。种子值的存在是为了解决可重复输出的问题,也就是说,如果采用相同的种子值以及相同的参数,生成的输出结果应该是一样的。采用开发的视角来看,我们可以把这种行为理解为缓存。

stop,停止序列。它用来告诉大模型,在生成文本的过程中,如果遇到停止序列,就停止生成。

frequency_penalty(频率惩罚)和 presence_penalty(存在惩罚)。这两个参数主要是为了减少内容重复的几率,所以,名字里都带有“惩罚”。二者的差别就是,frequency_penalty 表示根据一个 token 在已生成文本中出现的频率计算,presence_penalty 则表示根据一个 token 是否已经出现进行来计算。

logit_bias,logit 偏差。logit 是统计学中的一个函数。这个参数就是在 logit 函数计算中调整计算结果,主要的目的就是修改某些 token 出现的可能性,比如,我不希望某些词出现在最终的结果里。

logprobs:是否返回对数概率。前面我们说过,大模型生成每个 token 都是有概率的,如果设置了这个参数,就可以把概率返回,对大模型开发人员来说,方便进行调试。这里的概率采用对数的方式进行表示。

top_logprobs:返回每个位置最可能返回的 token 数量。如果要调试大模型,除了希望知道概率,有时候,我们还想知道排名靠前的 token 都有哪些。通过设置这个参数,我们就可以让大模型返回这些排名靠前的 token。

top_p:另一种采样方式,与 temperature 相对。我们前面讲了温度决定了大模型如何选取下一个 token,top_p 是另外一种采用方式,也就是在概率前多少的 token 中进行选择。在实际的使用中,选择 top_p 和 temperature 其中之一就好了。

至此,我们把补全接口的请求参数讲了一遍,你已经对它有了一个初步的认识,下一讲,我们还要再用一讲的篇幅讲讲聊天补全接口的应答。

注:后续技术类文章会同步到我的公众号里,搜索公众号 小志的博客 感兴趣的读友可以去找来看看。

© 版权声明

相关文章

暂无评论

none
暂无评论...