S01E01 · Theo / Core

Mechanics Behind Generative AI

Lesson

Ready

Generative AI is changing how we work. Many of us are working faster, tackling more complex problems, or improving the quality and security of our products.

But as agents take over more and more of the work we’ve been doing for years, some of us are questioning the future of programming. We may worry about whether our jobs will even exist in the next few months. At some point, this shift takes away the satisfaction, sense of purpose, and even the joy we get from our work.

MEGA.dev is a story about all of this. And I’m inviting you to join us in the next 4 weeks to learn about generative AI. Together with Theo, Angie, Kent and John, we’ll look at what it means to be a MEGA Developer and how to become one.

Outline

  • Introduction: generative AI, harnesses, configuration, agentic tooling, custom tools
  • Mechanics: instructions, completion, tokenization, prediction, attention, instruction following
  • Limitations: illusions, confabulation, base knowledge, knowledge cutoff, context windows, output limits
  • Providers: models, capabilities, features, settings, pricing, specialization, model mixing
  • Interactions: text generation, structured outputs, function calling, native tools, external tools
  • Steering: generalization, associations, self-querying, latent space, J-space, reasoning

Things worth knowing about LLMs

Working with Large Language Models (LLMs) is easy: all we need to do is send a message. But if we look closer, we’ll find there are things we can do to get better results, and that this can be pushed far beyond direct interaction. On the internet, we can find setups, tools and workflows, but often they have to be adjusted to our projects and our preferences. Then it’s useful to have a general understanding of what’s going on under the hood.

Large language models are typically neural networks trained on large amounts of text to generate content by predicting what comes next. We can think of them as functions that take an input (a prompt) and return an output (a completion). But today, models such as GPT-6 are more like systems that can process multimodal input, generate multimodal output and “reason” about what they do.

The LLMs we work with are often available through platforms and tools such as ChatGPT, Cursor, Claude Code, or Gemini, but we can also interact with them through an API. No matter which model or tools we use, certain traits and mechanisms are present, even if they aren’t visible to the user.

Below we have an overview of the most important things we need to get a brief understanding of before moving further.

Tokenization: LLMs work with numbers, so any data we want to process has to be encoded as numbers and then decoded back. This led to the idea of tokenizers, which assign identifiers to chunks of text. The chunks are chosen through a process that optimizes both the number of chunks in a dictionary and their size. That’s all you need to know for now, but if you’re interested, Let’s build the GPT Tokenizer is one of the best resources on the topic.

Vertical LLM interaction using cl100k_base. “Hey, how are you?” encodes to token IDs 19182, 11, 1268, 527, 499, 30. A language model generates new IDs 40, 2846, 3815, 2294, 11, 9523, 0, which decode to the illustrative response “I’m doing great, thanks!” Token chunks are gray; IDs are red. Leading spaces are preserved.

Open figure

Predicting the Next Token: An LLM generates content token by token, “predicting” what comes next based on what came before. It repeats this process until it selects a special “end token”. The tricky part is that no one can tell exactly what the output will be or why it selects particular tokens. Also, once a token is chosen, there’s no way to remove it, so one poor decision may negatively affect subsequent tokens, and that effect adds up. But we know a lot about the mechanics behind it, and What Is ChatGPT Doing … and Why Does It Work? is an older but still accurate write-up on the topic.

Tokens for “Have a nice” (cl100k_base) feed a language model. Illustrative, invented next-token probabilities: weekend 48%, day 32%, evening 15%, other 5%. The selected new token, “ day”, is not the most probable; it decodes into the continuation “Have a nice day”.

Open figure

Non-determinism: Even with the same input, LLMs do not always produce the same output. This is not only due to the model and its settings; hardware can also play a role, as discussed in Defeating Nondeterminism in LLM Inference. For us, this means we can never be fully sure of the results produced by a language model, regardless of how the prompt and settings look. This is the exact opposite of what we’ve learned about programming over the years.

Illustrative repeated runs with the same input, model and settings: asked for two positive integers summing to 10, the model returns 3 and 7, 4 and 6, or 4 and 7. The first two answers are valid; the third is wrong because its sum is 11. These are hypothetical outputs, not measured runs.

