콘텐츠로 이동

1장 · 환경 준비

목표

빈 폴더에서 시작해서, 의존성이 설치된 실행 가능한 Python 프로젝트를 만듭니다. 이 장이 끝나면 uv run python으로 FastAPI를 import할 수 있는 상태가 됩니다.

준비물

도구 확인 명령 비고
Python 3.10+ python3 --version 3.10·3.11·3.12 전 테스트 통과 검증. 3.9 이하 불가(X \| Y 타입 문법)
uv uv --version 없으면: curl -LsSf https://astral.sh/uv/install.sh \| sh
git git --version

uv가 뭔가요? Python의 패키지·가상환경 관리자입니다. Java 세계의 Maven/Gradle에 해당하며, uv sync 한 번으로 격리된 환경(.venv/) 생성과 의존성 설치를 끝냅니다. 자세한 대응표는 05 §1을 참고하세요.

따라하기

1. 프로젝트 폴더 생성

저장소 루트에서:

mkdir agent && cd agent

2. pyproject.toml 작성

Maven의 pom.xml에 해당하는 프로젝트 정의 파일입니다.

[project]
name = "prepay-agent"
version = "0.1.0"
description = "카드 선결제 에이전트 — 챗봇 WAS와 LLM 사이의 에이전틱 처리 계층"
requires-python = ">=3.10"
dependencies = [
    "fastapi>=0.115",
    "uvicorn[standard]>=0.30",
    "pydantic>=2.7",
    "pydantic-settings>=2.3",
]

[dependency-groups]
dev = [
    "pytest>=8",
    "httpx>=0.27",
]

[tool.uv]
package = false

[tool.pytest.ini_options]
pythonpath = ["."]
testpaths = ["tests"]

3. 의존성 설치

uv sync

.venv/(격리된 실행 환경)와 uv.lock(잠금 파일)이 생깁니다. uv.lock은 커밋하고 .venv/는 커밋하지 않습니다 — Gradle의 lockfile은 커밋하고 빌드 산출물은 안 하는 것과 같습니다.

4. .env.example 작성

# 복사해서 .env 로 사용: cp .env.example .env
# .env 는 .gitignore 대상 — API key 를 절대 커밋하지 말 것 (docs/05 §5)

# LLM 연결 — 개발: OpenRouter / 운영: 사내 서빙 (Q9 확정 후 교체)
LLM_BASE_URL=https://openrouter.ai/api/v1
LLM_API_KEY=sk-or-여기에-본인-키
LLM_MODEL=openai/gpt-oss-120b

# Redis — Step 4 부터 사용 (접속 정보는 Q6 확정 시 갱신)
REDIS_URL=redis://localhost:6379/0

각자 cp .env.example .env 후 본인 키를 채웁니다. .env는 절대 커밋하지 않습니다 — 저장소 루트 .gitignore에 이미 등록되어 있습니다.

코드 해설 — pyproject.toml 한 줄씩

부분 의미 Spring이라면
dependencies 4종 fastapi(웹 프레임워크) / uvicorn(서버) / pydantic(DTO+검증) / pydantic-settings(설정) spring-web / 내장 Tomcat / Bean Validation / @ConfigurationProperties
[dependency-groups] dev 테스트에만 필요한 의존성 Maven의 <scope>test</scope>
[tool.uv] package = false 이 프로젝트는 배포용 라이브러리가 아닌 애플리케이션이라는 선언 — 패키지 빌드 없이 의존성만 관리 jar를 Maven Central에 올릴 게 아니라는 뜻
[tool.pytest.ini_options] pythonpath = ["."] 테스트 실행 시 프로젝트 루트를 import 경로에 추가 — from app... import가 가능해짐 클래스패스 설정

LangGraph·openai 의존성이 아직 없는 게 눈에 띌 텐데, 의도적입니다. Step에 필요해지는 시점에 추가합니다(4장에서 langgraph, 5장에서 openai). 처음부터 다 넣지 않는 이유는, 각 의존성이 왜 필요한지를 추가하는 순간에 이해하기 위해서입니다.

