마이그레이션 가이드

마이그레이션 가이드 (Migration Guide)

Haystack 2.x를 쓰다가 3.x로 올라가려는 분들을 위한 가이드예요. 모든 브레이킹 체인지(breaking change)를 하나씩 짚고, 코드를 어떻게 바꿔야 하는지 보여드릴게요. 처음 Haystack을 시작하는 분이라면 이 페이지는 건너뛰고 Get Started 가이드로 바로 가면 됩니다.

출처: 공식문서

큰 그림: 2.x와 3.x는 무엇이 다른가?

Haystack 3.x는 2.x의 진화이지 재작성(rewrite)이 아니에요. 컴포넌트, 파이프라인, Agent는 이전처럼 작동합니다. 대부분의 애플리케이션은 import 업데이트와 작은 기계적인 변경만으로 옮겨갈 수 있어요. 브레이킹 체인지 전체 목록과 확장된 예제는 Haystack 저장소의 MIGRATION.md에 유지되고 있습니다.

코딩 에이전트로 마이그레이션하고 싶다면, 이 양식을 작성해 Haystack v3 마이그레이션 스킬 접근 권한을 받을 수 있어요.

설치 업데이트하기 (Update Your Installation)

패키지 이름은 그대로입니다:

pip install --upgrade haystack-ai

알아둬야 할 의존성 변경 두 가지가 있어요:

  • haystack-experimental이 더 이상 자동으로 설치되지 않습니다. 이 패키지는 이제 아카이브되어 유지보수되지 않으며, 0.19.0.post1이 마지막 릴리스예요. haystack_experimental을 아직 import하는 코드가 있다면 명시적으로 설치하고 버전을 고정(pin)하세요: pip install "haystack-experimental==0.19.0.post1". 대부분의 실험은 haystack-ai 자체로 승격되었으니, import를 core 버전으로 옮기는 것을 우선적으로 고려하세요.
  • 여러 컴포넌트가 전용 통합 패키지로 이동했고, 이제 추가 pip install이 필요해요. 아래 "통합 패키지로 이동한 컴포넌트"를 참고하세요.

제거·이름 변경된 컴포넌트 (Removed and Renamed Components)

레거시 Generator 제거

OpenAIGenerator, AzureOpenAIGenerator, HuggingFaceAPIGenerator, HuggingFaceLocalGenerator가 제거됐어요. 대체재는 그것들의 채팅 버전입니다: Haystack core의 OpenAIChatGeneratorAzureOpenAIChatGenerator, huggingface-api-haystack 통합의 HuggingFaceAPIChatGenerator, 그리고 transformers-haystack 통합의 TransformersChatGenerator(이름이 바뀐 HuggingFaceLocalChatGenerator)예요. 모든 ChatGenerator는 이제 평범한 str 입력도 받으므로, 단순한 텍스트-in/텍스트-out 사용 사례는 구조 변경이 거의 필요 없습니다.

Before (v2.x):

from haystack.components.generators import OpenAIGenerator

gen = OpenAIGenerator()
result = gen.run("What is NLP?")

text = result["replies"][0]  # str
meta = result["meta"][0]  # dict with model metadata

After (v3.0):

from haystack.components.generators.chat import OpenAIChatGenerator

gen = OpenAIChatGenerator()
result = gen.run("What is NLP?")  # str input accepted directly

reply = result["replies"][0]  # ChatMessage
text = reply.text  # str
meta = reply.meta  # dict with model metadata (now on the message)

PromptBuilder(출력: str)을 레거시 Generator에 연결했던 파이프라인은 ChatGenerator로 바꿔도 그대로 동작해요. 파이프라인 타입 시스템이 연결 지점에서 strlist[ChatMessage]로 자동 변환하기 때문입니다. 두 가지 짚고 갈 점:

  • 레거시 Generator의 별도 meta 출력 소켓은 사라졌어요. pipeline.connect("llm.meta", ...) 호출은 제거하세요. 답변별 메타데이터는 이제 각 ChatMessage.meta에 있으며, AnswerBuilder가 거기서 자동으로 읽습니다.
  • 시스템 프롬프트를 설정하려면 제거된 system_prompt init 파라미터 대신 메시지 앞에 ChatMessage.from_system(...)을 붙이세요.

