Skip to content

Agent with Memory

%%{init: {'look': 'handDrawn', 'theme': 'base', 'themeVariables': {'primaryColor': '#eef2ff', 'primaryBorderColor': '#1e40af', 'primaryTextColor': '#1e293b', 'lineColor': '#1e3a8a', 'edgeLabelBackground': '#ffffff', 'clusterBkg': '#fbfcff', 'clusterBorder': '#2563eb', 'fontFamily': '-apple-system, system-ui, Segoe UI, Roboto, Helvetica, Arial, sans-serif', 'fontSize': '15px'}, 'flowchart': {'nodeSpacing': 50, 'rankSpacing': 58, 'padding': 14, 'htmlLabels': true, 'curve': 'basis'}}}%%
flowchart LR
  Q(["Question"]) --> A("Agent")
  A --> M("Recall what's relevant")
  M --> A
  A --> O(["Personalised answer"])

Outcome: the agent remembers facts across sessions and pulls only the ones relevant to the current question, instead of replaying an ever-growing transcript.

How it works

  • SemanticMemory stores facts and retrieves by similarity. max_results caps how many come back.
  • Recall is a tool the agent calls, so retrieval shows up in the execution like any other step.
  • Only relevant facts enter the prompt. Cost stays flat as memory grows.
  • The store is swappable. Point it at your own backend without changing the agent.

Prerequisites

A Conductor server with an LLM provider, and CONDUCTOR_SERVER_URL set.

The agent

Save this as agent_memory.py:

"""Agent with memory — recall facts across sessions by similarity.

Derived from sdk/python-sdk/examples/agents/25_semantic_memory.py.

SemanticMemory stores facts and returns the most relevant ones for a query, so
the agent is primed with what it needs instead of the whole history. Swap the
store for your own backend; the agent contract does not change.
"""

from conductor.ai.agents import Agent, AgentRuntime, tool
from conductor.ai.agents.semantic_memory import SemanticMemory

MODEL = "openai/gpt-4o-mini"

memory = SemanticMemory(max_results=3)
memory.add("The customer's name is Alice and she prefers email.")
memory.add("Alice has been on the Enterprise plan since March 2021.")
memory.add("Alice reported a billing discrepancy on invoice #1042.")
memory.add("Alice's preferred language is English.")
memory.add("Enterprise customers get priority support with a 1-hour SLA.")
memory.add("Alice's timezone is US/Pacific.")


@tool
def recall(query: str) -> str:
    """Recall relevant context about the customer."""
    return memory.get_context(query)


agent = Agent(
    name="memory_support_agent",
    model=MODEL,
    tools=[recall],
    instructions=(
        "You are a support agent with a memory. Call recall before answering, "
        "then personalise the reply with what you find."
    ),
)


if __name__ == "__main__":
    with AgentRuntime() as runtime:
        result = runtime.run(agent, "I have a question about my last invoice.")
        result.print_result()
        print("execution id:", result.execution_id)

Run it

python agent_memory.py

Asking about an invoice recalls the Enterprise plan, the open discrepancy on #1042, and the 1-hour SLA — not the timezone or language facts, which aren't relevant. Open Executions to see the recall call and exactly which facts it returned.

The same example in other SDKs

The agent API is the same shape in every SDK. These are the upstream sources this recipe was derived from — Java has the SemanticMemory type but no numbered example yet, so that row links the class:

SDK Example
Python 25_semantic_memory.py
Java SemanticMemory.java
TypeScript 25-semantic-memory.ts
C# Program.cs

Production notes

  • Memory is an injection surface. Anything stored gets read back into a prompt — validate before writing.
  • Decide what's worth remembering. Storing whole transcripts makes retrieval worse, not better.
  • Give facts a source and a timestamp so you can expire or correct them later.
  • Scope memory per customer or tenant. A shared store leaks context between users.
  • max_results is a cost control. Raising it grows every prompt.