Open figure

Confabulation (or hallucinations): Generative models are trained on vast but limited datasets and produce results based on probabilities. Their behavior also strongly depends on the available context and the task. As a result, models make mistakes, and working with them is not about certainty but about increasing the chance of getting the results we want. A very good read on this is Why language models hallucinate. It’s worth knowing that we have no solution for eliminating confabulation entirely.

Illustrative ambiguity: Alice may be a project, a friend, or a book character. The user means the project but does not supply that context. Asked “Tell me about Alice,” a model may describe the girl who follows a rabbit into Wonderland: a plausible answer about the wrong referent.

Open figure

Reasoning: Language models “think” before answering by generating reasoning tokens. We can observe this every day, and it is reflected in the “global workspace” (J-Space) described by Anthropic in “Verbalizable Representations Form a Global Workspace in Language Models.”

More thinking often leads to better results, but it also takes more time and costs more. Reasoning settings vary by provider, and we can often adjust them. However, the right setting depends on the model and the task we want it to handle.

Still, there are some signs that reasoning isn’t quite what we might have expected: models sometimes fail at a task simply because the information is presented in a different order (Premise Order Matters).

Illustrative vertical flow: the query “What is 17 × 6?” enters a model, which generates reasoning tokens before answering “102.” Token boxes are schematic, not an actual reasoning trace or token count.

Open figure

We’re not just talking about theory here, but about the foundations of generative AI as we’ve seen it over the past few years. Almost everything here hasn’t changed since ChatGPT’s release in November 2022 and remains useful whether we work with agents, build harnesses or build agents from scratch.

Mechanics of Large Language Models

To take the way we work with agents to the next level, we need a clear understanding of their core mechanics so we can use their strengths and avoid their weaknesses.

Request: Each request to an LLM includes context and settings. The context is often an array of messages that needs to be “completed” with an AI response. The settings include the model and reasoning level, as well as available tools and platform-specific fields. Currently, the most popular format for interacting with an LLM API is the Responses API.

Illustrative Responses API exchange. A JSON request asks for the driving distance from Paris to Lyon and defines a Maps tool. The model requests the tool, the application returns its result in a new request, and the model answers. Model and distance values are unspecified placeholders. Static, simplified turns.

Open figure

Completion: LLMs generate content by “predicting the next token”, and the fact that we can chat with them is only due to a format called ChatML that structures the processed context using special tokens. You can play with it using Tiktokenizer. Modern LLMs structure their responses using special tokens, so we can easily tell what the user said, what was generated, and which instructions were provided by the developers of the tool we’re using. In other words, from the model’s perspective, chat messages are just plain text.

The supplied ChatML-style stream beside its structured chat: system says “Answer briefly.”, user says “Hi”, assistant says “Hello”. Red special tokens mark message starts, role/content boundaries, and message ends. The final assistant prefix is open, ready for the model’s next token.

Open figure

Context Window: LLMs need all the content required to generate a response, but the amount they can handle is limited to roughly 250k–1M tokens, depending on the model. In practice, we rarely hit this limit because tools use various forms of auto-compaction.

Still, it’s worth remembering that not everything in a thread is passed to the model. At the same time, we know that the model predicts the next token based on the context available so far. This makes longer conversations with agents lossy, as some information gets compressed or trimmed.

Schematic context window, not to scale. System prompt and tool definitions share a finite token budget with a user message, AI reasoning, a tool call, tool result, further reasoning and an AI answer. New tokens extend the answer into remaining capacity. Only selected thread content is supplied; reasoning accounting and context limits vary by model.

Open figure

While context compaction keeps getting better over time, we’re still talking about compression, so some data gets lost or gets extracted. Either way, the model loses sight of what was originally in our query, making it less likely that we’ll get the result we asked for.

Three copies of illustrative project notes become progressively blurred after successive context compactions. Compaction helps a long agent thread stay within the context window, but details may be lost. Blur is a visual analogy, not literal image processing or a measured rate of information loss.

