1.概述
ChatGPT是一款由OpenAI推出的先進對話模型,其強大的自然語言處理能力使得它成爲構建智能對話系統和人機交互應用的理想選擇。爲了進一步拓展ChatGPT的功能和適應不同領域的需求,OpenAI提供了插件開發平臺,讓開發者可以定製化和擴展ChatGPT的能力。
2.內容
OpenAI 插件將 ChatGPT 連接到第三方應用程序。這些插件使 ChatGPT 能夠與開發人員定義的 API 進行交互,從而增強 ChatGPT 的功能並允許其執行廣泛的操作。插件使 ChatGPT 能夠執行以下操作:
- 檢索實時信息;例如,體育賽事比分、股票價格、最新新聞等。
- 檢索知識庫信息;例如,公司文檔、個人筆記等。
- 協助用戶採取行動;例如,預訂航班、訂餐等。
插件開發人員公開一個或多個 API 端點,並附有標準化清單文件和 OpenAPI 規範。這些定義了插件的功能,允許 ChatGPT 使用文件並調用開發人員定義的 API。
AI 模型充當智能 API 調用者。給定 API 規範和何時使用 API 的自然語言描述,模型會主動調用 API 來執行操作。例如,如果用戶詢問“我應該在巴黎哪裏住幾晚?”,模型可能會選擇調用酒店預訂插件 API,接收 API 響應,並結合 API 數據生成面向用戶的答案及其自然語言能力。
2.1 插件流程
要構建插件,瞭解端到端流程是非常有必要的,流程如下所示:
- 創建清單文件並將其託管在yourdomain.com/.well-known/ai-plugin.json
- 該文件包含有關您的插件的元數據(名稱、徽標等)、有關所需身份驗證的詳細信息(身份驗證類型、OAuth URL 等)以及您想要公開的端點的 OpenAPI 規範。
- 該模型將看到 OpenAPI 描述字段,這些字段可用於爲不同字段提供自然語言描述。
- 建議在開始時僅公開 1-2 個端點,並使用最少數量的參數,以最大程度地縮短文本長度。插件描述、API 請求和 API 響應都插入到與 ChatGPT 的對話中。這不利於模型的上下文限制。
- 在ChatGPT頁面後臺系統中註冊插件
- 從頂部下拉列表中選擇插件模型,然後選擇“插件”、“插件商店”,最後選擇“開發自己的插件”。
- 如果需要身份驗證,請提供 OAuth 2client_id和client_secret/或 API 密鑰。
- 激活插件
- 必須自己手動激活插件
-
如果需要 OAuth,用戶將通過 OAuth 重定向到您的插件進行登錄。
- 能夠與另外 100 個用戶共享自己的插件
- 開始對話
- OpenAI 將在發送給 ChatGPT 的消息中注入插件的簡潔描述,最終用戶看不到。這將包括插件描述、端點和示例。
- 當用戶提出相關問題時,如果看起來相關,模型可能會選擇從您的插件調用 API 調用;對於POST請求,我們要求開發者構建用戶確認流程以避免破壞行爲。
- 該模型會將 API 調用結果合併到對用戶的響應中。
- 該模型可能會在其響應中包含從 API 調用返回的鏈接。
- 該模型還可以在 Markdown 中格式化來自 API 的數據,並且 ChatGPT UI 將自動呈現 Markdown。
2.2 快速使用
創建插件需要 3 個步驟:
- 構建 API
- 以 OpenAPI yaml 或 JSON 格式記錄 API
- 創建一個 JSON 清單文件,用於定義插件的相關元數據
每個插件都需要一個ai-plugin.json文件,該文件需要託管在API的域名上。例如,名爲example.com的公司將通過https://example.com域名使插件的JSON文件可訪問,因爲這是他們API託管的位置。當通過ChatGPT UI安裝插件時,在後端我們會查找位於/.well-known/ai-plugin.json的文件。/.well-known文件夾是必需的,並且必須存在於自己的域名上,以便ChatGPT可以與自己的插件連接。如果找不到文件,則無法安裝插件。對於本地開發,可以使用HTTP,但如果指向遠程服務器,則需要使用HTTPS。
所需ai-plugin.json文件的最小定義如下所示:
{ "schema_version": "v1", "name_for_human": "TODO List", "name_for_model": "todo", "description_for_human": "Manage your TODO list. You can add, remove and view your TODOs.", "description_for_model": "Help the user with managing a TODO list. You can add, remove and view your TODOs.", "auth": { "type": "none" }, "api": { "type": "openapi", "url": "http://localhost:3333/openapi.yaml" }, "logo_url": "http://localhost:3333/logo.png", "contact_email": "[email protected]", "legal_info_url": "http://www.example.com/legal" }
請注意,列在“公共”下的項目將在插件商店對用戶可用。
以下是具有不同身份驗證方法的示例:
# App-level API keys type ManifestServiceHttpAuth = BaseManifestAuth & { type: 'service_http'; authorization_type: HttpAuthorizationType; verification_tokens: { [service: string]?: string; }; } # User-level HTTP authentication type ManifestUserHttpAuth = BaseManifestAuth & { type: 'user_http'; authorization_type: HttpAuthorizationType; } type ManifestOAuthAuth = BaseManifestAuth & { type: 'oauth'; # OAuth URL where a user is directed to for the OAuth authentication flow to begin. client_url: string; # OAuth scopes required to accomplish operations on the user's behalf. scope: string; # Endpoint used to exchange OAuth code with access token. authorization_url: string; # When exchanging OAuth code with access token, the expected header 'content-type'. For example: 'content-type: application/json' authorization_content_type: string; # When registering the OAuth client ID and secrets, the plugin service will surface a unique token. verification_tokens: { [service: string]?: string; }; }
上述提到的清單文件中某些字段的長度存在限制,這些限制可能會發生變化。還對API響應體強加了最大長度限制,目前爲100,000個字符,但這也可能隨着時間變化而調整。
總體而言,最佳實踐是儘可能簡潔地描述和響應,因爲模型有有限的上下文窗口。
2.3 OpenAPI定義
接下來的步驟是構建OpenAPI規範以文檔化API。ChatGPT中的模型除了OpenAPI規範和清單文件中定義的內容外,對你的API一無所知。這意味着,如果你有一個龐大的API,你不需要將所有功能暴露給模型,而是可以選擇特定的端點。例如,如果你有一個社交媒體API,你可能希望讓模型通過GET請求訪問網站內容,但防止模型能夠對用戶的帖子進行評論,以降低垃圾信息的可能性。
OpenAPI規範是包裹在您的API之上的包裝器。一個基本的OpenAPI規範如下所示:
openapi: 3.0.1 info: title: TODO Plugin description: A plugin that allows the user to create and manage a TODO list using ChatGPT. version: 'v1' servers: - url: http://localhost:3333 paths: /todos: get: operationId: getTodos summary: Get the list of todos responses: "200": description: OK content: application/json: schema: $ref: '#/components/schemas/getTodosResponse' components: schemas: getTodosResponse: type: object properties: todos: type: array items: type: string description: The list of todos.
首先定義規範版本、標題、描述和版本號。當在ChatGPT中運行查詢時,它會查看信息部分中定義的描述,以確定插件是否與用戶查詢相關。
OpenAPI規範中的限制:
- API規範中每個API端點描述/摘要字段的最大長度爲200個字符
- API規範中每個API參數描述字段的最大長度爲200個字符
2.4 運行插件
一旦爲API、清單文件和API的OpenAPI規範創建完成,現在可以通過ChatGPT UI連接插件了。我們創建的插件可能運行在兩個不同的地方,要麼是在開發環境的本地,要麼是在遠程服務器上。
如果在本地運行API的版本,可以將插件界面指向自己的本地主機服務器。要將插件與ChatGPT連接,請導航到插件商店,然後選擇“開發自己的插件”。輸入自己的本地主機和端口號(例如localhost:3333)。請注意,目前僅支持本地開發的auth類型爲none。
如果插件在遠程服務器上運行,則需要首先選擇“開發自己的插件”進行設置,然後再選擇“安裝未驗證的插件”將其安裝到您的環境中。只需將插件的清單文件添加到yourdomain.com/.well-known/路徑中,然後開始測試自己的API。但是,請注意,對於清單文件的後續更改,您需要將新更改部署到公共站點上,這可能需要較長的時間。在這種情況下,我們建議設置一個本地服務器作爲自己的API的代理,這樣可以快速原型化OpenAPI規範和清單文件的更改。
3.示例插件
爲了開始構建,官方提供了一組涵蓋不同身份驗證模式和用例的簡單插件。從簡單的無身份驗證待辦事項列表插件到更強大的檢索插件,這些示例讓我們瞭解了希望通過插件實現的目標。
在開發過程中,可以在計算機上本地運行該插件,也可以通過GitHub Codespaces、Replit或CodeSandbox等雲開發環境運行該插件。
3.1 瞭解如何構建一個無需身份驗證的簡單待辦事項列表插件
首先,查看無身份驗證頁面,然後定義一個ai-plugin.json包含以下字段的文件
{ "schema_version": "v1", "name_for_human": "TODO List (No Auth)", "name_for_model": "todo", "description_for_human": "Manage your TODO list. You can add, remove and view your TODOs.", "description_for_model": "Plugin for managing a TODO list, you can add, remove and view your TODOs.", "auth": { "type": "none" }, "api": { "type": "openapi", "url": "PLUGIN_HOSTNAME/openapi.yaml" }, "logo_url": "PLUGIN_HOSTNAME/logo.png", "contact_email": "[email protected]", "legal_info_url": "https://example.com/legal" }
請注意,PLUGIN_HOSTNAME應該是插件服務器的實際主機名。
接下來,我們可以定義 API 端點來爲特定用戶創建、刪除和獲取待辦事項列表項。
import json import quart import quart_cors from quart import request # Note: Setting CORS to allow chat.openapi.com is only required when running a localhost plugin app = quart_cors.cors(quart.Quart(__name__), allow_origin="https://chat.openai.com") _TODOS = {} @app.post("/todos/<string:username>") async def add_todo(username): request = await quart.request.get_json(force=True) if username not in _TODOS: _TODOS[username] = [] _TODOS[username].append(request["todo"]) return quart.Response(response='OK', status=200) @app.get("/todos/<string:username>") async def get_todos(username): return quart.Response(response=json.dumps(_TODOS.get(username, [])), status=200) @app.delete("/todos/<string:username>") async def delete_todo(username): request = await quart.request.get_json(force=True) todo_idx = request["todo_idx"] if 0 <= todo_idx < len(_TODOS[username]): _TODOS[username].pop(todo_idx) return quart.Response(response='OK', status=200) @app.get("/logo.png") async def plugin_logo(): filename = 'logo.png' return await quart.send_file(filename, mimetype='image/png') @app.get("/.well-known/ai-plugin.json") async def plugin_manifest(): host = request.headers['Host'] with open("ai-plugin.json") as f: text = f.read() # This is a trick we do to populate the PLUGIN_HOSTNAME constant in the manifest text = text.replace("PLUGIN_HOSTNAME", f"https://{host}") return quart.Response(text, mimetype="text/json") @app.get("/openapi.yaml") async def openapi_spec(): host = request.headers['Host'] with open("openapi.yaml") as f: text = f.read() # This is a trick we do to populate the PLUGIN_HOSTNAME constant in the OpenAPI spec 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()
最後,我們需要設置和定義 OpenAPI 規範以匹配本地或遠程服務器上定義的端點。無需通過規範公開 API 的全部功能,而是可以選擇讓 ChatGPT 僅訪問某些功能。
還有許多工具可以自動將您的服務器定義代碼轉換爲 OpenAPI 規範,因此無需手動執行此操作。對於上面的 Python 代碼,OpenAPI 規範將如下所示:
openapi: 3.0.1 info: title: TODO Plugin description: A plugin that allows the user to create and manage a TODO list using ChatGPT. If you do not know the user's username, ask them first before making queries to the plugin. Otherwise, use the username "global". version: "v1" servers: - url: PLUGIN_HOSTNAME paths: /todos/{username}: get: operationId: getTodos summary: Get the list of todos parameters: - in: path name: username schema: type: string required: true description: The name of the user. responses: "200": description: OK content: application/json: schema: $ref: "#/components/schemas/getTodosResponse" post: operationId: addTodo summary: Add a todo to the list parameters: - in: path name: username schema: type: string required: true description: The name of the user. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/addTodoRequest" responses: "200": description: OK delete: operationId: deleteTodo summary: Delete a todo from the list parameters: - in: path name: username schema: type: string required: true description: The name of the user. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/deleteTodoRequest" responses: "200": description: OK components: schemas: getTodosResponse: type: object properties: todos: type: array items: type: string description: The list of todos. addTodoRequest: type: object required: - todo properties: todo: type: string description: The todo to add to the list. required: true deleteTodoRequest: type: object required: - todo_idx properties: todo_idx: type: integer description: The index of the todo to delete. required: true
3.2 瞭解如何構建具有服務級別身份驗證的簡單待辦事項列表插件
首先,查看服務級別身份驗證頁面,然後定義一個ai-plugin.json包含以下字段的文件:
{ "schema_version": "v1", "name_for_human": "TODO List (service auth)", "name_for_model": "todo", "description_for_human": "Manage your TODO list. You can add, remove and view your TODOs.", "description_for_model": "Plugin for managing a TODO list, you can add, remove and view your TODOs.", "auth": { "type": "service_http", "authorization_type": "bearer", "verification_tokens": { "openai": "Replace_this_string_with_the_verification_token_generated_in_the_ChatGPT_UI" } }, "api": { "type": "openapi", "url": "https://example.com/openapi.yaml" }, "logo_url": "https://example.com/logo.png", "contact_email": "[email protected]", "legal_info_url": "https://example.com/legal" }
請注意,服務級別身份驗證插件需要驗證令牌。設置服務訪問令牌後,該令牌是在 ChatGPT Web UI 中的插件安裝過程中生成的。
還需要將“Example.com”更新爲遠程服務器的名稱。
接下來,我們可以定義 API 端點來爲特定用戶創建、刪除和獲取待辦事項列表項。端點還檢查用戶是否經過身份驗證。
import json import quart import quart_cors from quart import request app = quart_cors.cors(quart.Quart(__name__)) # This key can be anything, though you will likely want a randomly generated sequence. _SERVICE_AUTH_KEY = "REPLACE_ME" _TODOS = {} def assert_auth_header(req): assert req.headers.get( "Authorization", None) == f"Bearer {_SERVICE_AUTH_KEY}" @app.post("/todos/<string:username>") async def add_todo(username): assert_auth_header(quart.request) request = await quart.request.get_json(force=True) if username not in _TODOS: _TODOS[username] = [] _TODOS[username].append(request["todo"]) return quart.Response(response='OK', status=200) @app.get("/todos/<string:username>") async def get_todos(username): assert_auth_header(quart.request) return quart.Response(response=json.dumps(_TODOS.get(username, [])), status=200) @app.delete("/todos/<string:username>") async def delete_todo(username): assert_auth_header(quart.request) request = await quart.request.get_json(force=True) todo_idx = request["todo_idx"] if 0 <= todo_idx < len(_TODOS[username]): _TODOS[username].pop(todo_idx) return quart.Response(response='OK', status=200) @app.get("/logo.png") async def plugin_logo(): filename = 'logo.png' return await quart.send_file(filename, mimetype='image/png') @app.get("/.well-known/ai-plugin.json") async def plugin_manifest(): host = request.headers['Host'] with open("ai-plugin.json") as f: text = f.read() return quart.Response(text, mimetype="text/json") @app.get("/openapi.yaml") async def openapi_spec(): host = request.headers['Host'] with open("openapi.yaml") as f: text = f.read() return quart.Response(text, mimetype="text/yaml") def main(): app.run(debug=True, host="0.0.0.0", port=5002) if __name__ == "__main__": main()
最後,我們需要設置並定義 OpenAPI 規範以匹配遠程服務器上定義的端點。一般來說,無論身份驗證方法如何,OpenAPI 規範看起來都是一樣的。使用自動 OpenAPI 生成器將減少創建 OpenAPI 規範時出錯的可能性。
openapi: 3.0.1 info: title: TODO Plugin description: A plugin that allows the user to create and manage a TODO list using ChatGPT. If you do not know the user's username, ask them first before making queries to the plugin. Otherwise, use the username "global". version: "v1" servers: - url: https://example.com paths: /todos/{username}: get: operationId: getTodos summary: Get the list of todos parameters: - in: path name: username schema: type: string required: true description: The name of the user. responses: "200": description: OK content: application/json: schema: $ref: "#/components/schemas/getTodosResponse" post: operationId: addTodo summary: Add a todo to the list parameters: - in: path name: username schema: type: string required: true description: The name of the user. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/addTodoRequest" responses: "200": description: OK delete: operationId: deleteTodo summary: Delete a todo from the list parameters: - in: path name: username schema: type: string required: true description: The name of the user. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/deleteTodoRequest" responses: "200": description: OK components: schemas: getTodosResponse: type: object properties: todos: type: array items: type: string description: The list of todos. addTodoRequest: type: object required: - todo properties: todo: type: string description: The todo to add to the list. required: true deleteTodoRequest: type: object required: - todo_idx properties: todo_idx: type: integer description: The index of the todo to delete. required: true
4.總結
插件開發平臺爲開發者提供了一系列API和工具,使其可以自定義ChatGPT的輸入輸出、增加特定任務的支持以及集成外部數據和服務。開發者可以通過插件實現特定的領域知識、自定義回答模式、定製話題導向等功能,從而讓ChatGPT更貼合特定的使用場景和用戶需求。
在插件開發過程中,開發者可以藉助ChatGPT的先進預訓練模型,以及豐富的開發文檔和示例代碼來快速上手。插件支持多種編程語言,並與現有的ChatGPT API無縫集成,保證了開發的便捷性和靈活性。
值得注意的是,插件開發平臺也注重模型的安全性和可控性。OpenAI提供了強大的監管措施和審覈流程,確保插件的使用符合社區準則,並防止濫用或不當行爲。
總體而言,ChatGPT插件開發平臺爲開發者提供了一個廣闊的創作空間,讓他們可以將ChatGPT打造成更具個性和實用性的智能對話系統。通過這個平臺,開發者可以將ChatGPT的潛力發揮到極致,爲用戶提供更加智能、定製化的交互體驗。