ToolInvoker 제거

도구 실행은 이제 Agent 컴포넌트가 담당해요. ChatGenerator를 ToolInvoker에 연결하는 대신 도구를 Agent에 전달하면 됩니다. Agent가 도구 정의를 채팅 생성기로 전달하고, 요청된 도구 호출을 실행하며, 도구 결과를 대화에 덧붙이고, 종료 조건에 도달할 때까지 반복합니다.

Before (v2.x):

from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.tools import ToolInvoker
from haystack.dataclasses import ChatMessage

chat_generator = OpenAIChatGenerator(tools=[weather])
tool_invoker = ToolInvoker(tools=[weather])

llm_result = chat_generator.run(
    messages=[ChatMessage.from_user("What is the weather in Berlin?")],
)
tool_result = tool_invoker.run(messages=llm_result["replies"])

After (v3.0):

from haystack.components.agents import Agent
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage

agent = Agent(
    chat_generator=OpenAIChatGenerator(),
    tools=[weather],
)
result = agent.run(messages=[ChatMessage.from_user("What is the weather in Berlin?")])

Agenttool_invoker_kwargs 파라미터는 사라졌고, 관련 옵션은 이제 최상위 생성자 파라미터가 됐어요:

  • max_workerstool_concurrency_limit
  • enable_streaming_callback_passthroughtool_streaming_callback_passthrough
  • convert_result_to_json_string은 제거됨: 문자열이 아닌 도구 결과는 이제 항상 json.dumps로 직렬화됩니다.

Agent 밖에서 준비된 도구 호출을 실행해야 한다면 Tool.invoke를 직접 호출하고, 결과를 ChatMessage.from_tool 메시지로 모델에 보내면 됩니다.

기타 제거 및 이름 변경

v2.x v3.0 대체재
TransformersSimilarityRanker SentenceTransformersSimilarityRanker (동일 파라미터 수용, async 지원 추가)
DALLEImageGenerator OpenAIImageGenerator (동일 API; OpenAI가 DALL-E 계열을 은퇴시킨 뒤 이름 변경)
AsyncPipeline Pipeline (아래 Pipeline 변경 참고)

통합 패키지로 이동한 컴포넌트 (Components Moved to Integration Packages)

일부 컴포넌트가 Haystack core 밖으로 나와 haystack-core-integrations 저장소에 호스팅되는 전용 통합 패키지로 옮겨졌어요. 이렇게 하면 core를 가볍게 유지하고 수정 사항이 Haystack 릴리스 주기와 무관하게 배포될 수 있죠. 마이그레이션하려면 새 패키지를 설치하고(pip install <new-package>) import를 업데이트하세요:

