(번역) 자바스크립트로 첫 ChatGPT 플러그인 만들기

한정(Han Jung)
21 min readJun 4, 2023

--

원문: https://www.sitepoint.com/javascript-chatgpt-plugin/

챗 플러그인 시스템은 ChatGPT의 기능을 확장하고, 자체 비즈니스 데이터를 통합하며, 고객이 비즈니스와 상호작용할 수 있는 새로운 채널을 추가하는 흥미로운 방법입니다. 이 글에서는 챗 플러그인이 무엇인지, 무엇을 할 수 있는지, 그리고 자바스크립트를 통해 어떻게 직접 플러그인을 구축할 수 있는지에 대해 이야기합니다.

이 문서(또는 OpenAI에서 ‘트레이닝 데이터’라고 부르는) 첫 ChatGPT 플러그인을 빌드하고 ChatGPT 인터페이스와 통합하기 위한 빠른 시작 가이드를 제공합니다.

플러그인 빌드에 대한 공식 문서는 아직 파이썬 예제만 제공되고 있습니다. 자바스크립트 개발자를 돕기 위해 몇 분 안에 플러그인을 설정하고 실행할 수 있는 단계별 튜토리얼과 저장소를 준비했습니다. 빠른 시작을 위한 저장소에서는 공식 예제의 투두 리스트를 기준으로 하며, 도움이 되는 몇 가지 추가 기능을 제공합니다.

챗 플러그인이 삶을 변화시키는 자비스 같은 경험이 될지 아니면 그저 값비싼 브라우저용 알렉사가 될지는 미지수입니다. 플러그인이 어떤 기능을 제공할 수 있는지 어떤 점을 주의해야 하는지 직접 플러그인을 만드는 방법을 살펴보시고 판단해 보길 바랍니다.

챗 플러그인이란 뭔가요?

‘챗 플러그인’을 사용하면 ChatGPT 모델이 서드파티 앱을 사용하거나 상호작용이 가능해집니다. 본질적으로 언어 모델이 채팅 대화 중에 API 호출이나 작업을 생성하기 위해 따르는 일련의 지침 및 사양입니다. 서드파티 시스템과의 통합을 통해 ChatGPT 사용자는 새로운 범위의 기능을 사용할 수 있습니다.

  • 자체 비즈니스 데이터 및 데이터베이스(예: 영업 및 마케팅 시스템)를 생성, 업데이트 및 수정합니다.
  • 외부 서비스에서 정보를 가져옵니다.(예: 금융, 날씨 API)
  • 작업 수행(예: Slack 메시지 보내기)

플러그인의 구성 요소

AI와 상호작용하는 앱을 구축하기는 어렵고 복잡한 시스템처럼 보일 수 있지만, 일단 시작하면 놀라울 정도로 간단하다는 것을 알게 됩니다. “플러그인”은 ChatGPT 모델에게 API의 기능과 접근 방법 및 언제 호출을 해야 하는지 시기를 알려주는 간단한 지침 집합입니다.

이는 두 가지 중요한 두 파일로 요약됩니다.

  1. ai-plugin.json: 플러그인의 필수 메타데이터가 포함된 플러그인 매니페스트입니다. 여기에는 이름, 작성자, 설명, 인증 및 연락처 세부 정보가 포함됩니다. 이 매니페스트는 ChatGPT에서 플러그인의 기능을 이해하는 데 사용됩니다.
  2. openapi.yaml: OpenAPI 사양의 API 라우트 및 스키마에 대한 사양입니다. json 파일로도 제공될 수 있습니다. 이는 ChatGPT가 어떤 API를 사용할 수 있는지, 어떤 이유로 사용할 수 있는지, 요청과 응답이 어떻게 표시되는지 알려줍니다.

플러그인 서비스의 기능 및 호스팅은 당신의 선택에 달려 있습니다. API는 REST API 또는 프로그래밍 언어를 사용해 어디서나 호스팅 할 수 있습니다.

