OpenAI接口开发指南

OpenAI主要API

OpenAI Api 官方地址为:https://platform.openai.com/docs/api-reference,常用的 OpenAI Api 接口总共分为 4 类:对话类、私有化模型训练类、通用类、图片 & 音频类,其中对话类与私有化模型训练类是最常用的。

对话类接口

这类是最常用也是最核心的接口,用于人机对话。对话类接口又细分为:Chat、Completions。Chat 是指多轮对话;Completions 是指单轮对话,主要用于一次性生成一篇文章等,不具备多次对话交互的能力。

Chat(多轮对话)

请求地址: POST https://api.openai.com/v1/chat/completions

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": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello!"}]}'

Completions(单轮对话)

请求地址:POST https://api.openai.com/v1/completions

示例:

curl "https://api.openai.com/v1/completions" \-H "Content-Type: application/json" \-H "Authorization: Bearer $OPENAI_API_KEY" \-d '{"model": "text-davinci-003","prompt": "Say this is a test","max_tokens": 7,"temperature": 0}'

参数prompt:用户输入的提示词,由于 Completions 是单轮对话,所以不像 Chat 接口 messages 那么复杂

私有化模型构建类

这类是用于构建私有化模型的相关接口。私有化模型构建分为两种方式:Embeddings、Fine-tunes。两个模型这里简单的介绍下:

Embeddings,以改变上下文的方式来打造私有化模型,该方式不对 GPT 本身的模型进行调整。

Fine-tunes,基于 GPT 的模型再进行额外的训练,会对 GPT 模型本身的参数进行微调。

Embeddings请求地址:POST https://api.openai.com/v1/embeddings

示例:

curl "https://api.openai.com/v1/embeddings" \-H "Authorization: Bearer $OPENAI_API_KEY" \-H "Content-Type: application/json" \-d '{"input": "The food was delicious and the waiter...","model": "text-embedding-ada-002"}

Embedding 建议使用 text-embedding-ada-002,input表示需要向量化的数据

Fine-tunings的接口比较多,这里主要介绍创建 Fine-tunning 的接口。大多数场景下,都会“离线”完成模型训练,然后“在线”实时调用训练后的模型,而“离线”训练更多的是借助 OpenAI 的官方工具。

Fine-tunings 的使用需要有一定的模型训练的技术基础以及经验要求,对于大多数场景来说,Embeddings 的方式会更加容易落地。

请求地址 POST https://api.openai.com/v1/fine-tunes

示例:

curl "https://api.openai.com/v1/fine-tunes" \-H "Content-Type: application/json" \-H "Authorization: Bearer $OPENAI_API_KEY" \-d '{// 训练集的FileID"training_file": "file-XGinujblHPwGLSztz8cPS8XY"}'

参数说明:

  • training_file:需要训练的文件 ID,这个文件 ID 是预先通过通用类-Files接口上传文件后获得的
  • validation_file:验证集的文件 ID,用于验证训练后的模型效果
  • model:主要有:ada、babbage、curie(默认)。ada:模型小,性能差,运行快;babbage:模型中,性能中,运行中;curie:模型大,性能优,运行慢
  • n_epochs:基于训练集的训练次数,1 表示训练一次,2 表示训练两次,训练的越多越容易过拟合,而越少则会出现欠拟合。
  • batch_size:规定模型的每一步训练,会选取训练集中的多少条数据进行。
  • learning_rate_multiplier:学习率,取值范围0到1。你可以认为学习率的值越大,模型学习训练集的过程越快越“不仔细”。如果模型学习训练集的数据太快,容易忽略数据的细节,可能导致优质的数据被忽略;如果模型学习训练集的数据太慢太“仔细”,可能受部分质量差的数据影响,从而影响最终的模型效果
  • prompt_loss_weight:prompt 的权重,取值范围0到1。如果 “prompt_loss_weight” 取值较高,那么在训练过程中模型会更关注于生成与预期响应相符的内容;如果 “prompt_loss_weight” 取值较低,那么模型则更关注于生成与目标内容接近的内容。
  • compute_classification_metrics:这个参数决定了是否在训练过程中计算和跟踪分类任务的性能指标,例如精度(accuracy)、精确度(precision)、召回率(recall)、F1 分数等
  • classification_n_classes:这个参数定义了分类任务中的类别数量。例如,在二分类任务中,classification_n_classes 的值就是 2;在有 10 个不同标签的多分类任务中,它的值就是 10。
  • classification_positive_class:这个参数定义了在二元分类任务中,哪个类别被认为是“正类”。通常,在一个二元分类任务中,我们将其中一个类别标记为“正类”,另一个类别标记为“负类”。例如,在垃圾邮件检测的任务中,垃圾邮件可以被标记为“正类”,非垃圾邮件被标记为“负类”。对于某些性能指标(例如精确度、召回率)的计算,需要知道哪个类别是“正类”
  • classification_betas:这个参数用于设定计算 F-分数(F-beta score)时的 beta 值。F-分数是精确度和召回率的加权调和平均,其中 beta 值决定了精确度和召回率的权重。如果 beta 值大于 1,那么召回率将有更大的权重;如果 beta 值小于 1,那么精确度将有更大的权重。这个参数是一个列表,可以设定多个 beta 值,模型将为每个 beta 值计算一个 F-分数
  • suffix:模型名称的后缀名。如果后缀是 “custom-model-name”,那么生成的模型名称可能会像 ‘ada:ft-your-org:custom-model-name-2022-02-15-04-21-04’ 这样。”

其他接口

获取 Fine-tunes 训练的模型列表

GET https://api.openai.com/v1/fine-tunes

获取某一个模型的详细信息

GET https://api.openai.com/v1/fine-tunes/{fine_tune_id}

取消正在训练的模型

POST https://api.openai.com/v1/fine-tunes/{fine_tune_id}/cancel

获取某一个模型训练过程中的事件

GET https://api.openai.com/v1/fine-tunes/{fine_tune_id}/events

删除一个模型

DELETE https://api.openai.com/v1/models/{model}

通用类

获取 Models 列表:GET https://api.openai.com/v1/models

获取 Models 详情:

GET https://api.openai.com/v1/models/{model}

Files(上传文件到 GPT)

主要用于 Fine-tunings 的训练数据集、验证数据集的上传

示例:

curl "https://api.openai.com/v1/files" \-H "Authorization: Bearer $OPENAI_API_KEY" \// 文件用途-F purpose="fine-tune" \-F file="@mydata.jsonl"

