Agent 개발을 위한 Poetry로 Python 가상환경 관리하기

프로젝트 초기화부터 패키지 설치까지 Poetry 사용 방법

Poetry를 활용한 Python 프로젝트의 가상환경 생성 및 디펜던시 관리 방법을 다룬다. poetry new vs poetry init 비교, virtualenvs.in-project 설정, Python 패키지 구조 요구사항, pyproject.toml 설정, 가상환경 활성화/비활성화 방법, 그리고 Poetry 2.0+ 변경사항까지 실전 예제와 함께 단계별로 설명한다.

Engineering
DevOps
Python
Agent
Cloud
Azure
Poetry
저자

Kwangmin Kim

공개

2025년 11월 26일

1 Poetry를 활용한 Dependency 관리

Poetry는 Python 프로젝트의 의존성 관리패키징을 위한 현대적인 도구다.

1.1 Poetry의 장점

  • 의존성 관리: pyproject.toml 파일로 모든 패키지 버전 관리
  • 가상환경 자동 생성: 프로젝트별로 독립된 Python 환경 자동 구축
  • Lock 파일: poetry.lock으로 정확한 버전 재현 가능
  • 패키징: 배포용 패키지 빌드 자동화
  • 개발/운영 분리: 개발용/프로덕션용 디펜던시 구분 관리

1.2 pip vs Poetry

항목 pip + requirements.txt Poetry
설정 파일 requirements.txt (수동 관리) pyproject.toml (자동 생성)
버전 고정 수동으로 작성 poetry.lock 자동 생성
가상환경 별도 도구 필요 (venv, virtualenv) 내장 기능
의존성 해결 충돌 시 수동 해결 자동 해결
개발/운영 분리 별도 파일 필요 하나의 파일로 관리

2 프로젝트 생성 및 설정

2.1 새 프로젝트 생성

# 수동 생성  
mkdir -p ~/projects/insilico  
cd ~/projects/insilico  
pyenv local 3.11.10  
#생성된 디렉토리 구조  
insilico/  
├── pyproject.toml  
└── main.py          # ← 소스 코드는 루트에 (또는 직접 src/ 생성)  
  • 폴더 생성: 수동
  • 프로젝트 구조: insilico/ (빈 폴더)
  • pyproject.toml: 대화형으로 생성
  • 소스 폴더: 없음 (직접 생성 필요)
  • tests 폴더: 없음 (직접 생성 필요)
  • README.md: 없음 (직접 생성 필요)
  • Python 버전: pyenv local 3.11.10으로 명시
# 자동생성  
poetry new insilico  
cd insilico  
#생성된 디렉토리 구조  
insilico/  
├── pyproject.toml  
├── README.md  
├── insilico/        # ← 소스 코드는 여기  
│   └── __init__.py  
└── tests/  
  • 폴더 생성: 자동 (중첩 구조)
  • 프로젝트 구조: insilico/insilico/ (패키지 폴더 포함)
  • pyproject.toml: 자동 생성 (기본값)
  • 소스 폴더: insilico/ 자동 생성
  • tests 폴더: 자동 생성
  • README.md: 자동 생성
  • Python 버전: 시스템 기본값

본인은 수동으로 다음과 같이 생성

  • 본인은 poetry 어떻게 동작하는지 알고싶어서 수동으로 생성했지만 자동 생성도 괜찮음
# 1. 폴더 생성 및 Python 버전 고정  
mkdir -p ~/projects/insilico  
cd ~/projects/insilico  
pyenv local 3.11.10  

# 2. Poetry 초기화  
poetry init # pyproject.toml 파일을 생성  
  • 아래는 poetry init 실행으로 인해 pyproject.toml 파일을 생성하기 위해 나타나는 대화형 질문들이다.
Package name [insilico]: insilico  
Version [0.1.0]: 0.1.0  
Description []: AI Agent Development Using LangChain & LangGraph  
Author [kmkim, n to skip]:   
License []: MIT  
Compatible Python versions [^3.11]: ^3.11   
Would you like to define your main dependencies interactively? (yes/no) [yes] no  
Would you like to define your development dependencies interactively? (yes/no) [yes] no  