챗 플러그인 생태계의 새로운 기회

챗 플러그인의 출시로 개발자, 디자이너, 비즈니스 및 기업가에게 다양한 기회가 열렸습니다.

  • 상호작용이 더욱 ‘스마트’하고 ‘유동적’이게 될 수 있습니다.: 플러그인은 인간화, 가정, 컨텍스트화 및 요청을 결합하는 기능을 도입합니다. 이는 딱딱한 GUI나 구조화된 데이터 API로는 충족할 수 없는 유동적인 요소를 상호작용에 추가합니다. 예를 들어 *”오늘 재킷을 입어야 하나요?”*라는 프롬프트는 사용자의 위치를 기반으로 날씨 서비스에 대한 API 호출, 그리고 날씨에 대한 해석 및 원래 질문에 대한 답변을 제공합니다. “네. 재킷을 입으시는게 좋겠어요. 현재 기온은 12도이며 비가 올 확률은 80%입니다.” 라고요.
  • 새로운 고객 채널: ChatGPT는 2023년 4월에 1억 7,300만명의 활성 사용자가장 빠르게 성장하는 사용자 기록을 세웠습니다. 이 플랫폼에 입점하게 된다면 많은 잠재 고객에게 다가갈 기회를 얻게 된다는 것은 의심할 여지가 없습니다. 또한, 이 플랫폼을 사용하는 기존 고객과 더 쉽고 직관적이며 접근하기 쉬운 방식으로 상호작용할 수 있습니다.
  • 인공지능 인터페이스(Artificial Intelligence Interface, A.I.I)의 부상: 이제 사용자들은 ‘버튼’을 클릭하지 않고도 복잡한 멀티파티 작업을 수행할 수 있습니다. 플러그인은 이론적으로 기존 UI에 집중하지 않고도(또는 전혀 집중할 필요 없이) 놀라운 서비스를 제공할 수 있습니다. 직관적인 사양은 직관적인 웹 앱만큼 중요해질 수 있습니다.
  • 새로운 비즈니스 기회: AI는 일자리를 뺏는 동시에 일자리를 제공합니다. 플러그인 생태계가 성공적으로 구축되면 플러그인 개발자, AI API 개발자, 그리고 기업용 플러그인을 호스팅, 인증, 관리하는 완전히 새로운 비즈니스 분야에 기회와 공간이 창출될 것입니다.

플러그인 개발 시 고려 사항 및 제한 사항

