LlamaCppChatGenerator

LlamaCppChatGenerator

Llama.cpp에서 실행되는 LLM으로 채팅 완성을 만들어주는 컴포넌트예요. 주로 ChatPromptBuilder 뒤에 두면 돼요.

출처: LlamaCppChatGenerator

본문

개요

Llama.cpp는 대규모 언어 모델의 효율적인 추론을 위한 C/C++ 라이브러리예요. 효율적인 양자화 GGUF 형식을 활용해서 메모리 요구량을 크게 줄이고 추론을 가속화해요. 덕분에 표준 머신(GPU 없이도)에서 LLM을 효율적으로 실행할 수 있어요.

Llama.cpp는 GGUF 형식의 LLM 양자화 바이너리 파일을 사용하는데, 이 파일은 Hugging Face에서 다운로드할 수 있어요. LlamaCppChatGenerator는 초기화 때 model 파라미터로 로컬에 저장된 GGUF 파일 경로를 받아서 Llama.cpp에서 실행되는 모델을 지원해요.

도구 지원

LlamaCppChatGenerator는 tools 파라미터를 통해 함수 호출을 지원해요. 유연한 도구 구성을 받아들여요.

  • Tool 객체 목록: 개별 도구를 리스트로 전달.
  • 단일 Toolset: 전체 Toolset을 바로 전달.
  • 도구·Toolset 혼합: 여러 Toolset을 독립 도구와 한 리스트에 결합.

관련 도구를 논리적 그룹으로 묶으면서 필요할 때 독립 도구도 포함할 수 있어요.

from haystack.tools import Tool, Toolset
from haystack_integrations.components.generators.llama_cpp import LlamaCppChatGenerator

# Create individual tools
weather_tool = Tool(
    name="weather", description="Get weather info", parameters=..., function=...
)
news_tool = Tool(
    name="news", description="Get latest news", parameters=..., function=...
)

# Group related tools into a toolset
math_toolset = Toolset([add_tool, subtract_tool, multiply_tool])

# Pass mixed tools and toolsets to the generator
generator = LlamaCppChatGenerator(
    model="/path/to/model.gguf",
    tools=[math_toolset, weather_tool, news_tool], # Mix of Toolset and Tool objects
)

도구 작업에 대한 자세한 내용은 Tool과 Toolset 문서를 참고하세요.

설치

이 통합을 쓰려면 llama-cpp-haystack 패키지를 설치해요.

pip install llama-cpp-haystack

다른 compute 백엔드 사용

기본 설치는 Linux·Windows에서 CPU용으로 llama.cpp를 빌드하고 MacOS에서는 Metal을 사용해요. 다른 compute 백엔드를 쓰려면:

예를 들어 cuBLAS 백엔드와 함께 llama-cpp-haystack를 쓰려면 다음 명령을 실행해야 해요.

export GGML_CUDA=1
CMAKE_ARGS="-DGGML_CUDA=on" pip install llama-cpp-python
pip install llama-cpp-haystack

이 페이지의 예시들은 sentence-transformers-haystack 패키지의 Sentence Transformers 임베더를 사용해요. 예시를 실행하려면 설치하세요.

pip install sentence-transformers-haystack

사용법

  • 원하는 LLM의 GGUF 버전을 다운로드해요. 인기 모델의 GGUF 버전은 Hugging Face에서 받을 수 있어요.
  • GGUF 파일 경로로 LlamaCppChatGenerator를 초기화하고 필요한 모델·텍스트 생성 파라미터를 지정해요.
from haystack_integrations.components.generators.llama_cpp import LlamaCppChatGenerator
from haystack.dataclasses import ChatMessage

generator = LlamaCppChatGenerator(
    model="/content/openchat-3.5-1210.Q3_K_S.gguf",
    n_ctx=512,
    n_batch=128,
    model_kwargs={"n_gpu_layers": -1},
    generation_kwargs={"max_tokens": 128, "temperature": 0.1},
)
messages = [ChatMessage.from_user("Who is the best American actor?")]
result = generator.run(messages)

추가 모델 파라미터 전달

