LangChain 챗봇2장 · 개발 환경 준비18 / 20← 이전목차다음 →MetaContents

2장. 개발 환경 준비

프로젝트 1 — 내 PC 점검표 만들기

수업 첫날, 수강생마다 PC 상태가 다릅니다. 누구는 가상환경을 켜지 않았고, 누구는 .env 를 다른 폴더에 두었고, 누구는 키 앞에 빈칸을 붙였습니다. 한 번 실행하면 준비가 됐는지 차례로 점검해 "통과 / 확인 필요" 표로 보여 주는 스크립트를 만들어 보세요. 실습 1이 저장한 out_ch02_requirements.txt 를 쓰므로 실습 1을 먼저 해야 합니다. 마지막 점검에서 모델에게 짧은 질문을 하나 보내므로 .env 의 키와 인터넷이 있어야 합니다. 이 절의 출력은 API 키를 받기 전에 실행하지 않고 유추한 예상 출력입니다.

항목내용
쓰는 파일out_ch02_requirements.txt(실습 1이 저장한 "이름==판" 목록), 과목 폴더의 .env
점검할 것파이썬 판, 가상환경, 패키지 판, .env 있음, 키 꼴, 짧은 질문의 답과 걸린 시간
남기는 파일out_ch02_checklist.csv(항목, 결과, 내용의 세 열)

요구사항은 다섯 가지입니다.

  1. 파이썬이 3.12 이상인지, 가상환경 안에서 돌고 있는지 점검합니다.
  2. out_ch02_requirements.txt 의 패키지마다 지금 설치된 판이 목록의 판과 같은지 점검합니다.
  3. .env 를 찾을 수 있는지, OPENAI_API_KEY 가 키의 꼴(sk- 로 시작, 빈칸 없음, 자리표시가 아님, 20글자 이상)인지 점검합니다. 키는 가린 채로만 적습니다.
  4. 키 꼴이 맞으면 짧은 질문 하나를 보내 답과 걸린 시간을 적고, 10초 안에 답이 왔는지 점검합니다. 키 꼴이 틀리면 질문은 건너뛰고 "키를 먼저 확인하세요"라고 적습니다.
  5. 모든 결과를 표로 찍고 통과한 수를 센 뒤 out_ch02_checklist.csv 로 저장합니다.

단계별 힌트입니다.

  1. 점검 결과는 {"항목": …, "결과": "통과" 또는 "확인 필요", "내용": …} 사전을 목록에 쌓습니다. 사전을 더하는 작은 함수 add(item, ok, detail) 를 만들어 두면 편합니다.
  2. 파이썬 판은 sys.version_info >= (3, 12) 처럼 튜플끼리 견줍니다. 가상환경은 실습 1처럼 sys.prefix != sys.base_prefix 입니다.
  3. 목록 파일의 한 줄은 line.split("==") 로 이름과 판으로 나눕니다. 지금 판은 importlib.metadata.version 으로 읽습니다.
  4. find_dotenv(usecwd=True) 는 못 찾으면 빈 글자를 돌려줍니다. 찾았을 때만 load_dotenv 를 부릅니다.
  5. 걸린 시간은 time.perf_counter() 를 질문 앞뒤로 불러 뺍니다. 모델을 부르는 줄은 try/except 로 감싸 오류가 나도 점검표가 끝까지 찍히게 합니다.

확인할 것: 다 풀었으면 항목마다 스스로 확인해 체크해 보세요.

채점 기준배점
파이썬과 가상환경 점검이 맞다15
패키지 판을 목록과 바르게 견줬다20
키를 화면에 그대로 내지 않고 꼴을 점검했다25
질문과 걸린 시간을 재고 오류를 잡았다25
표와 csv 저장, 통과 수가 있다15

코드의 흐름

예시 풀이의 코드가 어떤 차례로 흘러가는지 한 장으로 그렸습니다. 풀기 전에 큰 줄기를 먼저 보고, 풀다가 막히면 지금 어느 상자에 있는지 확인해 보세요.

환경 점검, 키 점검, 질문 하나, 점검표의 네 단계를 이은 코드 흐름도

상자 하나가 예시 풀이의 단계 하나이고, 회청 화살표를 따라가면 실행 차례입니다. 상자 아래의 글은 그 단계에서 쓰는 핵심 코드입니다. 2단계(키 점검)의 결과가 3단계로 넘어가는지 정합니다. 키 꼴이 틀리면 3단계는 질문을 보내지 않고 "확인 필요"만 적은 채 4단계로 갑니다.

결과 보기 (예시 풀이)

1단계. 파이썬과 패키지 점검하기

Python
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 와 키 꼴 점검하기

Python
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단계. 짧은 질문 하나와 걸린 시간 재기

Python
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단계. 점검표 찍고 저장하기

Python
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장부터 생기는 오류가 환경 탓인지 코드 탓인지 가르기 쉽습니다.

← 이전 절2장 · 실습 5 — 오류를 잡아 친절하게 알리기다음 절 →2장 · 정리