챗봇이 기억하는 방법
•
챗봇은 기억력이 0이다.
→ 즉, 챗봇이 기억하는 것이 아니다.
•
그럼 도대체 뭐가 기억하는 것이냐?
◦
프롬프트 자체 내에 MessagePlaceholder객체에서 저장하고 기억한다.
◦
시스템에 저장된다고 보면 된다.
챗봇에 메모리를 넣는 방법
1. 질문(Question)
•
사용자가 어떤 질문을 입력하면 이 질문을 바탕으로 대답을 생성하기 위한 과정을 거친다.
•
질문이 주어지면 이 질문을 이해하고 관련된 정보를 대형 언어 모델(LLM)로 전달하기 위한 추가적인 작업들이 수행된다.
2. 정보 검색 (Retrieval, 선택적 옵션)
•
질문에 대한 답변을 하기 위해 추가적인 외부 정보가 필요한 경우, 정보 검색을 수행한다.
•
Storage:
◦
질문과 관련된 정보를 검색하기 위해 저장소(Storage)에 저장된 데이터를 참조한다.
◦
이 저장소는 다양한 유형의 데이터, 예를 들어 문서, 텍스트 조각 등을 포함할 수 있다.
•
Retrieved Chunks:
◦
저장소에서 관련이 있다고 판단되는 데이터 조각(chunks)을 검색해낸다.
◦
이 검색된 데이터 조각(청크)들은 질문에 대한 답변을 더 풍부하게 만드는 데 사용된다.
◦
이 과정은 선택적이기 때문에 모든 질문에 대해 반드시 수행되지는 않으며, 외부 정보를 참조할 필요가 있을 때만 수행된다.
3. 메모리 (Memory)
•
대형 언어 모델이 과거의 대화나 정보를 기억하는 부분을 나타낸다.
•
이는 이전의 대화 내용, 관련된 문맥 정보를 저장하고 있다가, 이후의 대화나 응답에 사용할 수 있도록 하는 기능이다.
•
예를 들어, 사용자가 이전에 제공한 정보를 기억하여 현재의 질문에 더 정확한 답변을 제공할 수 있다.
4. 프롬프트 구성 (Prompt)
•
검색된 정보와 메모리에서 불러온 정보(1,2,3번 과정)가 함께 프롬프트(prompt)로 구성된다.
•
이 프롬프트는 대형 언어 모델(LLM)에 전달되어 답변을 생성하는 데 사용된다.
•
이 프롬프트에는 질문 자체와, 그에 대해 필요한 문맥적 정보들이 포함된다.
5. 대형 언어 모델 (LLM)
•
LLM (Large Language Model)은 입력된 프롬프트를 기반으로 질문에 대한 답변(Answer)을 생성한다.
•
LLM은 주어진 정보와 학습된 데이터들을 바탕으로 가장 적합한 답변을 도출해낸다.
6. 답변 생성 및 기억 (Answer)
•
LLM에서 생성된 답변은 사용자에게 전달된다.
•
이 답변은 질문과 관련된 문맥 정보, 검색된 외부 정보, 그리고 기억된 정보를 모두 반영한 것이다.
•
사용자는 이 답변을 통해 질문에 대한 정보를 얻을 수 있다.
•
그리고 해당 답변은 메모리에 저장된다. - 기억 과정
•
가장 간단한 형태의 메모리
•
단순히 채팅 기록 메시지를 체인으로 전달하는 것
ChatPromptTemplate
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages(
[
SystemMessage(
content="You are a helpful assistant. Answer all questions to the best of your ability."
),
MessagesPlaceholder(variable_name="messages"),
]
)
> prompt.input_variables
['messages']
Python
복사
Chain
chain = prompt | model
ai_msg = chain.invoke(
{
"messages": [
HumanMessage(
content="Translate from Korean to English: 나는 프로그래밍을 사랑한다."
),
AIMessage(content="I love programming."),
HumanMessage(content="What did you just say?"),
],
}
)
> ai_msg.pretty_print()
I said, "I love programming."
Python
복사
•
이전 대화를 체인으로 전달하면 질문에 답하기 위한 맥락으로 사용할 수 있다는 것을 알 수 있다.
•
챗봇 메모리의 기본 개념
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import START, MessagesState, StateGraph
Python
복사
Node
•
MessageState
상태에 메시지 목록을 보유하는 것은 매우 일반적이다.
그래서 메시지를 쉽게 사용할 수 있도록 미리 빌드된 상태로 정의해논게 Message State다.
from langchain_core.messages import SystemMessage
# Define the function that calls the model
def call_model(state: MessagesState):
system_prompt = (
"You are a helpful assistant. "
"Answer all questions to the best of your ability."
)
messages = [SystemMessage(content=system_prompt)] + state["messages"]
response = model.invoke(messages)
return {"messages": response}
Python
복사
•
노드가 공유 상태를 읽고 쓰는 방식으로 통신하는 그래프
◦
state_schema ([], 기본값: None ) - 상태를 정의하는 스키마 클래스
◦
config_schema ([[]], 기본값: None ) - 구성을 정의하는 스키마 클래스, 이를 사용하여 API에서 구성 가능한 매개 변수를 노출한다.
workflow = StateGraph(state_schema=MessagesState)
# Define the node and edge
workflow.add_node("model", call_model)
workflow.add_edge(START, "model")
Python
복사
•
여기에서 설정하는 thread_id를 마치 채팅방 id라고 생각하면 된다.
# Add simple in-memory checkpointer
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)
Python
복사
Display
from IPython.display import Image
Image(app.get_graph().draw_mermaid_png())
Python
복사
app.invoke
from langchain_core.messages import HumanMessage
ai_msg = app.invoke(
{"messages": [HumanMessage(content="Translate to Korean: I love programming.")]},
config={"configurable": {"thread_id": "1"}},
)
> ai_msg.keys()
dict_keys(['messages'])
Python
복사
•
메시지를 출력할 때는 항상 인덱스를 -1로 설정해야 메모리에 저장되어 있는 콘텐츠가 아닌 최신 콘텐츠를 회신하게 된다.
> ai_msg['messages'][-1].content
프로그래밍을 사랑합니다.
Python
복사
ai_msg = app.invoke(
{"messages": [HumanMessage(content="What did I just ask you?")]},
config={"configurable": {"thread_id": "1"}},
)
> ai_msg['messages'][-1].content
You asked me to translate the phrase "I love programming" into Korean.
Python
복사