# AI로 채팅 어시스턴트 만들기
스타트렉에서 승무원들이 우주선 컴퓨터와 편하게 대화하며 복잡한 질문을 하고 깊이 있는 답변을 받던 장면을 기억하시나요? 1960년대에는 순수한 공상과학처럼 보였던 것이 이제 여러분이 이미 알고 있는 웹 기술을 사용해 만들 수 있는 것이 되었습니다.
이번 수업에서는 HTML, CSS, JavaScript, 그리고 백엔드 통합을 통해 AI 채팅 어시스턴트를 만들 것입니다. 지금까지 배운 동일한 기술이 문맥을 이해하고 의미 있는 응답을 생성할 수 있는 강력한 AI 서비스에 어떻게 연결되는지 발견하게 될 것입니다.
AI는 단순히 정보를 찾아주는 것뿐 아니라, 방대한 도서관에 접근해 질문에 맞게 정보를 종합하여 일관된 답변을 제공하는 것과 같습니다. 수천 페이지를 검색하는 대신 직접적이고 문맥에 맞는 응답을 얻게 됩니다.
통합은 익숙한 웹 기술을 함께 작동시키는 방식으로 이루어집니다. HTML은 채팅 인터페이스를 만들고, CSS는 시각적 디자인을 담당하며, JavaScript가 사용자 상호작용을 관리하고, 백엔드 API가 모든 것을 AI 서비스에 연결합니다. 이것은 마치 오케스트라의 여러 섹션이 함께 교향곡을 만드는 것과 비슷합니다.
본질적으로 우리는 자연스러운 인간 소통과 기계 처리 간의 다리를 구축하는 것입니다. AI 서비스 통합의 기술적 구현과 상호작용을 직관적으로 느끼게 하는 디자인 패턴을 모두 배우게 됩니다.
수업이 끝나면 AI 통합은 신비로운 과정이 아니라 여러분이 다룰 수 있는 또 다른 API처럼 느껴질 것입니다. 여러분이 배우던 웹 개발 원칙을 사용하여 ChatGPT와 Claude 같은 애플리케이션을 구동하는 기본 패턴들을 이해하게 될 것입니다.
## ⚡ 다음 5분 내 할 수 있는 것
**바쁜 개발자를 위한 빠른 시작 경로**
```mermaid
flowchart LR
A[⚡ 5분] --> B[GitHub 토큰 받기]
B --> C[AI 플레이그라운드 테스트]
C --> D[파이썬 코드 복사]
D --> E[AI 응답 보기]
```
- **1분차**: [GitHub Models Playground](https://github.com/marketplace/models/azure-openai/gpt-4o-mini/playground)에 방문해 개인 액세스 토큰 생성
- **2분차**: 플레이그라운드 인터페이스에서 AI 상호작용 직접 테스트
- **3분차**: "Code" 탭 클릭 후 Python 코드 조각 복사
- **4분차**: 로컬에서 토큰과 함께 코드 실행: `GITHUB_TOKEN=your_token python test.py`
- **5분차**: 자신의 코드에서 처음 AI 응답 생성되는 것 확인
**빠른 테스트 코드**:
```python
import os
from openai import OpenAI
client = OpenAI(
base_url="https://models.github.ai/inference",
api_key="your_token_here"
)
response = client.chat.completions.create(
messages=[{"role": "user", "content": "Hello AI!"}],
model="openai/gpt-4o-mini"
)
print(response.choices[0].message.content)
```
**왜 이것이 중요한가**: 5분 안에 프로그래밍 AI 상호작용의 마법을 경험할 수 있습니다. 이것이 여러분이 사용하는 모든 AI 애플리케이션의 기본 빌딩 블록입니다.
완성된 프로젝트는 다음과 같은 모습입니다:

## 🗺️ AI 애플리케이션 개발을 통한 학습 여정
```mermaid
journey
title 웹 개발에서 AI 통합으로
section AI 기초 이해하기
생성형 AI 개념 발견하기: 4: You
GitHub 모델 플랫폼 탐색하기: 6: You
AI 매개변수 및 프롬프트 마스터하기: 8: You
section 백엔드 통합
파이썬 API 서버 구축하기: 5: You
AI 함수 호출 구현하기: 7: You
비동기 작업 처리하기: 8: You
section 프론트엔드 개발
현대적 채팅 인터페이스 만들기: 6: You
실시간 상호작용 마스터하기: 8: You
반응형 사용자 경험 구축하기: 9: You
section 전문적 응용
완전한 AI 시스템 배포하기: 7: You
성능 패턴 최적화하기: 8: You
프로덕션 준비된 앱 만들기: 9: You
```
**여정의 목표**: 이 수업이 끝나면 ChatGPT, Claude, Google Bard 같은 현대 AI 어시스턴트를 지원하는 동일한 기술과 패턴을 활용해 완전한 AI 기반 애플리케이션을 구축하게 될 것입니다.
## AI 이해하기: 신비에서 숙련으로
코드를 보기 전에 우리가 다루는 것이 무엇인지 이해해봅시다. API를 사용해본 적이 있다면 기본 패턴을 알 것입니다: 요청을 보내고 응답을 받는다.
AI API도 유사한 구조지만 데이터베이스에서 미리 저장된 데이터를 가져오는 대신, 방대한 문서에서 학습한 패턴을 바탕으로 새 응답을 생성합니다. 이는 도서관 카탈로그 시스템과 여러 출처에서 정보를 종합할 수 있는 박식한 사서의 차이와 비슷합니다.
### "생성 AI(Generative AI)"란 무엇인가?
로제타 스톤이 학자들이 이집트 상형문자를 이해할 수 있도록 알려진 언어와 비교해 패턴을 찾았던 방법을 생각해보세요. AI 모델도 비슷하게 작동합니다 – 방대한 텍스트에서 패턴을 찾아 언어 작동 방식을 이해하고 그 패턴을 이용해 새 질문에 적절한 답변을 생성합니다.
**간단한 비교로 설명하자면:**
- **전통적 데이터베이스**: 출생 증명서처럼 매번 정확히 같은 문서를 요청하는 것
- **검색 엔진**: 사서에게 고양이 관련 책을 찾아달라고 하는 것 – 가능한 자료를 보여줌
- **생성 AI**: 박식한 친구에게 고양이에 대해 물어보는 것 – 그들의 말로 여러분이 궁금해하는 내용을 맞춤 설명
```mermaid
graph LR
A[당신의 질문] --> B[AI 모델]
B --> C[패턴 인식]
C --> D[콘텐츠 생성]
D --> E[맥락적 응답]
F[학습 데이터
책, 기사, 웹] --> B
```
### AI 모델이 배우는 방식 (간단 설명)
AI 모델은 책, 기사, 대화 등 텍스트가 담긴 방대한 데이터셋에 노출되어 학습합니다. 학습 과정에서 다음의 패턴을 파악합니다:
- 글 쓰기에서 생각이 구성되는 방식
- 함께 자주 등장하는 단어들
- 대화가 일반적으로 흘러가는 방식
- 공식 및 비공식 대화 간 문맥 차이
**고고학자가 고대 언어를 해독하는 과정과 비슷합니다**: 수천 개 예시를 분석해 문법, 어휘, 문화적 배경을 이해하고, 그렇게 얻은 패턴으로 새로운 텍스트 해석 가능해집니다.
### 왜 GitHub Models인가?
우리는 실용적인 이유로 GitHub Models를 사용합니다 – 자체 AI 인프라를 구축하지 않고도(솔직히 지금은 구축하고 싶지 않을 겁니다!) 엔터프라이즈급 AI에 접근할 수 있기 때문입니다. 마치 날씨 API를 쓰는 것처럼 무수히 많은 기상 관측소를 직접 세우려 하지 않는 것과 같습니다.
사실상 "AI 서비스로서 제공"되며, 가장 좋은 점은 무료로 시작할 수 있어서 큰 비용 걱정 없이 실험할 수 있다는 점입니다.
```mermaid
graph LR
A[프론트엔드 채팅 UI] --> B[백엔드 API]
B --> C[GitHub 모델 API]
C --> D[AI 모델 처리]
D --> C
C --> B
B --> A
```
GitHub Models를 백엔드 통합에 사용하여 개발자 친화적인 인터페이스로 전문 AI 기능에 접근합니다. [GitHub Models Playground](https://github.com/marketplace/models/azure-openai/gpt-4o-mini/playground)는 다양한 AI 모델을 체험하고 특성을 이해할 수 있는 테스트 환경입니다.
## 🧠 AI 애플리케이션 개발 생태계
```mermaid
mindmap
root((AI 개발))
Understanding AI
Generative Models
패턴 인식
콘텐츠 생성
맥락 이해
응답 합성
AI Parameters
온도 조절
토큰 제한
Top-p 필터링
시스템 프롬프트
Backend Architecture
API Integration
GitHub 모델
인증
요청 처리
오류 관리
Python Infrastructure
FastAPI 프레임워크
비동기 작업
환경 보안
CORS 구성
Frontend Experience
Chat Interface
실시간 업데이트
메시지 기록
사용자 피드백
로딩 상태
Modern Web Tech
ES6 클래스
Async/Await
DOM 조작
이벤트 처리
Professional Patterns
Security Best Practices
토큰 관리
입력 검증
XSS 방지
에러 경계
Production Readiness
성능 최적화
반응형 디자인
접근성
테스트 전략
```
**핵심 원칙**: AI 애플리케이션 개발은 전통적인 웹 개발 기술과 AI 서비스 통합을 결합해 자연스럽고 반응성 높은 지능형 애플리케이션을 만듭니다.

**플레이그라운드의 유용함 요점:**
- GPT-4o-mini, Claude 등 무료로 다양한 AI 모델 사용해보기
- 코딩 전에 아이디어와 프롬프트 미리 테스트
- 자주 사용하는 프로그래밍 언어로 바로 쓸 수 있는 코드 스니펫 획득
- 창의성 수준, 응답 길이 같은 설정을 조정해 출력 결과 차이 확인
조금 놀아본 뒤 “Code” 탭을 클릭하고 구현할 프로그래밍 언어를 선택해 필요한 코드를 얻으세요.

## Python 백엔드 통합 설정하기
이제 Python을 사용해 AI 통합을 구현해 보겠습니다. Python은 간결한 문법과 강력한 라이브러리 덕분에 AI 애플리케이션에 매우 적합합니다. GitHub Models 플레이그라운드에서 제공하는 코드를 시작으로 재사용 가능하고 프로덕션 준비된 함수로 리팩터링할 것입니다.
### 기본 구현 이해하기
플레이그라운드에서 Python 코드를 가져오면 다음과 비슷한 모양일 것입니다. 처음에는 복잡해 보여도 걱정 말고 하나씩 살펴봅시다:
```python
"""Run this model in Python
> pip install openai
"""
import os
from openai import OpenAI
# 모델에 인증하려면 GitHub 설정에서 개인 액세스 토큰(PAT)을 생성해야 합니다.
# 여기 지침을 따라 PAT 토큰을 생성하세요: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens
client = OpenAI(
base_url="https://models.github.ai/inference",
api_key=os.environ["GITHUB_TOKEN"],
)
response = client.chat.completions.create(
messages=[
{
"role": "system",
"content": "",
},
{
"role": "user",
"content": "What is the capital of France?",
}
],
model="openai/gpt-4o-mini",
temperature=1,
max_tokens=4096,
top_p=1
)
print(response.choices[0].message.content)
```
**이 코드에서 일어나는 일:**
- **필요한 도구들 가져오기**: `os`는 환경 변수 읽기에, `OpenAI`는 AI와 대화하는 데 사용
- **OpenAI 클라이언트 설정**: OpenAI 직접이 아닌 GitHub AI 서버 지점으로
- **인증**: 특수 GitHub 토큰으로 인증 (곧 설명 예정)
- **대화 구성**: 서로 다른 "역할"을 가진 메시지로 대화 무대 세팅
- **요청 보내기**: 미세 조정 매개변수를 포함해 AI에 요청 전송
- **응답 추출**: 응답 데이터에서 실제 텍스트만 꺼내기
### 메시지 역할 이해하기: AI 대화 프레임워크
AI 대화는 명확한 목적이 있는 몇 가지 "역할" 구조를 사용합니다:
```python
messages=[
{
"role": "system",
"content": "You are a helpful assistant who explains things simply."
},
{
"role": "user",
"content": "What is machine learning?"
}
]
```
**연극 연출을 떠올려보세요:**
- **시스템 역할**: 배우를 위한 무대 지시문처럼 AI가 어떻게 행동하고, 어떤 성격을 가지며, 어떻게 응답할지 지시
- **사용자 역할**: 애플리케이션 사용자가 실제 묻는 질문 또는 메시지
- **어시스턴트 역할**: AI의 답변 (사용자가 보내지는 않지만 대화 기록에 포함됨)
**실제 상황 비유**: 파티에서 친구를 소개하는 상황:
- **시스템 메시지**: "이 친구 사라는 의학을 쉽게 설명하는 능력이 뛰어난 의사예요."
- **사용자 메시지**: "백신이 어떻게 작동하는지 설명해 줄래?"
- **어시스턴트 응답**: 사라가 친절한 의사처럼 답변, 변호사나 요리사처럼 말하지 않음
### AI 매개변수 이해하기: 응답 행동 미세 조정
AI API 호출에서 수치 매개변수는 모델이 응답을 생성하는 방식을 제어합니다. 이 설정을 통해 다양한 사용 사례에 맞게 AI 행동을 조정할 수 있습니다:
#### 온도(Temperature, 0.0~2.0): 창의성 다이얼
**역할**: AI 응답의 창의성 또는 예측 가능성을 제어합니다.
**재즈 뮤지션의 즉흥 연주 강도에 비유:**
- **온도 0.1**: 매번 같은 멜로디 연주 (예측 가능 매우 높음)
- **온도 0.7**: 적절히 변주하며 인식 가능 유지 (균형 잡힌 창의성)
- **온도 1.5**: 예측 불가능한 실험적 재즈 (창의성 매우 높음)
```python
# 매우 예측 가능한 응답 (사실 질문에 좋음)
response = client.chat.completions.create(
messages=[{"role": "user", "content": "What is 2+2?"}],
temperature=0.1 # 거의 항상 "4"라고 말함
)
# 창의적인 응답 (브레인스토밍에 좋음)
response = client.chat.completions.create(
messages=[{"role": "user", "content": "Write a creative story opening"}],
temperature=1.2 # 독특하고 예상치 못한 이야기를 생성함
)
```
#### 최대 토큰 수(Max Tokens, 1~4096+): 응답 길이 제한기
**역할**: AI 응답의 최대 길이를 설정합니다.
**토큰은 대략 단어와 비슷한 단위** (영어 기준 약 1토큰 = 0.75 단어):
- **max_tokens=50**: 짧고 간결 (문자 메시지 수준)
- **max_tokens=500**: 한두 문단 정도
- **max_tokens=2000**: 상세한 설명과 예시 포함 가능
```python
# 짧고 간결한 답변
response = client.chat.completions.create(
messages=[{"role": "user", "content": "Explain JavaScript"}],
max_tokens=100 # 간단한 설명을 강제함
)
# 자세하고 포괄적인 답변
response = client.chat.completions.create(
messages=[{"role": "user", "content": "Explain JavaScript"}],
max_tokens=1500 # 예제를 포함한 자세한 설명 허용
)
```
#### Top_p (0.0~1.0): 집중 매개변수
**역할**: AI가 가장 가능성 높은 응답에 얼마나 집중할지 제어합니다.
**거대한 어휘 사전에서 단어별 출현 확률 순으로 정렬된 모습을 상상:**
- **top_p=0.1**: 가장 가능성 높은 상위 10% 단어만 고려 (매우 집중)
- **top_p=0.9**: 상위 90% 단어 고려 (더 창의적)
- **top_p=1.0**: 모든 단어 고려 (최대 다양성)
**예시: "The sky is usually..." 질문 시**
- 낮은 top_p: 거의 항상 "blue"라고 답변
- 높은 top_p: "blue", "cloudy", "vast", "changing", "beautiful" 등 다양한 답변 가능
### 모든 것을 종합하기: 다양한 사용 사례 별 매개변수 조합
```python
# 사실적이고 일관된 답변을 위해 (예: 문서화 봇)
factual_params = {
"temperature": 0.2,
"max_tokens": 300,
"top_p": 0.3
}
# 창의적인 글쓰기 지원을 위해
creative_params = {
"temperature": 1.1,
"max_tokens": 1000,
"top_p": 0.9
}
# 대화식이고 도움이 되는 응답을 위해 (균형 잡힌)
conversational_params = {
"temperature": 0.7,
"max_tokens": 500,
"top_p": 0.8
}
```
```mermaid
quadrantChart
title AI 매개변수 최적화 매트릭스
x-axis 낮은 창의성 --> 높은 창의성
y-axis 짧은 응답 --> 긴 응답
quadrant-1 창의적 콘텐츠
quadrant-2 상세 분석
quadrant-3 빠른 사실
quadrant-4 대화형 AI
Documentation Bot: [0.2, 0.3]
Customer Service: [0.4, 0.4]
General Assistant: [0.7, 0.5]
Creative Writer: [0.9, 0.9]
Brainstorming Tool: [0.8, 0.8]
```
**매개변수가 중요한 이유 이해하기**: 응용 프로그램마다 필요한 응답 유형이 다릅니다. 고객 서비스 봇은 일관되고 사실적인 응답(낮은 온도)이 필요하지만, 창의적 글쓰기 도우미는 상상력 많고 다양한 응답(높은 온도)이 적합합니다. 이런 매개변수를 이해하면 AI의 성격과 응답 스타일을 조절할 수 있습니다.
```
**Here's what's happening in this code:**
- **We import** the tools we need: `os` for reading environment variables and `OpenAI` for talking to the AI
- **We set up** the OpenAI client to point to GitHub's AI servers instead of OpenAI directly
- **We authenticate** using a special GitHub token (more on that in a minute!)
- **We structure** our conversation with different "roles" – think of it like setting the scene for a play
- **We send** our request to the AI with some fine-tuning parameters
- **We extract** the actual response text from all the data that comes back
> 🔐 **Security Note**: Never hardcode API keys in your source code! Always use environment variables to store sensitive credentials like your `GITHUB_TOKEN`.
### Creating a Reusable AI Function
Let's refactor this code into a clean, reusable function that we can easily integrate into our web application:
```python
import asyncio
from openai import AsyncOpenAI
# Use AsyncOpenAI for better performance
client = AsyncOpenAI(
base_url="https://models.github.ai/inference",
api_key=os.environ["GITHUB_TOKEN"],
)
async def call_llm_async(prompt: str, system_message: str = "You are a helpful assistant."):
"""
Sends a prompt to the AI model asynchronously and returns the response.
Args:
prompt: The user's question or message
system_message: Instructions that define the AI's behavior and personality
Returns:
str: The AI's response to the prompt
"""
try:
response = await client.chat.completions.create(
messages=[
{
"role": "system",
"content": system_message,
},
{
"role": "user",
"content": prompt,
}
],
model="openai/gpt-4o-mini",
temperature=1,
max_tokens=4096,
top_p=1
)
return response.choices[0].message.content
except Exception as e:
logger.error(f"AI API error: {str(e)}")
return "I'm sorry, I'm having trouble processing your request right now."
# Backward compatibility function for synchronous calls
def call_llm(prompt: str, system_message: str = "You are a helpful assistant."):
"""Synchronous wrapper for async AI calls."""
return asyncio.run(call_llm_async(prompt, system_message))
```
**향상된 함수 이해하기:**
- 사용자 프롬프트와 선택적 시스템 메시지 두 매개변수 수용
- 일반 어시스턴트 동작을 위한 기본 시스템 메시지 제공
- Python 타입 힌트로 코드 문서화 품질 향상
- 함수 목적과 매개변수 상세 설명이 포함된 docstring 포함
- 응답 내용만 반환해 웹 API에서 사용하기 쉽게 설계
- 일관된 AI 동작을 위한 동일 모델 매개변수 유지
### 시스템 프롬프트의 마법: AI 성격 프로그래밍
매개변수가 AI 사고 방식을 제어한다면 시스템 프롬프트는 AI가 자신을 누구로 생각하는지를 제어합니다. AI를 다루면서 가장 흥미로운 부분 중 하나로, AI에 전체 성격, 전문성 수준, 의사소통 스타일을 부여하는 것과 같습니다.
**시스템 프롬프트는 연기자를 배역에 맞게 캐스팅하는 것과 같습니다**: 한 명의 일반 어시스턴트 대신 상황별 전문화를 만들어낼 수 있습니다. 인내심 많은 선생님? 창의적 브레인스토밍 파트너? 현실적인 비즈니스 고문? 시스템 프롬프트만 바꾸면 됩니다!
#### 시스템 프롬프트가 강력한 이유
흥미로운 점은 AI 모델이 다양한 역할과 전문성을 가진 대화를 너무나 많이 학습했다는 것입니다. AI에 특정 역할을 주면 배운 모든 패턴을 불러오는 스위치를 켜는 것과 같습니다.
**AI의 메소드 연기와 같습니다**: 배우에게 “당신은 현명한 교수”라고 말하면 자세, 어휘, 동작을 즉시 조절하는 것처럼 AI도 언어 패턴을 비슷하게 조절합니다.
#### 효과적인 시스템 프롬프트 작성법: 예술과 과학
**훌륭한 시스템 프롬프트의 구성 요소:**
1. **역할/정체성**: AI가 누구인가?
2. **전문성**: 무엇을 알고 있는가?
3. **의사소통 스타일**: 어떻게 말하는가?
4. **구체적 지시사항**: 무엇에 집중해야 하는가?
```python
# ❌ 모호한 시스템 프롬프트
"You are helpful."
# ✅ 상세하고 효과적인 시스템 프롬프트
"You are Dr. Sarah Chen, a senior software engineer with 15 years of experience at major tech companies. You explain programming concepts using real-world analogies and always provide practical examples. You're patient with beginners and enthusiastic about helping them understand complex topics."
```
#### 문맥을 포함한 시스템 프롬프트 예시
서로 다른 시스템 프롬프트가 완전히 다른 AI 성격을 만들어내는 모습을 봅시다:
```python
# 예제 1: 참을성 있는 교사
teacher_prompt = """
You are an experienced programming instructor who has taught thousands of students.
You break down complex concepts into simple steps, use analogies from everyday life,
and always check if the student understands before moving on. You're encouraging
and never make students feel bad for not knowing something.
"""
# 예제 2: 창의적인 협력자
creative_prompt = """
You are a creative writing partner who loves brainstorming wild ideas. You're
enthusiastic, imaginative, and always build on the user's ideas rather than
replacing them. You ask thought-provoking questions to spark creativity and
offer unexpected perspectives that make stories more interesting.
"""
# 예제 3: 전략적 비즈니스 고문
business_prompt = """
You are a strategic business consultant with an MBA and 20 years of experience
helping startups scale. You think in frameworks, provide structured advice,
and always consider both short-term tactics and long-term strategy. You ask
probing questions to understand the full business context before giving advice.
"""
```
#### 시스템 프롬프트의 효과 체험하기
같은 질문에 다양한 시스템 프롬프트를 적용해 극적인 차이를 확인해 봅니다:
**질문**: "내 웹 앱에서 사용자 인증을 어떻게 처리하나요?"
```python
# 교사 프롬프트와 함께:
teacher_response = call_llm(
"How do I handle user authentication in my web app?",
teacher_prompt
)
# 일반적인 응답: "좋은 질문입니다! 인증을 간단한 단계로 나눠 보겠습니다.
# 마치 나이트클럽 문지기가 신분증을 확인하는 것처럼 생각해 보세요..."
# 비즈니스 프롬프트와 함께:
business_response = call_llm(
"How do I handle user authentication in my web app?",
business_prompt
)
# 일반적인 응답: "전략적 관점에서 인증은 사용자
# 신뢰와 규제 준수에 매우 중요합니다. 보안,
# 사용자 경험, 확장성을 고려한 프레임워크를 설명해 드리겠습니다..."
```
#### 고급 시스템 프롬프트 기법
**1. 문맥 설정**: AI에 배경 정보를 제공하기
```python
system_prompt = """
You are helping a junior developer who just started their first job at a startup.
They know basic HTML/CSS/JavaScript but are new to backend development and databases.
Be encouraging and explain things step-by-step without being condescending.
"""
```
**2. 출력 형식**: AI에게 응답 구조 지시하기
```python
system_prompt = """
You are a technical mentor. Always structure your responses as:
1. Quick Answer (1-2 sentences)
2. Detailed Explanation
3. Code Example
4. Common Pitfalls to Avoid
5. Next Steps for Learning
"""
```
**3. 제약 조건 설정**: AI가 하지 말아야 할 일 정의하기
```python
system_prompt = """
You are a coding tutor focused on teaching best practices. Never write complete
solutions for the user - instead, guide them with hints and questions so they
learn by doing. Always explain the 'why' behind coding decisions.
"""
```
#### 채팅 어시스턴트에서 이것이 중요한 이유
시스템 프롬프트를 이해하면 특화된 AI 어시스턴트를 만들 수 있는 놀라운 힘을 얻습니다:
- **고객 서비스 봇**: 도움이 되고, 참을성 있으며, 정책을 인지함
- **학습 튜터**: 격려하고, 단계별로, 이해도를 확인함
- **창의적 파트너**: 상상력이 풍부하고, 아이디어를 확장하며, "만약에?" 질문을 던짐
- **기술 전문가**: 정확하고, 상세하며, 보안에 신경씀
**핵심 통찰**: 단순히 AI API를 호출하는 것이 아니라, 특정 사용 사례에 맞춘 맞춤형 AI 성격을 만드는 것입니다. 이것이 현대 AI 애플리케이션이 일반적이지 않고 맞춤형이며 유용하게 느껴지는 이유입니다.
### 🎯 교육 점검: AI 성격 프로그래밍
**잠시 멈추고 반성하기**: 시스템 프롬프트를 통해 AI 성격을 프로그래밍하는 법을 방금 배웠습니다. 이것은 현대 AI 애플리케이션 개발의 기본 기술입니다.
**간단한 자기평가**:
- 시스템 프롬프트가 일반 사용자 메시지와 어떻게 다른지 설명할 수 있나요?
- temperature와 top_p 매개변수의 차이는 무엇인가요?
- 특정 사용 사례(예: 코딩 튜터)를 위한 시스템 프롬프트를 어떻게 만들겠나요?
**실제 연관성**: 배운 시스템 프롬프트 기법은 GitHub Copilot의 코딩 지원부터 ChatGPT의 대화형 인터페이스까지 모든 주요 AI 애플리케이션에서 사용됩니다. 당신은 주요 기술 기업 AI 제품팀이 사용하는 동일한 패턴을 익히고 있습니다.
**도전 질문**: 초보자와 전문가처럼 사용자 유형별로 다른 AI 성격을 어떻게 설계할 수 있을까요? 동일한 AI 모델이 프롬프트 엔지니어링을 통해 다양한 대상을 어떻게 지원할 수 있을지 고민해 보세요.
## FastAPI로 웹 API 구축하기: 고성능 AI 통신 허브
이제 프론트엔드를 AI 서비스와 연결하는 백엔드를 구축해 봅시다. 모던 Python 프레임워크인 FastAPI를 사용하여 AI 애플리케이션용 API를 빌드할 것입니다.
FastAPI는 이 프로젝트에 다음과 같은 장점이 있습니다: 동시 요청을 처리하는 내장 비동기 지원, 자동 API 문서 생성, 뛰어난 성능. FastAPI 서버는 프론트엔드 요청을 받으면 AI 서비스와 통신하고 포맷된 응답을 반환하는 중간자 역할을 합니다.
### AI 애플리케이션에 FastAPI를 사용하는 이유?
"프론트엔드 자바스크립트에서 직접 AI를 호출하면 안 되나요?" 혹은 "Flask나 Django 대신 FastAPI를 쓰는 이유가 뭐죠?"라는 질문이 떠오릅니다. 좋은 질문입니다!
**FastAPI가 우리가 만드는 것에 완벽한 이유는 다음과 같습니다:**
- **기본적으로 비동기**: 여러 AI 요청을 동시에 처리해 지체되지 않음
- **자동 문서화**: `/docs` 경로에서 아름답고 인터랙티브한 API 문서 페이지를 무료로 제공
- **내장 검증**: 문제가 생기기 전에 오류를 잡음
- **번개처럼 빠름**: 가장 빠른 Python 프레임워크 중 하나
- **최신 Python**: 최신 기능과 문법을 모두 활용
**그리고 백엔드가 필요한 이유는 다음과 같습니다:**
**보안**: AI API 키는 비밀번호와 같습니다 – 만약 프론트엔드 자바스크립트에 넣으면, 웹사이트 소스를 보는 누구나 훔쳐서 AI 크레딧을 사용할 수 있습니다. 백엔드가 민감한 자격 증명을 안전하게 보관합니다.
**요청 제한 및 제어**: 사용자의 요청 빈도를 제어하고, 사용자 인증을 구현하며, 사용 로그를 남길 수 있습니다.
**데이터 처리**: 대화를 저장하거나 부적절한 컨텐츠를 필터링하거나 여러 AI 서비스를 조합하는 로직이 백엔드에 존재합니다.
**아키텍처는 클라이언트-서버 모델과 유사합니다:**
- **프론트엔드**: 사용자 인터페이스와 상호작용 레이어
- **백엔드 API**: 요청 처리 및 라우팅 레이어
- **AI 서비스**: 외부 계산 및 응답 생성
- **환경 변수**: 안전한 설정과 자격 증명 저장
### 요청-응답 흐름 이해하기
사용자가 메시지를 보내면 어떤 일이 일어나는지 살펴봅니다:
```mermaid
sequenceDiagram
participant User as 👤 사용자
participant Frontend as 🌐 프론트엔드
participant API as 🔧 FastAPI 서버
participant AI as 🤖 AI 서비스
User->>Frontend: "안녕 AI!" 입력
Frontend->>API: POST /hello {"message": "안녕 AI!"}
Note over API: 요청 검증
시스템 프롬프트 추가
API->>AI: 포맷된 요청 전송
AI->>API: AI 응답 반환
Note over API: 응답 처리
대화 기록
API->>Frontend: {"response": "안녕하세요! 무엇을 도와드릴까요?"}
Frontend->>User: AI 메시지 표시
```
**각 단계 이해하기:**
1. **사용자 상호작용**: 사람이 채팅 인터페이스에 입력
2. **프론트엔드 처리**: 자바스크립트가 입력을 잡아 JSON 형식으로 만듦
3. **API 검증**: FastAPI가 Pydantic 모델로 요청 자동 검증
4. **AI 통합**: 백엔드가 컨텍스트(시스템 프롬프트)를 추가하고 AI 서비스 호출
5. **응답 처리**: API가 AI 응답을 받아 필요 시 수정 가능
6. **프론트엔드 표시**: 자바스크립트가 채팅에서 응답 표시
### API 아키텍처 이해하기
```mermaid
sequenceDiagram
participant Frontend
participant FastAPI
participant AI Function
participant GitHub Models
Frontend->>FastAPI: POST /hello {"message": "안녕하세요 AI!"}
FastAPI->>AI Function: call_llm(message, system_prompt)
AI Function->>GitHub Models: API 요청
GitHub Models->>AI Function: AI 응답
AI Function->>FastAPI: 응답 텍스트
FastAPI->>Frontend: {"response": "안녕하세요! 어떻게 도와드릴까요?"}
```
```mermaid
flowchart TD
A[사용자 입력] --> B[프론트엔드 검증]
B --> C[HTTP POST 요청]
C --> D[FastAPI 라우터]
D --> E[Pydantic 검증]
E --> F[AI 함수 호출]
F --> G[GitHub 모델 API]
G --> H[응답 처리]
H --> I[JSON 응답]
I --> J[프론트엔드 업데이트]
subgraph "보안 계층"
K[CORS 미들웨어]
L[환경 변수]
M[오류 처리]
end
D --> K
F --> L
H --> M
```
### FastAPI 애플리케이션 만들기
단계별로 API를 만들어 봅시다. `api.py`라는 파일을 만들고 다음 FastAPI 코드를 작성합니다:
```python
# api.py
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from llm import call_llm
import logging
# 로깅 구성
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# FastAPI 애플리케이션 생성
app = FastAPI(
title="AI Chat API",
description="A high-performance API for AI-powered chat applications",
version="1.0.0"
)
# CORS 구성
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 프로덕션에 적합하게 구성
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 요청/응답 검증을 위한 Pydantic 모델
class ChatMessage(BaseModel):
message: str
class ChatResponse(BaseModel):
response: str
@app.get("/")
async def root():
"""Root endpoint providing API information."""
return {
"message": "Welcome to the AI Chat API",
"docs": "/docs",
"health": "/health"
}
@app.get("/health")
async def health_check():
"""Health check endpoint."""
return {"status": "healthy", "service": "ai-chat-api"}
@app.post("/hello", response_model=ChatResponse)
async def chat_endpoint(chat_message: ChatMessage):
"""Main chat endpoint that processes messages and returns AI responses."""
try:
# 메시지 추출 및 검증
message = chat_message.message.strip()
if not message:
raise HTTPException(status_code=400, detail="Message cannot be empty")
logger.info(f"Processing message: {message[:50]}...")
# AI 서비스 호출 (참고: 더 나은 성능을 위해 call_llm은 비동기로 만들어야 함)
ai_response = await call_llm_async(message, "You are a helpful and friendly assistant.")
logger.info("AI response generated successfully")
return ChatResponse(response=ai_response)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error processing chat message: {str(e)}")
raise HTTPException(status_code=500, detail="Internal server error")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=5000, reload=True)
```
**FastAPI 구현 이해하기:**
- 현대 웹 프레임워크 역할을 하는 FastAPI와 데이터 검증용 Pydantic 임포트
- 서버 실행 시 `/docs`에서 자동 API 문서 생성
- 다양한 출처 프론트엔드 요청을 허용하는 CORS 미들웨어 활성화
- 요청/응답 자동 검증과 문서화를 위한 Pydantic 모델 정의
- 비동기 엔드포인트 사용으로 동시 요청 성능 향상
- HTTP 상태 코드와 예외 처리를 위한 HTTPException 사용
- 모니터링과 디버깅을 위한 구조화된 로깅 포함
- 서비스 상태 확인용 헬스 체크 엔드포인트 제공
**기존 프레임워크 대비 FastAPI 주요 장점:**
- **자동 검증**: Pydantic 모델이 처리 전 데이터 무결성 보장
- **인터랙티브 문서**: `/docs`에서 테스트 가능한 자동 문서 제공
- **타입 안전성**: Python 타입 힌트가 런타임 오류 방지 및 코드 품질 향상
- **비동기 지원**: 다중 AI 요청 동시 처리 시 블로킹 없음
- **성능 우수**: 실시간 애플리케이션 요청 처리 속도 매우 빠름
### CORS 이해하기: 웹의 보안 경비원
CORS(Cross-Origin Resource Sharing)는 건물의 경비원처럼 방문자가 출입 허가가 있는지 확인합니다. 왜 중요한지, 애플리케이션에 어떤 영향을 주는지 알아봅시다.
#### CORS란 무엇이며 왜 존재하는가?
**문제점**: 아무 웹사이트가 허락 없이 당신을 대신해 은행 웹사이트에 요청을 보낼 수 있다면? 보안에 큰 위험입니다! 브라우저는 기본적으로 "동일 출처 정책(Same-Origin Policy)"으로 이를 막습니다.
**동일 출처 정책**: 브라우저는 웹페이지가 로드된 도메인, 포트, 프로토콜과 동일한 곳에만 요청을 보내도록 허용합니다.
**실생활 비유**: 아파트 경비 – 기본적으로 거주자(같은 출처)만 건물에 출입 가능. 친구(다른 출처)를 초대하려면 경비에게 허락을 명확히 알려야 함.
#### 개발 환경에서 CORS
개발 중 프론트엔드와 백엔드는 다른 포트에서 실행됩니다:
- 프론트엔드: `http://localhost:3000` (HTML 직접 열 경우 file://)
- 백엔드: `http://localhost:5000`
동일한 컴퓨터지만 서로 다른 "출처"로 간주됩니다!
```python
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI(__name__)
CORS(app) # 이것은 브라우저에 "다른 출처에서 이 API에 요청하는 것이 괜찮다"고 알립니다
```
**CORS 설정이 실제로 하는 일:**
- API 응답에 특수 HTTP 헤더를 추가해 브라우저에 "이 교차 출처 요청은 허용됨"을 알림
- "예비 요청(preflight)" 처리 (브라우저가 실제 요청 전 권한 확인 위해 종종 보냄)
- 브라우저 콘솔에서 흔히 보는 "CORS 정책에 의해 차단됨" 오류 방지
#### CORS 보안: 개발 환경 대 운영 환경
```python
# 🚨 개발: 모든 출처 허용 (편리하지만 보안에 취약함)
CORS(app)
# ✅ 운영: 특정 프론트엔드 도메인만 허용
CORS(app, origins=["https://yourdomain.com", "https://www.yourdomain.com"])
# 🔒 고급: 환경별로 다른 출처 허용
if app.debug: # 개발 모드
CORS(app, origins=["http://localhost:3000", "http://127.0.0.1:3000"])
else: # 운영 모드
CORS(app, origins=["https://yourdomain.com"])
```
**중요성**: 개발 시 `CORS(app)`는 마치 현관문을 잠그지 않은 것과 같아 편리하지만 안전하지 않습니다. 운영 환경에서는 API와 통신 가능한 정확한 웹사이트만 지정해야 합니다.
#### 일반적인 CORS 시나리오와 해결책
| 시나리오 | 문제 | 해결책 |
|----------|---------|----------|
| **로컬 개발** | 프론트엔드가 백엔드에 접근 불가 | FastAPI에 CORSMiddleware 추가 |
| **GitHub Pages + Heroku** | 배포된 프론트엔드가 API 접근 불가 | GitHub Pages URL을 CORS 출처에 추가 |
| **커스텀 도메인** | 운영 환경에서 CORS 오류 발생 | 도메인에 맞게 CORS 출처 업데이트 |
| **모바일 앱** | 앱이 웹 API에 접근 불가 | 앱 도메인 추가 또는 신중히 `*` 사용 |
**프로 팁**: 브라우저 개발자 도구 네트워크 탭에서 `Access-Control-Allow-Origin` 같은 응답 헤더를 확인할 수 있습니다.
### 오류 처리 및 검증
우리 API가 올바른 오류 처리를 포함하는 것을 확인해 봅시다:
```python
# 메시지를 받았는지 확인하세요
if not message:
return jsonify({"error": "Message field is required"}), 400
```
**핵심 검증 원칙:**
- 요청 처리 전에 필수 필드 확인
- JSON 형식의 의미 있는 오류 메시지 반환
- 적절한 HTTP 상태 코드 사용 (잘못된 요청은 400)
- 프론트엔드 개발자가 문제를 디버깅하기 쉽도록 명확한 피드백 제공
## 백엔드 설정 및 실행하기
이제 AI 통합과 FastAPI 서버가 준비되었으니 실행해 봅시다. 설치, 환경 변수 설정, 개발 서버 시작 과정이 포함됩니다.
### Python 환경 설정
Python 개발 환경을 설정합시다. 가상환경은 맨해튼 프로젝트의 구획 방식을 닮았습니다 – 각 프로젝트마다 독립된 공간에서 특정 도구와 의존성을 관리해 프로젝트 간 충돌을 방지합니다.
```bash
# 백엔드 디렉토리로 이동하세요
cd backend
# 가상 환경을 만드세요 (프로젝트를 위한 깨끗한 공간을 만드는 것과 같습니다)
python -m venv venv
# 가상 환경을 활성화하세요 (Linux/Mac)
source ./venv/bin/activate
# Windows에서는 다음을 사용하세요:
# venv\Scripts\activate
# 필요한 패키지를 설치하세요
pip install openai fastapi uvicorn python-dotenv
```
**방금 한 일:**
- 다른 곳에 영향 없이 패키지를 설치할 수 있는 독립된 Python 환경 생성
- 터미널이 이 환경을 사용하도록 활성화
- 주요 라이브러리 설치: OpenAI (AI 처리), FastAPI (웹 API), Uvicorn (서버 실행), python-dotenv (비밀 관리)
**주요 의존성 설명:**
- **FastAPI**: 최신 빠른 웹 프레임워크, 자동 문서화 지원
- **Uvicorn**: FastAPI 애플리케이션 구동용 초고속 ASGI 서버
- **OpenAI**: GitHub 모델과 OpenAI API 통합 공식 라이브러리
- **python-dotenv**: `.env` 파일에서 환경 변수 안전하게 로드
### 환경 구성: 비밀 유지하기
API를 시작하기 전에 웹 개발에서 가장 중요한 교훈 중 하나를 다룹니다: 비밀을 진짜 비밀로 유지하는 법. 환경 변수는 애플리케이션만 접근 가능한 보안 금고와 같습니다.
#### 환경 변수란 무엇인가?
**환경 변수를 안전금고에 비유**해 보세요 – 귀중품을 거기에 보관하고 키는 오직 당신(앱)만 갖고 있습니다. 민감 정보를 코드에 직접 쓰는 대신(누구나 볼 수 있음) 환경에 안전하게 저장하는 방식입니다.
**차이점:**
- **잘못된 방식**: 모니터에 비밀번호를 붙여 놓기
- **올바른 방식**: 당신만 접근 가능한 안전한 비밀번호 관리자에 저장
#### 환경 변수가 중요한 이유
```python
# 🚨 절대 이렇게 하지 마세요 - API 키가 모두에게 보임
client = OpenAI(
api_key="ghp_1234567890abcdef...", # 누구나 이 키를 훔칠 수 있습니다!
base_url="https://models.github.ai/inference"
)
# ✅ 이렇게 하세요 - API 키를 안전하게 저장
client = OpenAI(
api_key=os.environ["GITHUB_TOKEN"], # 오직 당신의 앱만 접근할 수 있습니다
base_url="https://models.github.ai/inference"
)
```
**비밀을 하드코딩하면 발생하는 일:**
1. 버전 관리 노출: Git 저장소를 보는 누구나 API 키 확인 가능
2. 공개 저장소: GitHub에 푸시하면 키가 전 세계에 노출
3. 팀원 공유: 프로젝트 팀원 모두 개인 API 키에 접근
4. 보안 침해: 키를 훔치면 AI 크레딧을 악용당함
#### 환경 파일 설정
백엔드 디렉터리에 `.env` 파일을 만듭니다. 이 파일은 비밀을 로컬에 저장합니다:
```bash
# .env 파일 - 절대 Git에 커밋되어서는 안 됩니다
GITHUB_TOKEN=your_github_personal_access_token_here
FASTAPI_DEBUG=True
ENVIRONMENT=development
```
**`.env` 파일 이해하기:**
- 한 줄에 하나씩 `KEY=value` 형식
- 등호 앞뒤 공백 없음
- 값 주위에 따옴표 보통 불필요
- 주석은 `#`로 시작
#### GitHub 개인 액세스 토큰 만들기
GitHub 토큰은 GitHub AI 서비스를 사용할 권한을 애플리케이션에 주는 특별한 비밀번호입니다:
**토큰 생성 단계:**
1. GitHub 설정 → 개발자 설정 → 개인 액세스 토큰 → 토큰 (클래식)
2. “새 토큰 생성 (클래식)” 클릭
3. 만료 기간 설정 (테스트용 30일, 운영용 더 길게)
4. 범위 선택: "repo" 등 필요한 권한 체크
5. 토큰 생성 후 바로 복사(다시 볼 수 없음)
6. `.env` 파일에 붙여넣기
```bash
# 토큰이 어떻게 생겼는지 예시입니다 (이것은 가짜입니다!)
GITHUB_TOKEN=ghp_1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6P7Q8R
```
#### Python에서 환경 변수 로드하기
```python
import os
from dotenv import load_dotenv
# .env 파일에서 환경 변수를 로드합니다
load_dotenv()
# 이제 안전하게 액세스할 수 있습니다
api_key = os.environ.get("GITHUB_TOKEN")
if not api_key:
raise ValueError("GITHUB_TOKEN not found in environment variables!")
client = OpenAI(
api_key=api_key,
base_url="https://models.github.ai/inference"
)
```
**이 코드가 하는 일:**
- `.env` 파일을 로드해 변수 파이썬에서 사용 가능하게 함
- 필요한 토큰의 존재 유무 검사(오류 처리 잘 함)
- 토큰 없으면 명확한 오류 발생
- 코드 내 노출 없이 안전하게 토큰 사용
#### Git 보안: `.gitignore` 파일
`.gitignore`는 Git에 추적하거나 업로드하지 않을 파일을 알려줍니다:
```bash
# .gitignore - 이 줄들을 추가하세요
.env
*.env
.env.local
.env.production
__pycache__/
venv/
.vscode/
```
**중요성**: `.env`를 `.gitignore`에 추가하면 Git이 환경 파일 무시, 비밀이 GitHub에 잘못 올라가지 않도록 방지
#### 환경별 다른 비밀
전문 애플리케이션은 환경별로 다른 API 키를 사용합니다:
```bash
# .env.development
GITHUB_TOKEN=your_development_token
DEBUG=True
# .env.production
GITHUB_TOKEN=your_production_token
DEBUG=False
```
**중요한 이유**: 개발 실험이 운영 AI 사용량에 영향을 미치지 않도록, 환경별로 다른 보안 수준을 유지하려면 필요
### 개발 서버 시작: FastAPI에 생명 불어넣기
이제 흥미진진한 순간이 왔습니다 – FastAPI 개발 서버를 시작하고 AI 통합이 실제로 작동하는 모습을 보는 것입니다! FastAPI는 비동기 Python 애플리케이션을 위해 특별히 설계된 초고속 ASGI 서버인 Uvicorn을 사용합니다.
#### FastAPI 서버 시작 프로세스 이해하기
```bash
# 방법 1: 직접 파이썬 실행 (자동 재시작 포함)
python api.py
# 방법 2: Uvicorn 직접 사용 (더 많은 제어)
uvicorn api:app --host 0.0.0.0 --port 5000 --reload
```
이 명령을 실행하면 뒤에서 다음과 같은 일이 일어납니다:
**1. Python이 FastAPI 애플리케이션을 로드합니다**:
- 필요한 모든 라이브러리(FastAPI, Pydantic, OpenAI 등)를 가져옵니다
- `.env` 파일에서 환경 변수를 불러옵니다
- 자동 문서화가 포함된 FastAPI 애플리케이션 인스턴스를 생성합니다
**2. Uvicorn이 ASGI 서버를 구성합니다**:
- 비동기 요청 처리 기능을 갖춘 포트 5000에 바인딩합니다
- 자동 검증이 적용된 요청 라우팅을 설정합니다
- 개발 시 핫 리로드(파일 변경 시 재시작)를 활성화합니다
- 대화형 API 문서를 생성합니다
**3. 서버가 리스닝을 시작합니다**:
- 터미널에 `INFO: Uvicorn running on http://0.0.0.0:5000`가 표시됩니다
- 서버는 여러 동시 AI 요청을 처리할 수 있습니다
- 자동 문서가 `http://localhost:5000/docs`에서 준비됩니다
#### 모든 것이 정상 작동할 때 보여야 하는 것
```bash
$ python api.py
INFO: Will watch for changes in these directories: ['/your/project/path']
INFO: Uvicorn running on http://0.0.0.0:5000 (Press CTRL+C to quit)
INFO: Started reloader process [12345] using WatchFiles
INFO: Started server process [12346]
INFO: Waiting for application startup.
INFO: Application startup complete.
```
**FastAPI 출력 이해하기:**
- **변경사항 감시 활성화됨**: 개발을 위한 자동 재시작 기능 활성화
- **Uvicorn 실행 중**: 고성능 ASGI 서버가 작동 중임
- **재로더 프로세스 시작됨**: 파일 변경 감지를 통한 자동 재시작 기능 활성화
- **애플리케이션 시작 완료**: FastAPI 앱이 정상적으로 초기화됨
- **대화형 문서 제공됨**: `/docs`에서 자동 API 문서 이용 가능
#### FastAPI 테스트: 여러 강력한 방법
FastAPI는 자동 대화형 문서화를 포함하여 API를 테스트할 편리한 방법을 여러 가지 제공합니다:
**방법 1: 대화형 API 문서 (권장)**
1. 브라우저에서 `http://localhost:5000/docs`에 접속하세요
2. 모든 엔드포인트가 문서화된 Swagger UI가 보입니다
3. `/hello`를 클릭 → "Try it out" → 테스트 메시지 입력 → "Execute" 클릭
4. 응답을 브라우저에서 바로 보기 편한 형식으로 확인
**방법 2: 기본 브라우저 테스트**
1. 루트 엔드포인트 `http://localhost:5000` 접속
2. 서버 상태 확인용 `http://localhost:5000/health` 접속
3. FastAPI 서버가 정상 실행 중인지 확인 가능
**방법 2: 명령어 라인 테스트 (고급)**
```bash
# curl로 테스트 (가능한 경우)
curl -X POST http://localhost:5000/hello \
-H "Content-Type: application/json" \
-d '{"message": "Hello AI!"}'
# 예상 응답:
# {"response": "안녕하세요! 저는 당신의 AI 비서입니다. 오늘 무엇을 도와드릴까요?"}
```
**방법 3: Python 테스트 스크립트**
```python
# test_api.py - 이 파일을 생성하여 API를 테스트하세요
import requests
import json
# API 엔드포인트를 테스트하세요
url = "http://localhost:5000/hello"
data = {"message": "Tell me a joke about programming"}
response = requests.post(url, json=data)
if response.status_code == 200:
result = response.json()
print("AI Response:", result['response'])
else:
print("Error:", response.status_code, response.text)
```
#### 일반적인 시작 문제 해결
| 에러 메시지 | 의미 | 해결 방법 |
|-------------|-------|------------|
| `ModuleNotFoundError: No module named 'fastapi'` | FastAPI가 설치되어 있지 않음 | 가상 환경에서 `pip install fastapi uvicorn` 실행 |
| `ModuleNotFoundError: No module named 'uvicorn'` | ASGI 서버가 설치되어 있지 않음 | 가상 환경에서 `pip install uvicorn` 실행 |
| `KeyError: 'GITHUB_TOKEN'` | 환경 변수가 누락됨 | `.env` 파일과 `load_dotenv()` 호출 확인 |
| `Address already in use` | 포트 5000이 이미 사용 중 | 5000번 포트를 사용하는 프로세스 종료 또는 포트 변경 |
| `ValidationError` | 요청 데이터가 Pydantic 모델과 일치하지 않음 | 요청 형식이 예상 스키마와 맞는지 검토 |
| `HTTPException 422` | 처리할 수 없는 엔티티 | 요청 검증 실패, `/docs`에서 올바른 형식 확인 |
| `OpenAI API error` | AI 서비스 인증 실패 | GitHub 토큰이 올바르고 권한이 있는지 확인 |
#### 개발 모범 사례
**핫 리로딩**: FastAPI와 Uvicorn은 Python 파일을 저장할 때 자동으로 재시작합니다. 코드를 수정하고 즉시 테스트할 수 있어 수동 재시작이 필요 없습니다.
```python
# 핫 리로딩을 명시적으로 활성화
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True) # debug=True는 핫 리로드를 활성화합니다
```
**개발용 로깅**: 진행 상황 파악을 위해 로깅 추가:
```python
import logging
# 로깅 설정
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@app.route("/hello", methods=["POST"])
def hello():
data = request.get_json()
message = data.get("message", "")
logger.info(f"Received message: {message}")
if not message:
logger.warning("Empty message received")
return jsonify({"error": "Message field is required"}), 400
try:
response = call_llm(message, "You are a helpful and friendly assistant.")
logger.info(f"AI response generated successfully")
return jsonify({"response": response})
except Exception as e:
logger.error(f"AI API error: {str(e)}")
return jsonify({"error": "AI service temporarily unavailable"}), 500
```
**로깅이 도움이 되는 이유**: 개발 중에 들어오는 요청, AI의 응답, 발생하는 오류를 정확히 확인할 수 있어 디버깅이 훨씬 빨라집니다.
### GitHub Codespaces 설정하기: 클라우드 개발의 간편함
GitHub Codespaces는 브라우저 어느 곳에서든 접속 가능한 강력한 클라우드 개발 컴퓨터입니다. Codespaces에서 작업할 시 백엔드를 프론트엔드가 접근 가능하도록 몇 가지 추가 구성이 필요합니다.
#### Codespaces 네트워킹 이해하기
로컬 개발 환경에서는 모든 것이 같은 컴퓨터에서 실행됩니다:
- 백엔드: `http://localhost:5000`
- 프론트엔드: `http://localhost:3000` (또는 file://)
Codespaces에서는 개발 환경이 GitHub 서버에서 실행되므로, "localhost"가 다른 의미를 가집니다. GitHub이 서비스용 공개 URL을 자동으로 생성하지만, 이를 제대로 구성해야 합니다.
#### Codespaces 단계별 설정
**1. 백엔드 서버 시작하기**:
```bash
cd backend
python api.py
```
Codespaces 환경 내에서 실행되는 FastAPI/Uvicorn 시작 메시지가 나타납니다.
**2. 포트 공개 설정**:
- VS Code 하단 패널의 "Ports" 탭 찾기
- 리스트에서 포트 5000 확인
- 포트 5000에서 우클릭
- "Port Visibility" → "Public" 선택
**왜 공개해야 하나요?** 기본적으로 Codespace 포트는 비공개(본인만 접근 가능)입니다. 공개 설정하면 브라우저에서 실행되는 프론트엔드가 백엔드와 통신할 수 있습니다.
**3. 공개 URL 확인**:
포트를 공개하면 다음과 같은 URL이 생성됩니다:
```
https://your-codespace-name-5000.app.github.dev
```
**4. 프론트엔드 구성 업데이트**:
```javascript
// 프론트엔드 app.js에서 BASE_URL을 업데이트하세요:
this.BASE_URL = "https://your-codespace-name-5000.app.github.dev";
```
#### Codespace URL 구조 이해
Codespaces URL은 다음과 같은 규칙을 따릅니다:
```
https://[codespace-name]-[port].app.github.dev
```
**분해해서 보면:**
- `codespace-name`: Codespace의 고유 식별자(대부분 사용자 이름 포함)
- `port`: 서비스가 실행 중인 포트 번호 (FastAPI 앱은 5000)
- `app.github.dev`: GitHub의 Codespace 애플리케이션 도메인
#### Codespace 설정 테스트
**1. 백엔드 직접 테스트**:
공개 URL을 새 브라우저 탭에 열어 다음 화면을 확인하세요:
```
Welcome to the AI Chat API. Send POST requests to /hello with JSON payload containing 'message' field.
```
**2. 브라우저 개발자 도구로 테스트**:
```javascript
// 브라우저 콘솔을 열고 API를 테스트하세요
fetch('https://your-codespace-name-5000.app.github.dev/hello', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({message: 'Hello from Codespaces!'})
})
.then(response => response.json())
.then(data => console.log(data));
```
#### Codespaces vs 로컬 개발 비교
| 항목 | 로컬 개발 | GitHub Codespaces |
|--------|-----------------|--------------------|
| **설정 시간** | 길게 걸림 (Python, 의존성 설치 필요) | 즉시 사용 가능 (사전 구성된 환경) |
| **URL 접근** | `http://localhost:5000` | `https://xyz-5000.app.github.dev` |
| **포트 구성** | 자동 처리 | 수동 (포트 공개 설정 필요) |
| **파일 저장** | 로컬 컴퓨터에 저장 | GitHub 저장소에 저장 |
| **협업** | 환경 공유 어려움 | Codespace 링크로 쉽게 공유 가능 |
| **인터넷 의존성** | AI API 호출 시만 필요 | 모든 작업에 필요 |
#### Codespace 개발 팁
**Codespaces 환경 변수**:
`.env` 파일은 Codespaces에서도 동일하게 작동하지만, Codespace 내에서 직접 환경 변수를 설정할 수도 있습니다:
```bash
# 현재 세션에 대한 환경 변수를 설정합니다
export GITHUB_TOKEN="your_token_here"
# 또는 지속성을 위해 .bashrc에 추가하세요
echo 'export GITHUB_TOKEN="your_token_here"' >> ~/.bashrc
```
**포트 관리**:
- Codespaces는 애플리케이션이 포트를 열면 자동으로 감지합니다
- 여러 포트를 동시에 포워딩 가능(예: 나중에 데이터베이스 추가 시)
- Codespace가 실행 중인 동안 포트 접근 가능
**개발 워크플로우**:
1. VS Code에서 코드 수정
2. FastAPI는 Uvicorn의 reload 모드 덕분에 자동 재시작
3. 공개 URL 통해 변경 사항 즉시 테스트
4. 준비되면 커밋하고 푸시
> 💡 **프로 팁**: 개발 중 Codespace 백엔드 URL을 즐겨찾기에 추가하세요. Codespace 이름이 고정이므로 같은 Codespace를 사용하면 URL이 바뀌지 않습니다.
## 프론트엔드 채팅 인터페이스 만들기: 사람이 AI와 만나는 곳
이제 사용자 인터페이스를 구축하겠습니다 – 사용자가 AI 어시스턴트와 상호작용하는 방식을 결정하는 부분입니다. 원래 아이폰 인터페이스 디자인처럼 복잡한 기술을 직관적이고 자연스럽게 만드는 데 중점을 둡니다.
### 현대 프론트엔드 아키텍처 이해하기
우리의 채팅 인터페이스는 "싱글 페이지 애플리케이션(SPA)"이라고 부르는 방식입니다. 옛날식처럼 클릭할 때마다 새로운 페이지를 불러오는 대신, 앱이 부드럽고 즉시 업데이트됩니다:
**옛날 웹사이트**: 실제 책 읽기처럼 완전히 새로운 페이지로 넘김
**우리 채팅 앱**: 휴대폰 사용처럼 모든 화면이 자연스럽게 흐르고 업데이트됨
```mermaid
graph TD
A[사용자가 메시지 입력] --> B[JavaScript가 입력을 캡처]
B --> C[데이터 검증 및 형식 지정]
C --> D[백엔드 API로 전송]
D --> E[로딩 상태 표시]
E --> F[AI 응답 수신]
F --> G[채팅 인터페이스 업데이트]
G --> H[다음 메시지 준비 완료]
```
```mermaid
classDiagram
class ChatApp {
+messages: HTMLElement
+form: HTMLElement
+input: HTMLElement
+sendButton: HTMLElement
+BASE_URL: string
+API_ENDPOINT: string
+constructor()
+initializeEventListeners()
+handleSubmit(event)
+callAPI(message)
+appendMessage(text, role)
+escapeHtml(text)
+scrollToBottom()
+setLoading(isLoading)
}
ChatApp --> DOM : 조작함
ChatApp --> FastAPI : 요청을 보냄
```
### 프론트엔드 개발의 세 기둥
모든 프론트엔드 애플리케이션 – 단순 웹사이트부터 Discord나 Slack 같은 복잡한 앱까지 – 는 세 가지 핵심 기술 위에 구축됩니다. 웹에서 보고 상호작용하는 모든 것의 기초라고 생각하세요:
**HTML (구조)**: 기본 토대
- 어떤 요소들이 존재하는지 결정 (버튼, 텍스트 영역, 컨테이너)
- 콘텐츠에 의미 부여 (이것은 헤더, 이것은 폼 등)
- 다른 모든 것이 쌓이는 기본 구조 생성
**CSS (표현)**: 인테리어 디자이너
- 모든 것을 아름답게 꾸밈 (색상, 글꼴, 레이아웃)
- 다양한 화면 크기 지원 (휴대폰, 노트북, 태블릿)
- 부드러운 애니메이션과 시각적 피드백 제공
**JavaScript (동작)**: 두뇌
- 사용자 행동에 반응 (클릭, 입력, 스크롤)
- 백엔드와 통신하고 페이지를 동적으로 업데이트
- 모든 것을 인터랙티브하고 동적으로 만듦
**비유하자면 건축 설계와 같습니다:**
- **HTML**: 구조 설계도 (공간과 관계 정의)
- **CSS**: 미적 및 환경 디자인 (시각 스타일과 사용자 경험)
- **JavaScript**: 기계 시스템 (기능과 상호작용)
### 현대 JavaScript 아키텍처가 중요한 이유
우리 채팅 앱은 전문 애플리케이션에서 사용하는 최신 JavaScript 패턴을 사용합니다. 이 개념들을 이해하면 개발자로 성장하는 데 큰 도움이 됩니다:
**클래스 기반 아키텍처**: 객체 청사진을 만드는 것처럼 코드를 클래스 단위로 조직
**Async/Await**: 시간이 걸리는 작업(API 호출 등)을 처리하는 현대적인 방법
**이벤트 드리븐 프로그래밍**: 앱이 사용자 동작(클릭, 키 입력)에 반응하며 무한 루프를 돌지 않음
**DOM 조작**: 사용자 상호작용과 API 응답에 따라 웹 페이지 내용을 동적으로 업데이트
### 프로젝트 구조 설정
다음과 같이 정리된 구조로 frontend 디렉터리를 만드세요:
```text
frontend/
├── index.html # Main HTML structure
├── app.js # JavaScript functionality
└── styles.css # Visual styling
```
**아키텍처 이해하기:**
- 구조(HTML), 동작(JavaScript), 표현(CSS)를 분리
- 탐색 및 수정하기 쉬운 간단한 파일 구조 유지
- 웹 개발 모범 사례를 따른 조직화와 유지보수성 확보
### HTML 기초 만들기: 접근성을 위한 의미 있는 구조
HTML 구조부터 시작합시다. 현대 웹 개발은 "시맨틱 HTML"을 강조하는데, 이는 단순히 모양이 아닌 목적에 맞는 HTML 요소를 사용하는 것입니다. 이것은 스크린 리더, 검색엔진, 기타 도구에서 앱 접근성을 높입니다.
**시맨틱 HTML이 중요한 이유**: 전화로 누군가에게 당신의 채팅 앱을 설명한다고 상상해 보세요. "타이틀이 있는 헤더, 대화가 표시되는 메인 영역, 메시지 입력을 위한 하단 폼이 있다"고 말하겠죠. 시맨틱 HTML은 이런 자연스런 설명에 맞는 요소를 씁니다.
`index.html`을 다음과 같이 신중하게 구조화된 마크업으로 만드세요:
```html
Ask me anything!