JamJet

핵심 개념

JamJet의 에이전트, 노드, 상태 및 내구성을 이해합니다.

핵심 개념

JamJet은 AI 에이전트를 위한 내구성 런타임입니다. 핵심 아이디어는 간단합니다. 워크플로는 일시적인 함수 호출이 아닌 복구 가능한 상태 전환으로 실행됩니다. 이것이 재생, 크래시 복구, 승인 일시 정지, 정확한 추적을 가능하게 만듭니다. 이 페이지는 핵심 프리미티브를 다룹니다.

작성 방식 선택하기

JamJet은 에이전트를 구축하는 세 가지 방법을 제공합니다. 세 가지 모두 동일한 IR로 컴파일되고 동일한 Rust 런타임에서 실행되며, 각각을 사용하는 시점에서 차이가 있습니다.

의사결정 플로우차트

에이전트가 추론 전략(react, plan-and-execute, critic)을 사용하여
LLM을 호출하나요?

├─ 예 → Agent + Workflow SDK 사용
│        (from jamjet import Agent, Workflow, tool)

└─ 아니오 → 플로우가 주로 도구 오케스트레이션, 라우팅 또는
             코드 배포 없이 변경하고 싶은 설정인가요?

        ├─ 예 → YAML 워크플로우 사용

        └─ 아니오 → Python 데코레이터 API 사용
                 (@workflow, @node)

세 가지 방식

방식적합한 경우상태예시
Agent + Workflow SDK추론 기능이 있는 멀티 에이전트 시스템Pydantic BaseModel (타입 지정, 검증됨)claims-processing, wealth-management
YAML 워크플로우도구 파이프라인, 설정 기반 플로우YAML 스키마 (타입 지정됨)rag-assistant
Python 데코레이터 API커스텀 로직, Python 라이브러리 접근Dict 기반 StatePython SDK docs

Agent + Workflow SDK

에이전트가 사고해야 할 때 — 도구를 선택하고, 결과를 추론하고, 출력을 개선해야 할 때 사용하세요. 각 에이전트는 작업에 맞는 추론 전략을 가집니다.

from jamjet import Agent, Workflow, tool
from pydantic import BaseModel

@tool
def search_web(query: str) -> dict:
    """웹에서 정보를 검색합니다."""
    ...

researcher = Agent(
    name="researcher",
    model="claude-sonnet-4-6",
    tools=[search_web],
    instructions="주어진 주제에 대한 정확한 정보를 찾습니다.",
    strategy="react",        # 긴밀한 도구 사용 루프
    max_iterations=5,
)

writer = Agent(
    name="writer",
    model="claude-sonnet-4-6",
    instructions="연구 내용을 바탕으로 명확한 요약을 작성합니다.",
    strategy="critic",       # 초안 → 평가 → 개선
    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})

다음의 경우 선택하세요: 에이전트에 전략(react, plan-and-execute, critic, consensus, debate)이 필요한 경우, 타입이 지정된 Pydantic 상태가 필요한 경우, 사람의 개입이 필요한 경우(human_approval=True), 또는 여러 전문 에이전트가 협업하는 경우.

YAML 워크플로우

플로우가 결정론적 오케스트레이션인 경우 사용하세요 — 이 도구를 호출하고, 그 다음 모델을 호출하고, 조건에 따라 라우팅합니다. 에이전트 추론이 필요하지 않습니다.

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

다음과 같은 경우 선택: 플로우가 도구와 모델의 고정된 파이프라인이고, 개발자가 아닌 사람이 플로우를 편집해야 하거나, 코드를 재배포하지 않고 라우팅을 변경해야 할 때.

Python 데코레이터 API

노드 내부에서 커스텀 Python 로직이 필요한 경우 사용하세요 — 데이터 변환, 라이브러리 호출, YAML로는 너무 복잡한 조건부 로직.

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}

다음과 같은 경우 선택: 노드 내부에서 Python 라이브러리가 필요하거나, 로직이 YAML로는 너무 복잡하지만 에이전트 추론은 필요하지 않거나, 클래스 기반 워크플로우를 선호할 때.

혼합해서 사용할 수 있나요?

네. 세 가지 모두 동일한 IR로 컴파일됩니다. YAML 워크플로우는 에이전트를 도구로 호출할 수 있습니다. Python 워크플로우 단계는 YAML로 정의된 서브 워크플로우를 실행할 수 있습니다. 런타임은 어떤 작성 방식으로 IR이 생성되었는지 신경 쓰지 않습니다.


워크플로우

워크플로우는 노드의 방향성 그래프입니다. 다음을 포함합니다:

  • 고유한 idversion
  • state_schema — 그래프를 통해 흐르는 데이터의 타입 구조
  • 실행이 시작되는 start 노드
  • 하나 이상의 end 노드
