-
[AI]내 프로젝트에서 AI 호출하기 - 구글 AI 스튜디오에서 API KEY 발급 과정개발(DEV)/개발-기타 2026. 4. 4. 16:41
카드 등록 없이 AI API를 무료로 사용하기
개인 프로젝트, 서비스에 AI 호출 기능을 추가해보고자 한다.
항상 드는 생각인 과금,, 혹은 무료로 사용하고 싶은데 어떻게 하면 좋을까?
OpenAI API는 소액이라도 결제가 필요하지만, Google Gemini API는 영구 무료 티어로 개발 및 테스트를 시작할 수 있다.
API 키 발급 방법부터 Node.js + React로 간단한 챗봇 만들기를 해보고자 한다.
(서비스 내 내용을 AI 호출 시 프롬프트로 보내는 방법으로, 챗봇이 아니더라도 AI 를 사용하는 기능이면 유사하다.)
1. OpenAI API vs Google Gemini API — 무료 사용 가능 여부 비교
AI 기능을 자신의 서비스나 프로젝트에 붙이고 싶을 때 가장 먼저 드는 고민은 비용 문제다. ChatGPT로 잘 알려진 OpenAI의 API와, Google이 제공하는 Gemini API는 무료 정책에서 큰 차이가 있다.
OpenAI API는 신규 계정 생성 시 약 $5(USD)의 무료 크레딧을 제공하지만, 이 크레딧은 3개월 이내에 소진되거나 만료된다. 이후에는 반드시 결제 수단(신용카드)을 등록해야 API 호출이 가능하다. 즉, 소규모 사이드 프로젝트나 개인 학습 용도라 하더라도 카드 등록 없이는 지속적인 API 사용이 불가능하다.
Google Gemini API는 다르다. Google AI Studio에서 발급한 API 키는 별도의 결제 수단 등록 없이도 일정 한도 내에서 영구적으로 무료로 사용할 수 있다. 개발 및 테스트 단계, 또는 트래픽이 낮은 소규모 서비스라면 무료 티어만으로도 충분히 운영이 가능한 수준이다.
구분 OpenAI API Google Gemini API 무료 사용 가능 여부 제한적 (5$ 크레딧) 영구 무료티어 무료 한도 5$ 크레딧 소진 후 즉시 유료 Flash: 10RPM / 500RPD / Flash-Lite: 15RPM/1000PRD 카드 등록 필요 필요함 불필요 최저가 모델 토큰 비용 $0.15 / 1M tokens (GPT-4o min) $0 (무료 티어 내에서) 무료 사용 가능 모델 $5 크레딧 내 일부 모델만 Gemini 2.5 Flash, Flash-Lite 등 위 표에서 핵심적인 차이는 카드 등록 없이 API 호출이 가능한가 여부다. OpenAI는 $5 크레딧 소진 이후 카드 없이는 호출 자체가 차단되지만, Google Gemini API는 무료 티어 범위 내에서 아무런 결제 정보 없이도 계속 사용 가능하다.
2. Google Gemini API 무료 티어 한도 상세
2026년 4월 기준, Google Gemini API 무료 티어에서 사용 가능한 주요 모델과 한도는 다음과 같다. 참고로 Gemini 2.0 Flash는 2026년 6월 1일자로 지원 종료가 예정되어 있으므로, 신규 프로젝트에서는 Gemini 2.5 Flash를 사용하는 것을 권장한다.

RPM은 분당 요청 수(Requests Per Minute), RPD는 일당 요청 수(Requests Per Day)를 의미한다. Gemini 2.5 Flash 기준으로 하루 최대 500회, 분당 10회까지 무료로 호출이 가능하다. 개인 프로젝트나 사내 소규모 도구 수준에서는 이 한도면 충분히 활용할 수 있다.
중요한 점은 RPD(일당 요청 수)가 태평양 표준시(PST) 자정을 기준으로 매일 초기화된다는 것이다. 한국 시간으로는 오전 9시(서머타임 적용 시 오전 8시)에 초기화된다고 볼 수 있다.
운영 트래픽이 증가하거나 더 높은 한도가 필요하다면, Google Cloud 결제를 연동하여 유료 Tier 1으로 전환하면 된다. 유료 전환 시 RPM이 대폭 상승하며 SLA(서비스 수준 협약)도 적용된다.
3. Google AI Studio에서 API 키 발급하는 방법
API 키 발급 절차는 매우 간단하다. Google 계정만 있으면 5분 이내에 완료할 수 있다.

