AI Agent (Tools Agent) flacht Postgres Chat Memory-Verlauf in der System-Message-Zeichenkette ab — deaktiviert Prompt Caching

Ich betreibe einen WhatsApp-Bot auf AI Agent (Tools Agent) + OpenAI Chat Model Node (gpt-4-1-mini, Responses API aktiviert, File Search Built-in Tool für RAG) + Postgres Chat Memory + 3 Custom Tools (Call n8n Workflow Tool Type).

Mein System Prompt ist ziemlich groß (~8-9k Tokens, hauptsächlich statische Anweisungen und Referenzbeispiele), daher hätte ich mit einer guten Prompt Caching-Quote rechnen können, da sich dieser Inhalt zwischen den Anfragen nicht ändert. Ich habe das OpenAI-Nutzungs-Dashboard überprüft und die Cache-Hit-Rate liegt bei etwa 2%.

Ich habe die rohe Input-Payload aus den Ausführungsdaten des OpenAI Chat Model Nodes gezogen und die Ursache gefunden: Der gesamte System Prompt, der dynamische Conversation Context Block (Kundenname, Session-Status, Arbeitszeiten usw.) und die vollständige History aller Human/AI-Turns werden alle in einen einzelnen „System: …" String zusammengefasst, bevor sie an die API gesendet werden, anstatt sie als strukturiertes Messages-Array mit separaten, rollengetagten Objekten (system / human / ai / tool) zu übergeben.

Da der dynamische Context Block zwischen den statischen Anweisungen und den eigentlichen Conversation Turns sitzt und sich dieser Block bei jeder einzelnen Anfrage ändert, bricht der Präfix-Match für alles, was folgt, zusammen — daher funktioniert Caching nie, obwohl sich der Großteil des Prompts (die statischen Anweisungen) nie ändert.

Soweit ich LangChain’s AgentExecutor verstehe, konvertiert der Memory Wrapper die History standardmäßig zu einem String, es sei denn, return_messages=True ist explizit gesetzt, und der Prompt sollte idealerweise ein ChatPromptTemplate mit einem MessagesPlaceholder verwenden, um History als eigentliche Message-Objekte beizubehalten. Ich sehe keine dieser beiden Optionen als konfigurierbar irgendwo in der UI des AI Agent Nodes.

Frage: Gibt es einen unterstützten Weg (versteckte Expression, Node-Einstellung oder andere Memory Node-Konfiguration), um den integrierten AI Agent Node dazu zu bringen, Chat-History als strukturiertes Array anstelle eines in den System Prompt String zusammengefassten Strings zu übergeben? Oder ist dies eine bekannte Einschränkung der aktuellen Tools Agent-Implementierung?

Der Hinweis zum Nachweis ist der erste Token-Block, der sich ändert. Führe einen winzigen A/B-Test in derselben WhatsApp-Sitzung durch: einen Aufruf mit deaktiviertem Postgres Chat Memory und einen mit aktiviertem Memory, vergleiche dann die rohe Input-Nutzlast und cache_creation_input_tokens / cache_read_input_tokens.

Wenn der deaktivierte Durchlauf die 8–9k Anweisungen als stabiles Präfix beibehält und der speicher-aktivierte Durchlauf Kunden-/Sitzungs-/Verlaufstexte vor diesem Präfix einfügt, ist dein Cache-Miss kein OpenAI-Cache-Einstellungsproblem. Es ist die Message-Assembly-Schicht. Poste nur diesen redigierten Diff und die zwei Cache-Zähler; keine Kundentexte nötig.

Hallo,

Jetzt verstehe ich das Problem, danke der ausführlichen Erklärung.

Eigentlich geht es nicht um ein Modellproblem, sondern um ein Problem mit der Prompt-Struktur in n8n.

Aktuell kombiniert n8n alles (Systeminstruktionen + dynamischer Kontext wie Kundennamen/Sitzungsdaten + Chat-Verlauf) in einen langen String, bevor es an OpenAI gesendet wird.

Da sich bei jedem Request ein Teil dieser Eingabe ändert (wie Sitzungsinformationen oder Nutzerkontext), ist der finale Prompt nie genau gleich, auch wenn 80–90 % davon statisch sind.

Und das ist der Hauptgrund, warum dein Prompt Caching nicht richtig greift. OpenAI Caching funktioniert nur, wenn das Präfix byte-für-byte identisch ist, und bei dir wird diese Konsistenz durch den eingespielten dynamischen Block unterbrochen.

Kurz gesagt:

  • Dein Systemprompt ist größtenteils statisch (gut für Caching)
  • Aber er wird durch dynamischen Kontext und Verlauf „verunreinigt"
  • n8n flacht alles in einen String ab, statt strukturierte Messages zu verwenden
  • Also behandelt OpenAI jeden Request als neuen Prompt

Was das praktisch bedeutet

Dein Setup ist nicht kaputt, es ist nur:

  • ineffizient beim Caching
  • wegen der internen Speicher- und Kontextbehandlung durch n8n’s AI Agent

Um das richtig zu beheben, gibt es zwei Ansätze:

Option 1 (schnelle Verbesserung in n8n)

  • Reduziere oder isoliere die Injektion von dynamischem Kontext in den Systemprompt
  • Halte den Systemprompt so statisch wie möglich
  • Minimiere Änderungen im Präfix-Abschnitt

Option 2 (saubere Produktivlösung)

  • Verlasse dich nicht auf das interne Prompt-Building des AI Agent
  • Baue Messages manuell in strukturiertem Format:
    • System Message (statisch)
    • Context Message (separate Rolle)
    • Chat-Verlauf als korrektes Array
      Das stellt das Caching-Verhalten vollständig wieder her und bietet vorhersehbare Performance.

Um Option 1 in der Praxis zum Laufen zu bringen: Halten Sie das System-Prompt-Feld im AI Agent zu 100% statisch – keine Ausdrücke, keine dynamischen Variablen – und verschieben Sie den gesamten pro-Session-Kontext (Kundenname, Status, Arbeitszeiten usw.) stattdessen in die erste Benutzermeldung. Sie können das als synthetische „User"-Nachricht am Anfang des Conversation Arrays vor dem eigentlichen Chat einfügen. Da OpenAIs Caching präfixbasiert funktioniert und die System Message bei jedem Aufruf byte-für-byte identisch bleibt, sollte das statische Präfix zuverlässig gecacht werden. Der Kompromiss besteht darin, dass sich die Kontextfenster-Struktur leicht verschiebt, aber für ein 8-9k statisches System Prompt ist das normalerweise der kostengünstigste Weg, ohne auf die integrierte Tool-Ausführung des AI Agent zu verzichten.

1 „Gefällt mir“

Ich würde das als Problem der Nachrichtenassemblierung behandeln, nicht als Problem der Modellauswahl.

Die Diagnose, die ich durchführen würde:

  1. zwei Raw-Model-Payloads mit aktiviertem Speicher erfassen;
  2. zwei Raw-Model-Payloads mit deaktiviertem Speicher erfassen;
  3. nur die ersten 1–2k Token jeder Payload vergleichen;
  4. cache_creation_input_tokens und cache_read_input_tokens für die gleichen Aufrufe vergleichen.

Wenn das erste sich ändernde Token vor oder innerhalb deiner 8–9k statischen Anweisungen erscheint, wird der Cache verfehlt, auch wenn sich der Prompt für einen Menschen größtenteils „statisch