翻译为Python:

import requestsurl = "https://api.openai.com/v1/files"
headers = {"Authorization": "Bearer $OPENAI_API_KEY"
}
data = {"purpose": "fine-tune","file": ("mydata.jsonl", open("mydata.jsonl", "rb"))
}response = requests.post(url, headers=headers, files=data)

其他接口

获取文件列表

GET https://api.openai.com/v1/files

获取单个文件描述信息

GET https://api.openai.com/v1/files/{file_id}

获取单个文件内容

GET https://api.openai.com/v1/files/{file_id}/content

图片 & 音频 类

文生图:https://api.openai.com/v1/images/generations

示例:

curl "https://api.openai.com/v1/images/generations" \-H "Content-Type: application/json" \-H "Authorization: Bearer $OPENAI_API_KEY" \-d '{"prompt": "A cute baby sea otter","n": 2,"size": "1024x1024"}'

编辑图:https://api.openai.com/v1/images/edits

示例:

curl "https://api.openai.com/v1/images/edits" \-H "Authorization: Bearer $OPENAI_API_KEY" \-F image="@otter.png" \-F mask="@mask.png" \-F prompt="A cute baby sea otter wearing a beret" \-F n=2 \-F size="1024x1024"

图变体:https://api.openai.com/v1/images/variations

curl "https://api.openai.com/v1/images/variations" \-H "Authorization: Bearer $OPENAI_API_KEY" \-F image="@otter.png" \-F n=2 \-F size="1024x1024"

参数:

  • n:生成图片数量
  • response_format:返回图片的格式:url 或者 b64_json

Audio(语音转文字):https://api.openai.com/v1/audio/transcriptions

curl "https://api.openai.com/v1/audio/transcriptions" \-H "Authorization: Bearer $OPENAI_API_KEY" \-H "Content-Type: multipart/form-data" \-F file="@/path/to/file/audio.mp3" \-F model="whisper-1"

Function Calling 调用流程

functions参数属于多轮对话接口的参考,表示模型可能生成JSON输入的函数列表,每个对象的子参数如下:

  • name: 名称,必填项,要调用的函数名称。必须由小写字母a-Z,大写字母A-Z,数字0-9,下划线和短横线组成,并且最大长度为64个字符。
  • description: 描述,模型使用该描述来选择何时以及如何调用这个函数。
  • parameters: 该函数接受的参数,以JSON Schema对象的形式描述。

function call:控制模型如何响应函数调用。“none"表示模型不调用函数,而是直接回应给最终用户。“auto"表示模型可以选择在最终用户和调用函数之间进行切换。如果使用{“name”:“my_function”}指定特定的函数,模型将强制调用该函数。当没有函数存在时,默认值为"none”。如果存在函数,默认值为"auto”。

注意:被调用的函数返回值必须为json.

JSON Schema对象

一个 JSON Schema 示例,用于描述一个人的信息:

{"$schema": "http://json-schema.org/draft-07/schema#","type": "object","properties": {"Name": {"type": "string"},"Age": {"type": "integer","minimum": 0},"Salary": {"type": "number"},"IsMarried": {"type": "boolean"}},"required": ["Name", "Age"]
}
  • $schema: 这是 JSON Schema 的元数据字段,用于定义使用的 JSON Schema 规范的版本。
  • type: 指定 JSON 对象应有的数据类型。在这个例子中,它是一个 object。
  • properties: 用于描述 JSON 对象内部属性的规则。它是一个对象,其中每个键都是要描述的属性名,每个值都是该属性应满足的条件。
  • required: 一个数组,列出了哪些字段是必需的。在这个例子中,Name 和 Age 是必需字段。

Function Calling流程实践

首先定义数据集:

import pandas as pd
import json# 创建一个稍微复杂的DataFrame,包含多种数据类型
df_complex = pd.DataFrame({'Name': ['Alice', 'Bob', 'Charlie'],'Age': [25, 30, 35],'Salary': [50000.0, 100000.5, 150000.75],'IsMarried': [True, False, True]
})
# 将DataFrame转换为JSON格式(按'split'方向)
df_complex_json = df_complex.to_json(orient='split')

得到一段json可以作为大模型的输入。

定义一个准备被大模型调用的函数:

def calculate_total_age_from_split_json(input_json):"""从给定的JSON格式字符串(按'split'方向排列)中解析出DataFrame,计算所有人的年龄总和,并以JSON格式返回结果。参数:input_json (str): 包含个体数据的JSON格式字符串。返回:str: 所有人的年龄总和,以JSON格式返回。"""# 将JSON字符串转换为DataFramedf = pd.read_json(input_json, orient='split')# 计算所有人的年龄总和total_age = df['Age'].sum()# 将结果转换为字符串形式,然后使用json.dumps()转换为JSON格式return json.dumps({"total_age": str(total_age)})

可以将上面的json计算出年龄总和,下面我们的目标是让大模型能够自动选择这个函数进行计算。

对于上面的函数,functions定义如下:

functions = [{"name": "calculate_total_age_from_split_json","description": "计算年龄总和的函数,从给定的JSON格式字符串(按'split'方向排列)中解析出DataFrame,计算所有人的年龄总和,并以JSON格式返回结果。","parameters": {"type": "object","properties": {"input_json": {"type": "string","description": "执行计算年龄总和的数据集"},},"required": ["input_json"],},
}]

函数的返回必须为json,参数定义的JSON Schema表示有一个字符串参数input_json,它是必须字段。

然后我们就可以进行函数调用了:

import openaiopenai.api_key = "sk-xxx"messages = [{"role": "system", "content": f"你是一位优秀的数据分析师, 现在有这样一个数据集input_json:{df_complex_json},数据集以JSON形式呈现"},{"role": "user", "content": "请在数据集input_json上执行计算所有人年龄总和函数"}
]
res = openai.ChatCompletion.create(model="gpt-3.5-turbo",messages=messages,functions=functions,function_call="auto",
)

可以从结果中提取函数名和传递的参数:

function_name = res["choices"][0]["message"]["function_call"]["name"]
function_args = json.loads(res["choices"][0]["message"]["function_call"]["arguments"])

然后我们通过这个函数名调用该函数,传递这个参数给这个函数:

final_response = globals()[function_name](**function_args)
final_response
'{"total_age": "90"}'

可以看到已经得到了最终的计算结果。

