Lerneinheit · Verstehen durch Bauen

Bau dein eigenes Tiny-Agents-System

Concierge und Runner selbst gebaut: ein Router ohne LLM-Call, ein Agent mit frischem Kontext, eine harte Kompressionsgrenze. In acht Schritten, gegen einen beliebigen OpenAI-kompatiblen Endpunkt.

8 Schritte · rund 210 Minuten Bauzeit

Ein Agent mit fünf Werkzeugen funktioniert. Ein Agent mit zweihundert nicht mehr

  • und zwar aus zwei völlig verschiedenen Gründen, die dauernd in einen Topf geworfen werden. Der Baustein Tiny Agents erklärt diese beiden Gründe und die Architektur, die sie trennt. Dieser Kurs baut sie.

Am Ende hast du ein Verzeichnis tiny-agents/, in dem ein Concierge ohne einen einzigen LLM-Aufruf entscheidet, wer eine Anfrage bearbeitet, und ein Runner, der den gewählten Agenten mit frischem Kontext, seinen eigenen ein bis fünf Werkzeugen und einem Budget startet, das nicht verhandelbar ist. Dazu ein Artefakt-Speicher, der aus 38.000 Token gescraptem Text einen Digest von 800 macht, ohne den Rest wegzuwerfen.

Die Regel: kein Framework

Eine Regel hält den Kurs zusammen, und sie ist dieselbe wie in Bau dein eigenes PyTorch: Don't import it, build it.

Erlaubt sind ein HTTP-Client, ein YAML-Parser und NumPy. Also httpx (oder requests), pyyaml, numpy. Wer will, nimmt zusätzlich tiktoken zum Zählen

  • das ist Buchhaltung, nicht Architektur.

Verboten sind Agenten-Frameworks jeder Art: LangChain, LlamaIndex, CrewAI, AutoGen, smolagents, das Agents SDK. Sie würden dir genau die drei Bauteile abnehmen, um die es hier geht: Routing, Kontextverwaltung, Budget-Durchsetzung.

Ausdrücklich nicht verboten, aber nicht nötig: eine Vektordatenbank. Der Router dieses Kurses hält seine Beispiele in einer Python-Liste und rechnet Kosinus-Ähnlichkeit mit einem NumPy-Einzeiler. Bei ein paar hundert Beispielen ist das nicht die Sparversion, sondern die ehrliche: Du siehst dabei, dass Qdrant an dieser Stelle eine Optimierung ist und kein Baustein. Wann sie sich lohnt, steht am Ende von Kapitel 03.

Was du brauchst

Python 3.11 oder neuer. Alles andere ist eine pip install-Zeile.

Einen OpenAI-kompatiblen Endpunkt. Das ist die einzige externe Abhängigkeit des Kurses, und es ist bewusst die schwächste mögliche: Alles, was /v1/chat/completions und /v1/embeddings spricht, genügt. Lokal über Ollama, gemietet über OpenRouter, selbst gehostet über vLLM oder LiteLLM. Der Kurs redet nie mit einem Anbieter-SDK, nur mit zwei URLs.

export TINY_BASE_URL="http://localhost:11434/v1"   # Ollama lokal
export TINY_API_KEY="ollama"                       # Ollama ignoriert ihn, andere nicht
export TINY_CHAT_MODEL="qwen3:8b"
export TINY_EMBED_MODEL="bge-m3"

Ein Chat-Modell, das Werkzeugaufrufe beherrscht. Ab Kapitel 05 brauchst du tools im Request. Kleine Modelle können das oft schlechter, als ihre Modellkarte behauptet - wenn dein Runner reihenweise Geisteraufrufe zählt, ist das erst mal ein Modellbefund und kein Bug in deinem Code. Genau deshalb zählt Kapitel 05 sie überhaupt.

Ein mehrsprachiges Embedding-Modell. Das ist die eine Stelle, an der eine falsche Wahl den ganzen Kurs kaputtmacht: Ein englischlastiges Modell wie all-MiniLM-L6-v2 bricht beim Routing deutscher Anfragen ein, und du suchst den Fehler stundenlang in deinem Schwellwert. Empfohlen ist bge-m3 - läuft lokal in Ollama (ollama pull bge-m3) und liegt bei den meisten Anbietern ebenfalls. Alternative: multilingual-e5-large, das aber Präfixe erwartet (query: vor der Anfrage, passage: vor dem Beispiel). Wer die vergisst, verliert Trefferqualität, ohne dass irgendetwas kaputtgeht - eine der unangenehmeren Fehlerklassen.

Der Aufbau

Am Ende von Kapitel 08 sieht dein Repo so aus. Es wächst Kapitel für Kapitel dorthin, du legst also jetzt nur tiny-agents/ und tiny/ an:

