LLM WikiAccess-protected knowledge portal

WIKI

Haystack 3.0: 훅·스킬·비동기 파이프라인으로 프로덕션 에이전트 프레임워크를 다시 짠 방식

왜 지금 봐야 하나 Haystack 3.0은 2026년 7월 20일에 공개됐다. 이번 릴리스가 중요한 이유는 새 모델 커넥터를 몇 개 더 붙인 정도가 아니라, 에이전트 프레임워크의 운영 경계 세 가지를 한 번에 다시 정했기 때문 이다. 툴 실행은 더 이상 ToolInvoker 같은 별도 컴포넌트가 아니라 Agent 가 직접 소유한다. 많은 스킬과 긴 툴 결과를 프롬프트에 그대로 싣지 않고, progressive disclosu

경로human/study/content/ai-frontier/35-haystack-3-0-hooks-skills-async-pipeline.md
카테고리Study
태그#ai-review #async #cicd #haystack #hooks #pipeline #skills #study

왜 지금 봐야 하나

Haystack 3.0은 2026년 7월 20일에 공개됐다. 이번 릴리스가 중요한 이유는 새 모델 커넥터를 몇 개 더 붙인 정도가 아니라, 에이전트 프레임워크의 운영 경계 세 가지를 한 번에 다시 정했기 때문이다.

에이전트 런타임을 직접 운영하는 팀에게 이 변화는 “새 기능이 생겼다”보다 “어디까지를 core로 믿고, 어디서부터는 명시적으로 묶을지 바뀌었다”에 가깝다.


핵심 변화 한눈에 보기

2.x까지의 중심3.0에서 달라진 점운영자가 바로 받는 영향
에이전트 제어면ToolInvoker + 개별 confirmation 경로Agent가 tool loop·hooks·run metadata를 직접 소유tool 실행, HITL, tracing, loop control이 한 표면으로 합쳐짐
컨텍스트 관리스킬/툴 정의를 upfront로 더 많이 노출SkillToolset의 progressive disclosure, ToolResultOffloadHook긴 지침·긴 툴 결과를 그대로 context에 밀어 넣지 않아도 됨
실행 모델Pipeline / AsyncPipeline 이원화Pipeline 단일 표면 + run_async / stream 통합Jupyter/FastAPI/event loop 경계에서 덜 헷갈리지만, sync/async 의미 차이는 더 명확히 알아야 함
신뢰 경계YAML에 적힌 모듈을 사실상 그대로 importtrusted-module allowlist + dangerous builtin 차단커스텀 컴포넌트 pipeline 로딩 절차를 배포/운영 문서에 넣어야 함
패키징core에 더 많은 integrations 포함haystack-core-integrations로 분리설치 패키지와 import 경로 audit 필요

Haystack 3.0이 다시 그은 세 경계

Haystack 3.0: 제어면, 실행면, 신뢰면을 각각 명시적으로 분리 1) Agent control plane `Agent`가 tool loop를 직접 실행 hooks: `before_llm` → `before_tool` → `after_tool` → `on_exit` run metadata: `step_count`, `token_usage`, `tool_call_counts` ToolInvoker 제거, tracing span이 step 단위로 정리됨 2) Serving/runtime plane `Pipeline` 하나로 sync / async / stream 통합 리소스는 `warm_up()`에서 잡고 `close()`에서 해제 API key 검증 시점도 생성자가 아니라 warm-up/first-run으로 이동 event loop 안에서 sync/async 경계가 더 분명해짐 3) Trust/package plane YAML deserialization이 allowlist 뒤로 이동 integrations 분리 + legacy generator 제거 import path, 설치 패키지, unsafe bypass를 직접 관리해야 함 "trusted source인가"가 배포 체크리스트로 올라옴 실무 해석 Prompt budget 스킬은 이름/설명만 먼저 보고 필요할 때만 본문을 연다 Run lifecycle 생성자에서 다 준비하지 않고 warm-up / close로 생명주기를 묶는다 Supply-chain trust pipeline YAML을 앱 설정처럼 보지 말고 실행 가능한 artifact로 취급해야 한다 결국 3.0은 “Agent를 더 똑똑하게 만들었다”보다 “Agent를 어떤 경계와 수명주기로 운영할 것인지”를 코드 표면에 강제한 릴리스다. 따라서 도입 검증도 답변 품질만 보지 말고, tool loop 제어, context budget, event loop, deserialization trust를 함께 봐야 한다.
Haystack 3.0의 세 경계: Agent control plane, serving runtime, trust boundary

