Skip to content

AIAgent / init_agent

源码版本v2026.7.20

Verantwortung

init_agent ist die «Aufbauwerkstatt» des Agenten: Provider (provider), Toolsets (toolsets), Kompressionsschwellen (compression thresholds), Custom-Provider-extra_body, Gedächtnis- und Lernkomponenten werden in die Agent-Instanz injiziert, sodass sie alle Abhängigkeiten besitzt, um eine Dialogrunde (turn) zu drehen. Die AIAgent-Klasse selbst ist nur die dünne Hülle über diesem Produkt.

Designmotiv

Konfiguration und Runtime zu trennen, hält den Codepfad für «eine Dialogrunde drehen» so zustandslos wie möglich. init_agent macht einmalig alle Start-Entscheidungen fest (Provider-Wahl, Kompressionsstrategie, Toolset-Schalter, extra_body-Merge); danach tritt run_conversation in den Rhythmus «Nachricht füttern → Schleife drehen» ein, ohne die Konfiguration nochmal anzufassen. Direkter Gewinn: run_conversation darf gefahrlos parallel laufen — wird dieselbe Agent-Instanz von mehreren eingehenden Nachrichten gleichzeitig angetrieben, gibt es kein «Konfiguration wird gerade geändert»-Race.

Dass die Kompressionsschwelle zur Startzeit aufgelöst wird statt erst beim Kompressionstrigger, hat einen zweiten Grund: Die 272K-Fenster der Codex-gpt-5.x-Familie brauchen eine «automatisch angehobene» Schwelle, um das Fenster voll zu nutzen — und diese Anhebung will man dem Nutzer einmal mitteilen. Zur Laufzeit jedes Mal berechnet, würde die Mitteilung entweder dauernd wiederholt oder vergessen. Startzeit einmal berechnet, Marker-Datei schreiben, später nur noch den Marker lesen.

Schlüsseldateien

Datenfluss

  1. AIAgent.__init__ (run_agent.py:423) sammelt die Konstruktionsparameter unverändert.
  2. Aufruf von init_agent:276, nacheinander:
  3. Der fertige Agent stellt die Methode run_conversation (run_agent.py:6350) zur Verfügung, die an die modulweite agent/conversation_loop.py:588 weiterleitet.
  4. Das Gateway (gateway) GatewayRunner (gateway/run.py:3029) hält den zusammengebauten Agenten und übergeben ihm eingehende Nachrichten.

Der Provider-Name wird in init_agent auf Kleinbuchstaben normalisiert, Whitespace abgeschnitten; provider dient sowohl als Routing-Hinweis als auch als Basis für den api_mode-Schluss:

python
agent.base_url = base_url or ""
provider_name = provider.strip().lower() if isinstance(provider, str) and provider.strip() else None
agent.provider = provider_name or ""
...
if api_mode in {"chat_completions", "codex_responses", "anthropic_messages", "bedrock_converse", "codex_app_server"}:
    agent.api_mode = api_mode
elif agent.provider == "openai-codex":
    agent.api_mode = "codex_responses"
elif agent.provider in {"xai", "xai-oauth"}:
    agent.api_mode = "codex_responses"

Die Auflösung der Kompressionsschwelle liegt in _resolve_compression_threshold. Codex-Autoraise ist einseitig — sie kann die Schwelle nur anheben, nicht senken, was der Nutzer bereits höher gesetzt hat:

python
if model_cthresh is None:
    return global_threshold, None
if is_codex_autoraise:
    if model_cthresh <= global_threshold + 1e-9:
        # Autoraise never lowers; keep the user's higher/equal threshold.
        return global_threshold, None
    return model_cthresh, {
        "model": model,
        "from": global_threshold,
        "to": model_cthresh,
    }
return model_cthresh, None

Der Merge des extra_body für Custom-Provider matcht konfigurierte Einträge an base_url + model und merged extra_body in request_overrides; bereits vorhandene Schlüssel des Nutzers haben Vorrang:

python
merged_extra_body = dict(extra_body)
existing_extra_body = overrides.get("extra_body")
if isinstance(existing_extra_body, dict):
    merged_extra_body.update(existing_extra_body)
overrides["extra_body"] = merged_extra_body
agent.request_overrides = overrides

Die Richtung von update ist «extra_body aus der Konfiguration als Boden, darüber der bereits vorhandene extra_body des Nutzers» — zur Laufzeit in request_overrides["extra_body"] gesteckte Felder werden nicht von der Startkonfiguration überschrieben.

Grenzen und Fehler

  • Provider-Name lässt sich nicht zu api_mode auflösen: Gibt der Nutzer provider="foobar" an, wird api_mode nicht geschlossen und fällt auf den Standard-Pfad chat_completions. Unterstützt foobar tatsächlich nur codex_responses, kommt bei der ersten Nachricht eine 400. init_agent validiert nicht, ob der Provider auf einer Whitelist steht; es normalisiert nur Groß-/Kleinschreibung.
  • Custom-extra_body-Merge-Konflikt: Sind für dieselbe base_url mehrere Einträge konfiguriert und matchen alle dasselbe Modell, gewinnt in _custom_provider_extra_body_for_agent der «erste mit explizitem Modell-Match»; die folgenden werden ignoriert. Ein Eintrag ohne model-Feld gilt als Fallback (fallback) und greift nur, wenn kein expliziter Modell-Match vorhanden ist. Hat der Nutzer die Konfiguration geändert, ohne den Agenten neu zu starten, denkt er, das neue extra_body sei aktiv, aber tatsächlich läuft noch der alte Fallback.
  • Kompressionsschwelle mit unzulässigem Wert: Ist global_threshold None oder negativ, macht _resolve_compression_threshold keine Bereichsvalidierung und reicht den Wert durch. Negativ schaltet die Kompression dauerhaft ab; None wirft beim Vergleich einen TypeError. Die Konfigurationsschicht (hermes config) hat eine Bereichsprüfung, aber init_agent validiert nicht doppelt, sondern vertraut dem Konfigurationsprodukt.
  • Autoraise-Marker schreiben fehlgeschlagen: Ist $HERMES_HOME read-only oder die Platte voll, überspringt _record_codex_gpt55_autoraise_notice stillschweigend; der Preis ist, dass beim nächsten init die Mitteilung nochmal erscheint. Das ist ein bewusster Trade-off: Ein gescheiterter Marker-Schreiben darf den Agenten nicht am Start hindern.
  • Lazy Import von _ra(): Hilfsfunktionen in init_agent holen das run_agent-Modul über _ra() statt über einen Top-Level-Import, damit Tests run_agent.OpenAI und andere Attribute monkeypatchen können, bevor sie init_agent aufrufen. Kosten: ein zusätzlicher Import beim ersten Aufruf; ist der Patch-Zeitpunkt zu spät, sind bereits gebundene Attribute nicht mehr durch den neuen Patch überdeckt.

Zusammenfassung

init_agent ist die Übersetzungsschicht von Konfiguration → Runtime; alle Start-Entscheidungen (Provider-Wahl, Kompressionsstrategie, Toolset-Schalter) fallen hier einmalig. Danach tritt der Agent in den zustandslosen Rhythmus «Nachricht füttern → Schleife drehen» ein, ohne die Konfiguration weiter zu verändern.

Inoffizielle Community-Lernseite. Basiert auf dem MIT-lizenzierten NousResearch/hermes-agent-Quellcode.