Reference Agent Agents

Case-Based Plan Reuse for AI Agents

A reusable case-based reasoning pattern for agents: treat past PlanTraces as searchable cases, rank them by similarity and quality, adapt the best ones, and record reuse lineage.

Problem Agents usually start each task from scratch even when previous runs contain useful plans, failures, and successful reasoning traces.
Outcome A reusable memory layer that selects high-quality prior cases, adapts them into a new plan, validates the result, and records parent-child reuse links.
Implementation evidence

The solution is backed by inspectable code

This solves agent plan reuse. Instead of treating memory as a transcript dump, store past reasoning episodes as cases that can be embedded, scored, adapted, validated, and retained.

Code

from dataclasses import dataclass
from math import exp


@dataclass
class PlanTrace:
    trace_id: str
    goal_text: str
    plan: list[str]
    avg_score: float
    created_at_seconds: float
    reuse_count: int = 0
    attempt_count: int = 0


class ScorableRanker:
    def __init__(self, embedding_store, weights=None):
        self.embedding_store = embedding_store
        self.weights = weights or {
            "similarity": 0.4,
            "reward": 0.3,
            "recency": 0.2,
            "adaptability": 0.1,
        }

    def rank(self, goal_text, traces, now_seconds):
        goal_emb = self.embedding_store.get_or_create(goal_text)
        ranked = []
        for trace in traces:
            trace_emb = self.embedding_store.get_or_create(trace.goal_text + "\n" + "\n".join(trace.plan))
            components = {
                "similarity": self.embedding_store.cosine(goal_emb, trace_emb),
                "reward": trace.avg_score,
                "recency": exp(-(now_seconds - trace.created_at_seconds) / (30 * 24 * 60 * 60)),
                "adaptability": trace.reuse_count / max(trace.attempt_count, 1),
            }
            score = sum(components[k] * self.weights[k] for k in self.weights)
            ranked.append((score, components, trace))
        return sorted(ranked, key=lambda item: item[0], reverse=True)
class PlannerReuseAgent:
    def __init__(self, memory, ranker, llm, top_k=3):
        self.memory = memory
        self.ranker = ranker
        self.llm = llm
        self.top_k = top_k

    async def run(self, context):
        goal_text = context["goal"]["goal_text"]
        all_traces = self.memory.plan_traces.get_all(limit=500)
        ranked = self.ranker.rank(goal_text, all_traces, context["now_seconds"])
        selected = [trace for _score, _parts, trace in ranked[: self.top_k]]

        prompt = self._adaptation_prompt(goal_text, selected)
        new_plan = self.llm.generate_plan(prompt)
        new_trace_id = self.memory.plan_traces.create(goal_text=goal_text, plan=new_plan)

        for parent in selected:
            self.memory.plan_traces.add_reuse_link(
                parent_trace_id=parent.trace_id,
                child_trace_id=new_trace_id,
            )

        context["plan_trace_id"] = new_trace_id
        context["plan"] = new_plan
        context["reused_trace_ids"] = [trace.trace_id for trace in selected]
        return context

    def _adaptation_prompt(self, goal_text, traces):
        cases = "\n\n".join(
            f"Case {i+1}: {trace.goal_text}\nScore: {trace.avg_score}\nPlan:\n"
            + "\n".join(f"- {step}" for step in trace.plan)
            for i, trace in enumerate(traces)
        )
        return f"Adapt the useful patterns from these prior cases to solve:\n{goal_text}\n\n{cases}"

Usage

agent = PlannerReuseAgent(memory=memory, ranker=ScorableRanker(memory.embedding), llm=llm)
context = await agent.run({
    "goal": {"goal_text": "Build a RAG evaluator for a new paper corpus"},
    "now_seconds": time.time(),
})

How it works

The reusable object is the case lifecycle: retrieve prior traces, rank them with similarity plus value signals, adapt the top cases into a new plan, validate challenger plans against champions, and retain only cases that remain useful.

Source

The implementation is part of Stephanie: planner_reuse.py.

Full explanation

For the complete CBR middleware, retention policy, champion promotion, and PlanTrace monitor design, read: Case Based Reasoning: Teaching AI to Learn From itself.

The publishing loop Research → book → capstone → solution → real use → new evidence
Browse all solutions →