끄적끄적

ChatGPT API 사용해보기 본문

개발/js & ts & node.js

ChatGPT API 사용해보기

코리이 2023. 3. 26. 16:10

요즘 ChatGPT 에 대해서 시끌벅적하다. 특히나 최근에 Micorsoft 에서 copilot 을 단순한 개발이 아닌 ms office 에 적용하기도 하면서 업무에 직접적으로 영향을 주기 시작하고 있고 ChatGPT Api 대신 ChatGPT 플러그인이 나오면서 일반인도 충분히 사용 가능하도록 출시되었다. 즉, 이제는 실생활에 밀접하게 적용되고 있다고 생각해 볼 수 있다. 

이렇게 AI 와 대화하고 여러 의견 및 정답을 얻어가는 과정을 프롬프트 엔지니어링이라고 하는데 개인적인 생각에 앞으로 프롬프트 엔지니어링이라는 말은 사라지고 업무를 할 때 자연스럽게 써야하는 미래가 올 것 같다. 비유해보자면 과거에 펜과 종이를 통해 업무를 보다가 지금에 와서는 워드 및 한글 등을 통해 모든 업무를 컴퓨터화해서 보고 있다. 현재는 워드나 한글을 할 줄 모르면 일 자체를 할 수 없는 세상이라는 것이다. 그러한 방향과 비슷하게 앞으로는 이 프롬프트 엔지니어링이라는 것을 모르면 일 자체가 할 수 없는 상황이 올 것이라고 생각한다.

그래서 이러한 흐름에 맞춰 공부도 해볼까 해서 이것저것 도전해보고 있다. 하지만 개발자라면 Api 부터 손이 갈 것이라고 생각해서 Api 를 사용해본 경험을 포스팅해보고자 한다.

가격

시작하기 전에 ChatGPT 를 사용하려면 얼마가 필요한지 알아 볼 필요가 있다. 괜히 실습때문에 돈 날리는 일 없게 꼼꼼히 확인 후 진행하자. 아래 링크에서 가격을 확인해 볼 수 있다.

 

Pricing

Simple and flexible. Only pay for what you use.

openai.com

일단 필자가 사용해 볼 Api 는 Chat 이다. Chat 의 경우 아래처럼 Prompt 의 경우 1K(1000) Token 당 $0.03 이며, Completion 의 경우 1K(1000) Token 당 $0.06 이라고 한다. ChatGPT 대답의 가격이 더 비싸다. 뒤에서 나오겠지만 대충 어느정도의 가격이 드냐면 아래처럼 물어봤을 때 총 84 token 이 사용 되었다. 어떻게 토큰이 산정되는지는 지식이 부족해 잘 모르겠다. 참고해서 테스트 하면 될 것 같다.

prompt: "이거 사용법 좀 step 별로 알려줘" # 25 Token
answer: "먼저, 어떤 것의 사용법을 알려주셔야 하는지 알려주시면 더 자세한 답변을 드릴 수 있습니다. 감사합니다." # 59 Token

Api Key 발급

Api 를 사용하기 위해서는 Api Key 를 발급받아야 한다. 내 프로필을 눌러 "View API keys" 를 클릭해 아래처럼 key 를 발급 받고 시크릿 키를 어딘가에 복사해 두자. 개인적으로 시크릿키는 테스트로 사용 후에는 삭제해두길 권장한다. 실제 사용목적이 없는데도 남아있으면 추후에 요금 폭탄으로 돌아올지도 모른다.

API 사용해보기

ChatGPT 공식 문서를 보면 어느 정도는 자세하게 나와 있다. 하지만 curl 을 이용해서 직접 네트워크 작업을 사용하지 않고 라이브러리를 사용하는 방법은 아직 잘 나와 있지 않은 듯 싶다. 그래도 오히려 HTTP 네트워크를 제공해준다는 것은 쉽게 개발할 수 있다는 의미이기도 하다. 하지만 이번 포스팅에서는 라이브러리를 활용해볼까 한다. 참고로 필자는 Node.js 를 사용할 건데 어차피 이 라이브러리는 axios 를 래핑한 것 뿐이라고 한다.

 

OpenAI API

An API for accessing new AI models developed by OpenAI

platform.openai.com

node 프로젝트 세팅하는 건 생략하고 공식적으로 제공해주는 npm 모듈을 받아보자.

npm install openai

그 후 공식적으로 제공해주는 샘플 코드를 실행해 보았다.

const { Configuration, OpenAIApi } = require("openai");

