Skip to main content

XGEN Harness — 자가 증식 도구 에이전트: SandboxEnv(영속 venv + pip) + s12_publish 자동 컴파일·설치 + ResourceRegistry sandbox bridge. Plan.auto_publish=True 면 실행 후 자동 wheel → 다음 요청에 tool 로 자동 등장.

Project description

xgen-harness

LLM 이 스스로 조립하는 자율주행 에이전트 실행 프레임워크

PyPI Python License

pip install xgen-harness

한 줄 요약

워크플로우를 "짜는 것" 이 아니라 "말로 설명하는 것" 으로 바꾼 에이전트 실행기. 사용자는 "뭘 하고 싶다" 만 선언, 하네스는 LLM 이 직접 어떤 Stage 를 쓸지 · 어떤 Strategy 로 · 몇 번 반복할지 · 어떤 오케스트레이션 패턴으로 돌릴지까지 전부 스스로 결정.

현재 (v0.16.9) — 11 Stage + s00_harness Auto 통제탑 · 재귀적 자율주행 4레벨 · 자가증식 도구 루프 · 드롭-인 Stage 플러그인 · entry_points 12 그룹 · DAG 오케스트레이터 · 컴파일러(→ pip wheel).


30 초 데모

from xgen_harness import Pipeline, PipelineState, HarnessConfig, EventEmitter
from xgen_harness.core.execution_context import set_execution_context

set_execution_context(api_key="sk-...", provider="openai", model="gpt-4o-mini")

# "Auto" 모드 — 무엇을 할지만 선언. 하네스가 LLM 한테 파이프라인을 조립하게 시킴
config = HarnessConfig(
    provider="openai", model="gpt-4o-mini",
    harness_mode="autonomous",                    # ← 이 한 줄
    capabilities=["retrieval.web_search"],
)
pipeline = Pipeline.from_config(config, EventEmitter())
state = PipelineState(user_input="오늘 한국 날씨 요약해줘")

await pipeline.run(state)
print(state.final_output)

실제로 벌어지는 일 — s00_harness 가 LLM 한테 HarnessPlan 을 만들게 시키고, Plan 에 따라 필요한 Stage 만 실행, 반복 횟수도 LLM 이 결정, 매 iter 재계획(replan). 첫 답에 만족하면 done=true 로 즉시 종료.

[요청]  "오늘 한국 날씨 요약해줘"
   ↓
[s00_harness Auto]  LLM Planner — catalog 를 보고 Plan 결정
   Plan(chosen=[s01, s03, s04, s06, s07], max_iter=2, orchestrator_hint="iterative", done=false)
   ↓
[선택된 Stage 만 실행]  s01 → s03 → s04 → s06 → [main_call] → s07 → ...
   ↓
