JamJet

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

AnsatzAm besten geeignet fürStateBeispiel
Agent + Workflow SDKMulti-Agenten-Systeme mit ReasoningPydantic BaseModel (typisiert, validiert)claims-processing, wealth-management
YAML-WorkflowsTool-Pipelines, config-getriebene FlowsSchema in YAML (typisiert)rag-assistant
Python-Decorator-APICustom-Logik, Zugriff auf Python-LibrariesDict-basierter StatePython 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: summary

Wä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 id und version
  • 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: think

Workflows 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-TypWas er tut
modelRuft ein LLM auf (Claude, GPT-4, Gemini, etc.)
toolRuft ein externes Tool über MCP auf
httpFührt eine HTTP-Anfrage aus
branchLeitet die Ausführung basierend auf einer Bedingung weiter
parallelVerzweigt gleichzeitig in mehrere Branches
waitPausiert bis zu einem externen Event
evalBewertet die Ausgabequalität (Rubrik, Assertion, Latenz)
endBeendet 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 Ausgabe

State 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:

  1. Bevor jeder Knoten läuft, wird ein node_started-Event in die Datenbank geschrieben
  2. Nach Abschluss jedes Knotens wird ein node_completed-Event mit dem State-Patch geschrieben
  3. Bei einem Neustart rekonstruiert der Scheduler das Event-Log, um exakt zu ermitteln, wo die Ausführung gestoppt wurde
  4. 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:

  1. Pollt die Ausführungs-Queue nach anstehenden Arbeiten
  2. Erwirbt eine Sperre auf die Ausführung, um doppelte Läufe zu verhindern
  3. Verteilt Knoten an Worker-Threads
  4. 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

Featurejamjet dev (lokal)Hosted / Self-hosted
SpeicherungSQLitePostgreSQL
WorkersEinzelprozessVerteilt
MCP-ServerLokales stdioRemote SSE/HTTP
AuthentifizierungKeinemTLS / API-Keys

Das Programmiermodell ist identisch — derselbe YAML- oder Python-Code läuft unverändert in beiden Umgebungen.


Nächste Schritte

On this page