기존 import (haystack-ai<3.0.0) 새 패키지 새 import
from haystack.components.generators.chat import HuggingFaceAPIChatGenerator huggingface-api-haystack from haystack_integrations.components.generators.huggingface_api import HuggingFaceAPIChatGenerator
from haystack.components.embedders import HuggingFaceAPITextEmbedder huggingface-api-haystack from haystack_integrations.components.embedders.huggingface_api import HuggingFaceAPITextEmbedder
from haystack.components.embedders import HuggingFaceAPIDocumentEmbedder huggingface-api-haystack from haystack_integrations.components.embedders.huggingface_api import HuggingFaceAPIDocumentEmbedder
from haystack.components.rankers import HuggingFaceTEIRanker huggingface-api-haystack from haystack_integrations.components.rankers.huggingface_api import HuggingFaceTEIRanker
from haystack.components.generators.chat import HuggingFaceLocalChatGenerator transformers-haystack from haystack_integrations.components.generators.transformers import TransformersChatGenerator
from haystack.components.readers import ExtractiveReader transformers-haystack from haystack_integrations.components.readers.transformers import TransformersExtractiveReader
from haystack.components.classifiers import TransformersZeroShotDocumentClassifier transformers-haystack from haystack_integrations.components.classifiers.transformers import TransformersZeroShotDocumentClassifier
from haystack.components.routers import TransformersTextRouter transformers-haystack from haystack_integrations.components.routers.transformers import TransformersTextRouter
from haystack.components.routers import TransformersZeroShotTextRouter transformers-haystack from haystack_integrations.components.routers.transformers import TransformersZeroShotTextRouter
from haystack.components.extractors import NamedEntityExtractor (Hugging Face backend) transformers-haystack from haystack_integrations.components.extractors.transformers import TransformersNamedEntityExtractor
from haystack.components.extractors import NamedEntityExtractor (spaCy backend) spacy-haystack from haystack_integrations.components.extractors.spacy import SpacyNamedEntityExtractor
from haystack.components.embedders import SentenceTransformersTextEmbedder sentence-transformers-haystack from haystack_integrations.components.embedders.sentence_transformers import SentenceTransformersTextEmbedder
from haystack.components.embedders import SentenceTransformersDocumentEmbedder sentence-transformers-haystack from haystack_integrations.components.embedders.sentence_transformers import SentenceTransformersDocumentEmbedder
from haystack.components.embedders import SentenceTransformersSparseTextEmbedder sentence-transformers-haystack from haystack_integrations.components.embedders.sentence_transformers import SentenceTransformersSparseTextEmbedder
from haystack.components.embedders import SentenceTransformersSparseDocumentEmbedder sentence-transformers-haystack from haystack_integrations.components.embedders.sentence_transformers import SentenceTransformersSparseDocumentEmbedder
from haystack.components.embedders.image import SentenceTransformersDocumentImageEmbedder sentence-transformers-haystack from haystack_integrations.components.embedders.sentence_transformers import SentenceTransformersDocumentImageEmbedder
from haystack.components.rankers import SentenceTransformersSimilarityRanker sentence-transformers-haystack from haystack_integrations.components.rankers.sentence_transformers import SentenceTransformersSimilarityRanker
from haystack.components.rankers import SentenceTransformersDiversityRanker sentence-transformers-haystack from haystack_integrations.components.rankers.sentence_transformers import SentenceTransformersDiversityRanker
from haystack.components.websearch import SerperDevWebSearch serperdev-haystack from haystack_integrations.components.websearch.serperdev import SerperDevWebSearch
from haystack.components.websearch import SearchApiWebSearch searchapi-haystack from haystack_integrations.components.websearch.searchapi import SearchApiWebSearch
from haystack.components.classifiers import DocumentLanguageClassifier langdetect-haystack from haystack_integrations.components.classifiers.langdetect import DocumentLanguageClassifier
from haystack.components.routers import TextLanguageRouter langdetect-haystack from haystack_integrations.components.routers.langdetect import TextLanguageRouter
from haystack.components.audio import LocalWhisperTranscriber whisper-haystack from haystack_integrations.components.audio.whisper import LocalWhisperTranscriber
from haystack.components.audio import RemoteWhisperTranscriber whisper-haystack from haystack_integrations.components.audio.whisper import RemoteWhisperTranscriber
from haystack.components.converters import TikaDocumentConverter tika-haystack from haystack_integrations.components.converters.tika import TikaDocumentConverter
from haystack.components.converters import AzureOCRDocumentConverter azure-form-recognizer-haystack from haystack_integrations.components.converters.azure_form_recognizer import AzureOCRDocumentConverter
from haystack.components.connectors import OpenAPIConnector openapi-haystack from haystack_integrations.components.connectors.openapi import OpenAPIConnector
from haystack.components.connectors import OpenAPIServiceConnector openapi-haystack from haystack_integrations.components.connectors.openapi import OpenAPIServiceConnector
from haystack.components.converters import OpenAPIServiceToFunctions openapi-haystack from haystack_integrations.components.converters.openapi import OpenAPIServiceToFunctions
from haystack.tracing.datadog import DatadogTracer datadog-haystack from haystack_integrations.tracing.datadog import DatadogTracer
from haystack.tracing import OpenTelemetryTracer opentelemetry-haystack from haystack_integrations.tracing.opentelemetry import OpenTelemetryTracer

