-
GPT-4로 인공지능 데이터 캐싱 서버 구축하기 feat. Promise PoolProject/OpenList 2024. 9. 25. 20:29반응형
안녕하세요, Openlist 팀의 백엔드 기술에 관심을 가져주셔서 감사합니다!
기술 블로그 작성하는 게 정말 재미있네요! 오늘은 우리 팀의 이야기를 공유하기 위해, GPT-4를 활용한 인공지능 데이터 캐싱 서버를 구축한 경험을 중심으로 글을 써볼까 합니다.
Why GPT-4?
일단 처음에는 기존의 Clova Studio를 사용하기로 했었어요. 우리에겐 20만 원이라는 크레딧이 있었거든요. 하지만 호기심에 GPT-4에 같은 질문을 넣어봤는데, CLOVA Studio랑 비교했을 때 놀라운 데이터 생성 능력을 직접 경험하고는 GPT-4를 사용하기로 결정했습니다.
API 키 발급 받기
GPT-4를 사용하려면 먼저 OpenAI 플랫폼에서 API 키를 발급받아야 해요. 이 과정은 비교적 간단해서 아래 문서만 보고 따라 하셔도 금방 하실 수 있습니다. 기본적으로 처음 사용하면 5달러 크레딧을 받게 되는데요. GPT-4 모델을 사용하려면 무료 크레딧으로는 사용할 수 없고, 한 번이라도 크레딧을 충전해야 사용할 수 있답니다. 참고해 주세요!
https://platform.openai.com/docs/quickstart?context=python
Node.js에 GPT-4 연동
API 키를 발급받은 후에는 Node.js 환경에 GPT-4를 연동했어요. 서버가 복잡하지 않아서 간단하게 구현할 수 있었죠. dotenv 라이브러리를 사용하여 API key 값을 환경변수로 관리하고, OpenAI 라이브러리를 통해 데이터 생성을 하도록 코드를 짰습니다.
import dotenv from 'dotenv'; import OpenAI from 'openai'; dotenv.config({ path: '.env' }); const apiKey = process.env.OPENAI_SECRET_KEY; const organization = process.env.OPENAI_ORGANIZATION; // 응답이 유효한지 확인하는 함수 const checkIfValidResponse = (response, count) => { // ... }; // 카테고리를 받아서 GPT-4로 데이터 생성 후 PostgreSQL에 저장하는 함수 export const generateGptData = async (category, count = 10) => { const openai = new OpenAI({ apiKey, organization }); const [main, sub, minor] = category; console.log('main,sub,minor:', category); const content = ` 여기에는 system role 내용을 입력해주세요. `; // 에러가 나면 재시도 let retryCount = 1; while (retryCount--) { try { const completion = await openai.chat.completions.create({ messages: [ { role: 'system', content, }, { role: 'user', content: `${category}` }, ], model: 'gpt-4-1106-preview', response_format: { type: 'json_object' }, }); console.log('gpt start'); const response = completion.choices[0]; console.log('response: ', response); const checklistItems = JSON.parse( response.message.content.replace(/\\\\n/g, ''), ); console.log(checklistItems); checkIfValidResponse(checklistItems, count); return checklistItems; } catch (error) { console.error('Error during AI generation:', error); retryCount++; } } };
⚒️ 응답이 깨지는 문제 발생
하지만 응답이 깨져서 들어오는 문제가 발생했어요. 😱
해결
기존 GPT-4 API에 요청을 보내는 함수 외에도, checkIfValidResponse() 함수를 통해 응답에 오류가 없는지 검증하고, while 문을 통해 재시도 옵션을 추가했습니다. 이렇게 하면 실패한 응답이 왔을 때 다시 요청을 보내도록 할 수 있죠.
데이터베이스 테이블 생성
다음으로, PostgreSQL 데이터베이스에 새로운 테이블을 생성했습니다. 이 테이블은 GPT-4로부터 생성된 데이터를 저장하는 데 사용되었어요.
create table if not exists public.ai_checklist_item_model ( "updatedAt" timestamp default now() not null, "createdAt" timestamp default now() not null, "aiChecklistItemId" serial constraint "PK_8467caa2fd5d9cf9879673b4c05" primary key, content varchar not null, selected_count_by_user integer default 0 not null, selected_count_by_naver_ai integer default 0 not null, evaluated_count_by_naver_ai integer default 0 not null, final_score integer default 0 not null, "categoryId" integer constraint "FK_25965092abe80a49babceefda5f" references public.category_model );
Redis Pub/Sub과 Promise Pool 도입
데이터 처리를 위해 Redis Pub/Sub과 Promise Pool을 도입했어요. 이를 통해 비동기적으로 여러 데이터를 효율적으로 처리할 수 있었죠.
📚 Promise Pool이란?
Promise Pool은 동시에 여러 비동기 작업을 관리하고 제어하는 데 사용되는 툴입니다. 이를 통해 동시에 여러 요청을 처리하면서도 각각의 요청이 서로 간섭하지 않도록 할 수 있어요.
🔄 Redis Pub/Sub의 역할
Redis Pub/Sub 시스템은 메시지 기반 통신을 가능하게 합니다. 이를 통해 서버 간 메시지를 비동기적으로 주고받을 수 있으며, 효율적인 데이터 처리가 가능해집니다.
import redis from 'redis'; import { RedisPub } from './redis-pub.js'; import { PromisePool } from '@supercharge/promise-pool'; import dotenv from 'dotenv'; import { generateGptData } from './generate-server.js'; import { saveData } from './gpt-data-saver.js'; dotenv.config({ path: '.env' }); const subscriber = redis.createClient({ url: process.env.REDIS_URL, }); // 카테고리를 받아서 GPT-4로 데이터 생성 후 PostgreSQL에 저장하는 함수 async function processCategory(category, publisher) { // ... } // Redis Pub/Sub을 통해 Promise Pool 방식으로 카테고리를 받아 GPT-4로 데이터 생성 후 PostgreSQL에 저장하는 함수 async function init() { const publisher = new RedisPub(); const redisSub = await subscriber.connect(); redisSub.subscribe('ai_generate', async function (message) { console.log('message:', message); const parsedMessage = JSON.parse(message); if (parsedMessage.messageData === 'generateGptData') { const { messageData, categories } = parsedMessage; console.log('messageData:', messageData); console.log('categories:', categories); console.log('start'); // Promise Pool 방식으로 processCategory 함수 실행 const { results, errors } = await PromisePool.withConcurrency(5) .for(categories) .process(async (category) => { await processCategory(category, publisher); }); // 오류 처리 또는 결과 확인 if (errors.length) { publisher.send( 'ai_generate', JSON.stringify({ messageData: 'error', errorLog: errors, }), ); console.error('Errors:', errors); } console.log('end'); } }); } init();
위의 코드는 redis-sub.js 코드인데요. 지정된 메시지(generateGptData)를 subscribe하면, GPT-4 API를 호출하고, DB에 저장하는 로직이 순차적으로 진행되도록 했고, 이 부분에서 Promise Pool 방식을 적용했습니다.
우리 팀은 @supercharge/promise-pool 라이브러리를 통해 Promise Pool 방식을 구현했어요.
일단은 5개의 레일을 만들어 뒀고, DB 상황에 맞춰서 늘릴 예정입니다. 테스트해 보니 놀라울 정도로 속도가 빨라진 걸 경험할 수 있었죠.
⚒️ Temperature 이슈 해결
프로젝트 중 한 가지 이슈가 발생했어요. GPT-4의 temperature 설정을 높게 하니, 응답 속도가 매우 느려졌거든요. 이 문제를 해결하기 위해 temperature 옵션을 제거했고, 결과적으로 훨씬 빠르고 만족스러운 결과를 얻을 수 있었습니다.
우분투 서버에 배포
우분투 서버에 배포하는 과정은 아래 포스팅을 참고해 주세요.
Node.js 서버 인스턴스 세팅 및 PM2를 이용한 서버 자동화
Node.js 서버 인스턴스 세팅 및 PM2를 이용한 서버 자동화 | Notion
이 글에서는 우분투 환경에서 Node.js 프로젝트를 세팅하고, pm2를 활용하여 서버를 자동화하는 과정을 단계별로 설명하겠습니다. 먼저, Node.js를 설치하고, git을 사용하여 프로젝트를 복제한 후,
msmspark.notion.site
배포 후 node main.js로 publish를 해 보니 admin page에서 잘 실행됐다는 로그가 찍혔어요.
아주 잘 작동하는 걸 확인했습니다. 😊
마무리
이렇게 생성 서버를 구축해 보았는데요. AI 기술과 서버 관리를 같이하면서 도전적이었지만, 그만큼 많이 배웠어요. 여러분도 이런 프로젝트에 도전해서 재미있는 AI 연동을 직접 경험해 보시길 바랍니다! 🌟👩💻👨💻
이상으로 GPT-4를 활용한 인공지능 데이터 캐싱 서버 구축 프로젝트에 대한 이야기를 마치겠습니다.
여러분의 소중한 피드백을 기다리고 있겠습니다!
비가 오는 날엔 ~
RainyCode를 찾아와
밤을 새워 기다릴게...반응형'Project > OpenList' 카테고리의 다른 글
Ubuntu 서버에서 Node.js 프로젝트 세팅하기 feat. PM2로 서버 자동화 (2) 2024.09.25 CLOVA-Studio로 인공지능 데이터 평가 서버 구축하기 feat. 데이터 품질 개선 알고리즘 (2) 2024.09.25 Pipe & Filter 아키텍처로 인공지능 데이터 캐싱 시스템 구축하기 (0) 2024.09.25 NestJS로 CLOVA Studio API 연동하기: 완벽 가이드 (1) 2024.09.25