Do you confirm generation? (yes/no) [yes] yes  
# 3. 수동으로 구조 생성  
mkdir -p insilico tests  
touch insilico/__init__.py tests/__init__.py  
touch README.md  
insilico/                      # 프로젝트 루트 폴더  
├── pyproject.toml            # 자동 생성 (기본 설정 포함)  
├── README.md                 # 수동 생성   
├── src/                 # 수동 생성  
└── tests/                    # 수동 생성  
  • 수동으로 하든 자동으로 하든 후에 pyproject.toml만 잘 작성해주면 아무 문제 없음

2.2 Poetry 가상 환경 생성

  • 기존 pyproject.toml이 있을때 가상환경 생성
# 기존 pyproject.toml이 있을때, 가상환경 생성 (자동으로 .venv 폴더에 생성)  
poetry install   
  • install: The install command reads the pyproject.toml file from the current project, resolves the dependencies, and installs them.
  • 이때 가상환경 생성됨
  • .venv/ 폴더 생성
  • poetry.lock 생성
  • pyproject.toml에 정의된 패키지 설치
poetry env list  
insilico-sFIBWfwq-py3.11 (Activated)  
  • 본인은 conda를 사용자라서 activation의 의미가 혼동이 왔었는데 conda의 가상환경 활성화 상태와 poetry의 활성화 상태의 정의가 다름을 깨달았다.
    • Conda 환경: conda activate env_name 로 실행하면 쉘 명령어(activate)를 사용하여 쉘 프롬프트를 변경하는 의미
    • Poetry 환경: poetry env list로 실행하면 현재 poetry env list 명령어를 실행 중인 곳이 해당 환경인지를 나타낸다. 즉, 위의 (Activated)의 의미는 poetry env list 명령어를 실행하고 있는 현재 프로세스가 해당 insilico-sFIBWfwq-py3.11 가상 환경 내부에 있음을 의미하는 것이다.

2.3 가상환경 활성화 및 비활성화

  • Poetry 환경에서 실제 가상환경을 활성화 시키려면?
    • poetry에서 가상환경의 활성화는 poetry shell로 가능했는데 Poetry 2.0+부터는 이 명령어가 코어 기능에서 제거(Removed)되었다 (deprecated)

2.3.1 표준 활성화 방법

  • eval $(poetry env activate): 공식 웹사이트에서 제 1 에시로 나옴
azureuser@test-agent:~/projects/insilico$ eval $(poetry env activate) # 가상환경 활성화   
(insilico-py3.11) azureuser@test-agent:~/projects/insilico$ deactivate # 가상환경이 활성화되었음. 가상환경 비활성화 명령어 입력  
azureuser@test-agent:~/projects/insilico$ # 가상환경 비활성화됨  

2.3.2 개별 명령어 실행

  • poetry run 명령어는 가상환경을 수동으로 활성화하지 않아도 프로젝트의 가상환경을 찾고, 해당 가상환경 안에서 명령어를 실행해주는 역할을 한다.
  • poetry run은 뒤에 실행하고자 하는 명령(Command)을 인수로 받는다.
    • Poetry는 insilico/.venv/bin/python을 사용하도록 설정한 후, 이 Python으로 test_setup.py 스크립트를 실행
azureuser@test-agent:~/projects/insilico$ cat test_setup.py  
from langchain import __version__ as lc_version  
from langgraph import version  

print(f"LangChain: {lc_version}")  
print("LangGraph: imported successfully")  
# 가상환경 활성화 없이 Poetry로 명령어 실행  
poetry run python test_setup.py  
azureuser@test-agent:~/projects/insilico$ poetry run python test_setup.py  
LangChain: 1.1.0  
LangGraph: imported successfully  

2.3.3 수동 활성화

  • 가장 직접적인 방법으로 path 를 읽어와서 활성화시킨다. poetry 가 비정상적으로 설치됐을 경우 가장 효과적으로 활성화 시킬 수 있다.
source $(poetry env info --path)/bin/activate  

2.4 Poetry의 가상환경 위치 설정

  • pyenv vs venv
    • pyenv: Python 버전 관리
      • pyenv local 3.11.10
      • 역할: Python 인터프리터 버전 관리
      • 설치 위치: ~/.pyenv/versions/3.11.10/
      • 관리 대상: Python 실행 파일 자체
      • 목적: 프로젝트마다 다른 Python 버전 사용
    • Poetry .venv: 패키지 격리
      • poetry config virtualenvs.in-project true: 프로젝트 폴더 내에 .venv 생성하도록 설정
      • poetry install
      • 설치 위치: 프로젝트 폴더 내 .venv/
      • 관리 대상: 패키지(langchain, fastapi 등)
      • 목적: 프로젝트마다 독립된 패키지 환경
