Startseite / Artikel

Praktische Hinweise: Der memory-effiziente KI-Agent – Entwicklung eines Context-Engines in Go

Schritt-für-Schritt-Anleitung zu den Praktischen Hinweisen: Der merkmalseffiziente KI-Agent – Aufbau eines Kontext-Engines in Go: Verträge, Überprüfungen sowie Code-Slots für Teams, die dieses Muster einsetzen.

Verlag: REACTAPP.TOP10 Min. Lesezeit2311 Wörter

Quellen: The Memory-Efficient AI Agent: Building a Context Engine in Go

Die folgenden Anmerkungen skizzieren einen praktischen Weg durch „The Memory-Efficient AI Agent: Building a Context Engine in Go“. Der Schwerpunkt liegt auf Verträgen, Überprüfungen sowie Code-Platzhaltern, anstatt auf motivierenden Erläuterungen. Während der Übersichtsphase 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. Ziehen Sie kleine, testbare Einheiten vor statt umfangreicher Skripte. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf ein verworrenes Ablaufschema.

Einstieg: Imports und das Datenmodell

Die Phasen „Einführung“, „Importe“ und „Vorstufe“ funktionieren am besten, wenn sie als messbare Einheiten betrachtet werden. Erfassen Sie vor Erweiterung des Umfangs ein gelungenes Beispiel, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Betrachten Sie diese Phase als Vertrag zwischen den Eingaben und den validierten Ausgaben. Benennen Sie die Ergebnisdokumente, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Legen Sie Budgetgrenzen pro Turnus und pro Sitzung fest. Agentenbasierte Tools erweitern den Kontext oft übermäßig; feste Obergrenzen verhindern, dass Demonstrationen zu unerwarteten Rechnungen werden.

import (
	"container/heap"
	"container/list"
	"encoding/gob"
	"fmt"
	"math"
	"os"
	"strings"
)
type MemoryItem struct {
	ID       int
	Content  string
	Priority int
	Vector   []float64
	index    int
}

Der Prioritätsmotor: Max-Heap mit container/heap

Die Phase des Priority Engine Max-Heap funktioniert am besten, wenn sie als messbarer Bereich betrachtet wird. Erfassen Sie vor Erweiterung des Umfangs ein Beispiel für einen erfolgreichen Ablauf, einen Fehlerfall sowie eine Notiz zur Rücksetzung. Erfassen Sie außerdem die Laufzeiten sowie die Kosten für Tokens oder Abfragen neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Ablauf von einer Demo-Umgebung in gemeinsam genutzte Umgebungen übergeht. Halten Sie den Zustand des Graphen flach und typisiert – verschachtelte Datenstrukturen verbergen, welcher Knoten welches Feld geschrieben hat, und führen zu Unterbrechungen beim Fortsetzen des Ablaufs.

type PriorityQueue []*MemoryItem

func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].Priority > pq[j].Priority // Max-heap logic
}
func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
	pq[i].index = i
	pq[j].index = j
}
func (pq *PriorityQueue) Push(x interface{}) {
	n := len(*pq)
	item := x.(*MemoryItem)
	item.index = n
	*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	old[n-1] = nil
	item.index = -1
	*pq = old[0 : n-1]
	return item
}

Das Schiebefenster: Temporaler Kontext mit container/list

Die Sliding Window Temporal-Ebene funktioniert am besten, wenn sie als messbare Struktur betrachtet wird. Erfassen Sie ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zum Rollback, bevor Sie den Umfang erweitern. Bewahren Sie die Konfiguration außerhalb des Anwendungscode auf. Umgebungsdateien, Geheimdatenspeicher sowie Feature-Flags sollten an einem Ort gesammelt sein, den Betreuer ohne Durchsicht des gesamten Graphen prüfen können. Halten Sie den Zustand des Graphen einfach und typisiert. Verschachtelte Datenstrukturen verbergen, welcher Knoten welches Feld geschrieben hat, und führen zu Unterbrechungen bei der Fortsetzung der Verarbeitung. Die Sliding Window Temporal-Ebene funktioniert am besten, wenn sie als messbare Struktur betrachtet wird. Erfassen Sie ein „goldenes“ Transkript, einen Fehlerfall sowie eine Notiz zum Rollback, bevor Sie den Umfang erweitern. Ziehen Sie kleine, testbare Einheiten vor großen, komplexen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortungsbereich verweisen und nicht auf einen verworrenen Ablaufprozess.

