TechByteByByte

Setting Up a Real LangChain Project

Build a proper project folder, install the right packages for OpenAI and Gemini, and handle API keys the safe way — before writing another line of LangChain logic.

#LangChain#Setup#Python#Environment Variables

In Module 1, you ran a couple of small scripts and they just… worked. That’s fine for learning, but it’s not how a real project should be built. A real project needs a proper folder, the right packages installed in the right place, and a safe way to store something very sensitive: your API keys.

This module is deliberately less exciting than the ones before it. There’s no clever trick here, no “aha” moment about why LangChain exists. What there is, instead, is a foundation — get it right once, here, and every module after this one can focus purely on the interesting part, without you having to think about setup again.

Why a proper project structure actually matters

Let’s be honest about why this matters, instead of just telling you to do it.

If you write all your code in one file, with your API key typed directly into it, two real problems show up almost immediately:

  1. You’ll eventually share that code — pasting it into a forum post, pushing it to GitHub, sending it to a friend — and your API key goes with it. Someone else can now spend money using your account, under your name.
  2. Your project will grow. What starts as one file quickly needs a place for your tools, a place for your prompts, a place for your tests. Without a plan for this from the start, everything ends up dumped into one increasingly messy file.

So before writing any more LangChain code, let’s build the actual folder a real, small project should live in.

The project folder

Here’s a small, genuinely sensible structure for the kind of project you’ll be building throughout this course:

langchain-demo/

├── .env                  ← your real API keys live here (never shared)
├── .env.example           ← a template showing what keys are needed (safe to share)
├── .gitignore              ← tells Git to never track .env
├── requirements.txt       ← the exact packages this project needs
├── config.py               ← loads your keys and settings, once
└── app.py                  ← your actual program

You don’t need every one of these files on day one. But it’s worth understanding why each one exists, because you’ll be using this same shape for the rest of the course.

  • .env holds real, secret values — your actual API keys. This file should never be shared, and never uploaded anywhere.
  • .env.example is a safe, shareable copy of .env — it lists which keys your project needs, without containing any real, working values. This is what you’d actually commit to a shared codebase, so a teammate knows exactly what to set up.
  • .gitignore is a file that tells Git — the tool most projects use to track and share code — to completely ignore certain files. .env should always be listed here, so it’s physically impossible to accidentally include your real keys when sharing your code.
  • requirements.txt lists the exact Python packages your project depends on, so anyone else (including future-you, on a new computer) can install everything with one command.
  • config.py is where we’ll load and organize our settings once, so the rest of our code never has to think about how the keys got loaded — it just uses them.

Let’s build this for real, one piece at a time.

Step 1: a clean, isolated Python environment

Before installing anything, it’s worth creating what’s called a virtual environment — a private, isolated space for this specific project’s packages, completely separate from any other Python project on your computer. Without one, installing a package for this project can quietly change what’s available in every other Python project you have, which can cause real, confusing breakage later.

# create the isolated environment (only needs to be done once per project)
python -m venv venv

# activate it — you'll need to do this every time you work on the project
# macOS / Linux:
source venv/bin/activate

# Windows:
venv\Scripts\activate

Once activated, your terminal will usually show (venv) at the start of the line. That’s your confirmation everything you install next will stay contained to this one project.

Step 2: installing the actual packages

Now let’s install what we genuinely need — LangChain’s core package, plus one provider package for each AI company we’re using in this course, plus one small helper for loading our .env file safely.

pip install langchain langchain-openai langchain-google-genai python-dotenv

Let’s be precise about what each one of these actually gives you, since you shouldn’t install things you can’t explain:

  • langchain — the main package, containing the current, recommended building blocks: chat_models, messages, tools, agents, and everything else you saw mapped out in Module 2.
  • langchain-openai — the specific code needed to talk to OpenAI’s servers.
  • langchain-google-genai — the specific code needed to talk to Google’s Gemini servers.
  • python-dotenv — a small, independent helper (not made by the LangChain team) that reads your .env file and loads its values into your program safely. We’ll use it in a moment.

Now let’s capture exactly what we installed, so this project can be reproduced later:

pip freeze > requirements.txt

That single command writes every currently installed package, and its exact version, into requirements.txt. Anyone who later runs pip install -r requirements.txt will get the identical setup you have right now.

Step 3: getting your actual API keys

You’ll need two separate keys for this course — one from OpenAI, one from Google — since we’re deliberately showing both providers throughout.

  • OpenAI: create a key at platform.openai.com, under your account’s API keys section.
  • Gemini: create a key at Google AI Studio (aistudio.google.com), which gives you a free-tier key for the Gemini Developer API.

