Lesson 4: Module 04: State and Memory
此内容尚不支持你的语言。
Give your machines the ability to remember, within a run and across runs.
Learning Objectives
Section titled “Learning Objectives”- Pass data between steps with step outputs (
steps.<name>.<field>) - Keep durable, structured state in a
storesblock that survives across runs - Use
rememberandrecallsteps for persistent knowledge retrieval (RAG, Retrieval-Augmented Generation, which means feeding real documents to the AI so it answers based on facts, not guesses) - Know when to use step outputs vs stores vs memory
Complexity Ladder: Applies to all levels; stores and memory enhance machines at any complexity.
The Concept: Giving Machines Memory
Section titled “The Concept: Giving Machines Memory”Think of step outputs as a whiteboard the machine uses during a single run — each step writes its result and later steps read it. A store is a filing cabinet with labeled drawers — structured records that survive after the run ends. Memory is a research library — knowledge you search by meaning and retrieve in future sessions.
So far, our machines have been stateless — data flows from inputs through steps to outputs, then disappears. That works for single-shot tasks, but agents often need to:
- Track progress within a run (step outputs)
- Keep durable records across separate runs (stores)
- Ground responses in retrieved knowledge (memory / RAG)
Step Outputs Stores Memory (within a run) (across runs) (across runs)┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐│ steps.a.field │ │ save / query │ │ remember / recall││ │ │ │ │ ││ Flows A -> B │ │ Structured rows │ │ Search by meaning││ One direction │ │ with types and │ │ or by key ││ Simplest option │ │ access rules │ │ ││ │ │ │ │ Use for: knowledge││ Use for: passing │ │ Use for: counters│ │ base, cache, ││ data between │ │ history, records │ │ user preferences ││ adjacent steps │ │ │ │ │└──────────────────┘ └──────────────────┘ └──────────────────┘There is no separate state block in mashinTalk. Within a run, steps read each other’s outputs. Across runs, durable data lives in a store (structured) or in memory (semantic, structured, or episodic). This keeps every piece of persistent state governed and auditable like everything else.
Start With Koda
Section titled “Start With Koda”Koda requires a free account. Sign in or create an account to use Koda exercises throughout this course. If you’re not signed in yet, read on; the exercises will be here when you’re ready.
Before diving into the syntax, try building a machine with memory using Koda:
“Build a conversation machine that recalls the previous message from memory, responds to the new message, and remembers the exchange for next time.”
Check that Koda uses recall and remember steps with a collection. Study the structure; the rest of this module explains each piece in detail.
Within a Run: Step Outputs
Section titled “Within a Run: Step Outputs”Every step’s result is available to later steps by name. This is the simplest and most common way data moves:
compute plan {targets: ["a", "b"]}
compute act {count: steps.plan.targets.length}If data only needs to flow from one step to the next, this is all you need.
Across Runs: Stores
Section titled “Across Runs: Stores”A store is a typed, governed database the machine owns. Define it in a stores section, write with save, read with query:
stores store visits source: managed resource visit id as uuid, primary_key message as text, is required timestampsStore access follows the machine’s permission rules, and every read and write is recorded in the behavioral ledger like any other action.
Building It: Conversation Tracker
Section titled “Building It: Conversation Tracker”A machine that recalls the previous exchange from memory, responds, and remembers the new exchange for next time:
machine conversation_tracker "Conversation Tracker"
accepts message as string, is required session_id as string, is required
responds with response as string
behaves // Retrieve the previous exchange for this session recall previous collection: "conversations" namespace: input.session_id query: input.message limit: 1
// LLM step, generates a response using the recalled context ask respond, using: "anthropic:claude-haiku-4" with task "The user said: ${input.message}\nTheir previous message was: ${steps.previous.results}\n\nAcknowledge their message." returns response as string, is required
// Persist this exchange for the next run remember save_turn collection: "conversations" namespace: input.session_id content: input.message
verifies test "responds using the recalled exchange" assuming previous {results: ["Hi there"]} assuming respond {response: "Welcome back!"} assuming save_turn {ok: true} given {message: "Can you help?", session_id: "sess_1"} expect {response: "Welcome back!"}Memory: Persistent Knowledge
Section titled “Memory: Persistent Knowledge”remember and recall steps store and retrieve knowledge that persists across sessions and machines. There are three memory types:
| Memory Type | Purpose | Example |
|---|---|---|
| Semantic (search by meaning, finds similar content even with different wording) | Find content by meaning | “What do we know about shipping?” |
| Structured (key-value lookup, exact match by a known key) | Key-value lookup | Cache, user preferences |
| Episodic (event timeline, a chronological log of what happened) | Event timeline | Interaction logs, activity history |
Semantic Memory (RAG)
Section titled “Semantic Memory (RAG)”The most powerful memory pattern: store documents, retrieve by semantic similarity (matching meaning rather than exact words), and ground LLM responses in real data.
machine knowledge_qa "Knowledge QA"
accepts question as string, is required
responds with answer as string citations as list grounded as boolean
behaves // Step 1: Retrieve relevant context from the knowledge base recall retrieve collection: "knowledge_base" query: input.question limit: 5
// Step 2: Generate grounded answer using retrieved context ask answer, using: "anthropic:claude-sonnet-4" with role "You answer questions based ONLY on the provided context. If the context doesn't contain the answer, say 'I don't have that information.' Always cite sources. NEVER make up information not in the context." with task "Context:\n${steps.retrieve.results}\n\nQuestion: ${input.question}" returns answer as string, is required citations as list grounded as boolean
verifies test "grounds the answer in retrieved context" assuming retrieve {results: ["Returns are accepted within 30 days."]} assuming answer {answer: "Returns are accepted within 30 days.", citations: ["policy.md"], grounded: true} given {question: "What is the return window?"} expect {answer: "Returns are accepted within 30 days.", grounded: true}This is the RAG pattern. It reduces hallucinations by grounding the LLM’s response in retrieved documents rather than relying on training data alone.
Storing to Memory
Section titled “Storing to Memory”remember store_fact collection: "knowledge_base" content: input.document metadata: {source: input.source}Structured Memory (Key-Value)
Section titled “Structured Memory (Key-Value)”For caching and preferences, exact lookups by key, not similarity search:
// Write a value to structured memoryremember cache_result key: "user_prefs:${input.user_id}" value: {theme: "dark", language: "en"}
// Read a value from structured memoryrecall get_prefs key: "user_prefs:${input.user_id}"When to Use What
Section titled “When to Use What”| Need | Use | Why |
|---|---|---|
| Pass data between steps | Step outputs | steps.name.field, simplest option |
| Track a durable counter or record | Store (save/query) |
Typed rows, access rules, survives runs |
| Cache an API response | remember (structured) |
Persist across runs, TTL support |
| Search knowledge base | remember (semantic) |
Similarity search, RAG grounding |
| Log user interactions | remember (episodic) |
Timeline, audit trail |
Rule of thumb: If data only needs to flow from one step to the next, use step outputs. If data needs to survive between runs as structured records, use a store. If you need to find things by meaning or by key later, use memory.
Key Syntax
Section titled “Key Syntax”// A store (durable structured state)stores store visits source: managed resource visit id as uuid, primary_key message as text, is required timestamps
// Memory storeremember name collection: "name" content: input.document
// Memory retrieverecall name collection: "name" query: input.question limit: 5Common Mistakes
Section titled “Common Mistakes”-
Reaching for persistence when step outputs suffice. If data just flows from Step A to Step B, use
steps.a.fieldin Step B. Don’t store it just to read it back in the same run. -
Expecting a
stateblock. There isn’t one. Older examples on the web sometimes showstateunderbehaves; the compiler rejects it and points you to stores. Durable state is a store; in-run state is step outputs. -
Storing everything in semantic memory. Semantic search (search by meaning) is powerful but not free. Use structured memory (key-value lookup) for exact lookups (user preferences, cache) and semantic memory only when you need similarity search.
What’s Next
Section titled “What’s Next”In Module 05, you’ll learn how to control execution flow: chaining steps, branching conditionally, and building loops.