workflow:
  id: my-agent
  version: 0.1.0
  state_schema:
    query: str
    answer: str
    confidence: float
  start: think

워크플로우는 실행 전에 IR(중간 표현) 그래프로 컴파일됩니다. IR은 Rust 스케줄러가 실제로 실행하는 것이며 — YAML과 Python은 단지 작성 인터페이스일 뿐입니다.

노드

노드는 워크플로우의 연산 단위입니다. 각 노드는 작동 방식을 결정하는 type을 가집니다:

노드 타입기능
modelLLM 호출 (Claude, GPT-4, Gemini 등)
toolMCP를 통해 외부 도구 호출
httpHTTP 요청 실행
branch조건에 따라 실행 경로 분기
parallel여러 브랜치로 동시 실행 분산
wait외부 이벤트까지 실행 일시 중지
eval출력 품질 평가 (루브릭, 어설션, 지연시간)
end워크플로우 종료

모든 노드는 state에서 읽고 쓰기를 수행합니다.

State

State는 워크플로우 실행의 공유 데이터 저장소입니다. 노드 간, 재시작 간에도 지속됩니다.

state_schema:
  query: str        # 사용자 입력
  search_results: list[str]  # 중간 데이터
  answer: str       # 최종 출력

State는 타입이 지정됨 — 스키마는 컴파일 시점에 검증됩니다. 런타임에서 각 노드는 모든 state 키를 읽고 자신의 output_key에 쓸 수 있습니다.

tip: State는 메모리가 아닌 데이터베이스에 저장됩니다. 실행 중 런타임이 충돌하더라도 state는 완전히 복구되며, 마지막 체크포인트부터 실행이 재개됩니다.

실행

**실행(execution)**은 특정 입력으로 워크플로우를 한 번 실행하는 것입니다. 각 실행은 고유 ID를 받습니다 (예: exec_01JM4X8NKWP2).

실행의 특징:

  • 내구성 — 데이터베이스에 저장되어 재시작에도 유지됨
  • 관찰 가능 — 모든 state 전환이 이벤트로 기록됨
  • 검사 가능jamjet inspect로 전체 state, 이벤트 타임라인, 토큰 사용량 확인 가능

내구성

내구성은 JamJet의 핵심 보장 사항입니다: 런타임이 충돌하더라도 실행은 항상 완료됩니다.

이는 이벤트 소싱을 통해 작동합니다:

  1. 각 노드가 실행되기 전에 node_started 이벤트가 데이터베이스에 기록됩니다
  2. 각 노드가 완료된 후 상태 패치와 함께 node_completed 이벤트가 기록됩니다
  3. 재시작 시 스케줄러는 이벤트 로그를 재생하여 실행이 중단된 정확한 지점을 재구성합니다
  4. 실행은 완료되지 않은 첫 번째 노드부터 재개됩니다

작업은 손실되지 않습니다. 노드가 두 번 실행되지 않습니다.

참고: 이는 "최소 한 번" 전달 방식과 다릅니다. JamJet의 스케줄러는 분산 락을 사용하여 여러 워커 프로세스가 있어도 각 노드가 정확히 한 번 실행되도록 보장합니다.

에이전트

에이전트는 다음을 수행할 수 있는 워크플로입니다:

  • 다른 에이전트가 발견하고 호출할 수 있음 (Agent Card를 통해)
  • 다른 에이전트에게 작업 위임 (A2A 프로토콜을 통해)
  • 여러 사용자 상호작용에 걸쳐 장기 실행 상태 유지

모든 에이전트는 Agent Card를 가지고 있습니다 — 기능, 엔드포인트, 입출력 스키마에 대한 기계 판독 가능한 설명입니다. 이는 A2A 프로토콜의 기반입니다.

스케줄러

JamJet 스케줄러는 Rust로 작성되었으며 jamjet dev(로컬) 또는 호스팅 런타임(프로덕션)의 일부로 실행됩니다.

작동 방식:

  1. 실행 큐에서 대기 중인 작업을 폴링합니다
  2. 중복 실행을 방지하기 위해 실행에 대한 락을 획득합니다
  3. 워커 스레드로 노드를 디스패치합니다
  4. 각 노드 이후 체크포인트를 기록합니다

스케줄러는 JamJet 워크플로가 기본적으로 내구성을 갖는 이유입니다 — 실행을 절대 잊지 않습니다.

로컬 vs. 프로덕션

기능jamjet dev (로컬)호스팅 / 자체 호스팅
스토리지SQLitePostgreSQL
워커단일 프로세스분산
MCP 서버로컬 stdio원격 SSE/HTTP
인증없음mTLS / API 키

프로그래밍 모델은 동일합니다 — 동일한 YAML 또는 Python 코드가 두 환경 모두에서 변경 없이 실행됩니다.


다음 단계

On this page