type SlidingWindow struct {
	queue    *list.List
	capacity int
}

func NewSlidingWindow(capacity int) *SlidingWindow {
	return &SlidingWindow{queue: list.New(), capacity: capacity}
}
func (sw *SlidingWindow) Add(item *MemoryItem) {
	if sw.queue.Len() >= sw.capacity {
		sw.queue.Remove(sw.queue.Front())
	}
	sw.queue.PushBack(item)
}

Vektorisierung und Ähnlichkeit: Semantische Suche mit math und strings

In der Phase der Vektorisierung und Ähnlichkeit sollten die Eingaben, der Verantwortliche für den jeweiligen 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 Erzeugnisse, definieren Sie Erfolgskontrollen und lehnen Sie stille, unvollständige Abschlüsse ab. Setzen Sie menschliche Freigabe für Schritte voraus, die Geld kosten oder Produktionsdaten ändern. Eine Kompilierzeit-Verkabelung entspricht nicht notwendigerweise vollständiger Geschäftsabwicklung.

func TextToVector(text string) []float64 {
	vocab := []string{"database", "connection", "fix", "leak", "system", "user"}
	vec := make([]float64, len(vocab))
	words := strings.Fields(strings.ToLower(text))
	for _, word := range words {
		for i, v := range vocab {
			if strings.Contains(word, v) {
				vec[i]++
			}
		}
	}
	return vec
}
func CosineSimilarity(a, b []float64) float64 {
	var dot, normA, normB float64
	for i := range a {
		dot += a[i] * b[i]
		normA += a[i] * a[i]
		normB += b[i] * b[i]
	}
	if normA == 0 || normB == 0 {
		return 0
	}
	return dot / (math.Sqrt(normA) * math.Sqrt(normB))
}

Persistenz: Binäre Serialisierung mit encoding/gob

Für die binäre Serialisierung mit Persistenz und Phasenmodell sollten vor dem Codeändern 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 versteckten Zuständen schließen zu müssen. Erfassen Sie neben den funktionalen Ergebnissen auch die Ausführungsdauer sowie die Kosten für Token oder Abfragen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Ablauf von Demonstrationsumgebungen in gemeinsam genutzte Umgebungen wechselt. Setzen Sie menschliche Freigabe für Schritte ein, die Geld kosten oder Produktionsdaten verändern. Eine Verkabelung zur Kompilierzeit bedeutet nicht automatisch vollständige Geschäftsabdeckung.

type AgentMemory struct {
	LongTerm []*MemoryItem
}
func SaveMemory(filename string, mem *AgentMemory) error {
	file, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer file.Close()
	return gob.NewEncoder(file).Encode(mem)
}

Die Ausführung: main()

Für die Hauptphase von The Execution 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 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 gesammelt sein, den die Operator überprüfen können, ohne den gesamten Ablauf durchlesen zu müssen. Setzen Sie menschliche Freigabe für Kanten ein, die Geld ausgeben oder Produktionsdaten ändern. Eine Verkabelung zur Kompilierzeit bedeutet nicht automatisch vollständige Geschäftsabdeckung. Für die Hauptphase von The Execution 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 verborgene Zustände schließen zu müssen. Ziehen Sie kleine, testbare Einheiten vor großen, komplexen Skripten vor. Wenn ein Schritt fehlschlägt, sollte der Fehler auf eine einzige Verantwortung verweisen und nicht auf einen verworrenen Ablauf.

