criogenai

IBM agent types

Learning agent

A critic scores its actions; it gets better with experience.

A learning agent improves from feedback. The performance element acts; a critic judges the outcome; the learning element updates what the agent believes works; a problem generator makes it try something new now and then, so it does not settle too early.

Here a support bot learns which reply style customers rate best over 40 conversations, without being told. Raise exploration to try other styles more often.

Use it when
Feedback arrives over time (ratings, outcomes, tests)
The best action is not known in advance
Conditions drift and the agent should keep up
Skip it when
Mistakes are expensive while it learns
There is no reliable feedback signal

Run it

No model needed · CriogenAI engine in your browser
Ready
replyoutcomerewardbetter estimatesAct (choose style)CustomerCritic (rating)Learn (update)Try new
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: Memory (stores what was learned) + a hook that scores runs
import random

from criogenai import Storage

storage = Storage("sqlite://learning.db")  # what the agent has learned survives restarts
styles = ["short", "detailed", "friendly + steps"]

async def known(style: str) -> Dict[str, Any]:
    item = await storage.recall("styles", style)
    return item["value"] if item else {"n": 0, "mean": 0.0}

async def reply(question: str, rating_of: Callable[[str], float]) -> None:
    scores = {s: await known(s) for s in styles}
    explore = random.random() < 0.2  # the problem generator: sometimes try something new
    style = random.choice(styles) if explore else max(styles, key=lambda s: scores[s]["mean"])
    reward = rating_of(style)  # the critic: a customer rating, a test, a metric
    s = scores[style]
    s["n"] += 1
    s["mean"] += (reward - s["mean"]) / s["n"]  # the learning element
    await storage.remember("styles", style, s)
const storage = new Storage("sqlite://learning.db"); // what the agent has learned survives restarts
const styles = ["short", "detailed", "friendly + steps"];
type Score = { n: number; mean: number };

const known = async (style: string): Promise<Score> =>
  ((await storage.recall("styles", style))?.value as Score | undefined) ?? { n: 0, mean: 0 };

async function reply(question: string, ratingOf: (style: string) => number) {
  const scores = Object.fromEntries(await Promise.all(styles.map(async (s) => [s, await known(s)] as const)));
  const explore = Math.random() < settings.explore / 100; // the problem generator: sometimes try something new
  const style = explore ? styles[Math.floor(Math.random() * styles.length)] : styles.reduce((a, b) => (scores[b].mean > scores[a].mean ? b : a));
  const reward = ratingOf(style); // the critic: a customer rating, a test, a metric
  const s = scores[style];
  s.n += 1;
  s.mean += (reward - s.mean) / s.n; // the learning element
  await storage.remember("styles", style, s);
}