1. ToolInvoker가 사라지면서 Agent가 진짜 제어면이 됐다

Haystack 2.x에서는 툴 호출을 별도 컴포넌트로 두고 LLM 결과를 그쪽으로 넘기는 사고방식이 남아 있었다. 3.0의 migration guide는 이 점을 명확히 끊는다. ToolInvoker는 제거됐고, tool execution은 Agent가 직접 소유한다.

이 변화가 중요한 이유는 단순한 import 변경이 아니기 때문이다.

이제 이 여섯 가지가 한 객체 안에 모인다.

run metadata가 public surface로 올라왔다

Agent 소스는 step_count, token_usage, tool_call_counts를 예약된 run metadata state로 둔다. 또 step 실행은 haystack.agent.step span 아래에서 LLM 호출과 tool 실행을 나눠 기록한다. 이건 observability에 직접적인 의미가 있다.

즉, 3.0의 Agent는 단순 채팅 루프가 아니라 상태를 가진 workflow runtime 쪽으로 가까워졌다.

Human-in-the-Loop도 별도 특례가 아니라 훅으로 흡수됐다

기존의 confirmation 전략은 독자 표면을 가졌지만, 3.0에서는 ConfirmationHookbefore_tool에 거는 식으로 정리됐다. 이 설계가 좋은 이유는 “사람 승인”을 특례로 다루지 않고, 도구 실행 직전의 개입 지점이라는 일반 규칙으로 끌어올렸기 때문이다.

운영 측면에서 얻는 장점은 분명하다.

  1. tool 승인, 수정, 거부가 다른 훅들과 같은 모델로 표현된다.
  2. request-scoped resource는 hook_context로 흘려보내면 된다.
  3. 승인 로직을 별도 제어면으로 취급하지 않아도 된다.

하지만 tradeoff도 있다.


2. 스킬과 긴 툴 결과를 프롬프트에 전부 싣지 않는 방향으로 갔다

Haystack 3.0의 진짜 실용 변화는 agent control plane만이 아니다. 컨텍스트 예산을 다루는 방식도 꽤 크게 바뀌었다.

SkillToolset: 이름과 설명만 먼저 노출하는 progressive disclosure

SkillToolset은 warm-up 시점에 skill store를 스캔해 스킬 이름과 한 줄 설명만 load_skill tool 설명에 baked-in 한다. 모델은 일단 어떤 스킬이 있는지만 보고, 필요할 때 load_skill로 본문을 불러온다.

이 구조는 두 가지를 동시에 노린다.

이건 운영자에게 중요한 신호다. 앞으로는 “에이전트가 어떤 문서를 볼 수 있나”만이 아니라, 그 문서를 어떤 단계에서 context로 올릴지까지 설계 대상으로 봐야 한다.

ToolResultOffloadHook: 큰 결과는 store에 내리고 포인터만 남긴다

ToolResultOffloadHookafter_tool에서 동작하면서 긴 텍스트 결과를 store에 쓰고, 대화에는 preview + reference만 남긴다. 소스를 보면 이 훅은 특히 multi-user 환경을 꽤 의식한다.

즉, 이 기능은 단순한 token-saving trick이 아니다. tool 결과를 conversation에서 분리하는 저장 경계를 새로 만드는 기능이다.

여기서 바로 생기는 운영 규칙

상황3.0에서 더 좋은 선택이유
스킬 수가 많고 instruction이 길다SkillToolset으로 이름/설명만 먼저 노출초기 context를 얇게 유지
웹 검색/파일 읽기 결과가 길다ToolResultOffloadHook + 세션별 storecontext window 보호 + 사용자 간 격리
이미지/파일 결과가 많다아직 offload만 믿지 말고 별도 설계offload는 성공한 text output 중심

3. Pipeline 하나로 sync/async를 통일했지만, 의미까지 같아진 것은 아니다

AsyncPipeline 제거는 표면만 보면 단순하다. 하지만 실무에서는 오히려 어느 경로가 concurrent이고 어느 경로가 sequential인지 더 엄격하게 구분해야 한다는 뜻이다.

바뀐 점은 명확하다

그런데 운영자는 이 차이를 의식해야 한다

migration guide는 매우 노골적으로 적어 둔다.

