Hallo zusammen, Leo hier von agntdev.com! Heute möchte ich über etwas sprechen, das mir seit einigen Wochen im Kopf herumgeht, seit ich mit dem letzten Batch von Agenten-Frameworks arbeite. Genauer gesagt denke ich über den Aspekt des „Aufbaus“ nach – nicht nur über die Erstellung eines Agenten, sondern wie wir sie aufbauen und die oft übersehenen Implikationen, eine grundlegende Herangehensweise der anderen vorzuziehen. Wir haben die Phase des „Proof of Concept“ mit den Agenten hinter uns gelassen, und jetzt geht es darum, sie zuverlässig, wartbar und wirklich nützlich zu machen.
Der spezifische Winkel, den ich heute betrachte, ist Die Versteckten Kosten von Fertigkomponenten für Agenten: Warum es manchmal günstiger sein kann, Ihre eigenen zu erstellen.
Jetzt weiß ich, was einige von euch denken: „Leo, meinst du das ernst? Wir haben gerade all diese erstaunlichen Tools und Frameworks erhalten, die uns vorgefertigte Speichermodule, Planungs-Komponenten und Tool-Executors bieten. Warum zum Teufel sollte ich meine eigenen erstellen?“ Und glaubt mir, ich habe mir diese Frage viele Male gestellt. Lange Zeit war ich ein leidenschaftlicher Verfechter des Mantras „nutze das Framework“. Warum das Rad neu erfinden, oder?
Mein Standpunkt begann sich während eines kürzlichen Kundenprojekts zu ändern. Wir bauten einen internen Support-Agenten für ein mittelständisches SaaS-Unternehmen. Die Idee war einfach: ein Agent, der in der Lage ist, häufige Kundenfragen zu beantworten, indem er durch die Dokumentation stöbert, Datenbankstatus überprüft und sogar Tickets hochschiebt, wenn nötig. Wir begannen mit einem der beliebten Python-Agenten-Frameworks – ihr wisst schon, die, die euch versprechen, einen Agenten in wenigen Minuten zu erstellen. Und in den ersten Tagen war es wie Magie.
Wir haben einige vorgefertigte Komponenten für den Speicher (eine Vektor-Datenbank-Integration), die Planung (eine grundlegende LLM-Kette) und die Ausführung von Tools (indem wir einige interne APIs aufrufen) zusammengefügt. Die Demo sah fantastisch aus. Der Kunde war beeindruckt. Wir haben eine Kombucha aufgemacht, um das zu feiern. Aber dann kam die Phase des Tests unter realen Bedingungen.
Die Illusion der Geschwindigkeit: Wenn „Schnellstart“ zu „Langsame Fehlersuche“ wird
Die Probleme begannen subtil. Der Agent halluzinierte manchmal, was bei LLMs üblich ist, aber die Art und Weise, wie er halluzinierte, war besonders. Es war nicht gerechtfertigt, irgendetwas zu sagen; er gab Fakten an, die fast richtig, aber leicht falsch waren, und zog aus einer Mischung von historischen Interaktionen und aktuellem Kontext. Wir begannen, die Speicherkomponente zu untersuchen.
Das Speichermodul dieses speziellen Frameworks war für allgemeine Konversationshistorien konzipiert. Es zeichnete Runden auf, fasste sie zusammen und holte relevante Stücke basierend auf semantischer Ähnlichkeit ab. Das klingt auf dem Papier gut, oder? Aber unser Agent musste zwischen der aktuellen Anfrage eines Benutzers, dem historischen Kontext des selben Benutzers und dem allgemeinen Wissen aus der Dokumentation unterscheiden. Die vorgefertigte Komponente behandelte alles wie einen großen Sack voller Wörter.
Mein Team hat Tage damit verbracht, zu versuchen, die Parameter dieser „Black Box“-Speicherkomponente zu ändern. Wir haben die Stückgrößen geändert, mit verschiedenen Integrationsmodellen experimentiert und sogar versucht, die Eingaben zu filtern, bevor sie den Speicher erreichten. Nichts schien zu funktionieren. Das Problem war nicht die *Funktionalität* der Komponente; es war ihre *Design-Philosophie*, die nicht mit unserem spezifischen Problem übereinstimmte.
Wir haben schließlich erkannt, dass wir, um das Verhalten zu erreichen, das wir benötigten, entweder einen aufwendigen Wrapper um den vorgefertigten Speicher schreiben mussten (was wie ein Kampf gegen das Framework aussah) oder tief in den Quellcode eintauchen und ihn ändern mussten (was wie die Anmeldung für einen Wartungsalbtraum aussah). Hier begannen die „versteckten Kosten“ sichtbar zu werden.
Das Gewicht der Abstraktion: Wenn Allgemeinheit zur Last wird
Frameworks zielen von Natur aus auf Allgemeinheit ab. Sie möchten ein breites Publikum mit unterschiedlichen Bedürfnissen bedienen. Das bedeutet, dass ihre Komponenten oft so konzipiert sind, dass sie flexibel, konfigurierbar und etwas stur darüber sind, wie die Dinge *funktionieren sollten*. Und für 80 % der Anwendungsfälle ist das fantastisch! Das beschleunigt die Entwicklung wirklich.
Aber was ist mit den verbleibenden 20 %? Was tun, wenn Ihr Agent einen sehr spezifischen Speichertyp benötigt, der zwischen dem flüchtigen Gesprächskontext, den langfristigen Benutzerpräferenzen und dem statischen Wissen unterscheidet? Oder wenn seine Planungslogik eng in den Zustand eines komplexen externen Systems integriert werden muss, anstatt einfach generische Toolaufrufe zu verknüpfen?
Hier beginnt die Abstraktion zu belasten. Sie verwenden nicht einfach eine Komponente; Sie erben ihre Annahmen, Einschränkungen und inhärenten Vorurteile. Und zu versuchen, ein quadratisches Stück in ein rundes Loch zu zwingen, selbst mit viel Klopfen, führt in der Regel zu einem gebrochenen Stück oder einem schlecht geformten Loch.
In unserem Szenario des Support-Agenten war die vorgefertigte Speicherkomponente für einen Gesprächsfluss konzipiert, bei dem der gesamte historische Kontext mehr oder weniger gleich ist. Unser Agent musste jedoch eine neue Anfrage gegenüber einer FAQ-Datenbank priorisieren und das historische Gespräch nur einbeziehen, wenn die Anfrage mehrdeutig war oder eindeutig auf eine frühere Interaktion verwies. Die Komponente des Frameworks war einfach nicht für diese nuancierte Unterscheidung ohne umfangreiche Anpassungen konzipiert.
Wann es Sinn macht, Ihre eigenen zu erstellen: Kontrolle und Klarheit
Nach vielen Überlegungen (und einigen späten Pizzanächten) haben wir beschlossen, das vorgefertigte Speichermodul aufzugeben und unser eigenes zu implementieren. Das schien zunächst ein Rückschritt zu sein, aber die Klarheit, die es brachte, war sofort spürbar.
Wir haben ein Speichersystem speziell für unsere Bedürfnisse entworfen:
- Element für flüchtige Gespräche: Eine einfache deque (doppelt endbare Warteschlange) für die letzten N Runden des aktuellen Gesprächs. Wird nach X Minuten Inaktivität oder wenn eine neue, unterschiedliche Anfrage eintrifft, gelöscht.
- Benutzerprofil-Speicherung: Eine leichte Datenbank (Redis, in unserem Fall), die die spezifischen Präferenzen des Benutzers, aktuelle Tickets und häufig gestellte Fragen für diesen Benutzer speichert. Dies bleibt zwischen den Sitzungen bestehen.
- Wissensdatenbank-Index: Unser bevorzugter Vektorspeicher, speziell für Dokumentation und FAQs.
Die Logik zur Wiederherstellung wurde dann maßgeschneidert:
- Zuerst versuchen, die Anfrage direkt mit der Wissensdatenbank abzugleichen.
- Wenn das Vertrauen nicht ausreicht, das Benutzerprofil-Speicher für vergangene Interaktionen oder relevante Präferenzen überprüfen.
- Im äußersten Fall oder um die Konversation flüssiger zu gestalten, den Kontext aus dem flüchtigen Element ziehen.
Hier ist eine vereinfachte Skizze in Python, wie unsere benutzerdefinierte Speicherwiederherstellung aussehen könnte, nur um Ihnen eine Vorstellung zu geben:
class CustomAgentMemory:
def __init__(self, user_id, knowledge_base_client, user_profile_store):
self.user_id = user_id
self.kb_client = knowledge_base_client
self.profile_store = user_profile_store
self.conversation_history = collections.deque(maxlen=10) # Flüchtiges Element
def add_to_history(self, role, message):
self.conversation_history.append({"role": role, "content": message})
def get_context(self, current_query: str) -> list[str]:
context_chunks = []
# 1. Priorisieren Sie die Wissensdatenbank für direkte Antworten
kb_results = self.kb_client.search(current_query, top_k=3)
if kb_results:
context_chunks.extend([res["text"] for res in kb_results])
# Wenn eine sehr starke Übereinstimmung vorliegt, benötigen wir vielleicht im Moment nicht viele andere Informationen
if any(res["score"] > 0.8 for res in kb_results):
return context_chunks
# 2. Überprüfen Sie das Benutzerprofil für einen personalisierten Kontext
user_prefs = self.profile_store.get_user_preferences(self.user_id)
if user_prefs:
context_chunks.append(f"Benutzervorlieben: {user_prefs}")
recent_user_issues = self.profile_store.get_recent_issues(self.user_id, current_query)
if recent_user_issues:
context_chunks.extend(recent_user_issues)
# 3. Fügen Sie die kürzliche Gesprächshistorie für die Flüssigkeit hinzu, aber mit niedrigerer Priorität
# Wir könnten dies zusammenfassen oder filtern, um Relevanz zu vermeiden
if self.conversation_history:
# Einfache Methode: Fügen Sie einfach die letzten Runden hinzu. Fortgeschrittener: LLM zusammenfassen oder filtern.
for item in list(self.conversation_history):
context_chunks.append(f"{item['role']}: {item['content']}")
return context_chunks
# Beispiel für die Verwendung (vereinfacht für die Kürze)
# kb_client = MyVectorDBClient()
# profile_store = MyRedisProfileStore()
# memory = CustomAgentMemory("user123", kb_client, profile_store)
# memory.add_to_history("user", "Mein Drucker funktioniert nicht.")
# memory.add_to_history("agent", "Welches Modell ist das?")
# context = memory.get_context("Wie behebe ich einen Papierstau bei meinem HP OfficeJet 3000?")
# print(context)
Dieser Ansatz hat uns die totale Kontrolle gegeben. Das LLM erhielt genau den Kontext, den wir wollten, in der Reihenfolge, die wir wünschten, mit dem richtigen Maß an Persistenz. Das Debuggen wurde einfach, da wir jede Zeile Code kannten. Wir mussten nicht raten, was die interne Blackbox des Frameworks tat.
Wenn die Einsatzbereiten Komponenten erneut leuchten: Die 80%-Regel
Jetzt sage ich nicht, dass Sie alle Frameworks und vorgefertigten Komponenten wegwerfen sollten. Ganz im Gegenteil! Für viele, sehr viele Agentenprojekte sind sie absolut die richtige Wahl. Wenn die Bedürfnisse Ihres Agenten gut mit den Annahmen des Frameworks übereinstimmen, sparen Sie erheblich Zeit.
Wenn Sie beispielsweise einen einfachen Chatbot erstellen, der nur Fragen aus einer einzigen Wissensquelle beantworten und einen grundlegenden Gesprächsfluss aufrechterhalten muss, sind die vorgefertigten Speicherk Komponenten eines Frameworks und die retrieval-augmented generation (RAG) perfekt. Sie erhalten Schnelligkeit, angemessene Standardwerte und eine gut getestete Grundlage.
Ein weiteres Gebiet, in dem Frameworks glänzen, ist die Orchestrierung von Werkzeugen. Ein standardisierter Weg, um Werkzeuge zu definieren, Argumente zu übergeben und deren Ausgaben zu verwalten, ist von unschätzbarem Wert. Selbst in unserem maßgeschneiderten Speicherszenario haben wir immer noch die Werkzeugausführungs-Komponente des Frameworks verwendet, da ihr Design perfekt auf unsere Bedürfnisse abgestimmt war. Wir mussten nicht neu erfinden, wie ein LLM entscheidet, welche API aufgerufen werden soll; wir mussten ihm einfach den richtigen Kontext geben, um diese Entscheidung zu treffen.
Der Schlüssel ist, die Kompromisse zu verstehen. Es ist die klassische Entscheidung „kaufen oder bauen“, aber mit einem Agenten-Twist. Kaufen (eine vorgefertigte Komponente verwenden) gibt Ihnen Geschwindigkeit und oft geringere anfängliche Entwicklungskosten. Bauen (Ihr eigenes erstellen) gibt Ihnen Kontrolle, Spezifität und oft niedrigere langfristige Wartungskosten für hochspezialisierte Agenten.
Handlungsaufforderungen für Ihr nächstes Agentenprojekt
-
Verstehen Sie das zentrale Problem Ihres Agenten tief: Bevor Sie sich überhaupt die Frameworks ansehen, definieren Sie genau, was Ihr Agent tun soll. Welche Art von Informationen muss er speichern? Wie trifft er Entscheidungen? Mit welchen externen Systemen interagiert er? Je spezifischer Sie sind, desto besser.
-
Bewerten Sie die Komponenten des Frameworks kritisch: Wählen Sie ein Framework nicht einfach nur, weil es beliebt ist. Für jede kritische Komponente (Speicher, Planung, Werkzeugausführung) fragen Sie sich:
- Stimmt die Designphilosophie dieser Komponente mit den einzigartigen Anforderungen meines Agenten überein?
- Wie viel Konfiguration oder Kapselung muss ich vornehmen, um es anzupassen?
- Was sind die zugrunde liegenden Annahmen? (Beispielsweise behandelt sein Speicher alle Kontexte gleich?)
- Wie einfach ist das Debuggen, wenn etwas mit dieser Komponente nicht stimmt? Kann ich ihren internen Zustand leicht überprüfen?
-
Scheuen Sie sich nicht zu kombinieren: Sie müssen sich nicht vollständig auf ein einziges Framework festlegen oder alles selbst erstellen. Sie können ein Framework für seine hervorragende Werkzeugorchestrierung verwenden, aber Ihren eigenen maßgeschneiderten Speicher implementieren. Oder sein Planungsmodul verwenden, aber ihm maßgeschneiderte Werkzeuge zur Verfügung stellen. Modularität ist Ihr Verbündeter.
-
Priorisieren Sie Klarheit über Einfallsreichtum (insbesondere für die zentrale Logik): Wenn Sie ein System aufbauen, das auf einem LLM basiert, um den Kontext zu interpretieren und Entscheidungen zu treffen, ist Mehrdeutigkeit Ihr Feind. Wenn das Erstellen Ihrer eigenen Komponente Ihnen eine perfekt klare Kontrolle über die Eingaben des LLM oder den Zustand Ihres Agenten gibt, ist diese Klarheit oft die zusätzliche Entwicklungszeit wert.
-
Berücksichtigen Sie die Wartungskosten: Wenn Sie eine vorgefertigte Komponente stark anpassen oder in Schichten von Abstraktion kapseln, könnten Sie sich mehr Wartungsprobleme einhandeln, als wenn Sie sie einfach von Grund auf neu gebaut hätten. Updates des zugrunde liegenden Frameworks könnten Ihre benutzerdefinierte Logik brechen, was zu mehr Refaktorisierung führt.
Mein Weg mit dem Support-Agentenprojekt hat wirklich die Idee hervorgehoben, dass „schneller“ nicht immer „günstiger“ auf lange Sicht ist. Manchmal kann es sich lohnen, sich die Zeit zu nehmen, ein zentrales Element Ihres Agentensystems selbst zu bauen, das perfekt auf Ihre einzigartigen Bedürfnisse abgestimmt ist, um Stunden des Debuggens, der Frustration und der Refaktorisierung später zu sparen. Es gibt Ihnen ein Gefühl von Eigenverantwortung und ein tieferes Verständnis für das Gehirn Ihres Agenten.
Also, beim nächsten Mal, wenn Sie ein Agentenprojekt starten, machen Sie eine Pause, bevor Sie blind das praktischste vorgefertigte Element greifen. Denken Sie darüber nach, was Ihren Agenten wirklich auszeichnet, und überlegen Sie, ob eine maßgeschneiderte Lösung letztendlich die kostengünstigste Wahl sein könnte. Viel Erfolg beim Bauen!
Verwandte Artikel
- Navigieren durch die Fallstricke: Häufige Fehler beim Erstellen autonomer Agenten
- Teststrategien für KI-Agenten
- Architekturmodelle für KI-Agenten
🕒 Published: