← Back

Python Virtual Environments for GenAI

Posted on Thu 19 February 2026 in GenAI

It's one of those things that feels like pure overhead the first time you skip it — and then, a few months and a few projects later, becomes the thing that saves you from a very specific, very avoidable kind of pain: two projects on the same machine quietly fighting over which version of a library gets to exist. Virtual environments are the fix, and in generative AI work specifically, they matter more than in most other kinds of Python development. Here's why, and how to actually use them well.

The Problem Virtual Environments Solve

By default, Python installs packages globally — one shared pool of libraries available to every script on your machine. That works fine until you have two projects with conflicting needs: Project A needs version 1.2 of a library, Project B needs version 2.0, and installing one breaks the other. Without isolation, you're stuck constantly reinstalling the "right" version depending on which project you're currently working on, and eventually something breaks in a way that's genuinely hard to trace back to a version mismatch.

A virtual environment solves this by creating a self-contained, isolated Python installation for a single project — its own set of installed packages, completely separate from your system Python and from any other project's environment.

Why This Matters More in GenAI Work Specifically

Generative AI projects tend to accumulate a distinctive combination of dependency pressures:

  • Fast-moving libraries. Packages like anthropic, openai, transformers, and torch update frequently, sometimes with breaking changes between versions — a project built against an older version can genuinely stop working after a routine pip install --upgrade.
  • Heavy, specific dependencies. Libraries like PyTorch or TensorFlow (referenced in the earlier "Why Python is Popular in Generative AI" post) often need to match specific CUDA versions or hardware configurations — getting this right for one project and then needing something different for another is a common source of pain without isolation.
  • Juggling multiple projects at once. It's common to have one project pinned to an older SDK version for stability while experimenting with a newer one elsewhere — isolation makes that trivial; without it, it's a constant source of conflict.
  • Reproducibility across machines and collaborators. If a teammate or a deployment environment doesn't have the exact same package versions, subtle bugs and inconsistent behavior — including in prompt behavior and API compatibility — become much harder to track down.

Creating and Using a Virtual Environment

Python's built-in venv module is the standard, no-extra-install way to create one:

python -m venv myenv

This creates a self-contained directory (myenv) holding an isolated Python interpreter and package installation location. Activating it switches your terminal session to use that isolated environment:

# macOS/Linux
source myenv/bin/activate

# Windows
myenv\Scripts\activate

Once activated, your prompt typically shows the environment name, and any pip install command installs packages into that environment only — not globally:

(myenv) $ pip install anthropic

Deactivating returns you to your system Python:

deactivate

A Practical GenAI Project Setup

A typical workflow for starting a new generative AI project:

mkdir my-ai-project
cd my-ai-project
python -m venv venv
source venv/bin/activate
pip install anthropic python-dotenv pydantic

This gives the project its own isolated copy of the anthropic SDK, python-dotenv (referenced in the earlier Python fundamentals post for loading API keys), and pydantic (covered in the JSON handling post for schema validation) — all contained to this project, with zero risk of colliding with a different project's dependencies elsewhere on the same machine.

Tracking Dependencies: requirements.txt

Creating the environment is only half the story — you also want a record of exactly what's installed, so the environment can be recreated elsewhere (a teammate's machine, a deployment server, your own machine after a fresh install):

pip freeze > requirements.txt

This generates a file listing every installed package and its exact version:

anthropic==0.39.0
pydantic==2.9.2
python-dotenv==1.0.1

Anyone else can then recreate the exact same environment:

python -m venv venv
source venv/bin/activate
pip install -r requirements.txt

This connects directly to the prompt versioning discipline covered earlier in this series — just as it's worth knowing exactly which prompt version produced a given result, it's worth knowing exactly which library versions your code was actually tested against, since an SDK update can change API behavior underneath you just as a model update can.

Why Pinning Versions Matters Specifically for AI SDKs

Provider SDKs (like anthropic or openai) evolve alongside the underlying models and APIs they wrap. An SDK update can change default parameters, response formats, or available methods — meaning code that worked perfectly last month can behave differently, or break outright, after an unpinned pip install --upgrade. Pinning exact versions in requirements.txt means your project only updates its dependencies deliberately, when you choose to test and verify the update, rather than silently picking up changes on every fresh install.

venv vs. Other Tools

venv is built into Python and sufficient for most individual projects, but a few alternatives show up often enough in GenAI work to be worth knowing about:

  • conda — popular in data science and ML contexts specifically because it can manage non-Python dependencies too (like specific CUDA versions for GPU-based libraries), which venv alone can't handle.
  • poetry or uv — dependency management tools that go beyond venv, handling version resolution, lockfiles, and packaging more robustly for larger or shared projects.
  • pipenv — an older tool combining virtual environments and dependency management into one workflow.

For a solo script or a small personal project, plain venv plus a requirements.txt is usually enough. For a larger, collaborative, or production-bound project, one of the more full-featured tools is often worth the extra setup.

A Common Mistake: Forgetting Which Environment Is Active

A frequent early frustration: running pip install or a script without realizing the virtual environment isn't activated, so packages install globally (or fail to import at all) instead of into the intended isolated environment. It's worth checking which Python is actually active, especially when something that "should be installed" throws an import error:

which python   # macOS/Linux
where python    # Windows

If the path doesn't point inside your project's venv folder, the environment isn't active — a quick, easy check that resolves a surprising number of "why isn't this working" moments.

Keeping Environments Out of Version Control

The virtual environment folder itself (venv/, myenv/, etc.) shouldn't be committed to version control — it's large, platform-specific, and entirely reconstructable from requirements.txt. A .gitignore entry handles this:

venv/
__pycache__/
.env

Note .env is included here too — this is where API keys typically live (as covered in the fundamentals and variables posts), and it should never be committed alongside your code for the same security reasons covered in that earlier discussion.

The Bottom Line

Virtual environments are a small, easy-to-skip habit early on that becomes genuinely important the moment you're juggling more than one generative AI project, collaborating with anyone else, or trying to reproduce a result reliably weeks or months later. Given how quickly AI SDKs and libraries evolve, isolating each project's dependencies — and tracking them explicitly in a requirements.txt — is what keeps a pip install --upgrade somewhere else on your machine from quietly breaking a project you haven't touched in weeks. It's not a glamorous part of GenAI development, but it's exactly the kind of foundational discipline that keeps everything else in this series — the prompts, the scripts, the classes, the API calls — actually working reliably over time.