순서 요약 발급 절차를 순서대로 정리하면 다음과 같다.
- aistudio.google.com 접속 후 Google 계정으로 로그인한다.
Google AI Studio
The fastest path from prompt to production with Gemini
aistudio.google.com
- 좌측 메뉴 또는 우측 상단에 있는 "Get API key" 버튼을 클릭한다.
- "Create API key" 버튼을 클릭하고, 연결할 Google Cloud 프로젝트를 선택하거나 새로 생성한다.
- 발급된 API 키를 복사하여 안전한 곳에 저장한다. 이 키는 다시 표시되지 않으므로 반드시 즉시 저장한다.
중요: API 키는 GitHub 등 공개 저장소에 절대 올리면 안 된다. 코드에 직접 하드코딩하지 말고, 반드시 환경변수(.env 파일)로 관리해야 한다. 키가 유출되면 타인이 내 한도를 소진하거나 유료 요금이 발생할 수 있다.









4. Node.js 프로젝트 환경 세팅
Node.js 환경에서 Gemini API를 사용하기 위해 필요한 패키지와 환경 설정을 준비한다.
4-1. 패키지 설치
터미널(Windows PowerShell 또는 명령 프롬프트)에서 아래 명령어를 실행하여 Google의 공식 Generative AI SDK와 환경변수 관리 패키지를 설치한다.
npm install @google/generative-ai dotenv4-2. 환경변수 설정 (.env 파일)
API 키를 코드에 직접 작성하는 것은 보안상 매우 위험하다. 서버 프로젝트 루트에 .env 파일을 생성하고 API 키를 저장한다. 이 프로젝트에서는
server/.env위치에 파일을 생성한다.# server/.env GEMINI_API_KEY=여기에_발급받은_API_키_입력Express.js 서버 진입점(
index.ts)의 최상단에서 dotenv를 로드하면 이후 모든 파일에서process.env.GEMINI_API_KEY로 키 값을 참조할 수 있다.// server/src/index.ts (최상단) import 'dotenv/config'; // 반드시 가장 먼저 로드해야 다른 모듈에서도 env 참조 가능 import express from 'express'; // ... 이하 생략4-3. .gitignore 설정
.env 파일이 Git에 포함되지 않도록 반드시 .gitignore에 추가한다. 대신
.env.example파일을 만들어 어떤 환경변수가 필요한지 팀원에게 안내한다.# .gitignore node_modules/ .env# .env.example (Git에 포함 — 실제 값은 절대 넣지 않음) GEMINI_API_KEY=여기에_발급받은_API_키_입력
5. 실전 적용 — MVC 패턴으로 AI 챗봇 서버 구현
실무 프로젝트에서는 API 호출 로직, HTTP 요청 처리, 타입 정의를 각각 분리하는 것이 유지보수에 유리하다. 이 프로젝트에서는 Express.js 서버에 MVC 패턴(Model-View-Controller)을 적용하여 역할을 명확히 분리했다.
파일 구조는 다음과 같다.
server/src/ ├── models/ │ └── ai.model.ts ← 타입/인터페이스 정의 (ChatMessage, ChatRequest, ChatResponse) ├── services/ │ └── ai.service.ts ← Gemini API 호출 로직 (비즈니스 로직) ├── controllers/ │ └── ai.controller.ts ← HTTP 요청/응답 처리 + 에러 핸들링 ├── routes/ │ └── ai.routes.ts ← 라우트 등록 (POST /api/ai/chat) └── index.ts ← 서버 진입점 (dotenv 로드 + 라우터 등록)5-1. 타입 정의 (ai.model.ts)
TypeScript의 인터페이스로 요청/응답 구조를 미리 정의해두면 오탈자나 타입 오류를 컴파일 단계에서 잡아낼 수 있다. 클라이언트와 서버가 주고받는 데이터 구조를 한 곳에서 관리한다.
// server/src/models/ai.model.ts /** 대화 메시지 한 건의 구조 (role: 발화자 / text: 내용) */ export interface ChatMessage { role: 'user' | 'model'; text: string; } /** 클라이언트 → 서버 요청 바디 */ export interface ChatRequest { message: string; // 현재 사용자 입력 history: ChatMessage[]; // 이전 대화 히스토리 } /** 서버 → 클라이언트 응답 바디 */ export interface ChatResponse { success: boolean; reply: string; // AI 응답 텍스트 model: string; // 사용된 모델명 tokensUsed?: { // 토큰 사용량 (선택) input: number; output: number; total: number; }; }5-2. AI 서비스 레이어 (ai.service.ts)
Gemini API 호출은 서비스 레이어에서만 담당한다. 컨트롤러는 HTTP 처리에만 집중하고, SDK 사용 방법이나 데이터 변환은 서비스 내부로 숨긴다. 특히 멀티턴 대화 구현의 핵심인
startChat()과 히스토리 형식 변환이 이 레이어에서 처리된다.// server/src/services/ai.service.ts import { GoogleGenerativeAI } from '@google/generative-ai'; import type { ChatMessage, ChatResponse } from '../models/ai.model.js'; const geminiClient = new GoogleGenerativeAI(process.env.GEMINI_API_KEY ?? ''); const GEMINI_MODEL_NAME = 'gemini-2.5-flash'; const geminiModel = geminiClient.getGenerativeModel({ model: GEMINI_MODEL_NAME }); export const aiService = { /** * 대화 히스토리를 기반으로 멀티턴 채팅 세션을 만들고 AI 응답을 반환합니다. * @param userMessage 현재 사용자 입력 * @param chatHistory 이전 대화 기록 */ sendMessage: async ( userMessage: string, chatHistory: ChatMessage[] ): Promise<ChatResponse> => { // Gemini SDK 형식으로 히스토리 변환: { role, text } → { role, parts: [{text}] } const formattedHistory = chatHistory.map((msg) => ({ role: msg.role, parts: [{ text: msg.text }], })); // 히스토리를 포함한 채팅 세션 시작 (이전 맥락 유지됨) const chatSession = geminiModel.startChat({ history: formattedHistory }); // 현재 메시지를 세션에 전송하고 응답 수신 const result = await chatSession.sendMessage(userMessage); const replyText = result.response.text(); // 토큰 사용량 추출 (무료 한도 모니터링용) const usageMeta = result.response.usageMetadata; const tokensUsed = usageMeta ? { input: usageMeta.promptTokenCount ?? 0, output: usageMeta.candidatesTokenCount ?? 0, total: usageMeta.totalTokenCount ?? 0 } : undefined; return { success: true, reply: replyText, model: GEMINI_MODEL_NAME, tokensUsed }; }, };멀티턴 대화의 핵심:
startChat({ history })에 이전 대화 기록을 넘겨주면 Gemini 모델이 앞선 맥락을 참고하여 응답한다. 클라이언트는 매 요청마다 전체 히스토리를 함께 전송하고, 서버는 상태를 저장하지 않는 무상태(stateless) 방식으로 동작한다.5-3. 컨트롤러 (ai.controller.ts)
컨트롤러는 HTTP 입출력만 담당한다. 입력값 유효성 검사, 서비스 호출, 에러 코드별 응답 분기를 처리한다. 비즈니스 로직(Gemini 호출)은 서비스에 위임하므로 컨트롤러 코드는 간결하게 유지된다.
// server/src/controllers/ai.controller.ts import type { Request, Response } from 'express'; import { aiService } from '../services/ai.service.js'; import type { ChatRequest } from '../models/ai.model.js'; export const aiController = { /** POST /api/ai/chat */ chat: async (req: Request, res: Response) => { const { message, history = [] }: ChatRequest = req.body; // 입력값 검증 if (!message || message.trim() === '') { return res.status(400).json({ success: false, error: '메시지를 입력해주세요.' }); } try { const chatResponse = await aiService.sendMessage(message, history); res.json(chatResponse); } catch (error: any) { // 429: 무료 티어 한도 초과 if (error.status === 429) { return res.status(429).json({ success: false, error: 'API 요청 한도를 초과했습니다. 잠시 후 다시 시도해주세요.', }); } res.status(500).json({ success: false, error: '서버 오류가 발생했습니다.' }); } }, };5-4. 라우트 등록 (ai.routes.ts → index.ts)
라우트 파일에서 컨트롤러를 연결하고, 서버 진입점(index.ts)에 라우터를 등록한다.
// server/src/routes/ai.routes.ts import { Router } from 'express'; import { aiController } from '../controllers/ai.controller.js'; const router = Router(); router.post('/chat', aiController.chat); // POST /api/ai/chat export default router;// server/src/index.ts (라우터 등록 부분) import 'dotenv/config'; // 최상단: 환경변수 로드 import aiRoutes from './routes/ai.routes.js'; // ... app.use('/api/ai', aiRoutes); // /api/ai/chat 엔드포인트 활성화
6. 프론트엔드 — React 챗봇 페이지 구현
프론트엔드도 역할을 분리하여 구현한다. API 호출 함수는 별도 파일로 분리하고, 말풍선 UI는 독립 컴포넌트로 만들어 재사용성을 높인다.
client/src/ ├── api/ │ └── chatApi.ts ← API 레이어 (axios 기반 서버 통신) ├── components/ │ └── ChatBubble.tsx ← 말풍선 컴포넌트 (user/model 구분 렌더링) └── pages/ └── ChatPage.tsx ← 챗봇 페이지 (대화 상태 관리 + 레이아웃)6-1. API 레이어 (chatApi.ts)
서버 통신 코드를 페이지 컴포넌트 밖으로 분리한다. Vite의 프록시 설정(
vite.config.ts의/api → localhost:4000)을 통해 개발 환경에서 포트 충돌 없이 동작한다.// client/src/api/chatApi.ts import axios from 'axios'; export interface ChatMessage { role: 'user' | 'model'; text: string; } export interface ChatResponse { success: boolean; reply: string; model: string; tokensUsed?: { input: number; output: number; total: number }; } const chatApiClient = axios.create({ baseURL: '/api/ai' }); /** * Gemini AI에 메시지를 전송하고 응답을 받습니다. * @param message 현재 사용자 메시지 * @param history 이전 대화 히스토리 */ export const sendChatMessage = (message: string, history: ChatMessage[]) => chatApiClient.post<ChatResponse>('/chat', { message, history });6-2. 챗봇 페이지의 대화 상태 관리 (ChatPage.tsx 핵심 로직)
대화 히스토리를 React 상태(
useState)로 관리하여 멀티턴 대화를 구현한다. 메시지 전송 시 사용자 메시지를 UI에 즉시 반영하고, 서버 응답을 받으면 AI 메시지를 히스토리에 추가한다.// client/src/pages/ChatPage.tsx (핵심 로직 발췌) const [chatHistory, setChatHistory] = useState<ChatMessage[]>([]); const [isWaitingForReply, setIsWaitingForReply] = useState(false); const handleSendMessage = async () => { const trimmedInput = inputText.trim(); if (!trimmedInput || isWaitingForReply) return; // 1. 사용자 메시지를 히스토리에 즉시 추가 (UI 즉시 반영) const userMessage: ChatMessage = { role: 'user', text: trimmedInput }; const updatedHistory = [...chatHistory, userMessage]; setChatHistory(updatedHistory); setInputText(''); setIsWaitingForReply(true); try { // 2. 이전 히스토리 포함하여 서버에 요청 // (history에서 마지막 사용자 메시지는 message 파라미터로 따로 전송) const response = await chatApi.sendChatMessage(trimmedInput, chatHistory); // 3. AI 응답을 히스토리에 추가 const aiMessage: ChatMessage = { role: 'model', text: response.data.reply }; setChatHistory((prev) => [...prev, aiMessage]); } catch (error: any) { setErrorMessage(error.response?.data?.error ?? '오류가 발생했습니다.'); } finally { setIsWaitingForReply(false); } };


