#Overview
Customer support agents face a fundamental problem: every new conversation starts from zero. The agent has no knowledge of the customer's account history, past issues, preferences, or the solutions that have already been tried. This forces customers to repeat themselves and forces agents to rediscover context that should already be known.
This example builds a support agent that retains customer context across sessions using the Memory Plugin. The agent decides what is worth remembering, recalls relevant context automatically before each conversation, and builds institutional knowledge that compounds over time — without the developer managing any of it explicitly.
What you will build:
- A support agent that autonomously stores customer profiles and interaction outcomes
- Automatic context injection so the agent arrives at each conversation already informed
- A shared knowledge base seeded from a support runbook, with the agent assigning importance
- A multi-agent support pool where every agent shares the same memory workspace
#Prerequisites
pip install daita-agents openaiexport OPENAI_API_KEY=sk-...
export DAITA_API_KEY=... # Required for cloud deployment#Basic Setup
The simplest possible configuration: a support agent with persistent memory. The agent decides what to store and when to recall it — you just give it the plugin and a prompt that sets the intent.
import asyncio
from daita import Agent
from daita.plugins import MemoryPlugin
async def main():
memory = MemoryPlugin()
agent = Agent(
name="Support Agent",
model="gpt-4o-mini",
prompt="""You are a customer support agent for Acme SaaS.
At the start of every conversation, you already have relevant memory
injected into your context — use it. If you see prior history for this
customer, apply it immediately without asking them to repeat themselves.
When you resolve an issue or learn something worth keeping, store it with
an appropriate importance score so future sessions benefit.""",
tools=[memory]
)
await agent.start()
# First conversation — agent starts cold but stores what it learns
response = await agent.run("""
Customer: Jane Smith (jane@example.com), Pro tier
Issue: API rate limiting errors on the /events endpoint
Resolution: Increased her rate limit to 10,000 req/min, documented in ticket #4821
Preference: Prefers async Slack updates over email
""")
print(response)
await agent.stop() # Curation runs automatically on stop
asyncio.run(main())On the next run, before the agent processes its first message, the Memory Plugin automatically injects relevant context into the system prompt:
## Relevant Memory
- [customer] Jane Smith (jane@example.com), Pro tier (importance: 0.8)
- [resolution] API rate limiting resolved: increased to 10,000 req/min, ticket #4821 (importance: 0.7)
- [preference] Jane prefers Slack updates over email (importance: 0.6)The agent arrives already informed — no explicit recall call needed.
#Multi-Agent Support Team
In a real support team, multiple agents handle tickets for the same customers. A shared workspace lets any agent in the pool access the full customer history — when one agent resolves an issue and stores the solution, the next agent handling the same customer finds it immediately.
import asyncio
from daita import Agent
from daita.plugins import MemoryPlugin
SUPPORT_PROMPT = """You are a customer support specialist for Acme SaaS.
Before responding, you will have relevant customer and issue history injected
into your context automatically. Use it. Do not ask customers to repeat
information you already have.
When you resolve an issue or discover something worth preserving, store it.
Check if a similar issue has been solved before investigating from scratch —
the answer may already be in memory."""
async def handle_ticket(ticket_id: str, customer: str, issue: str):
# Each agent gets its own plugin instance pointing at the shared workspace
memory = MemoryPlugin(
workspace="support_team",
auto_curate="on_stop"
)
agent = Agent(
name=f"Support-{ticket_id}",
model="gpt-4o-mini",
prompt=SUPPORT_PROMPT,
tools=[memory]
)
await agent.start()
response = await agent.run(f"""
Ticket: {ticket_id}
Customer: {customer}
Issue: {issue}
""")
print(f"[Ticket {ticket_id}] {response}")
await agent.stop()
async def main():
tickets = [
("T-001", "jane@example.com", "Dashboard not loading after login"),
("T-002", "bob@example.com", "Webhook signatures failing validation"),
]
for ticket_id, customer, issue in tickets:
await handle_ticket(ticket_id, customer, issue)
asyncio.run(main())Each agent gets its own MemoryPlugin instance pointing at the same workspace="support_team", so they share the same store without resource contention. When T-001 resolves Jane's issue and stores the fix, T-002 finds it automatically if the same problem comes up.
#Seeding a Knowledge Base from a Runbook
Support teams accumulate institutional knowledge: known bugs, proven workarounds, configuration edge cases. Rather than manually structuring this into a database, give the agent your support runbook and let it decide what to extract, what importance to assign, and how to categorize it.
import asyncio
from daita import Agent
from daita.plugins import MemoryPlugin
SUPPORT_RUNBOOK = """
# Acme SaaS Support Runbook
## Rate Limiting (Error 429)
Customers hitting 429 on /events are over their rate limit. Default Pro tier
limit is 5,000 req/min. Fix: admin panel → Account → Rate Limits → increase.
Enterprise customers can request custom limits. Common trigger: customers
increasing export frequency without adjusting limits first.
## Webhook Signature Failures
Webhook HMAC signatures include a timestamp. If the customer's server clock
is off by more than 5 minutes the signature will fail validation even with
the correct secret. Fix: sync the customer's server clock via NTP. This is
a frequent source of "my webhooks stopped working" tickets.
## Dashboard Blank Screen After Login
Usually a stale JWT left over from a password reset. The old token is cached
but now invalid. Fix: clear browser cookies and cache, log in fresh. If it
recurs, check if the customer has browser extensions that cache auth state.
## EU Data Residency
Enterprise customers on the EU data residency plan use a separate API base
URL: api.eu.acme.io. SDKs before v2.3 do not support this automatically —
customers need to configure the base URL manually. Affects all SDK methods
that make direct API calls.
## API Key Rotation
After rotating an API key, all active SDK instances must be restarted or
re-initialized. The SDK caches the key at startup. Customers often miss
background workers or cron jobs that still hold the old key.
"""
async def seed_knowledge_base():
memory = MemoryPlugin(
workspace="support_knowledge",
scope="global",
auto_curate="manual"
)
agent = Agent(
name="Knowledge-Seeder",
model="gpt-4o-mini",
prompt="""You are building a support knowledge base from a runbook.
Read the runbook carefully and store each distinct piece of knowledge
as a separate memory. Assign importance scores based on how critical
each item is for resolving customer issues (0.9 for frequent/critical
issues, 0.8 for important but less common, 0.7 for useful context).
Use clear categories like 'known_issue', 'account_configuration',
and 'troubleshooting_step'.""",
tools=[memory]
)
await agent.start()
await agent.run(f"""
Here is our support runbook. Extract and store every distinct piece of
knowledge — known issues, solutions, configuration details, and common
causes. Assign importance and categories based on how useful each fact
will be for resolving future tickets.
{SUPPORT_RUNBOOK}
""")
# Curate after seeding to consolidate into long-term memory
result = await memory.curate()
print(f"Knowledge base seeded: {result.facts_added} facts stored, cost ${result.cost_usd:.4f}")
await agent.stop()
async def run_support_agent():
memory = MemoryPlugin(
workspace="support_knowledge",
scope="global"
)
agent = Agent(
name="Support-Agent",
model="gpt-4o-mini",
prompt="""You are a customer support specialist. You have a knowledge
base of known issues and proven solutions in memory.
Before investigating any issue, search your memory. If a known solution
exists, apply it directly. If you discover something new, store it for
future agents.""",
tools=[memory]
)
await agent.start()
response = await agent.run("""
Customer reports: API calls to /events are returning 429 Too Many Requests.
Customer is on Pro tier and started seeing this after increasing their
data export frequency this morning.
""")
print(response)
await agent.stop()
async def main():
await seed_knowledge_base()
await run_support_agent()
asyncio.run(main())The agent reads the runbook, decides which facts are worth storing, assigns appropriate importance scores, and categorizes them — without the developer specifying any of it. The support agent that runs afterward finds the relevant solution automatically before it starts investigating.
#Deploying to Production
The Memory Plugin switches backends automatically based on environment. The same agent code that runs locally will run in production against the managed cloud backend after daita push — no code changes required.
daita push productionIn production, memory is stored in a managed vector database with:
- O(log N) recall performance as the knowledge base grows
- Concurrent-write safety for multi-agent support pools
- Persistence across serverless invocations
The workspace and scope configuration carries over unchanged.
#Complete Example
A full support pipeline: seed the knowledge base from a runbook, then run a pool of agents handling tickets against the shared memory.
import asyncio
from daita import Agent
from daita.plugins import MemoryPlugin
SUPPORT_PROMPT = """You are a senior customer support specialist for Acme SaaS.
You have two memory sources available:
- Injected context: customer history and relevant facts loaded automatically before this conversation
- Searchable memory: the full knowledge base, searchable via recall
At the start of every ticket:
1. Review the injected context for this customer's history
2. Search memory for known solutions to the reported issue
During the ticket:
3. Resolve the issue using what you know — don't start from scratch if the answer exists
4. If you discover a novel solution or learn something important, store it
The goal: every ticket makes the next agent smarter."""
async def handle_ticket(ticket: dict):
memory = MemoryPlugin(
workspace="support_team",
auto_curate="on_stop"
)
agent = Agent(
name="Support-Agent",
model="gpt-4o-mini",
prompt=SUPPORT_PROMPT,
tools=[memory]
)
await agent.start()
response = await agent.run(
f"Ticket #{ticket['id']} from {ticket['customer']}: {ticket['issue']}"
)
print(f"\n[Ticket {ticket['id']}]\n{response}\n")
await agent.stop()
async def main():
tickets = [
{
"id": "T-891",
"customer": "alice@startup.io (Pro tier)",
"issue": "Getting 401 Unauthorized on all API calls after rotating our API key yesterday"
},
{
"id": "T-892",
"customer": "carlos@enterprise.com (Enterprise EU tier)",
"issue": "SDK throws 'invalid host' errors after upgrading to v2.2"
}
]
for ticket in tickets:
await handle_ticket(ticket)
asyncio.run(main())