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

2장. 개발 환경 준비

환경 변수와 .env

지갑 속 출입증은 필요할 때만 꺼내 보입니다. 가게 문을 열 때 지갑에서 꺼내 앞치마 주머니에 옮겨 두면, 일하는 동안에는 주머니에서 바로 꺼내 씁니다. 코드도 같습니다. 키는 .env 파일(지갑)에 두고, 프로그램이 시작할 때 load_dotenv() 로 환경 변수(앞치마 주머니)에 옮긴 뒤, 필요한 곳에서 os.getenv() 로 꺼냅니다.

.env 파일, 환경 변수, 우리 코드, OpenAI 서버를 화살표로 잇고 .env 에서 깃허브·메일로 가는 길은 .gitignore 로 막은 구조도

윗줄의 파랑 화살표가 키가 흘러가는 길입니다. .env 파일의 키가 load_dotenv() 로 환경 변수에 올라가고, 우리 코드가 os.getenv() 로 꺼내, 요청에 실어 OpenAI 서버로 보냅니다. 아래 왼쪽의 회청 점선과 X 는 막아 둔 길로, .gitignore 가 .env 를 깃허브에 올리지 않게 막습니다. 아래 오른쪽 하늘색 점선 상자처럼 코드 파일에는 키가 아니라 키의 이름 OPENAI_API_KEY 만 적힙니다. 여기서 지갑이 .env, 앞치마 주머니가 환경 변수, 출입증을 내미는 손이 요청입니다. 비유와 다른 점은, 환경 변수는 프로그램이 끝나면 사라진다는 것입니다. 다음에 실행할 때 load_dotenv() 가 다시 올립니다.

.env 파일의 꼴

과목 폴더에는 견본 .env.example 이 있습니다. 이 파일을 복사해 이름을 .env 로 바꾸고, 발급받은_인증키 자리에 교수자가 준 키를 넣습니다.

출력
# 이 줄처럼 # 으로 시작하면 설명이다
OPENAI_API_KEY=발급받은_인증키
OPENAI_MODEL=gpt-4.1-mini
지킬 것까닭
= 앞뒤에 빈칸을 두지 않는다빈칸이 키의 일부로 읽힐 수 있다
따옴표로 감싸지 않아도 된다python-dotenv 는 따옴표가 있으면 떼고 읽는다
파일 이름은 .env 하나만.env.txt 로 저장되면 찾지 못한다. 탐색기에서 확장자를 켜고 확인한다
과목 폴더(맨 위)에 둔다find_dotenv(usecwd=True) 가 지금 폴더에서 위로 올라가며 찾는다
OPENAI_MODEL 은 없어도 된다코드가 os.getenv("OPENAI_MODEL", "gpt-4.1-mini") 로 기본값을 쓴다

키를 읽는 세 함수

함수원래 말하는 일
find_dotenv(usecwd=True)find(찾다), use cwd(current working directory, 지금 작업 폴더를 쓰다)지금 폴더에서 위로 올라가며 .env 를 찾아 경로를 돌려준다. 못 찾으면 빈 글자
load_dotenv(경로)load(싣다, 올리다).env 의 줄을 환경 변수로 올린다. 이미 있는 환경 변수는 덮지 않는다
os.getenv(이름, 기본값)get environment variable환경 변수를 읽는다. 없으면 기본값, 기본값도 없으면 None
dotenv_values(경로)values(값들).env 를 사전으로만 읽는다. 환경 변수는 건드리지 않는다

이 과정에서 모델을 부르는 코드는 모두 아래 세 줄로 시작합니다. 실습 코드는 data 폴더에서 돌므로, find_dotenv(usecwd=True) 가 한 칸 위의 과목 폴더에서 .env 를 찾습니다.

출력
load_dotenv(find_dotenv(usecwd=True))
MODEL = os.getenv("OPENAI_MODEL", "gpt-4.1-mini")
model = ChatOpenAI(model=MODEL, temperature=0)

짧은 예시

