开发指南:ChatGPT 插件开发(上)
开发指南:ChatGPT 插件开发(下)
目前的语言模型虽然功能强大,但仍有局限性。其只能从训练数据中学习,而这些数据可能已经过时或无法涵盖所有情况。同时,语言模型只能生成文本,而无法直接执行指令。为了解决这些问题,插件被提出作为语言模型的“眼睛和耳朵”,让模型能够获取更加及时、个性化和具体化的信息,并能够通过插件执行安全和受限的操作。
为了统一应用程序公开面向 AI 的接口的方式,开放标准预计会出现。OpenAI 正在早期尝试这个标准,并希望得到开发者的反馈。现在,OpenAI 正在逐步启用一些合作者的插件供 ChatGPT 用户使用,同时开始推出开发者可以为 ChatGPT 创建自己的插件的功能。在未来,随着安全系统的改进和使用经验的累积,OpenAI 还将对协议进行迭代,并计划使使用 OpenAI 模型的开发者能够将插件集成到自己的应用程序中。ChatGPT 希望建立一个社区,共同塑造人工智能与人类互动范式的未来。
邀请进入等待名单(等待名单申请入口[1])的插件开发者现在可以开始构建插件了。这一创新将使 ChatGPT 更加灵活和强大,能够解决更多的问题,满足更多的需求。第一批插件已经由 Expedia[2]、FiscalNote[3]、Instacart[4]、KAYAK[5]、Klarna[6]、Milo[7]、OpenTable[8]、Shopify[9]、Slack[10]、Speak[11], Wolfram[12] 和 Zapier[13] 创建。
开发指南:ChatGPT 插件开发 - 图1
目前官方托管了两个插件,一个是网页浏览器,一个是代码解释器。同时,开源了知识库检索插件的代码,让开发者可以自行托管以增强 ChatGPT 的信息。已经开始向等待名单中的用户和开发者扩展插件 alpha 访问权限。会优先考虑少数开发者和 ChatGPT Plus 用户,但也会逐步推出更广泛的访问权限。
浮之静
,赞3

网页浏览器(Alpha)

一种实验性模型,知道何时以及如何浏览互联网
受到过去工作(WebGPT[14],以及 GopherCite[15]、BlenderBot2[16]、LaMDA2[17] 等其他工作[18])的启发,允许语言模型从互联网中阅读信息严格地扩展了它们可以讨论的内容数量,超越了训练语料库,获取了来自当下的新鲜信息。
下面是浏览为ChatGPT用户带来的一种体验的示例,以前模型会礼貌地指出其训练数据中不包含足够的信息以便回答(例如:ChatGPT 检索有关最新奥斯卡奖的最新信息,然后进行了现在众所周知的ChatGPT诗歌表演),这是浏览可以成为一种附加体验的一种方式。
安全注意事项:
Web 浏览插件,让 ChatGPT 能够安全地访问网络浏览器,并考虑了安全问题和成为 Web 良好公民。该插件仅允许进行 GET 请求,从而降低了某些安全风险,但并未完全消除。这使得浏览插件适用于检索信息,但排除了具有更多安全和安全问题表面的“交易”操作,例如表单提交。浏览插件使用 Bing 搜索 API 从 Web 检索内容,并且插件运行在隔离服务中,因此 ChatGPT 的浏览活动与基础架构的其余部分分离。
为了尊重内容创作者和遵守 Web 规范,浏览器插件的用户代理会标记为 ChatGPT-User[19],并配置为遵守网站的 robots.txt 文件。这有时可能会导致“点击失败”消息,表示插件正在遵循网站的指示以避免爬行它。该用户代理仅用于代表 ChatGPT 用户采取直接操作,而不会以任何自动方式爬网页。ChatGPT 会公布 IP 出口范围[20],同时实施了限制速率措施,以避免向网站发送过多流量。使 ChatGPT 能够在合适的情况下使用网络资源。浏览插件会在 ChatGPT 的回复中显示访问的网站,并引用其来源。这种透明度的增加有助于用户验证模型回复的准确性,也向内容创建者归功,这是与网络互动的一种新尝试。
开发指南:ChatGPT 插件开发 - 图2
浮之静

代码解释器(Alpha)