직관적이고 코드가 필요 없는 인터페이스라는 이점은 나름의 과제를 안겨줍니다. 시간이 지남에 따라 생태계, 로직, 인터페이스가 발전할 것이라는 점을 인정하더라도 플러그인을 구축할 때 염두에 둬야 하는 몇 가지 사항이 있습니다. 특히 비즈니스를 위해 플러그인을 구축한다면 더욱 그렇습니다.

  • 느린 응답 속도: 자연어를 해석하고, 플러그인을 선택한 뒤 요청을 작성하고, 응답을 해석하는 데 모두 시간이 걸립니다. 간단한 정보 요청이나 작업의 경우 직접 수행하는 것이 더 빠를 수 있습니다. 위의 예에서와 같이 ChatGPT가 날씨를 해석해 회신하기를 15초 동안 기다리기보다 핸드폰 홈 화면을 보는 것이 훨씬 빠를 수 있습니다.
  • 높은 비용: 사용자는 플러그인과 상호작용하기 위해 토큰을 사용합니다. 따라서 무료로 무언가를 제공하더라도 서비스와의 상호작용에는 기본 비용이 추가됩니다. 또한, 이런 API를 호스팅하고 운영하기 위한 인프라 비용도 지불해야 합니다.
  • 기존 API를 사용하는 다른 방식입니다: 플러그인과 상호 작용하는 것은 여전히 내부적으로 REST API이며 다른 클라이언트와 동일한 작업을 수행할 것입니다. 플러그인은 현재 AI가 우리 업무를 수행하기 위한 새로운 패러다임이라기보다는 비즈니스와 상호 작용하기 위한 새로운 채널에 더 가깝습니다.
  • 조작이 가능합니다: 사용자는 기본적으로 API 응답을 볼 수 없기 때문에 플러그인 제작자가 잘못된 정보 및 기타 악의적인 수법을 사용해 답변을 왜곡할 수 있습니다. 예를 들어, 이 Reddit 스레드에서는 한 플러그인이 ChatGPT의 응답을 조작하기 위해 API 응답에 특정 지침을 삽입한 것을 발견했습니다. 신뢰할 수 있는 금융 뉴스 소스로 연결하지 않고 특정 회사 웹사이트에서 정보를 얻도록요.
  • 예측이 불가능합니다: 생성 모델(Generative model)에 의사 결정을 맡기는 것은 위험하며, 그 동작을 신뢰할 수 없습니다. 사람이 작성한 채팅 프롬프트를 기반으로 API 요청을 생성하기 위해 많은 추론과 추측이 뒤에서 이뤄지고 있습니다. 잘못 입력된 메시지나 모호한 설명으로 인해 잘못된 API가 호출되거나 동작이 수행될 수 있습니다. 확인하지 않은 업데이트나 삭제로 인해 손상을 초래할 수 있는 기능을 노출해서는 안 된다는 것은 두말할 나위도 없습니다.

이 플러그인을 개발하는 동안 할 일을 ‘완료’ 처리할 때 응답이 예상대로 작동하지 않는 경우도 있었습니다. API의 문제를 파악하는 대신 ChatGPT는 업데이트, 삭제, 추가를 반복하고 같은 방식으로 업데이트하는 루프에 빠졌습니다! 18번의 시도 끝에 중단할 방법이 없어 페이지를 새로고침하고 로컬 서버를 다시 시작해야 했습니다.

플러그인 루프에 빠진 ChatGPT

첫 자바스크립트 ChatGPT 플러그인 빌드하기

챗 플러그인을 위한 자체 Express 서버를 구축하겠습니다. 이 방법은 쉽게 시작할 수 있을뿐더러 미들웨어, 인증 및 기타 원하는 모든 프로덕션급 기능을 포함하도록 Express를 확장할 수 있습니다.

이 단계에서 생성하고 코드를 생성하고 추가할 파일은 다음과 같습니다. 헷갈리는 부분이 있다면 여기를 다시 살펴보거나 저장소를 복제하세요.

my-chat-plugin/
├─ .well-known/
│ ├─ ai-plugin.json <- 필수로 작성되어야 할 플러그인 메타데이터
├─ routes/
│ ├─ todos.js <- Todo 요청을 다룰 라우트
│ ├─ openai.js <- openAI 요청을 다룰 라우트
openapi.yaml <- Open API 스펙
index.js <- 플러그인 진입점

선행 조건

  • OpenAI 계정 생성: 가입
  • ChatGPT 플러그인 접근: 아직 유료 계정을 통해 접근 권한이 없는 경우 여기서 대기 명단에 등록할 수 있습니다.

프로젝트 설정하기

폴더를 만듭니다. 저는 my-chat-plugin으로 했습니다. 터미널이나 파워쉘에 이 명령어를 붙여 넣고 시작해 보세요.

## 1. 디렉터리 생성 및 열기
mkdir my-chat-plugin && cd my-chat-plugin

## 2. 프로젝트 기본 세팅 설정
npm init --yes
## 3. 의존 설치
npm install axios express cors js-yaml

OpenAI 매니페스트 및 API 사양 추가하기

이제 꼭 필요한 챗 플러그인 매니페스트와 OpenAI 사양을 생성하겠습니다. ChatGPT는 서버의 특정 라우트에서 이런 파일을 요청할 것이므로 이 라우트에 파일을 넣어야 합니다.

  • /.well-known/ai-plugin.json
  • /openapi.yaml

