tokio-prompt-orchestrator

Rust 크레이트 · Tokio · MIT

사용자와 LLM 사이에 용량 제한 파이프라인을 두세요.

중복된 프롬프트는 모델 호출 한 번을 함께 씁니다. 프로바이더에 장애가 나면 서킷 브레이커가 작동해 요청이 쌓이지 않고 즉시 실패합니다. 파이프라인이 버린 요청은 모두 데드 레터 큐에 들어가며, 확인하고 다시 실행할 수 있습니다. Anthropic, OpenAI, llama.cpp, vLLM 또는 직접 만든 백엔드와 함께 동작합니다.

Windows용 다운로드 (.exe) macOS, Linux, Homebrew, Scoop, cargo
cargo run --example llm_pipeline
API 키가 필요 없습니다. 아래 그림과 똑같은 시나리오를 실행합니다.

실제 실행 한 번을 다시 보기

사용자 4명이 요청 12개로 질문 3개를 보내고, 이어서 모의 프로바이더 장애 중에 8개가 더 도착합니다. 점 하나가 요청 하나이고, 모든 타임스탬프는 기록된 실행에서 가져온 것이며 다섯 배 느리게 재생합니다.

시간0.0 ms
모델 호출0
응답 완료0
브레이커closed
DLQ 대기0

출처: llm_pipeline_trace.json, 내장 모의 모델(호출당 300 ms)로 cargo run --example llm_pipeline 실행, 디버그 빌드, Windows x86_64.

중복 제거

동일한 프롬프트는 키로 묶여 하나로 합쳐집니다. 이 실행에서 요청 12개가 모델 호출 3번이 되었고, 중복 9개는 중복 제거 캐시에서 총 0.3 ms 만에 응답했습니다.

enhanced::Deduplicator

서킷 브레이커

3단계의 모든 워커 호출을 감쌉니다. 5번 실패하면 열리고, 이후 요청은 프로바이더에 닿지 않고 거부됩니다. 60 s 후 다시 확인합니다.

enhanced::CircuitBreaker

데드 레터 큐

조용히 버려지는 요청은 없습니다. 채널 포화, 타임아웃, 기한 만료, 실패, 브레이커 거부는 모두 이유와 함께 1000개짜리 링 버퍼에 들어갑니다.

handles.dlq.drain()

백프레셔

Tokio 태스크 다섯 개를 용량 제한 채널(512, 512, 512, 1024, 512, 256)로 연결합니다. 모델이 느려지면 프로듀서가 기다리거나 요청을 버리므로 부하가 걸려도 메모리 사용량이 일정합니다.

spawn_pipeline(worker)

그 실행의 출력

이 예제는 약 200줄이며, 직접 만든 백엔드를 연결할 때 좋은 템플릿입니다. 키와 함께 PROVIDER=anthropic 또는 PROVIDER=openai를 설정하면 실제 모델로 같은 3번의 호출을 보냅니다. 장애는 프로바이더 앞단에서 모의로 일으키므로 비용이 들지 않습니다.

examples/llm_pipeline.rs 보기

cargo run --example llm_pipeline

  

요청이 흐르는 방식

복원력은 3단계에 있습니다. ModelWorker를 둘러싸고 기한 확인, 서킷 브레이커, 타임아웃이 동작합니다. 중복 제거, 재시도, 캐싱, 속도 제한, 로드 밸런싱은 워커 바깥에 감싸는 빌딩 블록이며, 예제가 Deduplicator로 하는 방식 그대로 씁니다.

용량 제한 채널로 연결된 다섯 단계: 검색, 조립, 추론, 후처리, 스트리밍. 3단계는 모델 워커를 둘러싸고 기한 확인, 서킷 브레이커, 타임아웃을 실행합니다. 버려진 요청은 이유와 함께 데드 레터 큐로 갑니다.

빠른 시작

1직접 확인하기

예제를 클론해서 실행하세요. 키도 네트워크도 필요 없습니다.

git clone https://gitlab.com/mattbusel/tokio-prompt-orchestrator
cd tokio-prompt-orchestrator
cargo run --example llm_pipeline

2서버 설치 및 실행

대화형 터미널과 8080 포트의 HTTP API를 함께 제공합니다. echo는 키가 필요 없습니다. Windows(PowerShell 한 줄), Homebrew, Scoop, cargo binstall은 다운로드를 참고하세요.