pq := &PriorityQueue{}
heap.Init(pq)
sw := NewSlidingWindow(3)
rawItems := []struct {
	content  string
	priority int
}{
	{"System: You are a helpful assistant.", 10},
	{"User: How do I fix the database connection?", 5},
	{"CRITICAL: Fix database connection leak.", 9},
}

for _, ri := range rawItems {
	item := &MemoryItem{
		Content:  ri.content,
		Priority: ri.priority,
		Vector:   TextToVector(ri.content),
	}
	heap.Push(pq, item)
	sw.Add(item)
}
fmt.Println("--- Sliding Window (capacity 3) ---")
for e := sw.queue.Front(); e != nil; e = e.Next() {
	fmt.Printf("  Window holds: '%s'\n", e.Value.(*MemoryItem).Content)
}
for i := 0; i < 2; i++ {
	sw.Add(&MemoryItem{
		ID:       i + 1,
		Content:  fmt.Sprintf("Stream item %d: recent event", i+1),
		Priority: 1,
		Vector:   TextToVector("recent event"),
	})
}
fmt.Println("  After 2 more stream items added:")
for e := sw.queue.Front(); e != nil; e = e.Next() {
	fmt.Printf("  Window holds: '%s'\n", e.Value.(*MemoryItem).Content)
}
query := "database connection fix"
queryVec := TextToVector(query)

var bestMatch *MemoryItem
maxSim := -1.0

fmt.Printf("Querying for: '%s'\n", query)
for _, item := range *pq {
	sim := CosineSimilarity(item.Vector, queryVec)
	fmt.Printf("Comparing with: '%s' (Sim: %.2f)\n", item.Content, sim)
	if sim > maxSim {
		maxSim = sim
		bestMatch = item
	}
}
fmt.Printf("\nBest match found: '%s' (Sim: %.2f)\n", bestMatch.Content, maxSim)
mem := &AgentMemory{LongTerm: *pq}
SaveMemory("agent_memory.gob", mem)
fmt.Println("Memory state saved to agent_memory.gob")
PS C:\Users\User\ai-memory> go run .\ai_memory_experiment.go
--- Sliding Window (capacity 3) ---
  Window holds: 'System: You are a helpful assistant.'
  Window holds: 'User: How do I fix the database connection?'
  Window holds: 'CRITICAL: Fix database connection leak.'
  After 2 more stream items added:
  Window holds: 'CRITICAL: Fix database connection leak.'
  Window holds: 'Stream item 1: recent event'
  Window holds: 'Stream item 2: recent event'

Querying for: 'database connection fix'
Comparing with: 'System: You are a helpful assistant.' (Sim: 0.00)
Comparing with: 'User: How do I fix the database connection?' (Sim: 0.87)
Comparing with: 'CRITICAL: Fix database connection leak.' (Sim: 0.87)

Best match found: 'User: How do I fix the database connection?' (Sim: 0.87)
Memory state saved to agent_memory.gob
PS C:\Users\User\ai-memory>

Supercharging Agents mit MCP

Beim Arbeiten an der Phase „Supercharging Agents mit MCP“ 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 Phase als Vertrag zwischen Eingaben und validierten Ausgaben. Benennen Sie die Ergebnisdokumente, definieren Sie Erfolgskontrollen und lehnen Sie stille, teilweise abgeschlossene Abläufe ab. Protokollieren Sie für jeden Aufruf den Namen des Tools, den Hash der Argumente, die Latenzzeit sowie das Ergebnis. Ohne diese Aufzeichnungen verschwendet man Stunden beim Debuggen von Agentenschleifen.

Kernpunkte

Während der Phase der wichtigsten Erkenntnisse sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgsindikator sowie das Vorgehen bei teilweisen Fehlern. Diese Checkliste sorgt dafür, dass spätere Codeänderungen transparent bleiben. Notieren Sie die Laufzeiten sowie die Kosten für Token oder Abfragen neben den funktionalen Ergebnissen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Prozess von einer Demo in gemeinsam genutzte Umgebungen übergeht. Legen Sie nach teuren Schritten einen Kontrollpunkt an. Das Fortsetzen des Prozesses sollte keine erneuten Gebühren für denselben LLM-Aufruf verursachen, wenn ein Operator einen späteren Knoten erneut ausführt.

