Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Show the two day-4 abstracts from Chapter 1 to any researcher and they’ll sort them in five seconds. One searches over network designs; the other makes a model answer from fetched documents. Nobody needs a keyword list for that. They just read what each paper does.

Reading a short text and judging what it’s about is exactly what a language model is good at. So this chapter takes the decide function from Chapter 1 and hands it to a model.

There’s an optional live demo near the end that uses Google’s Gemini API, with the same free setup as Grounded AI Chapter 4: no credit card, just a key from aistudio.google.com/apikey. Everything before that runs right here in the page.

Chapter 2 of 12 · Foundations

Where we left off: Our scout runs a think, act, observe loop, but the “think” step is a list of hand-written keyword rules that match words, not topics.

What we fix now: Hand the “think” step to a language model: describe what you care about in a sentence, show it the papers, and get back a decision your code can act on.

By the end, you can:

  • explain which part of the agent a model replaces, and which parts stay ordinary code

  • build a prompt that asks for a structured decision, and read the reply safely before acting on it

  • identify why a model that can only see what’s in its prompt still gets stuck

The fix: the model proposes, your code decides what happens

The model’s job here is narrow. It reads text and writes text back: a proposal for what to do. It doesn’t run searches or write files. Your code reads that proposal, checks it, and carries it out, or doesn’t. I’ll keep coming back to this split for the rest of the course, because almost every safety decision later on depends on it.

The change from Chapter 1 is small in code:

  1. Instead of a keyword list, describe the interest in a sentence, the way you’d explain it to a colleague.

  2. Put that sentence and today’s papers into a prompt.

  3. Ask for a reply in a fixed format your code can read: which paper to pick (or none), and one sentence saying why.

  4. Your code reads the reply and acts on it: summarize, or stop.

Why a fixed format? Because the next step is code, and code can’t act on “I’d probably go with the second one, it looks more relevant”. It can act on {"pick": 1, "reason": "..."}. I ask for JSON by hand here so you can see where it goes wrong; Chapter 12 uses the model’s built-in structured output instead.

That’s everything the model will ever know about the task: one sentence of interest, the papers, and the reply format. Remember that; it’s the problem at the end of this chapter.

Plugging a model into the scout

A real model needs a network connection and an API key, and this page has neither. So the next cell uses a stand-in: mock_model returns a prewritten reply for each day. I wrote those replies by hand to look like typical model answers; they are not recorded from a real run. I’d rather show you a believable reply that behaves the same every time than a real one that changes on every page load. The Colab section at the end swaps in a real Gemini model with one line.

That one line matters: to the scout, a model is just a function that takes a prompt and returns text.

Day 4 goes the right way, and the reason explains why: one paper fetches passages to ground answers, the other searches over network designs. No keyword rule could have made that call.

Try run_scout(day_2) and run_scout(day_3) too. On day 3 the model says none of them fit, and the scout stops, like the loop in Chapter 1, except nobody wrote a rule for it.

Reading the model’s reply safely

There’s a quiet assumption in decide: that the model replies with clean JSON and a paper number that actually exists. Real models usually do. Not always.

Both crash, for different reasons. The chatty reply isn’t valid JSON as a whole, even though a perfectly good decision is sitting inside it. The second parses fine, but paper 7 doesn’t exist, so it crashes one step later, when the code tries to use it.

I treat every model reply as data to check, never as a command to follow. Here’s a parse_reply that pulls the JSON out of the text, checks the paper number, and falls back to stopping when something doesn’t make sense:

The chatty reply now works, and the impossible pick turns into a safe stop with a reason attached. decide checks every reply before the scout acts on it. This check will keep growing through the course; Chapter 12’s version also validates against a schema.

The stand-in says it can’t tell, and a careful real model often answers the same way. That’s a better answer than a guess. But a person would just open the paper and skim the method section. The answer is right there.

The scout can’t do that. Everything it knows was pasted into the prompt before it started, and when that isn’t enough, its only options are “pick”, “none”, or a guess. It gets worse at scale: a real arXiv day has over a hundred new papers, and pasting every full text into one prompt isn’t an option.

Bonus (Colab only): a real model decides

Everything above runs anywhere, because mock_model is just a dictionary lookup. To see a real model make these decisions, open this notebook in Colab and run the cell below:

Open In Colab

Get a free key at aistudio.google.com/apikey (no credit card needed), then paste it into API_KEY below. Treat it like a password: fine to paste into your own private Colab copy while experimenting, never commit it to a public repository or notebook.

Compare the real reasons with the stand-in ones. The wording will differ, and on day 5 a real model might pick paper 0 on a hopeful guess instead of saying it can’t tell. Run it a few times and the answers can change. That variation is the reason the second half of this course exists.

Quick check

Before moving on, answer for yourself (no peeking ahead):

  1. Of the three moves, think, act, observe, which one did the model take over? What stayed ordinary Python, and why does that split matter?

Check your reasoning ▸

A strong answer says the model only took over “think”: it reads text and proposes a decision. Acting on that decision (summarizing, stopping) and checking the reply stayed in your own code. That matters because the code is the part you can read, test, and trust; the model only ever produces text, and nothing happens unless your code chooses to act on it.

  1. Chapter 1 used a keyword list. This chapter describes the interest in a sentence. Why does that fix day 4, where the keyword rules failed?

Check your reasoning ▸

A good answer explains that keywords match spelling, so “search” in “architecture search” looked relevant and “grounding” was never on the list. A sentence describes a topic, and the model judges each abstract by meaning, so it can tell that searching over network designs isn’t about documents, and that fetching passages to ground answers is.

  1. Why does the prompt ask for JSON in a fixed shape instead of letting the model answer freely?

Check your reasoning ▸

Because the next step is code, and code needs something it can reliably read, like a paper number or null. A free-text answer (“I’d probably go with the second one”) would need a person to interpret it. The fixed format is what lets code act on a judgment about meaning.

  1. parse_reply turned “pick paper 7” into a safe stop. Why should code check a model’s decision instead of just trusting it?

Check your reasoning ▸

Because a model’s reply is text that can be malformed or simply wrong, even when it usually isn’t. Acting on it blindly means one bad reply crashes the program or, worse, does the wrong thing. A strong answer adds that the safe fallback matters as much as the check: when the reply doesn’t make sense, stopping honestly beats guessing.

  1. On day 5 the model said it couldn’t tell. What would a person do next, and what would the scout need in order to do the same thing?

Check your reasoning ▸

A person would open the paper and read more of it. The scout would need a way to ask for more information during its run, for example an action like “read the full text of paper 0”, which its code then carries out and feeds back into the next “think”. Right now the model can only judge what was pasted in before it started. A strong answer connects this back to the loop: the model needs actions it can choose between, not just a single verdict.


You can now: explain which part of an agent a model replaces, build a prompt that returns a structured decision, and check that decision before your code acts on it.

But one problem remains: the model can only judge what was pasted into its prompt. When an abstract doesn’t say enough, it can’t go and read more, and on a real day there are far too many papers to paste in at once. The next chapter gives the model actions it can ask for, like searching papers and reading one in full, and then asks an uncomfortable question: once it can act, how much should it be allowed to do without you?

Next → Chapter 3: Tools and the Autonomy Dial