tiny-agents/                ← dein Repo
├── registry/               ← die Cards, ab Kapitel 02
│   ├── web-reader.card.yaml
│   ├── crm-writer.card.yaml
│   └── docs-finder.card.yaml
├── tiny/                   ← das Paket
│   ├── __init__.py         (leer)
│   ├── llm.py              (03) OpenAI-kompatibler Client
│   ├── cards.py            (02) Format und Validator
│   ├── index.py            (03) Embeddings und Kosinus
│   ├── concierge.py        (03, 04) der Router
│   ├── tools.py            (05) die Werkzeug-Registry
│   ├── runner.py           (05, 06) Invocation-Schleife
│   └── artifacts.py        (07) Handle und expand()
└── scripts/
    ├── 01_token_vergleich.py
    ├── 03_router_eval.py
    └── 08_abc.py

Jedes Kapitel endet mit einem lauffähigen Stand. Nicht mit einem grünen Test, sondern mit einem Befehl, den du eingibst, und einer Ausgabe, die du liest: eine Zahl, eine Rangliste, eine Ablehnung. Das ist Absicht - dieser Kurs baut ein System, dessen ganzer Wert an Zahlen hängt, die man vorher nicht kennt.

Was dieser Kurs bewusst nicht baut

Der Prototyp, nicht das Produktionssystem. Drei Dinge, die ein echtes Tiny-Agents-System braucht, kommen hier nicht vor, und das steht am Ende von Kapitel 08 noch einmal ausführlich:

  • Traces in einer Datenbank. Der Kurs loggt nach stdout und in eine JSONL-Datei. Wer Routing-Entscheidungen über Wochen auswerten will, braucht Postgres.
  • Learned Routing. Bestätigte Routings zurück in den Index zu schreiben, ist Phase 2 - und ohne Traces ohnehin nicht möglich.
  • Gap-Clustering. Dass jeder Abstain die Roadmap für den nächsten Agenten ist, baust du in Kapitel 04 als Logzeile. Diese Logzeilen automatisch zu gruppieren, ist ein eigenes kleines Projekt.

Der Fachstoff hinter all dem steht in den sieben Kapiteln des Bausteins Tiny Agents, von „Zwei Probleme, zwei Größenordnungen“ bis „Was das kostet“. Du kannst den Kurs ohne sie fahren. Wer wissen will, warum eine Entscheidung so und nicht anders fällt, findet die Begründung dort.

Der Fahrplan

8 Schritte, je eine Einsicht und ein lauffähiger Stand. Jeder Schritt steht auf dem vorigen.

  1. 01
    Das Problem messen20 min

    Werkzeugliste und Werkzeugausgabe sind zwei Probleme mit zwei Größenordnungen.

    Meilenstein Ein Skript stellt die Token einer Werkzeugliste und einer einzigen gescrapten Seite nebeneinander, der Faktor steht als Zahl da.

  2. 02
    Die Capability Card25 min

    Ein Artefakt ist gleichzeitig Registrierung, Doku, Routing-Index und Testfall.

    Meilenstein Drei handgeschriebene Cards laufen durch den Validator, eine absichtlich kaputte wird mit lesbarer Meldung abgewiesen.

  3. 03
    Der Positiv-Index30 min

    Geroutet wird Anfrage gegen Anfrage, nicht Anfrage gegen Beschreibung.

    Meilenstein Für zwölf Testanfragen steht der richtige Agent auf Platz 1, Recall@1 wird als Zahl ausgegeben.

  4. 04
    Veto und Abstain20 min

    Ein Router ohne Schwellwert routet auch Unsinn, die Ablehnung ist ein Feature.

    Meilenstein „mach mir ein butterbrot“ wird ehrlich abgelehnt statt geroutet, und ein Counter-Example zieht seinen Agenten aus der Liste.

  5. 05
    Der Runner35 min

    Die Isolation kommt vom frischen Kontext, nicht vom eigenen Prozess.

    Meilenstein Ein Runner-Prozess bedient drei Cards mit je eigenem Kontext, ein Geisteraufruf wird erkannt und gezählt.

  6. 06
    Brief, Digest, Budget30 min

    Ein Budget, das im Systemprompt steht, ist keins.

    Meilenstein Eine Seite mit 38.000 Token kommt als Digest unter 800 Token zurück, mit genau einem Reparaturversuch am Schema.

  7. 07
    Der Artefakt-Speicher25 min

    Kompression ist erst dann vertretbar, wenn sie rückholbar ist.

    Meilenstein Eine Information, die im Digest fehlte, wird per expand() nachgeholt, ohne dass die 38.000 Token den Hauptkontext berühren.

  8. 08
    Messen, ob es was bringt25 min

    Eine These, die nicht scheitern kann, ist keine.

    Meilenstein Die eigene A/B/C-Kurve über wachsendes N steht als Tabelle da, auch „bringt hier nichts“ ist ein gültiges Ergebnis.