Concepts / Evaluating a First Version Before Adding Structure

Evaluating a First Version Before Adding Structure

The first version of an AI feature slice is a literal sequence of API calls in a single file, with no framework, abstraction, or agent loop.

  • Programming

A Predictable Mistake at the Start

When engineers begin building an AI feature, many reach for structure immediately. They choose a framework, define an agent loop, create wrapper classes for every model call, and plan a set of abstractions for features that do not exist yet. This instinct comes from good habits in conventional software. Applied to the first version of an AI feature, however, it often works against the goal. The first version becomes hard to read, hard to run, and hard to test before anyone has seen it perform its basic job.

The belief to examine in this article is that the first version should already look like a finished system. The correct starting point is smaller than that. This article describes what that smaller starting point looks like, why it is deliberate, and how the system grows from it.

What do you think happens?

Suppose a feature runs several model calls in sequence and the final reply is wrong. Version A is one readable file with six steps written one after another. Version B is spread across a framework, a loop, and several helper classes. Which version makes it easier to find the step that produced the bad reply?

  • Version A, the single readable file

  • Version B, the layered version with a framework and helper classes

  • Neither, because the number of files does not affect debugging

Reveal answer
Answer:

Version A, the single readable file.

In a literal slice, the failing step can be found by reading down the sequence and changing the relevant line. In a layered version, the path a value takes is spread across several places, so the step that produced the bad reply is harder to locate.

Why Structure Feels Like the Right Move

Structure feels responsible. A framework promises that common work is already handled. An agent loop promises that the model can decide what to do next. Wrapper classes promise that every model call is tidy and reusable. Each of these choices looks like good engineering when judged in isolation.

The problem is timing. Structure is usually chosen before there is evidence about what the system needs. A developer who has not yet seen which steps repeat, which prompts change, or where failures cluster may build a layer that fits the imagined system rather than the real one. The result is code that is organized around guesses.

The Literal First Slice

Definition

The first version of an AI feature slice is a literal sequence of API calls in a single file, with no framework, abstraction, or agent loop.

In a literal slice, the whole flow is written out. The steps are: receive the input, call the model with one prompt, parse its output, call the next model with a second prompt, format the result, and return it. Each of these steps is visible on its own line. Nothing is hidden behind a class or a loop that has to be inspected separately.

The source is candid that this code is not elegant. The file is ugly. It is also legible, and that legibility is the point. The literal version is not a shortcut to be discarded carelessly. It establishes a working baseline, and once a clear baseline exists, every later change can be compared against it.

Tracing a Value Through Two Model Calls

The following example is a generic stand-in for a model call. It runs without any external service. The function call_model represents one model call. In a real first slice it would be replaced by an actual API call. The rest of the file is the literal sequence: two model calls, a parsing step, a formatting step, and a return.

Code walkthrough
def call_model(prompt):
    return 'model says: ' + prompt

def handle_request(customer_text):
    draft = call_model('draft a reply to ' + customer_text)
    parsed = draft.replace('model says: ', '')
    review = call_model('check ' + parsed)
    formatted = 'Reply: ' + review.replace('model says: ', '')
    return formatted

print(handle_request('Where is my order?'))
  1. 1
    Line 1 defines the stand-in model call, which returns the prompt wrapped in a fixed prefix.
  2. 2
    Line 4 sends the customer text to the first model call; its output lands in draft.
  3. 3
    Line 5 is the parsing step. It removes the prefix so that the next prompt contains only the useful text.
  4. 4
    Line 6 sends the parsed text to the second model call; its output lands in review.
  5. 5
    Line 7 is the formatting step. It removes the prefix from review and adds a Reply label.
  6. 6
    Line 8 returns the formatted value, and line 10 prints it.
  • call_model is a stand-in for one model call
  • draft holds the output of the first model call
  • parsed is the intermediate result the second call consumes
  • review is the output of the second model call
  • formatted is the final value returned to the caller
Output
Reply: check draft a reply to Where is my order?

Read the diagram as a single path. Each arrow carries one value from one step to the next, and nothing has to be looked up elsewhere to follow the flow. The output of the first model call is an intermediate result: it is produced by line 4, consumed by the parsing step on line 5, and never returned to the caller. The parsed text is then the input to the second call. This is the property that makes the literal version easy to debug. To find where a value went wrong, you follow the arrows in the same order as the lines.

