GPT3 探索指南(三)

原文:zh.annas-archive.org/md5/e19ec4b9c1d08c12abd2983dace7ff20

译者:飞龙

协议:CC BY-NC-SA 4.0

第九章:构建一个由 GPT-3 提供动力的问答 app

到目前为止,我们已经查看了(并编写了)很多代码。但我们实际上还没有创建一个完全可用的 app。那就是我们将要做的事情。在本章中,我们将构建一个简单但功能强大的 Web app,让用户提出问题,由 GPT-3 从我们提供的知识库中回答。该 app 可用于回答任何类型的问题,但我们将用它来回答人们可能对我们有的问题 - 一个 问我任何事 的 app。所以,想象一个招聘专员或潜在雇主可以用来询问你的技能、成就和经验的网站。不想找新工作?没问题。同样,这个 app 可以用于任何类型的问答应用 - 所以可能是一个由 GPT-3 动力驱动的产品 FAQ,或一个由 GPT-3 动力驱动的教学助手 - 这完全取决于你。我们将从 app 将如何工作的快速概述开始,然后逐步介绍构建过程。

我们将涵盖的主题如下:

  • 介绍 GPT Answers

  • 介绍 Answers 端点

  • 设置和测试 Express

  • 为 GPT Answers 创建 API 端点

  • 创建 GPT Answers 用户界面

  • 整合 Answers 端点

  • 生成相关且准确的答案

  • 使用带有 Answers 端点的文件

技术要求

本章需要您访问 OpenAI API。您可以通过访问 openapi.com 来请求访问权限。

介绍 GPT Answers

在本节中,我们将构建一个由 GPT-3 提供动力的 Web app,让用户提出任何问题并从我们提供的数据知识库中获取答案。我们将称该 app 为 GPT Answers。是的,这个名称有点平淡,但我们可以随时使用 GPT-3 来帮助我们思考一个更好的名称。

以下是完成时 app 外观的截图。是的,用户界面可能像名称一样平淡,但其背后的功能一定令人印象深刻!

图 9.1 – GPT Answers 用户界面

图 9.1 – GPT Answers 用户界面

现在让我们深入了解 UI 的后台以及 app 将如何构建。

GPT Answers 技术概述

GPT Answers 将使用 Node.js、JavaScript 和 HTML 构建。我们还将使用一个名为 Express 的 Web 框架来简化开发。

重要提示

该 app 也可以使用 Python 构建,但对于本章,与之前的章节不同,我们只会介绍使用 Node.js/JavaScript 创建 app 的步骤。

问题将通过一个简单的网页表单提交,该表单将使用 JavaScript 向 app 也暴露的 API 端点发送请求。该 app 的 API 主要作为与 OpenAI API 交互的代理,但也将提供异常处理和响应格式化。

托管该 app

到目前为止,我们只使用replit.com来编写和测试代码。但是,replit.com还支持托管应用程序,并且使用起来非常容易。对于 Web 应用程序,您甚至可以使用自己的域名。因此,replit.com将成为我们的托管环境以及开发环境。

重要说明

由 GPT-3 支持的应用程序需要经过 OpenAI 批准才能向公众展示。我们在本章不会详细讨论此事,但我们将在第十章中涵盖应用程序批准流程,与 OpenAI 技术的应用上线

应用程序将使用的主要 OpenAI 端点是答案端点。但是由于我们尚未涵盖答案端点,请在开始编码之前快速介绍一下。

介绍答案端点

OpenAI Answers 端点专为问答任务而设计。它通过启用用于答案的真实来源而比 Completions 端点提供更多控制。对于我们的 GPT Answers 应用程序,这个真实来源将是用于回答问题的知识库。知识库(即文档)可以通过端点请求提供,也可以通过引用包含数据的预先上传的文件来提供。

答案端点的 URL 为 api.openai.com/v1/answers,该端点接受 HTTP POST 请求和一些输入参数。以下是可用输入参数的简要描述,但有关更完整的详细信息,请参阅位于 beta.openai.com/docs/api-reference/answers 的 OpenAI 文档的答案端点。

以下是必填参数:

  • model(必填,字符串) - 将用于完成的模型的 ID。

  • question(必填,字符串) - 要回答的问题。

  • examples(必填,数组) - 问题列表,带有答案,以帮助引导模型朝着答案的语气和格式前进。

  • examples_context(必填,字符串) - 包含用于为您提供的示例生成答案的上下文信息的文本片段。

  • documents(数组) - 应从中提取输入问题的答案的文档列表。如果documents参数是空列表,则将根据问题 - 答案示例来回答问题。另外,仅在不使用file参数时才需要documents参数。

  • file(字符串) - 包含要从中提取答案的文档的上传文件的 ID。如果未使用documents参数,则仅需要file参数。

可选参数如下:

  • search_model(字符串) - 用于搜索的引擎。默认为ada

  • max_rerank(整数)- 要处理的文档的最大数量。较高的值可以提高准确性,但会增加延迟和成本。默认为200

  • temperature(数字)- 默认为0,适用于定义明确答案,但较高的值可用于较不确定的答案。

  • logprobs(整数)- 默认为null。返回的可能标记数量。

  • max_tokens(整数)- 将用于生成答案的最大标记数量。默认为16

  • stop(字符串或数组)- 可选的最多四个模式序列,将导致 API 停止生成完成。默认为null

  • n(整数)- 为每个问题生成的答案数量。默认为1

  • logit_bias(映射)- 可以用于控制指定标记出现在完成中的可能性。

  • return_metadata(布尔值)- 如果使用了file参数并且文件引用包含元数据,则导致响应包含来自文件的元数据。

  • return_prompt(布尔值)- 导致将提示文本与响应一起返回。默认为false

  • expand(数组)- 导致响应包含关于完成或文件的详细信息。expand的值当前可以包括completionfile。默认为一个空数组。

    重要提示

    对于我们的 GPTAMA 应用程序,我们将不会使用所有可用的参数。

