Skip to content

Einstieg und Startfluss

源码版本v2026.7.20

Verantwortung

Aus «einem hermes-Befehl / einer Gateway-Nachricht (gateway message)» wird «ein im Speicher laufender Agent». Die Einstiegsschicht ist bewusst dünn gehalten – run_agent.py tut nur Weiterleiten und CLI-Zusammenbau; die echte Dependency-Injection steckt in agent_init.py. So teilen sich Gateway, TUI, CLI, ACP und cron denselben Initialisierungspfad.

Designmotiv

Einstiegsschicht dünn, Assembly zentralisiert — damit alle Aufrufpfade nur ein einziges Mal lernen. Würde AIAgent.__init__ selbst Provider (provider) auflösen, extra_body mergen, Kompressionsschwelle (compression threshold) berechnen, müssten Gateway, TUI und cron diese Logik jeweils nachbauen; eine Änderung an einer Stelle würde viele Stellen berühren. __init__ degeneriert zum reinen Forwarder; die eigentliche Entscheidung konvergiert in einer Funktion init_agent. Ein neu angedocktes Frontend (etwa ein künftiger MCP-Daemon) bekommt durch Konstruktion eines AIAgent die volle Fähigkeit, ohne die Assembly-Details zu kennen.

Dasselbe gilt für die Platzierung von hermes_bootstrap.py ganz vorne: Windows-UTF-8 ist eine «so früh wie möglich»-Korrektur; nachdem ein Kindprozess gespawned wurde, ist es zu spät. Also ist es ein eigenes Modul, das jeder Einstiegspunkt in der ersten Zeile importiert.

Schlüsseldateien

Datenfluss

  1. Der Nutzer führt hermes (CLI) aus oder das Gateway startet mit main() (run_agent.py:22965).
  2. Der Prozess durchläuft hermes_bootstrap.py für Pfad-/Umgebungskorrekturen und tritt in den CLI-Main:6434 oder die Gateway-Schleife ein.
  3. Es wird eine AIAgent:400-Instanz erzeugt; deren __init__ leitet an init_agent:276 weiter.
  4. init_agent löst Provider, Toolsets, Kompressionsschwellen, Custom-Provider-extra_body usw. auf und baut ein lauffähiges Agent-Objekt zusammen.
  5. Das Gateway hält diesen Agenten in GatewayRunner (gateway/run.py) und füttert jede eingehende Nachricht an run_conversation:588.

Der Funktionskörper von AIAgent.__init__ ist die wörtliche Ausführung von «Forwarder» — die Konstruktionsparameter werden unverändert an init_agent weitergereicht, ohne eigene Auflösung:

python
"""Forwarder — see ``agent.agent_init.init_agent``."""
from agent.agent_init import init_agent
init_agent(
    self,
    base_url=base_url,
    api_key=api_key,
    provider=provider,
    api_mode=api_mode,
    ...
)

Und das hermes_bootstrap.py, das als Erstes mit dem Prozess in Berührung kommt, macht nur auf Windows eine Codierung-Reparatur; auf POSIX gibt es direkt zurück — die Logik ist kurz:

python
if not _IS_WINDOWS:
    return False
if _bootstrap_applied:
    return False
os.environ.setdefault("PYTHONUTF8", "1")
os.environ.setdefault("PYTHONIOENCODING", "utf-8")
for stream_name in ("stdout", "stderr"):
    stream = getattr(sys, stream_name, None)
    ...
    reconfigure(encoding="utf-8", errors="replace")

Dass setdefault statt = verwendet wird, ist Absicht: Ein Nutzer kann vorab PYTHONUTF8=0 in die Umgebungsvariablen legen, um aktiv opt-out, und wird nicht überschrieben.

Grenzen und Fehler

  • Einstieg direkt konstruiert: Jemand umgeht hermes_bootstrap und startet auf Windows direkt python -m gateway.run; stdio bleibt cp1252, und nicht-ASCII-Output wirft UnicodeEncodeError. Die Position des Bootstrap ist Konvention, nicht erzwungen; die Doku verlangt, dass jeder Einstiegspunkt ihn in der ersten Zeile importiert.
  • AIAgent.__init__ wirft vor init_agent: Da der __init__-Körper nur aus Import + Aufruf besteht, kommt jeder Fehler aus dem Inneren von init_agent; der Stackframe wirkt «verschoben». Beim Debuggen ist der letzte Frame des Traceback init_agent — nicht von dem «Forwarder»-Kommentar in __init__ in die Irre führen lassen, als sei der Forwarder selbst buggy.
  • init_agent-Import ist lazy: from agent.agent_init import init_agent steht im __init__-Körper, nicht auf Modulebene, um Circular Imports zu vermeiden — agent_init importiert wiederum run_agent. Kosten: ein zusätzlicher Import bei der ersten Konstruktion eines AIAgent (Größenordnung Millisekunden); danach läuft alles über den Modul-Cache.
  • hermes_bootstrap-reconfigure kann scheitern: Ist stdout ersetzt durch BytesIO (Testszenario) oder bereits geschlossen, wirft reconfigure OSError/ValueError; der Code fängt das und überspringt stillschweigend. Der Umgebungsvariablen-Pfad greift trotzdem, sodass Kindprozesse nicht betroffen sind.

Zusammenfassung

Die Einstiegsschicht ist «Weiterleiten + Zusammenbauen» und trägt keine Geschäftslogik. AIAgent ist eine dünne Hülle, init_agent ist das eigentliche Assembly-Zentrum. Wenn diese Kette verstanden ist, beantwortet die Hauptschleife des Agenten die Frage «was passiert, nachdem eine Nachricht gefüttert wurde».

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