Open figure

Context Understanding: The fact that an LLM can handle 1M tokens does not mean using that many is a good idea. A model’s reasoning performance still drops with longer contexts, and as a rule of thumb, models perform best when using less than 30–40% of their context limit. For simpler tasks, such as retrieving information from a long text, the latest models perform really well.

Recall and reasoning are different capabilities. On MRCR 8-needle, Astra falls from 100% at 256–512K tokens to 96% at 512K–1M; Sol falls from 92% to 74%. AA-LCR scores rank Kimi K3 89, Fable 5.1 85, Sol/5.5 84, and Astra 81. Recall uses a zoomed 70–100% axis; reasoning scores are not a context-length sweep.

Open figure

Multimodality: Models have different capabilities, and some of them can process not only text but also images, audio and sometimes even video. To make this possible, data has to be tokenized as well (but in a different way) and then processed by a model. The important part is that models process numbers, not actual information, so they perceive images, audio and even text differently from how we might initially expect.

For example, language models often struggle to understand details such as overlapping elements, exact colors, or measurements.

Text, image, audio and video pass through separate tokenizers or encoders before their numerical token representations enter a shared transformer labeled Multimodal model. Text uses “A dog is barking” (cl100k_base); other token sequences are schematic. Distinct internal patterns identify each modality. Conceptual architecture; implementations vary.

Open figure

Structured Outputs: A model can generate text and structure it as a JSON string that can be easily processed in code. This way, we can extract information from unstructured documents, and this also allows us to use language models in application logic that often takes the form of agents.

Illustrative structured output: provided context asks for Kyoto’s city and country. A JSON Schema constrains the output fields; the language model uses the context and its learned knowledge to generate {“city”:“Kyoto”,“country”:“Japan”}. Matching the schema does not itself verify the values.

Open figure

Function Calling: Since models can generate JSON strings, one of the returned fields may be a function name, so they literally point to a tool that needs to be used. This information is handled in code to perform the action with the generated payload and feed the results back to a model.

Vertical function-calling flow, using an illustrative shopping-list example. Tool definitions and a user query go to the model, which generates a JSON call to tasks.create. Application code validates and executes the call. The tool result is fed back to the same model in a second call, and the agent confirms that Buy coffee was added to Shopping. Tool schemas are simplified.

Open figure

Code Mode: Function Calling requires all schemas to be present in the context, so the model can decide which tool to use. But we know the context window has its limits, and it’s a waste to include all this information even if the interaction does not need it. At the same time, the latest models have become very good at writing code.

This leads us to a scenario in which a model can be provided with only two tools, such as “search” and “execute”. This is enough for the agents to write code using available capabilities. It’s more efficient than function calling in almost every aspect, but it’s more difficult to deploy to production, since code has to be executed in sandboxes such as Daytona or Cloudflare. For coding agents that live on our computers, it’s often much easier because they run scripts locally.

Code mode in two steps. The model is exposed to find and execute. First, find returns capability schemas and signatures. Then the model writes JavaScript that chains search results into read calls. Execute runs the code in a sandbox and returns results to the model. The docs capabilities and code are illustrative.

Open figure

LLMs can’t physically interact with their environment, and there are strict limits on how much information they can process. But they can return structured data that we can use to make API calls. This lets us quickly move our interactions with AI “from answers to actions”, and we’re already seeing this in tools like Claude, Devin, Hermes, and Grok Bot.

Platforms and Harnesses

Most of us will work with AI tools such as Cursor, Claude Code, Omp, Pi, or T3 Code. While each offers some unique features, they all share the same foundation: a language model. The real difference lies in the “package”: roughly speaking, how they use the model’s native strengths and address its weaknesses, and how that ultimately affects UX and overall efficiency.

To make working with AI simple, harnesses often hide the underlying mechanics, so we don’t need to worry about them. The problem is, doing so requires generalization so the solution works for most users.

For example:

  • Auto Compaction addresses context window limits, so we can have long threads without errors. Under the hood, there’s often more compression and trimming going on, and this leads us to believe that “our agents know what we are talking about”, while in practice they may see only a small part of what we do.