现在我们已经对 Answers 端点进行了快速介绍,让我们开始编写我们的 GPTAMA 应用程序!

设置和测试 Express

Express 是用于 Node.js 的轻量级但灵活的 Web 应用程序框架,我们将在应用程序中使用它。通过 Replit.com,它非常容易上手。所以,我们要做的第一件事是在 Replit.com 上设置 Express 并进行测试。我们将从头开始,因此我们将为 GPTAMA 创建一个新的 repl。

要创建一个新的 Node.js REPL 并设置 Express,请完成以下步骤:

  1. replit.com登录。

  2. 创建一个名为gptanswers-node的新 Node.js REPL。

  3. 在输出窗格中,单击Shell选项卡,然后输入此命令:

    npx express-generator --no-view --force .
    
  4. 通过按下Enter键运行上一个命令,您应该会看到一个类似以下截图的结果:图 9.2 - express-generator 的输出

    图 9.2 - express-generator 的输出

    重要提示

    npx命令包含在 NPM 中,NPM 与 Node.js 一起安装。它用于运行express-generator,该生成器将创建一个基本的 Express 应用程序作为起点。命令以句点结尾,以指示express-generator将文件添加到当前目录。--no-view开关告诉生成器我们只是使用纯 HTML 作为我们的 UI,--force开关告诉生成器覆盖当前目录中的任何现有文件。

  5. express-generator完成后,在 shell 中运行以下命令:

    npm update
    
  6. 现在创建一个名为.replit的文件,并将以下Run命令添加到其中:

    Run = "node ./bin/www"
    
  7. 最后,点击Run按钮启动 Express 服务器。如果一切顺利,您应该在 Replit.com 编辑器中看到一个打开的浏览器窗口,其中显示 Express 的欢迎消息。它应如下图所示:

图 9.3 – 在 Replit.com 中运行的 Express 服务器

图 9.3 – 在 Replit.com 中运行的 Express 服务器

需要注意的两件事是浏览器窗格中的 URL 以及Run按钮变成了Stop按钮。这是因为 Express 正在运行一个 HTTP 服务器,该服务器将持续运行,直到停止。因此,在 Express 服务器运行时,应用程序可在网上访问,并通过浏览器窗格中的 URL 访问。此外,当您进行更改时,您需要点击Stop按钮然后点击Run按钮来停止和重新启动 Express。

如果您遇到任何问题,并且看不到 Express 页面,您可以再次按照本节的步骤操作而不会损坏任何内容。当您看到 Express 的欢迎页面时,您就可以继续进行。接下来,我们将为我们的 GPT Answers 应用程序创建 API 端点。

为 GPT Answers 创建 API 端点

当我们的应用程序完成时,我们将拥有一个完全功能的 API 端点,可以返回由 OpenAI API 生成的答案。但现在,我们将只创建一个返回占位符响应的端点。然后,我们将使用 Postman 测试端点,稍后再回来完成编码。

创建 API 端点

要创建 API 端点,请执行以下操作:

  1. 打开由express-generator创建的app.js文件。该文件应如下图所示:图 9.4 – 由 express-generator 创建的默认 app.js 文件

    图 9.4 – 由 express-generator 创建的默认 app.js 文件

  2. 编辑第 7 行,将var usersRouter = require('./routes/users')更改为以下内容:

    var answerRouter = require('./routes/answer');
    
  3. 编辑第 18 行,将app.use('/users', usersRouter);更改为以下内容:

    app.use('/answer', answerRouter);
    

    编辑第 7行和18行后,app.js文件应如下图所示:

    图 9.5 – 编辑后的 app.js 文件

    图 9.5 – 编辑后的 app.js 文件

  4. 删除routes/users.js文件。

  5. 创建一个新文件routes/answer.js

  6. 添加以下代码到answers.js文件中:

    const axios = require('axios');
    const express = require('express');
    const router = express.Router();
    
    router.post('/', (req, res) => {
      res.send({answer:'placeholder for the answer'});
    });
    
    module.exports = router;
    
  7. 点击Stop按钮,然后Start。您应该再次看到Welcome to E****xpress的消息。

我们创建的 API 端点接受 HTTP/answer。但由于它接受 HTTP POST,我们需要通过进行 POST 请求来测试它。为了做到这一点,我们将使用 Postman。

使用 Postman 测试我们的 API

此时,我们应该能够向我们的/answer端点进行 HTTP POST 请求并获得响应。要完成测试,请将从Replit.com浏览器(显示 Express 欢迎消息的浏览器)复制到剪贴板的应用程序 URL:

  1. 打开一个新的浏览器选项卡并登录到postman.com

  2. 创建一个名为gptanswers-node的新集合。

  3. /answer 中创建一个名为 test-answer-api 的新请求。端点 URL 的格式如下,其中{username} 是你的 Replit.com 用户名(假设你将 repl 命名为 gptanswers-node):

    https://gptanswers-node.{username}.repl.co
    
  4. 在端点 URL 输入框下方,选择 Body 选项卡,选择 Raw 单选按钮,并从内容类型下拉列表中选择 JSON

  5. 最后,添加以下 JSON 请求体:

    {
        "question" : "How old are you?"
    }
    

    在设置 Postman 请求后,它应该像以下的屏幕截图:

    图 9.6 – 在 Postman 中测试 GPT-CV 应用程序 API 端点的请求。

    图 9.6 – 在 Postman 中测试 GPT-CV 应用程序 API 端点的请求。

  6. 点击蓝色 Send 按钮提交请求并查看响应,应如下所示:

    {
        "answer": "placeholder for the answer"
    }
    

