Search

Conversational Chain

대분류
인공지능/데이터
프레임워크
소분류
LangChain/RAG
유형
LangChain
RAG
부유형
Regacy Chains Migrating Package
최종 편집 일시
2024/11/03 05:41
생성 일시
2024/11/02 11:31
14 more properties

채팅 기록(Conversational) 체인

Conversation Chain은 이전 메시지의 메모리를 통합하여 지속적인 대화를 유지한다.
LLM의 Memory 동작 방식을 잘 모르겠다면 이전 포스트 Memorization를 참고하고 다시 오자!
이점
스레드/별도 세션에 대한 기본 지원: Conversation Chain에서 이 기능을 사용하려면 체인 외부에 별도의 메모리 클래스를 인스턴스화해야 한다.
보다 명시적인 매개변수: Conversation Chain에는 숨겨진 기본 프롬프트가 포함되어 있어 혼동을 일으킬 수 있다.
스트리밍 지원: Conversation Chain은 콜백을 통한 스트리밍만 지원한다.

동작 과정

1. Query Input

사용자가 Query를 입력하면, Input 단계로 넘어가며 Memory를 통해 이전 대화 기록을 참조한다.

2. 입력 변환

그 다음, PromptTemplate은 입력을 LLM이 이해하기 쉬운 프롬프트 형식으로 변환하여, Chat LLM에 전달한다.

3. Output

Chat LLM이 생성한 출력은 Memory에도 저장되고 OutputParser를 통해 사용자가 원하는 형식으로 가공된다.

4. 응답(Response)

최종적으로 이 응답이 Response로 반환된다.

실습

기본 세팅

설치

해당 과정은 cpu를 사용해서 진행하여서 faiss-cpu 모듈을 사용하였다.
!pip install -U langchain langchain-community langchain-core langchain-openai langgraph faiss-cpu
Python
복사

Key 등록

아래 방법이나 .env에 정의하자.
import os os.environ['OPENAI_API_KEY'] = '여기에 사용하는 키 입력'
Python
복사

LLM 모델 정의 & 모듈 불러오기

import uuid from langchain_openai import ChatOpenAI from langgraph.checkpoint.memory import MemorySaver from langgraph.graph import START, MessagesState, StateGraph from langchain_core.messages import HumanMessage, SystemMessage model = ChatOpenAI(model="gpt-4o-mini")
Python
복사

Node

# 모델을 호출하는 함수를 정의 def call_model(state: MessagesState): response = model.invoke(state["messages"]) return {"messages": response}
Python
복사
# 새 그래프 정의 workflow = StateGraph(state_schema=MessagesState) # 순환할 두 노드를 정의 workflow.add_edge(START, "model") workflow.add_node("model", call_model)
Python
복사
인메모리 체크포인트 세이버.
# 메모리 추가 memory = MemorySaver() app = workflow.compile(checkpointer=memory)
Python
복사

Display에 띄워보자.

jupyter 노트북 환경에서 그래프를 보기위해 IPython을 사용했다.
from IPython.display import Image Image(app.get_graph().draw_mermaid_png())
Python
복사

UUID

UUID 생성
UUID가 뭔지 모르겠다면? : UUID
# 스레드 아이디: 이 특정 대화를 식별하는 고유 키 # 여기서는 임의의 uuid를 생성한다. thread_id = uuid.uuid4() > thread_id UUID('614388be-0682-40f6-97fb-ba8b933c2b73')
Python
복사
config
config = {"configurable": {"thread_id": thread_id}}
Python
복사

App - Stream_mode

출력을 스트리밍할 모드로, 기본값은 self.stream_mode이다.
옵션으론 'values', 'updates', 'debug’가 있다.

values

각 단계에 대한 상태의 현재 값을 출력
stream_mode="values" query = "제 이름은 홍길동입니다." input_messages = [ SystemMessage("당신은 선생님입니다."), HumanMessage(query) ] response = app.stream({"messages": input_messages}, config, stream_mode=stream_mode) for event in response: event["messages"][-1].pretty_print()
Python
복사
================================ Human Message ================================= 제 이름은 홍길동입니다. ================================== Ai Message ================================== 안녕하세요, 홍길동님! 만나서 반갑습니다. 어떻게 도와드릴까요?
Python
복사
기억하는지 확인
input_messages = [HumanMessage("제 이름은 뭔가요?")] response = app.stream({"messages": input_messages}, config, stream_mode=stream_mode) for event in response: event["messages"][-1].pretty_print()
Python
복사
================================ Human Message ================================= 제 이름은 뭔가요? ================================== Ai Message ================================== 홍길동님이라고 말씀하셨습니다. 맞나요? 추가로 궁금한 점이 있으시면 말씀해 주세요!
Python
복사

updates

각 단계에 대한 상태의 업데이트만 내보낸다.
출력은 노드 이름을 키로 하고 업데이트된 값을 값으로 하는 딕셔너리이다.
stream_mode="updates" input_messages = [HumanMessage("외국인에게 추천할 한국음식 하나만 추천해줘?")] response = app.stream({"messages": input_messages}, config, stream_mode=stream_mode) event = next(iter(response)) > event {'model': {'messages': AIMessage(content='외국인에게 추천할 한국 음식으로 **비빔밥**을 추천합니다. 비빔밥은 다양한 재료가 조화를 이루는 맛있는 요리로, 고추장과 함께 비벼 먹으면 풍부한 맛을 즐길 수 있습니다. 또한, 채소와 고기를 함께 즐길 수 있어 영양가도 높습니다. 비빔밥은 색감도 아름다워 시각적으로도 매력적이어서 외국인에게 좋은 인상을 줄 수 있을 것입니다!', ... 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})}} > event['model']['messages'].pretty_print() ================================== Ai Message ================================== 외국인에게 추천할 한국 음식으로 **비빔밥**을 추천합니다. ...
Python
복사

debug

각 단계에 대한 디버그 이벤트를 내보낸다.
stream_mode="debug" input_messages = [HumanMessage("대한민국의 수도는 어디인가요?")] response = app.stream({"messages": input_messages}, config, stream_mode=stream_mode)
Python
복사
이벤트(Event) 확인
event = next(iter(response)) event.keys() > event['step'] 6 > event['type'] checkpoint > event['timestamp'] 2024-11-02T03:20:13.354645+00:00 > event['payload'] {'config': {'tags': [], 'metadata': ChainMap({}), 'callbacks': ... 'step': 6, 'parents': {}}, 'next': ['__start__'], 'tasks': [{'id': 'e237a6de-a78a-90aa-bd25-e06cdf7d919c', 'name': '__start__', 'interrupts': (), 'state': None}]}
Python
복사
아니 페이로드도 모른다고요? 내가 못살아 아주 그냥 : 페이로드(Payload)