model, n_ctx, n_batch 인자는 편의를 위해 노출됐으며 초기화 때 키워드 인자로 Generator에 직접 전달할 수 있어요. 참고로 model은 llama.cpp의 model_path 파라미터로 변환돼요.

model_kwargs 파라미터로 모델 초기화 때 추가 인자를 전달할 수 있어요. 중복되는 경우 이 파라미터들이 model, n_ctx, n_batch 초기화 파라미터를 덮어써요.

사용 가능한 모델 인자에 대한 자세한 내용은 Llama.cpp의 LLM 문서를 참고하세요.

참고: Llama.cpp는 ChatMessage 형식 적용을 위해 모델 메타데이터에서 chat_template을 자동으로 추출해요. 모델 파라미터로 커스텀 chat_handler나 chat_format을 넘겨 사용되는 chat_template을 덮어쓸 수 있어요.

예를 들어 초기화 때 모델을 GPU로 오프로드하려면:

from haystack_integrations.components.generators.llama_cpp import LlamaCppChatGenerator
from haystack.dataclasses import ChatMessage

generator = LlamaCppChatGenerator(
    model="/content/openchat-3.5-1210.Q3_K_S.gguf",
    n_ctx=512,
    n_batch=128,
    model_kwargs={"n_gpu_layers": -1},
)
messages = [ChatMessage.from_user("Who is the best American actor?")]
result = generator.run(messages, generation_kwargs={"max_tokens": 128})
generated_reply = result["replies"][0].text
print(generated_reply)

텍스트 생성 파라미터 전달

generation_kwargs 파라미터로 max_tokens, temperature, top_k, top_p 같은 추가 생성 인자를 추론 중 모델에 전달할 수 있어요.

사용 가능한 생성 인자에 대한 자세한 내용은 Llama.cpp의 Chat Completion API 문서를 참고하세요.

참고: JSON 모드, 함수 호출, 도구는 모두 generation_kwargs로 지원돼요. 사용법은 llama-cpp-python GitHub README를 참고하세요.

예를 들어 max_tokens와 temperature를 설정하려면:

from haystack_integrations.components.generators.llama_cpp import LlamaCppChatGenerator
from haystack.dataclasses import ChatMessage

generator = LlamaCppChatGenerator(
    model="/content/openchat-3.5-1210.Q3_K_S.gguf",
    n_ctx=512,
    n_batch=128,
    generation_kwargs={"max_tokens": 128, "temperature": 0.1},
)
messages = [ChatMessage.from_user("Who is the best American actor?")]
result = generator.run(messages)

멀티모달(이미지+텍스트) 입력

from haystack.dataclasses import ChatMessage, ImageContent
from haystack_integrations.components.generators.llama_cpp import LlamaCppChatGenerator

# Initialize with multimodal support
llm = LlamaCppChatGenerator(
    model="llava-v1.5-7b-q4_0.gguf",
    chat_handler_name="Llava15ChatHandler", # Use llava-1-5 handler
    model_clip_path="mmproj-model-f16.gguf", # CLIP model
    n_ctx=4096, # Larger context for image processing
)

image = ImageContent.from_file_path("apple.jpg")
user_message = ChatMessage.from_user(
    content_parts=["What does the image show? Max 5 words.", image],
)

response = llm.run([user_message])["replies"][0].text
print(response)

# Red apple on straw.

generation_kwargs는 생성기 자체의 run 메서드에 직접 전달할 수도 있어요.

from haystack_integrations.components.generators.llama_cpp import LlamaCppChatGenerator
from haystack.dataclasses import ChatMessage

generator = LlamaCppChatGenerator(
    model="/content/openchat-3.5-1210.Q3_K_S.gguf",
    n_ctx=512,
    n_batch=128,
)
messages = [ChatMessage.from_user("Who is the best American actor?")]
result = generator.run(
    messages,
    generation_kwargs={"max_tokens": 128, "temperature": 0.1},
)

파이프라인 안에서

Hugging Face의 Simple Wikipedia 데이터셋을 사용하고 OpenChat-3.5 LLM으로 답을 생성하는 Retrieval Augmented Generation 파이프라인에서 LlamaCppChatGenerator를 써 볼게요.