现在,我们已经得到 API 端点的回应,接下来我们将创建一个 Web 表单来调用 API。

创建 GPT Answers 用户界面。

现在,让我们创建一个简单的 Web 表单界面,让用户提交问题以从我们的 API 获取答案。我们将从添加 UIkit 开始 – 这是一个流行的轻量级前端框架,你可以在 getuikit.com/ 了解更多信息。我们还将使用 Axios 使用一些 JavaScript 来对应用程序 API 进行 HTTP 调用。

UIkit 将使我们的应用程序拥有简单但干净和现代的外观。你可以从 getuikit.com 免费下载 UIkit,或者你可以使用一个托管版本,该版本可从 jsdeliver.com 获得,那就是我们将要使用的。

要添加 UIkit,请执行以下操作:

  1. 打开 public/index.html 文件。

  2. cdn.jsdelivr.net/npm/uikit@3.6.22/dist/css/uikit.min.css替换样式表的 URL。

  3. 使用以下代码替换 <body> 标签和 </body> 标签之间的所有内容:

      <div class="uk-section uk-section-large uk-height-viewport">
      <div class="uk-container uk-text-center uk-padding-large">
            <h1 class="uk-heading-medium"><strong>GPT</strong> Answers </h1>
            <p class="uk-text-lead">An Example Knowledge Base App Powered by GPT-3</p>
        </div>
        <div class="uk-container uk-text-center">
            <form class="uk-grid-collapse" uk-grid>
              <div class="uk-width-1-1 ">
                <input id="question" class="uk-input uk-width-1-3" type="text">
                <button type="submit" class="uk-button uk-button-default uk-width-1-5">Get Answer</button>
              </div>
            </form>
        </div>
        <div class="uk-container uk-text-center uk-padding">
          <div class="uk-inline">
            <div id="answer" class="uk-flex uk-flex-center uk-flex-middle uk-padding uk-width-expand"></div>
          </div>
        </div>
      </div>
    
  4. </body>标签上方添加以下代码。这将添加页面使用的 JavaScript 文件的引用。其中三个脚本将来自 CDN,一个 /javascripts/script.js,我们将在下一步中创建它:

    <script src="img/axios.min.js"></script>
    <script src="img/uikit.min.js"></script>
    <script src="img/uikit-icons.min.js"></script>
    <script src="img/script.js"></script>
    

    此时,public/index.html 文件的代码应如图所示:

    图 9.7 – 完成的  代码

    图 9.7 – 完成的 index.html 代码

    如果你点击 Stop 按钮然后点击 Run 按钮停止并重新启动 Express 服务器,你会看到主屏幕更新为如下屏幕截图的样子:

    图 9.8 – 问题输入表单

    图 9.8 – 问题输入表单

    现在我们需要添加一些 JavaScript 来调用应用程序 API。

  5. 创建 javascripts/script.js 文件并添加以下代码。

  6. 首先,我们将添加两个变量来保存 HTML 表单和答案 div

    const form = document.querySelector('form');
    const answer = document.querySelector('#answer');
    
  7. 接下来,我们将添加当提交表单时触发的代码:

    const formEvent = form.addEventListener('submit', event => {
      event.preventDefault();
      const question = document.querySelector('#question');
      if (question.value) {
        askQuestion(question.value);
      } else {
        answer.innerHTML = "You need to enter a question to get an answer.";
        answer.classList.add("error");
      }
    });
    
  8. 下面的代码将将文本附加到答案div中:

    const appendAnswer = (result) => {
      answer.innerHTML = `<p>${result.answer}</p>`;
    };
    
  9. 最后,我们将添加一个函数,使用 Axios 调用应用程序的 API 端点:

    const askQuestion = (question) => {
      const params = {
        method: 'post',
        url: '/answer',
        headers: {
          'content-type': 'application/json'
        },
        data: { question }
      };
      axios(params)
        .then(response => {
          const answer = response.data;
          appendAnswer(answer);
        })
        .catch(error => console.error(error));
    };
    
  10. 现在我们可以通过点击Stop按钮,然后点击Start按钮来进行测试。然后,在浏览器窗格中,在文本框中输入一个问题,然后点击GET ANSWER按钮。你应该会看到 API 回复的占位符答案,如下图所示:

图 9.9 – 使用占位符 API 代码测试 Web UI

图 9.9 – 使用占位符 API 代码测试 Web UI

在这一点上,我们已经搭建好了应用程序的基本框架。接下来,我们需要做的是写一些代码,将问题传递给 OpenAI API 答案端点。

集成答案端点