Illustrative harness compaction of a user–AI thread. Older messages become a shorter summary, tool calls and results are removed from the model input, and attachments are set aside. Recent messages are retained. The visible thread is not the same as the context the model receives for its next reply; compaction choices vary by harness.

Open figure

  • Plan Mode: Agents often encourage us to plan our work in a dedicated mode focused on adding context and clearly describing the task. This helps unless the plan becomes too broad or too detailed. In either case, models struggle to follow all the rules in a single thread. A better idea is to split the plan into smaller tasks, but coordinating those tasks takes more time unless the agents can manage their own work. We’ll discuss this in the upcoming lessons.

Illustrative long plan and agent implementation. The agent addresses items 03, 01 and 05 rather than executing the plan line by line. Item 02 is lost during compaction, item 04 is retained but missed, and item 03 is implemented incorrectly. Overly broad or detailed plans can strain context limits and long-context reasoning; these are possible failures, not measured outcomes.

Open figure

  • Skills are files (or folders) with instructions and sometimes scripts, designed to steer a model towards certain behaviors. The thing is, once enabled, they often remain in the context until compaction removes them or we start a new thread. The model can also trigger a skill on its own, but it chooses based only on the skill’s name and description, since skills can’t all be injected into the context at once.

Illustrative conversation: the user enables the upload skill, which is loaded once as a separate context block, then sends report.pdf. The agent sees a file reference and follows the skill to call the upload tool. A red line shows the skill remaining in context as the conversation moves to meeting planning. Actions are gray; message text is off-white. Skills often remain until compaction removes them or a new thread starts.

Open figure

  • Attachments like images or any other files, or even references to them, are often presented as if they are entirely visible to a model. But they almost never are. Their content has to be loaded by AI, and sometimes it gets loaded only partially. In other words, even if the UI suggests that some files and folders are visible to the agent, it does not mean they really are. The same applies to the entire codebase or any kind of knowledge base.

Illustrative thread with a reference to src/auth.ts and an attached project.zip. Their presence does not guarantee project or codebase access, or that file contents are in the model’s context. Contents must be loaded and may be absent or partial.

Open figure

  • Environment: Some information can be sent to a model upfront, such as a general profile or some rules. But as we work with agents, the environment changes—files get modified or a Git repository gets updated. The model has to be aware of this, but we can’t modify its instructions due to the caching mechanism, which we’ll discuss later. For now, we need to know that our message is not the only thing models get.

The agentic harness expands a user message: a system-reminder containing user context precedes “Hello world,” and runtime fields follow it. These additions stay inside the user message; the earlier instructions remain unchanged so their cached prefix can be reused. Example content is from the supplied payload.

Open figure

Those examples show us some of the underlying mechanics of the tools we work with every day. Their behavior depends on how LLMs work in general and on the API provider, but it always affects our experience and the results we get from AI. Throughout the course, we’ll explore even more behaviors like these and techniques for using them to our advantage.

Now, let’s take a closer look at popular providers such as OpenAI, Anthropic, xAI, and Gemini, their offerings, and their tooling.

  • OpenAI offers GPT models and an almost full range of multimodal capabilities, including image generation and editing, audio understanding and generation, and video generation. ChatGPT is its main product, and OpenAI shaped a popular API format called the Responses API.
  • Anthropic offers Claude models and focuses on text generation and image understanding. Its main products are Claude and Claude Code.
  • xAI aims to deliver a full range of multimodal capabilities. Its main products are Grok and Grok Bot.
  • Gemini offers a full range of multimodal capabilities, including video understanding. It also has its own API format called the Interactions API.
  • Bonus: we also have platforms such as OpenRouter, which offer easy access to models from all the major labs and a vast library of open-source models.

Technically, it’s possible to tell which model is best at a given moment (see Artificial Analysis), but that changes frequently, so it’s a good idea to avoid “vendor lock-in”. Especially since we may want to use a different model for a given task to optimize cost and speed, or multiple models for the same task to improve quality.

