实现了对插件的初步支持。插件是专门为语言模型设计的工具,可帮助 访问最新信息、运行计算或使用第三方服务。
插件是什么?插件可以成为语言模型的“眼睛和耳朵”,使它们能够访问最新、私人或太具体而无法包含在训练数据中的信息。
插件的诞生,对于每一个开发者,每一个公司,都是机遇和机会,因为我们公司的运营方式和程序开发方式将会迎来变革。
每一个开发者,每一个公司都可以通过 使用大型语言模型,来实现交互,提供最新信息。
官网提供了两个插件,一个网络浏览器和代码解释器,开源了知识库检索插件的代码,我们开发者也可以自定义插件。
如果我们想开发插件,文末有申请候补链接。
1.先来说说对公司的意义
我们这里举例最常见类型:
1.旅游网
通过插件,我们可以知道到达那里,留在那里,寻找可看可做的事情。
我们以前正常的旅途,是需要做大量准备的,比如我们去哪个酒店最便宜,最优惠,我们要去哪里玩,有没有推荐的,那里有什么风土人情,安不安全。需要带哪些东西,气温如何,有什么注意的等等。这些我们需要大量的搜索和询问,有了插件都解决了。
2.会计
提供并允许访问精选的市场领先的实时数据集,以获取法律、政治和监管数据和信息。
我们知道是大语言模型,训练数据都是过时的。可以有了插件就完全不一样了,他能够读取实时数据。
3.电商
可以实现即时购物车,从数以千计的网上商店搜索和比较价格,从各个品牌中搜索数百万种产品。
从最喜欢的当地店铺店买东西,是的,你没有看错,通过第三方插件,是可以实时购物的,和比较价格。
4.航班、住宿、租车
搜索航班、住宿和租车。获取在我们预算范围内可以去的所有地方的建议。
上面都是最常见公司的作用,其实每个公司,都能从第三方插件找到自己可以盈利的点。
2.对开发者的意义
对于开发者来说,传统开发都是使用平台提供的接口,包括没有提供插件以前,也是这种方式。提供插件后,就完全变了。不在是我们使用平台的接口,而是平台使用我们的接口。进入人工智能时代后,我们开发者将不得不借助人工智能平台,来让我们公司实现更智能、更人性的服务。
接着我们来看看官网提供的两个插件:
1.网络浏览器
允许语言模型从互联网上读取信息,获取最新鲜的数据。
这一插件,弥补了插件模型实时性的问题,比如问他今天几号,这个问题对于他来说就不是问题了。
比如,你能告诉我哪个人/电影赢得了这些类别的奥斯卡奖吗?
它提供的都是这两天的最新信息。
2.代码解释器
可以使用 处理上传和下载的实验性 模型
我们为模型提供了一个在 沙盒、防火墙执行环境中工作的 解释器,以及一些临时磁盘空间。由我们的解释器插件运行的代码在一个持久会话中进行评估,该会话在聊天对话期间一直有效(具有上限超时),后续调用可以相互构建。我们支持将文件上传到当前对话工作区并下载您的工作结果。
使用代码解释器特别有用的用例:
3.检索插件
开源检索插件使 能够访问个人或组织信息源(经许可)。它允许用户通过提问或用自然语言表达需求,从他们的数据源中获取最相关的文档片段,例如文件、笔记、电子邮件或公共文档。
作为一个开源和自托管的解决方案,开发人员可以部署他们自己的插件版本并在 上注册。该插件利用 嵌入并允许开发人员选择矢量数据库(、、、Redis、或)来索引和搜索文档。信息源可以使用 与数据库同步。
4.第三方插件开发
第三方插件由清单文件描述,其中包括插件功能的机器可读描述以及如何调用它们,以及面向用户的文档。
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. } 复制代码
用于管理待办事项的插件的示例清单文件
创建插件的步骤是:
3.聊天示例插件
有的开发者想开发聊天插件。我们举例如何构建一个无需授权的简单待办事项列表插件。
在开发过程中,可以在本地计算机或通过 、 或 等云开发环境运行插件。
1.如何构建一个无需授权的简单待办事项列表插件
1.首先,定义一个包含以下字段的 .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": "758e9ef7984b415688972d749f8aa58e" 12. } 13. }, 14. "api": { 15. "type": "openapi", 16. "url": "https://example.com/openapi.yaml", 17. "is_user_authenticated": false 18. }, 19. "logo_url": "https://example.com/logo.png", 20. "contact_email": "dummy@email.com", 21. "legal_info_url": "http://www.example.com/legal" 22. } 复制代码
请注意,服务级别身份验证插件需要验证令牌。该令牌是在 网络用户界面中的插件安装过程中生成的。
接下来,我们可以定义一些简单的 端点,为特定用户创建、删除和获取待办事项列表项。端点还对身份验证进行简单检查,因为这是必需的。
1. import json 2. 3. import quart 4. import quart_cors 5. from quart import request 6. 7. app = quart_cors.cors(quart.Quart(__name__), allow_origin="*") 8. 9. _SERVICE_AUTH_KEY = "TEST" 10. _TODOS = {} 11. 12. 13. def assert_auth_header(req): 14. assert req.headers.get( 15. "Authorization", None) == f"Bearer {_SERVICE_AUTH_KEY}" 16. 17. 18. @app.post("/todos/") 19. async def add_todo(username): 20. assert_auth_header(quart.request) 21. request = await quart.request.get_json(force=True) 22. if username not in _TODOS: 23. _TODOS[username] = [] 24. _TODOS[username].append(request["todo"]) 25. return quart.Response(response='OK', status=200) 26. 27. 28. @app.get("/todos/") 29. async def get_todos(username): 30. assert_auth_header(quart.request) 31. return quart.Response(response=json.dumps(_TODOS.get(username, [])), status=200) 32. 33. 34. @app.delete("/todos/") 35. async def delete_todo(username): 36. assert_auth_header(quart.request) 37. request = await quart.request.get_json(force=True) 38. todo_idx = request["todo_idx"] 39. # fail silently, it's a simple plugin 40. if 0 <= todo_idx < len(_TODOS[username]): 41. _TODOS[username].pop(todo_idx) 42. return quart.Response(response='OK', status=200) 43. 44. 45. @app.get("/logo.png") 46. async def plugin_logo(): 47. filename = 'logo.png' 48. return await quart.send_file(filename, mimetype='image/png') 49. 50. 51. @app.get("/.well-known/ai-plugin.json") 52. async def plugin_manifest(): 53. host = request.headers['Host'] 54. with open("manifest.json") as f: 55. text = f.read() 56. text = text.replace("PLUGIN_HOSTNAME", f"https://{host}") 57. return quart.Response(text, mimetype="text/json") 58. 59. 60. @app.get("/openapi.yaml") 61. async def openapi_spec(): 62. host = request.headers['Host'] 63. with open("openapi.yaml") as f: 64. text = f.read() 65. text = text.replace("PLUGIN_HOSTNAME", f"https://{host}") 66. return quart.Response(text, mimetype="text/yaml") 67. 68. 69. def main(): 70. app.run(debug=True, host="0.0.0.0", port=5002) 71. 72. 73. if __name__ == "__main__": 74. main() 复制代码
最后,我们需要设置和定义 规范以匹配本地或远程服务器上定义的端点。通常,无论身份验证方法如何, 规范看起来都是一样的。使用自动 生成器将减少创建 规范时出错的可能性,因此值得探索这些选项。
1. openapi: 3.0.1 2. info: 3. title: TODO Plugin 4. 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". 5. version: 'v1' 6. servers: 7. - url: https://example.com 8. paths: 9. /todos/{username}: 10. get: 11. operationId: getTodos 12. summary: Get the list of todos 13. parameters: 14. - in: path 15. name: username 16. schema: 17. type: string 18. required: true 19. description: The name of the user. 20. responses: 21. "200": 22. description: OK 23. content: 24. application/json: 25. schema: 26. $ref: '#/components/schemas/getTodosResponse' 27. post: 28. operationId: addTodo 29. summary: Add a todo to the list 30. parameters: 31. - in: path 32. name: username 33. schema: 34. type: string 35. required: true 36. description: The name of the user. 37. requestBody: 38. required: true 39. content: 40. application/json: 41. schema: 42. $ref: '#/components/schemas/addTodoRequest' 43. responses: 44. "200": 45. description: OK 46. delete: 47. operationId: deleteTodo 48. summary: Delete a todo from the list 49. parameters: 50. - in: path 51. name: username 52. schema: 53. type: string 54. required: true 55. description: The name of the user. 56. requestBody: 57. required: true 58. content: 59. application/json: 60. schema: 61. $ref: '#/components/schemas/deleteTodoRequest' 62. responses: 63. "200": 64. description: OK 65. 66. components: 67. schemas: 68. getTodosResponse: 69. type: object 70. properties: 71. todos: 72. type: array 73. items: 74. type: string 75. description: The list of todos. 76. addTodoRequest: 77. type: object 78. required: 79. - todo 80. properties: 81. todo: 82. type: string 83. description: The todo to add to the list. 84. required: true 85. deleteTodoRequest: 86. type: object 87. required: 88. - todo_idx 89. properties: 90. todo_idx: 91. type: integer 92. description: The index of the todo to delete. 93. required: true 复制代码