现在我们将返回到routes/answer.js文件中添加一些代码,以便调用 OpenAI Answers 端点来回答用户的问题,而不是返回占位符文本:

  1. 打开routes/answer.js文件并执行以下操作。

  2. 删除 第 5 行 之后的所有代码。

  3. 第 5 行 开始,添加以下代码,然后换行:

    const apiKey = process.env.OPENAI_API_KEY;
    const client = axios.create({
      headers: { 'Authorization': 'Bearer ' + apiKey }
    });
    
  4. 接下来,添加以下代码并在其后换行:

    const documents = [
      "I am a day older than I was yesterday.<|endoftext|>",
      "I build applications that use GPT-3.<|endoftext|>",
      "My preferred programming is Python.<|endoftext|>"
    ]
    
  5. 第 16 行 开始添加以下代码,然后换行:

    const endpoint = 'https://api.openai.com/v1/answers';
    
  6. 接下来,从 第 18 行 开始添加以下内容以完成代码:

    router.post('/', (req, res) => {
      // call the OpenAI API
        const data = {
        "documents": documents,
        "question": req.body.question,
        "search_model": "ada",
        "model": "curie",
        "examples_context": "My favorite programming language is Python.",
        "examples": [["How old are you?", "I'm a day older than I was yesterday."], ["What languages do you know?", "I speak English and write code in Python."]],
        "max_tokens": 15,
        "temperature": 0,
        "return_prompt": false,
        "expand": ["completion"],
        "stop": ["\n", "<|endoftext|>"],
      }
      client.post(endpoint, data)
        .then(result => {
          res.send({"answer" : result.data.answers[0]})
        }).catch(result => {
          res.send({"answer" : "Sorry, I don't have an answer."})
        });
    });
    module.exports = router;
    

    当你编辑完routes/answer.js文件后,文件应该像以下屏幕截图所示:

    图 9.10 – 编辑后的 routes/answer.js 文件

    图 9.10 – 编辑后的 routes/answer.js 文件

    我们快要完成了。在测试之前的最后一步是将我们的 OpenAI API 密钥添加为环境变量。

  7. 通过点击挂锁图标并添加一个名为OPENAI_API_KEY的密钥和您的 OpenAI API 密钥的值来将您的 OpenAI API 密钥添加为 REPL 的秘密,就像以下屏幕截图中的示例一样: 图 9.11 – 为 OpenAI API 密钥添加一个秘密

    图 9.11 – 为 OpenAI API 密钥添加一个秘密

  8. 点击Stop按钮,然后点击Run重新启动 Express,然后在问题文本框中输入你最喜欢的食物是什么?,然后点击GET ANSWER按钮。你应该会看到像以下屏幕截图展示的内容——来自 GPT-3 的答案:

图 9.12 – 来自 GPT-3 的答案

图 9.12 – 来自 GPT-3 的答案

现在我们有了一个简单但功能齐全的基于 GPT-3 的问答应用。然而,您可能想知道为什么我们在**你最喜欢的食物是什么?**这个问题上得到了回应(一个答案),当我们还没有给出那个答案。我们将在后面讨论这个问题。

生成相关且真实的答案

GPT-3 是一个语言模型 - 它预测应该跟随提供的提示文本的文本的统计可能性。从某种意义上说,它不是一个知识库,它并不太关心所生成的响应的事实准确性。这并不意味着它不会生成事实性答案;这只是意味着你不能指望所有时间答案都是准确的。但是 Answers 端点可以提供对所生成答案的准确性或相关性的很多控制。

正如我们之前在 介绍 Answers 端点 中讨论的那样,答案将从我们提供的文档中生成。在这一点上,我们是作为端点请求的一部分提供文档的。使用这种方法,如果答案无法从文档中推导出来,由 routes/answer.js 文件定义的引擎 - 我们使用了 Curie 引擎。但是假设我们只希望答案从我们的文档中推导出来,否则我们不希望返回答案。虽然我们无法完全控制这一点,但我们可以使用预先上传的文件使我们接近实现这一点。

当使用 Answers 端点时使用预先上传的文件时,与使用 HTTP 请求提供文档时一样,你不仅仅限于只有 200 个文档。事实上,预先上传的文件可能包含非常多的文档,因为每个组织可以拥有最多 1 GB 的文件空间。因为一个文件可能包含非常多的文档,所以对文件中的文档应用关键字过滤器以缩小可能用于答案的文档范围。从那里开始,文档被排名,然后由模型参数定义的引擎使用以生成答案。当你使用请求参数发送文档时,关键字过滤将被跳过,因为你可以发送的文档数量限制为 200 个。对于我们的 GPT Answers 应用程序,关键字过滤将帮助我们减少回答无关问题的可能性。所以,让我们看一下如何使用 Answers 端点中的文件。

使用 Answers 端点的文件