진짜 .env 를 건드리지 않도록 견본 글을 바로 읽어 봅니다. io.StringIO 는 글자열을 파일처럼 읽게 해 주는 도구입니다(String Input/Output). 견본의 키는 지어낸 시험용 글자입니다.

Python
import io
import os

from dotenv import dotenv_values

# .env 파일에 적을 글과 같은 꼴의 견본. 진짜 키가 아니다
sample = "# 연습용 견본\nTEST_API_KEY=sk-test-0000000000000000\nTEST_MODEL=gpt-4.1-mini\n"

# stream=: 파일 경로 대신 글을 바로 넣는다. 설명 줄(#)은 빠진다
values = dotenv_values(stream=io.StringIO(sample))
print(dict(values))
# dotenv_values 는 사전만 돌려주므로 환경 변수에는 들어가지 않는다
print("환경 변수 TEST_MODEL:", os.getenv("TEST_MODEL"))
# 기본값을 주면 없을 때 그 값을 돌려준다
print("TEST_TIMEOUT:", os.getenv("TEST_TIMEOUT", "30"))
출력
{'TEST_API_KEY': 'sk-test-0000000000000000', 'TEST_MODEL': 'gpt-4.1-mini'}
환경 변수 TEST_MODEL: None
TEST_TIMEOUT: 30

# 으로 시작한 설명 줄은 빠지고 "이름=값" 두 줄만 사전이 되었습니다. 환경 변수에 올리려면 load_dotenv() 를 불러야 하고, 실습 2에서 연습용 파일로 해 봅니다.

코드가 의미하는 것

이 코드는 지갑을 열어 안의 출입증을 들여다보기만 하고, 앞치마 주머니에는 옮기지 않는 일입니다. 견본 글 읽기, 환경 변수 확인, 기본값 쓰기의 세 동작입니다.

코드하는 일챗봇에서 뜻하는 것
io.StringIO(sample)글자열을 파일처럼 읽게 한다진짜 .env 를 건드리지 않고 같은 꼴의 글로 연습합니다
dotenv_values(stream=...)"이름=값" 줄을 사전으로 돌려준다키가 제대로 적혔는지 들여다볼 때 씁니다. 프로그램 전체에는 알리지 않습니다
os.getenv("TEST_MODEL")환경 변수를 읽는다챗봇 코드가 키와 모델 이름을 꺼내는 곳이 환경 변수입니다. 지갑만 열어 본 상태라 아직 None 입니다
os.getenv("TEST_TIMEOUT", "30")없으면 기본값을 돌려준다.env 에 OPENAI_MODEL 이 없어도 gpt-4.1-mini 로 도는 것과 같은 장치입니다

결과에서 읽을 것은 두 가지입니다.

  • 설명 줄은 빠지고 두 줄만 남았습니다. 사전에는 TEST_API_KEY 와 TEST_MODEL 만 있습니다. # 줄에 무엇을 적어도 값으로 읽히지 않습니다.
  • 사전과 환경 변수는 따로입니다. TEST_MODEL 이 사전에는 있지만 환경 변수로는 None 입니다. 모델을 부르는 코드가 키를 찾게 하려면 load_dotenv() 가 있어야 합니다.

주의할 점

  • .env 를 고친 뒤에는 프로그램을 다시 실행합니다. 이미 돌고 있는 프로그램(주피터 노트북 등)은 load_dotenv() 를 다시 불러도 이미 있는 값을 덮지 않습니다. 덮으려면 load_dotenv(override=True) 를 씁니다. override 는 "위에 덮어쓰다"라는 뜻입니다.
  • .env 파일을 열어 둔 채 화면을 공유하지 않습니다. 편집기 탭에 그대로 보입니다.
  • 과목 폴더의 .gitignore 에 .env 가 적혀 있는지 한 번 열어 확인합니다.
← 이전 절2장 · 키를 코드에 적지 않는 까닭다음 절 →2장 · OpenAI 라이브러리로 첫 호출