Skip to content

บทที่ 6: Memory — การจัดการหน่วยความจำ

LLMs ไม่มีหน่วยความจำ ทุกครั้งที่เรียกใช้ จะเริ่มต้นใหม่ทุกครั้ง Memory ช่วยให้ AI “จำ” บทสนทนาก่อนหน้าได้

❌ ไม่มี Memory:
User: ผมชื่อสมชาย
AI: สวัสดีครับคุณสมชาย!
User: ผมชื่ออะไร?
AI: ขอโทษครับ ผมไม่ทราบชื่อของคุณ ← ลืมแล้ว!
✅ มี Memory:
User: ผมชื่อสมชาย
AI: สวัสดีครับคุณสมชาย!
User: ผมชื่ออะไร?
AI: คุณชื่อสมชายครับ! ← จำได้!

วิธีจัดการ Memory ใน LangChain v1.0+

Section titled “วิธีจัดการ Memory ใน LangChain v1.0+”

ใน LangChain เวอร์ชันใหม่ การจัดการ memory ทำผ่าน message history โดยเราเก็บ messages ไว้เองและส่งเข้าไปใน prompt

วิธีพื้นฐาน — จัดการ Messages เอง

Section titled “วิธีพื้นฐาน — จัดการ Messages เอง”

คำอธิบาย: โค้ดตัวอย่างด้านล่างแสดงวิธีใช้งานด้วย Python ตามหัวข้อนี้แบบทีละขั้นตอน

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage
llm = ChatOpenAI(model="gpt-4o-mini")
# Prompt ที่มี placeholder สำหรับ chat history
prompt = ChatPromptTemplate.from_messages([
("system", "คุณเป็นผู้ช่วยที่เป็นมิตร ตอบเป็นภาษาไทย"),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{input}"),
])
chain = prompt | llm
# เก็บ chat history เอง
chat_history = []
def chat(user_message: str) -> str:
# เรียก LLM พร้อม history
response = chain.invoke({
"chat_history": chat_history,
"input": user_message,
})
# เก็บ messages ลง history
chat_history.append(HumanMessage(content=user_message))
chat_history.append(AIMessage(content=response.content))
return response.content
# ทดสอบ
print(chat("สวัสดี! ผมชื่อวิชัย"))
# สวัสดีครับคุณวิชัย! ยินดีที่ได้รู้จักครับ
print(chat("ผมชื่ออะไร?"))
# คุณชื่อวิชัยครับ! 😊

LangChain มี helper สำหรับจัดการ history อัตโนมัติ:

from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.chat_history import BaseChatMessageHistory
# เก็บ history แยกตาม session
store = {}
def get_session_history(session_id: str) -> BaseChatMessageHistory:
if session_id not in store:
store[session_id] = ChatMessageHistory()
return store[session_id]
# สร้าง chain พร้อม memory
prompt = ChatPromptTemplate.from_messages([
("system", "คุณเป็นผู้ช่วยที่เป็นมิตร"),
MessagesPlaceholder(variable_name="history"),
("human", "{input}"),
])
chain = prompt | llm
# Wrap ด้วย RunnableWithMessageHistory
chain_with_history = RunnableWithMessageHistory(
chain,
get_session_history,
input_messages_key="input",
history_messages_key="history",
)
# ใช้งาน — ระบุ session_id
config = {"configurable": {"session_id": "user-123"}}
response = chain_with_history.invoke(
{"input": "สวัสดี! ชื่อมานีค่ะ"},
config=config,
)
print(response.content)
response = chain_with_history.invoke(
{"input": "ฉันชื่ออะไรคะ?"},
config=config,
)
print(response.content) # จำได้ว่าชื่อมานี!

เทคนิค Memory ขั้นสูง

Section titled “เทคนิค Memory ขั้นสูง”

1. จำกัดจำนวน Messages (Sliding Window)

Section titled “1. จำกัดจำนวน Messages (Sliding Window)”

คำอธิบาย: โค้ดตัวอย่างด้านล่างแสดงวิธีใช้งานด้วย Python ตามหัวข้อนี้แบบทีละขั้นตอน

from langchain_core.messages import trim_messages
from langchain_core.runnables import RunnablePassthrough
# เก็บแค่ 10 messages ล่าสุด
trimmer = trim_messages(
max_tokens=1000,
strategy="last", # เก็บ messages ล่าสุด
token_counter=llm, # ใช้ LLM นับ tokens
include_system=True, # เก็บ system message เสมอ
allow_partial=False,
)
prompt = ChatPromptTemplate.from_messages([
("system", "คุณเป็นผู้ช่วยที่เป็นมิตร"),
MessagesPlaceholder(variable_name="history"),
("human", "{input}"),
])
# ใส่ trimmer ใน chain
chain = (
RunnablePassthrough.assign(history=lambda x: trimmer.invoke(x["history"]))
| prompt
| llm
)