一款实验性模型,可以使用 Python,处理上传和下载
为模型提供了一个工作中的 Python 解释器,在一个沙盒化、防火墙的执行环境中,以及一些短暂的磁盘空间。由解释器插件运行的代码在一个持久的会话中进行评估,该会话在聊天对话期间保持活动状态(有一个上限的超时时间),随后的调用可以在其上进行构建。支持将文件上传到当前的对话工作区,并下载其返回结果。
开发指南:ChatGPT 插件开发 - 图3
希望模型能够利用自身的编程技能,为我们的计算机提供更自然的接口,以使用大多数基本功能。能够访问速度快的初级程序员可以使全新的工作流程变得轻松高效,同时也可以向新的受众开放编程的好处。通过初步用户研究,发现比较适合的场景:

  • 解决数学问题,包括定量和定性分析
  • 进行数据分析和可视化
  • 在不同格式之间进行文件转换

简单来说:就是 ChatGPT 自己生成代码,并执行它,返回结果。当然它能处理的任务很有限,但潜力巨大,用户可以自己去发掘一下。
安全考虑:
将模型连接到编程语言解释器的主要考虑因素是正确地对执行进行沙箱隔离,以避免 AI 生成的代码在现实世界中产生意外的副作用。在受保护的环境中执行代码,并使用严格的网络控制来防止执行代码时的外部 Internet 访问。也会在每个会话中设置资源限制。禁用 Internet 访问会限制代码沙盒的功能,但团队认为这是正确的初步权衡。第三方插件是将模型安全地连接到外部世界的首选方法。
浮之静
,赞1

Retrieval 插件

Retrieval 插件(ChatGPT Retrieval Plugin[21])使 ChatGPT 能够访问个人或组织信息源(经过授权)。它允许用户通过自然语言提出问题或表达需求,从其数据源(如文件、笔记、电子邮件或公共文档)中获取最相关的文档片段。
作为开源和自托管解决方案,开发人员可以部署自己的插件版本并在 ChatGPT 中注册。该插件利用 OpenAI 嵌入,并允许开发人员选择用于索引和搜索文档的向量数据库(Milvus[22]、Pinecone[23]、Qdrant[24]、Redis[25]、Weaviate[26] 和 Zilliz[27])。可以使用 Webhook 将信息源与数据库同步。
安全考虑:
Retrieval 插件允许 ChatGPT 搜索内容向量数据库,并将最佳结果添加到 ChatGPT 会话中。这意味着它没有任何外部影响,主要的风险是数据授权和隐私。开发者应仅将其有权使用并可以在用户 ChatGPT 会话中共享的内容添加到其检索插件中。
浮之静
,赞2

第三方插件(Alpha)

一个实验性的模型,知道何时以及如何使用插件
开发指南:ChatGPT 插件开发 - 图4
第三方插件由一个清单文件描述(manifest.json[28]),其中包括插件能力的机器可读描述以及如何调用它们,以及面向用户的文档。

  1. {
  2. "schema_version": "v1",
  3. "name_for_human": "TODO Manager",
  4. "name_for_model": "todo_manager",
  5. "description_for_human": "Manages your TODOs!",
  6. "description_for_model": "An app for managing a user's TODOs",
  7. "api": { "url": "/openapi.json" },
  8. "auth": { "type": "none" },
  9. "logo_url": "https://example.com/logo.png",
  10. "legal_info_url": "http://example.com",
  11. "contact_email": "hello@example.com"
  12. }

创建插件的步骤包括:

  • 构建一个 API,包含您希望语言模型调用的端点(可以是新的 API,现有的 API 或专门为 LLMs 设计的现有 API 的包装器)。
  • 创建一个 OpenAPI 规范文档,记录您的 API,以及一个链接到 OpenAPI 规范的清单文件,其中包含一些插件特定的元数据。

在 chat.openai.com 上开始对话时,用户可以选择启用哪些第三方插件。已启用插件的文档将作为对话上下文的一部分显示给语言模型,使模型能够根据需要调用适当的插件 API 以满足用户意图。目前,插件旨在调用后端 API,但也在探索可以调用客户端 API 的插件。