Copy both keys somewhere temporary for a moment — you’re about to put them where they actually belong.

Step 4: storing keys the safe way

Here’s the file where your real keys will actually live. Create .env in your project’s root folder:

# .env — your REAL keys. This file is never shared or committed.
OPENAI_API_KEY=sk-your-real-openai-key-here
GOOGLE_API_KEY=your-real-google-key-here

Now create .env.example — the safe, shareable twin of that file:

# .env.example — shows what's needed, contains no real values
OPENAI_API_KEY=
GOOGLE_API_KEY=

And add this line to .gitignore, so Git is physically told to never track your real keys:

.env
venv/
__pycache__/

This is worth pausing on, because it’s not just a formality. If you skip this step and later push your project to GitHub, your real API key becomes visible to anyone in the world who looks at your repository’s history — and automated bots genuinely do scan public GitHub repositories specifically looking for exposed keys like these, within minutes of them being pushed. This isn’t a hypothetical risk; it’s one of the most common, real ways people accidentally rack up unexpected charges on their AI provider account.

Step 5: loading your keys safely into Python

Now let’s actually use python-dotenv to read that .env file. Create config.py:

# config.py
from dotenv import load_dotenv
import os

# reads the .env file and loads its values into the environment,
# exactly as if you'd set them manually in your terminal
load_dotenv()

OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")

if not OPENAI_API_KEY:
    raise ValueError("Missing OPENAI_API_KEY — check your .env file.")

if not GOOGLE_API_KEY:
    raise ValueError("Missing GOOGLE_API_KEY — check your .env file.")

Notice what this file actually does, and why it’s worth having as its own file rather than repeated everywhere: it loads the .env file exactly once, checks that both keys genuinely exist, and fails immediately with a clear error message if either one is missing — rather than letting your program run partway and fail later with a confusing error buried deep inside LangChain’s own code.

You’ll notice something interesting in a moment: LangChain’s own model classes actually look for OPENAI_API_KEY and GOOGLE_API_KEY in your environment automatically — you often won’t even need to pass a key in directly. load_dotenv() is what makes that automatic behavior possible, by making sure those values are genuinely present in the environment before LangChain goes looking for them.

Step 6: your first real, structured LangChain call

Now let’s write app.py — a small program that actually uses everything we just set up, calling both providers, the proper way.

# app.py
import config  # running this file loads and validates our .env values first

from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage

# no key needs to be passed here — LangChain finds it in the environment,
# thanks to config.py having already loaded it via load_dotenv()
openai_model = init_chat_model("openai:gpt-4o-mini")
gemini_model = init_chat_model("google_genai:gemini-2.0-flash")

question = [HumanMessage(content="In one sentence, what is LangChain?")]

print("OpenAI says:", openai_model.invoke(question).content)
print("Gemini says:", gemini_model.invoke(question).content)

Run this with:

python app.py

If everything is set up correctly, you’ll see two genuine, independent answers — one from each provider — and notice that at no point did your actual key ever appear anywhere in app.py itself. That separation is the entire point of everything we just built.

A quick, honest note on a common mistake

A frequent early mistake is putting real key values directly into code, “just for now,” meaning to fix it later:

# DON'T do this — even temporarily, even "just for testing"
model = init_chat_model("openai:gpt-4o-mini", api_key="sk-abc123...")

The problem isn’t that this fails to work — it works perfectly fine, which is exactly why it’s dangerous. “Just for now” code has a well-earned reputation for quietly becoming permanent, especially the moment you get busy or distracted. Building the .env habit from your very first project, rather than treating it as an optional extra step for later, is genuinely worth the small, one-time setup cost.

What you should take away from this module

You now have a real, reusable project shape:

  • A virtual environment, isolating this project’s packages from every other project on your machine.
  • The exact packages this course needs, captured in requirements.txt so the setup is reproducible.
  • Real API keys stored safely in .env, kept out of Git entirely by .gitignore, with .env.example as the safe, shareable template.
  • A small config.py that loads and validates those keys once, so the rest of your code never has to think about it again.
  • A working app.py that calls both OpenAI and Gemini, with your keys never appearing anywhere in the code itself.

Every module from here on will assume you have exactly this shape ready to go.

Where this goes next

With setup out of the way, the next module dives properly into Chat Models — the piece you’ve been using in small doses since Module 1, but haven’t yet explored in real depth: model parameters, streaming, async calls, and what actually changes when you switch providers.

Author
TechByteByByte Editorial Team
Reviewed by
TechByteByByte Admin
Published
Last reviewed