이 파일의 설명은 올바르게 작성하는 것이 정말 중요합니다! summarydescription_for_model 필드에 모호한 언어가 있으면 ChatGPT가 플러그인 사용 시기와 방법에 대해 혼동할 수 있습니다. 다음 단계를 따르세요.

  1. .well-known 폴더를 만들고 그 안에 ai-plugin.json파일을 추가합니다. 터미널에서 이 명령어를 수행하면 됩니다.
mkdir .well-known && touch .well-known/ai-plugin.json

그리고 이 코드를 ai-plugin.json에 붙여 넣으세요.

{
"schema_version": "v1",
"name_for_human": "My ChatGPT To Do Plugin",
"name_for_model": "todo",
"description_for_human": "Plugin for managing a To Do list. You can add, remove and view your To Dos.",
"description_for_model": "Plugin for managing a To Do list. You can add, remove and view your ToDos.",
"auth": {
"type": "none"
},
"api": {
"type": "openapi",
"url": "http://localhost:3000/openapi.yaml",
"is_user_authenticated": false
},
"logo_url": "http://localhost:3000/logo.png",
"contact_email": "support@yourdomain.com",
"legal_info_url": "http://www.yourdomain.com/legal"
}
  1. 프로젝트 루트 디렉터리에 openapi.yml 파일을 생성하고(touch openapi.yml 명령어를 터미널에서 수행하면 됩니다) 이 코드를 추가합니다.

이 사양은 ChatGPT가 API 라우트를 수행하는 작업(각 라우트에 대한 요약 참조)과 요청 및 응답을 이해하기 위해 사용됩니다. ChatGPT가 API에 문제가 있는 경우, 10번 중 9번은 이 사양이 API의 응답과 일치하지 않아서입니다.

openapi: 3.0.1
info:
title: TODO Plugin
description: A plugin that allows the user to create and manage a To Do list using ChatGPT.
version: "v1"
servers:
- url: http://localhost:3000
paths:
/todos:
get:
operationId: getTodos
summary: Get the list of todos
responses:
"200":
description: OK
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Todo"
post:
operationId: addTodo
summary: Add a todo to the list
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Todo"
responses:
"201":
description: Created
content:
application/json:
schema:
$ref: "#/components/schemas/Todo"
/todos/{id}:
delete:
operationId: removeTodo
summary: Delete a todo from the list when it is complete, or no longer required.
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
"204":
description: No Content
components:
schemas:
Todo:
type: object
properties:
id:
type: integer
format: int64
task:
type: string
required:
- id
- task

서버 생성하기

다음 단계는 플러그인의 진입점인 메인 파일을 생성하는 것입니다. 프로젝트 루트 디렉터리에 index.js파일을 추가하고 아래 코드를 입력합니다.

참고: ChatGPT 문서에는 openapi.yamlopenapi.json에 대한 라우트가 모두 나와있습니다. 로컬 테스트에서는 요청되는 yaml 파일만 표시되지만 나중에 사용될 수 있으므로 두 파일 모두 보관하는 것이 좋다고 생각합니다.

이 코드를 index.js에 붙여 넣으세요.

const express = require("express");
const cors = require("cors");
const todoRouter = require("./routes/todos");
const openaiRoutes = require("./routes/openai");

const app = express();
const PORT = 3000;
// ChatGPT가 플러그인에 접근하려면 chat.openapi.com을 허용하도록 CORS를 설정해야 합니다.
app.use(cors({ origin: [`http://localhost:${PORT}`, "https://chat.openai.com"] }));
app.use(express.json());
// 간단한 요청 로깅을 통해 ChatGPT가 플러그인을 호출하고 있는지 확인합니다.
app.use((req, res, next) => {
console.log(`Request received: ${req.method}: ${req.path}`);
next();
});
// OpenAI 필수 라우트
app.use(openaiRoutes);
// todos API 더미 라우트
app.use("/todos", todoRouter);
app.listen(PORT, () => {
console.log(`Plugin server listening on port ${PORT}`);
});

