LlamaIndex 챗 엔진 사용 패턴

LlamaIndex 챗 엔진 사용 패턴 (Usage Pattern)

챗 엔진으로 데이터와 대화하는 실제 패턴을 순서대로 볼게요. 인덱스에서 챗 엔진을 만드는 것부터 시작해요.

시작하기

인덱스에서 챗 엔진을 만들어요.

chat_engine = index.as_chat_engine()

💡 팁: 인덱스 만드는 법은 Indexing 문서를 참고하세요.

데이터와 대화를 시작해요.

response = chat_engine.chat("Tell me a joke.")

대화 히스토리를 리셋해 새 대화를 시작하려면:

chat_engine.reset()

대화형 채팅 REPL에 들어가려면:

chat_engine.chat_repl()

출처: 공식문서

챗 엔진 구성하기

챗 엔진 구성은 쿼리 엔진 구성과 아주 비슷해요.

하이레벨 API

인덱스에서 한 줄로 챗 엔진을 만들고 구성할 수 있어요.

chat_engine = index.as_chat_engine(chat_mode="condense_question", verbose=True)

⚠️ 참고: chat_mode를 kwarg로 지정하면 다른 챗 엔진에 접근할 수 있어요. condense_questionCondenseQuestionChatEngine, reactReActChatEngine, contextContextChatEngine에 대응해요.

⚠️ 참고: 하이레벨 API는 사용 편의성에 최적화되어 있지만, 완전한 범위의 구성 가능성을 노출하지는 않아요.

사용 가능한 챗 모드

  • best - 쿼리 엔진을 도구로 바꿔서, LLM이 지원하는 것에 따라 ReAct 데이터 에이전트나 OpenAI 데이터 에이전트와 함께 사용해요. OpenAI 데이터 에이전트는 OpenAI의 함수 호출 API를 쓰기 때문에 gpt-3.5-turbo 또는 gpt-4가 필요해요.
  • condense_question - 채팅 히스토리를 보고 사용자 메시지를 인덱스용 쿼리로 다시 작성해요. 쿼리 엔진의 응답을 읽고 나서 응답을 반환해요.
  • context - 모든 사용자 메시지로 인덱스에서 노드를 검색해요. 검색된 텍스트가 시스템 프롬프트에 삽입돼서, 챗 엔진이 자연스럽게 응답하거나 쿼리 엔진의 맥락을 사용할 수 있어요.
  • condense_plus_context - condense_questioncontext의 조합이에요. 채팅 히스토리를 보고 사용자 메시지를 인덱스용 검색 쿼리로 다시 작성해요. 검색된 텍스트가 시스템 프롬프트에 삽입돼서, 챗 엔진이 자연스럽게 응답하거나 쿼리 엔진의 맥락을 사용할 수 있어요.
  • simple - 쿼리 엔진 없이 LLM과 직접 단순하게 대화해요.
  • react - best와 같지만 ReAct 데이터 에이전트를 강제로 사용해요.
  • openai - best와 같지만 OpenAI 데이터 에이전트를 강제로 사용해요.

로우레벨 조합 API

더 세밀한 제어가 필요하면 로우레벨 조합 API를 쓸 수 있어요. 구체적으로는 index.as_chat_engine(...)을 호출하는 대신 ChatEngine 객체를 직접 생성해요.

⚠️ 참고: API 레퍼런스나 예제 노트북을 확인해야 할 수 있어요.

여기서는 이런 것들을 구성하는 예시예요.

  • condense question 프롬프트 구성,
  • 기존 히스토리로 대화 초기화,
  • verbose 디버그 메시지 출력.
from llama_index.core import PromptTemplate
from llama_index.core.llms import ChatMessage, MessageRole
from llama_index.core.chat_engine import CondenseQuestionChatEngine


custom_prompt = PromptTemplate(
    """\
Given a conversation (between Human and Assistant) and a follow up message from Human, \
rewrite the message to be a standalone question that captures all relevant context \
from the conversation.


<Chat History>
{chat_history}


<Follow Up Message>
{question}


<Standalone question>
"""
)


# list of `ChatMessage` objects
custom_chat_history = [
    ChatMessage(
        role=MessageRole.USER,
        content="Hello assistant, we are having a insightful discussion about Paul Graham today.",
    ),
    ChatMessage(role=MessageRole.ASSISTANT, content="Okay, sounds good."),
]


query_engine = index.as_query_engine()
chat_engine = CondenseQuestionChatEngine.from_defaults(
    query_engine=query_engine,
    condense_question_prompt=custom_prompt,
    chat_history=custom_chat_history,
    verbose=True,
)

CondenseQuestionChatEngine은 뒤에 둔 쿼리 엔진과 함께 condense question 방식을 구성하는 대표적인 예다요.

스트리밍

스트리밍을 켜려면 chat 대신 stream_chat 엔드포인트를 호출하면 돼요.

⚠️ 경고: 이 동작은 쿼리 엔진(streaming=True 플래그를 넘기는 방식)과 다소 일관성이 없어요. 일관되게 만드는 작업을 진행 중이에요!

동기 (stream_chat):

chat_engine = index.as_chat_engine()
streaming_response = chat_engine.stream_chat("Tell me a joke.")


for token in streaming_response.response_gen:
    print(token, end="")

비동기 (astream_chat):

FastAPI 같은 비동기 프레임워크를 쓸 때는 astream_chat을 사용해요. 호출을 await 해야 하고, 제공되는 비동기 스트리밍 인터페이스(예: async_response_gen() 또는 achat_stream)를 순회해야 해요.

chat_engine = index.as_chat_engine()
streaming_response = await chat_engine.astream_chat("Tell me a joke.")


async for token in streaming_response.async_response_gen():
    print(token, end="")

더 알아보기