要使用文件中的文档,我们需要做的第一件事是将文件上传到 OpenAI,以便 Answers 端点可以使用它。该过程涉及创建一个包含我们文档的文件,然后使用 文件端点 将文件上传并获取可在对 Answers 端点发出请求时使用的文件 ID。要创建和上传答案文件,请完成以下步骤:

  1. 创建一个名为 answers.jsonl 的新的jsonl文件,并为文件中的一些答案编写如下格式的答案:

    {"text": "I am a day younger than I will be tomorrow"}
    {"text": "I like to code in Python."}
    {"text": "My favorite food is carrot cake."}
    
  2. 创建另一个名为 files-upload.js 的新文件。

  3. file-upload.js 中添加以下代码:

  4. 需要几个将要使用的模块:

    const fs = require('fs');
    const axios = require('axios');
    const FormData = require('form-data');
    
  5. 接下来,添加以下代码来读取请求的 jsonl 数据:

    const data = new FormData();
    data.append('purpose', 'answers');
    data.append('file', fs.createReadStream('answers.jsonl'));
    
  6. 添加一个变量用于 HTTP 请求参数:

    const params = {
    method: 'post',
    url: 'https://api.openai.com/v1/files',
    headers: { 
      'Authorization': 'Bearer ' + process.env.OPENAI_API_KEY, 
      ...data.getHeaders()
    },
    data : data
    }
    
  7. 最后,添加代码以进行 HTTP 请求并记录结果:

    axios(params)
      .then(function(response) {
        console.log(response.data);
      })
      .catch(function(error) {
        console.log(error);
      });
    

    当编辑完 files-upload.js 后,它应该像以下截图中的代码一样:

    图 9.13 – file-upload.js 的完成代码

    图 9.13 – file-upload.js 的完成代码

  8. 在输出窗格中,点击Shell选项卡。

  9. ~/gptanswers-node提示符处,输入以下命令并附上你的 OpenAI API 密钥:

    export OPENAI_API_KEY="your-api-key-goes-here"
    
  10. 接下来,在 shell 中输入以下命令:

    node files-upload.js
    

    运行上述 shell 命令后,你应该会看到类似以下截图的输出结果:

    图 9.14 – files-upload.js 的 Shell 输出

    图 9.14 – files-upload.js 的 Shell 输出

  11. 从 JSON 结果中复制id值(以file-开头的值)到剪贴板。

  12. 点击小锁图标并创建一个名为ANSWERS_FILE的新秘密/环境变量,并将你在上一步中复制的 ID 值粘贴到值输入中,然后点击添加新的秘密按钮。

  13. 打开routes/answer.js并将第 20 行documents参数重命名为file。然后用process.env.ANSWERS_FILE替换documents值。

    上一个更新后,第 20 行应该看起来像以下截图中的第 20 行

    图 9.15 – 使用文件参数的 Answers 端点参数

    图 9.15 – 使用文件参数的 Answers 端点参数

    此时,你已经准备好测试了。

  14. 点击运行按钮,然后在问题输入中输入你最喜欢的食物是什么?,然后点击获取答案按钮。这次你会注意到答案是从我们的答案文件中生成的,就像以下截图所示:

图 9.16 – 从答案文件生成的答案

图 9.16 – 从答案文件生成的答案

但是现在,如果你输入一个与你的文件中的数据完全无关的问题,响应将会是对不起,我没有答案。你可以尝试询问诸如**你们有红色的这个吗?**这样的问题。你应该会看到一个类似以下截图的结果:

图 9.17 – 无法回答的问题

图 9.17 – 无法回答的问题

一个重要的事情要记住的是,答案文件和完成引擎(在我们的案例中是Curie)都用于生成答案。因此,有可能得到一个在你的文件中没有定义的答案。但是,你的答案文件中的数据越多,这种可能性就越小。但是因为我们现在只有三个文档在我们的答案文件中,所以如果你问类似**你最喜欢的度假地点是什么?**这样的问题,你可能会看到一个在你的答案文件中没有定义的答案,就像以下截图所示:

图 9.18 – 不是来自答案文件的答案

图 9.18 – 不是来自答案文件的答案

因此,即使我们在答案文件中提供答案,也不能保证 GPT-3 不会生成不准确的答案。但我们稍后将在本章和第十章使用 OpenAI-Powered 应用程序上线中讨论这一点。

到目前为止,我们有一个完全功能的应用程序。当然,我们可以添加更多功能来完善我们的应用程序,但核心功能已经就位。你需要做的主要事情是向答案文件中添加更多文档。要做到这一点,每次想要添加新数据时,请完成以下步骤:

  1. answers.jsonl 文件添加新文档。

  2. 打开 shell。

  3. 运行以下 shell 命令将你的 API 密钥设置为 shell 可以访问的环境变量:

    export OPENAI_API_KEY="your-api-key-goes-here"
    
  4. 在 shell 中运行以下命令以执行 files-upload.js

    node files-upload.js
    
  5. 通过单击锁图标并替换值为 ANSWERS_FILE 机密,复制文件 ANSWERS_FILE 环境变量。

  6. 单击 停止 按钮,然后单击 运行 按钮重新启动 Express。

再次,你的答案文件中有更多数据将减少出现非事实性答案的机会。但 GPT-3 仍然可能生成明显不是来自你的答案文件的答案。因此,考虑内容过滤仍然很重要,这也是我们将在下一章中更详细介绍的原因。

概要

在本章中,我们介绍了答案端点,并使用 Node.js/JavaScript 构建了一个简单但功能齐全的 Web 应用程序,可以从我们提供的文档中回答问题。对于我们的应用程序,我们创建了一个充当 OpenAI API 代理的 API 和一个提供用户界面的 HTML 页面。

在下一章中,我们将讨论 OpenAI 应用程序审查流程,并根据 OpenAI 的建议实施一些修改。然后,我们将介绍上线所需的步骤!

第十章:使用 OpenAI 提供的应用程序上线

在使用 OpenAI API 的应用程序上线之前,它们必须经过 OpenAI 的发布批准。批准过程有助于防止 OpenAI API 被故意或意外地滥用。它也有助于应用程序提供者和 OpenAI 规划资源需求,以确保应用程序在推出时表现良好,并随着使用量的增长而增加。

在此章节中,我们将讨论 OpenAI 应用程序使用案例指南以及审查和批准过程。然后,我们将根据 OpenAI 的指南讨论对我们的 GPT Answers 应用程序所做的更改。最后,我们将实施建议的更新,并讨论提交我们的应用程序进行审查,并希望获得批准的过程!

我们将涵盖的主题如下:

  • 上线

  • 理解用例指南

  • 处理潜在的批准问题

  • 完成预上线审查请求

技术要求

本章需要您可以访问OpenAI API。您可以通过访问openai.com来请求访问权限。

上线