# 프로젝트 폴더 내에 .venv 생성 (권장)  
azureuser@test-agent:~/projects/insilico$ poetry config virtualenvs.in-project true  
azureuser@test-agent:~/projects/insilico$ ls -la  
total 316  
drwxrwxr-x 4 azureuser azureuser   4096 Dec  3 04:18 .  
drwxrwxr-x 3 azureuser azureuser   4096 Dec  1 07:45 ..  
-rw-rw-r-- 1 azureuser azureuser      8 Dec  1 07:45 .python-version  
-rw-rw-r-- 1 azureuser azureuser 293841 Dec  1 07:55 poetry.lock  
-rw-rw-r-- 1 azureuser azureuser    711 Dec  1 07:55 pyproject.toml  
drwxrwxr-x 4 azureuser azureuser   4096 Dec  1 08:02 src  
-rw-rw-r-- 1 azureuser azureuser    155 Dec  1 08:02 test_setup.py  
drwxrwxr-x 2 azureuser azureuser   4096 Dec  1 08:02 tests  
  • poetry config virtualenvs.in-project true 명령어를 실행했지만 .venv 폴더가 아직 생성되지 않았다.
    • 시행착오 결과, 내가 poetry에서 가상환경 재설치를 위해 필요한 폴더 구조를 만들지 않아서 .venv 생성이 되지 않았던 것
    • 필요한 폴더 구조: Python 패키지 규칙과 Poetry의 프로젝트 구조 요구사항을 의미
    • Python 패키지 = 폴더 + __init__.py
    # __init__.py 있음 → Python 패키지  
    insilico/                       # 프로젝트 루트  
    ├── README.md                   # 프로젝트 설명  
    ├── pyproject.toml  
    ├── poetry.lock  
    ├── .venv/  
    └── src/  
        └── insilico/                   # 패키지 루트 (프로젝트명과 동일)  
            ├── __init__.py            # 패키지 표시 (필수)  
            ├── agents/  
               ├── __init__.py        # 서브패키지 표시 (필수)  
               └── chat_agent.py  
            └── utils/  
                ├── __init__.py        # 서브패키지 표시 (필수)  
                └── helpers.py  
    # import 성공  
    python -c "import insilico.agents"  
    python -c "from insilico import Agent"  
    # 정상 작동  
  • poetry new insilico 로 자동설치하면 이런 시행착오를 안겪고 가상환경으로 자동으로 만들 수 있음
  • 수동 설치시 아래의 구조를 수동으로 만들어야함
#가능한 디렉토리 구조: Flat 레이아웃 사용 (덜 권장)  
insilico/  
├── pyproject.toml  
├── README.md # 포에트리 구조 요구 사항: PyPI 등록 시 표시될 설명. 이 파일이 없어도 가상환경이 설치되지만 경고 메세지가 출력된다.  
├── insilico/        # 소스 코드 폴더명은 프로젝트 폴더명과 일치시켜야함  
│   └── __init__.py # 패키지 인식 스크립트 필요  
└── tests/  
  • 소스 코드 폴더명과 프로젝트 폴더명의 일치
    • 별도 설정 없이 패키지 자동 인식시키면 pip install insilicoimport insilico로 자동 사용 가능
  • 만약 소스 코드 폴더명 과 폴더명이 불일치하면 pyproject.toml을 수정해야함
    • 그래도 여전히, 패키지 이름과 일치하는 폴더는 필수적으로 만들어야한다.
#가능한 디렉토리 구조: src 레이아웃 사용 (표준 권장)  
insilico/ # 프로젝트 명 or 패키지 명  
├── pyproject.toml  
├── src/ # 소스 코드 폴더명: 프로젝트 명 or 패키지 명과 달라도 됨  
│       └── insilico/  # **패키지 이름과 일치하는 폴더 (필수)**  
│           ├── __init__.py  
│           └── (모듈 파일들...)  
└── tests/  
  • pyproject.toml 변경: Poetry가 src/ 디렉토리 내에서 패키지 소스 코드를 찾도록 지정
