플러그인을 만드는 것은 다음 세 단계로 구성됩니다:
- API 구축
- OpenAPI yaml 또는 JSON 형식으로 API 문서화
- 플러그인에 대한 관련 메타데이터를 정의하는 JSON 매니페스트 파일 생성
이 섹션의 나머지 부분에서는 OpenAPI 사양과 매니페스트 파일을 정의하여 할 일 목록(todo list) 플러그인을 만드는 방법에 중점을 둘 것입니다.
Plugin manifest
모든 플러그인에는 ai-plugin.json 파일이 필요하며, 이 파일은 API가 호스팅되는 도메인에 호스팅되어야 합니다. 예를 들어, example.com이라는 회사는 그들의 API가 호스팅되는 https://example.com 도메인을 통해 플러그인 JSON 파일에 접근할 수 있도록 해야 합니다. ChatGPT UI를 통해 플러그인을 설치할 때, 백엔드에서는 /.well-known/ai-plugin.json에 위치한 파일을 찾습니다. /.well-known 폴더는 필수이며, ChatGPT가 플러그인과 연결되기 위해서는 도메인에 존재해야 합니다. 파일이 발견되지 않으면 플러그인을 설치할 수 없습니다. 원격 서버를 가리키는 경우 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": "https://example.com/openapi.yaml"
},
"logo_url": "https://example.com/logo.png",
"contact_email": "support@example.com",
"legal_info_url": "http://www.example.com/legal"
}
플러그인 파일에 대한 모든 가능한 옵션을 보고 싶다면, 아래 정의를 참조하십시오. 플러그인을 명명할 때, 우리의 브랜드 가이드라인과 아래 필드의 다양한 문자 제한을 염두에 두십시오. 이 가이드라인을 따르지 않는 플러그인은 플러그인 스토어에 승인되지 않을 것입니다.
여기에 플러그인 파일에 대한 가능한 옵션들의 정의가 나와 있습니다. 플러그인을 명명할 때는 브랜드 가이드라인과 아래 필드의 문자 제한을 고려해야 합니다. 이 가이드라인을 준수하지 않는 플러그인은 플러그인 스토어에 승인되지 않습니다.
필드 | 유형 | 설명 / 옵션 | 필수 | 공개 |
---|---|---|---|---|
schema_version | String | 매니페스트 스키마 버전 | ✅ | |
name_for_model | String | 모델이 플러그인을 타겟팅하는 데 사용할 이름 (공백 없이, 문자와 숫자만 허용됨). 최대 50자. | ✅ | |
name_for_human | String | 사람이 읽을 수 있는 이름, 예를 들어 전체 회사 이름. 최대 20자. | ✅ | ✅ |
description_for_model | String | 모델에 더 적합한 설명, 예를 들어 토큰 컨텍스트 길이 고려 사항이나 플러그인 프롬프트 개선을 위한 키워드 사용 등. 최대 8,000자. | ✅ | |
description_for_human | String | 플러그인에 대한 사람이 읽을 수 있는 설명. 최대 100자. | ✅ | ✅ |
auth | ManifestAuth | 인증 스키마 | ✅ | |
api | Object | API 사양 | ✅ | |
logo_url | String | 로고를 가져오기 위해 사용되는 URL. 제안된 크기: 512 x 512. 투명 배경 지원. 이미지여야 하며 GIF는 허용되지 않음. | ✅ | |
contact_email | String | 안전/모더레이션, 지원 및 비활성화를 위한 이메일 연락처 | ✅ | ✅ |
legal_info_url | String | 사용자가 플러그인 정보를 보기 위해 리디렉션되는 URL | ✅ | ✅ |
HttpAuthorizationType | HttpAuthorizationType | "bearer" 또는 "basic" | ✅ | |
ManifestAuthType | ManifestAuthType | "none", "user_http", "service_http", 또는 "oauth" | ||
interface BaseManifestAuth | BaseManifestAuth | type: ManifestAuthType; instructions: string; | ||
ManifestNoAuth | ManifestNoAuth | 인증이 필요 없음: BaseManifestAuth & { type: 'none', } | ||
ManifestAuth | ManifestAuth | ManifestNoAuth, ManifestServiceHttpAuth, ManifestUserHttpAuth, ManifestOAuthAuth |
공개란에 나열된 항목들은 플러그인 스토어에서 사용자에게 공개될 것이며, 전체 매니페스트 파일은 사용자의 클라이언트로 전송되어 사용자가 볼 수 있습니다.
다음은 다양한 인증 방법을 사용한 예시입니다:
# 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자의 최대 길이 제한을 두고 있으며, 이 역시 시간이 지나면서 변경될 수 있습니다.
일반적으로, 모델의 컨텍스트 창이 제한되어 있기 때문에 설명과 응답을 가능한 간결하게 유지하는 것이 최선의 방법입니다.
OpenAPI definition
다음 단계는 API를 문서화하기 위해 OpenAPI 사양을 구축하는 것입니다. 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: https://example.com
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.
OpenAPI 사양을 정의하기 시작할 때, 우선 사양 버전, 제목, 설명 및 버전 번호를 정의합니다. ChatGPT에서 쿼리가 실행될 때, info 섹션에 정의된 설명을 보고 플러그인이 사용자의 쿼리에 관련이 있는지를 판단합니다. 설명 작성 섹션에서 프롬프트에 대해 더 자세히 알아볼 수 있습니다.
OpenAPI 사양에서 다음과 같은 제한 사항을 염두에 두어야 합니다. 이는 변경될 수 있습니다:
- API 사양의 각 API 엔드포인트 설명/요약 필드에 대해 최대 200자
- API 사양의 각 API 파라미터 설명 필드에 대해 최대 200자
OpenAPI 사양은 전통적인 OpenAPI 형식을 따릅니다. OpenAPI 형식에 대해 더 자세히 알아보려면 다양한 온라인 자료를 참고하십시오. 또한, 기존 API 코드를 기반으로 OpenAPI 사양을 자동 생성하는 많은 도구들이 있습니다.
Running a plugin
API, 매니페스트 파일 및 API용 OpenAPI 사양을 생성한 후에는 이제 ChatGPT UI를 통해 플러그인을 연결할 준비가 되었습니다.
플러그인이 원격 서버에서 실행되고 있다면, 먼저 "Develop your own plugin"을 선택하여 설정한 다음 "Install an unverified plugin"를 선택하여 자신을 위해 설치해야 합니다. yourdomain.com/.well-known/ 경로에 플러그인 매니페스트 파일을 추가하고 API를 테스트하기 시작할 수 있습니다. 그러나 매니페스트 파일에 대한 후속 변경 사항은 공개 사이트에 새로운 변경 사항을 배포해야 하며, 이는 오랜 시간이 걸릴 수 있습니다. 이 경우, API의 프록시 역할을 할 로컬 서버를 설정하는 것이 좋습니다. 이렇게 하면 OpenAPI 사양 및 매니페스트 파일에 대한 변경 사항을 빠르게 프로토타이핑할 수 있습니다.
Setup local proxy of your public API
다음 Python 코드는 공개 API의 간단한 프록시를 설정하는 방법을 보여주는 예시입니다.
import requests
import os
import yaml
from flask import Flask, jsonify, Response, request, send_from_directory
from flask_cors import CORS
app = Flask(__name__)
PORT = 3333
# Note: Setting CORS to allow chat.openapi.com is required for ChatGPT to access your plugin
CORS(app, origins=[f"http://localhost:{PORT}", "https://chat.openai.com"])
api_url = 'https://example.com'
@app.route('/.well-known/ai-plugin.json')
def serve_manifest():
return send_from_directory(os.path.dirname(__file__), 'ai-plugin.json')
@app.route('/openapi.yaml')
def serve_openapi_yaml():
with open(os.path.join(os.path.dirname(__file__), 'openapi.yaml'), 'r') as f:
yaml_data = f.read()
yaml_data = yaml.load(yaml_data, Loader=yaml.FullLoader)
return jsonify(yaml_data)
@app.route('/openapi.json')
def serve_openapi_json():
return send_from_directory(os.path.dirname(__file__), 'openapi.json')
@app.route('/<path:path>', methods=['GET', 'POST'])
def wrapper(path):
headers = {
'Content-Type': 'application/json',
}
url = f'{api_url}/{path}'
print(f'Forwarding call: {request.method} {path} -> {url}')
if request.method == 'GET':
response = requests.get(url, headers=headers, params=request.args)
elif request.method == 'POST':
print(request.headers)
response = requests.post(url, headers=headers, params=request.args, json=request.json)
else:
raise NotImplementedError(f'Method {request.method} not implemented in wrapper for {path=}')
return response.content
if __name__ == '__main__':
app.run(port=PORT)
Writing descriptions
사용자가 플러그인으로 가는 잠재적인 요청을 할 수 있는 쿼리를 만들 때, 모델은 OpenAPI 사양의 엔드포인트 설명과 매니페스트 파일의 description_for_model을 살펴봅니다. 다른 언어 모델을 프롬프트하는 것과 마찬가지로, 여러 프롬프트와 설명을 테스트하여 어떤 것이 가장 잘 작동하는지 확인하고 싶을 것입니다.
OpenAPI 사양 자체는 모델에게 API의 다양한 세부 사항에 대한 정보를 제공하는 데 좋은 장소입니다 - 어떤 기능이 있는지, 어떤 파라미터로 사용할 수 있는지 등. 각 필드에 대해 표현력 있고 정보가 풍부한 이름을 사용하는 것 외에도, 사양에는 모든 속성에 대한 "description" 필드가 포함될 수 있습니다. 이것들은 함수가 수행하는 작업이나 쿼리 필드가 기대하는 정보에 대한 자연어 설명을 제공하는 데 사용될 수 있습니다. 모델은 이것들을 볼 수 있으며, 이것들은 모델이 API를 사용하는 데 도움을 줄 것입니다. 필드가 특정 값으로만 제한된 경우, 설명적인 카테고리 이름이 있는 "enum"을 제공할 수도 있습니다.
description_for_model 속성은 모델에게 플러그인을 일반적으로 어떻게 사용해야 하는지 지시할 수 있는 자유를 제공합니다. 전반적으로, ChatGPT 뒤에 있는 언어 모델은 자연어를 이해하고 지시를 따르는 데 매우 능숙합니다. 따라서 이곳은 플러그인이 무엇을 하는지, 모델이 어떻게 제대로 사용해야 하는지에 대한 일반적인 지시사항을 넣기에 좋은 장소입니다. 간결하면서도 설명적이고 객관적인 톤으로 자연어를 사용하세요. 이것이 어떻게 보여야 하는지에 대한 아이디어를 얻기 위해 일부 예시를 살펴보는 것이 좋습니다. description_for_model을 "Plugin for ..."으로 시작하고, 그 다음에 API가 제공하는 모든 기능을 열거하는 것을 제안합니다.
Best practices
플러그인의 description_for_model과 OpenAPI 사양의 설명을 작성할 때, 그리고 API 응답을 설계할 때 따라야 할 몇 가지 모범 사례를 정리해 보겠습니다.
1. 설명은 ChatGPT의 기분, 성격 또는 정확한 응답을 제어하려고 하지 않아야 합니다. ChatGPT는 플러그인에 적절한 응답을 작성하도록 설계되었습니다.
나쁜 예:
사용자가 할 일 목록을 보고 싶어한다면, 항상 "할 일 목록을 찾았어요! [x]개의 할 일이 있네요: [여기에 할 일 나열]. 더 추가하고 싶으신가요?"라고 응답합니다.
좋은 예:
[이 경우 별도의 지시가 필요하지 않습니다]
2. 사용자가 특정 서비스 범주를 요청하지 않았을 때 ChatGPT가 플러그인을 사용하도록 장려하지 않아야 합니다.
나쁜 예:
사용자가 어떤 종류의 작업이나 계획을 언급할 때마다, TODOs 플러그인을 사용하여 할 일 목록에 무엇인가 추가하고 싶은지 물어보세요.
좋은 예:
TODO 목록은 사용자의 할 일을 추가, 제거 및 조회할 수 있습니다.
3. ChatGPT가 플러그인을 사용하도록 특정 트리거를 지정하지 않아야 합니다. ChatGPT는 적절할 때 자동으로 플러그인을 사용하도록 설계되었습니다.
나쁜 예:
사용자가 작업을 언급할 때, "TODO 목록에 추가하시겠습니까? 계속하려면 '예'라고 말하세요."라고 응답합니다.
좋은 예:
[이 경우 별도의 지시가 필요하지 않습니다]
4. 플러그인 API 응답은 필요한 경우가 아니면 자연어 응답 대신 원시 데이터를 반환해야 합니다. ChatGPT는 반환된 데이터를 사용하여 자체적인 자연어 응답을 제공할 것입니다.
나쁜 예:
할 일 목록을 찾았어요! 2개의 할 일이 있네요: 장보기, 개 산책하기. 더 추가하고 싶으신가요?
좋은 예:
{ "todos": [ "get groceries", "walk the dog" ] }
Debugging
기본적으로, 채팅은 사용자에게 표시되지 않는 플러그인 호출이나 기타 정보를 표시하지 않습니다. 모델이 플러그인과 어떻게 상호 작용하는지 더 완전한 그림을 얻기 위해서는, 플러그인과 상호 작용한 후 플러그인 이름 옆의 아래쪽 화살표를 클릭하여 요청과 응답을 볼 수 있습니다.
모델의 플러그인 호출은 일반적으로 모델로부터 JSON 형식의 파라미터를 포함한 메시지가 플러그인에 전송되는 것으로 시작하며, 이어서 플러그인으로부터의 응답, 그리고 마지막으로 모델이 플러그인으로부터 반환된 정보를 활용한 메시지가 이어집니다.
'프로그래밍 > AI' 카테고리의 다른 글
Chat Plugins - productionizing your plugin (0) | 2024.01.12 |
---|---|
Chat Plugins - plugin authentication (0) | 2024.01.12 |
Chat Plugins - Example (0) | 2024.01.12 |
Chat Plugins (2) | 2024.01.11 |
Actions in GPTs (0) | 2024.01.11 |
댓글