OpenAI 将活动的应用程序定义为向超过五个人提供 API 输出的任何应用程序。这包括您公司或组织中的人员。因此,即使一个私人测试版应用程序使用 OpenAI API 并拥有超过五个用户,它也被认为是活动的。要超出这一限制,您的应用程序需要经过 OpenAI 的审查和批准。

在未经 OpenAI 批准的情况下上线可能会导致您的 API 密钥立即被吊销,而且没有警告。此外,未经批准的上线可能导致您的账户被永久性地阻止进一步访问 API。因此,了解 OpenAI 使用案例指南和审查过程是一个好主意。

理解用例指南

可以使用 OpenAI API 的应用程序范围广泛。然而,并非所有用例都被允许,因此每个应用程序在上线之前都必须经过审查和批准。

每个应用程序都是根据特定情况进行评估的,因此了解您的应用程序是否允许的唯一方法是通过审查过程。特别是,OpenAI 发表了一些指南,您可以阅读和遵循,以使您的应用程序有最佳的批准机会。您可以在beta.openai.com/docs/use-case-guidelines找到这些指南。在大量投入应用程序之前,您应该先仔细阅读这些指南。

在本节中,我们不会涵盖所有应用程序指南。但主要是与安全相关的指南。OpenAI 定义的安全是摆脱可以对人们造成身体、心理或社会伤害的条件的自由,包括但不限于死亡、伤害、疾病、困扰、错误信息或激进化、财产或机会的损失或损害,以及对环境的损害

因此,作弊、欺骗、剥削、骚扰、伤害、恐吓、操纵、误导、盗窃、诈骗,或者在任何方式上可能造成伤害或损害的应用,无论是否有意,都是不允许的。大多数指南应该看起来相当明显。但有些指南并不那么明显。例如,在大多数情况下,你不能构建用于生成 Twitter 推文内容的应用。这是因为使用 AI 生成的内容违反了 Twitter 的可接受使用政策。因此,再次强调本节的重点不是覆盖具体的指南;重点是强调在构建应用之前审查和理解指南的重要性。通过在开始构建之前审查指南,你将能够专注于所有可接受的用例,并避免潜在的审批问题。我们将在审查流程之前看一些可能的问题。

处理潜在的审批问题

阅读完 OpenAI 用例指南后,我们可以考虑它们如何适用于我们的 GPT Answers 应用程序。我们的应用程序仅限于以我们在答案文件中提供的答案来回答问题。因此,它的范围非常有限,不会生成开放式的响应。基于此,指南建议我们的应用程序几乎总是可批准的。然而,再次强调,每个应用程序都是根据具体情况审批的,所以这并不是一个保证。

另外,作为开发人员,我们希望尽一切可能考虑安全最佳实践。OpenAI 在 beta.openai.com/docs/safety-best-practices 发布了安全最佳实践,这将有助于确保我们的应用程序是安全的,并且不容易被利用。这也将有助于增加我们的应用程序获得批准的机会。基于这些指南,我们将考虑对我们的 GPT Answers 应用程序进行一些修改。具体来说,我们将考虑以下内容:

  • 内容过滤

  • 输入和输出长度

  • 速率限制

让我们逐个讨论这些考虑因素,并讨论它们如何适用于我们的应用。

内容过滤

对于我们的 GPT Answers 应用程序,内容过滤可能是不必要的,因为完成是从我们提供的答案文件中生成的 - 这在某种程度上可以算作一种输出过滤。然而,我们可能不希望将不适当的问题发送到 OpenAI API,因为即使在我们的情况下响应是安全的,我们仍然会使用令牌。因此,我们将为问题实施内容过滤,以检查不适当的词语。

我们将要实现的内容过滤流程如下:

  1. 用户提出一个问题。

  2. 我们检查问题是否含有粗俗语言。

  3. 如果检测到粗俗语言,我们显示:这不是我们可以回答的问题

  4. 如果未检测到粗俗语言,我们将问题传递给 OpenAI API。

我们将使用一个名为 bad-wordsNode.js 库来检查问题文本中是否包含粗话,然后再将其发送到 OpenAI API。如果在文本中发现了粗话,我们将礼貌地回复一条消息,说这不是我们能回答的问题

要在问题文本上实现内容过滤,请执行以下操作:

  1. routes/answer.js 的第一行引入 bad-words 库,代码如下:

    const Filter = require(‘bad-words’);
    
  2. routes/answer.js 文件中,在以 const data 开头的行上面添加以下代码:

    let filter = new Filter();
    if (filter.isProfane(req.body.question)) {
        res.send({ “answer”: “That’s not a question we can answer.});
        return;
    }
    
  3. 点击停止按钮,然后点击运行按钮,并通过输入包含粗话的问题来进行测试。你应该会看到以下截图中的结果:

图 10.1 – 过滤问题中的粗话

图 10.1 – 过滤问题中的粗话

现在我们已经为问题实现了内容过滤。如果我们要使用完成端点生成答案,我们还想使用我们在第六章中讨论过的内容过滤引擎来对答案应用内容过滤。但是,因为我们是从提供的文件中生成答案,所以对于 GPT Answers 应用来说可能并不必要。因此,让我们继续考虑输入和输出长度。

输入和输出长度

OpenAI 建议限制输入和输出长度。输出可以使用 max_tokens 参数轻松限制。我们已经将 GPT Answers 应用的 max_tokens 参数设为 150。这是推荐的范围输出长度 - 如来自答案文件的问题答案。这将支持约 6-8 个句子的答案文本。如果你有更短的答案,你可以减小 max_tokens 的长度。较少,只要你允许足够来完全回答问题。