위 코드는 아래 작업을 수행합니다.

  • Express와 CORS 처리에 필요한 라이브러리를 가져옵니다.
  • 다음 단계에 추가할 라우트별 로직을 가져옵니다.
  • 로깅 미들웨어를 추가해 콘솔로 들어오는 모든 요청을 나타냅니다.
  • 전달할 API 서비스가 이미 있는 경우 사용할 수 있는 일반 전달 함수를 제공합니다.

필수 플러그인 라우트 설정하기

이 단계에서는 OpenAI와 ChatGPT가 필요한 파일을 가져오기 위한 필수 라우트를 추가합니다. 모든 특정 라우트 로직을 ‘routes’ 디렉터리에 배치할 것입니다. 여기에 플러그인 라우트와 다른 사용자 정의 라우트도 저장할 것입니다.

(이 구조를 추가 폴더(컨트롤러, 미들웨어, 서비스 등)로 확장하거나 직접 만들 수 있습니다.)

  1. /routes 폴더를 생성합니다.
  2. openai.js 파일을 생성합니다.
  3. routes/openai.js 파일에 다음 코드를 붙여 넣습니다.
const express = require("express");
const router = express.Router();
const fs = require("fs");
const path = require("path");
const yaml = require("js-yaml");

router.get("/openapi.yaml", async function (req, res) {
try {
const yamlData = fs.readFileSync(path.join(process.cwd(), "openapi.yaml"), "utf8");
const jsonData = yaml.load(yamlData);
res.json(jsonData);
} catch (e) {
console.log(e.message);
res.status(500).send({ error: "Unable to fetch manifest." });
}
});
router.get("/.well-known/ai-plugin.json", function (req, res) {
res.sendFile(path.join(process.cwd(), "/.well-known/ai-plugin.json"));
});
router.get("/logo.png", function (req, res) {
res.sendFile(path.join(process.cwd(), "logo.png"));
});
module.exports = router;

이 코드는 다음과 같은 역할을 합니다.

  • 플러그인이 매니페스트 및 API 사양을 검색하기 위한 두 가지 라우트를 정의합니다.
  • 플러그인이 채팅에서 플러그인 로고를 검색하고 표시하는 라우트를 정의합니다.
  • index.js에서 가져올 수 있도록 모든 라우트를 내보냅니다.

투두 라우트 설정하기

이제 간단한 생성, 업데이트 및 삭제 기능을 모방하는 몇 가지 라우트를 생성해 보겠습니다. 일반적으로 투두 리스트를 활용한 튜토리얼은 피하는 편이지만, 이 문서가 가이드에서 사용되기 때문에 가능한 한 이전 가능한 상태로 유지하고 싶었습니다.

  1. routes 폴더에 todos.js를 생성합니다.
  2. routes/todos.js파일에 아래 코드를 붙여 넣습니다.
const express = require("express");
const router = express.Router();

let todos = [
{ id: 1, task: "Wake up" },
{ id: 2, task: "Grab a brush" },
{ id: 3, task: "Put a little makeup" },
{ id: 4, task: "Build a Chat Plugin" },
]; // 미리 입력된 할 일
let currentId = 5; // 새로운 할 일을 할당하기 위한 유니크한 id
getTodos = async function (req, res) {
res.json(todos);
};
addTodo = async function (req, res) {
const { task } = req.body;
const newTodo = { id: currentId, task };
todos.push(newTodo);
currentId++;
res.json(newTodo);
};
removeTodo = async function (req, res) {
const { id } = req.params;
todos = todos.filter((todo) => todo.id !== Number(id));
res.json({ message: "Todo successfully deleted" });
};
router.get("/", getTodos);
router.post("/", addTodo);
router.delete("/:id", removeTodo);
module.exports = router;