<중략>  
[tool.poetry]  
name = "insilico"  
packages = [{ include = "insilico", from = "src" } # src/insilico/를 패키지로 지정]  
# ...  
<중략>  
  • 개발만 하고 배포 안 할 경우: 패키지 모드 비활성화 (비권장)
    • poetry install --no-root: # 폴더명, init.py 상관없이 설치 가능
[tool.poetry]  
package-mode = false  # ← 패키지 구조 무시  
name = "insilico"  
  • 아예 깔끔하게 기존 가상환경 삭제 하고 재생성 시도
# Poetry가 캐시 폴더에 이미 만든 가상환경 확인  
poetry env list  
# 출력: insilico-sFIBWfwq-py3.11 (Activated)  

# 기존 환경 삭제  
poetry env remove python  
# 또는 전체 삭제  
poetry env remove --all  
  • 가상환경 재설치
# insilico 폴더에 __init__.py 생성  
cd ~/projects/insilico  
touch __init__.py  
touch README.md  
  • pyproject.toml 수정
[tool.poetry]  
name = "insilico"  
version = "0.1.0"  
description = "AI Agent Development Using LangChain & LangGraph"  
authors = ["kmkim <kmkim@seegene.com>"]  
license = "MIT"  
readme = "README.md"  
packages = [{include = "insilico", from = "src"}]  # 가상환경 만들기전에 명시적으로 이 줄 추가  

[tool.poetry.dependencies]  
python = "^3.11"  
langchain = "^1.1.0"  
langchain-community = "^0.4.1"  
langgraph = "^1.0.4"  
python-dotenv = "^1.2.1"  
pydantic = "^2.12.5"  
fastapi = "^0.123.0"  
uvicorn = "^0.38.0"  
numpy = "^2.3.5"  
pandas = "^2.3.3"  
polars = "^1.35.2"  

[build-system]  
requires = ["poetry-core>=2.0.0,<3.0.0"]  
build-backend = "poetry.core.masonry.api"  
# 가상환경 재생성  
azureuser@test-agent:~/projects/insilico$ poetry install  
azureuser@test-agent:~/projects/insilico$ cd ~/projects/insilico  

# insilico 폴더에 __init__.py 생성  
touch insilico/__init__.py  

# agents 폴더에 __init__.py 생성  
touch insilico/agents/__init__.py  

# utils 폴더에 __init__.py 생성  
touch insilico/utils/__init__.py  
azureuser@test-agent:~/projects/insilico$ cd insilico/  
azureuser@test-agent:~/projects/insilico/insilico$ ls  
__init__.py  agents  utils  
azureuser@test-agent:~/projects/insilico/insilico$ cd agents  
azureuser@test-agent:~/projects/insilico/insilico/agents$ ls  
__init__.py  
azureuser@test-agent:~/projects/insilico/insilico/agents$ cd ../../  
azureuser@test-agent:~/projects/insilico$ ls  
README.md  insilico  poetry.lock  pyproject.toml  test_setup.py  tests  
azureuser@test-agent:~/projects/insilico$ nano pyproject.toml  
azureuser@test-agent:~/projects/insilico$ poetry install  
Creating virtualenv insilico in /home/azureuser/projects/insilico/.venv  
Installing dependencies from lock file  

Package operations: 64 installs, 0 updates, 0 removals  

  - Installing certifi (2025.11.12)  
  - Installing charset-normalizer (3.4.4)  
  - Installing h11 (0.16.0)  
  - Installing idna (3.11)  
  - Installing typing-extensions (4.15.0)  
  - Installing urllib3 (2.5.0)  
  - Installing annotated-types (0.7.0)  
  - Installing anyio (4.12.0)  
  - Installing httpcore (1.0.9)  
  - Installing pydantic-core (2.41.5)  
  - Installing requests (2.32.5)  
  - Installing typing-inspection (0.4.2)  
  - Installing httpx (0.28.1)  
  - Installing jsonpointer (3.0.0)  
  - Installing orjson (3.11.4)  
  - Installing packaging (25.0)  
  - Installing pydantic (2.12.5)  
  - Installing requests-toolbelt (1.0.0)  
  - Installing zstandard (0.25.0)  
  - Installing jsonpatch (1.33)  
  - Installing langsmith (0.4.49)  
  - Installing pyyaml (6.0.3)  
  - Installing tenacity (9.1.2)  
  - Installing langchain-core (1.1.0)  
  - Installing ormsgpack (1.12.0)  
  - Installing frozenlist (1.8.0)  
  - Installing greenlet (3.2.4)  
  - Installing langgraph-checkpoint (3.0.1)  
  - Installing multidict (6.7.0)  
  - Installing mypy-extensions (1.1.0)  
  - Installing propcache (0.4.1)  
  - Installing aiohappyeyeballs (2.6.1)  
  - Installing aiosignal (1.4.0)  
  - Installing attrs (25.4.0)  
  - Installing langchain-text-splitters (1.0.0)  
  - Installing langgraph-prebuilt (1.0.5)  
  - Installing langgraph-sdk (0.2.10)  
  - Installing marshmallow (3.26.1)  
  - Installing python-dotenv (1.2.1)  
  - Installing six (1.17.0)  
  - Installing sqlalchemy (2.0.44)  
  - Installing typing-inspect (0.9.0)  
  - Installing xxhash (3.6.0)  
  - Installing yarl (1.22.0)  
  - Installing aiohttp (3.13.2)  
  - Installing annotated-doc (0.0.4)  
  - Installing click (8.3.1)  
  - Installing dataclasses-json (0.6.7)  
  - Installing httpx-sse (0.4.3)  
  - Installing langchain-classic (1.0.0)  
  - Installing langgraph (1.0.4)  
  - Installing numpy (2.3.5)  
  - Installing polars-runtime-32 (1.35.2)  
  - Installing pydantic-settings (2.12.0)  
  - Installing python-dateutil (2.9.0.post0)  
  - Installing pytz (2025.2)  
  - Installing starlette (0.50.0)  
  - Installing tzdata (2025.2)  
  - Installing fastapi (0.123.0)  
  - Installing langchain (1.1.0)  
  - Installing langchain-community (0.4.1)  
  - Installing pandas (2.3.3)  
  - Installing polars (1.35.2)  
  - Installing uvicorn (0.38.0)  

Installing the current project: insilico (0.1.0)  
# 설정 확인  
azureuser@test-agent:~/projects/insilico$ poetry config --list  
cache-dir = "/home/azureuser/.cache/pypoetry"  
data-dir = "/home/azureuser/.local/share/pypoetry"  
installer.max-workers = null  
installer.no-binary = null  
installer.only-binary = null  
installer.parallel = true  
installer.re-resolve = true  
keyring.enabled = true  
python.installation-dir = "{data-dir}/python"  # /home/azureuser/.local/share/pypoetry/python  
requests.max-retries = 0  
solver.lazy-wheel = true  
system-git-client = false  
virtualenvs.create = true # Poetry가 poetry install 또는 poetry shell 실행 시 가상환경을 생성하도록 설정되어 있다.  
virtualenvs.in-project = true # 가상환경을 프로젝트 루트 디렉토리 내부에 생성하도록 설정되어 있다.   
virtualenvs.options.always-copy = false  
virtualenvs.options.no-pip = false  
virtualenvs.options.system-site-packages = false  
virtualenvs.path = "{cache-dir}/virtualenvs"  # /home/azureuser/.cache/pypoetry/virtualenvs  
virtualenvs.prompt = "{project_name}-py{python_version}"  
virtualenvs.use-poetry-python = false  

2.5 현재 가상환경 정보

# Poetry가 사용 중인 가상환경 경로  
azureuser@test-agent:~/projects/insilico$ poetry env info  

# Virtualenv  
# Python:         3.11.10  
# Implementation: CPython  
# Path:           /home/azureuser/projects/insilico/.venv  
# Executable:     /home/azureuser/projects/insilico/.venv/bin/python  
# Valid:          True  
#   
# Base  
# Platform:   linux  
# OS:         posix  
# Python:     3.11.10  
# Path:       /home/azureuser/.pyenv/versions/3.11.10  
# Executable: /home/azureuser/.pyenv/versions/3.11.10/bin/python3.11  

Subscribe

Enjoy this blog? Get notified of new posts by email: