Talking to a model (LLM): the theory and the first SDK call

Close-up of the edge of a dark glass object with the words "Perceive", "Synthesize" and "Interfere" engraved in relief, lit in purple tones and reflecting off the glass.
Wes Cockx / Google DeepMind — Unsplash License

In From AI noise to a method I wrote about how AI found its way into my day-to-day, both at work and on my own time. I said I'd write more, mostly technical content. This is the first one: how a language model works on the inside, and how to interact with it through code for the first time.

What a model is and what it's made of

This article is a good general introduction to how LLMs work, if you want the big picture before going into the detail of each piece.

At its core, a language model is a neural network: a network of nodes ("neurons") organized in layers, where every connection between two neurons carries a number — its weight — that decides how much that connection's signal "counts". Each neuron combines the signals reaching it, weighted by each connection, adds a value of its own — its bias — and applies a function that determines the activation passed on to the next layer. 3Blue1Brown has an excellent introduction to neural network theory, with videos and the classic example of recognizing handwritten digits.

Weights and biases together are the model's parameters. They aren't input data and they don't change between one call and the next: they're set during training — the process of adjusting them bit by bit, running through millions of examples until the model's predictions improve — and from then on they stay fixed, as the model's knowledge. 3Blue1Brown goes into how that adjustment works. Once deployed, the model uses those parameters unchanged on every response, though its creators can retrain or fine-tune it in later versions. When a model's name includes a number such as 70B or 400B, it refers to the approximate number of parameters in the model: the number of weights and biases in the entire network. More parameters isn't automatically "better", but it does give the model more capacity to represent complex patterns.

That alone isn't enough to build a language model: you also need a way to turn text into something a neural network can process, and a specific architecture — the transformer — that lets the network take an entire sentence's context into account, not just word by word. The same 3Blue1Brown series continues from there, explaining how those same weights and biases get used inside an LLM.

From text to numbers: tokens and embeddings

Those weights and biases only operate on numbers — a neural network doesn't understand text directly. Some models also process image, audio or video (multimodal models), but here I'm focusing on text, which is what I use in the example further down with Gemini.

The first thing that happens to a text input is that it's split into tokens: chunks of text, not necessarily whole words. A word like "unhappy" might split into several tokens, for example "un" and "happy", though the exact split depends on the tokenizer. It's not a grammar rule: the criterion is statistical — which chunks from a fixed-size vocabulary tend to appear together often in the language.

Each token has a vector attached to it — a list of hundreds or thousands of numbers — stored in what's called the embedding matrix: a table with one row per token in the vocabulary. That vector is the token's initial numeric representation. During training, its components get adjusted so the model learns patterns of use and relationships between tokens. As a result, the vectors can end up reflecting linguistic or semantic similarities, though they're not a perfect representation of meaning. It's not a separate "group by meaning" step: it's a consequence of how the network is trained. 3Blue1Brown devotes a chapter of the same series to this, inside an LLM, with the embedding matrix and the vectors explained visually.

One important nuance: that initial vector is static — the same for a token no matter what sentence it appears in. "Bank" has the exact same vector whether you mean a riverbank or a place to deposit money. Context gets added by the network's later layers, not by the embedding matrix.

How you get to a response

Those static vectors pass through many layers of attention — the transformer's central mechanism — which mix information from different tokens together based on how related they are within the sentence. That's where the vector for "bank" stops being always the same and starts depending on the rest of the sentence: it becomes contextual.

At the end of all those layers it reaches the language modelling head: a final layer that turns that result into a score for every possible token in the vocabulary — which can have hundreds of thousands of entries — and those scores become probabilities. Something like "the token 'cat' has a 2% chance of being next, 'dog' 15%, 'the' almost 0%".

One of those tokens gets picked — usually the most likely one, with some controlled room for variation — and added to the sequence. Then the whole process repeats to pick the next one. That's why an LLM generates text token by token, not all at once: every new token is predicted by looking at all the previous ones. All of an LLM's power comes from doing that one task well, over and over: predicting the next token.

From LLM theory to using an SDK

The entire neural network — its parameters, embedding matrix and attention layers — is trained and hosted on servers run by companies like Google, Anthropic, OpenAI and DeepSeek. It's too big and too expensive to train and run to have on a laptop (there are also smaller, local models, but that's for another article).

In short, these companies offer APIs that let you interact with their models programmatically, and there are two ways to use them:

  • Make the request to that API directly and by hand — with fetch, curl, whatever.
  • Use the vendor's SDK: a library that builds that same request for you — authentication, the JSON format, reading the response.

That's exactly what we're about to do below with @google/genai: a call to aiClient.interactions.create(...) instead of putting together a fetch() by hand.

The first real call

This is the bare minimum to get the SDK working — a single round trip to the model, nothing else. I'm using Gemini, from Google, following its official getting-started guide.

  1. API key: the credential that identifies your requests to Google's API. Created at aistudio.google.com/apikey, "Create API key" button.

  2. Environment: Google also offers the SDK in Python, but I'm using Node by personal preference — with "type": "module" in package.json so I can use import.

  3. SDK: npm install @google/genai.

  4. The script (main.js):

    import { GoogleGenAI } from "@google/genai";
    
    // Read the Google GenAI API key from the environment variables
    const apiKey = process.env.GEMINI_API_KEY;
    
    // Create a Google GenAI client instance
    const aiClient = new GoogleGenAI({
        apiKey: apiKey,
    });
    
    // Create an interaction with the model
    const interaction = await aiClient.interactions.create({
        model: "gemini-3.5-flash-lite",
        input: "Hi, which free model would you recommend for practicing the basics of an AI SDK?",
    });
    
    console.log(interaction.output_text);
    
  5. Run it: node main.js.

And with that, there's already a real response from the model in the terminal — exactly as that run returned it, unverified: the numbers and comparisons it includes aren't checked facts, they're part of what the model generated, and that's exactly what the next section calls into question.

The best model right now for getting started with an SDK, combining **genuinely free access, ease of use, and top-tier performance**, is:

### 1. The Clear Winner: **Google Gemini 1.5 Flash** (via Google AI Studio)

It's the best choice for beginners for the following reasons:

*   **100% free for developers:** With **Google AI Studio**, you get API key access without needing a credit card. Its free tier gives you up to 15 requests per minute (RPM) and a million tokens per minute, which is more than enough for learning and personal projects.
*   **Outstanding performance:** Despite being called "Flash" (built to be fast and lightweight), it beats GPT-3.5 and competes closely with GPT-4o on many tasks.
*   **Natively multimodal:** With the same free SDK you can send it text, images, audio, video and PDFs.

[...]

When the model is wrong about itself

The model introduced claims about itself that I hadn't asked it to verify, and it mixed outdated model names (gemini-1.5-flash, the one it recommends above) with the actual model it was using in that same call (gemini-3.5-flash-lite). I tried using the name it had suggested itself, and the API returned a real error:

NotFoundError: 404 Model 'gemini-1.5-flash' not found. Did you mean 'gemini-3.5-flash'?
Please verify the model name against the supported list: https://ai.google.dev/gemini-api/docs/models

I checked that name against the list of current models and the list of retired models: I didn't find the identifier in either list, so I couldn't confirm its availability. The API also rejected the request and suggested a different model name.

This is a concrete case of what's known as a hallucination: the model generates something that sounds plausible — a model name in the right format, from a family that exists — but is false. This article also discusses this problem: LLMs "can confidently produce incorrect or misleading information, especially when asked about facts or topics that are less common" — and a model talking about itself is exactly that case. The reliable source isn't the chat's answer, it's the official documentation — and it's the API's own error that ends up pointing to it.

Other companies, other SDKs

This article's example used Google (Gemini), but it's not the only one offering models and SDKs. Three major providers are Google, Anthropic (Claude) and OpenAI (GPT) — each with its own API, its own SDK, and its own catalog of current models.

There are several other players in the field: DeepSeek, a Chinese company whose models gained prominence in 2025 by competing with established models at a much lower cost; Mistral, a French AI company with a significant presence in the European market; xAI (Grok), from Elon Musk; and Meta, with its Llama family of models.

Among these companies there's a difference that isn't just about company size. Meta and DeepSeek publish models with open weights — that same parameter file I talked about at the start — that can be downloaded and run on your own hardware, subject to the terms of each Llama version's license or DeepSeek's. Google also offers open-weight models, like Gemma, even though its Gemini models have closed weights. Anthropic and OpenAI offer their main commercial models only as hosted services, without publishing their weights.

Either way, publishing the weights isn't the same as publishing all the training data and process, and it doesn't necessarily mean an open-source license. These are separate questions worth keeping apart. You can run Llama, DeepSeek or Gemma on your own hardware, but you can't redo the training that produced them: you're missing the code and the data they used, you only have the final result.

Here are some of the most important models from the companies above:

Company Models (current examples)
Anthropic Claude Opus 5.5, Claude Sonnet 5.5, Claude Haiku 5.5
Google Gemini 3.8 Flash, Gemini 3.5 Flash-Lite
OpenAI GPT-6 Astra, GPT-6.1 Sol, GPT-6 Luna
DeepSeek DeepSeek-V4-Pro, DeepSeek-V4.1-Flash

As of this article (October 2026). Every company ships new models often; the links above go to each one's current catalog, not to these specific names.

What's left

There's a gap between theory and making an actual API call, but it's not as big as it looked from outside: trained weights and biases, text turned into vectors, and a next-token prediction repeated over and over. The SDK just wraps that in a function.

What I haven't touched here: why I picked gemini-3.5-flash-lite over another model in Gemini's catalog, how you build a multi-turn conversation instead of a single call, and RAG — which uses these same embeddings for something else, finding relevant information before asking the model anything. Plenty of material for future articles.

← Back to the articles

Jestemrique

Development, projects, learning…

Theme