Während der Phase „Zusätzliche Links-Ressourcen“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgszeichen 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 überprüfen können, ohne den gesamten Ablauf durchlesen zu müssen. Erstellen Sie nach aufwändigen Schritten einen Checkpoint. Das Wiederaufnehmen des Vorgangs sollte keine doppelte Abrechnung für denselben LLM-Aufruf verursachen, wenn ein Betreiber einen späteren Knoten erneut ausführt. Während der Phase „Zusätzliche Links-Ressourcen“ sollten Sie zunächst den Vertrag aufschreiben: erforderliche Eingaben, Erfolgszeichen 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 Verantwortung verweisen und nicht auf einen verworrenen Ablauf.

Betriebscheckliste

Zur Phase der Betriebskontrollliste 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.

Dokumentieren Sie gemeinsam den erfolgreichen Ablauf sowie den Notfallplan. Wiederholungsversuche, menschliche Überprüfungen und die Handhabung von Fehlern gehören zum Produkt selbst, nicht zu späteren Optimierungen.

Fügen Sie menschliche Freigabe bei Schritten ein, die Geld ausgeben oder Produktionsdaten ändern. Kompilierzeitbezogene Verbindungen bedeuten noch keine vollständige Geschäftsabwicklung.

Schreiben Sie ein kurzes Handbuch: Wie werden Schlüssel ausgetauscht, wie wird die Warteschlange geleert und wie wird der letzte Eingang rückgängig gemacht?

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.

Fügen Sie menschliche Freigabe bei Schritten ein, die Geld ausgeben oder Produktionsdaten ändern. Compile-time Wiring bedeutet nicht automatisch vollständige Geschäftsabdeckung.

Vor der Einführung des Stack sollten Versionen eingefroren werden, ein „goldener“ Transkript für den kritischen Pfad erstellt und Rollback-Schritte bestätigt werden. Gemeinsame Umgebungen benötigen Rate Limits, Überprüfungen der Nutzerrechte sowie einen klaren Verantwortlichen für die Rotation von Geheimnissen. Wählen Sie langweilige Zuverlässigkeit statt cleverer, einmaliger Demonstrationen.

Batch-Hinweis für d4b7557c44d8: Halten Sie Provider-Schlüssel außerhalb des Repositories, legen Sie eine Obergrenze für Session-Tokens fest und speichern Sie Transkripte neben den Evaluierungs-Dateien, damit spätere Modellwechsel vergleichbar bleiben.

Für die Stufe 0 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. 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.

Detail der Verstärkungsmaßnahme 0/825: Messen Sie für diese Maßnahme die Ausführungsdauer, die Fehlerklasse sowie den Tokenverbrauch und entscheiden Sie anschließend auf der Grundlage eines festgelegten Fragekatalogs – und nicht aufgrund von Einzelfällen –, ob die Änderung beibehalten werden soll.

Beim Bearbeiten der ersten Stufe der Sicherheitsstärkung 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.

Sicherheitsstärkungsdetail 1/825: Messen Sie die Ausführungszeit, 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 zweite Stufe der Sicherheitsstärkung 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 neben den funktionalen Ergebnissen auch die Ausführungszeiten sowie die Kosten für Tokens oder Abfragen. Eine frühzeitige Sichtbarkeit der Kosten verhindert überraschende Rechnungen, wenn der Ablauf von einer Demo-Umgebung in gemeinsam genutzte Umgebungen übergeht.

Verstärkungsmaßnahme Detail 2/825: 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 dritten Phase der Verstärkungsmaßnahme sollten die Eingabedaten, der Verantwortliche für den Schritt sowie die Abschlusskriterien 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. 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 3/825: 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.