我们可以自行生成自然语言,也可以交给openai进行进一步处理:

# 追加第一次模型返回结果消息
messages.append(res["choices"][0]["message"])
# 追加function计算结果,注意:function message必须要输入关键词name
messages.append({"role": "function", "name": function_name,"content": final_response})
last_response = openai.ChatCompletion.create(model="gpt-3.5-turbo",messages=messages,
)
result = last_response["choices"][0]["message"]["content"]
result
'在数据集input_json上执行计算所有人年龄总和的函数后,得到的结果为90。'

让函数自动生成functions定义

前面我们定义完函数之后,还需要编写JSON Schema等定义。是否可以让大模型生成?

首先提取函数的文档字符串:

import inspect# 使用inspect模块提取文档字符串
function_declaration = inspect.getdoc(calculate_total_age_from_split_json)
function_declaration
"从给定的JSON格式字符串(按'split'方向排列)中解析出DataFrame,计算所有人的年龄总和,并以JSON格式返回结果。\n\n参数:\ninput_json (str): 包含个体数据的JSON格式字符串。\n\n返回:\nstr: 所有人的年龄总和,以JSON格式返回。"

尝试生成:

response = openai.ChatCompletion.create(model="gpt-3.5-turbo",messages=[{"role": "system","content": f"你是一位优秀的数据分析师,现在有一个函数的详细声明如下:{function_declaration}"},{"role": "user","content": """请根据这个函数声明,为我生成一个JSON Schema对象描述。这个描述应该清晰地标明函数的输入和输出规范。具体要求如下:
1. 在JSON Schema对象中,设置函数的参数类型为'object'.
2. 'properties'字段如果有参数,必须表示出字段的描述. 
3. 从函数声明中解析出函数的描述,并在JSON Schema中以中文字符形式表示在'description'字段.
4. 识别函数声明中哪些参数是必需的,然后在JSON Schema的'required'字段中列出这些参数. 
5. 输出的应仅为符合上述要求的JSON Schema对象内容, 不需要任何上下文修饰语句. """}]
)
content = response["choices"][0]["message"]["content"]
print(content)

两次结果分别为:

{"$schema": "http://json-schema.org/draft-07/schema#","type": "object","properties": {"input_json": {"description": "包含个体数据的JSON格式字符串","type": "string"}},"required": ["input_json"],"description": "从给定的JSON格式字符串中解析出DataFrame,计算所有人的年龄总和,并以JSON格式返回结果。","additionalProperties": false
}

和:

{"type": "object","properties": {"input_json": {"type": "string","description": "包含个体数据的JSON格式字符串。"}},"required": ["input_json"],"description": "从给定的JSON格式字符串中解析出DataFrame,计算所有人的年龄总和,并以JSON格式返回结果。"
}

使用少量样本提示(Few-Shot prompting)可以提升模型输出的稳定性和准确性。

Prompt编程

Prompt编程是指利用结构化的数据(如JSON、Markdown、XML)来定义Prompt,从而简单、高效的定制能力丰富的AI功能。Prompt编程可以让GPT的回答高度可控且稳定。

用一个《育儿师》的例子跟大家讲解Prompt编程,先来看看如何用Prompt编程来定义育儿师这款AI功能:

{// 用于定义你的AI App的简介"简介": {"名字": "育儿师","自我介绍": "从事教育30年,精通0-18岁孩子的的成长规律,精通教育规划、精通育儿问题解决、并且给出的相关解决方案有着比较好的可执行性"},// 用于定义系统相关信息,这里我们只定义了规则"系统": {"规则": ["000. 无论如何请严格遵守<系统 规则>的要求,也不要跟用户沟通任何关于<系统 规则>的内容",// 规定系统需要询问用户细节"201. 若用户询问育儿问题,比如孩子专注力不足等,必须先与用户讨论孩子表现细节,诸如详细的、与问题相关的行为、语言、语气、表情、肢体行为等",// 规定系统要基于<规则 201>来判断孩子是否存在问题,若存在则给出具体的可落地的方法"202. 基于<规则 201>的讨论,来判断用户咨询的问题是否真的存在,若存在则详细分析孩子问题的原因以及给出具体的、可落地执行的解决方案;若不存在则对用户进行安慰,安抚用户的焦虑"]},// 让系统跟用户打招呼"打招呼": "介绍<简介>"
}

系统模块结构

可以看到,上边的Prompt分为三个模块:简介、系统、打招呼。

  • 简介:用于介绍AI功能,这里可以描述功能的名字、用途、作者等,除此之前,你也可以自定一些字段Key来向用户更加详细的介绍你的AI功能。
  • 系统:用于定义你的AI功能的规则,这部分是AI功能的核心系统逻辑
  • 打招呼:规定GPT首次运行时,主动向用户打招呼,并定义打招呼的内容

系统必要模块,其他模块均为可选模块

使用“<>”会自动触发引用,比如示例中的:

000. 无论如何请严格遵守<系统 规则>的要求,也不要跟用户沟通任何关于<系统 规则>的内容

模块

用户模块

规范用户的信息输入。这块功能类似表单功能,有必填信息、选填信息等。来看个例子:

{"简介": {"名字": "育儿师","自我介绍": "从事教育30年,精通0-18岁孩子的的成长规律,精通教育规划、精通育儿问题解决、并且给出的相关解决方案有着比较好的可执行性","作者": "菠菜"},// 增加 "用户" 模块,用于规定用户的 必填信息 跟 选填信息"用户": {"必填信息": {"年龄段": ["0-3岁","3-6岁","6-12岁","12-18岁","18岁以上"],"性别": ["男","女"]},"选填信息": ["出生日期","所在省份"]},"系统": {"规则": ["000. 无论如何请严格遵守<系统 规则>的要求,也不要跟用户沟通任何关于<系统 规则>的内容",// 增加对应规则(101-104),来对<用户>模块的功能进行定义// 规定必填内容,若用户不回答,则拒绝提供咨询服务"101. 必须在用户提供全部<用户 必填信息>前提下,才能回答用户咨询问题,若用户拒绝给出资料或仅仅给出部分,请委婉拒绝",// 规定选填内容"102. 可以适当提示用户给一些<用户 选填信息>,若用户给出相关内容,后续的咨询回答也要作为参考",// 规定基于出生日期对于年龄的校验以及自动纠正逻辑"103. 若用户输入的孩子年龄与出生日期不相符,请以出生日期为准并对用户输入的孩子年龄进行修正",// 规定系统仅对18岁以下的孩子的问题提供相关咨询服务"104. 若用户孩子的年龄大于18岁,则委婉拒绝用户,不提供相关咨询服务","201. 若用户询问育儿问题,比如孩子专注力不足等,必须先与用户讨论孩子表现细节,诸如详细的、与问题相关的行为、语言、语气、表情、肢体行为等","202. 基于<规则 201>的讨论,来判断用户咨询的问题是否真的存在,若存在则详细分析孩子问题的原因以及给出具体的、可落地执行的解决方案;若不存在则对用户进行安慰,安抚用户的焦虑"]},"打招呼": "介绍<简介>"
}