ChatGPT 插件系统使语言模型在安全,受限的条件下能够与外部工具或服务进行交互。以解决大型语言模型目前面临的挑战(例如:跟上最新事件、访问最新信息以及提供基于证据的参考来增强模型的响应能力)。
插件还使用户能够评估模型输出的可信度并检查其准确性。然而,插件也存在潜在的风险,包括可能导致有害或意外行为。
ChatGPT 插件平台的开发包括几个安全措施和红队演练,以识别潜在的风险并制定安全设计的缓解措施。访问插件的部署正在逐步推出,并鼓励研究人员研究这个领域的安全风险和缓解措施。ChatGPT 插件系统具有广泛的社会影响,并可能产生重大的经济影响。

ChatGPT 插件文档(Alpha)

ChatGPT 插件文档[1],插件目前处于 alpha 阶段,需要申请加入候补名单才能获得访问权限。在 alpha 期间,OpenAI 会与用户和开发人员密切合作,对插件系统进行迭代,API 可能会发生重大变化。

插件简介

OpenAI 插件将 ChatGPT 与第三方应用程序连接起来。这些插件使 ChatGPT 能够与开发人员定义的 API 进行交互,增强 ChatGPT 的功能,使其能够执行各种操作。插件可以让 ChatGPT 做以下事情:

  • 检索实时信息;例如,体育比分、股票价格、最新新闻等。
  • 检索知识库信息;例如,公司文档、个人笔记等。
  • 代表用户执行操作;例如,预订航班、订购食物等。

插件开发者公开一个或多个 API 端点,伴随着一个标准化清单文件和一个 OpenAPI 规范。这些定义了插件的功能,允许 ChatGPT 消耗这些文件并调用开发者定义的 API。
AI 模型作为智能 API 调用者。给定 API 规范和使用 API 的自然语言描述,模型主动调用 API 执行操作。例如,如果用户问“在巴黎住几晚应该住哪里?”,模型可以选择调用酒店预订插件 API,接收 API 响应,并生成结合API数据和自然语言能力的用户可见答案。

插件开发流程

要构建一个插件,理解端到端流程非常重要。
创建一个清单文件并将其托管在 yourdomain.com/.well-known/ai-plugin.json:

  • 该文件包括有关插件的元数据(名称、标志等)、所需的身份验证详细信息(身份验证类型、OAuth URL等)以及要公开的端点的 OpenAPI 规范
    • 模型将看到 OpenAPI 描述字段,可以用于为不同字段提供自然语言描述。
    • 建议在开始时仅公开 1-2 个端点,最小化参数数量,以最小化文本长度。
    • 插件说明、API 请求和 API 响应都插入到与 ChatGPT 的对话中。这将占用模型的上下文限制。
  • 在 ChatGPT UI[2] 中注册插件
    • 从顶部下拉菜单中选择插件模型,然后选择“插件”、“插件商店”,最后选择“安装未经验证的插件”或“开发自己的插件”。
    • 如果需要身份验证,请提供 OAuth 2 client_id 和 client_secret 或 API 密钥。
  • 用户激活插件
    • 用户必须在 ChatGPT UI 中手动激活插件(ChatGPT 不会默认使用您的插件)。
    • 在 alpha 版期间,插件开发人员将能够与 15 个其他用户共享其插件(当前只有其他开发人员可以安装未经验证的插件)。随着时间的推移,OpenAI 将推出一种方式,可以提交你的插件进行审核,以向 ChatGPT 的所有用户公开。
    • 如果需要身份验证,则用户将通过 OAuth 被重定向到您的插件。您还可以选择在此处创建新帐户。
    • 将来,OpenAI 希望构建功能,帮助用户发现有用和流行的插件。
  • 用户开始对话
    • OpenAI 将向 ChatGPT 中注入您的插件的紧凑描述,对终端用户不可见。这将包括插件描述、端点和示例。
    • 当用户提出相关问题时,如果似乎相关,模型可能选择从你的插件调用 API。对于 POST 请求,我们要求开发人员构建用户确认流程。
    • 模型会将 API 结果合并到其对用户的响应中。
    • 模型可能会在其响应中包括从API调用返回的链接。这将显示为丰富的预览(使用 OpenGraph 协议[3],在其中我们提取 site_name、title、description、image 和 url 字段)。

目前,OpenAI 将在 Plugin 对话头中发送用户的国家和州信息(例如:如果你在加利福尼亚州,它会显示为 {“openai-subdivision-1-iso-code”: “US-CA”})。对于更多的数据源,用户需要通过同意屏幕进行选择。这对于购物、餐厅、天气等非常有用。可以在 OpenAI 开发者使用条款[4]中了解更多信息。

