<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Part 1: Foundations | Garage Education</title><link>https://www.garageeducation.org/docs/agent-harness-spring-ai/01-foundations/</link><atom:link href="https://www.garageeducation.org/docs/agent-harness-spring-ai/01-foundations/index.xml" rel="self" type="application/rss+xml"/><description>Part 1: Foundations</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>en-US</language><copyright>©</copyright><lastBuildDate>Sat, 10 Oct 2026 00:00:00 +0000</lastBuildDate><image><url>https://www.garageeducation.org/media/logo.svg</url><title>Part 1: Foundations</title><link>https://www.garageeducation.org/docs/agent-harness-spring-ai/01-foundations/</link></image><item><title>Chapter 1: Why a harness?</title><link>https://www.garageeducation.org/docs/agent-harness-spring-ai/01-foundations/01-why-a-harness/</link><pubDate>Sat, 10 Oct 2026 00:00:00 +0000</pubDate><guid>https://www.garageeducation.org/docs/agent-harness-spring-ai/01-foundations/01-why-a-harness/</guid><description>&lt;p&gt;A model reads text and writes text. It cannot run code, read files, or remember past calls. The harness adds those abilities. It does five jobs. It sends the prompt. It reads the reply. It runs the tools the model asks for. It returns the tool results. It decides when the run stops.&lt;/p&gt;
&lt;figure class="seq"&gt;
&lt;script type="application/json"&gt;
{
"title": "One harness run: the five jobs, in order.",
"lifelines": [
{"id": "you", "label": "Engineer", "tone": "external"},
{"id": "harness", "label": "Harness", "tone": "platform"},
{"id": "model", "label": "Model", "tone": "subscriber"},
{"id": "tool", "label": "countErrors tool", "tone": "platform"}
],
"messages": [
{"from": "you", "to": "harness", "label": "Is checkout slow?"},
{"from": "harness", "to": "model", "label": "Job 1: send the prompt and the tool list"},
{"from": "model", "to": "harness", "label": "tool call: countErrors(checkout)", "kind": "response"},
{"from": "harness", "to": "harness", "label": "Job 2: read the reply"},
{"from": "harness", "to": "tool", "label": "Job 3: run the tool"},
{"from": "tool", "to": "harness", "label": "412 errors", "kind": "response"},
{"from": "harness", "to": "model", "label": "Job 4: return the tool result"},
{"from": "model", "to": "harness", "label": "answer, based on the real count", "kind": "response"},
{"from": "harness", "to": "harness", "label": "Job 5: no more tool calls, so stop"},
{"from": "harness", "to": "you", "label": "answer", "kind": "response"}
]
}
&lt;/script&gt;
&lt;figcaption&gt;Figure 1.1. One harness run, with each of the five jobs labelled. Use Previous and Next to step through it. The count of 412 is the fake data from Chapter 4.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Example.&lt;/strong&gt; Asked alone, a model can only guess whether checkout is slow. With a harness, the model calls a &lt;code&gt;countErrors&lt;/code&gt; tool, reads the real count, and answers from that data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Objectives:&lt;/strong&gt; describe a model call, name the five harness jobs, and explain what the course builds.&lt;/p&gt;</description></item><item><title>Chapter 2: Project setup</title><link>https://www.garageeducation.org/docs/agent-harness-spring-ai/01-foundations/02-project-setup/</link><pubDate>Sat, 10 Oct 2026 00:00:00 +0000</pubDate><guid>https://www.garageeducation.org/docs/agent-harness-spring-ai/01-foundations/02-project-setup/</guid><description>&lt;p&gt;Create a Spring Boot 4.1.1 project with Java 17 or later. Add the Spring AI BOM 2.0.1, the Session BOM 0.6.0, the Temporal starter, and the OpenAI starter for LM Studio.&lt;/p&gt;
&lt;figure class="arch"&gt;
&lt;script type="application/json"&gt;
{
"title": "The project and what it talks to.",
"nodes": [
{"id": "app", "type": "boundary", "x": 0, "y": 0, "w": 420, "h": 250, "label": "Spring Boot 4.1.1 app · Java 17+"},
{"id": "aibom", "x": 20, "y": 40, "w": 180, "label": "Spring AI BOM", "detail": "2.0.1", "tone": "muted"},
{"id": "sbom", "x": 220, "y": 40, "w": 180, "label": "Session BOM", "detail": "0.6.0", "tone": "muted"},
{"id": "temporal", "x": 20, "y": 150, "w": 180, "label": "Temporal starter", "detail": "workflows and workers", "tone": "platform"},
{"id": "openai", "x": 220, "y": 150, "w": 180, "label": "OpenAI starter", "detail": "ChatClient, embeddings", "tone": "platform"},
{"id": "lm", "type": "boundary", "x": 490, "y": 0, "w": 260, "h": 250, "label": "LM Studio · localhost:1234"},
{"id": "gemma", "x": 530, "y": 50, "w": 180, "label": "Gemma", "detail": "chat.options.model", "tone": "ai"},
{"id": "bge", "x": 530, "y": 150, "w": 180, "label": "BGE-M3", "detail": "embedding.options.model", "tone": "ai"}
],
"edges": [
{"from": "openai", "to": "gemma", "label": "chat", "fromSide": "right", "toSide": "left", "animated": true},
{"from": "openai", "to": "bge", "label": "embed", "fromSide": "right", "toSide": "left"}
]
}
&lt;/script&gt;
&lt;figcaption&gt;Figure 2.1. The project and the local model server. The OpenAI starter reaches LM Studio through the base URL below. The figure leaves out PostgreSQL and the Temporal dev server, which later chapters connect.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-properties" data-lang="properties"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;spring.ai.openai.base-url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;http://localhost:1234&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;spring.ai.openai.api-key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;lm-studio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;spring.ai.openai.chat.options.model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;YOUR-GEMMA-IDENTIFIER&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;spring.ai.openai.embedding.options.model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;YOUR-BGE-M3-IDENTIFIER&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Before the course, send one request with a tool definition to the Gemma model. Confirm the response contains a tool call.&lt;/p&gt;
&lt;figure class="flow"&gt;
&lt;script type="application/json"&gt;
{
"title": "The pre-flight check.",
"steps": [
{"label": "Send one request with a tool definition to Gemma"},
{"label": "Does the response contain a tool call?", "no": "Do not start the course yet"},
{"label": "Start Chapter 3", "tone": "platform"}
]
}
&lt;/script&gt;
&lt;figcaption&gt;Figure 2.2. The pre-flight check. Every chapter from Chapter 4 on depends on the model returning tool calls.&lt;/figcaption&gt;
&lt;/figure&gt;</description></item><item><title>Chapter 3: The model call</title><link>https://www.garageeducation.org/docs/agent-harness-spring-ai/01-foundations/03-the-model-call/</link><pubDate>Sat, 10 Oct 2026 00:00:00 +0000</pubDate><guid>https://www.garageeducation.org/docs/agent-harness-spring-ai/01-foundations/03-the-model-call/</guid><description>&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Assistant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ChatClient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Assistant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChatClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;You are a careful assistant. Answer in two sentences or fewer.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;ChatClient.Builder&lt;/code&gt; is created by Spring Boot when a model starter is on the classpath. The model replies in text. The client hides the request format.&lt;/p&gt;
&lt;figure class="seq"&gt;
&lt;script type="application/json"&gt;
{
"title": "Assistant.ask: one model call.",
"lifelines": [
{"id": "code", "label": "Assistant.ask", "tone": "platform"},
{"id": "client", "label": "ChatClient", "tone": "platform"},
{"id": "model", "label": "Gemma", "tone": "subscriber"}
],
"messages": [
{"from": "code", "to": "client", "label": "prompt().system(…).user(question)"},
{"from": "client", "to": "model", "label": ".call(): request in the provider format"},
{"from": "model", "to": "client", "label": "reply text", "kind": "response"},
{"from": "client", "to": "code", "label": ".content(): a String", "kind": "response"}
]
}
&lt;/script&gt;
&lt;figcaption&gt;Figure 3.1. One model call. Your code never builds the HTTP request; the client does. No tools are attached yet, so the model can only answer from its own text.&lt;/figcaption&gt;
&lt;/figure&gt;</description></item><item><title>Chapter 4: Tools</title><link>https://www.garageeducation.org/docs/agent-harness-spring-ai/01-foundations/04-tools/</link><pubDate>Sat, 10 Oct 2026 00:00:00 +0000</pubDate><guid>https://www.garageeducation.org/docs/agent-harness-spring-ai/01-foundations/04-tools/</guid><description>&lt;p&gt;A tool is a Java method. The model chooses tools using only their names and descriptions. A vague description causes wrong choices.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LogTools&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Count error log events for one service in the last N minutes. Use this to check for a current error spike.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;countErrors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@ToolParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Service name, for example checkout&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@ToolParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Look-back window in minutes, from 1 to 1440&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;checkout&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;412&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// fake data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;figure class="sketch"&gt;
&lt;svg viewBox="0 0 880 300" role="img" aria-label="What the model sees of a tool, and what it never sees"&gt;
&lt;style&gt;.sk-code{fill:#23394d;font:12px "IBM Plex Mono",ui-monospace,monospace}.sk-box.seen{stroke:#087f79}.sk-box.unseen{stroke:#9cacb8;stroke-dasharray:5 4}&lt;/style&gt;
&lt;rect class="sk-box seen" x="10" y="10" width="520" height="280" rx="10"/&gt;
&lt;text class="sk-label" x="30" y="42"&gt;What the model sees&lt;/text&gt;
&lt;text class="sk-sub" x="30" y="78"&gt;name&lt;/text&gt;
&lt;text class="sk-code" x="150" y="78"&gt;countErrors&lt;/text&gt;
&lt;text class="sk-sub" x="30" y="112"&gt;description&lt;/text&gt;
&lt;text class="sk-code" x="150" y="112"&gt;Count error log events for one service&lt;/text&gt;
&lt;text class="sk-code" x="150" y="132"&gt;in the last N minutes. Use this to check&lt;/text&gt;
&lt;text class="sk-code" x="150" y="152"&gt;for a current error spike.&lt;/text&gt;
&lt;text class="sk-sub" x="30" y="188"&gt;service&lt;/text&gt;
&lt;text class="sk-code" x="150" y="188"&gt;Service name, for example checkout&lt;/text&gt;
&lt;text class="sk-sub" x="30" y="222"&gt;minutes&lt;/text&gt;
&lt;text class="sk-code" x="150" y="222"&gt;Look-back window in minutes, from 1 to 1440&lt;/text&gt;
&lt;text class="sk-sub" x="30" y="268"&gt;This is all it has to choose with.&lt;/text&gt;
&lt;rect class="sk-box unseen" x="560" y="10" width="310" height="280" rx="10"/&gt;
&lt;text class="sk-label" x="580" y="42"&gt;What it never sees&lt;/text&gt;
&lt;text class="sk-sub" x="580" y="78"&gt;the method body&lt;/text&gt;
&lt;text class="sk-code" x="580" y="112"&gt;return "checkout".equals(service)&lt;/text&gt;
&lt;text class="sk-code" x="580" y="132"&gt; ? 412 : 3; // fake data&lt;/text&gt;
&lt;text class="sk-sub" x="580" y="188"&gt;the class name&lt;/text&gt;
&lt;text class="sk-code" x="580" y="222"&gt;LogTools&lt;/text&gt;
&lt;/svg&gt;
&lt;figcaption&gt;Figure 4.1. A tool, as the model sees it. A vague description on the left means a wrong choice, however good the code on the right is.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Attach the tool with &lt;code&gt;.tools(logTools)&lt;/code&gt; on the prompt. Exercise: rename the tool, then remove its description. Compare the model&amp;rsquo;s choices each time.&lt;/p&gt;</description></item></channel></rss>