Academy

The LLM is a component

A language model alone is a raw text engine; every capability — memory, action, reliability — has to be engineered around it.

The Felesh team 3 min

You provision an API key, write a system prompt, and receive a remarkably fluent response. For a moment, it feels like you have deployed a finished product. Then you ask a follow-up question, and the model has completely forgotten the context. You ask it to update a customer record, and it confidently fabricates a success message while touching exactly zero databases.

A reply that says the record changed, with no write behind itYou ask the model to move customer 1042 to Pro. It replies that the customer is now on Pro. No tool runs, so the customers table still says plan Free and its last write is none. The reply is text only.asked to change a recordyouMove customer 1042 to Pro.modelDone. 1042 is now on Pro.customersid 1042plan: Freelast write: noneno tool call, so the database was never written
The reply says the plan changed, but no tool ran, so the record is still wrong: the model wrote text, not data.

This initial friction comes from a category error: treating a language model as a complete software solution rather than a raw computational component.

An LLM is fundamentally stateless. On its own, it predicts the next most likely token based on its training weights and the text in its context window. It has no persistent memory, no concept of time, and no native agency. It cannot verify its own logic. It cannot natively execute code, trigger webhooks, or read your internal documentation.

Two calls, and the plan from the first is gone from the secondCall 1 carries the user line my plan is Pro and the model’s reply noted. Call 2 starts with that same pair still on screen, then they leave: it carries only what plan am I on? The model replies that it does not know the plan. The history lives in your app and goes out only when your app sends it.call 1usermy plan is Promodelnotedyour app keeps the historycall 2usermy plan is Promodelnoteduserwhat plan am I on?modelI don’t know your plan.no earlier turn sent
Each call starts from zero: the plan said in call 1 is lost unless your code sends it again.

When you call a raw model API, you are interacting with a bare reasoning engine. Every function that makes a model useful in production is a layer of software wrapped around it. If you want it to remember user preferences, you build the state management that injects history into every request. If you want it to answer questions about proprietary data, you build the retrieval pipeline. If you want it to take action in the real world, you expose strict tools, parse the model’s output, and execute the requests on its behalf.

The model inside the code that surrounds itTwo inputs reach the model: memory holds the history, plan is Pro, and retrieval supplies a chunk from plan_policy. The model produces a next token. Parsing reads plan = Pro from its output, and the tool runs set_plan with customer 1042 and Pro. The model is one box; the other four are code you write.memoryhistory: plan Proretrievalchunk: plan_policymodelnext tokenparseplan = Protoolset_plan(1042, Pro)the model is one box; the four around it are code you write
The model is one box in the middle; memory, retrieval, parsing and the tool call are code you write around it.

Moving from a script that calls an endpoint to a reliable agentic system requires extensive structural scaffolding. Before designing that architecture, it helps to understand how the core component processes text, counts tokens, and produces structured data.