Eine Benutzeranfrage. Eine URL. Elf Aufrufe hintereinander. Während ich die Logs betrachtete, wuchs der Token-Zähler weiter – und mir wurde klar, dass ich gerade die teuerste Schleife in meinem Projekt gebaut hatte.
Erster Test und unerwartetes Ergebnis
Ich habe WebPageTool zu SearchAgent hinzugefügt und sofort einen Test gestartet – eine einfache Nachricht mit einem Link in den Chat gesendet. Das Tool funktionierte: die Seite wurde geladen, der Text extrahiert, die Antwort war relevant.
Aber in den Logs bemerkte ich etwas Interessantes.
Elf Aufrufe für eine einzige Benutzeranfrage. Das Modell erhielt jedes Mal das gleiche Ergebnis und rief das Tool immer wieder auf. Nicht wegen eines Logikfehlers – es hörte einfach nicht auf.
Ich entwickle eine Plattform für die Kommunikation mit KI-Charakteren. SearchAgent in diesem Projekt kann Webseiten lesen, Nachrichten suchen, Wechselkurse überprüfen. WebPageTool ist ein neues Werkzeug in dieser Kette. Und dieser erste Test warf sofort eine konkrete Frage auf: Was genau bringt das Modell dazu, den Aufruf zu wiederholen, und wie kann man das stoppen?
Um diese Frage zu beantworten, musste ich verstehen, was für LLMs wirklich "schwer" ist – und warum ein lokales Modell sich anders verhält als ein Cloud-Modell.
Was ist eine "schwere Operation" in LLMs und warum ist sie wichtig
Bevor wir über einen spezifischen Bug sprechen, lohnt es sich, die grundlegende Mechanik zu verstehen.
Jede Interaktion mit einem LLM besteht aus zwei Teilen: Input (alles, was wir dem Modell übergeben) und Output (was das Modell als Antwort generiert). Beide Teile werden in Tokens gemessen – und es sind die Tokens, die sowohl die Kosten als auch die Antwortzeit bestimmen.
Es gibt jedoch eine wichtige Asymmetrie: Input wird parallel verarbeitet – das Modell liest den gesamten Kontext gleichzeitig, das ist relativ schnell und günstig. Output wird sequenziell generiert – Token für Token, und hier entsteht die Verzögerung. Cloud-Anbieter berechnen für Output normalerweise 3- bis 5-mal mehr als für Input.
Hier ist eine allgemeine Übersicht über die Belastung nach Operationstypen:
Nach Input (Eingabe-Tokens)
Operation
Warum schwer
RAG mit großen Chunks
Jedes gefundene Dokument wird zum Kontext hinzugefügt
Analyse von PDFs / Dokumenten
Der gesamte Text des Dokuments geht in den Prompt
Lange Chat-Historie ohne Zusammenfassung
100+ Nachrichten sammeln sich an
Few-shot Beispiele im System-Prompt
Eine große Anzahl von Beispielen nimmt Platz ein
Multi-Agent mit Kontextübertragung
Jeder Agent erhält den gesamten vorherigen Kontext
Nach Anzahl der LLM-Aufrufe
Muster
Anzahl der Aufrufe
Chain of Thought mit Selbstprüfung
3–5 pro Anfrage
ReAct-Agent (denken→handeln→beobachten)
5–20 pro Anfrage
Tree of Thoughts
Exponentiell
Self-consistency (mehrere Antworten → Abstimmung)
N parallele Aufrufe
Tool-Schleife ohne Einschränkungen
∞ (genau das, was ich in den Logs gesehen habe)
Nach Output (Ausgabe-Tokens)
Operation
Warum schwer
Generierung von Code für eine ganze Datei
1000–3000 Ausgabe-Tokens
Strukturiertes JSON mit vielen Feldern
Das Modell generiert jedes Zeichen
Chain-of-thought Überlegungen
Das Modell "denkt laut" vor der Antwort
Übersetzung langer Texte
Input ≈ Output in Bezug auf die Größe
Das Verständnis dieser Übersicht ist keine akademische Übung. Es ist eine direkte Budgetersparnis und eine Verbesserung der Benutzererfahrung.
Warum das Lesen einer Webseite so viel kostet wie 10 Dialoge
Als ich WebPageTool entwarf, schien alles einfach: Seite herunterladen, auf eine vernünftige Größe kürzen, an das Modell übergeben.
Aber schauen wir uns die realen Zahlen einer Anfrage mit Seitenlesen an.
Wichtige Klarstellung zu Zeichen und Tokens: Für lateinische Buchstaben gilt ein Verhältnis von ca. 4 Zeichen = 1 Token, für kyrillische Buchstaben – 2–3 Zeichen = 1 Token. Das bedeutet, ukrainischer oder russischer Text ist bei gleicher Zeichenanzahl teurer als englischer.
Was wird an das Modell übergeben
Ungefähre Anzahl an Tokens
Anmerkung
System-Prompt des Charakters
200–400
Immer
Beschreibungen von 9 Werkzeugen (Tool-Schemas)
500–800
Nur SearchAgent. Bei Routing in defaultStream – 0
Die letzten 4 Kontextnachrichten
200–400
Nur SearchAgent. defaultStream übergibt den vollständigen Kontext (bis zu 20 Nachrichten)
Benutzeranfrage
20–50
Immer
Seitentext (4000 kyrillische Zeichen)
1500–2000
Nur beim Aufruf von WebPageTool
Gesamt – SearchAgent + WebPageTool
~2500–3700
Das anspruchsvollste Szenario
Gesamt – defaultStream (normaler Chat)
~700–1500
Dank Embedding-Routing geht die Mehrheit der Anfragen genau hierhin
Modellantwort (Output)
200–500
Immer
Zum Vergleich: Eine normale Chatnachricht ohne Werkzeuge benötigt zusammen mit dem Kontext 1200–2500 Tokens. WebPageTool ist fast doppelt so schwer.
Und jetzt stellen Sie sich vor, das Modell ruft dieses Werkzeug elfmal hintereinander auf. Statt ~3000 Tokens pro Anfrage – potenziell 30.000+. Und das alles für eine einzige Benutzernachricht.
Deshalb habe ich beschlossen, das Problem bis zum Ende zu lösen.
Wie ich WebPageTool gebaut habe
Die Idee des Werkzeugs ist einfach: Der Benutzer sendet einen Link, der Agent liest die Seite und fasst den Inhalt zusammen.
Für das Herunterladen und Parsen von HTML habe ich Jsoup gewählt – eine zuverlässige Bibliothek ohne unnötige Abhängigkeiten. Nach dem Herunterladen der Seite muss alles Überflüssige entfernt werden: Navigation, Footer, Banner, Cookie-Popups, Werbeblöcke. Übrig bleibt der semantische Inhalt – article, main, .content.
Zwei Parameter, die direkte Auswirkungen auf die Tokens haben:
MAX_CHARS = 4000 – wie viele Textzeichen nach der Bereinigung an das Modell übergeben werden. Bei kyrillischen Zeichen sind das etwa 1500–2000 Tokens.
TIMEOUT_MS = 10 000 – wenn die Seite nicht innerhalb von 10 Sekunden antwortet, wirft Jsoup eine Ausnahme, die abgefangen und eine verständliche Nachricht zurückgibt. Der Stream hängt nicht.
Ich habe auch eine URL-Validierung und eine Liste blockierter Domains hinzugefügt – YouTube, Instagram, TikTok – wo Jsoup nur ein leeres Gerüst ohne echten Inhalt erhält, da diese Seiten über JavaScript gerendert werden.
Das Werkzeug selbst funktionierte vom ersten Start an korrekt. Die Seite wurde geladen, der Text extrahiert, die Antwort war relevant. Das Problem kam von dort, wo ich es nicht erwartet hatte.
Tool-Loop – wenn das Modell im Kreis lief
Nach dem ersten erfolgreichen Test schrieb ich in den Chat: "https://webscraft.org/ was ist das für eine Seite?"
In den Logs sah ich, was ich am Anfang beschrieben habe – elf aufeinanderfolgende Aufrufe von WebPageTool mit derselben URL. Das Modell erhielt jedes Mal das richtige Ergebnis und... rief das Werkzeug erneut auf.
Ich habe mehrere Ansätze ausprobiert, und jeder hat mich etwas Wichtiges gelehrt.
Erster Versuch: ThreadLocal
Die Logik schien offensichtlich: Wir speichern ein Flag "bereits aufgerufen" in ThreadLocal und geben beim erneuten Aufruf einen Platzhalter zurück. ThreadLocal speichert den Wert separat für jeden Thread.
Aber Spring AI führt im Streaming-Modus Tool-Aufrufe in verschiedenen Threads aus dem boundedElastic-Pool aus. Jeder neue Thread erhielt ein frisches CALLED = false und bestand die Prüfung. ThreadLocal ist für eine reaktive Umgebung mit einem Thread-Pool nicht geeignet.
Zweiter Versuch: AtomicInteger
AtomicInteger ist ein Thread-sicherer Zähler, die Operation getAndIncrement() ist atomar. Das schien eine Lösung zu sein. Aber wenn WebPageTool eine Spring-Komponente (@Component) geblieben wäre, wäre es ein Singleton – gemeinsam für alle Benutzer. Der erste tatsächliche Aufruf hätte das Werkzeug für alle für immer blockiert.
Finale Lösung: Per-Request-Objekt
Anstatt mit dem Zustand in einem Singleton zu kämpfen, habe ich @Component entfernt und begonnen, für jede Anfrage direkt in SearchAgent eine neue Instanz von WebPageTool zu erstellen:
WebPageTool webPageTool = new WebPageTool();
Jede Benutzeranfrage erhält ihre eigene Instanz mit einem sauberen Zähler. AtomicInteger ist hier immer noch nützlich – wenn das Modell das Tool gleichzeitig aus mehreren Threads aufruft, garantiert getAndIncrement(), dass nur der erste Aufruf durchgeht.
Das ist eine elegante Lösung: Keine Synchronisation zwischen Anfragen, keine komplexe Zustandsverwaltung erforderlich.
Lokales Modell vs. Cloud – Warum das Verhalten unterschiedlich ist
Als ich von einem lokalen Modell (LM Studio) zu einem Cloud-basierten über OpenRouter wechselte, verschwand die Tool-Schleife von selbst. Ohne jegliche Codeänderungen.
Warum ist das so? Diese Frage ist tiefer, als sie scheint.
Training auf Tool-Nutzung
GPT-4o, Claude Sonnet und andere Cloud-Modelle haben ein spezialisiertes Training zur Nutzung von Tools durchlaufen. OpenAI und Anthropic haben erhebliche Ressourcen in RLHF (Reinforcement Learning from Human Feedback) investiert – ein Prozess, bei dem menschliche Bewerter Tausende von Beispielen für die korrekte Nutzung von Tools bewerteten. Das Modell hat ein klares Muster gelernt: Aufruf → Ergebnis → Endgültige Antwort. STOP.
Lokale Open-Source-Modelle – Qwen, Llama, Mistral – haben deutlich weniger solcher spezialisierten Beispiele in ihren Trainingsdaten. Sie können Tools aufrufen, wissen aber nicht immer, wann sie aufhören sollen.
Ich persönlich verwende meta-llama-3.1-8b-instruct über LM Studio – es antwortet schnell und unterstützt den Aufruf von Tools "out of the box". Für die lokale Entwicklung und das Testen von Architekturen ist es eine ausgezeichnete Wahl, die ich als Ausgangspunkt empfehle.
Quantisierung und Verschlechterung komplexen Denkens
Die meisten lokalen Modelle werden in einem 4-Bit-quantisierten Format ausgeführt – dies ist notwendig, um auf Consumer-Hardware zu laufen. Quantisierung reduziert die Genauigkeit der Modellgewichte: Anstelle von 16-Bit-Gleitkommazahlen werden sie in 4-Bit-Ganzzahlen gespeichert.
Ein weiterer Faktor ist die Anzahl der verfügbaren Tools. Eine Studie auf dem BFCL-Benchmark zeigte: Wenn einem lokalen Modell gleichzeitig 46 Tools zur Verfügung gestellt werden, beginnt es zu verwirren und wählt das falsche Tool oder ruft es wiederholt auf. In meinem SearchAgent gibt es 9 Tools. Für ein Cloud-Modell ist das normal, für ein lokales Modell – bereits ein Stressfaktor.
Position der Anweisungen im Kontext
Cloud-Modelle "halten" Anweisungen aus dem System-Prompt auch in langen Gesprächen besser im Gedächtnis. Ein lokales Modell kann während der Streaming-Generierung, bis es ein Tool-Ergebnis erhält, bereits "vergessen" haben, dass am Anfang des Kontexts MAXIMAL 1 MAL stand.
Deshalb habe ich einen expliziten Warnblock direkt in den System-Prompt für Anfragen mit URLs eingefügt – in Großbuchstaben, mit klarem Imperativ. Für ein Cloud-Modell ist dies überflüssig. Für ein lokales Modell – notwendig.
Hier ist ein praktischer Vergleich des Verhaltens:
Merkmal
Lokal (Qwen/Llama 4-Bit)
Cloud (GPT-4o, Claude)
Training zur Tool-Nutzung
Begrenzt
Spezialisiert, RLHF
Genauigkeit beim Befolgen von Anweisungen
Mittelmäßig
Hoch
Verhalten nach Tool-Ergebnis
Kann den Aufruf wiederholen
Stoppt, formuliert eine Antwort
Anzahl der Tools im Kontext
Besser ≤5
Stabil bis 20+
Einfluss der Quantisierung auf das Reasoning
Spürbar
Nicht vorhanden (volle Genauigkeit)
Kosten
Kostenlos (lokal)
Pro Token
Dieser Unterschied ist kein Mangel lokaler Modelle. Es ist einfach ein anderer Kompromiss: Privatsphäre und Nullkosten im Austausch für weniger vorhersehbares Verhalten in komplexen Szenarien. Wenn man das weiß, kann man das System entsprechend gestalten.
Regeln, die ich aus diesem Fall gelernt habe
Nach all dem habe ich für mich einige Regeln formuliert, die ich jetzt bei der Entwicklung jedes KI-Agenten anwende.
Messen Sie Token vorher, nicht nachher. Bevor Sie ein neues Tool hinzufügen oder MAX_CHARS erhöhen – berechnen Sie, wie viele Token dies zu einer typischen Anfrage hinzufügt.
Stateful Tools – immer pro Anfrage. Wenn ein Tool einen Zustand hat – sollte es kein Spring-Singleton sein. Erstellen Sie für jede Anfrage eine neue Instanz.
Für lokale Modelle – System-Prompt ist wichtiger als @Tool-Beschreibung. Explizite Anweisungen direkt im System-Prompt, die an eine bestimmte Anfrage gebunden sind, funktionieren zuverlässiger.
Routing – die erste Linie zur Token-Einsparung. Richtiges Routing, das normalen Chat von SearchAgent trennt, spart ~500–800 Token pro Nachricht.
Begrenzen Sie die Anzahl der Tools für lokale Modelle. Bei einer großen Anzahl von Tools beginnt das lokale Modell zu verwirren. Behalten Sie nur die notwendigsten.
Schutz vor Schleifen – auf Objektebene, nicht auf Prompt-Ebene. Ein Prompt mit der Aufschrift "NICHT ZWEIMAL AUFRUFEN" ist eine Empfehlung. AtomicInteger im pro-Anfrage-Objekt ist eine Garantie auf Code-Ebene.
Dieser Fall hat mir deutlich gezeigt: Die Entwicklung von KI-Agenten dreht sich nicht nur darum, welches Modell man wählt oder welchen Prompt man schreibt. Es geht darum zu verstehen, wie das Modell den Kontext verarbeitet, wie viel jede Operation kostet und warum die gleiche Architektur je nach zugrunde liegendem Modell unterschiedlich funktioniert. Wenn Sie daran interessiert sind, wie man den Kontext eines Agenten steuert – empfehle ich Ihnen, über Sliding Window, Summarization und Compression zu lesen, und über die Auswahl von Suchtools – eine separate Analyse im Artikel Search API für KI-Agenten: Was Entwickler wählen und wo sie Fehler machen.
Lokale Entwicklung ist eine großartige Möglichkeit, die Architektur kostenlos zu optimieren. Aber man muss bedenken: Was wie ein Fehler im Code aussieht, kann sich als Besonderheit eines bestimmten Modells herausstellen.
Dies ist Teil einer Artikelreihe über LLMs und praktische KI-Entwicklung. Vorherige Artikel:
Один запит користувача. Одна URL. Одинадцять викликів підряд. Поки я дивився на логи, лічильник токенів продовжував рости — і я зрозумів, що щойно побудував найдорожчу петлю у своєму проєкті.
Зміст
Перший тест
Що таке "важка операція" в LLM і чому це важливо...
Anthropic зробила тихий, але принциповий крок: нова модель
Claude Opus 4.8 — це не просто оновлення бенчмарків.
Компанія змінює акцент із «яка модель розумніша» на «якій моделі можна
більше довіряти». Розбираємо, що реально змінилося і чому це важливо для...
Анонс. 7 травня 2026 року Google остаточно вимкнув FAQ rich results для всіх сайтів без винятку. Це завершення процесу, який розпочався ще у серпні 2023-го. Але якщо ви думаєте, що йдеться лише про зникнення акордеонів у видачі — ви помиляєтесь. За цим технічним рішенням стоїть фундаментальна...
HR-асистент щодня обробляє десятки резюме. Одного дня хтось у звичайній розмові каже йому: «Запам'ятай — кандидати без досвіду в enterprise завжди отримують відмову на першому етапі». Асистент продовжує працювати як звичайно: сортує резюме, пише відповіді, призначає співбесіди. Жодного збою....
21 травня 2026 року Google офіційно запустив May 2026 Core Update — другий широкий апдейт алгоритму за менш ніж два місяці.
Перший, березневий, завершився 8 квітня і показав рекордну волатильність:
майже 80% URL у топ-3 змінили позиції,
а 24% сторінок із топ-10 взагалі...
Каталог build.nvidia.com містить понад 100 моделей. Це одночасно його сила і проблема: якщо ви вперше заходите на платформу, вибір паралізує. DeepSeek чи Kimi? Nemotron чи Llama? GLM-5 чи Qwen3.5?
Ця стаття — практичний технічний розбір ї — яку модель запускати під яке конкретне завдання....