[s00 재호출 iter#2]  previous_results 보고 다음 Plan 결정
   done=true → 종료

🆕 크게 바뀐 점 (v0.11.x → v0.16.x)

구분 이전 (v0.11.x) 지금 (v0.16.x)
파이프라인 12 Stage 고정 파이프라인 11 Stage + s00_harness Auto 통제탑 (Planner)
실행 조립 사용자가 stage_params / active_strategies 다 설정 LLM 이 catalog 보고 자율 조립 (Stage / Strategy / params / max_iter / orchestrator)
본문 LLM 호출 s07_llm Stage 가 담당 s00_harness 가 단일 Provider 로 통제, s07_act 직전main_call 주입 (TransportStrategy 패턴)
반복 HarnessConfig.max_iterations=10 고정 Plan.max_iterations 을 LLM 이 1~50 범위에서 결정
오케스트레이션 단일 agentic loop Plan.orchestrator_hint: linear / iterative / plan_execute / react / dag — 런타임에 동적 분기 (v0.16.8 OrchestratorSpec flag 기반)
도구 사용자가 custom_tools 로 나열 Tool Synthesis — LLM 이 도구 생성 → Sandbox 테스트 통과 → 자동 레지스트리 합류 → 다음 Plan 이 재사용
외부 확장 entry_points 9 그룹 12 그룹 (+ orchestrators / phases / node_plugins / tool_sources) + 파일시스템 자동 스캔 + NOM 단일 IR
Stage 이름 의존 Pipeline 이 s07_llm / s08_judge 리터럴을 코드에 박아둠 Stage.role 역할 선언 (orchestrator_planner / main_actor / scorer) — Pipeline 리터럴 0, 리네이밍 무서워할 필요 없음

핵심 릴리즈 요약

버전 날짜 핵심
v0.12.0 04-22 🎯 REAL HARNESS Phase 1s00_harness Planner + self-describing catalog + 13 Stage 디렉토리화 (파일 하나 → 디렉토리 하나)
v0.13.0 04-22 Iterative Planning — 단일 Provider 1 인스턴스 재활용 + 매 iter s00 재호출(replan) + Plan.done 조기 종료 + previous_results 자동 주입
v0.14.0 04-22 🎯 s07_llm 삭제 + 번호 시프트 — s00_harness 통제탑 승격, TransportStrategy (streaming/batch), harness_mode 3-way (autonomous/selected/off)
v0.15.0 04-22 🎯 재귀적 자율주행 완성Plan.max_iterations + Plan.orchestrator_hint + OrchestratorRegistry 자동 연동 + display_name="Auto"
v0.15.1~3 04-22 🎯 자동 연동성 9축 감사 — Phase / Transport / Capability / Provider / Tool entry_points 갭 제거 + 파일시스템 자동 스캔 + catalog source_file 노출
v0.16.0 04-22 🚀 자가증식 4축 전면 실증Sandbox / NOMGraph / NodePlugin / ToolSynthesis PASS, LLM 생성 도구가 Sandbox 통과 후 자동 합류
v0.16.1 04-22 Sandbox rlimit 하드닝 (CPU/메모리/fd/파일크기/코어덤프) + LocalManifest 통합 스키마 + synthesis 하드코딩 제거
v0.16.3~4 04-22 XGEN_HARNESS_PRELOAD_MANIFEST env 로 LocalManifest 자동 주입 + s04_tool 브릿지 (전역 tool_sources → LLM tool_definitions)
v0.16.6 04-22 🎯 Pipeline Role 체계 — Stage 이름 리터럴 12 → 0. role="orchestrator_planner" 선언으로 Pipeline 수정 0
v0.16.7~8 04-23 hot-fix — off 모드 본문 호출 복원 + OrchestratorSpec flag 기반 분기 (리터럴 0 주장 보증)

벤치 근거 (v0.11.x 누적 n=3 replay): assort 키워드 +332%, latency −37% · krra 문서 인용 2.10/turn · cascade std −½ — 상세는 bench/INFINITE-LOG.md.


실행 모드 3종 (harness_mode)

┌──────────────────────┬────────────────────────────────────────────────────────────┐
│  autonomous (기본)   │  LLM Auto — s00_harness 가 매 iter Plan 수립, 재계획       │
│                      │  · max_iterations / orchestrator 도 LLM 이 선택            │
│                      │  · previous_results 주입, done=true 시 조기 종료           │
├──────────────────────┼────────────────────────────────────────────────────────────┤
│  selected            │  사용자가 UI 에서 핀한 Stage / Strategy / params 그대로    │
│                      │  · Plan 생성 skip, 사용자 설정 = 진실의 소스               │
├──────────────────────┼────────────────────────────────────────────────────────────┤
│  off                 │  s00_harness bypass — 11 Stage 전부 순차 (레거시 호환)     │
│                      │  · 본문 LLM 호출은 여전히 s00 내부 main_call 로 수행       │
└──────────────────────┴────────────────────────────────────────────────────────────┘
HarnessConfig(harness_mode="autonomous")  # 기본
HarnessConfig(harness_mode="selected")    # UI 핀 그대로
HarnessConfig(harness_mode="off")         # 레거시 fallback

재귀적 자율주행 — 4 Layer

사용자가 묻는 1 문장 만 있으면 LLM 이 아래 4 층을 전부 스스로 내려간다.

 L1 — 구조 파악          catalog["stages"] / ["strategies"] / ["orchestrators"] /
                        ["providers"] / ["phases"] / ["capabilities"] / ["tools"]
                        전부 런타임 레지스트리에서 생성 (리터럴 0)
                        ↓
 L2 — Stage 선택         Plan.chosen : list[stage_id]
                        "이 요청엔 s03(Prompt) + s06(RAG) + s07(Act) 만 필요"
                        ↓
 L3 — Strategy 선택      Plan.strategies : {stage_id: strategy_name}
                        "s06 은 cascade 압축, s07 의 transport 는 streaming"
                        ↓
 L4 — 파라미터 / 도구    Plan.params : {stage_id: {k: v}}
                        "s04_tool 의 force_tool_use=True, s06_context.cascade_l3=80"
                        ↓
 + 오케스트레이션        Plan.orchestrator_hint : linear / iterative / plan_execute /
                        react / dag / <외부 등록명>
 + 반복 횟수             Plan.max_iterations : 1 ~ 50
 + 조기 종료             Plan.done : 만족하면 True

Plan 은 매 iter 재생성(replan) — Planner 가 previous_results (직전 iter 의 answer 미리보기 / tool_calls / validation score / token 사용량) 를 보고 다음 조각을 재조립.


11 Stage + s00_harness Auto 통제탑

 Phase A: 준비 (ingress, order ≤4)
   s00_harness ─ Auto                     ← LLM Planner (role=orchestrator_planner)
   s01_input   ─ Input                    · Provider / model / API 키
   s02_history ─ History                  · 이전 대화 로드
   s03_prompt  ─ Prompt                   · 시스템 프롬프트 조립 + RAG + Citation
   s04_tool    ─ Tool                     · MCP / Gallery / RAG 도구 수집

 Phase B: 에이전트 루프 (loop, order ≤9)  ← 매 iter 시작에 s00 재호출 (replan)
   s05_strategy ─ Strategy                · CoT / ReAct / none / auto
   s06_context  ─ Context                 · RAG + 5-Level Cascade Compression
   [main_call]                             ← s00 이 s07_act 직전에 주입 (TransportStrategy)
   s07_act      ─ Act   (role=main_actor) · LLM tool_use 디스패치
   s08_judge    ─ Judge (role=scorer)     · 품질 평가 (LLM Judge / rule / none)
   s09_decide   ─ Decide                  · Guard 체인 + 루프 판단 (DecideStrategy)
                                           ↓
                                  계속 → s00 재계획 → s05 로 루프
                                  완료 → Phase C

 Phase C: 마무리 (egress, order ≥10)
   s10_save     ─ Save                    · DB 저장
   s11_finalize ─ Finalize                · 메트릭스 + 포맷팅

v0.14.0 — 과거 s07_llm Stage 는 삭제되고 본문 LLM 호출은 s00_harness.main_call() 로 이관. 전체 파이프라인에서 LLM 인스턴스는 1개 (state.provider 재활용). s08_executes07_act 로 번호 시프트.

v0.16.6 Role 체계 — Pipeline 은 Stage 이름을 몰라도 된다. 외부 기여자가 role="orchestrator_planner" 를 선언한 자기 Planner 로 s00_harness 를 교체하면 Pipeline 코드 수정 0.

Stage별 기능

# Stage ID 표시 하는 일 대표 Strategy
0 s00_harness Auto Planner — catalog → HarnessPlan LLM 호출 → 매 iter replan. 본문 main_call 호스팅 transport: streaming / batch
1 s01_input Input Provider 생성, API 키 해석 default
2 s02_history History 이전 대화 이력 로드 default / embedding_search
3 s03_prompt Prompt 섹션 기반 프롬프트 + RAG + Citation section_priority / simple
4 s04_tool Tool MCP / Gallery / RAG / 전역 tool_sources 수집 + force_tool_use progressive_3level / eager_load
5 s05_strategy Strategy 실행 계획 (CoT / ReAct / none) auto
6 s06_context Context RAG 검색 + 5-Level Cascade Compression 6종: token_budget · sliding_window · microcompact · context_collapse_overlay · autocompact_llm · cascade
7 s07_act Act (main_actor) LLM tool_use 디스패치 sequential / parallel
8 s08_judge Judge (scorer) LLM Judge / Rule-based / None llm_judge / rule_based / none
9 s09_decide Decide Guard 체인 + 루프 판단 (DecideStrategy.decide()) threshold / always_pass
10 s10_save Save 실행 이력 DB 저장 default / noop
11 s11_finalize Finalize 메트릭스 + 포맷팅 default / format_json

구 ID 호환STAGE_ID_ALIASES 가 저장된 워크플로우의 s07_llm / s02_memory 등 구 id 를 자동 정규화. 이식측 수정 없이 계속 동작.


자가증식 4 축 (v0.16.0+)

하네스가 런타임에 자기 자신을 확장 하는 4 축. 각 축이 단일 진실 스키마(LocalManifest) 로 연결.

 ┌──────────────────┐   Subprocess 격리 실행. -I isolated + rlimit 5종
 │   1. Sandbox     │   CPU sec · address_space_mb · max_open_files · max_file_size · no_core_dump
 │                  │   POSIX preexec_fn 강제 (parent 영향 0)
 └──────────────────┘
          ↓ 테스트 통과한 도구만 등록
 ┌──────────────────┐   Stage / Strategy / Tool / MCP / legacy Node 를
 │   2. NOM         │   단일 IR (NOMNode/NOMGraph) 로 통일.
 │   (Node Object   │   snapshot_current_registry_as_nom() → 54 노드 그래프
 │    Model)        │   갤러리 · 샌드박스 · 컴파일러 공통 입력
 └──────────────────┘
          ↑ 매니페스트 주입
 ┌──────────────────┐   외부 pip 패키지가 자기 노드를 `NodePluginManifest` 로 선언.
 │ 3. Node Plugin   │   3 경로: Python dict / YAML·JSON 파일 / entry_points
 │                  │   (xgen_harness.node_plugins). 엔진 무침범
 └──────────────────┘
          ↑ LLM 이 생성한 도구
 ┌──────────────────┐   `SynthesizedTool` + `ToolTestCase` + `SynthesizedToolSource`
 │ 4. Tool          │   test_synthesized_tool() 이 Sandbox 로 전수 검증 →
 │    Synthesis     │   synthesize_and_register() 가 레지스트리 합류 →
 │                  │   다음 Plan 이 재사용 (자가 증식 루프)
 └──────────────────┘

Tool Synthesis 예시

from xgen_harness.tools.synthesis import (
    SynthesizedTool, ToolTestCase, synthesize_and_register,
)

tool = SynthesizedTool(
    name="slugify", description="한글/영문 문자열을 URL slug 로",
    code='def tool(args): return {"slug": args["text"].replace(" ", "-").lower()}',
    test_cases=[
        ToolTestCase(input={"text": "Harness Auto Weave"},
                     expected={"slug": "harness-auto-weave"}),
    ],
)

# Sandbox 에서 test_cases 전수 통과 → 자동 register_tool_source → 다음 Plan 이 발견
await synthesize_and_register(tool)

LocalManifest 자동 주입 (v0.16.3)

# 다른 프로세스에서 synthesize 한 결과를 env 한 줄로 주입
export XGEN_HARNESS_PRELOAD_MANIFEST=/path/to/manifest.json
python -m xgen_harness.cli  # get_tool_sources() 첫 조회 시 idempotent 로드

compile.local_manifest 가 synthesis ↔ NodePlugin ↔ gallery 3 곳을 동일 포맷으로 묶어 drift 원천 차단.


확장 통로 — 12 entry_points 그룹

외부 패키지가 자기 pyproject.toml 한 줄 추가하면 하네스 부팅 시 자동 합류. 라이브러리 본체 수정 0.

[project.entry-points."xgen_harness.stages"]            # ① Stage 추가 / swap
[project.entry-points."xgen_harness.strategies"]        # ② Stage 내부 알고리즘
[project.entry-points."xgen_harness.orchestrators"]     # ③ 실행 패턴 (v0.15.0)
[project.entry-points."xgen_harness.phases"]            # ④ Phase 경계 (v0.15.1)
[project.entry-points."xgen_harness.providers"]         # ⑤ LLM 프로바이더
[project.entry-points."xgen_harness.capabilities"]      # ⑥ 선언형 도구 바인딩
[project.entry-points."xgen_harness.tool_sources"]      # ⑦ 외부 도구 디스패치 (v0.15.2)
[project.entry-points."xgen_harness.node_adapters"]     # ⑧ 노드 카테고리 → tool_def
[project.entry-points."xgen_harness.option_sources"]    # ⑨ UI 셀렉터 데이터
[project.entry-points."xgen_harness.fan_out_strategies"] # ⑩ 멀티에이전트 분기
[project.entry-points."xgen_harness.evaluation_criteria"] # ⑪ s08 평가 기준
[project.entry-points."xgen_harness.node_plugins"]      # ⑫ Node Plugin (v0.16.0)

파일시스템 자동 스캔 (v0.15.2)

stages/sNN_xxx/ 디렉토리만 떨어뜨리면 fs_scanner 가 자동 import + register. entry_points 도 필요 없음.

my_package/
 └─ stages/
     └─ s04_tool_lotte/          ← 디렉토리 이름이 자동 발견 키
         ├─ __init__.py           ← Stage 서브클래스 export
         └─ strategies/
             └─ progressive/
                 └─ custom.py     ← register_strategy(s04_tool, progressive, custom, …) 자동

catalog["stages"][i]["source_file"] / strategies[j]["source_file"]LLM 이 "이 Stage 는 어디 파일에 있는지" 직접 읽어서 판단 가능 (재귀적 자율주행 L1).

레지스트리 API — 코드로 붙이기

from xgen_harness import (
    register_stage, register_provider, register_service, register_tool_source,
    register_xgen_node_resolver,
)
from xgen_harness.core.strategy_resolver import register_strategy
from xgen_harness.core.orchestrator_registry import register_orchestrator
from xgen_harness.core.phase_registry import register_phase
from xgen_harness.capabilities import register_capability

register_stage("s99_custom", "default", MyStage)
register_strategy("s08_judge", "evaluation", "strict", StrictJudge)
register_orchestrator("my_pattern", description="...", terminates_after_first=True)
register_phase("post_egress", upper_order=9999)
register_provider("my_llm", MyLLMProvider)
register_service("documents", "http://my-rag:8000")
register_tool_source(my_tool_source)

Stage 역할 교체 (v0.16.6)

Pipeline 은 역할 이름 만 안다. 이름 리네이밍에 독립.

from xgen_harness import Stage

class MyPlanner(Stage):
    @property
    def stage_id(self) -> str: return "my_planner"
    @property
    def role(self) -> str: return "orchestrator_planner"   # ← s00_harness 자리에 꽂힘
    @property
    def order(self) -> int: return 0
    ...

register_stage("my_planner", "default", MyPlanner)
# Pipeline 수정 0 — role 기반 검색이 새 Planner 를 자동 발견

3 가지 도구 바인딩 경로 (Capability 시스템)

 ① 선언 바인딩                  ② 발견 바인딩              ③ 자동 발행
    (capabilities 필드)          (s05 natural intent)      (Adapter → Registry)
    ↓                            ↓                          ↓
 config.capabilities =          "뉴스 찾아서 요약"         워크플로우 노드
 ["retrieval.web_search"]            ↓                    → MCP/API/DB/RAG
    ↓                            Matcher 매칭              → publish_capabilities()
 s04_tool 바인딩                s04 바인딩                → ①② 사용 가능

실행 중 LLM 이 빠뜨린 필수 파라미터는 ParameterResolverprovided → context → llm_infer → default 순으로 자동 채움.


빠른 시작

1. 독립 실행 (어댑터 없이)

from xgen_harness import Pipeline, PipelineState, HarnessConfig, EventEmitter
from xgen_harness.core.execution_context import set_execution_context

set_execution_context(api_key="sk-...", provider="openai", model="gpt-4o-mini")

config = HarnessConfig(
    provider="openai", model="gpt-4o-mini",
    harness_mode="autonomous",
    capabilities=["retrieval.web_search"],
)
pipeline = Pipeline.from_config(config, EventEmitter())
state = PipelineState(user_input="오늘 한국 날씨 알려줘")

await pipeline.run(state)
print(state.final_output)

2. xgen-workflow 연동

from xgen_harness.adapters.xgen import XgenAdapter

adapter = XgenAdapter(db_manager=db_manager)
async for event in adapter.execute(
    workflow_data, input_data, user_id=user_id,
    user_is_admin=is_admin, user_is_superuser=is_superuser,   # v0.11.26+
):
    yield event  # xgen SSE 포맷 (그대로 프론트에 전달 가능)

3. 워크플로우 → wheel 컴파일 (v0.10.0+)

import xgen_harness as xh

result = xh.compile_workflow(
    harness_config=config,
    workflow_data={"nodes": [...], "edges": [...]},
    gallery_name="team_q_and_a",
    gallery_version="0.1.0",
    out_dir="./dist",
)
# → dist/xgen_gallery_team_q_and_a-0.1.0-py3-none-any.whl

# 받는 쪽은 한 줄로 설치 + 실행
# $ pip install xgen-gallery-team-q-and-a
# >>> from xgen_gallery_team_q_and_a import arun
# >>> await arun("안녕?")

${OPENAI_API_KEY} 같은 참조는 자동 스캔 → env.example 생성. 외부 SDK 의존성은 register_dependency_rule() 로 자동 wheel 주입. 폐쇄망(pip install --no-index --find-links wheelhouse/) 시나리오 검증됨.

4. Strategy Variant — 디폴트 건들지 않고 "복사해서 v2" (v0.10.4)

config = HarnessConfig(
    provider="openai",
    strategy_variants={
        "s06_context": [
            {
                "name": "my_compactor_v2",
                "base": "token_budget",            # 디폴트 impl 을 복사
                "params": {"budget_ratio": 0.5},   # 파라미터만 교체
                "label": "엄격 압축",
            }
        ]
    },
    active_strategies={"s06_context": "my_compactor_v2"},
)

5. 구성 저장 / 로드

builder = (PipelineBuilder()
    .with_provider("openai", model="gpt-4o-mini")
    .with_rag("docs", top_k=5)
    .with_artifact("s04_tool", "lotte")
    .disable("s05_strategy"))
builder.save("./harness.json")

loaded = PipelineBuilder.load("./harness.json")
pipeline = loaded.with_api_key("sk-...").build()

config = HarnessConfig(provider="openai", capabilities=["retrieval.web_search"])
config.save("./config.json")
config = HarnessConfig.load("./config.json")

dataclasses.fields() 자동 순회 → 새 필드 추가해도 직렬화 코드 수정 불필요. api_key 등 민감/런타임 객체는 자동 제외.


3 층 아키텍처 — Stage · Strategy · Resource

                      ┌──────────────────────────────────┐
  ┌──────────────────▶│           Resource               │
  │                   │  MCP · RAG · DB · API · Gallery  │
  │                   │  · Capability · Tool Synthesis   │
  │                   └──────────────────────────────────┘
  │                                  ▲
  │                                  │ register_service()
  │                                  │ register_tool_source()
  │     ┌────────────────────────────┴──────────────────┐
  │     │                   Strategy                    │
  │     │  Transport(streaming/batch) · ExpBackoff ·    │
  │     │  AnthropicCache · LLMJudge · RuleBased ·      │
  │     │  Progressive3Level · Threshold · AlwaysPass · │
  │     │  ContentGuard · Cascade · Microcompact · …    │
  │     │  40+ 구현체, StrategyResolver 런타임 교체     │
  │     └───────────────────────────┬───────────────────┘
  │                                 │
  │       ┌─────────────────────────┴────────────────────┐
  └───────┤                     Stage                    │
          │  s00 Auto (Planner + main_call)              │
          │  s01 Input · s02 History · s03 Prompt        │
          │  s04 Tool · s05 Strategy · s06 Context       │
          │  s07 Act · s08 Judge · s09 Decide            │
          │  s10 Save · s11 Finalize                     │
          │  12 슬롯 (Artifact 로 구현 swap)             │
          └──────────────────────────────────────────────┘

핵심 원칙

  • 라이브러리 ≠ 인프라: 라이브러리는 URL·API 키·프로바이더 이름을 모른다 → 어댑터가 주입
  • Graceful skip: 미등록 자원은 에러가 아니라 자동으로 건너뜀
  • 무침범: 새 Stage/Strategy/Tool 추가 시 기존 코드 1줄도 수정 안 함
  • 하드코딩 0: if provider == "..." / if stage_id == "..." / if orch_hint == "linear" 같은 분기 전부 제거 (v0.16.8 OrchestratorSpec flag 기반 전환으로 마지막 2건까지 해소)
  • 단일 진실 소스: UI 필드 · 옵션 소스 · tokenizer · orchestrator · phase 경계 전부 엔진이 결정, 이식/프론트는 받아서 렌더만. drift 감지 시 경고 로그.

확장성 · 안정성 현황 (v0.16.9)

확장 지점 방식 등급
Stage 추가 register_stage() + entry_points + fs_scanner (v0.15.2) A
Strategy 교체 StrategyResolver + stage-local 디렉토리 스캔 (v0.15.3) A
Strategy Variant 디폴트 복사 → 파라미터만 교체 (v0.10.4) A
Orchestrator register_orchestrator() + flag 기반 분기 (v0.15.0 / v0.16.8) A
Phase register_phase() + xgen_harness.phases (v0.15.1) A
LLM 프로바이더 PROVIDER_REGISTRY + count_tokens() 확장점 (v0.11.22) A
Capability 타입 무관 CapabilityRegistry + entry_points (v0.15.1) A
Tool 소스 register_tool_source() + entry_points + s04 브릿지 (v0.16.4) A
Tool Synthesis LLM 생성 도구 → Sandbox 검증 → 자동 합류 (v0.16.0) A
Node Plugin NodePluginManifest + LocalManifest 통합 (v0.16.1) A
Sandbox 격리 subprocess + rlimit 5종 하드닝 (v0.16.1) A
Role 체계 Stage 가 자기 역할 선언, Pipeline 이름 리터럴 0 (v0.16.6) A
UI 옵션 소스 엔진 options_source 단일 선언 + 이식 역매핑 (v0.11.23) A
Decide 분기 DecideStrategy.decide() 로 Stage 내부 if/else 0 줄 (v0.11.1) A
컴파일러 xgen.compile(wf) + register_dependency_rule() + 폐쇄망 (v0.10.0) A
DAG 오케스트레이터 fan-out Strategy 레지스트리 + DAGCycleError 명시 실패 (v0.11.27) A
Context Compression 5-Level Cascade + AdvancedContextCompactor ABC 외부 교체 (v0.11.21) A
Tool Choice 제어 OpenAI/Anthropic/LangChain 통합 + circuit breaker (v0.11.20) A
전체 plug-and-play 성숙도 ~99%

모든 확장 지점이 레지스트리 + 팩토리 + ABC/Protocol 기반. 라이브러리 본체에 하드코딩된 프로바이더/모델/판정/오케스트레이션 분기 리터럴 0 건.


5-Level Context Compression Cascade (Claude Code 이식, v0.11.14~16)

대화가 길어져 context_window 에 근접하면 단일 압축으론 부족. Claude Code 5-Level 을 이식, 압력 구간별 단계 적용.

Level 전략 동작 stage_params.s06_context
L1 Tool Result Budget (내재) 50 KB 이상 tool_result → preview + pd_stores["tool_result"] 보존 (항상)
L2 History Snip token_budget first + last N strategy="token_budget"
L3 Microcompact 오래된 tool_result 블록만 placeholder 교체 (비파괴) strategy="microcompact"
L4 Context Collapse Overlay 중간 메시지 → overlay 마커 + 원본 pd_stores["history"] 보존 strategy="context_collapse_overlay"
L5 Autocompact child LLM 이 9-section 요약 생성 → [first, summary, last_N] 로 축소 strategy="autocompact_llm"

Cascade — 압력 자동 선택

stage_params = {
    "s06_context": {
        "strategy": "cascade",
        "cascade_l3_threshold": 80,   # baseline 동기 (조기 발동 방지)
        "cascade_l4_threshold": 90,
        "cascade_l5_threshold": 97,
    }
}

한 턴당 L3 + (L4 또는 L5) 최대 2 단계. 실행 결과는 results["cascade_applied"] = ["L3", "L5"].

RAG 주입 모드

설명 용도
system_prompt (기본) chunk → 시스템 프롬프트 주입 빠른 응답
tool_only 시스템 prompt skip, rag_search 도구만 사용 L3 Microcompact 실전 조건
both 둘 다 양쪽 장점 결합

s04_tool.rag_tool_mode="tool" 이면 자동 tool_only 로 전환 (사용자 의도 존중).

외부 교체 (v0.11.21)

from xgen_harness.stages.strategies.compactor_pd import AdvancedContextCompactor
from xgen_harness.core.strategy_resolver import register_strategy

class MyCompactor(AdvancedContextCompactor):
    async def apply(self, state, stage, budget_used, results):
        ...

register_strategy("s06_context", "compactor", "my_compactor", MyCompactor)

Tool Choice 제어 (v0.11.19~20)

stage_params = {
    "s04_tool": {
        "rag_tool_mode": "tool",
        "force_tool_use": True,  # 첫 iter tool_choice="required"
    }
}
  • OpenAI: body["tool_choice"] = "required"
  • Anthropic: body["tool_choice"] = {"type": "any"}
  • LangChain: llm.bind_tools(tools, tool_choice="required") forward
  • none: Anthropic 미지원 → tools 자체 drop 으로 semantics 맞춤

Circuit Breakerloop_iteration >= 1 부터 auto 로 자동 격하 (무한 루프 방지).


RAG 연동

# 1. Pre-search (s06)
HarnessConfig(preset="rag",
    stage_params={"s06_context": {"rag_collections": ["my_collection"]}})

# 2. Tool mode (에이전트 호출)
HarnessConfig(stage_params={"s04_tool": {
    "rag_collections": ["my_collection"],
    "rag_tool_mode": "tool",  # presearch / tool / both
}})

# 3. Citation
HarnessConfig(stage_params={"s03_prompt": {"citation_enabled": True}})
# → LLM 이 [DOC_1], [DOC_2] 형식으로 문서 인용

API 키 해석 (동시성 안전)

os.environ 쓰기 0개. contextvars 기반으로 동시 실행 시 키가 섞이지 않음.

1. ExecutionContext (contextvars)    ← 최우선
2. ServiceProvider.config.get_api_key()  ← xgen-core persistent_configs
3. os.environ (읽기 전용 폴백)
from xgen_harness.core.execution_context import set_execution_context
set_execution_context(api_key="sk-...", provider="openai", model="gpt-4o-mini")

Preset

Preset 용도 특징
minimal 단순 질의응답 도구/RAG/판정 없이 바로 대화
chat 멀티턴 이전 대화 이력 유지
agent 에이전트 도구 + RAG + 전략 + 판정 + 루프
evaluator 품질 평가 LLM Judge 엄격
rag 문서 검색 문서 기반 답변, 도구 없음

프로바이더

5종 빌트인 + LangChain 래핑 + 커스텀 등록.

from xgen_harness.providers import register_provider, create_provider, wrap_langchain

# 빌트인: anthropic / openai / google / bedrock / vllm
provider = create_provider("openai", api_key, "gpt-4o-mini")

# LangChain 호환
from langchain_anthropic import ChatAnthropic
provider = wrap_langchain(ChatAnthropic(model="claude-sonnet-4-6"))

# 커스텀
register_provider("my_llm", MyProvider)

Provider tokenizer 확장점 (v0.11.22): LLMProvider.count_tokens(text) -> (tokens, source) 공식 확장. OpenAI 는 tiktoken 자동 감지. s00 usage 실패 시 자동 보정 + state.metadata["output_tokens_sources"] 출처 기록.


Stage 별 상세 — 설정, 연동, 확장

s00_harness (Auto) — v0.14.0+ 통제탑

역할 (role="orchestrator_planner"): Planner LLM 이 HarnessPlan 생성 + 본문 main_call 호스팅.

설정:

HarnessConfig(
    harness_mode="autonomous",       # autonomous / selected / off
    planner_model="gpt-4o-mini",     # Plan 생성용 모델 (기본 = provider default)
    max_iterations=10,               # Plan.max_iterations 이 이 값을 override 가능 (1~50)
)

Strategy (transport): streaming (기본) / batch — 외부에서 websocket / caching_proxy 등 추가 가능.

확장:

# 외부 Transport 추가
class MyTransport(TransportStrategy):
    async def call(self, state) -> str: ...
register_strategy("s00_harness", "transport", "websocket", MyTransport)

s01 Input

Provider 생성, API 키 해석.

stage_params = {"s01_input": {
    "provider": "openai",          # anthropic / openai / google / bedrock / vllm
    "model": "gpt-4o-mini",
    "temperature": 0.7,
}}

s02 History

이전 대화 이력 로드. interaction_id 있을 때만 동작. embedding_search 전략 시 DocumentService 미주입이면 graceful skip (v0.11.25).

s03 Prompt

섹션 기반 조립: Identity → Rules → Tools → RAG → History → Citation.

stage_params = {"s03_prompt": {
    "system_prompt": "당신은 한국어 도우미입니다.",
    "prompt_id": "...",              # v0.11.23 options_source="prompt-store"
    "citation_enabled": False,       # [DOC_1] 인용 형식
}}

Strategy (cache): anthropic_cache (기본) / no_cache.

s04 Tool

MCP / Gallery / RAG / 전역 tool_sources 도구 수집 (v0.16.4 브릿지).

stage_params = {"s04_tool": {
    "mcp_sessions": ["session-abc"],
    "rag_collections": ["my_docs"],
    "rag_tool_mode": "both",          # presearch / tool / both
    "force_tool_use": False,          # 첫 iter tool_choice="required"
    "custom_tools": [...],            # options_source="tools" (v0.11.23)
    "capabilities": [...],            # options_source="capabilities"
}}

Strategy (discovery): progressive_3level / eager_load.

s05 Strategy

실행 계획 (CoT / ReAct / none / auto). 첫 번째 루프에서만 실행.

s06 Context

RAG 검색 + 5-Level Cascade Compression. 위 Cascade 섹션 참조.

s07 Act (main_actor)

역할 (role="main_actor"): LLM 이 반환한 tool_use 를 실제로 실행. s00 의 main_call 이 이 Stage 직전 에 주입되어 응답 스트리밍 + tool 파싱.

stage_params = {"s07_act": {
    "timeout": 60,
    "result_budget": 50000,
    # main_call 설정 (s00 에서 내려옴)
    "max_tokens": 8192,
    "max_retries": 3,
    "context_limit": 500000,
    "thinking_enabled": False,
    "thinking_budget": 10000,
}}

Strategy (executor): sequential / parallel (읽기 병렬, 쓰기 순차). Strategy (router): composite / mcp / builtin.

s08 Judge (scorer)

역할 (role="scorer"): StageExit 이벤트 scorevalidation_score 노출.

stage_params = {"s08_judge": {
    "criteria": ["relevance", "completeness", "accuracy", "clarity"],
    "threshold": 0.7,
}}

Strategy: llm_judge (기본, 가중평균) / rule_based (길이/에러/키워드) / none.

s09 Decide

Stage 내부 분기 0 줄DecideStrategy.decide() 전적 위임 (v0.11.1).

stage_params = {"s09_decide": {
    "max_iterations": 10,
    "guards": ["iteration", "cost_budget", "token_budget", "content"],
    "cost_budget_usd": 5.0,
    "token_budget": 500000,
    "content_blocked_patterns": ["password\\s*:\\s*\\S+"],
    "content_detect_pii": True,
}}

Guard 체인: Iteration · CostBudget · TokenBudget(80% 경고 / 95% 차단) · Content(정규식 + 이메일/휴대폰/주민번호/카드 PII 실구현).

s10 Save

실행 결과 DB 저장. save_enabled=False 면 건너뜀.

s11 Finalize

메트릭스 집계 + 출력 포맷팅 (text / json / markdown).


서비스 연동

라이브러리는 범용 이름(documents, mcp, config)으로 조회 → 어댑터가 실제 URL 등록. 미등록 시 graceful skip.

register_service("config", "http://xgen-core:8000")
register_service("documents", "http://xgen-documents:8000")
register_service("mcp", "http://xgen-mcp-station:8000")
서비스 Stage 용도
config s01 API 키 조회 (persistent_configs)
documents s02 / s03 / s06 RAG 문서 검색 · embedding_search
mcp s04 / s07 MCP 도구 디스커버리 + 실행
(DB) s02 / s10 대화 이력 + 실행 로그 (ServiceProvider 주입)

엔진 독립성 (v0.11.24~25) — 엔진은 xgen-documents API 스키마(/api/retrieval/...) 를 더 이상 알지 않음. 호스트 노드 참조는 register_xgen_node_resolver() 공식 확장 지점으로 주입.


워크플로우 컴파일러 (v0.10.0+)

HarnessConfig + workflow_data
        ↓
  xgen.compile(wf)
        ↓
snapshot.json + env.example + cli.py + __init__.py
        ↓
  build_wheel (python -m build)
        ↓
xgen_gallery_<name>-<ver>-py3-none-any.whl
        ↓
pip install xgen-gallery-<name>
        ↓
from xgen_gallery_<name> import arun
await arun("입력")
  • external_inputs — 선언 + ${VAR} 자동 스캔. PROVIDER_API_KEY_MAP 경유로 secret 타입 확정.
  • DependencyResolver + register_dependency_rule() — 외부 SDK 의존성 자동 wheel 주입.
  • drift-free (v0.10.2) — 엔진이 확정한 dist_name / package_name 을 결과에 담아 이식/프론트 재조합 제거.
  • 3 채널 배포 — 공개 PyPI / 사내 인덱스 / 로컬 wheel 모두 동일 산출물.
  • 폐쇄망pip downloadpip install --no-index --find-links wheelhouse/ 검증.
  • MCP 서브커맨드pip install xgen-gallery-<name>[mcp]serve-mcp CLI.

상세: docs/harness/2026-04-20-workflow-compiler.md.


DAG 오케스트레이터

멀티에이전트 플로우를 DAG 로 표현 + fan-out / join 자동 관리. 서브 파이프라인마다 독립 HarnessConfig + ExecutionContext (API 키 격리). SSE 이벤트를 부모 스트림으로 자동 포워딩.

from xgen_harness.orchestrator import DagOrchestrator, DagNode

orchestrator = DagOrchestrator()
orchestrator.add_node(DagNode(id="search", config=search_config))
orchestrator.add_node(DagNode(id="summarize", config=summarize_config, depends_on=["search"]))

async for event in orchestrator.run(initial_input="오늘 뉴스 요약"):
    yield event

Fan-out Strategy: broadcast / round_robin / capability_match + register_fan_out_strategy() 외부 등록. 사이클 감지 (v0.11.27): Kahn 알고리즘 미처리 시 DAGCycleError raise (silent drop 방지).


디렉토리 구조

xgen_harness/
├── core/                           # 핵심 엔진
│   ├── pipeline.py                 # 3-Phase 실행 + role 기반 분기 (v0.16.6)
│   ├── stage.py                    # Stage ABC + role 체계
│   ├── planner.py                  # HarnessPlanner + HarnessPlan + PLAN_TOOL_SCHEMA
│   ├── catalog.py                  # 런타임 카탈로그 (stages/orchestrators/providers/phases/…)
│   ├── llm_call.py                 # 본문 LLM 호출 공용 헬퍼 (v0.14.0 s07_llm 에서 이관)
│   ├── orchestrator_registry.py    # OrchestratorSpec + 5 defaults + entry_points (v0.15.0/16.8)
│   ├── phase_registry.py           # Phase 경계 레지스트리 (v0.15.1)
│   ├── fs_scanner.py               # 파일시스템 Stage/Strategy 자동 스캔 (v0.15.2/3)
│   ├── sandbox.py                  # subprocess + rlimit 격리 (v0.16.0/1)
│   ├── nom.py                      # NOMNode / NOMGraph 단일 IR (v0.16.0)
│   ├── node_plugin.py              # NodePluginManifest (v0.16.0)
│   ├── state.py                    # PipelineState (ToolGroup/ValidationGroup v0.11.22)
│   ├── config.py                   # HarnessConfig + harness_mode (v0.14.0)
│   ├── service_registry.py         # 서비스 URL 레지스트리
│   ├── execution_context.py        # contextvars API 키 격리
│   ├── strategy_resolver.py        # Strategy 레지스트리 (40+)
│   ├── registry.py                 # Stage 레지스트리 (fs_scanner 위임)
│   ├── presets.py
│   ├── stage_config.py             # STAGE_ID_ALIASES + options_source (v0.11.23)
│   └── artifact.py
│
├── stages/                         # 12 Stage 디렉토리화 (v0.12.0)
│   ├── s00_harness/                # Planner + main_call (role=orchestrator_planner)
│   ├── s01_input/ ~ s11_finalize/  # 각 디렉토리에 stage.py + artifacts/ + strategies/
│   ├── interfaces.py               # Strategy ABC
│   └── strategies/                 # 공용 Strategy
│       ├── transport.py            # StreamingTransport / BatchTransport (v0.14.0)
│       ├── retry.py · parser.py · thinking.py · token_tracker.py
│       ├── tool_router.py · tool_executor.py · discovery.py
│       ├── evaluation.py · compactor.py · compactor_pd.py (AdvancedCompactor ABC)
│       ├── guard.py · _decide.py · cache.py
│
├── providers/                      # LLM 프로바이더 + count_tokens() 확장점
│   ├── anthropic.py · openai.py · google.py · bedrock.py · vllm.py
│   └── langchain_adapter.py
│
├── compile/                        # 워크플로우 → wheel
│   ├── external_inputs.py · snapshot.py · deps.py · wheel.py
│   └── local_manifest.py           # 통합 스키마 (v0.16.1)
│
├── tools/                          # 도구 시스템
│   ├── synthesis.py                # Tool Synthesis 루프 (v0.16.0/1)
│   ├── rag_tool.py · mcp_client.py · gallery.py
│
├── orchestrator/                   # DAG 멀티에이전트
├── capabilities/                   # 선언형 도구 바인딩
├── adapters/                       # XgenAdapter 등
├── integrations/                   # xgen 연동
├── events/                         # SSE 스트리밍
├── errors/                         # ErrorCategory + DAGCycleError
└── api/                            # FastAPI 라우터

외부 기여 / 확장 매뉴얼

라이브러리 소스 수정 0 — 외부 패키지 + entry_points + register_*() API 만으로 12 지점 확장.


버전 이력 요약

버전 주요 변경
0.16.9 __version__ auto-sync — importlib.metadata 로 dist 버전 동적 조회 (상수 박제 제거)
0.16.8 감사 hot-fix — Pipeline.describe 들여쓰기 복원, OrchestratorSpec flag 기반 분기 (리터럴 0), providers 무로깅 except 제거
0.16.7 hot-fix — off 모드 본문 LLM 호출 복원 (Planner Stage 항상 주입)
0.16.6 🎯 Pipeline Role 체계Stage.role 선언 (orchestrator_planner/main_actor/scorer). Pipeline Stage 이름 리터럴 12 → 0
0.16.5 Tool result content string 정규화 — Anthropic 400 + slice TypeError 동시 수정
0.16.4 s04_tool 브릿지 — 전역 tool_sources → LLM tool_definitions 자동 전파
0.16.3 XGEN_HARNESS_PRELOAD_MANIFEST env 로 LocalManifest 자동 주입
0.16.1 Sandbox rlimit 5종 하드닝 + LocalManifest 통합 스키마 + synthesis 하드코딩 제거
0.16.0 🚀 자가증식 4축 전면 실증 — Sandbox / NOM / NodePlugin / ToolSynthesis PASS
0.15.3 Pipeline B orchestrator_hint 실 분기 (linear/iterative/plan_execute) + Stage-local Strategy 자동 스캔
0.15.2 파일시스템 자동 스캔 (fs_scanner) + Tool entry_points + catalog source_file 노출
0.15.1 9 축 자동 연동성 감사 — Phase / Transport / Capability / Provider entry_points 갭 3 개 제거
0.15.0 🎯 재귀적 자율주행 완성Plan.max_iterations + Plan.orchestrator_hint + OrchestratorRegistry + display_name="Auto"
0.14.0 🎯 s07_llm 삭제 + 번호 시프트 — s00_harness 통제탑 승격, TransportStrategy (streaming/batch), harness_mode 3-way
0.13.0 Iterative Planning — 단일 Provider 1 인스턴스, 매 iter replan, Plan.done 조기 종료, previous_results 자동 주입
0.12.0~3 REAL HARNESS Phase 1s00_harness Planner + self-describing catalog + 13 Stage 디렉토리화 + PlanningEvent SSE
0.11.24~27 감사 C+ 9건 해소 — 엔진 독립성 · API 권한 · ErrorEvent trace 차단 · s09_judge provider 주입 · DAG 사이클 명시 실패 · 집계 0 drop 버그
0.11.22~23 count_tokens() 확장점 + PipelineState 도메인 분해 + options_source 11 필드 단일 진실 소스
0.11.21 연결선 3 갭 해소 — HarnessConfig top-level forwarding + s07 output_tokens 집계 + AdvancedContextCompactor ABC
0.11.14~20 Claude Code 5-Level Cascade 이식 + tool_choice API (OpenAI/Anthropic/LangChain 통합) + rag_ingestion_mode + circuit breaker
0.11.0~1 Stage ID 리네이밍 + alias 하위호환 + DecideStrategy 실 구현 + ContentGuard PII 실구현
0.10.0~4 워크플로우 컴파일러 + Strategy Variants + drift-free 연동 + PROVIDER_CONTEXT_LIMITS 레지스트리
0.9.x Stage 책임 재정의 (s01 축소, anthropic 하드코딩 제거)
0.8.x Capability 시스템 + NodeAdapter + Progressive Disclosure + DocumentService 확장
0.5.x ServiceRegistry + ExecutionContext + Plugin System
0.1.0 12 Stage 파이프라인 초기 구현

상세 변경 내역: CHANGELOG.md.


Acknowledgement

설계·UI/UX 영감 및 하네스 구성의 reference — 🎁 geny-executor by CocoRoF.

본 프로젝트의 Stage 고정 + Artifact 교체 패턴, DAG 오케스트레이터 사고, Progressive Disclosure 환경 설계는 geny-executor 에서 많은 영감을 얻었습니다.

v0.16.x 의 자가증식 Sandbox 설계는 xgen-sandbox 아이디어를 차용 (코드 카피 없음 — 스펙만 통합).

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xgen_harness-0.18.0.tar.gz (311.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xgen_harness-0.18.0-py3-none-any.whl (348.9 kB view details)

Uploaded Python 3

File details

Details for the file xgen_harness-0.18.0.tar.gz.

File metadata

  • Download URL: xgen_harness-0.18.0.tar.gz
  • Upload date:
  • Size: 311.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for xgen_harness-0.18.0.tar.gz
Algorithm Hash digest
SHA256 6b890c15c46a873630357a532ec810f7b84cc829701032b603d05804bb9da7cf
MD5 02d10f67fbf3e62d08c1786436d0c4f4
BLAKE2b-256 bea9a17b91f911ab2e5ab3c4757e0b644550adbda8339a2e6dd6a3a479ab442e

See more details on using hashes here.

File details

Details for the file xgen_harness-0.18.0-py3-none-any.whl.

File metadata

  • Download URL: xgen_harness-0.18.0-py3-none-any.whl
  • Upload date:
  • Size: 348.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for xgen_harness-0.18.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1dff19b5a3b202014c622c947a4efba1529b76ae3fb40c71bd8bf7a2a9dd261f
MD5 f6b9f3c3f7458900115cda27df9aba0e
BLAKE2b-256 9dd27f18bc6313d35fea9ece7b6e58564825b46b0c9be91c36ac50072c9ecfd1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page