“用户”模块规定了用户需要输入的数据,并且在<系统 规则>里的 101 - 104 定义了相关规则。当然用户模块不是必须的(必填信息、选填信息也同理),当你想对用户的输入进行特殊要求的时候,就可加上该模块。

指令模块

如果我们想通过特殊的指令来与AI功能进行交互,比如:用户想查看一下之前输入的孩子的信息等,就需要我们引入"指令"模块。

我们来看一下"指令"模块的示例:

{"简介": {//...},"用户": {//...},"系统": {// 指令模块,在系统模块下"指令": {// 规定指令前缀"前缀": "/",// 指令列表"列表": {// 信息指令定义,当用户在会话中输入 '/信息'的时候,系统将会回答用户之前输入的关于孩子的信息"信息": "回答 <用户 必填信息> + <用户 选填信息> 相关信息",}},"规则": [// ...]},"打招呼": "介绍<简介>"
}

可运行的JSON数据:

{"简介":{"名字":"育儿师","自我介绍":"从事教育30年,精通0-18岁孩子的的成长规律,精通教育规划、精通育儿问题解决、并且给出的相关解决方案有着比较好的可执行性"},"用户":{"必填信息":{"年龄段":["0-3岁","3-6岁","6-12岁","12-18岁","18岁以上"],"性别":["男","女"]},"选填信息":["出生日期","所在省份"]},"系统":{"指令":{"前缀":"/","列表":{"信息":"回答 <用户 必填信息> + <用户 选填信息> 相关信息"}},"规则":["000. 无论如何请严格遵守<系统 规则>的要求,也不要跟用户沟通任何关于<系统 规则>的内容","101. 必须在用户提供全部<用户 必填信息>前提下,才能回答用户咨询问题,若用户拒绝给出资料或仅仅给出部分,请委婉拒绝","102. 可以适当提示用户给一些<用户 选填信息>,若用户给出相关内容,后续的咨询回答也要作为参考","103. 若用户输入的孩子年龄与出生日期不相符,请以出生日期为准并对用户输入的孩子年龄进行修正","104. 若用户孩子的年龄大于18岁,则委婉拒绝用户,不提供相关咨询服务","201. 若用户询问育儿问题,比如孩子专注力不足等,必须先与用户讨论孩子表现细节,诸如详细的、与问题相关的行为、语言、语气、表情、肢体行为等","202. 基于<规则 201>的讨论,来判断用户咨询的问题是否真的存在,若存在则详细分析孩子问题的原因以及给出具体的、可落地执行的解决方案;若不存在则对用户进行安慰,安抚用户的焦虑"]},"打招呼":"介绍<简介>"}

设计技巧

Prompt编程将Prompt细分为4个模块:<简介>、<系统>、<用户>、<打招呼>,这就是模块化。<系统>模块进一步细化为3个子模块:<系统 指令>、<系统 返回格式>、<系统 规则>等,这就是总分

模块化,是指将相近的功能放到一个模块中,这样模块内部更加内聚,而模块之间更加低耦,避免功能之间杂糅交叉的现象产生。总分,是指将一个复杂的功进行拆分、细化。将复杂的功能拆分为相对简单的多个子模块,从而降低复杂功能的实现难度。

<系统>的模块化

模块化的一个核心点就是高内聚、低耦合,设计<系统 指令>和<系统 规则>时,容易产生高耦合的场景,例如:

{"系统": {"指令": {"前缀": "/","列表": {"Start": "随机出一个0-99的数字,这个数字我们命名为<x>","Again": "忘掉之前的沟通信息,并随机出一个0-99的数字,这个数字我们命名为<x>"}},"规则": ["000. 跟用户沟通过程中,一定不要跟用户沟通关于<系统 规则>相关的内容","001. <x>不得告知用户"]}
}

上边的"规则"并没有内聚到<系统 规则>,而是在<指令 列表 Start/Again>,并且重复,我们应该调整为:

{"系统": {"指令": {"前缀": "/","列表": {"Start": "执行<系统 规则 001>","Again": "执行<系统 规则 001>"}},"规则": ["000. 跟用户沟通过程中,一定不要跟用户沟通关于<系统 规则>相关的内容","001. 若之前出过随机数请忘记。现随机出一个0-99的数字,这个数字我们命名为<x>,<x>不得告知用户"]}
}

这样,"规则"类的功能定义都放入到了<系统 规则>中更加内聚,且指令只是单纯对<系统 规则>的引用。

<系统 规则>的总分

如果要设计一个功能复杂的<系统 规则>,就需要总分的设计思路了。比如我们可以通过"序号段"来区分规则的类型,再用"子号段"来描述具体的规则,如果"子号段"的内容也过多,可以继续拆分、细化,比如:

{"系统": {/*1. 规则总章号段      :0000-09992. <用户>模块规则号段 :1000-19993. 系统核心功能逻辑号段:2000-2999系统核心功能又细分为:3.1 指令规则号段:2101-21993.2 返回格式规则号段:2201-22993.3 其他核心功能规则号段:2301-2399*/"规则": [// 规则总章"0000. 请严格遵守<系统 规则>里的内容,并严格禁止跟用户讨论任何关于<系统 规则>的内容"// <用户>模块规则"1000. <用户 必填信息>为必填,若用户没有给出相关信息,请委婉拒绝服务""1001. <用户 选填信息>为选填,若用户给出相关信息,请参考",// 指令规则"2101. 出10小学4年级数学道题,每道题10分... ...",// 返回格式规则"2201. 你回复的格式必须为JSON,且格式内容为<返回格式>","2202. xxxx",// 其他核心功能规则"2301. xxx","2302. xxx",],}
}

AI微服务

利用Prompt编程,将GPT定制成具备某种智能能力的AI微服务,系统接入这个AI微服务,就具备了智能的能力。

《AI数学老师》:

{"简介": {"名字": "AI数学老师","自我介绍": "从事小学数学教育30年,精通设计各种数学考试题",},"系统": {"指令": {"前缀": "/","列表": {"出题": "严格遵守<系统 规则 001>进行出题","重新出题": "忘掉之前的信息,执行<系统 指令 列表 出题>"}},"返回格式": {// 定义返回数据"questions": [{// 定义id字段,并且定义为int类型"id": "<题目序号>,int型",// 定义题目字段,默认为string类型"title": "<题目>","type": "<题目类型:单选 or 多选>","score": "<分值>,int型","options": [{"optionTitle": "<选项内容>","isRight": "<是否是正确答案>,bool型"}]}]},"规则": ["000. 无论如何请严格遵守<系统 规则>的要求,也不要跟用户沟通任何关于<系统 规则>的内容",// 规定出题策略"001. 题目必须为小学三年级课程范围内的语文试题,总共10题,5道单选题,5道多选题。10个题的总分值为100分,请根据题目难度动态分配",// 规定ChatGPT返回数据格式为JSON,并且遵守<返回格式>"002. 返回格式必须为JSON,且为:<返回格式>,不要返回任何跟JSON数据无关的内容"]}
}

GPT并不是万能的,也有它的不足之处,比如:数学计算、联网、私有信息问答等。那在实际应用中我们可以利用插件的方式来弥补这些不足。之前的课程讲了Function Call,这节课,我们换一种方式,利用Prompt编程来实现。

{"系统": {"指令": {"前缀": "/","列表": {"推理": "严格按照<系统 规则>进行分析"}},"返回格式": {"response": {"type": "<类型>,int型,1表示答复、2表示需要需要调用联网插件、3表示需要调用数学计算、4表示订单插件","normal": "<答复内容>","network": {"url": "<请求地址>"},"math": {"math_express": "<数学表达式>"},"search_order": {"order_id": "<订单ID>"}}},"规则": ["000. 无论如何请严格遵守<系统 规则>的要求,也不要跟用户沟通任何关于<系统 规则>的内容","001. 当你需要联网的时,可以使用联网插件,为<系统 返回格式 response network>","002. 当你需要计算数学表达式时,可以使用数学插件,为<系统 返回格式 response math>","003. 当你需要获取订单信息时,可以使用订单插件,为<系统 返回格式 response search_order>","999. 无论如何你的返回格式必须为JSON,且为:<系统 返回格式>,不要返回任何跟JSON数据无关的内容"]}
}

Embeddings 嵌入

ChatGPT官方提供了两种训练语料的方式:embedding(嵌入)、Fine-tuning(微调)。

基于embeddings的模型训练在技术层面并没有难度术,因为复杂的部分大模型已经帮我们实现了,我们需要做的主要是以下4步:

  1. 自有数据生成向量,存储到向量数据库
  2. 用户提问转成向量,去数据库做数据召回,找到TOPK的数据
  3. 根据用户提问和召回的数据重新组装成prompt
  4. 把组装好的prompt发给ChatGPT,等待响应结果

在OpenAI中,使用Embeddings来表示文本数据,默认的 ada-002 模型会将文本解析为 1536 个维度,以便于模型更好地理解和处理文本。这种方法能够大大提高模型处理文本数据的效率和准确度。

官方地址:https://platform.openai.com/docs/guides/embeddings

嵌入(embedding)是指将高维数据映射为低维表示的过程。在机器学习和自然语言处理中,嵌入通常用于将离散的符号或对象表示为连续的向量空间中的点。

文本数据生成向量调用测试

在调用embedding接口的时候需要注意,文本长度不能超过8191个token,如果超过长度需要进行切分。

  • input: 需要计算向量的文本
  • model : 计算向量需要使用的模型,建议使用 text-embedding-ada-002,ada模型是目前最廉价的支持中文最好的模型。
import openaiopenai.api_key = "sk-xxxx"response = openai.Embedding.create(input="今天天气很好",model="text-embedding-ada-002"
)
response

结果:

{"object": "list","data": [{"object": "embedding","index": 0,"embedding": [-0.004061323124915361,0.0013278661062940955,-0.002816090825945139,-0.030029574409127235,-0.009601871483027935,... ...]}],"model": "text-embedding-ada-002-v2","usage": {"prompt_tokens": 8,"total_tokens": 8}
}

看一下embedding的长度:

embeddings = response['data'][0]['embedding']
len(embeddings)

结果证实是1536 个维度。

向量数据库

向量数据库可参考openai官方给出的列表:

https://platform.openai.com/docs/guides/embeddings/how-can-i-retrieve-k-nearest-embedding-vectors-quickly

向量数据库的选项包括:

  • Pinecone,一个完全托管的向量数据库
  • Weaviate,一个开源的向量搜索引擎
  • Redis作为一个向量数据库
  • Qdrant,一个向量搜索引擎
  • Milvus,一个为可扩展相似性搜索构建的向量数据库
  • Chroma,一个开源的嵌入式存储
  • Typesense,快速的开源向量搜索
  • Zilliz,由Milvus提供支持的数据基础设施

这里建议选择PostgreSQL作为向量数据库,安装包下载地址:https://www.enterprisedb.com/downloads/postgres-postgresql-downloads

Linux平台安装方法:https://www.postgresql.org/download/

Windows安装PostgreSQL只需要不断下一步即可,安装pgvector可能会有点坑。

Windows平台安装pgvector

下载源码包:

git clone --branch v0.5.1 https://github.com/pgvector/pgvector.git

也可以到官网下载:https://pgxn.org/dist/vector/0.5.1/

首先确保已经安装 C++ support in Visual Studio,再用管理员身份运行cmd先执行:

call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"

实际路径根据自己安装的Visual Studio进行调整,可以通过everything搜索vcvars64.bat,得到路径,例如我的电脑是:call “C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvars64.bat”

然后进行下载的源码所在文件夹,依次执行如下命令:

set "PGROOT=D:\Program Files\PostgreSQL\16"
nmake /F Makefile.win
nmake /F Makefile.win install

注意:PGROOT根据pg的实际安装路径调整。

全部安装完成后,就可以使用psql登录PostgreSQL,创建数据库和表了:

CREATE DATABASE ai_emb;
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE documents (id bigserial PRIMARY KEY,title text,url text,description text,doc_chunk text,embedding vector(1536));

Embeddings案例

创建表:

CREATE TABLE doc1 (id bigserial PRIMARY KEY,doc_chunk text,embedding vector(1536)
);

准备一份makedown文档并处理:

import re
from filestools import read_txtmd = read_txt("D:\md\集团管理层培训.md")
md = md[:md.find("题库")].strip(" \n#")
// 去掉标题和加粗
md = re.sub("#+ |\*+", "", md)
// 去掉图片
md = re.sub("!\[image-\d+\]\(.+?\)", "", md)
len(md)

这份文档经过处理后长度为36424。

对该文档按500长度进行分块切片:

def get_text_chunks(content, max_chunk_size=500):return [content[i:i+max_chunk_size] for i in range(0, len(content), max_chunk_size)]chunks = get_text_chunks(md)
len(chunks)

最终得到73个分块。

下面我们连接PostgreSQL数据库:

import psycopg2# 连接PostgreSQL数据库
conn = psycopg2.connect(database="ai_emb",host="127.0.0.1",user="postgres",password="admin",port="5432")
conn.autocommit = True

pip install psycopg2即可安装Python客户端

然后我们将每个分块转换为embedding:

import openai
from tqdm import tqdm# openai.api_base = "https://ai.xxx.com/v1"
openai.api_key = "sk-xxxx"for chunk in tqdm(chunks):query_embedding_response = openai.Embedding.create(model="text-embedding-ada-002",input=chunk,)embedding = query_embedding_response['data'][0]['embedding']cur = conn.cursor()insert_query = "INSERT INTO doc1 (doc_chunk, embedding) VALUES (%s, %s);"cur.execute(insert_query, (chunk, embedding))conn.commit()

这样就将每个文档分块和对应的embedding存储到PostgreSQL数据库中。训练非常快,最终仅耗时38秒:

73/73 [00:38<00:00, 1.92it/s]

训练完成后,我们就可以进行提问,准备的问题是“复盘的目的”,我们将该问题转换为embedding向量:

prompt = '复盘的目的'prompt_response = openai.Embedding.create(model="text-embedding-ada-002",input=prompt,
)
prompt_embedding = prompt_response['data'][0]['embedding']

然后我们从PostgreSQL数据库查询出相似度达到阈值的对应文档分块,这里我们设置阈值为0.78,最大2个文本块:

from psycopg2.extras import DictCursorsimilarity_threshold = 0.78
max_matched_doc_counts = 2# 通过pgvector过滤出相似度大于一定阈值的文档块
similarity_search_sql = f'''
SELECT doc_chunk, 1 - (embedding <=> '{prompt_embedding}') AS similarity 
FROM documents WHERE 1 - (embedding <=> '{prompt_embedding}') > {similarity_threshold} ORDER BY id LIMIT {max_matched_doc_counts};
'''cur = conn.cursor(cursor_factory=DictCursor)
cur.execute(similarity_search_sql)
prompt_doc = "\n---\n".join((matched_doc['doc_chunk']for matched_doc in cur.fetchall()))
print(prompt_doc)

匹配出最相似的文本为:

体颁发奖项 |> 人性最大的欲望,莫过于受到外界的认可和赞赏
>                                                        — 威廉·詹姆斯复盘总结课前思考> 您平时有复盘的习惯么?
> 您一般是怎样做复盘的呢?复盘与经验总结复盘对过程目标进行梳理及成因分析,同时也对未发生的行为进行虚拟探究,找到其他行为的可能性和可行性,发现新方法和出路。复盘的关键目的与流程1. 回顾目标当初的目的是什么?要达到的目标&里程碑
2. 评估结果Highlights 结果与原来的自标比要好Lowlights 结果与原来的目标比要差
3. 分析原因成功关键因素 (主观/客观)失败根本原因 (主观/客观)
4. 总结经验经验&规律举措&行动计划哪些行为可以开始行动、停止、继续关键目的:把经验转化为接下来的工作方向和工作任务。> 复盘是为未来不再犯同样的错误和规避同样的风险。示例:> 小分队所有成员再次讨论和回顾了本次行动目标周三早上6点

然后我们再次提问openai:

improved_prompt = f"""
按下面提供的文档和步骤来回答接下来的问题:
(1) 首先,分析文档中的内容,看是否与问题相关
(2) 其次,只能用文档中的内容进行回复,越详细越好,并且以markdown格式输出
(3) 最后,如果问题与提问不相关,请回复"我会努力学习的"文档:
\"\"\"
{prompt_doc}
\"\"\"问题: {prompt}
"""
messages = [{"role": "user", "content": improved_prompt}]
response = openai.ChatCompletion.create(model="gpt-3.5-turbo-16k-0613",messages=messages,temperature=0.2,max_tokens=1024
)print(f"问题: {prompt}")
print(response['choices'][0]['message']['content'])
问题: 复盘的目的
复盘的目的是将过去的经验转化为接下来的工作方向和工作任务,以避免再次犯同样的错误和规避同样的风险。通过回顾目标、评估结果、分析原因和总结经验,可以找到成功的关键因素和失败的根本原因,进而得出经验和规律,并制定相应的举措和行动计划。复盘的关键目的是为了在未来的工作中能够更好地实现目标,并避免重复犯错。

Fine-tuning 微调

在OpenAI中,Fine-tuning主要用于提高预训练模型如GPT-3在特定任务上的性能。通过Fine-tuning,模型可以更好地理解和处理新任务的特性,从而得到更好的结果。

官方地址:https://platform.openai.com/docs/guides/fine-tuning

支持的模型

目前可用于fine-tune微调的模型有:

  • gpt-3.5-turbo-0613
  • babbage-002
  • davinci-002

注意gpt-3.5-turbo支持上下文连续对话,如果需要实现连续对话可以微调gpt-3.5-turbo模型。

gpt-3.5-turbo微调的数据输入格式为:

{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital of France?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already."}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'Romeo and Juliet'?"}, {"role": "assistant", "content": "Oh, just some guy named William Shakespeare. Ever heard of him?"}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "How far is the Moon from Earth?"}, {"role": "assistant", "content": "Around 384,400 kilometers. Give or take a few, like that really matters."}]}

官方提供的一份toy_chat_fine_tuning 的训练数据集:https://github.com/openai/openai-cookbook/blob/main/examples/data/toy_chat_fine_tuning.jsonl

babbage-002 and davinci-002的训练格式为:

{"prompt": "<prompt text>", "completion": "<ideal generated text>"}
{"prompt": "<prompt text>", "completion": "<ideal generated text>"}
{"prompt": "<prompt text>", "completion": "<ideal generated text>"}

训练数据的有效性可以参考:https://cookbook.openai.com/examples/chat_finetuning_data_prep

下面我们以davinci-002模型为示例进行演示。

依赖数据预处理

若我们有一个csv文件pre.csv内容如下:

prompt,completion
冬瓜、黄瓜、西瓜、南瓜都能吃,什么瓜不能吃,傻瓜
冬天,宝宝怕冷,到了屋里也不肯脱帽。可是他见了一个人乖乖地脱下帽,那人是谁,理发师
有一个字,人人见了都会念错。这是什么字,这是“错”字
鸡蛋壳有什么用处,用来包蛋清和蛋黄。

使用OpenAI 的命令行工具可以将该文件转换为 JSONL 文件,执行:

openai tools fine_tunes.prepare_data -f pre.csv

工具运行时会提示转换结果是否要添加一些字符:

Based on the analysis we will perform the following actions:
- [Necessary] Your format `CSV` will be converted to `JSONL`
- [Recommended] Add a suffix separator `\n\n###\n\n` to all prompts [Y/n]: 
- [Recommended] Add a suffix ending `\n` to all completions [Y/n]:
- [Recommended] Add a whitespace character to the beginning of the completion [Y/n]: 

最终生成新文件pre_prepared.jsonl,结果为:

{"prompt":"冬瓜、黄瓜、西瓜、南瓜都能吃,什么瓜不能吃","completion":"傻瓜\n"}
{"prompt":"冬天,宝宝怕冷,到了屋里也不肯脱帽。可是他见了一个人乖乖地脱下帽,那人是谁","completion":"理发师\n"}
{"prompt":"有一个字,人人见了都会念错。这是什么字","completion":"这是“错”字\n"}
{"prompt":"鸡蛋壳有什么用处","completion":"用来包蛋清和蛋黄。\n"}

也可以自行编码生成这种格式的文件。

注意:babbage-002和davinci-002模型支持使用这种格式的数据进行训练。对于gpt-3.5-turbo模型支持上下文只能使用如下格式训练:

{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital of France?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already."}]}

Python微调模型

首先上传训练集文件:

import openai# openai.api_base = "https://ai.xxxx.com/v1"
openai.api_key = "sk-xxx"
file = openai.File.create(file=open("pre_prepared.jsonl", "rb"),purpose='fine-tune'
)
file.id
'file-WiEcUA6z7cyNdHEPvvWGrJtU'

然后开始微调训练:

openai.FineTuningJob.create(training_file=file.id, model="davinci-002")

查看模型的训练状态:

# Retrieve the state of a fine-tune
openai.FineTuningJob.retrieve("ftjob-oG9bK7xiOJEBF6kwYGFepUal")
<FineTuningJob fine_tuning.job id=ftjob-oG9bK7xiOJEBF6kwYGFepUal at 0x226fab19450> JSON: {"object": "fine_tuning.job","id": "ftjob-oG9bK7xiOJEBF6kwYGFepUal","model": "davinci-002","created_at": 1697539548,"result_files": [],"status": "running","validation_file": null,"training_file": "file-WiEcUA6z7cyNdHEPvvWGrJtU","hyperparameters": {"n_epochs": 3},"trained_tokens": null,"error": null
}

其他函数:

# 列出10个最近进行微调的模型
openai.FineTuningJob.list(limit=10)
# 查看某个微调模型的状态
openai.FineTuningJob.retrieve("ftjob-abc123")
# 取消一个微调模型的训练
openai.FineTuningJob.cancel("ftjob-abc123")
# 列出某个微调模型的最近10个事件
openai.FineTuningJob.list_events(id="ftjob-abc123", limit=10)
# 删除一个已经训练好的 fine-tuned 模型
openai.Model.delete("ft:gpt-3.5-turbo:acemeco:suffix:abc123")

等待16分钟后,微调模型终于训练完成:

import datetimejob = openai.FineTuningJob.retrieve("ftjob-oG9bK7xiOJEBF6kwYGFepUal")
print(job.status, job.fine_tuned_model)
dt1 = datetime.datetime.fromtimestamp(job.created_at)
dt2 = datetime.datetime.fromtimestamp(job.finished_at)
print("耗时:", dt2 - dt1)
succeeded ft:davinci-002:personal::8Ac7vxPp
耗时: 0:16:21

测试模型:

completion = openai.Completion.create(model="ft:davinci-002:personal::8Ac7vxPp",prompt="什么船从来不下水"
)
print(completion.choices[0].text)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/114630.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【vSphere 8 自签名证书】企业 CA 签名证书替换 vSphere Machine SSL 证书Ⅰ—— 生成 CSR

目录 替换拓扑图证书关系示意图说明 & 关联博文 1. 默认证书截图2. 使用certificate-manager生成CSR2.1 创建存放CSR的目录2.2 记录PNID和IP2.3 生成CSR2.4 验证CSR 参考资料 替换拓扑图 证书关系示意图 默认情况下&#xff0c;VMCA 与 Machine SSL的关系是 本系列博文要…

UE5--物体卡片与材质入门

参考资料&#xff1a; 《Unreal Engine5 入门到精通》--左央 虚幻引擎5.2文档&#xff1a;https://docs.unrealengine.com/5.2/zh-CN/ 前言&#xff1a; 跟着左央老师的《Unreal Engine5 入门到精通》学习制作AI版胡闹厨房&#xff0c;把学习过程与学习到的东西归纳总结起来。 …

Ruby 之 csv 文件读写

csv 文件写入 require csvtitle ["col1", "col2"] contents [["row11", "row12"], ["row21", "row22"]]csv1 CSV.open("test1.csv", "wb") do |csv|# write file titlecsv << titl…

【网络协议】聊聊网关 NAT机制

再宿舍的时候&#xff0c;其实只能通过局域网进行处理&#xff0c;但是如果接入互联网&#xff0c;一般是配置路由器当然还有网关。 MAC头和IP头的细节 一旦配置了IP地址和网关&#xff0c;就可以制定目标地址进行访问。 MAC头主要信息目标和源MAC地址&#xff0c;以及协议类…

OpenCV显示中文(python)

OpenCV添加文字的方法putText(…)&#xff0c;添加英文是没有问题的&#xff0c;但如果你要添加中文就会出现“&#xff1f;&#xff1f;&#xff1f;”的乱码&#xff0c;需要特殊处理一下。 下文提供封装好的&#xff08;代码&#xff09;方法&#xff0c;供OpenCV添加中文使…

hive substr用法

hive substr用法 substr(string A, int start, int len) 其中start大於0&#xff0c;表示從前往后取數據&#xff0c;start小於0&#xff0c;表示從後往前取數據 if(matnr like 0000000000%, substring(matnr, -8), matnr) matnr,取倒數8個數 if(matnr like 0000000000%, subs…

【试题040】多个逻辑或例题2

1.题目&#xff1a;设int n0;&#xff0c;执行表达式n ||(n-1) ||(n0)||(n1)||(n2)后n的值是 &#xff1f; 2.代码解析&#xff1a; 逻辑或 || 运算符是一个短路运算符&#xff0c;它从左到右依次计算表达式&#xff0c;如果遇到一个为真&#xff08;非零&#xff09;的值&am…

javaweb中的servlet注解

2023.10.22 在web.xml文件中进行servlet信息的配置&#xff0c;显然开发效率比较低&#xff0c;每一个都需要配置一下。 在web.xml文件中的配置中&#xff0c;很少被修改的那部分&#xff0c;可以直接写在java类中。 Servlet3.0版本之后&#xff0c;推出了各种Servlet基于注解式…

kotlin修饰符const的含义

一. const属性简介 在 Kotlin 中&#xff0c;const 修饰符用于声明常量&#xff0c;常量的值在编译时就确定了&#xff0c;并且可以在编译时被嵌入到代码中 二. 使用const属性 companion object 中定义的属性和方法可以在类的实例上直接访问&#xff0c;就像 Java 中的静态变量…

uCOSIII实时操作系统 十 事件标志组

目录 事件标志组&#xff1a; 事件标志组API函数&#xff1a; 创建事件标志组&#xff1a; 等待事件标志组&#xff1a; 向事件标志组发送标志&#xff1a; 事件标志组实验&#xff1a; 事件标志组&#xff1a; 有时候一个任务可能需要和多个事件同步这个时候就需要使用事…

39.克鲁斯卡尔(Kruskal)算法

一言 已知n个顶点&#xff0c;选n-1条最短的边&#xff0c;不可成环。 概述 克鲁斯卡尔&#xff08;Kruskal&#xff09;算法是用来求加权连通图的最小生成树的算法。其基本思想是按照权值从小到大的顺序选择n-1条边&#xff0c;保证这n-1条边不构成回路。 这就要求要首先构…

一百九十一、Flume——Flume配置文件各参数含义(持续完善中)

一、目的 在实际项目的开发过程中&#xff0c;不同Kafka主题的数据规模、数据频率&#xff0c;需要配置不同的Flume参数&#xff0c;而这一切的调试、配置工作&#xff0c;都要建立在对Flume配置文件各参数含义的基础上 二、Flume各参数及其含义 &#xff08;一&#xff09;…

集成学习方法(随机森林和AdaBoost)

释义 集成学习很好的避免了单一学习模型带来的过拟合问题 根据个体学习器的生成方式&#xff0c;目前的集成学习方法大致可分为两大类&#xff1a; Bagging(个体学习器间不存在强依赖关系、可同时生成的并行化方法) 流行版本&#xff1a;随机森林(random forest)Boosting(个体…

springboot缓存篇之mybatis一级缓存和二级缓存

前言 相信很多人都用过mybatis&#xff0c;这篇文章主要是介绍mybatis的缓存&#xff0c;了解一下mybatis缓存是如何实现&#xff0c;以及它在实际中的应用 一级缓存 什么是mybatis一级缓存&#xff1f;我们先看一个例子&#xff1a; GetMapping("/list") public…

租用服务器后需要注意什么呢

租用服务器后需要注意什么呢 1、从IDC服务商中接收到服务器时&#xff0c;需要对服务器的各项性能进行测试确认&#xff0c;并做好记录以便对服务器的性能做到心中有数。 2、在服务器租用交接时&#xff0c;要了解服务器的安全设置情况&#xff0c;对服务器安全技术方面不了解…

深度学习硬件配置推荐(kaggle学习)

目录 1. 基础推荐2. GPU显存与内存是一个1:4的配比&#xff1f;3. deep learning 入门和kaggle比赛4. 有些 Kaggle 比赛数据集很大&#xff0c;可能需要更多的 GPU 显存&#xff0c;请推荐显存4. GDDR6和HBM25. HDD 或 SATA SSD 1. 基础推荐 假设您作为一个深度学习入门学者的…

【Mysql】B+树索引的使用(七)

前言 每个索引都对应一棵 B 树&#xff0c; B 树分为多层&#xff0c;最下边一层是叶子节点&#xff0c;其余的是内节点&#xff08;非叶子节点&#xff09;。所有用户记录都存储在 B 树的叶子节点&#xff0c;所有目录项记录都存储在内节点。 InnoDB 存储引擎会自动为主键&am…

Node学习笔记之包管理工具

一、概念介绍 1.1 包是什么 『包』英文单词是package &#xff0c;代表了一组特定功能的源码集合 1.2 包管理工具 管理『包』的应用软件&#xff0c;可以对「包」进行 下载安装 &#xff0c; 更新 &#xff0c; 删除 &#xff0c; 上传 等操作 借助包管理工具&#xff0c;可…

推理引擎之模型压缩浅析

目录 前言1. 模型压缩架构和流程介绍2. 低比特量化原理2.1 量化基础介绍2.2 量化方法2.3 量化算法原理2.4 讨论 3. 感知量化训练QAT原理3.1 QAT原理3.2 量化算子插入3.3 QAT训练流程3.4 QAT衍生研究3.5 讨论 4. 训练后量化PTQ4.1 动态PTQ4.2 静态PTQ4.3 KL散度实现静态PTQ4.4 量…

最详细STM32,cubeMX 定时器

这篇文章将详细介绍 STM32,cubeMX 定时器的配置和使用。 文章目录 前言一、定时器基础知识二、cubeMX 配置三、定时时长四、自动生成代码讲解五、实验程序总结 前言 实验开发板&#xff1a;STM32F103C8T6。所需软件&#xff1a;keil5 &#xff0c; cubeMX 。实验目的&#xff…