파이프라인 변경 (Pipeline Changes)

AsyncPipelinePipeline에 병합됨

AsyncPipeline 클래스가 제거됐어요. 그 비동기 메서드(run_async, run_async_generator, stream)는 이제 단일 Pipeline 클래스의 일부이며, 동기식 run과 함께 사용합니다.

Before (v2.x):

from haystack import AsyncPipeline

pipeline = AsyncPipeline()
result = await pipeline.run_async(data)

After (v3.0):

from haystack import Pipeline

pipeline = Pipeline()
result = await pipeline.run_async(data)

동기식 AsyncPipeline.run()을 사용하고 있었다면 주의하세요. 그 메서드는 동시 실행 async 엔진을 감싼 것이었기 때문에 Pipeline.run()이 완전히 대체재는 아니에요. 의도에 따라 고르세요:

# Keep concurrent execution from sync code:
result = asyncio.run(pipeline.run_async(data, concurrency_limit=4))

# Sequential execution is fine:
result = pipeline.run(data)  # components run one at a time; no concurrency_limit

Pipeline.run은 컴포넌트를 순차 실행하며 concurrency_limit을 받지 않는다는 점을 기억하세요. 동시 실행은 run_async / run_async_generator만 지원합니다. 또 breakpoints를 지원하는 것은 run 뿐이에요.

역직렬화(Deserialization)는 모듈 허용 목록으로 제한됨

Pipeline.load, Pipeline.loads, Pipeline.from_dict는 이제 신뢰할 수 있는 모듈 허용 목록(allowlist) 밖의 클래스를 import하기를 거부하고, 대신 DeserializationError를 던져요. 기본 허용 목록에는 haystack, haystack_integrations, haystack_experimental, builtins, typing, collections이 포함되어 있어서, Haystack 자체 패키지만 참조하는 파이프라인은 변경 없이 그대로 로드됩니다.

다른 패키지의 커스텀 컴포넌트, 콜러블, 타입을 참조하는 파이프라인은 추가 모듈을 명시적으로 허용해야 해요:

from haystack import Pipeline

# 1. Per-call kwarg — recommended for application code.
with open("pipeline.yaml") as fp:
    pipeline = Pipeline.load(fp, allowed_modules=["mypkg.*"])

# 2. Per-call bypass — "I fully trust this YAML; skip the allowlist".
with open("pipeline.yaml") as fp:
    pipeline = Pipeline.load(fp, unsafe=True)

# 3. Process-wide — call once at startup.
from haystack.core.serialization import allow_deserialization_module
allow_deserialization_module("mypkg.*")
# 4. Environment variable — useful for deployments where code shouldn't change.
export HAYSTACK_DESERIALIZATION_ALLOWLIST="mypkg.*,otherpkg.*"

자세한 내용은 Serialization 페이지를 참고하세요.

Agent 변경 (Agent Changes)

프롬프트 템플릿 변수는 기본적으로 필수

PromptBuilderChatPromptBuilder는 이제 모든 Jinja2 템플릿 변수를 필수로 취급합니다. 이전에는 변수가 기본적으로 선택 사항이었고, 누락된 값은 조용히 빈 문자열로 렌더링됐죠. required_variables 파라미터의 기본값이 None(전부 선택)에서 "*"(전부 필수)로 바뀌었습니다.

from haystack.components.builders import PromptBuilder

# Option 1: provide every variable (matches the new safe default).
builder = PromptBuilder(template="Hello, {{ name }}! {{ greeting }}")
builder.run(name="John", greeting="Welcome")

# Option 2: declare which variables are required; everything else stays optional.
builder = PromptBuilder(
    template="Hello, {{ name }}! {{ greeting }}",
    required_variables=["name"],
)
builder.run(name="John")  # greeting renders as ""

