프로젝트 1: 웹앱 (기획+시작)
오늘부터 2주 동안 '입력하면 AI가 처리해서 보여주는' 웹앱을 만듭니다. 먼저 선생님과 함께 대표 사례를 만들어 본 뒤, 내가 만들 프로젝트를 정하고 화면 뼈대까지 시작해요.
오늘 배우는 것
웹앱 프로젝트는 크게 입력 → 처리 → 출력 세 덩어리로 이루어져요. 오늘은 이 구조를 직접 만든 뒤, 내 프로젝트의 첫 화면까지 시작해봅니다.
오늘의 흐름 한눈에
처음 나오는 것 — 입력→처리→출력
지금까지 여러분이 만든 웹앱은 화면에 버튼과 결과만 있었어요. 오늘부터는 그 화면을 세 덩어리로 나눠서 생각해볼게요. 모든 웹앱 프로젝트가 이 구조 위에서 만들어지거든요.
"입력 → 처리 → 출력". 앞으로 어떤 앱을 만들든 이 세 단어를 먼저 떠올리면 설계의 절반은 끝난 거예요.
- "처리가 꼭 AI여야 하나요?" → 아니에요. 계산기처럼 단순 계산도 처리예요. 오늘은 그중에서 AI로 처리하는 것뿐이에요.
- "출력이 화면 말고도 있나요?" → 소리·파일도 출력이 될 수 있지만, 오늘은 화면에 보여주는 출력만 다뤄요.
세 덩어리를 그림처럼 떠올리기
글로만 보면 어려우니, 세 상자가 이어진 그림으로 상상해 보세요.
[ 입력 상자 ] → [ 처리 상자 ] → [ 출력 상자 ]
사용자 글 AI가 요약 화면에 표시
(text_area) (ask_ai) (st.write)다시 만나는 것 — Claude API
API·API 키·system prompt는 기초 과정에서 이미 배웠죠. 오늘은 새로 배우는 게 아니라, Claude Code에게 코드를 부탁하는 것과 내 프로그램이 직접 AI를 부르는 것이 어떻게 다른지 살펴볼게요.
- Claude Code로 코드를 받았다고 API가 저절로 연결되는 건 아니에요 — 앱 안에
ask_ai()가 있어야 해요. - API 키는 사람이 로그인할 때 쓰는 비밀번호가 아니에요. 앱이 AI에게 가는 문을 여는 열쇠라고 생각하면 돼요.
API 키는 어떻게 쓰이나요 — 복습 포인트
API 키는 기초에서 배운 그대로예요. 오늘은 딱 세 가지만 다시 확인해요.
- 키는 선생님이 나눠준 것을 써요. 직접 발급받지 않아요.
- 키를 화면이나 채팅창에 붙여넣지 않아요.
- 키가 안 먹히면 코드가 아니라 키 설정부터 확인해요.
"부탁하기" vs "고용하기" 다시 정리
오늘 가장 헷갈리기 쉬운 두 가지를 표로 다시 짚어요.
Claude Code에게 부탁 : 개발할 때, 나 대신 코드를 써 줌 (한 번)
내 앱이 API를 호출 : 앱이 돌 때, 손님마다 AI가 답함 (매번)ask_ai()로 Claude API를 직접 불러요. 둘은 하는 때가 달라요.오늘 배우는 핵심은 "내 앱이 스스로 AI를 부르게 만드는 것"이에요. 개발 도우미로서의 Claude Code와 헷갈리지 않도록 이 차이를 꼭 기억해요.
내 앱이 AI를 부르는 순간을 그림으로
사용자가 버튼을 누르면 앱 안에서 어떤 일이 벌어지는지 순서대로 그려볼게요.
사용자 → [버튼] → 앱이 ask_ai(질문) 호출
→ Claude API가 답을 만듦
→ 앱이 답을 받음 → 화면에 표시ask_ai() 한 줄 안에 들어 있어요. 우리는 그 함수를 부르기만 하면 됩니다.웹앱 = 입력 → 처리 → 출력
앞으로 여러분이 만들 모든 프로젝트는 이 세 덩어리로 쪼개서 생각할 수 있어요. 오늘 함께 만드는 '3줄 요약기'도 마찬가지예요.
st.text_area 같은 위젯을 씁니다.ask_ai()에 넘겨 Claude API가 처리한 답을 받습니다.st.write() 등으로 처리된 결과를 화면에 보여줍니다.- 입력 위젯을 안 만들고 코드에 값을 고정해 버림 → 사용자가 값을 바꿀 수 없어요.
- 처리 결과를 화면에 안 보여줌 →
st.write()같은 출력 줄을 빠뜨리기 쉬워요. - 처리와 출력을 한 줄에 섞어 써서 나중에 고치기 어려워져요.
🔒 힌트 — 내 앱을 세 덩어리로 나눠보기
만들고 싶은 앱이 떠올랐다면, 아래 빈칸을 말로 채워보세요. 세 칸이 다 채워지면 설계가 끝난 거예요.
세 덩어리가 실제로 어떻게 도는지
입력→처리→출력 구조가 실제로 어떻게 도는지, 출력까지 미리 보여줄게요. 지금은 눈으로만 훑어도 충분해요.
정중체 : 내일 회의 시간을 알려주시면 감사하겠습니다.
반말 : 내일 회의 몇 시야? 알려줘.
사투리 : 낼 회의 및 시고? 좀 알키도.앱마다 입력과 출력의 내용만 다를 뿐, "받고 → 맡기고 → 보여준다"는 흐름은 똑같아요. 이 감각만 잡으면 어떤 앱이든 시작할 수 있어요. 다음 미션에서 "무엇을 처리할지"를 정하는 게, 곧 내 앱이 무엇이 될지를 정하는 일이에요.
3줄 요약기 같이 만들기
① API 키 준비 — 복습
API 키는 기초에서 이미 .env로 다뤄봤죠. 이번에도 원리는 같아요. 배포할 때는 st.secrets가 그 역할을 대신합니다. 선생님이 나눠준 키를 아래처럼 저장하세요.
OPENAI_API_KEY=여기에_선생님이_알려준_키_붙여넣기- 키 앞뒤 공백·따옴표 없이 딱 붙여 저장.
.env는app.py와 같은 폴더에..env는 GitHub에 올리지 않기 — 배포 시엔 Secrets 칸에.
② ask_ai 함수 정의 — openai SDK로
지금까지는 AI를 부르는 함수를 만들 때 다른 도구를 쓰기도 했어요. 오늘은 openai 파이썬 SDK라는 도구로 ask_ai()를 새로 만듭니다. 이 함수는 앞으로 매주 그대로 다시 쓸 거예요.
from openai import OpenAI
client = OpenAI() # 키는 .env / secrets에서 자동으로
def ask_ai(prompt):
res = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}]
)
return res.choices[0].message.contentclient = OpenAI().env에서 자동으로 가져와요.def ask_ai(prompt):ask_ai예요.client.chat.completions.create(...)return res.choices[0].message.contentask_ai("...")를 부르면 벌어지는 일ask_ai("안녕?")이라고 쓰면 함수 안에서 Claude에게 "안녕?"이 배달되고 잠시 뒤 답장이 글자로 돌아와요. 우리는 그 답을 받아서 화면에 보여주기만 하면 돼요.ask_ai()를 한 번 만들어 두면, 앱 어디서든 이름만 부르면 AI를 쓸 수 있어요. 요약할 때도, 변환할 때도, 추천할 때도 같은 함수를 재사용해요.ask_ai() 정의는 앱에 딱 한 번만 있으면 돼요. 그다음부터는 필요할 때마다 ask_ai(...)로 부르기만 하면 됩니다.
ask_ai()를 정의만 하고 부르지 않음 → 버튼 안에서ask_ai(prompt)로 실제 호출해야 해요.return을 빠뜨림 → 답이 안 돌아와 화면이 비어요.res.choices[0].message.content에서[0]을 빠뜨림 → 글자만 못 꺼내요.
"Claude Code에게 시켜서 코드를 받는 것"은 여러분이 지금 이 순간 하고 있는 일이에요. 반면 ask_ai()는 여러분이 만든 앱이 실행되는 동안 앱 스스로 Claude에게 질문을 보내고 답을 받는 거예요. 앱은 옆에 사람이 없어도 이 일을 혼자 해낼 수 있어요.
🔒 힌트 — ask_ai가 왜 이렇게 생겼는지 한 줄씩
③ ask_ai를 한 번 테스트해 보기
화면을 만들기 전에, ask_ai()가 잘 도는지 짧은 질문으로 먼저 확인해요.
print(ask_ai("안녕? 한 문장으로 인사해줘."))안녕하세요! 오늘도 좋은 하루 보내세요.- 답 대신 에러가 뜸 → 대부분 키 설정 문제예요. 선생님께 확인 요청.
- 한참 멈춤 → 인터넷 연결을 확인해요. AI 응답은 잠깐 시간이 걸려요.
④ 입력→처리→출력 화면 만들기
이제 앞서 배운 세 덩어리를 그대로 코드에 옮깁니다.
import streamlit as st
st.title("📝 3줄 요약기")
# ── ① 입력 ──
text = st.text_area("긴 글을 붙여넣으세요")
# ── ② 처리 ──
if st.button("요약하기"):
prompt = f"다음 글을 3줄로 요약해줘:\n{text}"
result = ask_ai(prompt)
# ── ③ 출력 ──
st.write(result)st.text_area(...) — 입력text에 담겨요.if st.button(...) — 버튼prompt = f"...{text}" — 처리 준비st.write(result) — 출력ask_ai()가 돌려준 요약을 화면에 그대로 보여줘요.f"...{text}"가 뭐예요?{text} 자리에 사용자가 넣은 글이 그대로 끼워 넣어져요. 그래서 매번 다른 글을 넣어도 똑같은 지시문 틀로 요약을 부탁할 수 있어요.if st.button아래 줄을 들여쓰기 안 함 → 버튼과 상관없이 늘 실행돼요.st.write()를 빠뜨림 → 요약은 됐는데 화면에 안 보여요.text대신 다른 이름을 씀 → 위젯 변수명과 똑같이 맞춰야 해요.
ask_ai() 정의가 먼저 나오고, 그걸 부르는 화면 코드가 나중에 나와야 해요. 순서가 바뀌면 "그런 함수 없다"는 에러가 나요.st.로 시작하는 줄은 모두 화면에 무언가를 그리는 명령이에요. 반대로 ask_ai()는 화면이 아니라 AI를 부르는 명령이에요.
⑤ 프롬프트를 다듬으면 결과가 달라져요
같은 글이라도 prompt에 어떻게 부탁하느냐에 따라 요약 모양이 달라져요. 두 가지를 비교해 볼게요.
prompt = f"다음 글을 3줄로 요약해줘:\n{text}"
# prompt = f"다음 글을 초등학생도 알게 3줄로:\n{text}"기본 : 1. 삼성전자가 청소년 10만 명에게 AI 교육을 지원한다.
초등 : 1. 큰 회사가 학생들에게 AI 공부를 도와줘요.
2. 인터넷으로도 교실에서도 배울 수 있어요.🔒 힌트 — 좋은 프롬프트 쓰는 법
⑥ 앱 실행하기
streamlit run app.py📝 3줄 요약기
[ 긴 글을 붙여넣으세요 ]
[ 요약하기 ]
1. 삼성전자가 청소년 10만 명에게 AI 교육을 지원한다.
2. 전국 중·고등학생이 온·오프라인으로 참여할 수 있다.
3. 디지털 격차 해소와 인재 양성이 목표다.ModuleNotFoundError: openai→(venv)상태에서pip install openai다시 설치.- 요약이 안 나옴 →
text가 비어있는 채로 버튼을 눌렀는지 확인. - 요약이 너무 김 → 프롬프트에 "각 줄 한 문장, 딱 3줄만"을 명시.
- 버튼을 눌러도 반응 없음 →
if st.button(...)아래 코드의 들여쓰기를 확인. - 같은 글인데 매번 요약이 조금씩 다름 → AI 특성이에요, 정상입니다.
- 터미널에
streamlit: command not found→ 가상환경(venv)이 켜졌는지 확인. - 브라우저가 안 열림 → 터미널에 뜬
localhost주소를 직접 눌러요. - 수정했는데 화면이 그대로 → 브라우저 오른쪽 위 Rerun을 눌러요.
⑦ 프로젝트 예시 모음 — 이런 웹앱도 만들 수 있어요
방금 함께 만든 3줄 요약기는 다섯 가지 예시 중 하나일 뿐이에요. 다음 미션에서 내 프로젝트를 정할 때, 아래 예시를 참고해도 되고 완전히 다른 아이디어를 내도 좋아요.
다섯 개 중 하나를 그대로 베끼라는 뜻이 아니에요. "이 정도 폭으로 자유롭게 정해도 된다"는 감각을 가지려는 거예요. 다음 미션에서 여기 없는 아이디어를 내도 좋아요.
- 다섯 개를 다 만들려고 하지 마세요 → 다음 미션에서 딱 하나만 골라요.
- 예시와 똑같이 만들 필요 없어요 → 입력·출력만 내 식으로 바꿔도 새 앱이에요.
🔒 힌트 — 예시마다 입력·출력이 뭘까?
⑨ 미션1 코드 전체 흐름 되짚기
지금까지 만든 3줄 요약기의 전체 흐름을 한 번에 훑어볼게요. 준비 → 입력 → 처리 → 출력. 오늘 만든 요약기뿐 아니라, 다음 미션에서 만들 내 프로젝트도 똑같은 순서로 완성돼요.
ask_ai()가 무슨 일을 하는지 말할 수 있다 / ② 코드에서 입력·처리·출력을 손으로 짚을 수 있다 / ③ 프롬프트를 바꾸면 결과가 달라진다는 걸 안다. 이 셋이면 충분해요.이제 진짜 재밌는 부분이에요 — 내 프로젝트를 정할 차례예요. 미션2로 넘어가요!
🔒 힌트 — 에러가 계속 떠요 (전체 참고 코드)
아래 전체 구조와 비교해 내 코드에서 빠진 부분을 찾아보세요.
import streamlit as st
from openai import OpenAI
client = OpenAI()
def ask_ai(prompt):
res = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}])
return res.choices[0].message.content
st.title("📝 3줄 요약기")
text = st.text_area("긴 글을 붙여넣으세요")
if st.button("요약하기"):
st.write(ask_ai(f"다음 글을 3줄로 요약해줘:\n{text}"))키 관련 에러: 키 설정 파일이 제대로 들어갔는지 선생님께 확인을 요청하세요. 학생이 키를 직접 입력하지 않습니다.
내 프로젝트 문제정의 + 핵심기능
3줄 요약기가 잘 돌아간다면, 이제 내 프로젝트를 정할 차례예요. 꼭 지켜야 할 미션은 하나예요 — 입력→처리→출력 흐름을 갖춘 웹앱을 만들고 배포하는 것(배포는 다음 주에 완성해요). 주제는 여러분이 자유롭게 정하면 돼요.
참고 — 프로젝트 아이디어
아이디어가 떠오르지 않는다면 미션1에서 본 프로젝트 예시 모음(3줄 요약기·말투 변환기·재료 레시피 추천기·이름 짓기 도우미·공부 개념 풀이 봇) 중 하나를 골라도 되고, 완전히 다른 자유 주제를 정해도 됩니다.
주제 고르기 — 세 갈래로 생각하기
주제가 안 정해진다면 아래 세 갈래 중 하나를 따라가 보세요.
좋은 핵심기능 vs 아쉬운 핵심기능
같은 주제라도 핵심기능을 어떻게 잡느냐에 따라 오늘 끝낼 수 있는지가 갈려요. 좋은 예: "재료로 만들 요리 하나를 추천한다"(동사 1개). 아쉬운 예: "요리 추천 + 칼로리 계산 + 장보기 목록"(동사 3개).
- "~도 되고 ~도 되면 좋겠다" 생각이 들면 → 기능이 늘어나는 신호예요.
- 화면에 위젯이 다섯 개 넘게 필요하면 → 범위가 너무 커진 거예요.
- 핵심 기능을 3~4개 한꺼번에 정함 → 오늘은 딱 1개만 정해요.
- 문제정의 없이 기능부터 정함 → "누가, 왜 쓰는 앱인지" 한 문장을 먼저 써요.
- 주제가 너무 커서 막힘 → "누구 한 사람"을 정하면 범위가 확 좁아져요.
- 완벽한 걸 찾으려다 시간 다 씀 → 미션1 예시 중 끌리는 것 하나로 바로 시작해요.
- 남과 겹칠까 걱정 → 같은 주제라도 입력·출력을 다르게 하면 완전히 다른 앱이에요.
실제 학생들의 문제정의 예시
이전에 만들어진 문제정의 문장들이에요. 어떤 식으로 한 문장에 담았는지 살펴보세요.
· 뉴스를 오래 읽기 싫은 사람을 위해 핵심만 세 줄로 요약한다.
· 부모님께 정중히 문자 보내고 싶은 학생을 위해 말투를 바꿔준다.
· 냉장고 재료가 아까운 자취생을 위해 만들 요리를 추천한다.
· 발표 제목이 안 떠오르는 사람을 위해 제목 후보를 지어준다.
· 어려운 개념을 못 알아듣는 친구를 위해 눈높이로 풀어준다.🔒 힌트 — 문제정의 문장 틀
아래 빈칸만 채우면 문제정의 한 문장이 완성돼요.
예) "요리 초보를 위해, 남은 재료로 만들 요리를 추천해준다."
🔒 힌트 — 핵심기능 1개로 좁히는 법
기능이 여러 개 떠오르면, "이거 하나가 없으면 앱이 성립 안 되는 것"을 골라요.
내 프로젝트 화면 뼈대 만들기
문제정의와 핵심기능을 정했다면, 오늘은 입력 부분까지만 만들어볼게요. 처리(AI 연동)와 출력은 다음 주에 이어서 완성해요.
오늘 만드는 범위
st.title()로 내 앱 이름을 정합니다.st.text_input, st.text_area, st.selectbox 등)st.title("🗣️ 말투 변환기")
# ── ① 입력 ──
text = st.text_area("바꿀 문장을 입력하세요")
style = st.selectbox("바꿀 말투", ["정중체", "반말", "사투리"])
if st.button("변환하기"):
st.write("여기에 다음 주 처리 결과가 나올 거예요")🗣️ 말투 변환기
[ 바꿀 문장을 입력하세요 ]
바꿀 말투: [ 정중체 ▾ ]
[ 변환하기 ]
여기에 다음 주 처리 결과가 나올 거예요다른 입력 위젯도 골라보기
입력 위젯은 앱 성격에 따라 다르게 골라요. 아래 세 가지가 대표적이에요. (재료 레시피 추천기처럼 한 줄 입력이 필요하면 st.text_input을 쓰면 돼요 — 뒤에서 전체 코드를 함께 볼게요.)
실제로 여러 프로젝트의 첫 화면을 로컬에서 띄워봤어요. 어떤 위젯을 골랐는지 비교해 보세요.
위젯을 만들면 사용자가 넣은 값이 왼쪽 변수에 담겨요(예: text = st.text_area(...)). 다음 주엔 이 변수를 ask_ai()에 넘겨 처리해요.
🔒 힌트 — 어떤 위젯을 몇 개 놓을까
핵심기능 1개에 필요한 입력 하나면 충분해요. 선택이 필요하면 selectbox를 하나 더 놓아도 돼요. 위젯이 많아지면 오늘 범위를 넘겨요.
🔒 힌트 — 버튼을 눌러도 아무 일도 안 일어나요
오늘은 그게 정상이에요! 버튼 아래에 st.write("...예정") 한 줄만 있으면 성공이에요. 진짜 처리는 다음 주에 ask_ai()를 붙여서 완성해요.
🃏 선택지 카드 — 어떤 프로젝트로 시작할까?
카드별 AI 요청 예시 — 이렇게 부탁하면 돼요
화면 뼈대를 AI 도구에게 부탁할 때, 아래처럼 요청하면 원하는 위젯이 붙은 코드를 받을 수 있어요.
처음부터 끝까지 — 레시피 추천기로 따라 해보기
한 가지 예시(레시피 추천기)로 오늘 만들 화면을 처음부터 끝까지 따라가 볼게요. 제목 정하기 → 입력 위젯 놓기 → 버튼 놓기 순서예요.
import streamlit as st
st.title("🍳 재료 레시피 추천기")
items = st.text_input("가진 재료를 쉼표로 적어주세요")
if st.button("추천받기"):
st.write("여기에 다음 주 추천 결과가 나올 거예요")🍳 재료 레시피 추천기
[ 가진 재료를 쉼표로 적어주세요 ]
[ 추천받기 ]
여기에 다음 주 추천 결과가 나올 거예요이렇게 제목 + 입력 + 버튼이 보이면 오늘 미션3 완료예요. 다음 주에 ask_ai()를 붙여 진짜 추천이 나오게 만들어요.
- 오늘부터 AI 연동까지 하려다 시간 부족 → 오늘은 입력 화면까지만 목표로 해요.
- 위젯 종류를 고민만 하다 시간 다 씀 → 일단 아무 위젯이나 놓고 실행해본 뒤 바꿔도 돼요.
- 제목에 이모지를 안 넣어도 괜찮아요 → 기능이 먼저, 꾸미기는 나중에.
- AI에게 범위를 안 알려줌 → 처리·출력까지 다 만들어 줘서 오늘 범위를 넘겨요.
- 터미널에 빨간 에러가 있나요? → 있으면 몇 번째 줄인지 먼저 봐요.
st.title(...)의 괄호·따옴표가 짝이 맞나요?- 파일을 저장했나요? → 저장 후 Rerun을 눌러요.
🔒 힌트 — 입력 위젯 고르는 법
내 앱이 받을 값의 성격으로 위젯을 고르면 돼요.
다음 주엔 이렇게 완성돼요 — 미리보기
오늘 만든 뼈대에 ask_ai()를 붙이면 다음 주엔 이런 앱이 돼요 — 제목과 입력창 아래로 진짜 요약·변환·추천 결과가 나오게 됩니다. 완성 모습을 미리 그려보면 오늘 화면을 만들 때 방향이 또렷해져요.
ask_ai()의 진짜 결과가 들어가요. 화면 뼈대는 오늘 것을 그대로 씁니다. 어떤 프로젝트를 골랐든 원리는 같아요.완성이 아니라 화면 뼈대예요. 제목과 입력 위젯이 뜨고 버튼이 눌리면 오늘은 100점이에요.
다음 주 완성까지 남은 두 조각
오늘 뼈대를 만들었으니, 완성까지 남은 건 딱 두 조각이에요 — 버튼 안에 ask_ai(prompt)를 넣어 처리를 붙이고, 받은 결과를 st.write()로 출력에 연결하는 것.
- 입력값을 변수에 안 담음 → 다음 주에 그 변수를 못 써요.
- 버튼 라벨을 안 정함 → 무슨 앱인지 헷갈려요. 명확한 이름을 붙여요.
더 해보고 싶다면
미션 3까지 끝내고 시간이 남는다면 도전해 보세요. 다 못해도 괜찮아요.
보너스 ① system prompt로 AI 성격 정하기
system prompt는 기초에서 이미 배웠죠. 오늘은 그걸 ask_ai() 함수 안에 넣어서, 내 프로젝트의 AI가 항상 같은 태도로 답하게 만들어볼게요.
def ask_ai(prompt):
res = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "너는 친절하고 간결하게 답하는 도우미야."},
{"role": "user", "content": prompt}
])
return res.choices[0].message.content{"role": "system", ...}는 Claude에게 "너는 이런 성격/역할이야"라고 미리 알려주는 자리예요. 매번 질문할 때마다 반복해서 설명하지 않아도 돼요. 같은 질문이라도 system prompt에 따라 답의 말투와 태도가 달라져요. 세 가지를 비교해 볼게요.
친절한 도우미 : 안녕하세요! 무엇을 도와드릴까요?
깐깐한 선생님 : 안녕하세요. 오늘은 무엇을 점검해 볼까요?
재밌는 친구 : 오~ 안녕! 오늘 뭐 재밌는 거 없어?content)는 이번 한 번의 질문이고, system prompt는 대화 내내 유지되는 성격이에요. 그래서 "항상 이렇게 답해줘"는 system에, "이번엔 이걸 물어봐"는 content에 넣어요.- 너무 길게 씀 → 한두 문장이면 충분해요.
- 질문(content)에 넣을 내용을 system에 넣음 → 역할·태도만 system에.
🔒 힌트 — 내 프로젝트에 맞는 system prompt
보너스 ② 내 프로젝트 이름 정하고 노션에 기록
정한 문제정의·핵심기능·앱 이름을 노션 포트폴리오 공간에 한 줄씩 정리해보세요. 다음 주 완성본과 비교할 기준이 됩니다.
- system을 바꾸고 저장·Rerun을 안 함 → 예전 답이 그대로 보여요.
- 규칙을 너무 많이 넣음 → 서로 부딪혀서 답이 이상해져요.
🔒 힌트 — 노션에 남길 항목 체크
- 성격을 너무 세게 잡음(반말·장난) → 정보 전달 앱엔 안 맞을 수 있어요.
- 매번 성격이 바뀜 → system prompt를 고정해 두면 일관돼요.
오늘의 핵심 정리
오늘 배운 것을 한눈에
ask_ai()를 그대로 가져다 써요. 오늘 이 함수를 정확히 이해해 두면 앞으로 훨씬 편해요.다음 주에 이어서 할 것
ask_ai()를 연결해 진짜 결과가 나오게 해요."앱은 입력을 받아, AI에게 맡기고, 결과를 보여준다." 이 한 문장이 오늘 배운 전부예요.
오늘 자주 나온 질문 모음
- 앱이
streamlit run으로 실행되나요? - 제목과 입력 위젯이 화면에 보이나요?
- 내 문제정의 한 문장을 말할 수 있나요?
🔧 막혔을 때 — 자가 디버깅 4단계
에러가 떠도 당황하지 마세요. 선생님께 묻기 전에 이 순서대로 스스로 해결해 볼게요.
오늘 자주 만나는 에러 도감
아래는 오늘 실습에서 가장 자주 나오는 에러들이에요. 메시지를 보고 원인을 빠르게 찾아보세요.
가상환경에 openai 패키지가 없다는 뜻이에요.- 터미널 앞에
(venv)가 있는지 확인. pip install openai을 다시 실행.
들여쓰기(스페이스) 칸 수가 어긋났다는 뜻이에요.if st.button(...)아래 줄은 스페이스 4칸으로 맞춰요.- 탭과 스페이스를 섞지 않아요.
ask_ai 함수를 아직 만들지 않았거나, 이름을 잘못 썼어요.def ask_ai(prompt):정의가 부르는 곳보다 위에 있는지 확인.- 철자를
ask_ai로 정확히 맞춰요.
따옴표를 한쪽만 쓰고 닫지 않았을 때 나와요.- 문자열은
"..."처럼 양쪽 따옴표가 짝이 맞아야 해요. - 에러가 가리키는 줄의 따옴표를 먼저 봐요.
에러는 아니지만, 출력 줄이 빠졌을 수 있어요.- 버튼 안에
st.write(...)가 있는지 확인. - 입력창이 비어 있지 않은지 확인.
ask_ai가 아무것도 못 돌려줬을 때 생겨요.return이 빠지지 않았는지 확인.res.choices[0].message.content까지 정확히 썼는지 확인.
버튼과 상관없이 매번 코드가 도는 경우예요.- 실행할 코드를
if st.button(...):안쪽으로 들여쓰기.
streamlit이 아직 실행 중이 아닐 수 있어요.- 터미널에서
streamlit run app.py를 다시 실행. - 터미널에 뜬
localhost주소를 눌러요.
디버깅 순서 한 장 요약
에러 메시지는 "여기 이걸 고치면 돼"라는 안내문이에요. 빨간 글자를 무서워하지 말고, 몇 번째 줄인지부터 차분히 읽어보세요. 에러는 실패가 아니에요.