注入攻击是一种利用允许执行不受信任或意外输入的 Web 应用程序的攻击。例如,在 GPT Answers 应用中 - 如果用户提交的内容不是问题,而我们的后端代码将其传递给 OpenAI API 会发生什么?记得了吗,输入输出?尽管我们的应用程序范围严格,并且除了相关问题以外的任何内容都不会返回任何东西,但是添加一些代码来防止非常大的文本输入仍然是值得的,因为输入仍然会使用标记。因此,我们将添加一些代码来限制输入长度。平均句子是 75-100 个字符,因此我们将限制输入为 150 个字符,以允许更长的句子。

要限制我们的 GPT Answers 应用中的输入长度,请执行以下操作:

  1. 打开 routes/answer.js 并在以 router.post 开头的行后面的新行上添加以下代码:

    if (req.body.question.length > 150) {
      res.send({ “answer”: “Sorry. That question is too long.});
      return;
    }
    
  2. 点击停止按钮,然后点击运行按钮来停止和启动 Express 服务。

  3. 输入一个超过 150 个字符长的文本输入到问题框中,然后点击获取答案按钮。

    您现在会看到表单告诉用户他们输入的文本太长,如下截图所示:

图 10.2 – 长文本表单输出

图 10.2 – 长文本表单输出

再次强调,尽管我们的应用不应生成意外完成,但限制输入,以及请求速率限制,将有助于预防恶意尝试利用您的应用。接下来让我们来谈谈速率限制。

请求速率限制

速率限制防止用户在给定时间段内发出超过预定义数量的请求。这可防止恶意脚本潜在地向您的应用程序发出大量请求。我们将使用一个名为Express Rate Limit的可用于Node.js的库,根据 OpenAI 建议的指南将限制设置为每分钟最多六次请求。

要实现速率限制,请执行以下操作:

  1. 打开app.js,在行 9之后(或在var app = express();之后),添加以下代码:

    const rateLimit = require(“express-rate-limit”);
    const apiLimiter = rateLimit({
      windowMs: 1 * 60 * 1000,
      max: 6
    });
    app.use(/answer/, apiLimiter);
    
  2. 打开routes/answer.js,并在以router.post开头的行后添加以下代码:

    if (req.rateLimit.remaining == 0) {
      res.send({“answer” : “Ask me again in a minute.});
      return;
    };
    

    之前的更改为每分钟六次请求设置了速率限制。当在向 OpenAI API 发出请求之前达到速率限制时,我们会以消息回应,并要求在一分钟内再试一次,如下截图所示:

图 10.3 – 请求速率超过时的消息

图 10.3 – 请求速率超过时的消息

由于我们以与答案相同的 JSON 格式发送消息,因此消息会显示在表单页面上。

重要提示

您可以通过访问www.npmjs.com/package/limiter了解使用的速率限制器库。

好的,现在我们已经审查了用例指南并实施了一些安全最佳实践,我们准备讨论 OpenAI 预发布审核和批准流程。

完成预发布审核请求

当您的应用准备好上线时,您可以通过填写位于beta.openai.com/forms/pre-launch-review预发布审核请求表单来开始批准流程。

该表单收集您的联系信息,以及您的领英资料链接、应用程序的视频演示,以及关于应用用例和增长计划的一系列特定问题的答案。在接下来的部分中,我们将列出当前问题并提供可能适用于 GPT Answers 应用程序的示例答案。

预发布审核请求表中有很多问题,建议先在 Google 文档(或其他应用程序)中完整回答问题,然后在准备就绪时将答案复制粘贴到表单中。

该表单首先收集您的联系方式。在提供联系信息后,第一组问题会就高级别的用例进行提问。

高级用例问题

高层次的用例问题非常直观。但是,其中一个问题要求提供视频演示。所以,您需要提供一个视频演示,并将其发布到 YouTube 等地方,以便提供链接。以下是问题和一些示例答案:

  • 问题:您是否已经审查过 OpenAI 的用例指南?

    答案:是的

  • 问题:请描述一下您的公司是做什么的。

    答案:我的公司提供技术学习资源。

  • 问题:请描述一下您的应用程序是做什么的。

    答案:它让用户获取关于我的问题的答案。

  • 问题:您的申请之前是否被 OpenAI 审核过?此次审核的结果如何?此次提交与之前的审核有何关联?

    答案:没有

  • 问题:请链接到您的应用程序的短视频演示。

    答案:这里放置一个视频演示的链接。

  • 问题:请分享一个 OpenAI 团队可以用来演示/测试您的应用程序的登录凭据。

    答案:不需要登录凭据。

接下来的一组问题与安全性和风险缓解相关。您可能会猜到,有很多关于安全性和风险缓解的问题。让我们来看一看。

安全和风险缓解问题