Three Reasons the Literal Version Matters

  • The customer can read it. The people who care about the outcome can check what the system does without learning a framework.
  • The developer can run it directly, without first setting up machinery.
  • An evaluation set can run against it, so the first version can be measured from the start.

Together these reasons make the literal slice a working baseline. Because it can be read, run, and evaluated early, the first real measurements of the feature come from the simplest possible version of it.

Fixed Sequence Versus Agent Loop

The literal slice always runs the same calls in the same order. Each call happens exactly once. An agent loop works differently: the model decides whether to repeat a step or branch. The two designs share the same underlying model calls, but their control flow is different, and that difference is what makes the literal version easier to reason about.

In the literal group, you can predict every path through the code by reading it once. In the agent loop group, the number of model calls depends on what the model decides at run time. That unpredictability is exactly what makes the loop harder to debug in an early slice, so the source places it after a working literal baseline exists.

Where Frameworks and Abstractions Fit

Frameworks and abstractions are useful, but usually in a later phase. The source's position is that they belong once the literal sequence runs and the evaluation set can measure it. At that point, structure can be added where the code has shown a real need for it. Before then, a layer sits between the developer's code and the model API and hides the calls that the first slice keeps visible.

The diagram shows what the literal version does not need. Each layer above the model API hides something from the direct-call version. The framework hides how steps are chained, the loop hides how many calls happen, and the wrappers hide the individual calls. Those hidden details are exactly what a first slice needs to show, because they are where failures are found.

When Structure Pays Off

Abstractions chosen too early are chosen without evidence. Growing from a working literal slice lets the structure be shaped by what the working system actually does. The question to ask is not whether a framework is good in general, but whether the running slice has revealed a specific need it would meet. Repeated steps, prompts that change in the same way across calls, and failures that cluster in one place are the kinds of evidence that justify adding structure.

Mistakes When Starting Too Structured

  • Common mistake

    Building the framework, loop, and wrappers before the first call has run

    What it looks like

    A developer creates an agent loop and five wrapper classes, but the feature has never returned a reply.

    Why it fails

    The first version is then hard to run and hard to test before anyone has seen it do its basic job.

    Do this instead

    Write the literal sequence first, run it end to end, and only then consider which parts need structure.

  • Common mistake

    Treating the literal file as a shortcut to throw away

    What it looks like

    The team deletes the six-step file as soon as the framework version is started.

    Why it fails

    The literal version is the working baseline. Without it, later changes have nothing to be compared against.

    Do this instead

    Keep the literal version as the reference point and compare later structured versions against it on the evaluation set.

  • Common mistake

    Hiding intermediate results inside helper objects

    What it looks like

    The output of the first model call is stored in an object's internal field and never visible on its own line.

    Why it fails

    The path a value takes no longer matches the order of the lines, so the failing step is harder to find.

    Do this instead

    Keep each intermediate result in a named variable on its own line, as the literal slice does.

  • Common mistake

    Assuming a layered design is easier to debug before anyone has traced a single value through it

Practice Tracing the Literal Slice

EASY

Using the handle_request example, a customer sends the text 'Refund status?'. Without running the code, trace the value at each step: what does draft contain, what does parsed contain, and what does the function return? Then check your answer by running the file.

Hints
  • draft is the full output of the first call_model call, including the prefix 'model says: '.
  • parsed is draft with the prefix removed, and it becomes the input to the second call.
  • The second call adds the prefix 'check ' before the parsed text, and the formatting step removes its prefix and adds 'Reply: '.

Summary of the Literal-First Approach

At a glance

  • The first version of an AI feature slice is a literal sequence of API calls in a single file, with no framework, abstraction, or agent loop.
  • The literal version is legible to the customer, runnable by the developer, and evaluable against an evaluation set, which makes it a working baseline.
  • In a literal slice, a value's path matches the order of the lines, so a failing step can be found by reading down the sequence and changing the relevant line.
  • Frameworks and abstractions are useful, but usually in a later phase, once the working slice shows where structure is needed.
  • Good agentic systems are mostly just software, so the behavior should be visible, the steps testable, and failures traceable to specific places in the code.