curl -fsSL https://gitlab.com/mattbusel/tokio-prompt-orchestrator/-/raw/main/install.sh | sh
orchestrator --provider echo

# then, from another terminal
curl -s -X POST http://127.0.0.1:8080/api/v1/infer \
  -H 'Content-Type: application/json' \
  -d '{"prompt":"What is backpressure?"}'

3라이브러리로 사용하기

EchoWorker를 AnthropicWorker, OpenAiWorker, LlamaCppWorker, VllmWorker 중 하나로 바꾸세요.

[dependencies]
tokio-prompt-orchestrator = "1.4"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
use std::{collections::HashMap, sync::Arc};
use tokio_prompt_orchestrator::{spawn_pipeline, EchoWorker, ModelWorker, PromptRequest, SessionId};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let worker: Arc<dyn ModelWorker> = Arc::new(EchoWorker::new());
    let handles = spawn_pipeline(worker);
    let mut output = handles.take_output_rx().await.ok_or("output taken")?;

    handles.input_tx.send(PromptRequest {
        session: SessionId::new("demo"),
        request_id: "req-1".into(),
        input: "Hello, pipeline!".into(),
        meta: HashMap::new(),
        deadline: None,
    }).await?;

    if let Some(out) = output.recv().await { println!("{}", out.text); }
    for dropped in handles.dlq.drain() { println!("dropped {}: {}", dropped.request_id, dropped.reason); }
    Ok(())
}

에이전트와 도구를 위한 서버

orchestrator 바이너리는 터미널 프롬프트와 REST, SSE, WebSocket API를 나란히 실행합니다. 프롬프트를 POST하면 요청 ID를 받고, 그다음 결과를 가져옵니다. /health는 브레이커 상태와 큐 깊이를 알려 줍니다.

Claude Desktop과 Claude Code는 별도의 mcp 바이너리를 통해 stdio로 연결합니다: MCP 설정

Windows: .exe를 다운로드해서 더블클릭하세요. 설정에서 echo를 고르면 키 없이 써 볼 수 있습니다.

--provider echo 로 실행한 orchestrator가 터미널에 입력한 프롬프트 하나와 curl로 /api/v1/infer 에 보낸 프롬프트 하나에 응답하는 모습

함께 들어 있는 기능

속도 제한기

모델별 슬라이딩 윈도와 토큰 버킷. 분당 요청 10개로 제한했을 때의 실제 출력:

req-01 ok
...
req-10 ok
req-11 throttled: sliding window limit exceeded; window resets in 60001 ms
req-12 throttled: sliding window limit exceeded; window resets in 60001 ms

rate_limiter::RateLimiterRegistry

백엔드

Anthropic, OpenAI, llama.cpp, vLLM 워커, 오프라인 EchoWorker, 라운드 로빈이나 최소 부하 풀을 위한 LoadBalancedWorker. 그 밖의 백엔드는 async trait 하나만 구현하면 됩니다.

trait ModelWorker

터미널 대시보드

큐 깊이, 브레이커 상태, 중복 제거로 아낀 양, 로그 패널을 Ratatui TUI로 보여 줍니다. 모의 데이터 모드가 있어 파이프라인을 실행하지 않고도 살펴볼 수 있습니다.

cargo run --bin tui --features tui

선택 기능

feature flag로 Prometheus 메트릭, OpenTelemetry 트레이싱, Redis 기반 분산 중복 제거, 프롬프트 템플릿, A/B 테스트, 자동 튜닝 제어 루프를 추가할 수 있습니다. 기본 빌드에는 선택 의존성이 없습니다.

--features full

오버헤드

BENCHMARKS.md에 기록된 최근 실행 결과입니다(Windows, x86_64, EchoWorker 사용, 네트워크와 모델 시간 제외).

측정 항목p50
속도 제한 확인110 ns
send_with_shed (요청을 버리는 논블로킹 전송)204 ns
서킷 브레이커 확인(닫힘 상태)~0.4 µs
중복 제거 확인(캐시됨)~1.5 µs
동일한 프롬프트 100개 동시 요청, 중복 제거 적용, 추론 한 번총 52.6 µs
EchoWorker 동시 호출 1000번총 7.1 ms