插件开发

注意:此教程是根据官网文档总结而来,具体细节可能存在变化。
我们将使用 OpenAI 的插件系统创建一个简单的待办事项列表(to-do list)插件。它使用 Python 开发,并部署在 Replit 上。插件将使用服务级别(认证有 4 种方式:无认证,服务级,用户级和 OAuth,具体可查文档 Plugin authentication[5])的身份验证令牌进行身份验证,并允许用户创建、查看和删除待办事项。我们还需要定义一个 OpenAPI 规范以匹配我们插件中定义的端点。要完成本教程,你需要以下知识储备:

  • 对 Python[6] 有基本的了解
  • Replit 账户(在 replit.com[7] 免费注册),非必需,你可以自行部署服务器
  • OpenAI API 密钥(在 openai.com[8] 免费注册,API 收费)
  • 文本编辑器(VSCode[9], Sublime Text[10] 等)或 Replit IDE

    开发步骤

    Step1

    在项目中创建一个名为 manifest.json 的插件清单,并添加以下代码:

    1. {
    2. "schema_version": "v1",
    3. "name_for_human": "TODO Plugin (service http)",
    4. "name_for_model": "todo",
    5. "description_for_human": "Plugin for managing a TODO list, you can add, remove and view your TODOs.",
    6. "description_for_model": "Plugin for managing a TODO list, you can add, remove and view your TODOs.",
    7. "auth": {
    8. "type": "service_http",
    9. "authorization_type": "bearer",
    10. "verification_tokens": {
    11. "openai": "<YOUR_OPENAI_KEY>"
    12. }
    13. },
    14. "api": {
    15. "type": "openapi",
    16. "url": "https://<YOUR_REPO>.<YOUR_OWNER>.repl.co/openapi.yaml",
    17. "is_user_authenticated": false
    18. },
    19. "logo_url": "https://<YOUR_REPO>.<YOUR_OWNER>.repl.co/logo.png",
    20. "contact_email": "<YOUR_EMAIL>",
    21. "legal_info_url": "http://www.example.com/legal"
    22. }
  • : API 令牌

  • : Replit 应用名称
  • : Replit 用户名
  • : 邮箱地址

    Step2

    创建 main.py 文件,实现插件逻辑 ``` import os import quart import quart_cors from quart import Quart, jsonify, request

PORT = 5002 TODOS = {}

从环境变量中获取 auth key

SERVICE_AUTH_KEY = os.environ.get(“SERVICE_AUTH_KEY”)

创建 app,并启用 CORS,allow_origin=”*” 为允许从任何来源使用应用程序,不推荐此写法

app = quartcors.cors(Quart(_name), allow_origin=”*”)

app = quartcors.cors( Quart(_name), allow_origin=[ f”http://localhost:{PORT}“, “https://chat.openai.com“, ] )

添加一个 before_request 钩子来检查授权标头

@app.before_request def assert_auth_header(): auth_header = request.headers.get(“Authorization”) print(auth_header)

检查 auth 是否丢失或不正确,并在需要时返回错误

if not auth_header or auth_header != f”Bearer {SERVICE_AUTH_KEY}”: return jsonify({“error”: “Unauthorized”}), 401

路由:获取所有用户 TODO 列表

@app.route(“/todos”, methods=[“GET”]) async def get_todos(): return jsonify(TODOS)

路由:获取特定用户的 TODO 列表

@app.route(“/todos/“, methods=[“GET”]) async def get_todo_user(username): todos = TODOS.get(username, []) return jsonify(todos)

路由:特定用户添加 TODO 项

@app.route(“/todos/“, methods=[“POST”]) async def add_todo(username): request_data = await request.get_json() todo = request_data.get(“todo”, “”) TODOS.setdefault(username, []).append(todo) return jsonify({“status”: “success”})

路由:特定用户删除 TODO 项

@app.route(“/todos/“, methods=[“DELETE”]) async def delete_todo(username): request_data = await request.get_json() todo_idx = request_data.get(“todo_idx”, -1) if 0 <= todo_idx < len(TODOS.get(username, [])): TODOS[username].pop(todo_idx) return jsonify({“status”: “success”})

路由:获取 logo

@app.get(“/logo.png”) async def plugin_logo(): filename = ‘logo.png’ return await quart.send_file(filename, mimetype=’image/png’)

路由:插件清单,当通过 ChatGPT UI 安装插件时,ChatGPT 会在后端查找位于 /.well-known/ai-plugin.json。

如果找不到文件,则无法安装插件。

@app.get(“/.well-known/ai-plugin.json”) async def plugin_manifest(): host = request.headers[‘Host’] with open(“manifest.json”) as f: text = f.read() text = text.replace(“PLUGIN_HOSTNAME”, f”https://{host}“) return quart.Response(text, mimetype=”text/json”)

路由:OpenAPI 规范,帮助 ChatGPT 大模型了解你的 API

@app.get(“/openapi.yaml”) async def openapi_spec(): host = request.headers[‘Host’] with open(“openapi.yaml”) as f: text = f.read() text = text.replace(“PLUGIN_HOSTNAME”, f”https://{host}“) return quart.Response(text, mimetype=”text/yaml”)

def main(): app.run(debug=True, host=”0.0.0.0”, port=5002)

if name == “main“: main() ```