데이터셋 로드:

# Install HuggingFace Datasets using "pip install datasets"
from datasets import load_dataset
from haystack import Document, Pipeline
from haystack.components.builders.answer_builder import AnswerBuilder
from haystack.components.builders import ChatPromptBuilder
from haystack_integrations.components.embedders.sentence_transformers import (
    SentenceTransformersDocumentEmbedder,
    SentenceTransformersTextEmbedder,
)
from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever
from haystack.components.writers import DocumentWriter
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.dataclasses import ChatMessage

# Import LlamaCppChatGenerator
from haystack_integrations.components.generators.llama_cpp import LlamaCppChatGenerator

# Load first 100 rows of the Simple Wikipedia Dataset from HuggingFace
dataset = load_dataset("pszemraj/simple_wikipedia", split="validation[:100]")

docs = [
    Document(
        content=doc["text"],
        meta={
            "title": doc["title"],
            "url": doc["url"],
        },
    )
    for doc in dataset
]

SentenceTransformersDocumentEmbedder와 DocumentWriter로 문서를 InMemoryDocumentStore에 인덱싱:

doc_store = InMemoryDocumentStore(embedding_similarity_function="cosine")
# Install the Sentence Transformers embedders using "pip install sentence-transformers-haystack"
doc_embedder = SentenceTransformersDocumentEmbedder(
    model="sentence-transformers/all-MiniLM-L6-v2",
)

# Indexing Pipeline
indexing_pipeline = Pipeline()
indexing_pipeline.add_component(instance=doc_embedder, name="DocEmbedder")
indexing_pipeline.add_component(
    instance=DocumentWriter(document_store=doc_store),
    name="DocWriter",
)
indexing_pipeline.connect("DocEmbedder", "DocWriter")

indexing_pipeline.run({"DocEmbedder": {"documents": docs}})

RAG 파이프라인을 만들고 LlamaCppChatGenerator를 추가:

system_message = ChatMessage.from_system(
    """
    Answer the question using the provided context.
    Context:
    {% for doc in documents %}
    {{ doc.content }}
    {% endfor %}
    """,
)
user_message = ChatMessage.from_user("Question: {{question}}")
assistent_message = ChatMessage.from_assistant("Answer: ")

chat_template = [system_message, user_message, assistent_message]

rag_pipeline = Pipeline()

text_embedder = SentenceTransformersTextEmbedder(
    model="sentence-transformers/all-MiniLM-L6-v2",
)

# Load the LLM using LlamaCppChatGenerator
model_path = "openchat-3.5-1210.Q3_K_S.gguf"
generator = LlamaCppChatGenerator(model=model_path, n_ctx=4096, n_batch=128)

rag_pipeline.add_component(
    instance=text_embedder,
    name="text_embedder",
)
rag_pipeline.add_component(
    instance=InMemoryEmbeddingRetriever(document_store=doc_store, top_k=3),
    name="retriever",
)
rag_pipeline.add_component(
    instance=ChatPromptBuilder(template=chat_template),
    name="prompt_builder",
)
rag_pipeline.add_component(instance=generator, name="llm")
rag_pipeline.add_component(instance=AnswerBuilder(), name="answer_builder")

rag_pipeline.connect("text_embedder", "retriever")
rag_pipeline.connect("retriever", "prompt_builder.documents")
rag_pipeline.connect("prompt_builder", "llm")
rag_pipeline.connect("llm", "answer_builder")
rag_pipeline.connect("retriever", "answer_builder.documents")

파이프라인 실행:

question = "Which year did the Joker movie release?"
result = rag_pipeline.run(
    {
        "text_embedder": {"text": question},
        "prompt_builder": {"question": question},
        "llm": {"generation_kwargs": {"max_tokens": 128, "temperature": 0.1}},
        "answer_builder": {"query": question},
    },
)

generated_answer = result["answer_builder"]["answers"][0]
print(generated_answer.data)
# The Joker movie was released on October 4, 2019.

더 알아보기 (Learn more)