When working with AI, we’ll almost always want to use the best models available, although there are some tasks we want to automate or run at scale. Then we may want to check if lower settings

To avoid vendor lock-in, we’ll discuss a harness-agnostic setup with tools that aren’t tightly tied to a particular provider. For example, instead of using Codex, we’ll suggest working with Omp / Pi, OpenCode, or tools like T3 Code or Superset.

Generalized Steering

You may have heard of prompting techniques such as chain of thought, few-shot prompting, or tree of thoughts, which were popular before the rise of LRMs (Large Reasoning Models). Then came general instruction files such as AGENTS.md, containing broad rules and personalization details.

Recently, there’s been a common belief not only that we don’t need additional control over the model, but also that it can do more harm than good. While there’s some truth to that, the reality isn’t so simple. We may still want to steer a model, not by giving it precise instructions to follow, but by guiding it toward certain behaviors. For example:

  • Different perspectives: We can ask AI a set of questions and wait for the results. We can also ask multiple models the same question and then combine the results. Another option is to ask a model to start multiple subagents (often as separate threads) and delegate different parts of a task to them. This takes advantage of the fact that models “think” by generating tokens, and that whatever precedes a token affects which token is generated next.

Three ways to organize AI work: send a set of questions to one model and wait for answers; send the same question to multiple models and combine their responses; or have a coordinating model split a task among subagents, often in separate threads, then bring their results together. A and B denote illustrative parallel branches.

Open figure

  • Self-querying: LLMs hold vast knowledge, but it often stays beyond the reach of the current interaction, namely the “working memory”. We can ask a model a few questions before giving it the actual task. We may also ask a model to ask itself questions and then answer them to widen its own understanding of a topic.

Illustrative self-querying flow for payment retries. A user asks a question. Before responding, the model asks and answers supporting questions about duplicate charges and idempotency. If needed, it asks the user whether the API supports idempotency keys. These answers build relevant context for a better-informed response to the original question.

Open figure

  • Memory: Since every thread with an LLM starts from scratch, we can’t expect even the most intelligent model to understand everything about us. Agentic memory remains an open problem, and we’ll discuss various strategies to get the best possible results with it. For now, we just need to keep in mind that we need a way for an agent to access the required information to accomplish the task, even if that information wasn’t included in our original request.

An agentic thread runs from a brief request through an agent to a completed task. The agent searches an external knowledge base and receives context that was not included in the request.

Open figure

  • Self-Management: There are signs that software is heading towards self-configuration or even self-evolution. Good examples are Pi and OpenCode 2, where agents can manage all the settings without having to reload the environment. This paradigm changes both the way we work with agents and the way we create software. In other words, agents have to become first-class citizens in software. And as users, we need to think about how agents can work on our behalf and manage themselves with minimal involvement from us.

Conceptual self-configuring software: your preferences guide an authorized agent inside the running app. The agent updates live settings without using a settings interface or reloading, restarting, or rebuilding. Illustrative changes: light to dark theme and detailed to brief replies.

Open figure

  • Ambient, Durable Agents: We’re already familiar with working directly with agents. And while there’s still a lot we can improve about that, we’re quickly moving from local agents to remote agents that run on a schedule and respond to events. These agents are designed primarily to work autonomously, so their contact with humans is limited. We need to give them both a way to access necessary information and tools to interact with their environment safely and reliably. This often involves running agents in sandboxes, on their own VPS or PC, with dedicated accounts.

An ambient, durable agent lives on its own VPS in a sandbox with dedicated accounts. Schedules and events trigger it; information flows in and tools let it act on its environment. It works autonomously with limited human contact.

Open figure

Takeaway

So far, generative AI has progressed mostly through scaling, not fundamental architectural changes. In other words, it hasn’t changed much at its core. And as with any other technology we’ve encountered in our careers, it’s worth diving into the details to get at least a basic understanding of what’s going on under the hood. This lets us reason from first principles about working with agents or building them and makes it easier to tell what’s just hype and what may hold actual value.

Teaching Sections and Notes

Outcome

Lesson

Takeaways