Kernkonzepte
Verstehen Sie Agents, Nodes, State und Durability in JamJet.
Kernkonzepte
JamJet ist eine dauerhafte Laufzeitumgebung für KI-Agenten. Die Kernidee ist einfach: Workflows werden als wiederherstellbare Zustandsübergänge ausgeführt, nicht als flüchtige Funktionsaufrufe. Das ermöglicht Replay, Crash-Recovery, Freigabepausen und exakte Traces. Diese Seite behandelt die wichtigsten Grundbausteine.
Auswahl eines Authoring-Ansatzes
JamJet bietet drei Möglichkeiten zum Erstellen von Agenten. Alle drei kompilieren zur gleichen IR und laufen auf derselben Rust-Runtime — sie unterscheiden sich darin, wann man zu welchem greift.
Entscheidungsflussdiagramm
Ruft Ihr Agent LLMs mit Reasoning-Strategien auf
(react, plan-and-execute, critic)?
│
├─ JA → Verwenden Sie das Agent + Workflow SDK
│ (from jamjet import Agent, Workflow, tool)
│
└─ NEIN → Besteht der Flow hauptsächlich aus Tool-Orchestrierung, Routing
oder Config, die Sie ohne Code-Deploys ändern möchten?
│
├─ JA → Verwenden Sie YAML-Workflows
│
└─ NEIN → Verwenden Sie die Python-Decorator-API
(@workflow, @node)Die drei Ansätze
| Ansatz | Am besten geeignet für | State | Beispiel |
|---|---|---|---|
| Agent + Workflow SDK | Multi-Agenten-Systeme mit Reasoning | Pydantic BaseModel (typisiert, validiert) | claims-processing, wealth-management |
| YAML-Workflows | Tool-Pipelines, config-getriebene Flows | Schema in YAML (typisiert) | rag-assistant |
| Python-Decorator-API | Custom-Logik, Zugriff auf Python-Libraries | Dict-basierter State | Python SDK Docs |
Agent + Workflow SDK
Verwenden Sie dies, wenn Ihre Agenten denken müssen — Tools wählen, über Ergebnisse nachdenken, Outputs verfeinern. Jeder Agent erhält eine Reasoning-Strategie, die zu seiner Aufgabe passt.
from jamjet import Agent, Workflow, tool
from pydantic import BaseModel
@tool
def search_web(query: str) -> dict:
"""Search the web for information."""
...
researcher = Agent(
name="researcher",
model="claude-sonnet-4-6",
tools=[search_web],
instructions="Find accurate information on the given topic.",
strategy="react", # tight tool-use loop
max_iterations=5,
)
writer = Agent(
name="writer",
model="claude-sonnet-4-6",
instructions="Write a clear summary from the research.",
strategy="critic", # draft → evaluate → refine
max_iterations=3,
)
workflow = Workflow("research-writer", version="0.1.0")
@workflow.state
class ResearchState(BaseModel):
topic: str
research: str | None = None
summary: str | None = None
@workflow.step
async def research(state: ResearchState) -> ResearchState:
result = await researcher.run(f"Research: {state.topic}")
return state.model_copy(update={"research": result.output})
@workflow.step
async def write(state: ResearchState) -> ResearchState:
result = await writer.run(f"Summarize:\n{state.research}")
return state.model_copy(update={"summary": result.output})Wählen Sie dies, wenn: Agenten Strategien benötigen (react, plan-and-execute, critic, consensus, debate), Sie typisierten Pydantic-State wollen, Sie human-in-the-loop benötigen (human_approval=True) oder mehrere spezialisierte Agenten zusammenarbeiten.
YAML-Workflows
Nutzen Sie dies, wenn der Ablauf deterministische Orchestrierung ist — rufen Sie dieses Tool auf, dann jenes Modell, routen Sie basierend auf einer Bedingung. Kein Agent-Reasoning erforderlich.
id: summarize-url
version: "0.1.0"
nodes:
fetch:
type: tool
server: web-fetcher
tool: fetch_page
arguments:
url: "{{ state.url }}"
output_key: page_content
next: summarize
summarize:
type: model
model: claude-haiku-4-5-20251001
prompt: "Summarize: {{ state.page_content }}"
output_key: summaryWählen Sie dies, wenn: der Ablauf eine feste Pipeline aus Tools und Modellen ist, Sie möchten, dass Nicht-Entwickler den Ablauf bearbeiten können, oder Sie das Routing ohne Code-Neubereitstellung ändern müssen.
Python-Dekorator-API
Nutzen Sie dies, wenn Sie eigene Python-Logik innerhalb von Nodes benötigen — Datentransformationen, Bibliotheksaufrufe, bedingte Logik, die für YAML zu komplex ist.
from jamjet import workflow, node, State
@workflow(id="data-processor", version="0.1.0")
class DataProcessor:
@node(start=True)
async def process(self, state: State) -> State:
import pandas as pd
df = pd.read_csv(state["file_path"])
summary = df.describe().to_dict()
return {"analysis": summary}
@node
async def report(self, state: State) -> State:
response = await self.model(
model="claude-sonnet-4-6",
prompt=f"Write a report from this analysis:\n{state['analysis']}",
)
return {"report": response.text}Wählen Sie dies, wenn: Sie Python-Bibliotheken innerhalb von Nodes benötigen, die Logik für YAML zu komplex ist, aber kein Agent-Reasoning erfordert, oder Sie klassenbasierte Workflows bevorzugen.
Kann ich sie kombinieren?
Ja. Alle drei kompilieren zur selben IR. Ein YAML-Workflow kann einen Agent-als-Tool aufrufen. Ein Python-Workflow-Schritt kann einen YAML-definierten Sub-Workflow aufrufen. Die Runtime unterscheidet nicht, welche Authoring-Oberfläche die IR erzeugt hat.
Workflows
Ein Workflow ist ein gerichteter Graph aus Nodes. Er hat:
- Eine eindeutige
idundversion - Ein
state_schema— die typisierte Form der Daten, die durch den Graphen fließen - Einen
start-Node, bei dem die Ausführung beginnt - Einen oder mehrere
end-Nodes
workflow:
id: my-agent
version: 0.1.0
state_schema:
query: str
answer: str
confidence: float
start: thinkWorkflows werden vor der Ausführung zu einem IR (Intermediate Representation)-Graphen kompiliert. Die IR ist das, was der Rust-Scheduler tatsächlich ausführt — YAML und Python sind lediglich Authoring-Oberflächen.
Nodes
Nodes sind die Berechnungseinheiten in einem Workflow. Jeder Node hat einen type, der bestimmt, was er tut:
| Node-Typ | Was er tut |
|---|---|
model | Ruft ein LLM auf (Claude, GPT-4, Gemini, etc.) |
tool | Ruft ein externes Tool über MCP auf |
http | Führt eine HTTP-Anfrage aus |
branch | Leitet die Ausführung basierend auf einer Bedingung weiter |
parallel | Verzweigt gleichzeitig in mehrere Branches |
wait | Pausiert bis zu einem externen Event |
eval | Bewertet die Ausgabequalität (Rubrik, Assertion, Latenz) |
end | Beendet den Workflow |
Jeder Node liest aus dem State und schreibt in ihn.
State
State ist der gemeinsame Datenspeicher für eine Workflow-Ausführung. Er bleibt über Nodes und Neustarts hinweg bestehen.
state_schema:
query: str # Eingabe vom Benutzer
search_results: list[str] # Zwischendaten
answer: str # Endgültige AusgabeState ist typisiert — das Schema wird zur Compile-Zeit validiert. Zur Laufzeit kann jeder Node jeden State-Key lesen und in seinen output_key schreiben.
tip: State wird in der Datenbank gespeichert, nicht im Arbeitsspeicher. Wenn die Runtime mitten in der Ausführung abstürzt, wird der State vollständig wiederhergestellt und die Ausführung vom letzten Checkpoint fortgesetzt.
Executions
Eine Execution ist ein einzelner Durchlauf eines Workflows mit einer spezifischen Eingabe. Jede Execution erhält eine eindeutige ID (z. B. exec_01JM4X8NKWP2).
Executions sind:
- Durable — in der Datenbank gespeichert, überstehen Neustarts
- Observable — jede State-Transition wird als Event aufgezeichnet
- Inspectable — vollständiger State, Event-Timeline und Token-Nutzung einsehbar mit
jamjet inspect
Dauerhaftigkeit
Dauerhaftigkeit ist JamJets zentrale Garantie: Ausführungen werden immer abgeschlossen, selbst wenn die Laufzeitumgebung abstürzt.
Dies funktioniert durch Event Sourcing:
- Bevor jeder Knoten läuft, wird ein
node_started-Event in die Datenbank geschrieben - Nach Abschluss jedes Knotens wird ein
node_completed-Event mit dem State-Patch geschrieben - Bei einem Neustart rekonstruiert der Scheduler das Event-Log, um exakt zu ermitteln, wo die Ausführung gestoppt wurde
- Die Ausführung wird beim ersten unvollständigen Knoten fortgesetzt
Keine Arbeit geht verloren. Kein Knoten läuft zweimal.
note: Dies unterscheidet sich von "at-least-once"-Zustellung. JamJets Scheduler verwendet verteilte Sperren, um sicherzustellen, dass jeder Knoten genau einmal läuft, selbst bei mehreren Worker-Prozessen.
Agents
Ein Agent ist ein Workflow, der:
- Von anderen Agents entdeckt und aufgerufen werden kann (via Agent Cards)
- Aufgaben an andere Agents delegieren kann (via A2A-Protokoll)
- Lang laufende States über mehrere Benutzerinteraktionen hinweg verwalten kann
Jeder Agent hat eine Agent Card — eine maschinenlesbare Beschreibung seiner Fähigkeiten, Endpunkte und Input/Output-Schemata. Dies ist die Grundlage für das A2A-Protokoll.
Der Scheduler
Der JamJet-Scheduler ist in Rust geschrieben und läuft als Teil von jamjet dev (lokal) oder der gehosteten Laufzeitumgebung (in Produktion).
Er:
- Pollt die Ausführungs-Queue nach anstehenden Arbeiten
- Erwirbt eine Sperre auf die Ausführung, um doppelte Läufe zu verhindern
- Verteilt Knoten an Worker-Threads
- Schreibt Checkpoints nach jedem Knoten
Der Scheduler ist der Grund, warum JamJet-Workflows standardmäßig dauerhaft sind — er vergisst niemals eine Ausführung.
Lokal vs. Produktion
| Feature | jamjet dev (lokal) | Hosted / Self-hosted |
|---|---|---|
| Speicherung | SQLite | PostgreSQL |
| Workers | Einzelprozess | Verteilt |
| MCP-Server | Lokales stdio | Remote SSE/HTTP |
| Authentifizierung | Keine | mTLS / API-Keys |
Das Programmiermodell ist identisch — derselbe YAML- oder Python-Code läuft unverändert in beiden Umgebungen.
Nächste Schritte
- Schnellstart — bauen Sie Ihren ersten dauerhaften Agenten
- Python SDK — Dekoratoren, Routing, parallele Schritte
- Absturz-Wiederherstellung ausprobieren — sehen Sie Dauerhaftigkeit in Aktion