const configuration = new Configuration({
    apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

openai.createCompletion({
    model: "text-davinci-003",
    prompt: "Hello world",
}).then((result) => {
    console.log(result.data.choices[0].text);    
}).catch(err => console.log(err));

 

에러가 발생했다. 그 이유는 아직 카드 등록을 하지 않았기 때문이라고 한다. Api 서비스는 앞에서도 이야기 했지만 기본적으로 유료이기 때문에 카드 등록을 진행 한 후 같은 코드로 진행해 보았다. 이 글을 보시는 분들이라면 카드 등록을 해서 필자처럼 이상한 에러는 안나길 바란다.

 

드디어 성공적으로  Api 응답이 잘 왔다.

그럼 이제 조금 응용해서 다른 모델을 활용해보자. 앞에서 이야기 했던 gpt-3.5-turbo 모델을 활용해볼까 한다. 그리고 role 을 지정해서 사용해보도록 하겠다. 코드가 조금 바뀌었는데 응답 메시지 혀식이 조금 바뀌었기 때문이다. 개인적인 테스트에서는 이 때문에 요금이 조금 빠져나가는 뼈아픈 경험을 했는데 이 글을 보고 있다면 file 로 때려 넣어서 처음에 삽질을 안하시길 바라겠다. 아래처럼 코드를 작성한 후 실행해보자. 

openai.createChatCompletion({
    model: "gpt-3.5-turbo",
    messages: [{"role": "user", "content": "이거 사용법 좀 step 별로 알려줘"}],
    temperature: 0.7,
}).then((result) => {
    fs.writeFileSync(`${__dirname}/sample.json`, JSON.stringify(result.data));
}).catch(err => console.log(err));

아래는 응답이고 choices[0].message.content 에 답변이 나오는 것을 확인 할 수 있다.

{
  "id":"chatcmpl-6xXoQPGzNzwoaj41JjLhjJZ8Z9C5W",
  "object":"chat.completion",
  "created":1679649346,
  "model":"gpt-3.5-turbo-0301",
  "usage":{
    "prompt_tokens":25,
    "completion_tokens":59,
    "total_tokens":84
  },
  "choices":[
    {
      "message": {
        "role":"assistant",
        "content":"먼저, 어떤 것의 사용법을 알려주셔야 하는지 알려주시면 더 자세한 답변을 드릴 수 있습니다. 감사합니다."
      },
      "finish_reason":"stop",
      "index":0
    }
  ]
}

일단 원하는 대답은 아니지만 결과가 나오는 것을 확인 할 수 있었다.

활용해보기

하지만 ChatGPT 를 사용하는 유저 입장에서 단순하게 저렇게 대답만 해주는 걸 원하지 않고 대화를 이어나가면서 사용하길 바랄 것 같다. 그래서 아래와 같은 형태를 유지하며 사용해볼까 한다.

 

Check out this ShareGPT conversation

This is a conversation between a human and a GPT-3 chatbot. The human first asks: js 로 코딩을 할거야 잘 부탁해. The GPT-3 chatbot then responds: <div><p>안녕하세요! 저는 js 코딩에 대해 도움을 드릴 수 있습니다. 어떤 종

sharegpt.com

위 스크린샷을 보면 알겠지만 질문 네 가지를 했다.

 

  1. js 로 코딩을 할거야 잘 부탁해
  2. 음 우선 string 을 number 로 바꾸고 싶은데 number 가 아닌경우는 에러를 떨어뜨리는 코드를 만들어줘
  3. 함수 형태로 만들어줘
  4. 그런데 나는 소수는 안받고 싶어. 소수인 경우에는 에러를 띄워줘

같은 형태로 API 를 만들고 싶어서 크롬 개발자 도구를 활용해서 네트워크 요청 방식을 확인해봤더니 "parent Id" 를 지정해줘서 이야기를 이어 나갈 수 있도록 지정하고 있었다. 하지만 Api 상에서는 parentId 를 지정하는 부분이 현재는 확인이 안되고 role 을 지정해 이전 대화를 한꺼번에 넣도록 만들었다. 하나씩 이야기해보면 다음과 같다.

첫번째 질문

js 로 코딩을 할거야 잘 부탁해

 

우선적으로 system 역할을 지정해 js programmer 의 역할을 지정해주고 웹에서 진행했던 질문과 동일한 질문을 던져봤다.

const messages =[
    { role: 'system', content: 'You are a js programmer.' },
    { role: "user", content: 'js 로 코딩을 할거야 잘 부탁해' },
],

응답은 아래처럼 json 의 형태로 응답이 왔다. 

{
  "id": "chatcmpl-6xYIH7dtOI5ShREQmpgfT9C5DIprR",
  "object": "chat.completion",
  "created": 1679651197,
  "model": "gpt-3.5-turbo-0301",
  "usage": {
    "prompt_tokens": 35,
    "completion_tokens": 20,
    "total_tokens": 55
  },
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "네, 어떤 프로젝트를 시작할까요?"
      },
      "finish_reason": "stop",
      "index": 0
    }
  ]
}