즉, 2.x에서 “sync처럼 보이지만 사실 async engine wrapper였던” 감각으로 코드를 쓰던 팀은 3.0에서 행동을 다시 정리해야 한다.

warm_up / close가 중요해진 이유

같은 문서에서 OpenAI/Azure OpenAI 계열 컴포넌트는 외부 리소스를 __init__이 아니라 warm_up()에서 만들도록 바뀌었다고 설명한다. 이건 사소한 변경처럼 보여도, long-running service 운영에는 꽤 중요하다.

이건 프레임워크가 “노트북용 utility”보다 서버에 오래 떠 있는 런타임 쪽으로 설계를 돌렸다는 신호다.


4. 3.0은 pipeline YAML을 더 이상 무해한 설정 파일로 취급하지 않는다

가장 운영자다운 변화는 deserialization allowlist다. 이제 Pipeline.load, Pipeline.loads, Pipeline.from_dict는 신뢰된 모듈 목록 밖의 클래스를 로드하지 않는다.

기본 allowlist는 제한적이다.

그리고 builtins가 allowlist에 들어 있어도 eval, exec, open, getattr, __import__ 같은 위험 builtin은 별도 denylist로 막는다.

왜 이게 중요하나

이전에는 pipeline YAML이 사실상 임의 import를 유도할 수 있는 실행 artifact였다. 3.0은 이 사실을 더 숨기지 않는다. 그래서 운영 절차도 바뀌어야 한다.

  1. 커스텀 컴포넌트를 쓰는 pipeline은 배포 문서에 allowlist 등록 절차를 적는다.
  2. unsafe=True는 “빨리 되게 만드는 옵션”이 아니라 신뢰 우회라는 의미로 취급한다.
  3. pipeline 저장소와 코드 저장소를 분리해 관리했다면, 이제는 YAML provenance도 같이 관리해야 한다.

실제로 해야 할 선택

선택지언제 쓰는가운영 판단
allowed_modules=[...]앱이 정확히 필요한 모듈을 안다가장 명시적이고 안전한 기본값
allow_deserialization_module(...)프로세스 전체에서 반복적으로 같은 커스텀 모듈을 쓴다앱 엔트리포인트에 기록 필요
HAYSTACK_DESERIALIZATION_ALLOWLIST배포 레벨에서 제어하고 싶다IaC/런북에 남기기 좋음
unsafe=True완전히 신뢰하는 artifact를 일시적으로 읽는다상시 기본값으로 두면 안 됨

5. 코어는 가벼워졌지만 업그레이드 조각은 늘었다

3.0은 haystack-core-integrations 쪽으로 많은 컴포넌트를 밖으로 뺐다. 동시에 legacy generator들도 정리했다. 이건 방향 자체는 맞다. core 릴리스와 integration 릴리스를 분리하면, 작은 수정 때문에 코어 전체를 묶어서 배포하지 않아도 되기 때문이다.

하지만 업그레이드 관점에서는 귀찮은 일이 늘어난다.

가장 먼저 부딪히는 변화

그래서 upgrade PR에서는 무엇을 꼭 봐야 하나

  1. requirements / pyproject.toml에 integration package가 빠지지 않았는가
  2. import path만 바꾸고 실제 runtime dependency 설치는 놓치지 않았는가
  3. pipeline output에서 meta를 별도 socket으로 기대하는 코드가 남아 있지 않은가
  4. Document.id를 auto-generated 값으로 저장소 키처럼 쓰고 있었다면, non-empty meta가 있는 문서 재적재 계획이 있는가

여기서 중요한 건, 3.0의 core slimming이 성능 최적화가 아니라 릴리스 독립성과 의존성 경계 정리라는 점이다. 그러니 도입 검증도 benchmark보다 package graph와 import audit을 먼저 보는 편이 맞다.


도입 전에 해볼 검증 체크리스트

1) Agent 제어면 검증

2) 컨텍스트/스토어 검증

3) Pipeline 실행 검증

4) 신뢰/패키지 검증


이 릴리스에서 특히 조심할 한계

결국 Haystack 3.0의 핵심은 agent feature를 더 얹은 것이 아니라, 에이전트를 운영하는 사람이 어디서 개입하고 어디를 신뢰해야 하는지 코어 표면에서 강제하기 시작했다는 데 있다. 그래서 이 버전의 평가는 “에이전트가 더 잘 답하나”보다, “우리 시스템이 더 예측 가능하게 동작하나”에 먼저 두는 편이 맞다.

References