# Building your first LLM API call in Python (step by step)

> Source: <https://heymeraki.substack.com/p/aie_10-building-it>
> Published: 2026-09-15 15:05:56+00:00

Before going any further with this build, a quick note. This build assumes you have read aie_1.0. If you have not, start [there](https://heymeraki.substack.com/p/aie_10-introduction-to-ai-engineering?r=8ei6qe&utm_campaign=post&utm_medium=web), it’ll make this make more sense.

In the previous lesson, we established that an LLM, Large Language Model, is a prediction machine. It has no memory i.e. it is stateless. And as a result, it depends on the context you provide. In this build, we are going to talk to one in code. We’ll call what we build **First Contact.**

### What we are building

A Python script that makes an API call to Anthropic, prints what it gets back and logs how many tokens *(the unit a context window is measured in)* it used. It is intended to be a simple build so you see how LLM calls work.

### What you need

- A terminal
- Python installed on your machine
- An Anthropic API key ( [platform.claude.com](https://platform.claude.com/) , you will need to add a small credit balance as the free tier does not cover API access)
- A code editor (VS Code is fine if you do not have a preference)

### Setting up

Create a folder for the project and set up a virtual environment. A virtual environment keeps your project's dependencies isolated, you can think of it as a container for everything this project needs, separate from anything else on your machine.

```
mkdir ai-engineering
cd ai-engineering
python3 -m venv venv
source venv/bin/activate
```

You will know it worked when you see `(venv)` at the start of your terminal line.

Install the two libraries you need:

```
pip install anthropic python-dotenv
```

- `anthropic` is the official Python library for talking to Claude.
- `python-dotenv` reads your API key from a file so you never have to hardcode it in your script.

Create a `.env` file and add your key:

```
ANTHROPIC_API_KEY=your_key_here
```

Create the script file:

```
mkdir 01
touch 01/first_contact.py
```

Open `01/first_contact.py` in your editor. This is where you will build the script, piece by piece.

### **Step 1: load your API key**

The first thing the script needs to do is read your API key from the `.env` file. Without it, every call you make to Claude will fail.

``` python
from dotenv import load_dotenv
import os

load_dotenv()
```

- `load_dotenv()` reads your`.env` file and makes everything inside it available to the script.
- `import os` gives the script access to environment variables, the place where your API key lives after`load_dotenv()` runs.

After this line runs, your API key exists in the environment and your code can access it.

### **Step 2: create the client**

Before you can send a message to Claude, you need to create a connection to Anthropic’s API. You can think of it as opening a phone line, you set it up, and every call you make goes through it.

In your code, that connection is something called a client. It holds your credentials, knows where to send your requests and it gives you a way to interact with the API without dealing with any of the complications under the hood.

``` python
from anthropic import Anthropic

client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
```

- `os.getenv("ANTHROPIC_API_KEY")` reads the key from the environment.
- `Anthropic(api_key=...)` creates the client using that key.

### **Step 3: make the API call**

This is the call to Claude. You are sending a message and asking for a response.

```
response = client.messages.create(
    model="claude-haiku-4-5",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "What is a large language model? Answer in two sentences."}
    ]
)
```

A few things worth noting here:

- `model` specifies which Claude model to use.
- `max_tokens` sets a ceiling on how long the response can be.
- And `messages` , that list with the role and content, is the context window in its simplest form. This is what you send to the model and it is all it can see.

### **Step 4: read the response**

The response comes back as an object. You need to pull out the parts that matter, in our case this is the text and the token counts.

```
text = response.content[0].text
input_tokens = response.usage.input_tokens
output_tokens = response.usage.output_tokens
```

- `response.content[0].text` is the model’s response as a string.
- `response.usage` gives you the token counts, how many tokens you sent in and how many the model generated back.

### Step 5: print everything

```
print("Response:")
print(text)
print()
print(f"Input tokens: {input_tokens}")
print(f"Output tokens: {output_tokens}")
print(f"Total tokens: {input_tokens + output_tokens}")
```

Your final code should look like this:

``` python
from dotenv import load_dotenv
import os
from anthropic import Anthropic

load_dotenv()

client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))

response = client.messages.create(
    model="claude-haiku-4-5",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "What is a large language model? Answer in two sentences."}
    ]
)

text = response.content[0].text
input_tokens = response.usage.input_tokens
output_tokens = response.usage.output_tokens

print("Response:")
print(text)
print()
print(f"Input tokens: {input_tokens}")
print(f"Output tokens: {output_tokens}")
print(f"Total tokens: {input_tokens + output_tokens}")
```

### Run it

```
python3 01/first_contact.py
```

You should see something like this:

```
Response:
A large language model (LLM) is an AI system trained on vast amounts 
of text data to understand and generate human language. It uses deep 
learning to predict and produce text by identifying patterns in the 
data it learned from.

Input tokens: 19
Output tokens: 51
Total tokens: 70
```

### What you are seeing

The response is the prediction machine predicting, like we said in the last lesson, the most likely continuation of your input. Not based on any fact that it knows, it predicted what a two-sentence response to that question should look like based on its training data.

The token counts show what the context window looks like. You sent 19 (in my case) tokens. The model responded with 51. In total, the entire exchange used 70 tokens. That number is what adds up against the context window limit with every call that you make.

Now that you have made your first contact, in the next lesson, we’ll explore everything that went into the call we have just made. We’ll learn what happens when you hit send and learn how to start controlling it. If you have any questions about this build, let me know!