部署 Replit

上述代码比较啰嗦,如果你想快速部署,可以尝试以下步骤,直接从 lencx/chat-todo-plugin[11] 仓库导入代码到 Replit,即可以运行体验(manifest.json 中的变量需要替换为自己的)。

  • 打开 Replit,点击 Create Repl 按钮
  • 出现弹窗后,点击右上角的 Import from GitHub 按钮
  • 在 GitHub URL 中输入 https://github.com/lencx/chat-todo-plugin,Language 选择 Python
  • 然后点击右下角的 Import from GitHub 按钮,等待初始化完成
  • 点击 Run 按钮,等待运行完成

服务器运行后,就可以通过使用 ChatGPT 向插件端点发送请求来对其进行测试。如果你顺利走到这一步,那么恭喜你,你已经掌握了 ChatGPT 插件开发!
浮之静
,赞4
注意:因为我还未获得开发权限,后续测试可能还会遇到别的问题,所以此系列未完待续…,可以关注 lencx/chat-todo-plugin 项目获取最新动态。

References

ChatGPT 插件文档: https://platform.openai.com/docs/plugins/introduction
ChatGPT UI: https://chat.openai.com/chat
OpenGraph 协议: https://ogp.me/
OpenAI 开发者使用条款: https://openai.com/policies/plugin-terms
Plugin authentication: https://platform.openai.com/docs/plugins/authentication/plugin-authentication
Python: https://www.python.org
replit.com: https://replit.com
openai.com: https://openai.com
VSCode: https://code.visualstudio.com
Sublime Text: https://www.sublimetext.com
lencx/chat-todo-plugin: https://github.com/lencx/chat-todo-plugin
等待名单申请入口: https://openai.com/waitlist/plugins
Expedia: https://www.expedia.com
FiscalNote: https://fiscalnote.com
Instacart: https://www.instacart.com
KAYAK: https://www.kayak.com
Klarna: https://www.klarna.com
Milo: https://www.joinmilo.com
OpenTable: https://www.opentable.com
Shopify: https://www.shopify.com
Slack: https://slack.com
Speak: https://www.speak.com
Wolfram: http://wolfram.com
Zapier: https://zapier.com
WebGPT: https://openai.com/research/webgpt
GopherCite: https://arxiv.org/abs/2203.11147
BlenderBot2: https://parl.ai/projects/blenderbot2/
LaMDA2: https://ai.googleblog.com/2022/01/lamda-towards-safe-grounded-and-high.html
其他工作: https://arxiv.org/pdf/2209.14375.pdf
ChatGPT-User: https://platform.openai.com/docs/plugins/bot
IP 出口范围: https://platform.openai.com/docs/plugins/production/ip-egress-ranges
ChatGPT Retrieval Plugin: https://github.com/openai/chatgpt-retrieval-plugin
Milvus: https://milvus.io
Pinecone: https://www.pinecone.io
Qdrant: https://qdrant.tech
Redis: https://redis.io/docs/stack/search/reference/vectors
Weaviate: https://weaviate.io
Zilliz: https://zilliz.com
manifest.json: https://platform.openai.com/docs/plugins/getting-started