이 코드는 다음과 같은 역할을 합니다.

  • 할 일 가져오기, 생성하기, 삭제 기능을 제공하는 3개의 간단한 라우트를 생성합니다.
  • index.js 파일에서 가져올 라우트를 내보냅니다.

플러그인 검증 및 테스트하기

이제 재밌는 부분이 시작됩니다. ChatGPT에서 로컬 플러그인을 수동으로 빌드하고 실행하는데 필요한 모든 코드와 설정이 완료되었습니다! 이제 시작해 보죠.

  1. 생성한 서버 실행하기

터미널에서 node index.js를 입력해 서버를 실행하면 터미널에 'Plugin server listening on port 3000'가 노출됩니다.

2. ChatGPT 로컬 플러그인에 연결하기

chat.openai.com에 접속해 계정에서 새 채팅을 엽니다. GPT-4 메뉴를 클릭한 뒤 Plugins > Plugin Store > Develop Your Own Plugin 클릭 > localhost:3000을 입력한 뒤 Find manifest file을 클릭하세요.

3. 플러그인 테스트

ChatGPT가 매니페스트 파일을 가져오고 시작할 준비가 되었다는 검증 메시지가 노출되어야 합니다! 그렇지 않은 경우, 서버가 실행 중인 터미널에서 요청이 제대로 수신되고 있는지 확인하세요.

아래 명령어 중 몇 가지를 시도해 보고 기능적인 로컬 채팅 플러그인을 사용해 즐거운 시간을 보내보세요. 이런 명령어를 실행해 보는 건 어떤가요?

  • “내 할 일이 뭐야?"
  • 나 깼어(정확한 할 일 작업을 말하지 않아도 무엇을 말하는지 이해할 수 있습니다.)

(선택 사항)이 서버를 프록시로 사용하기

이미 로컬 또는 외부에서 요청을 보낼 API가 실행 중인 경우, 이 서버를 프록시로 사용해 해당 서버로 요청을 보낼 수 있습니다. 이 옵션을 사용하면 기존 코드 베이스를 다시 배포하거나 업데이트할 필요 없이 매니페스트 사양 파일을 처리하는 방법을 빠르게 테스트하고 반복할 수 있어 권장되는 옵션입니다.

  1. 생성한 경로에 index.js 파일을 추가한 뒤 아래 코드를 작성합니다.
// app.listen(... 전에 붙여 넣으세요.
// 기존 API에 대한 프록시 서버
const api_url = "http://localhost";
app.all("/:path", async (req, res) => {
const { path } = req.params;
const url = `${api_url}/${path}`;
console.log(`Forwarding call: ${req.method} ${path} -> ${url}`);
const headers = {
"Content-Type": "application/json",
};
try {
const response = await axios({
method: req.method,
url,
headers,
params: req.query,
data: req.body,
});
res.send(response.data);
} catch (error) {
console.error(`Error in forwarding call: ${error}`);
res.status(500).send("Error in forwarding call");
}
});

더 나아가면

이 기본 튜토리얼을 통해 본격적인 자바스크립트 기반 챗 플러그인을 구축하는 데 필요한 모든 것을 배울 수 있었습니다. 앱을 프로덕션 환경에 배포하려면 몇 가지 추가 인증 및 배포가 필요합니다. 이 튜토리얼에서 다루지 않지만 아래 자료를 참고해 보세요.

궁금한 점이 있거나 다음 시리즈를 요청하려면 링크드인으로 연락하시거나 SitePoint 커뮤니티에 방문하세요.

--

--

한정(Han Jung)
한정(Han Jung)

Written by 한정(Han Jung)

개인용 블로그로 사용하고 있습니다. 좋은 개발자가 꿈입니다. > https://www.notion.so/Han-Jung-c43f4bcd2b3f4b3d85b93aee41c5e098

No responses yet