An LLM API call is still an API call.
You send a request, authenticate with an API key, pass in some text, and get a response back. The unusual part is that the response is generated by a model, so you also have to care about things like prompt wording, token limits, latency, cost, and occasional failures.
In this chapter, you will make your first LLM call, read the response, estimate token usage, and add basic retry logic. These are small pieces, but they are the pieces every real AI application is built on.
First, we need a provider.
This course uses OpenRouter. OpenRouter is an AI gateway: one API key, one OpenAI-compatible API, and access to many models from providers such as OpenAI, Anthropic, Google, Meta, Mistral, and others.
That matters because beginners should not have to learn five different SDKs before they can build one useful app. With a gateway, you write one integration and choose the model with a string.
Your app sends a request to OpenRouter. OpenRouter sends that request to the model you selected and returns a response in a mostly consistent format.
This does not mean all models behave the same. They still differ in quality, speed, price, context window, tool support, and structured-output support. The benefit is simpler engineering: you can compare models by changing the model name instead of rewriting the whole client.
You can browse OpenRouter's model list and free model collection. Treat free-model availability as temporary. Pricing, limits, and supported model slugs change over time, so always check the model page before building a project around a specific model.
The examples below hardcode model names so you can run the snippets directly. If a model is not available for your account, replace the string with another model slug from OpenRouter.
Most LLM APIs use API keys. An API key proves that the request is coming from your account, and it is usually connected to your credits or billing method.
Create an account at openrouter.ai, then create an API key from your account settings.
Free access, rate limits, and payment requirements vary by model and can change. Check OpenRouter's pricing page and the specific model page before assuming a model is free for your use case.
An API key is a secret. Anyone who has it may be able to use your account. Do not paste it directly into your code.
Never do this:
Use an environment variable instead.
There are two common ways to do that.
This works well for quick experiments. The variable stays available in that terminal session.
.env fileFor a project, a local .env file is usually easier. Create a file named .env in your project root:
Then load it in Python with python-dotenv:
Add .env to .gitignore before you commit anything:
Install the libraries used in this chapter:
We will use the OpenAI Python SDK because OpenRouter supports an OpenAI-compatible chat API. The main change is the base_url.
Most chat-style LLM requests have the same core parts:
The most important part is the messages array. It is a list of messages in conversation order. Each message has a role and content.
The common roles are:
Here is a small example:
When you call the API, this is the basic flow:
In plain English:
Here is a complete first call through OpenRouter:
Here is what each part does.
base_url="https://openrouter.ai/api/v1" points the OpenAI SDK at OpenRouter instead of OpenAI's own endpoint.
model tells OpenRouter which model to use. OpenRouter model slugs usually look like provider/model-name. Here, openai/gpt-5.4-mini routes the request to OpenAI's GPT-5.4 Mini model. This is a concrete model slug, which is better for a course because learners are more likely to see the same behavior when they run the code.
messages contains the conversation. In this example, the system message sets the answer style and the user message asks the actual question.
max_completion_tokens limits how many tokens the model can generate. This protects you from unexpectedly long responses and helps control cost.
choices[0].message.content is the generated answer. usage, when present, gives token counts that are useful for cost tracking and debugging.
The response object is larger than the answer text. Simplified, it looks like this:
A few fields worth understanding:
choices[0]."stop" usually means the model finished normally. "length" means it hit the output limit and may be cut off.LLMs do not process text exactly as words. They process tokens.
A token is a small chunk of text. In English, a token is often about three or four characters, but that is only a rough estimate. Common words may be one token. Long words, uncommon words, punctuation, and code can split into several tokens.
Useful rules of thumb:
Token counts matter for three reasons:
Cost: Most providers charge by token. Output tokens are often more expensive than input tokens because generating text requires more compute.
Context window: Every model has a maximum number of tokens it can handle in one request. That limit includes your input, previous conversation, retrieved documents, and the model's output.
Latency: Longer inputs and longer outputs usually take more time.
For a better estimate with OpenAI-style tokenizers, use tiktoken:
For non-OpenAI model families, tiktoken is still only an estimate. Claude, Gemini, Llama, and other models use different tokenizers. Use estimates before sending the request, then log the actual counts returned in response.usage.
LLM APIs fail for ordinary reasons: bad keys, bad requests, rate limits, provider outages, network problems, timeouts, and not enough credits.
Good application code treats these as expected cases, not surprises.
Here are common errors:
Here is a small retry wrapper:
This wrapper retries only errors that are likely to be temporary. It does not retry bad API keys, invalid model names, malformed requests, or quota errors, because retrying those usually just wastes time and money.
Always set a timeout in application code. Without one, a request can keep your user waiting much longer than you intended.
For long answers or slower reasoning models, use a longer timeout and stream the response so the user sees progress.
Now we can send the same prompt to a few models and compare the answers. This is one of the practical benefits of using a gateway: one client, one key, several model families.
If one of these model slugs is not available for your account, replace it with a model from the current OpenRouter model list.
When you run the script, compare a few things:
Do not choose a model only because it works once. For real applications, test it on the kinds of prompts your users will actually send.
10 quizzes