Praktische Hinweise: Alles, was Sie zum Entwurf von agiler Erinnerung benötigen
Schritt-für-Schritt-Anleitung zu den Praktischen Notizen: Alles, was Sie für das Design agiler Speicherlösungen benötigen – Verträge, Überprüfungen sowie Code-Blöcke für Teams, die dieses Muster einsetzen.
Die folgenden Anmerkungen skizzieren einen praktischen Ansatz für das „All You Want For Agentic Memory Design“. Der Schwerpunkt liegt auf Verträgen, Überprüfungen und Code-Platzhaltern statt auf motivierenden Formulierungen. Während der Übersichtsphase sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikatoren sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gesammelt sein, den Betreiber ohne das Durchlesen des gesamten Systems überprüfen können.
Inhaltsverzeichnis
Die Inhaltsverzeichnisschicht funktioniert am besten, wenn sie als messbare Oberfläche betrachtet wird. Erfassen Sie einen erfolgreichen Ablauf, einen Fehlerfall sowie die Rollback-Anmerkung, bevor Sie den Umfang erweitern. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf und den Wiederherstellungsablauf. Wiederholversuche, menschliche Kontrollpunkte sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen. Halten Sie den Zustand der Graphen flach und typisiert – verschachtelte Datenblöcke verbergen, welcher Knoten welches Feld geschrieben hat, und führen zu Unterbrechungen beim Fortsetzen der Verarbeitung.
Der Agent vergaß ständig
Der Agent vergaß immer wieder, dass Schritt-für-Schritt-Verfahren am besten dann funktionieren, wenn sie als messbare Strukturen betrachtet werden. Erfassen Sie einen erfolgreichen Fall, einen Fehlerfall sowie die Notizen zur Rücksetzung, bevor Sie den Umfang erweitern. Ziehen Sie kleine, testbare Einheiten vor großen, komplexen Skripten. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren. Halten Sie den Zustand der Graphen einfach und typisiert – verschachtelte Strukturen verbergen, welcher Knoten welches Feld geschrieben hat, und führen zu Fehlern nach Unterbrechungen.
Warum Kontextfenster versagen (und die Studie, die es bewiesen hat)
Die Phase „Warum versagen die Context-Windows?“ funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie ein „goldenes Transkript“, einen Fehlerfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Halten Sie den Zustand des Graphen flach und typisiert. Verschachtelte Datenblöcke verbergen, welcher Knoten welches Feld geschrieben hat, und führen zu Unterbrechungen beim Fortsetzen der Verarbeitung. Die Phase „Warum versagen die Context-Windows?“ funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie ein „goldenes Transkript“, einen Fehlerfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern. Halten Sie die Konfiguration außerhalb des Anwendungscode. Umgebungsdateien, Geheimdatenspeicher sowie Feature-Flags sollten an einem Ort gespeichert werden, den Betreuer ohne Durchsicht des gesamten Graphen prüfen können.
Kurzfristige vs. Langfristige Erinnerung: Die grundlegende Trennung
Zur Phase Kurzfristiges vs. Langfristiges Gedächtnis sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Codeändern definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallweg. Wiederholungsversuche, menschliche Überprüfungen und die Handhabung von Fehlnachrichten gehören zum Produkt selbst, nicht zu späteren Optimierungen. Setzen Sie menschliche Freigabe für Schritte voraus, die Geld ausgeben oder Produktionsdaten ändern. Kompilierzeitbezogene Verbindungen bedeuten noch keine vollständige Geschäftsabwicklung.
Wie sich die Branche auf vier Arten des Gedächtnisses einigte
Zur Phase „Wie hat sich die Branche entwickelt“ sollten vor dem Ändern des Codes die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Bevorzugen Sie kleine, testbare Einheiten vor umfangreichen Skripten. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren. Setzen Sie menschliche Freigabe bei Schritten ein, die Geld ausgeben oder Produktionsdaten ändern. Kompilierzeitbezogene Verbindungen bedeuten noch nicht vollständige Geschäftsabläufe.
Entscheidungen bezüglich der Produktionsdatenbank: SQL gegen Vector gegen Graph
Für die SQL-Phase der Entscheidungsfindung in der Produktionsdatenbank sollten vor dem Ändern des Codes die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf verborgene Zustände schließen zu müssen. Betrachten Sie diese Phase als Vertrag zwischen den Eingaben und den validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Setzen Sie menschliche Freigabe bei Schritten ein, die Geld kosten oder Produktionsdaten ändern. Kompilierzeitliche Verbindungen entsprechen nicht der Geschäftsabschlussqualität. Für die SQL-Phase der Entscheidungsfindung in der Produktionsdatenbank sollten vor dem Ändern des Codes die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf verborgene Zustände schließen zu müssen. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gespeichert werden, den die Operator ohne Leserechte überprüfen können.
im gesamten Graphen.Schicht 1: Puffergedächtnis mit Zusammenfassung
Beim Arbeiten an der Schicht 1 – dem Puffergedächtnis – sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Wiederherstellungsprozess gemeinsam. Wiederholte Versuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen. Erstellen Sie Checkpoints nach aufwändigen Schritten. Das Wiederaufnehmen des Vorgangs sollte keine erneute Abrechnung für denselben LLM-Aufruf veranlassen, wenn ein Operator einen späteren Knoten erneut versucht.
from collections import deque
from typing import List, Dict
class BufferMemory:
def __init__(self, max_turns: int = 10):
# Each turn = one user message + one assistant message
self.history: deque = deque(maxlen=max_turns * 2)
def add_message(self, role: str, content: str):
self.history.append({"role": role, "content": content})
def get_context(self) -> List[Dict]:
return list(self.history)
def token_estimate(self) -> int:
total_chars = sum(len(m["content"]) for m in self.history)
return total_chars // 4 # rough approximation
def clear(self):
self.history.clear()
import os
from collections import deque
from typing import List, Dict
from openai import OpenAI
class SummarizingBufferMemory:
def __init__(self, max_turns: int = 8, summary_batch: int = 4):
self.client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.environ["OPENROUTER_API_KEY"],
)
self.model = "deepseek/deepseek-v4-flash-0731"
self.recent: deque = deque(maxlen=max_turns * 2)
self.rolling_summary: str = ""
self.summary_batch = summary_batch
def add_message(self, role: str, content: str):
if len(self.recent) == self.recent.maxlen:
self._compress_oldest()
self.recent.append({"role": role, "content": content})
def _compress_oldest(self):
batch = [self.recent.popleft() for _ in range(min(self.summary_batch * 2, len(self.recent)))]
text = "\n".join(f"{m['role']}: {m['content']}" for m in batch)
response = self.client.chat.completions.create(
model=self.model,
max_tokens=300,
messages=[
{
"role": "system",
"content": "You compress conversation history. Reply with the summary only.",
},
{
"role": "user",
"content": (
"Summarize this conversation segment in 2-4 sentences. "
"Preserve any decisions made, constraints stated, and conclusions reached.\n\n"
f"{text}"
),
},
],
)
new_summary = response.choices[0].message.content.strip()
if self.rolling_summary:
self.rolling_summary = f"{self.rolling_summary} | {new_summary}"
else:
self.rolling_summary = new_summary
def get_context(self) -> List[Dict]:
context = []
if self.rolling_summary:
context.append({
"role": "system",
"content": f"[Prior conversation summary: {self.rolling_summary}]",
})
context.extend(list(self.recent))
return context
Schicht 2: Episodisches Gedächtnis mit Zitierungsvalidierung
Beim Arbeiten an der Stufe des episodischen Gedächtnisses von Schicht 2 sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Ziehen Sie kleine, testbare Einheiten vor großen Skripten. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Erstellen Sie Zwischenprüfungen nach kostspieligen Schritten. Das Wiederaufnehmen des Vorgangs sollte keine erneute Abrechnung für denselben LLM-Aufruf veranlassen, wenn ein Operator einen späteren Knoten erneut versucht.
import json
import sqlite3
from datetime import datetime, timedelta
from dataclasses import dataclass, field
@dataclass
class Episode:
task_type: str
user_query: str
outcome: str
tools_used: list
citations: list # source references for validation
duration_seconds: float
success: bool
session_id: str = ""
created_at: str = field(default_factory=lambda: datetime.utcnow().isoformat())
class EpisodicMemory:
EXPIRY_DAYS = 28 # GitHub Copilot's production default
def __init__(self, db_path: str = "episodes.db"):
self.conn = sqlite3.connect(db_path, check_same_thread=False)
self._init_schema()
def _init_schema(self):
self.conn.executescript("""
CREATE TABLE IF NOT EXISTS episodes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_type TEXT NOT NULL,
user_query TEXT,
outcome TEXT,
tools_used TEXT,
citations TEXT,
duration_s REAL,
success INTEGER,
session_id TEXT,
created_at TEXT
);
CREATE INDEX IF NOT EXISTS idx_task_type ON episodes (task_type, success, created_at);
""")
self.conn.commit()
def record(self, ep: Episode):
self.conn.execute(
"""
INSERT INTO episodes
(task_type, user_query, outcome, tools_used, citations,
duration_s, success, session_id, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
ep.task_type, ep.user_query, ep.outcome,
json.dumps(ep.tools_used), json.dumps(ep.citations),
ep.duration_seconds, int(ep.success),
ep.session_id, ep.created_at,
),
)
self.conn.commit()
def recall_similar(self, task_type: str, limit: int = 3) -> list[Episode]:
cutoff = (datetime.utcnow() - timedelta(days=self.EXPIRY_DAYS)).isoformat()
cursor = self.conn.execute(
"""
SELECT task_type, user_query, outcome, tools_used, citations,
duration_s, success, session_id, created_at
FROM episodes
WHERE task_type = ? AND success = 1 AND created_at > ?
ORDER BY created_at DESC
LIMIT ?
""",
(task_type, cutoff, limit),
)
return [
Episode(
task_type=r[0], user_query=r[1], outcome=r[2],
tools_used=json.loads(r[3]), citations=json.loads(r[4]),
duration_seconds=r[5], success=bool(r[6]),
session_id=r[7], created_at=r[8],
)
for r in cursor.fetchall()
]
def validate_citations(self, episode: Episode, validator_fn) -> bool:
"""
validator_fn(citation: str) -> bool
Check if cited sources are still valid (file exists, URL responds, etc.)
Return False if any citation fails; the episode should be discarded.
"""
return all(validator_fn(c) for c in episode.citations)
Schicht 3: Semantisches Gedächtnis mit Weaviate-Hybridsuche
Beim Arbeiten an der Stufe „Layer 3 Semantic Memory“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Betrachten Sie diese Stufe als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Erzeugnisse, definieren Sie Erfolgskontrollen und lehnen Sie stille, teilweise abgeschlossene Abläufe ab. Erstellen Sie Zwischenkontrollpunkte nach aufwändigen Schritten. Die Wiederaufnahme des Vorgangs sollte keine erneute Abrechnung für denselben LLM-Aufruf veranlassen, wenn ein Operator einen späteren Knoten erneut ausführt. Beim Arbeiten an der Stufe „Layer 3 Semantic Memory“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgssignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gespeichert werden, den Operator ohne das Lesen des gesamten Graphen überprüfen können.
import uuid as uuid_lib
from datetime import datetime
import weaviate
from weaviate.classes.config import Configure, Property, DataType, VectorDistances
from weaviate.classes.query import MetadataQuery, HybridFusion, Filter
def embed(text: str) -> list[float]:
"""
Swap in any embedding source: OpenAI, Cohere, sentence-transformers, etc.
Returns a normalized float vector.
"""
from sentence_transformers import SentenceTransformer
_model = SentenceTransformer("all-MiniLM-L6-v2")
return _model.encode(text, normalize_embeddings=True).tolist()
class WeaviateSemanticMemory:
COLLECTION = "AgentMemory"
def __init__(self, host: str = "localhost", port: int = 8080):
self.client = weaviate.connect_to_local(host=host, port=port)
self._ensure_collection()
def _ensure_collection(self):
if self.client.collections.exists(self.COLLECTION):
return
self.client.collections.create(
name=self.COLLECTION,
# We provide our own vectors; no built-in vectorizer needed.
# Swap to Configure.Vectorizer.text2vec_openai() if you prefer managed embedding.
vectorizer_config=Configure.Vectorizer.none(),
vector_index_config=Configure.VectorIndex.hnsw(
distance_metric=VectorDistances.COSINE
),
properties=[
Property(name="content", data_type=DataType.TEXT),
Property(name="task_type", data_type=DataType.TEXT),
Property(name="source", data_type=DataType.TEXT),
Property(name="citations", data_type=DataType.TEXT),
Property(name="session_id", data_type=DataType.TEXT),
Property(name="confidence", data_type=DataType.NUMBER),
Property(name="created_at", data_type=DataType.TEXT),
],
)
def store(
self,
content: str,
task_type: str = "",
source: str = "agent",
citations: str = "",
session_id: str = "",
confidence: float = 1.0,
) -> str:
collection = self.client.collections.get(self.COLLECTION)
doc_id = str(uuid_lib.uuid4())
collection.data.insert(
properties={
"content": content,
"task_type": task_type,
"source": source,
"citations": citations,
"session_id": session_id,
"confidence": confidence,
"created_at": datetime.utcnow().isoformat(),
},
vector=embed(content),
uuid=doc_id,
)
return doc_id
def retrieve_hybrid(
self,
query: str,
n_results: int = 5,
min_confidence: float = 0.6,
task_type: str = None,
) -> list[dict]:
collection = self.client.collections.get(self.COLLECTION)
# Filter by confidence floor and optionally by task type
confidence_filter = Filter.by_property("confidence").greater_or_equal(min_confidence)
if task_type:
active_filter = (
Filter.by_property("task_type").equal(task_type) & confidence_filter
)
else:
active_filter = confidence_filter
results = collection.query.hybrid(
query=query,
vector=embed(query),
limit=n_results,
fusion_type=HybridFusion.RELATIVE_SCORE,
filters=active_filter,
return_metadata=MetadataQuery(score=True),
)
return [
{
"content": obj.properties["content"],
"score": obj.metadata.score,
"confidence": obj.properties.get("confidence", 1.0),
"source": obj.properties.get("source", ""),
"citations": obj.properties.get("citations", ""),
"uuid": str(obj.uuid),
}
for obj in results.objects
]
def update_confidence(self, doc_id: str, new_confidence: float):
collection = self.client.collections.get(self.COLLECTION)
collection.data.update(
uuid=doc_id,
properties={"confidence": new_confidence},
)
def close(self):
self.client.close()
Schicht 4: Prozedurales Gedächtnis und das Muster der Prompt-Entwicklung
Die Phase des prozeduralen Gedächtnisses in Schicht 4 funktioniert am besten, wenn sie als messbare Ebene betrachtet wird. Erfassen Sie einen erfolgreichen Fall, einen Fehlerfall sowie die Notizen zur Rücksetzung, bevor Sie den Umfang erweitern. Dokumentieren Sie gleichzeitig den erfolgreichen Ablauf und den Wiederherstellungsprozess. Versuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen. Legen Sie Budgets für Tokens pro Turnus und pro Sitzung fest. Agentenbasierte Tools erweitern den Kontext stark; feste Obergrenzen verhindern, dass Demonstrationen zu unerwarteten Rechnungen werden.
import json
import os
import re
from datetime import datetime, timedelta, timezone
from openai import OpenAI
MODEL = "deepseek/deepseek-v4-flash-0731"
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.environ["OPENROUTER_API_KEY"],
)
class ProceduralMemory:
def __init__(self, rules_path: str = "procedural_rules.json"):
self.rules_path = rules_path
self.rules: list[dict] = self._load()
def _load(self) -> list[dict]:
try:
with open(self.rules_path) as f:
return json.load(f)
except FileNotFoundError:
return []
def add_rule(self, situation: str, action: str, reason: str, confidence: float = 1.0):
self.rules.append({
"situation": situation,
"action": action,
"reason": reason,
"confidence": float(confidence),
"added_at": datetime.now(timezone.utc).isoformat(),
"trigger_count": 0,
})
self._save()
def get_applicable_rules(self, context: str, min_confidence: float = 0.7) -> list[dict]:
relevant = []
ctx_lower = context.lower()
dirty = False
for rule in self.rules:
if rule.get("confidence", 1.0) < min_confidence:
continue
keywords = rule["situation"].lower().split()
if not keywords:
continue
hits = sum(1 for kw in keywords if kw in ctx_lower)
if hits >= max(1, len(keywords) // 3):
rule["trigger_count"] = rule.get("trigger_count", 0) + 1
relevant.append(rule)
dirty = True
if dirty:
self._save()
relevant.sort(key=lambda r: r.get("confidence", 1.0), reverse=True)
return relevant[:5]
def prune_stale(self, max_age_days: int = 60, min_triggers: int = 2):
cutoff = (datetime.now(timezone.utc) - timedelta(days=max_age_days)).isoformat()
self.rules = [
r for r in self.rules
if r.get("added_at", "") > cutoff or r.get("trigger_count", 0) >= min_triggers
]
self._save()
def _save(self):
tmp = f"{self.rules_path}.tmp"
with open(tmp, "w") as f:
json.dump(self.rules, f, indent=2)
os.replace(tmp, self.rules_path)
def _parse_json(text: str) -> dict:
text = text.strip()
fenced = re.search(r"```(?:json)?\s*(.*?)```", text, re.S)
if fenced:
text = fenced.group(1).strip()
return json.loads(text)
def extract_rule_from_failure(failure_trace: str, memory: ProceduralMemory):
response = client.chat.completions.create(
model=MODEL,
max_tokens=250,
response_format={"type": "json_object"},
messages=[
{
"role": "system",
"content": "You return only a JSON object. No prose, no code fences.",
},
{
"role": "user",
"content": (
"A task failed. Extract one behavioral rule to prevent this failure.\n"
"Return ONLY valid JSON with keys: situation, action, reason, "
"confidence (0.0-1.0)\n"
f"Failure trace:\n{failure_trace}"
),
},
],
)
try:
rule = _parse_json(response.choices[0].message.content)
except (json.JSONDecodeError, AttributeError, TypeError):
return None
if not all(k in rule for k in ("situation", "action", "reason")):
return None
memory.add_rule(
situation=str(rule["situation"]),
action=str(rule["action"]),
reason=str(rule["reason"]),
confidence=float(rule.get("confidence", 1.0)),
)
return rule
Zusammenführung: Asynchroner Speichermanager und Systemdesign
Die Asynchronisierungsphase beim Zusammenführen der Komponenten funktioniert am besten, wenn sie als messbare Struktur betrachtet wird. Erfassen Sie vor Erweiterung des Umfangs ein gelungenes Beispiel, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Ziehen Sie kleine, testbare Einheiten vor umfangreichen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Halten Sie den Zustand der Graphen strukturiert und typisiert. Verschachtelte Datenstrukturen verbergen, welcher Knoten welches Feld geschrieben hat, und führen zu Störungen nach Unterbrechungen.
import json
from concurrent.futures import ThreadPoolExecutor
from dataclasses import dataclass, field
@dataclass
class TaskResult:
task_type: str
query: str
outcome: str
tools_used: list
citations: list
duration_seconds: float
success: bool
new_facts: list[dict] = field(default_factory=list)
session_id: str = ""
class MemoryManager:
def __init__(
self,
weaviate_host: str = "localhost",
episodic_db: str = "episodes.db",
rules_path: str = "procedural_rules.json",
):
self.buffer = SummarizingBufferMemory(max_turns=8)
self.episodic = EpisodicMemory(db_path=episodic_db)
self.semantic = WeaviateSemanticMemory(host=weaviate_host)
self.procedural = ProceduralMemory(rules_path=rules_path)
self._pool = ThreadPoolExecutor(max_workers=2, thread_name_prefix="memory_write")
def build_context(self, query: str, task_type: str) -> list[dict]:
context: list[dict] = []
# Procedural rules first: they constrain behavior throughout the task
rules = self.procedural.get_applicable_rules(query)
if rules:
rules_text = "\n".join(
f"- When '{r['situation']}': {r['action']} (reason: {r['reason']})"
for r in rules
)
context.append({"role": "user", "content": f"[Behavioral rules:\n{rules_text}]"})
# Semantic facts: domain knowledge and past discoveries
facts = self.semantic.retrieve_hybrid(query, n_results=5, min_confidence=0.6)
if facts:
facts_text = "\n".join(f"- {f['content']}" for f in facts)
context.append({"role": "user", "content": f"[Relevant knowledge:\n{facts_text}]"})
# Past episodes: outcome templates for similar tasks
episodes = self.episodic.recall_similar(task_type, limit=3)
if episodes:
ep_text = "\n".join(
f"- Outcome: {e.outcome} (tools: {', '.join(e.tools_used)})"
for e in episodes
)
context.append({"role": "user", "content": f"[Past similar tasks:\n{ep_text}]"})
# Current conversation last: the model reads this most carefully
context.extend(self.buffer.get_context())
return context
def record_turn(self, role: str, content: str):
self.buffer.add_message(role, content)
def persist(self, result: TaskResult):
# Submit to thread pool and return immediately; never block the caller
self._pool.submit(self._persist_worker, result)
def _persist_worker(self, result: TaskResult):
ep = Episode(
task_type=result.task_type,
user_query=result.query,
outcome=result.outcome,
tools_used=result.tools_used,
citations=result.citations,
duration_seconds=result.duration_seconds,
success=result.success,
session_id=result.session_id,
)
self.episodic.record(ep)
for fact in result.new_facts:
self.semantic.store(**fact)
if not result.success:
extract_rule_from_failure(result.outcome, self.procedural)
def shutdown(self):
self._pool.shutdown(wait=True)
self.semantic.close()
Drei Entscheidungen, die Ihre Architektur definieren
Die drei Entscheidungen, die eine Phase definieren, funktionieren am besten, wenn sie als messbare Struktur betrachtet werden. Erfassen Sie ein „goldenes Transkript“, einen Fehlerfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern. Betrachten Sie diese Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Halten Sie den Zustand des Graphen flach und typisiert. Verschachtelte Datenblöcke verbergen, welcher Knoten welches Feld geschrieben hat, und führen zu Unterbrechungen bei der Fortsetzung der Verarbeitung. Die drei Entscheidungen, die eine Phase definieren, funktionieren am besten, wenn sie als messbare Struktur betrachtet werden. Erfassen Sie ein „goldenes Transkript“, einen Fehlerfall sowie eine Notiz zur Rücksetzung, bevor Sie den Umfang erweitern. Halten Sie die Konfiguration außerhalb des Anwendungscode. Umgebungsdateien, Geheimdatenspeicher sowie Feature-Flags sollten an einem Ort gespeichert werden, den Betreuer ohne Durchsicht des gesamten Graphen prüfen können.
Gedächtnisvergiftung: Wie die Angriffe aussehen und wie man sich dagegen wehrt
Für das Problem des Speichervergiftens sollten vor dem Ändern des Codes die Eingaben, der Verantwortliche für den jeweiligen Schritt sowie die Abbruchkriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallweg. Wiederholungsversuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen. Setzen Sie menschliche Freigabe für Schritte voraus, bei denen Geld ausgegeben wird oder Produktionsdaten geändert werden. Eine Kompilierzeit-Verkabelung bedeutet nicht automatisch vollständige Geschäftsabdeckung.
Die eigentliche Empfehlung
Zur eigentlichen Empfehlungsphase sollten die Eingabedaten, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Codeändern definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Zur Vorzugsbehandlung kommen kleine, testbare Einheiten vor umfangreichen Skripten. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema. Menschliche Freigabe sollte bei Schritten erforderlich sein, die Geld ausgeben oder Produktionsdaten ändern. Kompilierzeitbezogene Verbindungen bedeuten noch keine vollständige Geschäftsabwicklung.
Lassen Sie uns gemeinsam weiter lernen
In der Phase „Lassen Sie uns weiter lernen“ sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Betrachten Sie diese Phase als Vertrag zwischen den Eingaben und den validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Setzen Sie menschliche Freigabe für Schritte ein, die Geld ausgeben oder Produktionsdaten ändern. Kompilierzeitbezogene Verbindungen entsprechen nicht der Geschäftskomplettheit. In der Phase „Lassen Sie uns weiter lernen“ sollten die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor dem Ändern des Codes definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gesammelt sein, den die Operator ohne das Lesen des gesamten Systems überprüfen können.
Weitere nützliche Artikel
Während der Phase „Weitere nützliche Artikel“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikatoren sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Notfallweg gemeinsam. Wiederholte Versuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen. Legen Sie nach aufwändigen Schritten einen Checkpoint an. Das System sollte bei erneuten Versuchen eines Operators nicht denselben LLM-Aufruf erneut berechnen.
Operative Checkliste
In der Phase der operativen Checkliste sollten Sie vor einer Codeänderung die Eingaben, den Verantwortlichen für den Schritt sowie die Beendigungskriterien definieren. Operator:innen sollten in der Lage sein, den Schritt anhand eines bekannten Checkpoints erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen.
Erhalten Sie Aufzeichnungen der Laufzeiten sowie der Kosten für Tokens oder Abfragen neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn sich der Pfad von einer Demo-Umgebung in gemeinsam genutzte Umgebungen verschiebt.
Setzen Sie menschliche Freigabe für Kanten voraus, die Geld ausgeben oder Produktionsdaten ändern. Eine Verkabelung zur Kompilierzeit bedeutet nicht automatisch vollständige Geschäftsabdeckung.
Schreiben Sie ein kurzes Handbuch: Wie man Schlüssel rotiert, wie man die Warteschlange leert und wie man den letzten Eingang rückgängig macht.
Halten Sie die Konfiguration außerhalb des Anwendungscode. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort zusammengefasst sein, den Betreuer ohne das Lesen des gesamten Graphen überprüfen können.
Setzen Sie menschliche Freigabe für Kanten voraus, die Geld ausgeben oder Produktionsdaten ändern. Eine Verkabelung zur Kompilierzeit bedeutet nicht automatisch vollständige Geschäftsabdeckung.
Vor der Veröffentlichung des Stacks sollten Versionen eingefroren werden, ein „goldener“ Transkript für den kritischen Pfad erstellt und die Rollback-Schritte bestätigt werden. Gemeinsam genutzte Umgebungen benötigen Rate Limits, Überprüfungen der Nutzerrechte sowie einen klaren Verantwortlichen für die Rotation von Geheimnissen. Man sollte langweilige Zuverlässigkeit vor cleveren, einmaligen Demonstrationen bevorzugen.
Batch-Hinweis für b038012e06fc: Halten Sie die Anbieter-Schlüssel außerhalb des Repositories, legen Sie eine Obergrenze für Tokens pro Sitzung fest und speichern Sie die Transkripte neben den Evaluierungs-Dateien, damit spätere Modellwechsel vergleichbar bleiben.
Für die Sicherheitsmaßnahmen in Phase 0 sollten vor dem Code-Ändern die Eingaben, der Verantwortliche für den Schritt sowie die Abbruchkriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckten Zustände schließen zu müssen. Betrachten Sie diese Phase als Vertrag zwischen den Eingaben und den validierten Ausgaben. Benennen Sie die Artefakte, definieren Sie Erfolgskontrollen und lehnen Sie stille, teilweise abgeschlossene Abläufe ab.
Verstärkungsmaßnahme Detail 0/804: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.
Beim Bearbeiten der ersten Stufe der Verstärkungsmaßnahmen notieren Sie zunächst den Vertrag: erforderliche Eingaben, Erfolgsignal sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gesammelt sein, den Betreiber ohne das Durchlesen des gesamten Systems prüfen können.
Verstärkungsmaßnahme Detail 1/804: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.
Die Verstärkungsmaßnahme Stufe 2 funktioniert am besten, wenn sie als messbare Oberfläche betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlerfall sowie die Notiz zur Rücksetzung. Ziehen Sie kleine, testbare Einheiten vor umfangreichen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf einen verworrenen Ablaufprozess.
Detail zur Verstärkung 2/804: Messen Sie für diese Notiz die Ausführungszeit, die Fehlerklasse sowie den Tokenverbrauch und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt von Einzelfallberichten, ob die Änderung beibehalten werden soll.
Für die Stufe 3 der Verstärkungsmaßnahmen sollten vor dem Ändern des Codes die Eingabedaten, der Verantwortliche für den Schritt sowie die Abbruchkriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Neben den funktionalen Ergebnissen sollten Zeiten sowie Kosten für Token oder Abfragen aufgezeichnet werden. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Weg von einer Demo-Umgebung in gemeinsam genutzte Umgebungen wechselt.
Detail der Verstärkungsmaßnahme 3/804: Messen Sie die Gesamtlaufzeit, die Fehlerklasse sowie den Tokenverbrauch für diese Maßnahme und entscheiden Sie anschließend anhand eines festgelegten Fragebogens statt aufgrund von Einzelfallbeobachtungen, ob die Änderung beibehalten werden soll.
Beim Bearbeiten der Stufe 4 der Verstärkungsmaßnahmen sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikatoren sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Wiederherstellungsprozess gemeinsam. Wiederholversuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.
Details zur Verstärkung 4/804: Messen Sie die Ausführungszeit, die Fehlerklasse sowie den Tokenverbrauch für diese Maßnahme und entscheiden Sie anschließend anhand eines festgelegten Fragekatalogs – und nicht aufgrund von Einzelfällen –, ob die Änderung beibehalten werden soll.
Die Stufe 5 der Verstärkungsmaßnahmen funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlfall sowie eine Notiz zur Rücksetzung. Betrachten Sie diese Stufe als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die relevanten Dokumente, definieren Sie Erfolgsprüfungen und lehnen Sie stille, teilweise abgeschlossene Abläufe ab.
Verstärkungsmaßnahme Detail 5/804: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.
Für die 6. Stufe der Verstärkungsmaßnahme sollten vor dem Ändern des Codes die Eingabedaten, der Verantwortliche für den Schritt sowie die Abschlusskriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Die Konfiguration sollte außerhalb des Anwendungscode gespeichert werden. Umgebungsdateien, Geheimdatenspeicher sowie Feature-Flags sollten an einem Ort zusammengefasst sein, den die Operator überprüfen können, ohne den gesamten Codeverlauf durchlesen zu müssen.
Verstärkungsmaßnahme Detail 6/804: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.
Beim Bearbeiten der Stufe 7 der Sicherheitsverbesserungen sollten Sie zunächst den Ablaufplan aufschreiben: erforderliche Eingaben, Erfolgsindikatoren sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Ziehen Sie kleine, testbare Einheiten vor großen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortungsbereich verweisen und nicht auf ein verworrenes Ablaufschema.
Sicherheitsdetail 7/804: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Anweisung und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragekatalogs – und nicht nur aufgrund von Einzelfällen –, ob die Änderung beibehalten werden soll.
Die Stufe 8 der Sicherheitsverbesserungen funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie vor Erweiterung des Umfangs ein „goldenes“ Transkript, einen Fehlfall sowie eine Notiz zur Rücksetzung. Notieren Sie die Zeiten sowie den Token- oder Abfragedurchsatz neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Ablauf von einer Demo in gemeinsame Umgebungen übergeht.
Verstärkungsmaßnahme Detail 8/804: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.
Für die 9. Phase der Verstärkungsmaßnahme sollten vor dem Ändern des Codes die Eingabedaten, der Verantwortliche für den Schritt sowie die Abschlusskriterien definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Dokumentieren Sie sowohl den erfolgreichen Ablauf als auch den Notfallfall gemeinsam. Wiederholungsversuche, menschliche Überprüfungen sowie die Handhabung von Fehlern gehören zum Produkt selbst und nicht zu späteren Optimierungen.
Verstärkungsmaßnahme Detail 9/804: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.
Beim Bearbeiten der Stufe 10 zur Sicherheitsstärkung sollten Sie zunächst einen Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikatoren sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Betrachten Sie diese Stufe als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die relevanten Artefakte, definieren Sie Erfolgsprüfungen und lehnen Sie stille, teilweise abgeschlossene Änderungen ab.
Sicherheitsdetail 10/804: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Anweisung und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragekatalogs – und nicht nur aufgrund von Einzelfällen –, ob die Änderung beibehalten werden soll.
Die Stufe 11 zur Sicherheitsstärkung funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie vor der Erweiterung des Umfangs ein „goldenes Transkript“, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Bewahren Sie Konfigurationen außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher und Feature-Flags sollten an einem Ort gesammelt werden, den Betreiber ohne das Durchlesen des gesamten Systems prüfen können.
Verstärkungsmaßnahme Detail 11/804: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.
Zur 12. Stufe der Verstärkungsmaßnahmen sollten die Eingabedaten, der Verantwortliche für den Schritt sowie die Abbruchkriterien vor der Codeänderung definiert werden. Die Operator sollten in der Lage sein, den Schritt von einem bekannten Checkpoint aus erneut auszuführen, ohne auf versteckte Zustände schließen zu müssen. Bevorzugen Sie kleine, testbare Einheiten vor umfangreichen Skripten. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzelne Verantwortung verweisen und nicht auf ein verworrenes Ablaufverfahren.
Verstärkungsmaßnahme Detail 12/804: Messen Sie die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch für diese Notiz und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragebogens statt aufgrund von Einzelfällen, ob die Änderung beibehalten werden soll.