# Option 3: restore the old "all optional" behavior.
builder = PromptBuilder(
    template="Hello, {{ name }}! {{ greeting }}",
    required_variables=None,
)
builder.run(name="John")  # greeting renders as ""

Agentuser_promptsystem_prompt의 모든 Jinja2 템플릿 변수를 필수로 취급합니다. required_variables=["var1", "var2"]를 넘기면 일부만 필수로 지정하거나, required_variables=None으로 옛 "전부 선택" 동작을 되살릴 수 있어요.

에이전트 전용 브레이크포인트 API 제거

에이전트 전용 브레이크포인트 API(AgentBreakpoint, ToolBreakpoint, AgentSnapshot, 그리고 Agent.runbreak_point / snapshot / snapshot_callback 파라미터)가 제거됐어요. Agent 내부 실행을 일시 중지·재개하는 것은 더 이상 지원되지 않습니다. 파이프라인 레벨 브레이크포인트가 일반적인 디버깅 사용 사례를 여전히 커버하고, tracing이 Agent 동작을 조사하는 권장 방법이에요.

실행 시점 프롬프트 제약

Agent.runAgent.run_async는 더 이상 system_promptuser_prompt를 받지 않으며, 둘 다 초기화 시점에 설정해야 해요. 실행마다 프롬프트를 조립해야 한다면, Agent 앞에서 ChatMessage 객체를 만들고(예: ChatPromptBuilder로) messages 입력으로 전달하면 됩니다. messages 맨 앞의 시스템 메시지가 런타임 시스템 프롬프트 역할을 해요. 같은 변경이 LLM 컴포넌트에도 적용됩니다.

State 읽기는 명시적 매핑 필요

도구는 inputs_from_state 매핑을 명시적으로 선언할 때만 Agent의 State에서 이름으로 값을 읽습니다. 옛 암묵적 동작 — State 키와 이름이 일치하는 어떤 도구 파라미터든 조용히 State에서 채워지는 것 — 은 제거됐어요. State에서 읽어야 하는 도구에는 inputs_from_state={"state_key": "parameter_name"}을 추가하세요. State-애노테이션 파라미터를 통해 전체 State 객체를 받는 도구는 영향이 없습니다.

예약된 state_schema

Agent는 이제 state_schema에서 step_count, token_usage, tool_call_counts, continue_run, tools, hook_context 이름을 예약하고, 이 중 하나라도 넘기면 ValueError를 던져요. 충돌하는 항목은 이름을 바꾸세요.

Human-in-the-Loop 확인은 이제 before_tool

confirmation_strategiesconfirmation_strategy_context 파라미터가 제거됐어요. 확인 전략을 before_tool 훅 포인트에 등록된 ConfirmationHook으로 감싸고, 요청 스코프 리소스는 범용 hook_context 실행 인자로 전달하세요:

Before (v2.x):

agent = Agent(
    chat_generator=...,
    tools=[...],
    confirmation_strategies={"my_tool": BlockingConfirmationStrategy(...)},
)
agent.run(
    messages=[...],
    confirmation_strategy_context={"websocket": ws},
)

After (v3.0):

from haystack.hooks.human_in_the_loop import ConfirmationHook

confirmation_hook = ConfirmationHook(
    confirmation_strategies={"my_tool": BlockingConfirmationStrategy(...)},
)
agent = Agent(
    chat_generator=...,
    tools=[...],
    hooks={"before_tool": [confirmation_hook]},
)
agent.run(messages=[...], hook_context={"websocket": ws})

전체 워크스루는 Human-in-the-Loop을 참고하세요. 또한 확인 전략은 이제 모델이 만든 도구 인자만 보게 되며, State에서 주입된 값은 실행 시점에 적용되고 더 이상 확인 대상에 포함되지 않아요.

동작 변경 (Behavior Changes)

비어 있지 않은 meta를 가진 문서의 자동 생성 Document.id 변경

