Setting Up a Clean AI Dev Environment

Tech Buddy June 12, 2026 3 min read
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

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

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 .csproj PackageReferences.
  • requirements.txt — the fully resolved, fully pinned lockfile generated by pip-compile. This is your packages.lock.json.

The tool that bridges them is pip-tools.

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.

C# / .NET
<!-- .csproj — your direct deps -->
                          <PackageReference
                            Include="Anthropic.SDK"
                            Version="3.*" />
                          
                          <!-- packages.lock.json — resolved tree -->
                          <!-- generated by dotnet restore --restore-locked-mode -->
Python
# 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

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, run pip-compile to generate the pinned lockfile, and pip-sync to install it exactly — never use pip freeze
  • Store API keys in .env files and load with python-dotenv; never commit secrets
  • Use os.environ["KEY"] (not getenv) so missing config fails fast
  • Point VS Code's interpreter to ./venv/bin/python for accurate IntelliSense