content 만 확인하면 된다. 간단한 질문이였으므로 간단한 대답이 들어왔다. 웹 브라우저에서 진행한 것과 비교해 다른 대답이 들어왔지만 일단 이어나가기 위해 응답에 적힌 content 를 사용했다. 또한 응답을 보면 알겠지만 내가 사용한 token 의 갯수를 확인할 수도 있다.

두 번째 질문 

음 우선 string 을 number 로 바꾸고 싶은데 number 가 아닌경우는 에러를 떨어뜨리는 코드를 만들어줘

 

두 번째 질문을 하기 전에 첫 번째 질문에 대한 대답을 assistant 에 그대로 적어줬다. 그리고 이어서 웹에서 진행한 것과 같은 두 번째 질문을 했다.

const messages = [
    { role: 'system', content: 'You are a js programmer.' },
    { role: "user", content: 'js 로 코딩을 할거야 잘 부탁해' },
    { role: "assistant", content: '네, 좋습니다. 어떤 문제를 해결해야 할까요?' },
    { role: "user", content: '음 우선 string 을 number 로 바꾸고 싶은데 number 가 아닌경우는 에러를 떨어뜨리는 코드를 만들어줘' },
],

응답은 아래와 같다. 포멧은 이전과 동일하기 때문에 content 만 적어보았다.

{
  "message": {
    "role": "assistant",
    "content": "아래 코드와 같이 `Number()` 메소드를 이용하여 문자열을 숫자로 변환할 수 있고, `isNaN()` 함수를 이용하여 변환된 숫자가 유효한 숫자인지 확인할 수 있습니다. 유효하지 않은 숫자인 경우 `TypeError` 를 throw 하는 코드를 작성해보겠습니다.\n\n```js\nfunction stringToNumber(str) {\n  const num = Number(str);\n  if (isNaN(num)) {\n    throw new TypeError(`${str} is not a valid number`);\n  }\n  return num;\n}\n\ntry {\n  const num1 = stringToNumber(\"10\");\n  console.log(num1); // 숫자 10 출력\n  const num2 = stringToNumber(\"abc\");\n  console.log(num2);\n} catch (error) {\n  console.error(error); // TypeError: abc is not a valid number 출력\n}\n```"
  },
  "finish_reason": "stop",
  "index": 0
}

적힌 content 를 약간의 파싱을 해보니 js 코드를 아래처럼 보여줬다.

function stringToNumber(str) {
  const num = Number(str);
  if (isNaN(num)) {
    throw new TypeError(`${str} is not a valid number`);
  }
  return num;
}

try {
  const num1 = stringToNumber("10");
  console.log(num1); // 숫자 10 출력
  const num2 = stringToNumber("abc");
  console.log(num2);
} catch (error) {
  console.error(error); // TypeError: abc is not a valid number 출력
}

이번 대답에 의해 세번째 질문을 할 필요가 없어졌다. 이미 함수로 지정해 주었기 때문이다. 함수의 형태는 조금 달라졌지만 둘 다 쓰는데는 큰 문제가 없어 보인다. 그래서 세 번째 질문은 스킵하고 네 번째 질문으로 바로 넘어갔다. 

마지막 질문

그런데 나는 소수는 안받고 싶어. 소수인 경우에는 에러를 띄워줘

 

같은 형태로 message 를 누적으로 role 을 지정 해서 만들어 주었다.

const messages = [
    { role: 'system', content: 'You are a js programmer.' },
    { role: "user", content: 'js 로 코딩을 할거야 잘 부탁해' },
    { role: "assistant", content: '네, 좋습니다. 어떤 문제를 해결해야 할까요?' },
    { role: "user", content: '음 우선 string 을 number 로 바꾸고 싶은데 number 가 아닌경우는 에러를 떨어뜨리는 코드를 만들어줘' },
    { role: "assistant", content: "아래 코드와 같이 `Number()` 메소드를 이용하여 문자열을 숫자로 변환할 수 있고, `isNaN()` 함수를 이용하여 변환된 숫자가 유효한 숫자인지 확인할 수 있습니다. 유효하지 않은 숫자인 경우 `TypeError` 를 throw 하는 코드를 작성해보겠습니다.\n\n```js\nfunction stringToNumber(str) {\n  const num = Number(str);\n  if (isNaN(num)) {\n    throw new TypeError(`${str} is not a valid number`);\n  }\n  return num;\n}\n\ntry {\n  const num1 = stringToNumber(\"10\");\n  console.log(num1); // 숫자 10 출력\n  const num2 = stringToNumber(\"abc\");\n  console.log(num2);\n} catch (error) {\n  console.error(error); // TypeError: abc is not a valid number 출력\n}\n```" },
    { role: "user", content: '그런데 나는 소수는 안받고 싶어. 소수인 경우에는 에러를 띄워줘' },
],