Document.id를 자동 생성하는 데 쓰는 해시가 이제 meta의 표준(키 정렬) JSON 직렬화에서 계산됩니다. 그래서 ID가 더 이상 meta 키의 삽입 순서에 의존하지 않아요. meta가 비어 있는 문서는 v2.x ID를 유지하지만, meta가 비어 있지 않은 문서는 3.0에서 다른 ID를 얻습니다.

Haystack 2.x가 작성한 Document Store에 이미 저장된 문서와 자동 생성 ID가 일치하는 것에 의존한다면, 영향을 받는 문서를 다시 인제스트하거나, 이전 id를 명시적으로 넘기거나, 저장된 ID를 제자리에서 마이그레이션하면 됩니다: 저장된 문서를 읽고, Haystack 3.x로 ID를 재생성한 뒤(replace(doc, id="")), 다시 쓰고, 옛 ID 아래의 항목을 삭제하세요. 완전한 예제 스크립트는 MIGRATION.md에 있습니다.

로깅이 더 이상 프로세스 전체를 재구성하지 않음

Haystack을 import해도 더 이상 포맷팅 핸들러를 루트 로거에 붙이거나 structlog를 프로세스 전체에 설정하지 않아요. 핸들러는 haystack, haystack_integrations, haystack_experimental 네임스페이스로 한정됩니다. 옛 프로세스 전체 동작을 되살리려면 configure_logging(logger_name="")을 호출하고, 내 애플리케이션도 루트 로거를 설정할 때 중복 로그 라인을 막으려면 configure_logging(propagate=False)를 호출하세요. 자세한 내용은 Logging 페이지를 참고하세요.

트레이싱이 더 이상 자동 활성화되지 않음

해당 SDK가 설치되어 있어도 Haystack이 더 이상 Datadog이나 OpenTelemetry 트레이싱을 자동 활성화하지 않으며, 두 트레이서 모두 통합 패키지(datadog-haystack, opentelemetry-haystack)로 옮겨졌어요. 통합의 커넥터 컴포넌트(DatadogConnector, OpenTelemetryConnector)를 파이프라인에 추가하거나, 트레이서로 haystack.tracing.enable_tracing(...)을 호출해서 명시적으로 활성화하세요. HAYSTACK_AUTO_TRACE_ENABLED 환경 변수는 더 이상 효과가 없습니다. 자세한 내용은 Tracing을 참고하세요.

API 키는 워밍업(warm-up) 시점에 확인

외부 서비스(OpenAI, Azure OpenAI 같은)를 쓰는 컴포넌트는 이제 __init__ 대신 warm_up() 중에 API 클라이언트를 만듭니다. 누락된 API 키는 생성 시점이 아니라 워밍업 또는 첫 실행 때 보고돼요.

to_dict() 출력 구조 변경

GeneratedAnswer.to_dict()ExtractedAnswer.to_dict()는 이제 {"type": ..., "init_parameters": {...}} 봉투(envelope)로 감싸는 대신 객체 필드의 평평한 딕셔너리를 반환하며, 다른 Haystack 데이터 클래스와 정렬됩니다. from_dict()는 여전히 옛 봉투 형식을 받아들이므로, 기존 직렬화 아티팩트는 계속 로드돼요. 직렬화된 출력을 읽는 코드는 init_parameters 아래가 아니라 최상위 레벨에서 필드에 접근하도록 업데이트하세요.

Haystack 1.x에서 마이그레이션하기

Haystack 1.x(farm-haystack 패키지)는 3.0보다 훨씬 전에 수명이 끝났어요. 아직 1.x를 쓰고 있다면 먼저 haystack-ai 패키지로 마이그레이션하세요. 1.x→2.x 마이그레이션을 다루던 이 페이지의 이전 버전은 저장소의 v2 브랜치에 보존되어 있습니다. 아카이브된 1.x 문서는 ZIP 파일로, 옛 튜토리얼은 GitHub 히스토리에서 확인할 수 있어요.

더 알아보기 (Learn more)