跳转到内容
Developer Preview — APIs and language features may change before 1.0

Lesson 4: Module 04: State and Memory

此内容尚不支持你的语言。

Give your machines the ability to remember, within a run and across runs.

  • Pass data between steps with step outputs (steps.<name>.<field>)
  • Keep durable, structured state in a stores block that survives across runs
  • Use remember and recall steps 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.

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.

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.

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.

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
timestamps

Store access follows the machine’s permission rules, and every read and write is recorded in the behavioral ledger like any other action.

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!"}

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

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.

remember store_fact
collection: "knowledge_base"
content: input.document
metadata: {source: input.source}

For caching and preferences, exact lookups by key, not similarity search:

// Write a value to structured memory
remember cache_result
key: "user_prefs:${input.user_id}"
value: {theme: "dark", language: "en"}
// Read a value from structured memory
recall get_prefs
key: "user_prefs:${input.user_id}"
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.

// A store (durable structured state)
stores
store visits
source: managed
resource visit
id as uuid, primary_key
message as text, is required
timestamps
// Memory store
remember name
collection: "name"
content: input.document
// Memory retrieve
recall name
collection: "name"
query: input.question
limit: 5
  1. Reaching for persistence when step outputs suffice. If data just flows from Step A to Step B, use steps.a.field in Step B. Don’t store it just to read it back in the same run.

  2. Expecting a state block. There isn’t one. Older examples on the web sometimes show state under behaves; the compiler rejects it and points you to stores. Durable state is a store; in-run state is step outputs.

  3. 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.

In Module 05, you’ll learn how to control execution flow: chaining steps, branching conditionally, and building loops.