criogenai

IBM agent types

Model-based reflex agent

Rules plus an internal picture of what it cannot see.

A model-based reflex agent still acts on rules, but it keeps an internal model of the world, updated from what it senses and what its own actions do. That lets it act sensibly when it can only see part of the world.

This robot vacuum only senses the room it is in. Its memory of which rooms are clean is what lets it stop; a simple reflex vacuum would never know it was done.

Use it when
The world is only partly observable
State changes slowly and predictably
Rules still describe what to do
Skip it when
Choices between competing goals (goal- or utility-based)

Run it

No model needed · CriogenAI engine in your browser
Ready
perceptstatewhat my action changedSensorWorld modelRulesAct
The run
  1. Press Run to watch the pattern work, step by step.

This run is the TypeScript code below, running on the CriogenAI engine in your browser (WebAssembly). Without a key, a scripted model stands in for MODEL; with your key, your provider answers, called from this tab. The tools return made-up data.

Build it with CriogenAI

Built from primitives: Workflow state (the internal model) + route
rooms = ["A", "B", "C", "D"]

def step(state: Dict[str, Any]) -> Any:
    # The internal model: rooms known to be clean, kept in the run state.
    known = set(state["known"])
    here = state["at"]
    if state["dirty"].get(here):
        return goto("step", {"dirty": {**state["dirty"], here: False}, "known": [*known, here]})
    known.add(here)
    if known == set(rooms):
        return goto("done", {"known": sorted(known)})
    nearest = next(r for r in rooms if r not in known)
    return goto("step", {"at": nearest, "known": sorted(known)})

wf = Workflow()
wf.add_node("step", step)
wf.add_node("done", lambda state: {"output": "all rooms clean"})
wf.start("step").goto("step", ["step", "done"]).edge("done", END)
world = {"at": "A", "known": [], "dirty": {"A": True, "B": False, "C": True, "D": True}}
print((await wf.compile().run(world, max_steps=40)).state["output"])
const rooms = ["A", "B", "C", "D"];
const app = new Workflow()
  .node("step", (state: State) => {
    // The internal model: rooms known to be clean, kept in the run state.
    const known = new Set<string>(state.known);
    const here: string = state.at;
    if (state.dirty[here]) return goto("step", { dirty: { ...state.dirty, [here]: false }, known: [...known, here] });
    known.add(here);
    if (rooms.every((r) => known.has(r))) return goto("done", { known: [...known] });
    return goto("step", { at: rooms.find((r) => !known.has(r)), known: [...known] });
  })
  .node("done", () => ({ output: "all rooms clean" }))
  .start("step")
  .goto("step", ["step", "done"])
  .edge("done", END)
  .compile();
const world = { at: "A", known: [], dirty: { A: true, B: false, C: true, D: true } };
const result = await app.run(world, { maxSteps: 40 });
console.log(result.state.output);