7. 전체 흐름도 및 주의사항
7-1. 전체 데이터 흐름 요약
이 프로젝트의 AI 챗봇은 다음 순서로 동작한다.
- 사용자 입력 → ChatPage.tsx의 textarea에서 Enter 또는 전송 버튼 클릭
- 상태 업데이트 → chatHistory에 사용자 메시지 즉시 추가, 로딩 표시 활성화
- API 호출 → chatApi.ts가
POST /api/ai/chat으로 message + history 전송 - 라우팅 → ai.routes.ts → ai.controller.ts로 요청 전달
- 서비스 처리 → ai.service.ts에서 히스토리 형식 변환 후 Gemini SDK 호출
- Gemini 응답 →
gemini-2.5-flash모델이 대화 맥락을 고려한 응답 생성 - 응답 반환 → { success, reply, model, tokensUsed } 형태로 클라이언트에 전달
- UI 갱신 → chatHistory에 AI 메시지 추가, ChatBubble 컴포넌트로 렌더링
7-2. 무료 티어 사용 시 주의사항 정리
무료 티어를 사용할 때 반드시 알아두어야 할 사항들이 있다. 첫째, 무료 티어에서는 입력한 데이터가 Google의 모델 학습에 활용될 수 있다. 개인정보나 민감한 업무 데이터를 프롬프트에 포함하지 않도록 주의해야 한다. 민감 데이터를 다루어야 한다면 유료 플랜으로 전환하고 데이터 처리 설정을 별도로 확인해야 한다.
둘째, 한도 초과 시 HTTP 429 에러(Too Many Requests) - 너무 긴 프롬프트 or 동시에 많은 요청등도 포함가 발생한다. 이 프로젝트에서는 컨트롤러(ai.controller.ts)에서 429 에러를 감지해 사용자에게 안내 메시지를 반환하고, 프론트엔드(ChatPage.tsx)에서는 노란색 경고 박스로 표시한다.
셋째, Google은 정책 변경을 통해 무료 한도를 조정할 수 있다. 실제 운영 서비스라면 한도 변경에 대비하여 유료 플랜 전환 시점을 미리 계획해두는 것이 안전하다.
마지막으로, API 키는 서버의
.env파일로 관리하고 절대 코드에 하드코딩하거나 공개 저장소에 올리지 않아야 한다. 키 값이 필요한 환경에서는.env.example을 참고하여 직접.env를 생성한다. 만약 키가 유출되었다면 즉시 Google AI Studio에서 해당 키를 삭제하고 새로 발급받아야 한다.7-3. 사용량 조회
메뉴 -> 사용량에서 프로젝트 별 사용량 조회 가능 (오류 발생에 대한 부분도 조회 가능)

참고)
'개발(DEV) > 개발-기타' 카테고리의 다른 글
[ThreeJS]웹 브라우저에서 3D 게임을? Three.js로 구현하는 인터랙티브 웹 세상 (0) 2026.04.15 [패키지매니저]npm vs yarn vs pnpm: 나에게 맞는 패키지 매니저 선택 가이드 (동작 원리 포함) (0) 2026.04.04 [Electron]Electron 데스크탑 애플리케이션 만들기, 배포 및 GitHub 자동 업데이트 방법 까지 (0) 2026.04.01 실시간 동시 편집 에디터 만들기 OT방식으로 구현해보기 (0) 2026.04.01 템플릿 엔진 머스테치(Mustache) 란? (0) 2026.03.24