2장. 개발 환경 준비
프로젝트 1 — 내 PC 점검표 만들기
수업 첫날, 수강생마다 PC 상태가 다릅니다. 누구는 가상환경을 켜지 않았고, 누구는 .env 를 다른 폴더에 두었고, 누구는 키 앞에 빈칸을 붙였습니다. 한 번 실행하면 준비가 됐는지 차례로 점검해 "통과 / 확인 필요" 표로 보여 주는 스크립트를 만들어 보세요. 실습 1이 저장한 out_ch02_requirements.txt 를 쓰므로 실습 1을 먼저 해야 합니다. 마지막 점검에서 모델에게 짧은 질문을 하나 보내므로 .env 의 키와 인터넷이 있어야 합니다. 이 절의 출력은 API 키를 받기 전에 실행하지 않고 유추한 예상 출력입니다.
| 항목 | 내용 |
|---|---|
| 쓰는 파일 | out_ch02_requirements.txt(실습 1이 저장한 "이름==판" 목록), 과목 폴더의 .env |
| 점검할 것 | 파이썬 판, 가상환경, 패키지 판, .env 있음, 키 꼴, 짧은 질문의 답과 걸린 시간 |
| 남기는 파일 | out_ch02_checklist.csv(항목, 결과, 내용의 세 열) |
요구사항은 다섯 가지입니다.
- 파이썬이 3.12 이상인지, 가상환경 안에서 돌고 있는지 점검합니다.
out_ch02_requirements.txt의 패키지마다 지금 설치된 판이 목록의 판과 같은지 점검합니다..env를 찾을 수 있는지,OPENAI_API_KEY가 키의 꼴(sk-로 시작, 빈칸 없음, 자리표시가 아님, 20글자 이상)인지 점검합니다. 키는 가린 채로만 적습니다.- 키 꼴이 맞으면 짧은 질문 하나를 보내 답과 걸린 시간을 적고, 10초 안에 답이 왔는지 점검합니다. 키 꼴이 틀리면 질문은 건너뛰고 "키를 먼저 확인하세요"라고 적습니다.
- 모든 결과를 표로 찍고 통과한 수를 센 뒤
out_ch02_checklist.csv로 저장합니다.
단계별 힌트입니다.
- 점검 결과는
{"항목": …, "결과": "통과" 또는 "확인 필요", "내용": …}사전을 목록에 쌓습니다. 사전을 더하는 작은 함수add(item, ok, detail)를 만들어 두면 편합니다. - 파이썬 판은
sys.version_info >= (3, 12)처럼 튜플끼리 견줍니다. 가상환경은 실습 1처럼sys.prefix != sys.base_prefix입니다. - 목록 파일의 한 줄은
line.split("==")로 이름과 판으로 나눕니다. 지금 판은importlib.metadata.version으로 읽습니다. find_dotenv(usecwd=True)는 못 찾으면 빈 글자를 돌려줍니다. 찾았을 때만load_dotenv를 부릅니다.- 걸린 시간은
time.perf_counter()를 질문 앞뒤로 불러 뺍니다. 모델을 부르는 줄은try/except로 감싸 오류가 나도 점검표가 끝까지 찍히게 합니다.
확인할 것: 다 풀었으면 항목마다 스스로 확인해 체크해 보세요.
| 채점 기준 | 배점 |
|---|---|
| 파이썬과 가상환경 점검이 맞다 | 15 |
| 패키지 판을 목록과 바르게 견줬다 | 20 |
| 키를 화면에 그대로 내지 않고 꼴을 점검했다 | 25 |
| 질문과 걸린 시간을 재고 오류를 잡았다 | 25 |
| 표와 csv 저장, 통과 수가 있다 | 15 |
코드의 흐름
예시 풀이의 코드가 어떤 차례로 흘러가는지 한 장으로 그렸습니다. 풀기 전에 큰 줄기를 먼저 보고, 풀다가 막히면 지금 어느 상자에 있는지 확인해 보세요.
상자 하나가 예시 풀이의 단계 하나이고, 회청 화살표를 따라가면 실행 차례입니다. 상자 아래의 글은 그 단계에서 쓰는 핵심 코드입니다. 2단계(키 점검)의 결과가 3단계로 넘어가는지 정합니다. 키 꼴이 틀리면 3단계는 질문을 보내지 않고 "확인 필요"만 적은 채 4단계로 갑니다.
결과 보기 (예시 풀이)
1단계. 파이썬과 패키지 점검하기
import os
import sys
import time
from importlib.metadata import PackageNotFoundError, version
from pathlib import Path
import pandas as pd
from dotenv import find_dotenv, load_dotenv
from langchain_openai import ChatOpenAI
# 점검 결과를 {"항목", "결과", "내용"} 사전으로 쌓는다
checks = []
def add(item, ok, detail):
"""점검 하나의 결과를 목록에 더한다. ok 가 True 면 통과."""
checks.append({"항목": item, "결과": "통과" if ok else "확인 필요", "내용": detail})
# 파이썬 판: version_info 는 (3, 14, 6, …) 같은 튜플이라 (3, 12) 와 바로 견줄 수 있다
add("파이썬 3.12 이상", sys.version_info >= (3, 12), sys.version.split()[0])
add("가상환경 안", sys.prefix != sys.base_prefix, Path(sys.prefix).name)
# 실습 1이 저장한 "이름==판" 목록과 지금 설치된 판을 견준다
for line in Path("out_ch02_requirements.txt").read_text(encoding="utf-8").split():
name, want = line.split("==")
try:
now = version(name)
except PackageNotFoundError:
now = None
add(f"{name} 판", now == want, f"목록 {want} / 지금 {now or '없음'}")
print(f"점검한 항목: {len(checks)}개")점검한 항목: 8개코드가 의미하는 것 add(item, ok, detail) 는 점검 하나를 "항목, 결과, 내용" 한 줄로 쌓는 함수로, 뒤의 모든 점검이 같은 꼴로 표에 들어가게 합니다. sys.version_info >= (3, 12) 로 튜플끼리 견줘 판을 확인하고, 실습 1이 남긴 장부(out_ch02_requirements.txt)를 한 줄씩 읽어 지금 판과 견줍니다. 실습 1을 하지 않았다면 이 파일이 없어 여기서 멈춥니다.
2단계. .env 와 키 꼴 점검하기
def mask(key, keep=3):
"""키의 앞 keep 글자만 남기고 뒤는 **** 로 가린다. 키가 없으면 '없음'."""
return key[:keep] + "****" if key else "없음"
def looks_like_key(key):
"""키의 꼴만 본다: sk- 로 시작, 빈칸 없음, 자리표시가 아님, 20글자 이상."""
return bool(key) and key.startswith("sk-") and " " not in key and key != "발급받은_인증키" and len(key) >= 20
# find_dotenv(usecwd=True): 지금 폴더(data)에서 위로 올라가며 .env 를 찾는다. 못 찾으면 ""
env_path = find_dotenv(usecwd=True)
add(".env 파일", env_path != "", Path(env_path).name if env_path else "못 찾음")
if env_path:
load_dotenv(env_path)
key = os.getenv("OPENAI_API_KEY")
key_ok = looks_like_key(key)
add("키 꼴", key_ok, mask(key))
# 모델 이름도 .env 에서 바꿀 수 있게 하고, 없으면 gpt-4.1-mini 를 쓴다
MODEL = os.getenv("OPENAI_MODEL", "gpt-4.1-mini")
print("키 꼴이 맞나:", key_ok, "/", mask(key))키 꼴이 맞나: True / sk-****코드가 의미하는 것 looks_like_key 는 키를 서버에 보내 보기 전에 꼴만 보고 걸러 내는 문지기입니다. 자리표시(발급받은_인증키)를 그대로 둔 경우나 빈칸이 섞인 경우를 여기서 잡으면, 401 을 받으러 서버까지 가지 않아도 됩니다. 결과에는 mask(key) 로 앞 세 글자만 적어 점검표 파일에 키가 남지 않게 합니다.
3단계. 짧은 질문 하나와 걸린 시간 재기
if key_ok:
# timeout=30: 30초 안에 답이 없으면 멈춘다. max_retries=1: 실패하면 한 번만 더 보낸다
model = ChatOpenAI(model=MODEL, temperature=0, timeout=30, max_retries=1)
# perf_counter: 걸린 시간을 재는 초시계. 앞뒤로 불러 뺀다
start = time.perf_counter()
try:
reply = model.invoke("한 낱말로만 답해 줘. 준비됐니?")
seconds = time.perf_counter() - start
add("짧은 질문", True, f"답 '{reply.content}'")
add("10초 안에 답", seconds < 10, f"{seconds:.1f}초")
except Exception as e:
# 오류가 나도 점검표는 끝까지 찍는다. 오류의 이름만 적는다
add("짧은 질문", False, type(e).__name__)
else:
add("짧은 질문", False, "키를 먼저 확인하세요")
print("마지막 점검:", checks[-1]["항목"], "→", checks[-1]["결과"])마지막 점검: 10초 안에 답 → 통과코드가 의미하는 것 if key_ok: 로 키 꼴이 맞을 때만 질문을 보내, 앞 단계가 막히면 뒤 단계를 건너뜁니다. timeout=30 과 max_retries=1 은 답이 오지 않을 때 오래 붙잡혀 있지 않게 하는 장치이고, perf_counter 로 잰 시간은 챗봇 사용자가 답을 기다릴 시간을 어림하게 해 줍니다. 예상 출력의 "통과"는 키를 넣은 PC 를 가정한 것입니다.
4단계. 점검표 찍고 저장하기
table = pd.DataFrame(checks)
print(table.to_string(index=False))
# "통과" 인 줄을 센다. True 를 1 로 더한다
passed = int((table["결과"] == "통과").sum())
print(f"통과 {passed} / {len(table)}")
# utf-8-sig: 엑셀에서 한글이 깨지지 않게 저장한다
table.to_csv("out_ch02_checklist.csv", index=False, encoding="utf-8-sig")
print("저장: out_ch02_checklist.csv") 항목 결과 내용
파이썬 3.12 이상 통과 3.14.6
가상환경 안 통과 .venv
langchain 판 통과 목록 1.4.7 / 지금 1.4.7
langchain-core 판 통과 목록 1.7.3 / 지금 1.7.3
langchain-openai 판 통과 목록 1.7.3 / 지금 1.7.3
openai 판 통과 목록 3.42.1 / 지금 3.42.1
python-dotenv 판 통과 목록 1.2.4 / 지금 1.2.4
tiktoken 판 통과 목록 0.14.0 / 지금 0.14.0
.env 파일 통과 .env
키 꼴 통과 sk-****
짧은 질문 통과 답 '네.'
10초 안에 답 통과 1.0초
통과 12 / 12
저장: out_ch02_checklist.csv.env 에 교수자가 준 키를 넣은 PC 라면 열두 항목이 모두 통과할 것으로 예상합니다. 짧은 질문의 답은 모델마다 "네.", "준비됐어요." 처럼 조금씩 다르고, 걸린 시간도 인터넷 사정에 따라 1초 안팎에서 달라집니다. 키를 넣기 전에는 다르게 나옵니다. 이 교안을 만든 PC 에서 .env 에 자리표시(발급받은_인증키)를 그대로 둔 채 이 풀이를 실제로 돌렸더니, "키 꼴"이 발급받**** 으로 "확인 필요", "짧은 질문"이 "키를 먼저 확인하세요"로 "확인 필요"가 되어 통과 9 / 11 이 찍혔습니다. 키 꼴이 틀려 질문을 보내지 않았으므로 "10초 안에 답" 줄은 생기지 않았습니다. 점검표는 이렇게 막힌 곳과 고칠 곳을 한눈에 보여 줍니다.
코드가 의미하는 것 pd.DataFrame(checks) 로 쌓은 사전을 표로 바꾸고, (table["결과"] == "통과").sum() 으로 통과 수를 셉니다. utf-8-sig 로 저장한 out_ch02_checklist.csv 는 엑셀로 열어 볼 수 있는 점검 기록입니다. 출력의 통과 12 / 12 는 예상 출력이고, 자리표시 키로 실제 돌린 결과는 바로 위 문단의 통과 9 / 11 입니다.
이 프로젝트가 뜻하는 것
이 프로젝트는 가게 문을 열기 전에 주방 점검표를 한 장씩 짚어 가는 일과 같습니다. 조리대와 도구를 세고(1단계), 지갑 속 출입증을 확인하고(2단계), 거래처에 시험 삼아 작은 주문을 하나 넣어 보고(3단계), 점검표를 벽에 붙여 둡니다(4단계). 여기서 조리대와 도구가 가상환경과 패키지, 출입증이 키, 작은 주문이 짧은 질문, 점검표가 out_ch02_checklist.csv 입니다. 비유와 다른 점은, 사람은 점검표를 건너뛰고 싶어 하지만 코드는 매번 빠짐없이 같은 순서로 점검한다는 것입니다.
| 단계 | 출력 | 뜻 |
|---|---|---|
| 1. 파이썬·패키지 | 점검한 항목 8개 | 파이썬과 가상환경 둘, 실습 1의 목록에 있는 패키지 여섯 개를 견줬습니다 |
| 2. 키 꼴 | True / sk-**** | 키의 앞 세 글자만 보이고, 꼴은 맞습니다. 자리표시 그대로면 False 가 됩니다 |
| 3. 짧은 질문 | 10초 안에 답 → 통과 | 진짜 모델에게 질문 하나가 오가는 데 1초 안팎이 걸렸습니다 |
| 4. 점검표 | 통과 12 / 12 | 모두 통과하면 다음 장으로 넘어갈 준비가 끝난 것입니다 |
한 줄로 줄이면, 이 장에서 준비한 것(가상환경, 패키지, .env, 키, 첫 호출)을 한 번에 점검하는 스크립트를 만든 프로젝트입니다. 앞 단계가 막히면 뒤 단계는 무리하게 하지 않고 "확인 필요"와 까닭을 남기게 짰습니다. 키를 넣기 전의 실제 실행에서 통과 9 / 11 이 나온 것처럼, 어느 줄이 막혔는지가 곧 고칠 곳입니다. 수업 첫날이나 PC 를 바꾼 날 한 번 돌려 두면, 3장부터 생기는 오류가 환경 탓인지 코드 탓인지 가르기 쉽습니다.