응답은 아래와 같다.

{
  "message": {
    "role": "assistant",
    "content": "자바스크립트 내장 함수인 `parseInt()` 함수를 사용하면 문자열을 정수로 변환할 수 있습니다. 이 함수는 소수점 이하의 숫자를 무시하므로 소수에 대한 처리를 걱정하지 않아도 됩니다. 만약 문자열이 정수가 아니라면 `NaN`을 반환하므로 이를 이용하여 오류 처리를 할 수 있습니다. 아래는 이에 대한 예시입니다.\n\n```js\nfunction stringToInteger(str) {\n  const num = parseInt(str);\n  if (isNaN(num)) {\n    throw new TypeError(`${str} is not a valid integer`);\n  }\n  return num;\n}\n\ntry {\n  const num1 = stringToInteger(\"10\");\n  console.log(num1); // 숫자 10 출력\n  const num2 = stringToInteger(\"3.14\");\n  console.log(num2); // TypeError: 3.14 is not a valid integer 출력\n} catch (error) {\n  console.error(error);\n}\n```"
  },
  "finish_reason": "stop",
  "index": 0
}

 

마지막 응답을 코드 부분만 확인해보니 다음과 같았다. 비교해서 보기 위해 웹 브라우저에서 만들어진 코드도 추가했다.

/* 
* Api 를 활용한 대답 
*/
function stringToInteger(str) {
  const num = parseInt(str);
  if (isNaN(num)) {
    throw new TypeError(`${str} is not a valid integer`);
  }
  return num;
}

try {
  const num1 = stringToInteger("10");
  console.log(num1); // 숫자 10 출력
  const num2 = stringToInteger("3.14");
  console.log(num2); // TypeError: 3.14 is not a valid integer 출력
} catch (error) {
  console.error(error);
}

/* 
* 웹 브라우저를 활용한 대답 
*/
function parseInteger(str) {
  const num = parseInt(str);

  if (isNaN(num)) {
    throw new Error("입력된 값이 숫자가 아닙니다.");
  } else if (num.toString() !== str) {
    throw new Error("입력된 값이 소수입니다.");
  }

  return num;
}

try {
  const num1 = parseInteger("123");
  console.log(num1);

  const num2 = parseInteger("3.14");
  console.log(num2);
} catch (error) {
  console.error(error.message);
}

 

비교해보면 알겠지만 Error 부분과 함수 네이밍을 제외하고는 동일한 결과가 나왔다. 나름 성공적이였다. 이제 이를 활용하면 ChatGPT 와 같은 서비스를 만들어 낼 수도 있을 것 같다.

요금확인

마무리하기 전에 현재 테스트를 하는데에 요금이 어느정도 나왔을까 확인해 보았다. 

 

몇개의 Api 를 사용하지 않았는데 생각보다 돈이 꽤나 나왔다. 개인적으로 사이드 프로젝트 서비스로 만들어 내기는 조금 부담스러울 수 있는 금액인 것 같다. 특히나 현재 API 는 서로 대화가 늘어갈 수록 prompt 갯수가 증가하는 구조다 보니 요금 폭탄을 막기 위해선 간단간단한 것만 쓰거나 개인 비서 정도로만 만들어서 활용해봐야 할 것 같다.

결론

ChatGPT 는 어떤 사람은 단순 거짓말쟁이라고 하고 어떤 사람은 사용하기 유용한 툴이라고 하고, 극단적인 사람들은 많은 직업군을 대체할 것이라고 말한다. 특히나 개발자 연봉이 높아진 시대에 가장 공격받기 쉬운 직군이 개발자가 된게 아닐까 싶기도 하다. 하지만 한 가지 명확한 것을 AI 에 적응해 나가는 사람이 미래에 살아남는다는 것이다. 비슷한 관점으로 사람은 생각보다 쉽게 새로운 환경에 익숙해진다고 생각하기도 한다. 현재 개발자 중에 IDE 활용 안하는 개발자 없듯이 추후에는 AI 를 활용 안하는 개발자는 없을 것 같다고 생각한다. 시니어가 필요 없다던지 주니어가 필요 없다던지가 중요한게 아니라 시니어든 주니어든 그냥 개발자라면 익숙해 질 것이라는 것이다. 

그 외적으로 이 포스팅에서 필자는 아직 모델의 종류도 뭐가 뭔지 잘 모르고 대충 대화만 던지는 방식으로 진행했다. 하지만 프롬프트 엔지니어링에서 중요한게 질문을 어떻게 질 좋은 질문을 던지는가가 중요하다고 한다. 좀 더 공부해볼 필요는 있을 것 같다.