동작 확인

uv run python -c "import fastapi; print(fastapi.__version__)"
# 0.121.x 같은 버전이 출력되면 성공

이 장의 완성 코드 전문

아래 접이식 블록은 저장소 최종본과 자동 동기화됩니다 — 코드가 바뀌면 agent/ 에서 uv run python scripts/refresh_guide_code.py 가 문서를 다시 쓰고, 불일치는 tests/test_guide_sync.py 가 테스트 실패로 잡습니다(3장의 "문서의 예시 = fixture" 전략의 확장). 최종본에는 이후 장의 내용이 이미 반영되어 있습니다 — 예를 들어 pyproject 에는 4·5·6장에서 추가하는 langgraph·openai·checkpoint-redis 가 이미 들어 있습니다. 본문의 단계별 서사와 다른 부분은 각 장이 설명합니다.

전문 · agent/pyproject.toml
[project]
name = "prepay-agent"
version = "0.1.0"
description = "카드 선결제 에이전트 — 챗봇 WAS와 LLM 사이의 에이전틱 처리 계층"
requires-python = ">=3.10"  # 하한은 3.10 (X | Y 타입 문법). 3.10·3.11·3.12 전 테스트 통과 검증됨
dependencies = [
    "fastapi>=0.115",
    "uvicorn[standard]>=0.30",
    "pydantic>=2.7",
    "pydantic-settings>=2.3",
    "langgraph>=1.2.7",
    "openai>=2.44.0",
    "langgraph-checkpoint-redis>=0.5.0",
]

[dependency-groups]
dev = [
    "pytest>=8",
    "httpx>=0.27",
]

[tool.uv]
package = false

[tool.pytest.ini_options]
pythonpath = ["."]
testpaths = ["tests"]
전문 · agent/.env.example
# 복사해서 .env 로 사용: cp .env.example .env
# .env 는 .gitignore 대상 — API key 를 절대 커밋하지 말 것 (docs/05 §5)

# 서버 기동 (표준 기동법: uv run python -m app) — 포트는 CLI 가 아니라 여기서 관리
APP_HOST=127.0.0.1
APP_PORT=8800
APP_RELOAD=true

# LLM 구현 선택 — mock(가짜 규칙, 오프라인) | openai(실제 모델, Step 3 부터)
LLM_PROVIDER=openai

# LLM 요청/응답 JSONL 저장 위치 (빈 값이면 저장 안 함) — 프롬프트 튜닝·장애 분석용
LLM_LOG_DIR=logs/llm

# structured output(response_format) 사용 여부 — OpenRouter 는 하위 제공자들의
# constrained decoding 버그(응답 오염)가 관측되어 false 권장. 사내 서빙에선 true 로 재검증 (Q1)
LLM_STRUCTURED_OUTPUT=false

# LLM 연결 — 개발: OpenRouter / 운영: 사내 서빙 (Q9 확정 후 교체)
LLM_BASE_URL=https://openrouter.ai/api/v1
LLM_API_KEY=sk-or-여기에-본인-키
LLM_MODEL=openai/gpt-oss-120b

# Redis — 대화 상태(체크포인트) 저장소. 접속 정보·TTL 정책은 Q6 확정 시 갱신
# 로컬 개발: docker run -d --name prepay-redis -p 127.0.0.1:6379:6379 redis:8
REDIS_URL=redis://localhost:6379/0
REDIS_TTL_MINUTES=60

이 장에서 배운 것

  • uv = Maven/Gradle. uv sync = 의존성 설치, uv run <명령> = 프로젝트 환경 안에서 실행
  • pyproject.toml = pom.xml. 앱 프로젝트는 package = false
  • 비밀값은 .env(커밋 금지), 템플릿은 .env.example(커밋)