在编写本书时,有 14 个安全和风险缓解问题。您将看到其中一些问题涉及内容过滤、设置输入和输出长度以及请求速率限制等问题。这些问题对批准是重要的且必需的,这就是为什么我们在我们的 GPT Answers 应用中实现了它们:

  • 问题:用户可以在您的应用程序的输入文本框中插入的最大字符数是多少?

    答案:150

  • 问题:您的应用程序运行的最大输出标记是多少?

    答案:150

  • 问题:您的应用程序的典型用户是谁(例如,企业、研究实验室、企业家、学术界等)?您以某种方式验证或认证用户吗?如果是,如何?

    答案:最可能的用户是对我的专业背景感兴趣的招聘人员。用户未经验证,但使用用户的 IP 地址进行了速率限制。

  • 问题:用户需要支付才能访问您的应用程序吗?如果是,金额是多少?

    答案:没有

  • 问题:您是否为您的应用程序实现了速率限制?如果是,速率限制是多少,如何执行?

    答案:是的,速率限制由 IP 地址强制执行,请求限制为每分钟六次请求。

  • 问题:您是否为您的应用程序实现了某种形式的内容过滤?如果是,被过滤的内容是什么,通过什么手段进行过滤,以及如何执行?

    答案:所有答案都是从预先上传用于与答案端点一起使用的答案文件生成的。因此,不使用内容过滤。

  • 问题:您是否捕获用户对您的输出质量或其他细节(例如,返回不愉快的内容)的反馈?如果是,这些数据如何监控和处理?

    答案:提供了一个链接到 Google 表单,让用户报告他们可能遇到的任何问题。

  • 问题:您是否会监控您应用程序的特定用户的使用情况(例如,调查体积的激增,标记某些关键字等)?如果是,以什么方式和通过什么执行机制?

    答案:不,因为范围仅限于由我提供的答案文件中的数据。

  • 问题:您的应用程序是否清楚地披露了内容是由 AI 生成的?以什么方式?

    答案:是的,问题输入页面上的文字让用户知道答案是由 GPT-3 生成的。

  • 问题:您的应用程序中是否有人类介入的形式?如果有,请描述。

    答案:是的,所有问题的答案都来自一个最初由人类创建和更新的答案文件。

  • 问题:您是否为此项目实施了其他安全或风险缓解因素?请描述。

    答案:OpenAI 令牌使用将被密切监控异常使用模式。

  • 问题:您的应用程序与社交媒体之间有何关系(如果有的话)?

    答案:没有。

  • 问题:你的应用程序与政治内容有何关系(如果有的话)?

    答案:没有。

  • 问题:如果您的团队具有特定的资格或背景,可能有助于缓解上述任何风险,请在此处详细说明。

    答案:我们没有特定的资格。

在安全和风险缓解问题之后,你将被询问关于你的增长计划。

增长计划问题

为了管理资源需求并限制滥用的可能性,新的应用程序被授予了最大花费限制。这就限制了可以处理的令牌的最大数量,从而限制了可扩展性。然而,随着你的应用程序建立了一份可靠记录,最大花费限制可以随着时间的推移而增加。

你的初始花费限制需要经过批准才能上线,并且在应用程序上线后需要提交额外的表单来请求花费限制的增加。花费限制增加表单位于beta.openai.com/forms/quota-increase。要计算您的花费限制,请在 Playground 中输入一个典型的提示,并设置引擎和响应长度。然后将鼠标悬停在提示输入下方的数字上,您将看到一个估计的成本,如下面的屏幕截图所示:

图 10.4 – 估计成本

img/B16854_10_004.jpg

图 10.4 – 估计成本

通过 Playground 的成本,你可以按预估的用户数量和每月请求数量进行乘法运算。你需要对增长计划部分的问题提供一个估计。

以下是关于你的增长计划的问题:

  • 问题:您希望请求多少美元价值的每月配额?

    答案:$18

  • 问题:您预计每个月会消耗多少令牌?针对哪些引擎?

    答案:~ 1 Mn ada 代币和~1 Mn curie 代币。

  • 问题:您最初将向多少用户(大约)推出您的应用程序?您如何知道这些用户?/您将如何找到这些用户?

    答案:订阅我们 SaaS 服务的 5,000 名用户

  • 问题:请描述您在初始推出后的增长计划。

    答案:我们计划向我们服务的所有新用户推出该应用程序 - 每月约 500 个

  • 问题:如果获准,您打算在哪个日期启动您的应用程序?

    答案:2021 年 11 月 5 日

  • 问题:如果有用的话,您可以在上面的启动日期上进行详细说明。

    答案:我们希望尽快推出。

在成长规划问题之后,还有一些杂项问题要总结,然后您就完成了。

总结问题

总结问题请求您对应用程序开发过程以及构建应用程序的经验提供反馈。这是向 OpenAI 提供信息的机会,可以帮助他们改进其他开发者的开发体验:

  • 问题:我们很喜欢听取反馈!您是否想与 OpenAI 团队分享任何内容(例如,构建应用程序最困难的部分或您希望看到的功能)?

    答案:最困难的部分是找出最佳的请求速率限制方法。

  • 问题:如果我们批准您的应用程序,您是否希望添加任何合作者来访问 API?如果是,请以逗号分隔的形式列出他们的电子邮件。

    答案:不,目前只有我一个人。

  • 问题:我们对此过程的反馈特别感兴趣。您完成这个表单需要多长时间?您觉得最困难的是什么?

    答案:我花了大约 5 天时间。我对编码还很陌生,所以学习曲线很具挑战性。

  • 问题:您还有什么要分享的吗?

    答案:我非常喜欢与 API 合作!

  • 问题:表单提交日期

    答案:05/11/2021

在完成并提交“预发布审查请求”表单后,您应该在几天内收到回复。回复将是批准或拒绝,并附有拒绝的原因。根据拒绝原因,您可能能够解决任何指出的问题并重新提交进行另一次审查。然而,希望您的应用程序获得批准,并且您已经获得了上线的批准!

概要

恭喜,您已完成探索 GPT-3和您的第一个 OpenAI 驱动的应用程序!在这一点上,您的应用程序应该已经准备好进行审查流程了。请记住,所有应用程序都是根据具体情况逐案批准的。因此,仅仅完成本书中的步骤并不保证获得批准。但是,您现在了解了用例指南以及应用程序审查和批准流程。此外,您具备了处理 OpenAI 可能要求的任何更改所需的知识和技能。

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值