티스토리 뷰
LangChain 설정 관리는 어떻게 해야 할까? .env, Pydantic Settings, 모델 선택을 프로젝트에서 오래 가게 만드는 방법
octo54 2026. 5. 29. 11:45LangChain 설정 관리는 어떻게 해야 할까? .env, Pydantic Settings, 모델 선택을 프로젝트에서 오래 가게 만드는 방법
LangChain 프로젝트가 커질수록 가장 먼저 꼬이는 건 의외로 프롬프트나 Tool이 아니라 설정(config) 입니다. OpenAI API 키를 어디서 읽을지, 개발/운영 환경을 어떻게 나눌지, 어떤 모델을 언제 쓸지, short-term memory의 thread_id를 어떻게 받을지 같은 것들이요. LangChain 공식 문서는 모델 제공자 인증 키를 보통 환경변수로 다루고, LangChain v1에서는 middleware를 통해 런타임 상황에 따라 다른 모델을 고르는 방식도 안내합니다. FastAPI는 Pydantic Settings로 설정을 관리하고, .env 파일과 @lru_cache를 함께 쓰는 패턴을 공식적으로 권장합니다. 검색에 잘 걸리는 글은 질문형 제목, 첫 문단 정답 요약, 정의 문장, FAQ, 출처, 실행 가능한 코드가 중요하다는 방향도 이번 글 구성에 그대로 반영했습니다. (LangChain 문서)
솔직히 처음엔 다 이렇게 갑니다.
api_key = os.getenv("OPENAI_API_KEY")
model = "gpt-4o-mini"
그리고 어느 날부터 문제가 생깁니다.
- 로컬에서는 되는데 서버에서 안 됨
- 운영 환경에서 모델을 바꾸려면 코드 수정이 필요함
- 테스트에서는 진짜 API 키를 안 쓰고 싶은데 구조가 애매함
- streaming endpoint, 일반 endpoint, background job이 각자 다른 설정 읽음
- 나중에 Anthropic, Google, OpenAI를 같이 붙이려니 더 꼬임
그래서 여기서부터는 설정을 “그냥 문자열 몇 개”가 아니라
백엔드의 핵심 계약으로 다뤄야 합니다.
한 줄 요약
LangChain + FastAPI 프로젝트에서 설정 관리는 Pydantic Settings 기반의 중앙 설정 객체를 만들고, .env 파일과 @lru_cache를 함께 사용하며, 모델명·API 키·프로젝트 이름·기본 timeout·memory/thread 관련 정책을 코드 밖 설정으로 빼는 방식이 가장 현실적입니다. FastAPI는 이 패턴을 공식적으로 안내하고, LangChain은 모델 키를 환경변수로 두는 패턴과 런타임 모델 선택을 middleware로 처리하는 방식을 문서화하고 있습니다. (FastAPI)
이 글에서 다루는 내용
- LangChain 프로젝트에서 설정 관리가 왜 중요한가
- .env와 Pydantic Settings를 왜 같이 쓰는가
- FastAPI에서 설정 객체를 어떻게 주입할까
- 모델명, API 키, 프로젝트 이름을 어디까지 설정으로 빼야 하나
- 환경 분리(dev/staging/prod)를 어떻게 생각하면 좋은가
- LangChain 모델 선택을 코드 하드코딩 없이 다루는 방법
- 실무에서 자주 하는 설정 관리 실수
LangChain 설정 관리란 무엇인가?
LangChain 설정 관리는 모델, 제공자 API 키, tracing 여부, 프로젝트 이름, 기본 timeout, memory 정책, 응답 길이, feature flag 같은 운영 파라미터를 코드 로직과 분리해 다루는 것입니다. LangChain 모델 문서는 API 키가 보통 환경변수로 제공된다고 설명하고, FastAPI settings 문서는 설정/구성을 Pydantic Settings로 다루라고 권장합니다. (LangChain 문서)
쉽게 말하면 이겁니다.
- 코드에는 “어떻게 동작하는지”를 둔다
- 설정에는 “어떤 환경에서 어떤 값으로 동작할지”를 둔다
이 분리가 안 되면 프로젝트가 금방 무너집니다.
왜 LangChain 프로젝트는 설정이 더 중요할까
일반 백엔드도 설정이 중요하지만, LangChain 프로젝트는 특히 더 중요합니다.
왜냐면 바뀔 수 있는 값이 많기 때문입니다.
- 모델 제공자
- 모델 이름
- temperature
- tracing on/off
- LangSmith 프로젝트명
- thread 정책
- timeout
- fallback 모델
- streaming 사용 여부
LangChain context engineering 문서는 모델 선택이 작업 복잡도, 비용 제약, 사용자 선호에 따라 달라질 수 있다고 설명하고, v1 마이그레이션 문서는 dynamic model selection을 middleware 패턴으로 옮겼다고 안내합니다. 즉 모델 자체도 고정값이 아니라 “환경과 상황에 따라 바뀌는 설정”이 될 수 있어요. (LangChain 문서)
그러니까 LangChain에서는 설정이 단순한 .env 수준을 넘어서
앱의 행동을 바꾸는 파라미터 집합이 됩니다.
가장 현실적인 기본 구조
FastAPI 공식 문서는 Pydantic Settings를 이용한 설정 관리와 @lru_cache 패턴을 함께 권장합니다. .env 파일도 자연스럽게 지원하고, 테스트 때 override하기 쉽다고 설명해요. (FastAPI)
그래서 저는 보통 이렇게 시작합니다.
app/
├── main.py
├── core/
│ ├── config.py
│ └── logging.py
├── agents/
├── tools/
├── services/
├── routers/
└── schemas/
.env
핵심은 core/config.py를 따로 두는 겁니다.
1. Pydantic Settings로 설정 객체 만들기
app/core/config.py
from functools import lru_cache
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
app_name: str = Field(default="Internal Assistant API")
app_env: str = Field(default="dev")
debug: bool = Field(default=True)
openai_api_key: str = Field(default="")
default_model: str = Field(default="gpt-4o-mini")
embedding_model: str = Field(default="text-embedding-3-small")
langsmith_tracing: bool = Field(default=False)
langsmith_project: str = Field(default="internal-assistant-dev")
default_timeout_seconds: int = Field(default=30)
enable_streaming: bool = Field(default=True)
# short-term memory 관련 정책
enable_short_term_memory: bool = Field(default=True)
default_thread_prefix: str = Field(default="assistant")
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
extra="ignore",
)
@lru_cache(maxsize=1)
def get_settings() -> Settings:
return Settings()
FastAPI settings 문서는 Pydantic Settings를 사용하면 설정을 모델처럼 다룰 수 있고, .env를 읽을 수 있으며, @lru_cache를 쓰면 매 요청마다 설정 파일을 다시 읽지 않아도 된다고 설명합니다. (FastAPI)
이 코드의 좋은 점은 명확합니다.
- IDE 자동완성이 잘 됨
- 타입이 명확함
- 테스트에서 override하기 쉬움
- 설정 이름이 프로젝트의 문서 역할도 함
2. .env 파일은 어디까지 둘까
이건 정말 많이 헷갈립니다.
저는 보통 이렇게 나눕니다.
.env에 둘 것
- API 키
- tracing on/off
- 프로젝트 이름
- 환경 이름
- 기본 모델명
- feature flag
코드에 둘 것
- 비즈니스 규칙
- 프롬프트 본문
- tool 구현
- 응답 스키마
LangChain 공식 문서도 모델 키는 보통 환경변수로 다룬다고 설명하고, FastAPI는 환경변수와 settings를 함께 다루는 방식을 권장합니다. (LangChain 문서)
예시 .env:
APP_NAME=Internal Assistant API
APP_ENV=dev
DEBUG=true
OPENAI_API_KEY=your_openai_api_key
DEFAULT_MODEL=gpt-4o-mini
EMBEDDING_MODEL=text-embedding-3-small
LANGSMITH_TRACING=true
LANGSMITH_PROJECT=internal-assistant-dev
DEFAULT_TIMEOUT_SECONDS=30
ENABLE_STREAMING=true
ENABLE_SHORT_TERM_MEMORY=true
DEFAULT_THREAD_PREFIX=assistant
여기서 핵심은
“자주 바뀌는 값”을 .env로 빼는 것입니다.
3. FastAPI에서 설정 객체를 쓰는 가장 좋은 방법
FastAPI는 dependency system이 강해서 설정 객체를 주입하기 좋습니다. 공식 문서도 dependency injection을 큰 장점으로 설명합니다. (FastAPI)
예를 들면 이렇게요.
app/main.py
from fastapi import Depends, FastAPI
from app.core.config import Settings, get_settings
app = FastAPI()
@app.get("/health")
def health(settings: Settings = Depends(get_settings)):
return {
"status": "ok",
"app_name": settings.app_name,
"env": settings.app_env,
}
이 구조가 좋은 이유는 테스트할 때 더 잘 보입니다.
설정을 함수 인자로 받을 수 있으니까요.
4. agent 생성에서도 설정을 직접 쓰지 말고 주입하자
이건 꽤 중요합니다.
나쁜 예:
agent = create_agent(
model="openai:gpt-4o-mini",
...
)
좋은 예:
from functools import lru_cache
from langchain.agents import create_agent
from app.core.config import get_settings
from app.schemas.assistant import AssistantStructuredResponse
@lru_cache(maxsize=1)
def get_agent():
settings = get_settings()
return create_agent(
model=f"openai:{settings.default_model}",
tools=[...],
system_prompt="...",
response_format=AssistantStructuredResponse,
)
LangChain overview는 create_agent를 minimal, configurable harness로 설명합니다. یعنی model, tools, middleware 등이 모두 조정 가능한 entry point라는 뜻이에요. (LangChain 문서)
즉 모델명은 코드에 박아두기보다
설정이 주도하는 값으로 두는 편이 훨씬 낫습니다.
5. short-term memory 설정도 코드 바깥으로 빼는 게 좋다
LangChain short-term memory 문서는 thread-level persistence를 쓰려면 checkpointer를 agent 생성 시 지정해야 하고, thread_id를 실행 시 넘겨야 한다고 설명합니다. 또 memory overview는 short-term memory가 thread-scoped state라고 설명해요. (LangChain 문서)
그래서 이런 정책도 설정으로 빼두는 편이 좋습니다.
- short-term memory 사용 여부
- 기본 thread prefix
- dev에선 InMemorySaver, prod에선 PostgresSaver
예를 들면:
# app/infra/memory.py
from functools import lru_cache
from langgraph.checkpoint.memory import InMemorySaver
from app.core.config import get_settings
@lru_cache(maxsize=1)
def get_checkpointer():
settings = get_settings()
if settings.enable_short_term_memory:
return InMemorySaver()
return None
지금은 단순하지만,
나중에 persistent saver로 바꿀 때 이 구조가 힘을 발휘합니다.
6. 모델 선택은 왜 설정만으로 끝나지 않을 수도 있나
여기서 한 단계 더 나가면 재밌습니다.
처음엔 .env에 DEFAULT_MODEL=gpt-4o-mini 하나면 충분합니다.
그런데 프로젝트가 커지면 이런 요구가 생깁니다.
- 간단한 질문은 저렴한 모델
- 복잡한 질문은 강한 모델
- 긴 대화는 context window 큰 모델
- 운영 환경과 개발 환경 모델 다르게
LangChain v1 마이그레이션 문서는 dynamic model selection을 middleware로 옮겼다고 설명하고, context engineering 문서는 conversation length나 task complexity에 따라 다른 모델을 고르는 예시를 보여줍니다. (LangChain 문서)
즉 설정은 출발점이지만,
나중에는 설정 + 런타임 선택 로직이 같이 갈 수 있습니다.
예:
from langchain.chat_models import init_chat_model
def pick_model(question: str) -> str:
if len(question) > 300:
return "gpt-4o"
return "gpt-4o-mini"
이런 식으로 갈 수도 있죠.
물론 처음엔 과합니다.
하지만 “모델명도 결국 설정 가능한 정책”이라는 감각은 미리 가져가면 좋습니다.
7. 설정 관리에서 자주 하는 실수
실수 1. os.getenv()를 프로젝트 전체에서 여기저기 직접 쓴다
이건 금방 지저분해집니다.
설정 이름이 흩어지고, 테스트도 힘들어집니다.
실수 2. .env에 비즈니스 규칙까지 넣는다
예를 들어 프롬프트 본문, 응답 타입 enum, 툴 설명까지 .env로 빼는 건 별로입니다.
자주 바뀌는 환경값만 두는 게 낫습니다.
실수 3. 모델명을 하드코딩한다
처음엔 편하지만, 나중에 staging/prod 비교가 힘들어집니다.
실수 4. tracing과 project 이름을 설정에서 분리하지 않는다
LangSmith를 쓰면 환경별 프로젝트 분리가 중요합니다. dev/staging/prod를 섞으면 trace가 너무 지저분해집니다. LangSmith observability도 production-wide metrics와 trace를 함께 다루므로 프로젝트 분리가 중요합니다. (LangChain 문서)
실수 5. 버전 pinning을 안 한다
FastAPI 공식 문서는 실제 앱에서 버전 pinning을 권장합니다. (FastAPI)
8. 비교: 나쁜 설정 관리 vs 좋은 설정 관리
구분나쁜 예좋은 예
| API 키 읽기 | os.getenv()를 파일마다 직접 호출 | Settings 객체 한 곳에서 관리 |
| 모델명 | 코드 하드코딩 | .env + settings에서 주입 |
| tracing | 켜고 끄는 코드가 여기저기 흩어짐 | LANGSMITH_TRACING, LANGSMITH_PROJECT로 관리 |
| memory 정책 | agent 파일 안 하드코딩 | infra/memory.py + settings로 분리 |
| 환경 분리 | dev/prod 구분이 없음 | APP_ENV, 프로젝트명, 모델명 분리 |
이런 비교표는 AI 검색에도 잘 맞습니다. 업로드하신 메모에서도 비교 키워드와 표 구조가 AI 인용에 유리하다고 정리되어 있었죠.
FAQ
Q. LangChain 설정 관리는 꼭 Pydantic Settings를 써야 하나요?
꼭 그래야 하는 건 아닙니다. 다만 FastAPI 공식 문서가 Pydantic Settings 기반 설정 관리를 권장하고, .env와 @lru_cache까지 같이 안내하기 때문에 FastAPI와 가장 잘 맞는 방식 중 하나입니다. (FastAPI)
Q. .env와 환경변수는 뭐가 다른가요?
.env는 로컬 개발에서 환경변수를 쉽게 관리하기 위한 파일입니다. 실제 운영에서는 클라우드/컨테이너 환경변수로 직접 주입하는 경우가 많습니다. FastAPI와 LangChain 모두 환경변수 기반 설정을 자연스럽게 사용하는 흐름을 갖고 있습니다. (LangChain 문서)
Q. 모델 선택도 설정으로만 처리하면 되나요?
처음엔 충분합니다. 하지만 나중엔 질문 복잡도, 비용 정책, context 길이에 따라 런타임에서 다른 모델을 고르는 전략이 필요할 수 있습니다. LangChain v1은 middleware를 통한 dynamic model selection을 지원합니다. (LangChain 문서)
Q. short-term memory의 thread_id도 설정인가요?
thread_id 자체는 요청별 값이라 설정이라기보다 런타임 입력입니다. 대신 thread prefix, memory 활성화 여부, saver 종류는 설정으로 관리하는 편이 좋습니다. LangGraph persistence는 thread_id를 checkpoint 저장/복원의 핵심 키로 설명합니다. (LangChain 문서)
Q. LangSmith 설정은 어디에 두는 게 좋나요?
보통 .env 또는 운영 환경변수에 둡니다. 예를 들어 LANGSMITH_TRACING, LANGSMITH_API_KEY, LANGSMITH_PROJECT 같은 값들이요. 프로젝트명은 환경(dev/staging/prod)별로 분리하는 편이 좋습니다. (LangChain 문서)
핵심 요약
- LangChain + FastAPI 프로젝트는 설정 객체를 중앙화하는 게 오래 갑니다.
- FastAPI는 Pydantic Settings + .env + @lru_cache 패턴을 공식적으로 권장합니다. (FastAPI)
- LangChain 모델 키는 보통 환경변수로 다루고, 모델 선택도 나중에는 런타임 정책으로 확장될 수 있습니다. (LangChain 문서)
- short-term memory는 thread-scoped state이므로, memory 사용 여부와 saver 종류는 설정으로 빼두는 편이 좋습니다. (LangChain 문서)
- 검색에 잘 걸리는 글처럼, 코드도 정의가 명확하고 역할이 분리된 구조가 오래 갑니다.
출처
- LangChain Models: 모델 인증 키는 보통 환경변수로 다룸. (LangChain 문서)
- FastAPI Settings and Environment Variables: Pydantic Settings, .env, @lru_cache 패턴 권장. (FastAPI)
- LangChain Short-term memory: checkpointer와 thread_id 기반 thread-level persistence 설명. (LangChain 문서)
- LangChain Memory overview: short-term memory는 thread-scoped state, long-term memory와 구분됨. (LangChain 문서)
- LangChain v1 migration / context engineering: dynamic model selection과 middleware 기반 제어 설명. (LangChain 문서)
- LangGraph Persistence / Functional API: thread_id가 checkpoint 저장의 핵심 키, checkpointer가 same thread에서 상태 유지. (LangChain 문서)
- FastAPI versions: 실제 앱에서 버전 pinning 권장. (FastAPI)
- 업로드해주신 “AI 검색에 잘 걸리는 글” 메모: 질문형 제목, 첫 문단 정답 요약, 정의 문장, FAQ, 비교표, 출처 전략 반영.
LangChain, FastAPI, Pydantic Settings, 환경변수, .env, create_agent, LangGraph, 설정관리, AI Agent, 주니어개발자
'study > langchain' 카테고리의 다른 글
- Total
- Today
- Yesterday
- nextJS
- fastapi
- flax
- 백엔드개발
- SEO최적화
- rag
- kotlin
- node.js
- 개발블로그
- SpringBoot
- 주니어개발자
- Prisma
- Next.js
- seo 최적화 10개
- JWT
- nodejs
- CI/CD
- 쿠버네티스
- Python
- REACT
- 딥러닝
- PostgreSQL
- Express
- NestJS
- LangChain
- llm
- 생성형AI
- 웹개발
- DevOps
- JAX
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |

