【教程分享】使用Python记录GPT API的完整过程

【一文系列】一篇文章记录gpt API的使用过程(python版)

“一文系列”目标是仅通过一篇文章来解决一个类别问题,简洁高效,快速获取知识,提升技能。

文章目录

  • 【一文系列】一篇文章记录gpt API的使用过程(python版)
  • 前言
  • 一、背景介绍
  • 二、gpt API的代码调用
  • 1. 环境准备
  • 2. 环境验证
  • 3. 简单参数说明
  • 三、牛刀小试:利用gpt API实现加法器
  • 1. 创建任务提示词
  • 2. 代码示例
  • 3. 运行并测试
  • 4. 注意点
  • 四、进阶案例:利用gpt API实现交互式翻译器
  • 1. 创建任务提示词
  • 2. 代码示例
  • 3. 运行并测试
  • 总结

  • 前言

    让我们开始吧!!!

    自然语言处理(NLP)作为人工智能领域的关键技术之一,正在以迅猛的步伐发展。OpenAI的GPT系列模型一直是NLP领域的领军者,为我们带来了许多令人惊叹的进展。也为开发者提供了无与伦比的自然语言处理能力。本文将探讨ChatGPT API的背景,并以python语言为例,基于gpt-3.5-turbo-0613模型进行API调用、小例子、进阶使用等方面的讨论,帮助读者能够了解如何利用AI来创造程序开发的新时代。


    一、背景介绍

    就在前些时间,openai推出了gpt-3.5-turbo-0613和gpt-3.5-turbo-16k这两款为开发者提供更强大和多样化的自然语言处理模型,在gpt-3.5-turbo模型的基础上进一步缩短了单次访问的响应时间,并扩展了模型的应用范围。

    作为大语言模型,gpt的功能远不止进行智能聊天那么简单,如果能够借助AI的力量来实现我们日常开发中比较棘手的问题,那才是AI真正能为开发人员进行赋能的价值,基于以上思考,本文将从简单的gpt API使用作为入口,并通过案例来展示gpt模型在NLP领域的前瞻性意义以及能为开发人员带来的无限可能。

    二、gpt API的代码调用

    1. 环境准备

    (1)python3环境: 本文在进行gpt API的使用上是直接基于python3的openai模块进行的,所以应该确保操作系统中按照了python3环境,python3的安装这里不再过多陈述,具体的安装方法请参考python官网。
    (2)openai API key: 需要去openai官网上申请API key。
    (3)外网访问条件:openai api的访问服务目前还没有向国内提供,在进行调用时需要通过技术手段进行科学上网,或是在国外vps服务器上访问,推荐使用第二种方案,第一种会有被封号的可能。
    (4)openai python模块:安装好python3环境后可以使用以下2种命令安装openai模块

    使用pip工具

    pip3 install openai
    

    使用conda工具

    # 需要安装conda环境
    conda install openai
    

    2. 环境验证

    完成上述的环境准备,就可以上手进行openai模块的调用,可以使用以下代码来验证环境的可用性。

    将api key写入环境变量,不推荐以明文方式在代码中出现

    export OPENAI_API_KEY="<OPENAI_API_KEY>"
    

    环境验证代码

    import openai
    import os
    
    # 从环境变量中读取openai api key
    openai.api_key = os.getenv('OPENAI_API_KEY')
    
    resp = openai.ChatCompletion.create(
        model = 'gpt-3.5-turbo-0613',
        messages = [{'role': 'system', 'content': 'hello'}],
        timeout = 30,
        n = 1
    )
    print(resp)
    

    当有如下输出后说明环境验证成功,接下来就可以享受AI带来的乐趣了。
    请添加图片描述

    3. 简单参数说明

    (1)请求参数

    1. model: 模型的名称,这里调用gpt-3.5-turbo-0613模型。
    2. messages: 消息上下文列表,使用数组表示,数组的元素表示一次会话消息,其中role属性表示当前会话的角色,包括:systemuserassistant。system表示系统消息,user表示模型使用者,assistant表示gpt机器人;content属性表示当前会话的内容,未来提交给gpt的提示词就是这个属性。
    3. timeout: 会话超时时间,单位为秒。
    4. n: 希望gpt给出回答的数目,会影响gpt响应中的choices数组长度,默认为1,一般使用默认值即可。

    (2)响应参数

    1. choices: gpt模型做出的回答的对象数组,数组长度为请求参数中的n。choices对象的各个属性如下:
  • finish_reason: 模型对于此次会话结束的原因,分别为stoplengthmax_tokens,其中stop正常结束,后面两项分别为是因为达到了最大内容长度和最大token而异常结束。
  • index: 在choices数组中的索引。
  • message: 会话消息对象,包括如下属性:
  • content: 消息内容,即gpt模型给出的回答内容。
  • role: gpt模型所扮演的角色,一般固定为assistant
    1. created: 请求的时间戳。
    2. id: 请求id。
    3. model: 模型名称,与请求中的model参数一致。
    4. object: 返回的对象类型(例如:chat.completion)
    5. usage: token的利用量,包括:
    6. completion_tokens:模型完成会话所利用的token量。
    7. prompt_tokens:提示词利用的token量。
    8. total_tokens:总共利用的token量,即completion_tokens与prompt_tokens的累加和。

    上述列出的是平时开发中最为常用的参数,更多参数请参考openai官方文档。


    三、牛刀小试:利用gpt API实现加法器

    完成环境的构建,就可以借助gpt API进行一些有趣的实验,在这一部分将以实现一个简单的加法器作为切入点,并总结了本人在使用gpt API时的步骤和心得。

    1. 创建任务提示词

    提示词(prompt)在使用gpt这种生成式大语言模型中至关重要,好的提示词可以清晰的让AI理解功能需求,并能够对输入输出格式进行把控。本人在构建提示词时习惯从以下方面来考虑:

    (1)背景:描述需求场景,让gpt能够理解我们的需求。
    (2)输入格式:给出我们提供给gpt的输入格式,并对必要部分进行说明,让gpt能够更有目的的提前我们给出的提问。
    (3)输出格式:这部分至关重要,在不规定输出格式时,gpt给出的回答格式是没有规则的,我们很难对结果进行目的性提取。因此需要严格规定gpt的输出格式,这一点就类似于我们日常的api接口开发,需要对期望结果指定返回格式,对于gpt模型而言道理同理。
    (4)示例:对于较为复杂的需求可能只通过背景的描述还不足够让gpt所理解,所以需要给出1到多个示例,就类似于我们在做算法题一样,这样可以让gpt给出的结果更加精准。
    (5)要求:给出gpt一些要求去限制其回答,例如异常处理,格式控制等。
    (6)任务:明确需求任务,让gpt作为执行引擎来完成我们的目标需求。
    (7)确认:用于确认gpt能否理解我们的需求,同时也作为模型预处理阶段gpt给我们的反馈,只有经过确认的模型我们才可以开始之后的交互操作。

    基于上述说明,为了gpt能够实现加法器需求,可以给出类似如下的提示词:

    sum.prompt(我习惯于将提示词文件命名为.prompt后缀,只是为了方便识别)

    -- 背景
    加法功能是我们常用的功能,可以将两个数字进行相加并求和,请按照以下要求完成数字求和的操作。
    
    -- 输入格式
    \input: [方括号内为数字1], [方括号内为数字2]
    (说明:输入必须以"\input: "字符串作为开头,后面是两个数字类型参数
    
    -- 输出格式
    \output: [方括号内为数字1 + 数字2的结果]
    (说明:输出必须以"\output: "字符串作为开头,后面是输入的两个数字类型的累加和
    
    
    -- 示例
        -- 我的输入:
        \input: 1, 2
        -- 你的输出:
        \output: 3
    
    -- 要求
        1. 请校验输入格式,不满足输入格式的字符串按照错误情况处理,错误情况请只回答"error";
        2. 请严格按照输出的格式进行回答;
    
    -- 任务
    请严格按照上述内容和要求根据我的输入做出相应回答,请只按照输出格式回答,拒绝其他描述性文字。
    
    -- 确认
    如果了解了上述要求,请只回答”yes“
    

    2. 代码示例

    import openai
    import os
    
    openai.api_key = os.getenv("OPENAI_API_KEY")
    
    model_name = 'gpt-3.5-turbo-0613'
    
    # 加载提示词文件并获取提示词
    with open('./sum.prompt', 'r', encoding='utf-8') as f:
        prompt = f.read()
    
    
    def gpt_sum(val1: int, val2: int):
        # 首先给出gpt任务提示词
        messages = [{'role': 'system', 'content': prompt}]
        # 模拟gpt的确认响应,后续可以直接以user角色给出gpt问题
        messages.append({'role': 'assistant', "content": 'yes'})
        # 以user角色给出gpt问题
        user_input = f"\input: {val1}, {val2}"
        messages.append({'role': 'user', 'content': user_input})
        gpt_resp = openai.ChatCompletion.create(
            model=model_name,
            messages=messages,
            timeout=30
        )
        if gpt_resp.choices and gpt_resp.choices[0]:
            resp_str: str = gpt_resp.choices[0].message.content
            if resp_str and resp_str.startswith('\output: '):
                return int(resp_str[len('\output: '):].strip())
        raise Exception(
            f'Failed to get available response from gpt, resp_str={resp_str}')
    
    
    if __name__ == '__main__':
        terminal_input = input("Please give two integers, split by comma: ")
        inputs: list[str] = terminal_input.split(',')
        if len(inputs) < 2:
            raise Exception("Invalid input, Please give two integers, split by comma")
        val1 = int(inputs[0].strip())
        val2 = int(inputs[1].strip())
        print(f"result = {gpt_sum(val1, val2)}")
    
    

    3. 运行并测试

    以下是执行结果:
    请添加图片描述


    4. 注意点

    在实验中测试发现gpt对于输入格式的校验存在误判的情况,一般是会将错误的输入格式理解为正确的,但几乎没有出现将正确的输入格式理解为错误的情况;另外一般gpt能够将与规定输入格式相差较大的输入正确判断。以下是对上述观点的测试代码

    gpt对与输入格式误判

    import openai
    import os
    
    openai.api_key = os.getenv("OPENAI_API_KEY")
    
    model_name = 'gpt-3.5-turbo-0613'
    
    
    if __name__ == '__main__':
        # 加载提示词文件并获取提示词
        with open('./sum.prompt', 'r', encoding='utf-8') as f:
            prompt = f.read()
        # 首先给出gpt任务提示词
        messages = [{'role': 'system', 'content': prompt}]
        # 模拟gpt的确认响应,后续可以直接以user角色给出gpt问题
        messages.append({'role': 'assistant', "content": 'yes'})
        
        # 以下的用户输入不满足提示词格式
        user_input = "2, 3"
        messages.append({'role': 'user', 'content': user_input})
        gpt_resp = openai.ChatCompletion.create(
            model=model_name,
            messages=messages,
            timeout=30
        )
        # gpt仍然将非法的输入格式理解为正确的,并能给出答案
        misjudgement_content= gpt_resp.choices[0].message['content']
        print(misjudgement_content)
        messages.append({'role': 'assistant', 'content': misjudgement_content})
        # 给出一个更加离谱的输入,一般这种情况gpt能够正确给出判断
        messages.append({'role': 'user', 'content': "错误的输入"})
        gpt_resp = openai.ChatCompletion.create(
            model=model_name,
            messages=messages,
            timeout=30
        )
        correct_judgment = gpt_resp.choices[0].message['content']
        # 能够正确给出校验结果
        print(correct_judgment)
    

    结果如下,可以发现gpt对于第一次的user输入未能给出正确的校验:
    请添加图片描述

    总结:最好在使用时使用我们自己的程序对异常输入进行提前校验,防止gpt的误判已经可能对gpt带来的干扰。


    四、进阶案例:利用gpt API实现交互式翻译器

    有了上述的尝试经验,可以利用gpt做一些更加复杂的尝试,毕竟单纯使用gpt作为累加器来说实属大材小用。在这部分将借助gpt来实现一个终端交互式的翻译器。

    实际上这部分的区别主要在于提示词的创建,另外考虑到gpt对于请求速率会有限制,在请求时增加了指数退避重试机制,来提高功能的可用。

    按照第三部分的步骤进行如下的操作:

    1. 创建任务提示词

    translator.prompt

    -- 背景
    需要实现将非中文语言(例如:英文、日文、韩文等)翻译成中文的功能。
    
    -- 输入格式
    {
        ”source": [方括号内是需要被翻译的文字内容,字符串类型]
    }
    (说明:输入是json格式,包含一个source属性)
    
    -- 输出格式
    {
        "success": [方括号内表示此次功能是否成功,值为布尔类型,成功为true, 失败为false]
        "translation": [方括号内是将输入内容翻译为中文的文字内容,字符串类型,当且仅当success为true时有值]
        "reason": [方括号内是错误信息,字符串类型,当且仅当success为false时有值]
    }
    (说明:输出是json格式,包含success和translation属性)
    
    -- 示例1
        -- 我的输入
        {
            "source": "Try it yourself. It was fun!"
        }
    
        -- 你的回答
        {
            "success": true,
            "translation": "试试看吧,这很有趣!"
        }
    -- 示例2
        -- 我的输入
        {
            "source": "楽しみに待っています。"
        }
    
        -- 你的回答
        {
            "success": true,
            "translation": "我正在期待地等待。"
        }
    -- 示例3
        -- 我的输入
        {
            "wrong_attr": "wrong attribute"
        }
    
        -- 你的回答
        {
            "success": false,
            "reason": "输入格式错误",
        }
    
    -- 要求
        1. 请校验输入格式,不满足输入格式的字符串按照错误情况处理;
        2. 请严格按照输出的json格式进行回答;
    
    -- 任务
    请严格按照上述内容和要求根据我的输入做出相应回答,请只按照输出内容回答,拒绝其他描述性文字。
    
    -- 确认
    如果了解了上述要求,请只回答”yes“
    

    2. 代码示例

    import jsonpickle
    import openai
    import os
    import time
    
    openai.api_key = os.getenv("OPENAI_API_KEY")
    
    model_name = 'gpt-3.5-turbo-0613'
    
    with open('./translator.prompt', 'r', encoding='utf-8') as f:
        prompt = f.read()
    
    
    class ChatGpt(object):
    
        __init_interval = 2
        __max_internal_exponent = 5
    
        def __init__(self, model: str, messages: list, timeout: int = 30, max_retries: int = 3):
            self.model = model
            self.messages = messages
            self.timeout = timeout
            self.max_retries = max_retries
    
        def response(self):
            retry_time = 0
            # 进行指数退避重试
            while True:
                try:
                    return openai.ChatCompletion.create(
                        model=self.model,
                        messages=self.messages,
                        timeout=self.timeout
                    )
                except openai.error.RateLimitError as e:
                    interval = self.__init_interval * \
                        (1 << min(self.__max_internal_exponent, retry_time))
                    print(
                        f"[warning]: Slepp {interval}s and retry due to rate limitation")
                    time.sleep(interval)
                    retry_time += 1
    
    
    def translate(content: str):
        messages = [{'role': 'system', 'content': prompt}]
        messages.append({'role': 'assistant', "content": 'yes'})
        messages.append({'role': 'user', 'content': jsonpickle.encode({
            "source": content
        }, indent=True)})
        gpt = ChatGpt(model=model_name, messages=messages)
        gpt_resp = gpt.response()
        if gpt_resp.choices and gpt_resp.choices[0]:
            resp = gpt_resp.choices[0].message.content
            resp_obj = jsonpickle.decode(resp)
            if True is resp_obj['success']:
                return resp_obj['translation']
            else:
                if False is resp_obj['success'] and resp_obj['reason']:
                    raise Exception(resp_obj['reason'])
        return None
    
    
    if __name__ == '__main__':
        while True:
            source = input("Please input, enter Q to quit: ")
            if source == 'Q':
                print('Bye!')
                break
            print(f">>> {translate(source)}")
    
    

    3. 运行并测试

    以下是执行结果:
    请添加图片描述
    上述测试分别使用英文、日文和法文进行了测试,实际发现gpt模型更倾向于欧美语言的翻译,对于其他地区的翻译有时会出现不太准确的情况,不过可以证实gpt已经可以很好的完整我们既定的需求了。


    总结

    一文总结

    通过本篇文章,可以帮助读者了解ChatGPT API的背景和代码调用方式。同时,我们探索了API的小例子和进阶使用技巧。ChatGPT API为开发者带来了更多可能性,我们期待在不同领域看到更多创新和应用。

    最后希望笔者的文章能给大家带来帮助,内容方面如有不足之处也希望大家多多给出意见和建议,让我们共同进步!!!

    示例代码地址:gitee

    作者:一期一会君

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【教程分享】使用Python记录GPT API的完整过程

    发表回复