2. สรุปบทสนทนา (Summary Memory)

Section titled “2. สรุปบทสนทนา (Summary Memory)”

คำอธิบาย: โค้ดตัวอย่างด้านล่างแสดงวิธีใช้งานด้วย Python ตามหัวข้อนี้แบบทีละขั้นตอน

from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
llm = ChatOpenAI(model="gpt-4o-mini")
# Chain สำหรับสรุปบทสนทนา
summary_prompt = ChatPromptTemplate.from_template("""
สรุปบทสนทนาต่อไปนี้ให้กระชับ เก็บข้อมูลสำคัญไว้:
สรุปก่อนหน้า: {existing_summary}
บทสนทนาใหม่:
{new_messages}
สรุปใหม่:
""")
summary_chain = summary_prompt | llm | StrOutputParser()
class SummaryMemory:
def __init__(self):
self.summary = ""
self.recent_messages = []
self.max_recent = 6 # เก็บ 6 messages ล่าสุด
def add_message(self, role: str, content: str):
self.recent_messages.append(f"{role}: {content}")
# ถ้ามากเกินไป ให้สรุป
if len(self.recent_messages) > self.max_recent:
self._summarize()
def _summarize(self):
# สรุป messages เก่า
messages_text = "\n".join(self.recent_messages[:-2])
self.summary = summary_chain.invoke({
"existing_summary": self.summary,
"new_messages": messages_text,
})
# เก็บแค่ 2 messages ล่าสุด
self.recent_messages = self.recent_messages[-2:]
def get_context(self) -> str:
context = ""
if self.summary:
context += f"สรุปบทสนทนาก่อนหน้า: {self.summary}\n\n"
if self.recent_messages:
context += "บทสนทนาล่าสุด:\n" + "\n".join(self.recent_messages)
return context

3. Persistent Memory (บันทึกลง Database)

Section titled “3. Persistent Memory (บันทึกลง Database)”

คำอธิบาย: โค้ดตัวอย่างด้านล่างแสดงวิธีใช้งานด้วย Python ตามหัวข้อนี้แบบทีละขั้นตอน

# ใช้ Redis เป็น backend
from langchain_community.chat_message_histories import RedisChatMessageHistory
def get_session_history(session_id: str):
return RedisChatMessageHistory(
session_id=session_id,
url="redis://localhost:6379",
ttl=3600, # เก็บ 1 ชั่วโมง
)
# ใช้ SQLite เป็น backend
from langchain_community.chat_message_histories import SQLChatMessageHistory
def get_session_history(session_id: str):
return SQLChatMessageHistory(
session_id=session_id,
connection="sqlite:///chat_history.db",
)

ตัวอย่าง: สร้าง Chatbot สมบูรณ์

Section titled “ตัวอย่าง: สร้าง Chatbot สมบูรณ์”

คำอธิบาย: โค้ดตัวอย่างด้านล่างแสดงวิธีใช้งานด้วย Python ตามหัวข้อนี้แบบทีละขั้นตอน

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import ChatMessageHistory
# Setup
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.7)
store = {}
def get_history(session_id: str):
if session_id not in store:
store[session_id] = ChatMessageHistory()
return store[session_id]
# Prompt
prompt = ChatPromptTemplate.from_messages([
("system", """คุณเป็น TechBot — ผู้ช่วยด้านเทคโนโลยี
- ตอบเป็นภาษาไทย
- ให้ตัวอย่างโค้ดเมื่อเหมาะสม
- ถามกลับถ้าต้องการข้อมูลเพิ่ม"""),
MessagesPlaceholder(variable_name="history"),
("human", "{input}"),
])
# Chain
chain = prompt | llm | StrOutputParser()
chatbot = RunnableWithMessageHistory(
chain, get_history,
input_messages_key="input",
history_messages_key="history",
)
# Interactive Chat Loop
def main():
session_id = "demo-session"
config = {"configurable": {"session_id": session_id}}
print("🤖 TechBot พร้อมให้บริการ! (พิมพ์ 'quit' เพื่อออก)\n")
while True:
user_input = input("คุณ: ")
if user_input.lower() == "quit":
print("👋 ลาก่อนครับ!")
break
response = chatbot.invoke(
{"input": user_input},
config=config,
)
print(f"🤖 TechBot: {response}\n")
if __name__ == "__main__":
main()

เปรียบเทียบ Memory Strategies

Section titled “เปรียบเทียบ Memory Strategies”
Strategyข้อดีข้อเสียเหมาะกับ
Full Historyจำได้ทั้งหมดใช้ tokens มากบทสนทนาสั้น
Sliding Windowควบคุม tokensลืมเรื่องเก่าบทสนทนาทั่วไป
Summaryประหยัด tokensเสีย detailบทสนทนายาว
Persistentไม่หายเมื่อ restartต้องตั้ง databaseProduction