Setting Up a Clean AI Dev Environment
If you're coming from .NET, you're used to a well-structured ecosystem. You install Visual Studio, target a specific .NET version in your .csproj, and NuGet handles dependencies. Switching to Python can feel like the Wild West by comparison — multiple Python versions floating around your machine, pip install dumping packages globally, and projects stepping on each other's dependencies.
This gets especially painful in AI engineering. The OpenAI SDK, LangChain, and Anthropic's client library all pin specific versions of shared dependencies. Without proper isolation, upgrading one project silently breaks another. This lesson gives you the setup that production AI engineers actually use.
Why Python Version Management Matters
In .NET, you declare <TargetFramework>net8.0</TargetFramework> and the runtime handles the rest. Python works differently — the interpreter version is a system-level concern, and different AI projects routinely need different Python versions. The Anthropic SDK may require Python 3.9+, while a legacy ETL pipeline might be pinned to 3.8. You need a way to switch cleanly.
The tool for this is pyenv. It installs and manages multiple Python versions side-by-side, letting you pin a specific version per project.
Installing pyenv
macOS / Linux:
# Install pyenv via Homebrew (macOS) or the official installer
curl https://pyenv.run | bash
# Add to your shell profile (~/.zshrc or ~/.bashrc)
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
# Restart your shell, then install a specific Python version
pyenv install 3.11.9
pyenv global 3.11.9 # set system-wide default
# Verify
python --version # Python 3.11.9
Windows:
# Use pyenv-win — install via PowerShell
Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" -OutFile "./install-pyenv-win.ps1"
./install-pyenv-win.ps1
# Then in a new terminal:
pyenv install 3.11.9
pyenv global 3.11.9
Run pyenv local 3.11.9 inside a project folder to create a .python-version file. pyenv automatically activates the right version whenever you cd into that directory — just like a .nvmrc for Node.
Virtual Environments: Your Project Sandbox
If pyenv is your Python version manager, virtual environments (venv) are your package sandbox. Each project gets its own isolated set of installed packages, completely separate from every other project and the system Python.
Think of it like a dedicated NuGet packages folder per solution, except the isolation is enforced at runtime rather than just at build time.
Creating and Activating a venv
# Create a virtual environment called "venv" in your project root
python -m venv venv
# Activate it
# macOS/Linux:
source venv/bin/activate
# Windows (Command Prompt):
venv\Scripts\activate.bat
# Windows (PowerShell):
venv\Scripts\Activate.ps1
# Your prompt changes to show (venv) — you're now isolated
(venv) $ pip install anthropic openai # installs ONLY into this venv
# Deactivate when done
deactivate
If you run pip install without activating a venv, you're installing globally. Check which python (macOS/Linux) or where python (Windows) before installing anything — it should point inside your venv folder.
Managing Dependencies: pip-tools
This is where Python's analogy to .NET gets really clean once you know the right tools. The standard you'll see in production AI projects separates two concerns, exactly like NuGet does:
requirements.in— your direct dependencies, loosely pinned. This is your.csprojPackageReferences.requirements.txt— the fully resolved, fully pinned lockfile generated bypip-compile. This is yourpackages.lock.json.
The tool that bridges them is pip-tools.
pip freeze > requirements.txt?pip freeze dumps every package in your venv — including transitive dependencies you didn't ask for — into one flat list. There's no way to tell which entries are your direct deps vs. things they pulled in. When a package needs updating, you're editing a lockfile blindly. Don't use it.
The pip-tools Workflow
Install pip-tools into your venv first:
pip install pip-tools
Create requirements.in with only your direct dependencies, loosely pinned:
# requirements.in — what YOU depend on (like .csproj PackageReferences)
anthropic>=0.30
openai>=1.40
pydantic>=2.0
python-dotenv>=1.0
tenacity>=9.0 # retry logic
Compile it to a fully resolved lockfile:
# Resolves the full dependency tree and writes requirements.txt
pip-compile requirements.in
# Upgrade all packages to their latest compatible versions
pip-compile --upgrade requirements.in
The generated requirements.txt pins every package in the tree with exact versions — including transitive deps you never listed yourself. Now install exactly what's in the lockfile:
# Installs what's in requirements.txt AND removes anything that shouldn't be there
pip-sync requirements.txt
pip-sync is stricter than pip install -r: it also removes packages not in the lockfile. Your venv is always in a known, reproducible state.
<!-- .csproj — your direct deps -->
<PackageReference
Include="Anthropic.SDK"
Version="3.*" />
<!-- packages.lock.json — resolved tree -->
<!-- generated by dotnet restore --restore-locked-mode -->
# requirements.in — your direct deps
anthropic>=0.30
# requirements.txt — resolved lockfile
# generated by: pip-compile requirements.in
# installed by: pip-sync requirements.txt
Dev Dependencies
Keep a separate requirements-dev.in for tools that don't belong in production containers:
# requirements-dev.in
-r requirements.in # inherit prod deps
pytest>=8.0
black>=24.0
mypy>=1.0
pip-compile requirements-dev.in -o requirements-dev.txt
pip-sync requirements.txt requirements-dev.txt # sync both together
This mirrors .NET's PackageReference with PrivateAssets="all" — dev tools are tracked separately and never make it into production.
Pinning vs. Constraining Versions in requirements.in
| Syntax | Meaning | When to Use |
|---|---|---|
anthropic>=0.30 |
Minimum version, pip-compile pins exactly | Direct deps in requirements.in |
anthropic==0.34.0 |
Exact pin | In generated requirements.txt — never edit by hand |
anthropic |
Latest stable | Never — always constrain in AI apps |
AI SDKs release frequently. Even minor version bumps can silently change model behavior or response parsing. Let pip-compile pin the exact versions in the lockfile — and only upgrade intentionally with pip-compile --upgrade.
VS Code Integration
VS Code is the dominant IDE for Python AI work (PyCharm is the other strong option). Getting VS Code to use your venv correctly is essential — otherwise its IntelliSense won't see your installed packages.
Selecting the Interpreter
# After activating your venv and installing packages:
# In VS Code: Ctrl+Shift+P → "Python: Select Interpreter"
# Choose the one pointing to ./venv/bin/python (or .\venv\Scripts\python.exe on Windows)
Once selected, VS Code stores this in .vscode/settings.json:
{
"python.defaultInterpreterPath": "${workspaceFolder}/venv/bin/python"
}
Recommended VSCode Extensions for AI Development
- Python (Microsoft) — core language support, IntelliSense, debugging
- Pylance — fast type checking and autocompletion (powered by Pyright)
- Python Debugger (Debugpy) — breakpoints and variable inspection
- Even Better TOML — syntax support for
pyproject.toml - REST Client — test API endpoints without leaving VS Code
Workspace Settings for AI Projects
// .vscode/settings.json
{
"python.defaultInterpreterPath": "${workspaceFolder}/venv/bin/python",
"editor.formatOnSave": true,
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
},
"python.linting.enabled": true,
"python.linting.pylintEnabled": false,
"python.linting.flake8Enabled": false,
"python.analysis.typeCheckingMode": "basic"
}
Project Structure for AI Applications
A well-organized AI project makes it easy to swap models, add evaluation harnesses, and onboard new engineers. Here's the structure used in production AI engineering teams:
my-ai-app/
├── .python-version # pyenv version pin
├── .env # API keys (never commit!)
├── .env.example # template with placeholder values
├── .gitignore # includes venv/, .env, __pycache__/
├── requirements.in # your direct deps (loosely pinned)
├── requirements.txt # generated lockfile (pip-compile output)
├── requirements-dev.in # dev-only direct deps
├── requirements-dev.txt # generated dev lockfile
├── pyproject.toml # optional: tool config (black, mypy)
├── src/
│ ├── __init__.py
│ ├── client.py # AI client abstraction
│ ├── prompts.py # prompt templates
│ ├── models.py # Pydantic models for I/O
│ └── utils.py # shared utilities
├── tests/
│ ├── __init__.py
│ ├── test_client.py
│ └── test_prompts.py
└── scripts/
└── run_eval.py # evaluation harnesses
The .gitignore for AI Projects
# .gitignore
venv/
.env
*.pyc
__pycache__/
.pytest_cache/
.mypy_cache/
*.egg-info/
dist/
.DS_Store
# Never commit these
*.key
*_credentials.json
Environment Variables and API Keys
AI applications are key-heavy — OpenAI API key, Anthropic API key, vector DB credentials, etc. The pattern is identical to what you'd use in .NET with appsettings.json and User Secrets, but Python has its own conventions.
# .env file (never commit this)
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
PINECONE_API_KEY=...
APP_ENV=development
LOG_LEVEL=DEBUG
# In your code — load with python-dotenv
from dotenv import load_dotenv
import os
load_dotenv() # reads .env into environment variables
api_key = os.environ["ANTHROPIC_API_KEY"] # raises KeyError if missing
# OR
api_key = os.getenv("ANTHROPIC_API_KEY", "") # returns "" if missing
In production code, prefer os.environ["KEY"] over os.getenv("KEY"). The former raises a KeyError immediately if the variable is missing, making configuration errors loud and early rather than silently passing an empty string to your AI API.
Reproducible Environments: The Full Workflow
Here's the complete setup workflow a new engineer would follow when cloning your AI project:
# 1. Clone the repo
git clone https://github.com/your-org/my-ai-app
cd my-ai-app
# 2. Activate the correct Python version
pyenv local # reads .python-version, activates automatically
# 3. Create and activate a fresh venv
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# 4. Install pip-tools, then sync all dependencies from the lockfile
pip install pip-tools
pip-sync requirements.txt requirements-dev.txt
# 5. Set up environment variables
cp .env.example .env
# Edit .env with real API keys
# 6. Verify everything works
python -c "import anthropic; print('Ready!')"
pytest tests/ -q
This five-step process is deterministic. Given the same .python-version and pip-tools-generated requirements.txt, every engineer gets byte-identical package versions. This is exactly what you need for AI applications where subtle version differences can change model behavior.
Key Takeaways
- Use pyenv to manage multiple Python versions and pin one per project via
.python-version - Always create a venv per project — never install AI packages globally
- Use pip-tools: list your direct deps in
requirements.in, runpip-compileto generate the pinned lockfile, andpip-syncto install it exactly — never usepip freeze - Store API keys in .env files and load with
python-dotenv; never commit secrets - Use
os.environ["KEY"](notgetenv) so missing config fails fast - Point VS Code's interpreter to
./venv/bin/pythonfor accurate IntelliSense
📥 Downloads
session0.1-setup-environemnt.zip1.6 KB

Comments
Loading comments…