|
|
1 month ago | |
|---|---|---|
| .. | ||
| solution | 1 month ago | |
| README.md | 1 month ago | |
README.md
AI로 채팅 어시스턴트 만들기
스타트렉에서 승무원들이 우주선 컴퓨터와 편하게 대화하며 복잡한 질문을 하고 깊이 있는 답변을 받던 장면을 기억하시나요? 1960년대에는 순수한 공상과학처럼 보였던 것이 이제 여러분이 이미 알고 있는 웹 기술을 사용해 만들 수 있는 것이 되었습니다.
이번 수업에서는 HTML, CSS, JavaScript, 그리고 백엔드 통합을 통해 AI 채팅 어시스턴트를 만들 것입니다. 지금까지 배운 동일한 기술이 문맥을 이해하고 의미 있는 응답을 생성할 수 있는 강력한 AI 서비스에 어떻게 연결되는지 발견하게 될 것입니다.
AI는 단순히 정보를 찾아주는 것뿐 아니라, 방대한 도서관에 접근해 질문에 맞게 정보를 종합하여 일관된 답변을 제공하는 것과 같습니다. 수천 페이지를 검색하는 대신 직접적이고 문맥에 맞는 응답을 얻게 됩니다.
통합은 익숙한 웹 기술을 함께 작동시키는 방식으로 이루어집니다. HTML은 채팅 인터페이스를 만들고, CSS는 시각적 디자인을 담당하며, JavaScript가 사용자 상호작용을 관리하고, 백엔드 API가 모든 것을 AI 서비스에 연결합니다. 이것은 마치 오케스트라의 여러 섹션이 함께 교향곡을 만드는 것과 비슷합니다.
본질적으로 우리는 자연스러운 인간 소통과 기계 처리 간의 다리를 구축하는 것입니다. AI 서비스 통합의 기술적 구현과 상호작용을 직관적으로 느끼게 하는 디자인 패턴을 모두 배우게 됩니다.
수업이 끝나면 AI 통합은 신비로운 과정이 아니라 여러분이 다룰 수 있는 또 다른 API처럼 느껴질 것입니다. 여러분이 배우던 웹 개발 원칙을 사용하여 ChatGPT와 Claude 같은 애플리케이션을 구동하는 기본 패턴들을 이해하게 될 것입니다.
⚡ 다음 5분 내 할 수 있는 것
바쁜 개발자를 위한 빠른 시작 경로
flowchart LR
A[⚡ 5분] --> B[GitHub 토큰 받기]
B --> C[AI 플레이그라운드 테스트]
C --> D[파이썬 코드 복사]
D --> E[AI 응답 보기]
- 1분차: GitHub Models Playground에 방문해 개인 액세스 토큰 생성
- 2분차: 플레이그라운드 인터페이스에서 AI 상호작용 직접 테스트
- 3분차: "Code" 탭 클릭 후 Python 코드 조각 복사
- 4분차: 로컬에서 토큰과 함께 코드 실행:
GITHUB_TOKEN=your_token python test.py - 5분차: 자신의 코드에서 처음 AI 응답 생성되는 것 확인
빠른 테스트 코드:
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 애플리케이션 개발을 통한 학습 여정
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: 박식한 친구에게 고양이에 대해 물어보는 것 – 그들의 말로 여러분이 궁금해하는 내용을 맞춤 설명
graph LR
A[당신의 질문] --> B[AI 모델]
B --> C[패턴 인식]
C --> D[콘텐츠 생성]
D --> E[맥락적 응답]
F[학습 데이터<br/>책, 기사, 웹] --> B
AI 모델이 배우는 방식 (간단 설명)
AI 모델은 책, 기사, 대화 등 텍스트가 담긴 방대한 데이터셋에 노출되어 학습합니다. 학습 과정에서 다음의 패턴을 파악합니다:
- 글 쓰기에서 생각이 구성되는 방식
- 함께 자주 등장하는 단어들
- 대화가 일반적으로 흘러가는 방식
- 공식 및 비공식 대화 간 문맥 차이
고고학자가 고대 언어를 해독하는 과정과 비슷합니다: 수천 개 예시를 분석해 문법, 어휘, 문화적 배경을 이해하고, 그렇게 얻은 패턴으로 새로운 텍스트 해석 가능해집니다.
왜 GitHub Models인가?
우리는 실용적인 이유로 GitHub Models를 사용합니다 – 자체 AI 인프라를 구축하지 않고도(솔직히 지금은 구축하고 싶지 않을 겁니다!) 엔터프라이즈급 AI에 접근할 수 있기 때문입니다. 마치 날씨 API를 쓰는 것처럼 무수히 많은 기상 관측소를 직접 세우려 하지 않는 것과 같습니다.
사실상 "AI 서비스로서 제공"되며, 가장 좋은 점은 무료로 시작할 수 있어서 큰 비용 걱정 없이 실험할 수 있다는 점입니다.
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는 다양한 AI 모델을 체험하고 특성을 이해할 수 있는 테스트 환경입니다.
🧠 AI 애플리케이션 개발 생태계
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 코드를 가져오면 다음과 비슷한 모양일 것입니다. 처음에는 복잡해 보여도 걱정 말고 하나씩 살펴봅시다:
"""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 대화는 명확한 목적이 있는 몇 가지 "역할" 구조를 사용합니다:
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: 예측 불가능한 실험적 재즈 (창의성 매우 높음)
# 매우 예측 가능한 응답 (사실 질문에 좋음)
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: 상세한 설명과 예시 포함 가능
# 짧고 간결한 답변
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" 등 다양한 답변 가능
모든 것을 종합하기: 다양한 사용 사례 별 매개변수 조합
# 사실적이고 일관된 답변을 위해 (예: 문서화 봇)
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
}
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도 언어 패턴을 비슷하게 조절합니다.
효과적인 시스템 프롬프트 작성법: 예술과 과학
훌륭한 시스템 프롬프트의 구성 요소:
- 역할/정체성: AI가 누구인가?
- 전문성: 무엇을 알고 있는가?
- 의사소통 스타일: 어떻게 말하는가?
- 구체적 지시사항: 무엇에 집중해야 하는가?
# ❌ 모호한 시스템 프롬프트
"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 성격을 만들어내는 모습을 봅시다:
# 예제 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.
"""
시스템 프롬프트의 효과 체험하기
같은 질문에 다양한 시스템 프롬프트를 적용해 극적인 차이를 확인해 봅니다:
질문: "내 웹 앱에서 사용자 인증을 어떻게 처리하나요?"
# 교사 프롬프트와 함께:
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에 배경 정보를 제공하기
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에게 응답 구조 지시하기
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가 하지 말아야 할 일 정의하기
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 서비스: 외부 계산 및 응답 생성
- 환경 변수: 안전한 설정과 자격 증명 저장
요청-응답 흐름 이해하기
사용자가 메시지를 보내면 어떤 일이 일어나는지 살펴봅니다:
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: 요청 검증<br/>시스템 프롬프트 추가
API->>AI: 포맷된 요청 전송
AI->>API: AI 응답 반환
Note over API: 응답 처리<br/>대화 기록
API->>Frontend: {"response": "안녕하세요! 무엇을 도와드릴까요?"}
Frontend->>User: AI 메시지 표시
각 단계 이해하기:
- 사용자 상호작용: 사람이 채팅 인터페이스에 입력
- 프론트엔드 처리: 자바스크립트가 입력을 잡아 JSON 형식으로 만듦
- API 검증: FastAPI가 Pydantic 모델로 요청 자동 검증
- AI 통합: 백엔드가 컨텍스트(시스템 프롬프트)를 추가하고 AI 서비스 호출
- 응답 처리: API가 AI 응답을 받아 필요 시 수정 가능
- 프론트엔드 표시: 자바스크립트가 채팅에서 응답 표시
API 아키텍처 이해하기
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": "안녕하세요! 어떻게 도와드릴까요?"}
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 코드를 작성합니다:
# 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
동일한 컴퓨터지만 서로 다른 "출처"로 간주됩니다!
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI(__name__)
CORS(app) # 이것은 브라우저에 "다른 출처에서 이 API에 요청하는 것이 괜찮다"고 알립니다
CORS 설정이 실제로 하는 일:
- API 응답에 특수 HTTP 헤더를 추가해 브라우저에 "이 교차 출처 요청은 허용됨"을 알림
- "예비 요청(preflight)" 처리 (브라우저가 실제 요청 전 권한 확인 위해 종종 보냄)
- 브라우저 콘솔에서 흔히 보는 "CORS 정책에 의해 차단됨" 오류 방지
CORS 보안: 개발 환경 대 운영 환경
# 🚨 개발: 모든 출처 허용 (편리하지만 보안에 취약함)
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가 올바른 오류 처리를 포함하는 것을 확인해 봅시다:
# 메시지를 받았는지 확인하세요
if not message:
return jsonify({"error": "Message field is required"}), 400
핵심 검증 원칙:
- 요청 처리 전에 필수 필드 확인
- JSON 형식의 의미 있는 오류 메시지 반환
- 적절한 HTTP 상태 코드 사용 (잘못된 요청은 400)
- 프론트엔드 개발자가 문제를 디버깅하기 쉽도록 명확한 피드백 제공
백엔드 설정 및 실행하기
이제 AI 통합과 FastAPI 서버가 준비되었으니 실행해 봅시다. 설치, 환경 변수 설정, 개발 서버 시작 과정이 포함됩니다.
Python 환경 설정
Python 개발 환경을 설정합시다. 가상환경은 맨해튼 프로젝트의 구획 방식을 닮았습니다 – 각 프로젝트마다 독립된 공간에서 특정 도구와 의존성을 관리해 프로젝트 간 충돌을 방지합니다.
# 백엔드 디렉토리로 이동하세요
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를 시작하기 전에 웹 개발에서 가장 중요한 교훈 중 하나를 다룹니다: 비밀을 진짜 비밀로 유지하는 법. 환경 변수는 애플리케이션만 접근 가능한 보안 금고와 같습니다.
환경 변수란 무엇인가?
환경 변수를 안전금고에 비유해 보세요 – 귀중품을 거기에 보관하고 키는 오직 당신(앱)만 갖고 있습니다. 민감 정보를 코드에 직접 쓰는 대신(누구나 볼 수 있음) 환경에 안전하게 저장하는 방식입니다.
차이점:
- 잘못된 방식: 모니터에 비밀번호를 붙여 놓기
- 올바른 방식: 당신만 접근 가능한 안전한 비밀번호 관리자에 저장
환경 변수가 중요한 이유
# 🚨 절대 이렇게 하지 마세요 - 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"
)
비밀을 하드코딩하면 발생하는 일:
- 버전 관리 노출: Git 저장소를 보는 누구나 API 키 확인 가능
- 공개 저장소: GitHub에 푸시하면 키가 전 세계에 노출
- 팀원 공유: 프로젝트 팀원 모두 개인 API 키에 접근
- 보안 침해: 키를 훔치면 AI 크레딧을 악용당함
환경 파일 설정
백엔드 디렉터리에 .env 파일을 만듭니다. 이 파일은 비밀을 로컬에 저장합니다:
# .env 파일 - 절대 Git에 커밋되어서는 안 됩니다
GITHUB_TOKEN=your_github_personal_access_token_here
FASTAPI_DEBUG=True
ENVIRONMENT=development
.env 파일 이해하기:
- 한 줄에 하나씩
KEY=value형식 - 등호 앞뒤 공백 없음
- 값 주위에 따옴표 보통 불필요
- 주석은
#로 시작
GitHub 개인 액세스 토큰 만들기
GitHub 토큰은 GitHub AI 서비스를 사용할 권한을 애플리케이션에 주는 특별한 비밀번호입니다:
토큰 생성 단계:
- GitHub 설정 → 개발자 설정 → 개인 액세스 토큰 → 토큰 (클래식)
- “새 토큰 생성 (클래식)” 클릭
- 만료 기간 설정 (테스트용 30일, 운영용 더 길게)
- 범위 선택: "repo" 등 필요한 권한 체크
- 토큰 생성 후 바로 복사(다시 볼 수 없음)
.env파일에 붙여넣기
# 토큰이 어떻게 생겼는지 예시입니다 (이것은 가짜입니다!)
GITHUB_TOKEN=ghp_1A2B3C4D5E6F7G8H9I0J1K2L3M4N5O6P7Q8R
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에 추적하거나 업로드하지 않을 파일을 알려줍니다:
# .gitignore - 이 줄들을 추가하세요
.env
*.env
.env.local
.env.production
__pycache__/
venv/
.vscode/
중요성: .env를 .gitignore에 추가하면 Git이 환경 파일 무시, 비밀이 GitHub에 잘못 올라가지 않도록 방지
환경별 다른 비밀
전문 애플리케이션은 환경별로 다른 API 키를 사용합니다:
# .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 서버 시작 프로세스 이해하기
# 방법 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에서 준비됩니다
모든 것이 정상 작동할 때 보여야 하는 것
$ 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 문서 (권장)
- 브라우저에서
http://localhost:5000/docs에 접속하세요 - 모든 엔드포인트가 문서화된 Swagger UI가 보입니다
/hello를 클릭 → "Try it out" → 테스트 메시지 입력 → "Execute" 클릭- 응답을 브라우저에서 바로 보기 편한 형식으로 확인
방법 2: 기본 브라우저 테스트
- 루트 엔드포인트
http://localhost:5000접속 - 서버 상태 확인용
http://localhost:5000/health접속 - FastAPI 서버가 정상 실행 중인지 확인 가능
방법 2: 명령어 라인 테스트 (고급)
# curl로 테스트 (가능한 경우)
curl -X POST http://localhost:5000/hello \
-H "Content-Type: application/json" \
-d '{"message": "Hello AI!"}'
# 예상 응답:
# {"response": "안녕하세요! 저는 당신의 AI 비서입니다. 오늘 무엇을 도와드릴까요?"}
방법 3: 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 파일을 저장할 때 자동으로 재시작합니다. 코드를 수정하고 즉시 테스트할 수 있어 수동 재시작이 필요 없습니다.
# 핫 리로딩을 명시적으로 활성화
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True) # debug=True는 핫 리로드를 활성화합니다
개발용 로깅: 진행 상황 파악을 위해 로깅 추가:
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. 백엔드 서버 시작하기:
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. 프론트엔드 구성 업데이트:
// 프론트엔드 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. 브라우저 개발자 도구로 테스트:
// 브라우저 콘솔을 열고 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 내에서 직접 환경 변수를 설정할 수도 있습니다:
# 현재 세션에 대한 환경 변수를 설정합니다
export GITHUB_TOKEN="your_token_here"
# 또는 지속성을 위해 .bashrc에 추가하세요
echo 'export GITHUB_TOKEN="your_token_here"' >> ~/.bashrc
포트 관리:
- Codespaces는 애플리케이션이 포트를 열면 자동으로 감지합니다
- 여러 포트를 동시에 포워딩 가능(예: 나중에 데이터베이스 추가 시)
- Codespace가 실행 중인 동안 포트 접근 가능
개발 워크플로우:
- VS Code에서 코드 수정
- FastAPI는 Uvicorn의 reload 모드 덕분에 자동 재시작
- 공개 URL 통해 변경 사항 즉시 테스트
- 준비되면 커밋하고 푸시
💡 프로 팁: 개발 중 Codespace 백엔드 URL을 즐겨찾기에 추가하세요. Codespace 이름이 고정이므로 같은 Codespace를 사용하면 URL이 바뀌지 않습니다.
프론트엔드 채팅 인터페이스 만들기: 사람이 AI와 만나는 곳
이제 사용자 인터페이스를 구축하겠습니다 – 사용자가 AI 어시스턴트와 상호작용하는 방식을 결정하는 부분입니다. 원래 아이폰 인터페이스 디자인처럼 복잡한 기술을 직관적이고 자연스럽게 만드는 데 중점을 둡니다.
현대 프론트엔드 아키텍처 이해하기
우리의 채팅 인터페이스는 "싱글 페이지 애플리케이션(SPA)"이라고 부르는 방식입니다. 옛날식처럼 클릭할 때마다 새로운 페이지를 불러오는 대신, 앱이 부드럽고 즉시 업데이트됩니다:
옛날 웹사이트: 실제 책 읽기처럼 완전히 새로운 페이지로 넘김
우리 채팅 앱: 휴대폰 사용처럼 모든 화면이 자연스럽게 흐르고 업데이트됨
graph TD
A[사용자가 메시지 입력] --> B[JavaScript가 입력을 캡처]
B --> C[데이터 검증 및 형식 지정]
C --> D[백엔드 API로 전송]
D --> E[로딩 상태 표시]
E --> F[AI 응답 수신]
F --> G[채팅 인터페이스 업데이트]
G --> H[다음 메시지 준비 완료]
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 디렉터리를 만드세요:
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을 다음과 같이 신중하게 구조화된 마크업으로 만드세요:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Chat Assistant</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="chat-container">
<header class="chat-header">
<h1>AI Chat Assistant</h1>
<p>Ask me anything!</p>
</header>
<main class="chat-messages" id="messages" role="log" aria-live="polite">
<!-- Messages will be dynamically added here -->
</main>
<form class="chat-form" id="chatForm">
<div class="input-group">
<input
type="text"
id="messageInput"
placeholder="Type your message here..."
required
aria-label="Chat message input"
>
<button type="submit" id="sendBtn" aria-label="Send message">
Send
</button>
</div>
</form>
</div>
<script src="app.js"></script>
</body>
</html>
각 HTML 요소와 그 목적 이해하기:
문서 구조
<!DOCTYPE html>: 브라우저에 최신 HTML5 문서임을 알림<html lang="en">: 스크린 리더와 번역 도구용 페이지 언어 지정<meta charset="UTF-8">: 다국어 텍스트를 위한 올바른 문자 인코딩 보장<meta name="viewport"...>: 모바일 반응형 페이지를 위해 확대/축소 조절 제어
시맨틱 요소
<header>: 타이틀과 설명이 있는 최상단 영역 명확하게 지정<main>: 기본 콘텐츠 영역 지정 (대화가 표시되는 부분)<form>: 사용자 입력용으로 시맨틱하게 올바르며 키보드 네비게이션 지원
접근성 특징
role="log": 스크린 리더에 이 영역이 메시지의 시간 순 로그임을 알림aria-live="polite": 스크린 리더에 조용히 새 메시지 알림 제공aria-label: 폼 컨트롤에 설명 레이블 제공required: 브라우저가 메시지 입력을 필수로 검증
CSS 및 JavaScript 통합
class속성: CSS 스타일링을 위한 후크 제공 (예:chat-container,input-group)id속성: JavaScript가 특정 요소를 찾고 조작하도록 허용- 스크립트 위치: HTML 로드 후 JavaScript 파일 로드
이 구조가 좋은 이유:
- 논리적 흐름: 헤더 → 메인 콘텐츠 → 입력 폼은 자연스러운 읽기 순서와 일치
- 키보드 접근 가능: 모든 인터랙티브 요소를 탭으로 접근 가능
- 스크린 리더 친화적: 시각 장애 사용자를 위한 명확한 랜드마크와 설명
- 모바일 반응형: viewport 메타 태그로 반응형 디자인 구현
- 점진적 향상: CSS나 JavaScript가 실패해도 작동 가능
대화형 JavaScript 추가하기: 현대 웹 애플리케이션 로직
이제 우리의 채팅 인터페이스에 생명을 불어넣는 JavaScript를 작성해 봅시다. ES6 클래스, async/await, 이벤트 기반 프로그래밍 등 전문 웹 개발에서 접할 수 있는 최신 JavaScript 패턴을 사용할 것입니다.
최신 JavaScript 아키텍처 이해하기
순차적으로 실행되는 일련의 함수(절차적 코드)를 작성하는 대신, 클래스 기반 아키텍처를 만들겠습니다. 클래스는 객체를 만들기 위한 청사진과 같아서 건축가의 설계도가 여러 집을 짓는 데 쓰이는 것과 비슷합니다.
웹 애플리케이션에 클래스를 사용하는 이유?
- 조직화: 관련 기능들이 한곳에 모여 있음
- 재사용성: 같은 페이지에 여러 채팅 인스턴스를 만들 수 있음
- 유지보수 용이: 특정 기능을 쉽게 디버깅하고 변경 가능
- 전문성 기준: React, Vue, Angular 같은 프레임워크에서도 이 패턴을 사용함
다음과 같은 현대적이고 잘 구조화된 JavaScript로 app.js를 만드세요:
// app.js - 현대적인 채팅 애플리케이션 로직
class ChatApp {
constructor() {
// 조작해야 할 DOM 요소 참조 가져오기
this.messages = document.getElementById("messages");
this.form = document.getElementById("chatForm");
this.input = document.getElementById("messageInput");
this.sendButton = document.getElementById("sendBtn");
// 여기에서 백엔드 URL 설정
this.BASE_URL = "http://localhost:5000"; // 환경에 맞게 이 부분 업데이트
this.API_ENDPOINT = `${this.BASE_URL}/hello`;
// 채팅 앱 생성 시 이벤트 리스너 설정
this.initializeEventListeners();
}
initializeEventListeners() {
// 폼 제출 이벤트 듣기 (사용자가 전송 버튼 클릭하거나 Enter 누를 때)
this.form.addEventListener("submit", (e) => this.handleSubmit(e));
// 입력 필드에서 Enter 키 이벤트도 듣기 (더 나은 사용자 경험)
this.input.addEventListener("keypress", (e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
this.handleSubmit(e);
}
});
}
async handleSubmit(event) {
event.preventDefault(); // 폼이 페이지를 새로 고침하지 못하게 방지
const messageText = this.input.value.trim();
if (!messageText) return; // 빈 메시지는 보내지 않기
// 무언가 진행 중임을 사용자에게 알리기
this.setLoading(true);
// 사용자 메시지를 즉시 채팅에 추가 (낙관적 UI)
this.appendMessage(messageText, "user");
// 사용자가 다음 메시지를 입력할 수 있도록 입력 필드 비우기
this.input.value = '';
try {
// AI API 호출하고 응답 대기
const reply = await this.callAPI(messageText);
// AI 응답을 채팅에 추가
this.appendMessage(reply, "assistant");
} catch (error) {
console.error('API Error:', error);
this.appendMessage("Sorry, I'm having trouble connecting right now. Please try again.", "error");
} finally {
// 성공 여부와 관계없이 인터페이스 다시 활성화
this.setLoading(false);
}
}
async callAPI(message) {
const response = await fetch(this.API_ENDPOINT, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ message })
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data.response;
}
appendMessage(text, role) {
const messageElement = document.createElement("div");
messageElement.className = `message ${role}`;
messageElement.innerHTML = `
<div class="message-content">
<span class="message-text">${this.escapeHtml(text)}</span>
<span class="message-time">${new Date().toLocaleTimeString()}</span>
</div>
`;
this.messages.appendChild(messageElement);
this.scrollToBottom();
}
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
scrollToBottom() {
this.messages.scrollTop = this.messages.scrollHeight;
}
setLoading(isLoading) {
this.sendButton.disabled = isLoading;
this.input.disabled = isLoading;
this.sendButton.textContent = isLoading ? "Sending..." : "Send";
}
}
// 페이지가 로드될 때 채팅 애플리케이션 초기화
document.addEventListener("DOMContentLoaded", () => {
new ChatApp();
});
각 JavaScript 개념 이해하기
ES6 클래스 구조:
class ChatApp {
constructor() {
// 새 ChatApp 인스턴스를 생성할 때 실행됩니다
// 채팅을 위한 "설정" 함수와 같습니다
}
methodName() {
// 메서드는 클래스에 속한 함수입니다
// "this"를 사용하여 클래스 속성에 접근할 수 있습니다
}
}
Async/Await 패턴:
// 옛날 방식 (콜백 헬):
fetch(url)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
// 현대식 방식 (async/await):
try {
const response = await fetch(url);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
이벤트 기반 프로그래밍: 무언가 발생했는지 계속 확인하는 대신 이벤트를 "청취"합니다:
// 양식이 제출되면 handleSubmit을 실행합니다
this.form.addEventListener("submit", (e) => this.handleSubmit(e));
// Enter 키가 눌렸을 때도 handleSubmit을 실행합니다
this.input.addEventListener("keypress", (e) => { /* ... */ });
DOM 조작:
// 새로운 요소 생성
const messageElement = document.createElement("div");
// 속성 수정
messageElement.className = "message user";
messageElement.innerHTML = "Hello world!";
// 페이지에 추가
this.messages.appendChild(messageElement);
보안 및 모범 사례
XSS 방지:
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text; // 이것은 HTML을 자동으로 이스케이프합니다
return div.innerHTML;
}
중요성: 사용자가 <script>alert('hack')</script>를 입력했을 때, 이 함수는 실행되지 않고 텍스트로 표시되도록 합니다.
에러 처리:
try {
const reply = await this.callAPI(messageText);
this.appendMessage(reply, "assistant");
} catch (error) {
// 앱이 중단되는 대신 사용자 친화적인 오류를 표시합니다
this.appendMessage("Sorry, I'm having trouble...", "error");
}
사용자 경험 고려사항:
- 낙관적 UI: 사용자의 메시지를 즉시 추가하며 서버 응답을 기다리지 않음
- 로딩 상태: 대기 중 버튼 비활성화 및 "전송 중..." 표시
- 자동 스크롤: 최신 메시지가 항상 보이도록 유지
- 입력 검증: 빈 메시지는 전송하지 않음
- 키보드 단축키: Enter 키로 메시지 전송 (실제 채팅 앱처럼)
애플리케이션 흐름 이해하기
- 페이지 로드 →
DOMContentLoaded이벤트 발생 →new ChatApp()생성 - 생성자 실행 → DOM 요소 참조 가져오기 → 이벤트 리스너 설정
- 사용자 메시지 입력 → Enter 키 누르거나 전송 버튼 클릭 →
handleSubmit실행 - handleSubmit → 입력 검증 → 로딩 상태 표시 → API 호출
- API 응답 받음 → 채팅에 AI 메시지 추가 → 인터페이스 재활성화
- 다음 메시지 준비 완료 → 사용자는 계속 채팅 가능
이 아키텍처는 확장 가능해서 메시지 편집, 파일 업로드, 다중 대화 스레드 등의 기능을 코어 구조를 다시 작성하지 않고도 쉽게 추가할 수 있습니다.
🎯 교육적 점검: 최신 프론트엔드 아키텍처
아키텍처 이해도: 현대 JavaScript 패턴을 활용해 완전한 싱글 페이지 애플리케이션을 구현했습니다. 이는 전문적인 프론트엔드 개발 수준을 의미합니다.
주요 개념 숙달:
- ES6 클래스 아키텍처: 체계적이고 유지보수에 좋은 코드 구조
- Async/Await 패턴: 최신 비동기 프로그래밍
- 이벤트 기반 프로그래밍: 사용자 반응형 UI 설계
- 보안 모범 사례: XSS 방지 및 입력 검사
업계 연계성: 배우신 패턴(클래스 기반 아키텍처, 비동기 처리, DOM 조작)은 React, Vue, Angular 같은 최신 프레임워크의 기본입니다. 생산 환경 애플리케이션과 동일한 아키텍처적 사고를 쌓고 있습니다.
성찰 질문: 이 채팅 앱을 다중 대화 지원이나 사용자 인증 기능으로 확장하려면 어떻게 해야 할까요? 아키텍처 변경과 클래스 구조가 어떻게 진화할지 생각해 보세요.
채팅 인터페이스 스타일링
이제 CSS로 현대적이고 시각적으로 매력적인 채팅 인터페이스를 만들어 봅시다. 좋은 스타일링은 전문성 있는 느낌을 주고 전반적인 사용자 경험을 개선합니다. Flexbox, CSS Grid, 커스텀 속성 등 최신 CSS 기능을 사용해 반응형이면서 접근성 좋은 디자인을 구현합니다.
다음과 같은 포괄적인 스타일을 styles.css에 작성하세요:
/* styles.css - Modern chat interface styling */
:root {
--primary-color: #2563eb;
--secondary-color: #f1f5f9;
--user-color: #3b82f6;
--assistant-color: #6b7280;
--error-color: #ef4444;
--text-primary: #1e293b;
--text-secondary: #64748b;
--border-radius: 12px;
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.chat-container {
width: 100%;
max-width: 800px;
height: 600px;
background: white;
border-radius: var(--border-radius);
box-shadow: var(--shadow);
display: flex;
flex-direction: column;
overflow: hidden;
}
.chat-header {
background: var(--primary-color);
color: white;
padding: 20px;
text-align: center;
}
.chat-header h1 {
font-size: 1.5rem;
margin-bottom: 5px;
}
.chat-header p {
opacity: 0.9;
font-size: 0.9rem;
}
.chat-messages {
flex: 1;
padding: 20px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 15px;
background: var(--secondary-color);
}
.message {
display: flex;
max-width: 80%;
animation: slideIn 0.3s ease-out;
}
.message.user {
align-self: flex-end;
}
.message.user .message-content {
background: var(--user-color);
color: white;
border-radius: var(--border-radius) var(--border-radius) 4px var(--border-radius);
}
.message.assistant {
align-self: flex-start;
}
.message.assistant .message-content {
background: white;
color: var(--text-primary);
border-radius: var(--border-radius) var(--border-radius) var(--border-radius) 4px;
border: 1px solid #e2e8f0;
}
.message.error .message-content {
background: var(--error-color);
color: white;
border-radius: var(--border-radius);
}
.message-content {
padding: 12px 16px;
box-shadow: var(--shadow);
position: relative;
}
.message-text {
display: block;
line-height: 1.5;
word-wrap: break-word;
}
.message-time {
display: block;
font-size: 0.75rem;
opacity: 0.7;
margin-top: 5px;
}
.chat-form {
padding: 20px;
border-top: 1px solid #e2e8f0;
background: white;
}
.input-group {
display: flex;
gap: 10px;
align-items: center;
}
#messageInput {
flex: 1;
padding: 12px 16px;
border: 2px solid #e2e8f0;
border-radius: var(--border-radius);
font-size: 1rem;
outline: none;
transition: border-color 0.2s ease;
}
#messageInput:focus {
border-color: var(--primary-color);
}
#messageInput:disabled {
background: #f8fafc;
opacity: 0.6;
cursor: not-allowed;
}
#sendBtn {
padding: 12px 24px;
background: var(--primary-color);
color: white;
border: none;
border-radius: var(--border-radius);
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: background-color 0.2s ease;
min-width: 80px;
}
#sendBtn:hover:not(:disabled) {
background: #1d4ed8;
}
#sendBtn:disabled {
background: #94a3b8;
cursor: not-allowed;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Responsive design for mobile devices */
@media (max-width: 768px) {
body {
padding: 10px;
}
.chat-container {
height: calc(100vh - 20px);
border-radius: 8px;
}
.message {
max-width: 90%;
}
.input-group {
flex-direction: column;
gap: 10px;
}
#messageInput {
width: 100%;
}
#sendBtn {
width: 100%;
}
}
/* Accessibility improvements */
@media (prefers-reduced-motion: reduce) {
.message {
animation: none;
}
* {
transition: none !important;
}
}
/* Dark mode support */
@media (prefers-color-scheme: dark) {
.chat-container {
background: #1e293b;
color: #f1f5f9;
}
.chat-messages {
background: #0f172a;
}
.message.assistant .message-content {
background: #334155;
color: #f1f5f9;
border-color: #475569;
}
.chat-form {
background: #1e293b;
border-color: #475569;
}
#messageInput {
background: #334155;
color: #f1f5f9;
border-color: #475569;
}
}
CSS 아키텍처 이해하기:
- CSS 커스텀 속성(변수) 사용으로 일관된 테마와 쉬운 유지 관리
- Flexbox 레이아웃 적용으로 반응형 디자인과 적절한 정렬 구현
- 부드러운 애니메이션 포함, 메시지 등장 시 산만하지 않게 표현
- 사용자 메시지, AI 응답, 에러 상태 구분 시각적 표현 제공
- 데스크톱과 모바일 모두 지원하는 반응형 디자인
- 감소된 동작 선호도와 적절한 명암 대비로 접근성 고려
- 사용자의 시스템 환경 설정을 따른 다크 모드 지원
백엔드 URL 구성하기
마지막 단계는 JavaScript 내 BASE_URL을 백엔드 서버 주소에 맞게 업데이트하는 것입니다:
// 로컬 개발용
this.BASE_URL = "http://localhost:5000";
// GitHub Codespaces용 (실제 URL로 교체)
this.BASE_URL = "https://your-codespace-name-5000.app.github.dev";
백엔드 URL 결정:
- 로컬 개발: 프론트엔드, 백엔드를 모두 로컬에서 실행 시
http://localhost:5000사용 - Codespaces: 포트 5000을 공개한 후 포트 탭에서 백엔드 URL 확인
- 프로덕션: 배포 시 실제 도메인으로 변경
💡 테스트 팁: 브라우저에서 루트 URL을 직접 방문해 백엔드 테스트 가능. FastAPI 서버의 환영 메시지가 표시됩니다.
테스트 및 배포
프론트엔드와 백엔드가 모두 완성되었으니, 전체가 잘 작동하는지 테스트하고 채팅 어시스턴트를 다른 사람과 공유할 배포 옵션을 살펴보겠습니다.
로컬 테스트 워크플로우
완성된 애플리케이션을 테스트하려면 다음 단계를 따라하세요:
graph TD
A[백엔드 서버 시작] --> B[환경 변수 구성]
B --> C[API 엔드포인트 테스트]
C --> D[브라우저에서 프론트엔드 열기]
D --> E[채팅 기능 테스트]
E --> F[문제 디버깅]
단계별 테스트 과정:
-
백엔드 서버 시작:
cd backend source venv/bin/activate # 또는 Windows에서 venv\Scripts\activate python api.py -
API 정상 동작 확인:
- 브라우저에서
http://localhost:5000열기 - FastAPI 서버의 환영 메시지 확인
- 브라우저에서
-
프론트엔드 열기:
- 프론트엔드 디렉터리로 이동
index.html파일을 웹 브라우저에서 열기- 또는 VS Code의 Live Server 확장 기능 사용 권장
-
채팅 기능 테스트:
- 입력 필드에 메시지 입력
- "전송" 클릭 또는 Enter 키 누름
- AI가 적절히 응답하는지 확인
- 브라우저 콘솔에서 JavaScript 오류 여부 확인
흔한 문제점 해결법
| 문제 | 증상 | 해결책 |
|---|---|---|
| CORS 오류 | 프론트엔드가 백엔드에 접근 불가 | FastAPI의 CORSMiddleware 올바르게 설정했는지 확인 |
| API 키 오류 | 401 Unauthorized 응답 | GITHUB_TOKEN 환경변수 확인 |
| 연결 거부됨 | 프론트엔드 네트워크 에러 | 백엔드 URL과 Flask 서버 실행 여부 점검 |
| AI 응답 없음 | 빈 결과 또는 에러 응답 | 백엔드 로그에서 API 쿼터 또는 인증 문제 확인 |
일반 디버깅 단계:
- 브라우저 개발자 도구 콘솔에서 JavaScript 오류 확인
- 네트워크 탭에서 API 요청/응답 성공 확인
- 백엔드 터미널 출력에서 Python 오류 및 API 이슈 점검
- 환경 변수가 올바르게 로드되고 접근 가능한지 확인
📈 AI 애플리케이션 개발 마스터 타임라인
timeline
title 완전한 AI 애플리케이션 개발 여정
section AI Foundations
Understanding Generative AI
: 패턴 인식 개념 이해하기
: AI 매개변수 제어 마스터하기
: 프롬프트 엔지니어링 기법 배우기
GitHub Models Integration
: AI 서비스 플랫폼 탐색하기
: 인증을 안전하게 처리하기
: 모델 매개변수 최적화하기
section Backend Development
Python API Architecture
: FastAPI 애플리케이션 구축하기
: 비동기 작업 구현하기
: 안전한 엔드포인트 만들기
AI Service Integration
: 외부 AI API에 연결하기
: 속도 제한 처리하기
: 오류 경계 구현하기
section Frontend Mastery
Modern JavaScript Patterns
: ES6 클래스 아키텍처 마스터하기
: async/await 흐름 구현하기
: 반응형 인터페이스 구축하기
Real-time User Experience
: 동적 채팅 인터페이스 만들기
: 로딩 상태 처리하기
: 사용자 상호작용 최적화하기
section Production Readiness
Security & Performance
: 안전한 토큰 관리 구현하기
: XSS 취약점 방지하기
: API 성능 최적화하기
Professional Deployment
: 확장 가능한 아키텍처 구축하기
: 유지보수 가능한 코드 작성하기
: 개발 프로세스 문서화하기
🎓 졸업 마일스톤: 현대 AI 비서를 지원하는 핵심 기술과 아키텍처 패턴으로 완전한 AI 기반 애플리케이션을 성공적으로 구축했습니다. 이 역량은 전통적 웹 개발과 최첨단 AI 통합의 교차점에 위치합니다.
🔄 다음 수준 역량:
- 고급 AI 프레임워크(LangChain, LangGraph) 탐색 준비 완료
- 멀티모달 AI 애플리케이션(텍스트, 이미지, 음성) 개발 역량
- 벡터 데이터베이스 및 검색 시스템 구현 가능
- 머신러닝 및 AI 모델 미세 조정 기반 마련
GitHub Copilot 에이전트 챌린지 🚀
에이전트 모드를 사용해 다음 과제를 수행하세요:
설명: 대화 기록과 메시지 지속성을 채팅 어시스턴트에 추가하세요. 이 챌린지는 채팅 애플리케이션의 상태 관리와 데이터 저장 기능 구현 방법을 이해하는 데 도움을 줍니다.
과제: 채팅 애플리케이션을 수정하여 세션 간에도 유지되는 대화 기록 기능을 포함시키세요. 채팅 메시지를 로컬 스토리지에 저장하고, 페이지 로드 시 대화 기록을 표시하며, "기록 지우기" 버튼을 추가하세요. 또한 타이핑 인디케이터와 메시지 타임스탬프도 구현해 채팅 경험을 더 실감나게 만드세요.
agent mode에 대해 더 알아보세요.
과제: 나만의 AI 어시스턴트 만들기
이제 자신만의 AI 어시스턴트 구현을 시작합니다. 튜토리얼 코드를 단순 복제하는 대신, 배운 개념을 적용해 자신만의 관심사와 용례를 반영한 무언가를 만들어 보세요.
프로젝트 요구사항
깨끗하고 체계적인 구조로 프로젝트를 설정합시다:
my-ai-assistant/
├── backend/
│ ├── api.py # Your FastAPI server
│ ├── llm.py # AI integration functions
│ ├── .env # Your secrets (keep this safe!)
│ └── requirements.txt # Python dependencies
├── frontend/
│ ├── index.html # Your chat interface
│ ├── app.js # The JavaScript magic
│ └── styles.css # Make it look amazing
└── README.md # Tell the world about your creation
핵심 구현 작업
백엔드 개발:
- FastAPI 코드를 자신의 방식으로 만들기
- 독특한 AI 성격 만들기 – 요리 도우미, 창작 파트너, 공부 친구 등
- 오류가 발생해도 앱이 멈추지 않도록 견고한 에러 처리 추가
- API 작동 방식을 이해할 수 있도록 명확한 문서 작성
프론트엔드 개발:
- 직관적이고 환영받는 느낌의 채팅 인터페이스 구축
- 자랑할 만한 깨끗하고 최신 JavaScript 작성
- AI 성격을 반영한 맞춤형 스타일링 디자인 – 재미있고 컬러풀? 깔끔하고 미니멀? 자유롭게!
- 휴대폰과 컴퓨터 모두에서 잘 작동하도록 보장
개인화 요구사항:
- AI 어시스턴트 전용 고유 이름과 캐릭터 선택 – 자신의 관심사나 해결하고자 하는 문제에 맞게
- 어시스턴트 분위기에 맞는 시각 디자인 커스터마이즈
- 사용자들이 대화를 시작하고 싶어 하도록 매력적인 환영 메시지 작성
- 다양한 질문으로 어시스턴트를 테스트하여 반응 평가
향상 아이디어 (선택 사항)
프로젝트를 한 단계 끌어올리고 싶나요? 다음과 같은 재미있는 아이디어를 탐색해 보세요:
| 기능 | 설명 | 연습할 기술 |
|---|---|---|
| 메시지 기록 | 페이지 새로고침 후에도 대화 기억 | localStorage, JSON 처리 |
| 타이핑 인디케이터 | 응답 대기 중 "AI가 입력 중..." 표시 | CSS 애니메이션, 비동기 프로그래밍 |
| 메시지 타임스탬프 | 각 메시지 전송 시간 표시 | 날짜/시간 포맷, UX 디자인 |
| 채팅 내보내기 | 대화 내용을 다운로드 기능으로 제공 | 파일 처리, 데이터 내보내기 |
| 테마 전환 | 라이트/다크 모드 토글 기능 | CSS 변수, 사용자 환경 설정 |
| 음성 입력 | 음성 → 텍스트 기능 추가 | 웹 API, 접근성 |
테스트 및 문서화
품질 보증:
- 다양한 입력 유형과 경계 조건으로 애플리케이션 테스트
- 여러 화면 크기에서 반응형 디자인 확인
- 키보드 내비게이션 및 화면 읽기 프로그램으로 접근성 확인
- HTML 및 CSS 표준 준수 검증
문서화 요구사항:
- 프로젝트 설명과 실행 방법을 담은 README.md 작성
- 채팅 인터페이스 사용 모습 스크린샷 포함
- 추가한 고유 기능 또는 커스터마이징 문서화
- 다른 개발자를 위한 명확한 설정 안내 제공
제출 지침
프로젝트 제출물:
- 소스코드 전체가 포함된 프로젝트 폴더
- 프로젝트 설명 및 설정 안내가 담긴 README.md
- 채팅 어시스턴트 실행 화면 스크린샷
- 학습한 내용과 겪은 어려움에 대한 짧은 회고
평가 기준:
- 기능성: 채팅 어시스턴트가 기대한 대로 작동하는가?
- 코드 품질: 코드가 잘 조직되고 주석 처리, 유지보수가 용이한가?
- 디자인: 인터페이스가 시각적으로 매력적이고 사용자 친화적인가?
- 창의성: 구현이 얼마나 독창적이고 개인화되었는가?
- 문서화: 설치 안내와 설명이 명확하고 완전한가?
💡 성공 팁: 기본 요구사항부터 시작하고, 모두 잘 작동하면 기능을 추가하세요. 고급 기능 전에 핵심 경험을 우선 다듬으세요.
솔루션
보너스 챌린지
AI 어시스턴트를 한 단계 더 발전시키고 싶나요? AI 통합과 웹 개발에 대한 이해를 깊게 해주는 고급 도전에 도전해 보세요.
퍼스널리티 커스터마이징
진짜 마법은 AI 어시스턴트에게 독특한 성격을 부여할 때 일어납니다. 다양한 시스템 프롬프트를 실험해 전문적 도우미부터 특화된 어시스턴트까지 만들어 보세요:
전문 어시스턴트 예시:
call_llm(message, "You are a professional business consultant with 20 years of experience. Provide structured, actionable advice with specific steps and considerations.")
창의적 글쓰기 도우미 예시:
call_llm(message, "You are an enthusiastic creative writing coach. Help users develop their storytelling skills with imaginative prompts and constructive feedback.")
기술 멘토 예시:
call_llm(message, "You are a patient senior developer who explains complex programming concepts using simple analogies and practical examples.")
프론트엔드 향상
다음 시각적 및 기능적 개선을 통해 채팅 인터페이스를 변모시켜 보세요:
고급 CSS 기능:
- 부드러운 메시지 애니메이션과 전환 구현
- CSS 쉐이프와 그라데이션으로 사용자 정의 채팅 버블 디자인 추가
- AI가 "생각 중"일 때 타이핑 인디케이터 애니메이션 제작
- 이모지 반응 또는 메시지 평가 시스템 디자인
JavaScript 향상:
- 키보드 단축키 추가(Ctrl+Enter로 전송, Esc로 입력 초기화)
- 메시지 검색 및 필터링 기능 구현
- 대화 내보내기 기능 만들기(텍스트 또는 JSON 형태로 다운로드)
- 메시지 손실 방지용 자동 저장 기능(localStorage 활용)
고급 AI 통합
복수 AI 퍼스널리티:
- 다양한 AI 성격을 선택할 수 있는 드롭다운 생성
- 사용자의 선호하는 퍼스널리티 localStorage에 저장
- 대화 흐름 유지하는 컨텍스트 전환 구현
스마트 응답 기능:
- 대화 컨텍스트 인식 추가 (AI가 이전 메시지 기억)
- 대화 주제에 따른 스마트 제안 기능 구현
- 일반 질문에 대한 빠른 답장 버튼 생성
🎯 학습 목표: 이 보너스 도전 과제들은 프로덕션 애플리케이션에서 사용되는 고급 웹 개발 패턴과 AI 통합 기법을 이해하는 데 도움이 됩니다.
요약 및 다음 단계
축하합니다! 여러분은 AI 기반 채팅 어시스턴트를 처음부터 완성하였습니다. 이 프로젝트는 현대 웹 개발 기술과 AI 통합을 직접 체험할 수 있는 소중한 경험을 제공하였습니다. 이 기술들은 오늘날 기술 환경에서 점차 중요해지고 있습니다.
여러분이 성취한 내용
이번 수업 전반에 걸쳐 여러 핵심 기술과 개념을 익혔습니다:
백엔드 개발:
- AI 기능을 위해 GitHub Models API 연동
- Flask를 사용하여 적절한 오류 처리와 함께 RESTful API 구축
- 환경 변수를 이용한 보안 인증 구현
- 프론트엔드와 백엔드 간 교차 출처 요청을 위한 CORS 설정
프론트엔드 개발:
- 의미론적 HTML을 사용한 반응형 채팅 인터페이스 제작
- async/await 및 클래스 기반 아키텍처를 활용한 현대적 자바스크립트 구현
- CSS Grid, Flexbox, 애니메이션을 통한 매력적인 UI 디자인
- 접근성 기능과 반응형 디자인 원칙 추가
풀스택 통합:
- HTTP API 호출로 프론트엔드와 백엔드 연결
- 실시간 사용자 상호작용과 비동기 데이터 흐름 처리
- 애플리케이션 전반에 오류 처리 및 사용자 피드백 구현
- 사용자 입력부터 AI 응답까지 전체 워크플로우 테스트
주요 학습 성과
mindmap
root((AI 채팅 앱 스킬))
API Integration
Authentication
Error Handling
Async Programming
Web Development
HTML5 시맨틱스
모던 CSS
ES6+ 자바스크립트
User Experience
반응형 디자인
접근성
실시간 상호작용
AI Understanding
프롬프트 엔지니어링
모델 파라미터
대화 흐름
이 프로젝트를 통해 AI 기반 애플리케이션 구축의 기본을 익혔으며, 이는 웹 개발의 미래를 의미합니다. 이제 AI 기능을 기존 웹 애플리케이션에 통합하여 지능적이고 반응적인 사용자 경험을 만드는 방법을 이해하셨습니다.
전문적인 적용 분야
이번 수업에서 개발한 기술은 현대 소프트웨어 개발 경력에 직접 통용됩니다:
- 최신 프레임워크 및 API를 사용하는 풀스택 웹 개발
- 웹 및 모바일 앱 내 AI 통합
- 마이크로서비스 아키텍처용 API 설계 및 개발
- 접근성과 반응형 디자인 중심의 사용자 인터페이스 개발
- 환경 구성 및 배포를 포함한 DevOps 실무
AI 개발 여정 계속하기
다음 학습 단계:
- 더 고급 AI 모델 및 API (GPT-4, Claude, Gemini) 탐색
- 더 나은 AI 응답을 위한 프롬프트 엔지니어링 기법 학습
- 대화 설계 및 챗봇 사용자 경험 원칙 연구
- AI 안전성, 윤리, 책임 있는 AI 개발 관행 조사
- 대화 기억 및 컨텍스트 인식이 포함된 복잡한 애플리케이션 개발
고급 프로젝트 아이디어:
- AI 중재 기능을 갖춘 다중 사용자 채팅룸
- AI 기반 고객 서비스 챗봇
- 개인 맞춤형 학습을 제공하는 교육용 튜터 어시스턴트
- 다양한 AI 인격을 가진 창의적 글쓰기 협력자
- 개발자를 위한 기술 문서 보조 도구
GitHub Codespaces 시작하기
클라우드 개발 환경에서 이 프로젝트를 시도해보고 싶나요? GitHub Codespaces는 브라우저에서 완벽한 개발 환경을 제공하며, 로컬 환경 설정 없이도 AI 애플리케이션을 실험하기에 이상적입니다.
개발 환경 설정
1단계: 템플릿으로 만들기
- Web Dev For Beginners repository로 이동
- 우측 상단에서 "Use this template" 클릭 (GitHub 로그인 필요)
2단계: Codespaces 실행
- 새로 만든 저장소 열기
- 초록색 "Code" 버튼 클릭 후 "Codespaces" 선택
- "Create codespace on main" 선택하여 개발 환경 시작
3단계: 환경 구성
Codespace가 로드되면 다음을 사용할 수 있습니다:
- Python, Node.js 등 필수 개발 도구 사전 설치
- 웹 개발용 확장 프로그램이 포함된 VS Code 인터페이스
- 백엔드와 프론트엔드 서버 실행용 터미널 접근
- 애플리케이션 테스트용 포트 포워딩
Codespaces의 이점:
- 로컬 환경 설정 및 구성 문제 제거
- 다양한 기기에서 일관된 개발 환경 제공
- 웹 개발용 도구 및 확장 사전 구성 포함
- 버전 관리와 협업을 위한 GitHub와 원활한 통합
🚀 프로 팁: Codespaces는 복잡한 환경 설정을 자동으로 처리해주기 때문에 AI 애플리케이션 학습과 프로토타입 제작에 완벽하며, 설정 문제 대신 개발과 학습에 집중할 수 있습니다.
면책 조항:
이 문서는 AI 번역 서비스 Co-op Translator를 사용하여 번역되었습니다. 정확성을 위해 최선을 다하고 있지만, 자동 번역에는 오류나 부정확한 부분이 포함될 수 있음을 유의하시기 바랍니다. 원문 문서가 권위 있는 출처로 간주되어야 합니다. 중요한 정보의 경우 전문 인간 번역을 권장합니다. 본 번역의 사용으로 인해 발생하는 오해나 잘못된 해석에 대해 당사는 책임을 지지 않습니다.




