RAG, MMR, 임베딩 심화

This commit is contained in:
2026-05-29 18:35:36 +09:00
parent b23b5e9b5f
commit d1db36883d
44 changed files with 3579 additions and 70 deletions
+557 -15
View File
@@ -23,34 +23,40 @@
"id": "ceaff2f6",
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-27T08:50:09.993923078Z",
"start_time": "2026-05-27T08:50:09.983490192Z"
"end_time": "2026-05-28T01:43:20.987484992Z",
"start_time": "2026-05-28T01:43:20.978670755Z"
}
},
"source": [
"import selectors\n",
"\n",
"import langchain_core\n",
"#라이브러리 로드\n",
"\n",
"from langchain_ollama import ChatOllama\n",
"from langchain_ibm import ChatWatsonx\n",
"from langchain_core.prompts import PromptTemplate, ChatPromptTemplate\n",
"from langchain_core.prompts import PromptTemplate, ChatPromptTemplate, MessagesPlaceholder\n",
"from langchain_core.output_parsers import StrOutputParser, JsonOutputParser, PydanticOutputParser\n",
"from langchain_core.runnables import RunnablePassthrough, RunnableParallel, RunnableLambda\n",
"from langchain_core.messages import HumanMessage, SystemMessage, AIMessage\n",
"from langchain_core.chat_history import InMemoryChatMessageHistory, BaseChatMessageHistory\n",
"from langchain_core.runnables.history import RunnableWithMessageHistory\n",
"from prompt_toolkit.history import InMemoryHistory\n",
"from pydantic import BaseModel, Field\n",
"from typing import Literal\n",
"from dotenv import load_dotenv\n",
"import os"
],
"outputs": [],
"execution_count": 56
"execution_count": 39
},
{
"cell_type": "code",
"id": "2e83941f",
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-27T08:50:11.888281707Z",
"start_time": "2026-05-27T08:50:11.876005807Z"
"end_time": "2026-05-28T01:01:25.315262434Z",
"start_time": "2026-05-28T01:01:25.303683341Z"
}
},
"source": [
@@ -59,18 +65,19 @@
"\n",
"apikey = os.getenv(\"WATSONX_API_KEY\")\n",
"project_id = os.getenv(\"WATSONX_PROJECT_ID\")\n",
"watsonx_ai_url = os.getenv(\"WATSONX_URL\")\n"
"watsonx_ai_url = os.getenv(\"WATSONX_URL\")\n",
"hf_token = os.getenv(\"HF_TOKEN\")\n"
],
"outputs": [],
"execution_count": 57
"execution_count": 26
},
{
"cell_type": "code",
"id": "7c0a9354",
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-27T08:50:16.189743767Z",
"start_time": "2026-05-27T08:50:13.584144045Z"
"end_time": "2026-05-28T01:01:29.753326236Z",
"start_time": "2026-05-28T01:01:26.671654629Z"
}
},
"source": [
@@ -87,7 +94,7 @@
"gemma_llm = ChatOllama(model=\"gemma4:e2b\")"
],
"outputs": [],
"execution_count": 58
"execution_count": 27
},
{
"cell_type": "code",
@@ -1965,11 +1972,546 @@
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
" - InMemoryChatMessageHistory\n",
" - 메모리에 대화 저장 후 대화 기록 관리\n"
],
"id": "84cc5b7e61f2a23d"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-28T00:54:22.590632509Z",
"start_time": "2026-05-28T00:52:55.700793745Z"
}
},
"cell_type": "code",
"outputs": [],
"execution_count": null,
"source": "",
"id": "fb66178274d6381"
"source": [
"history = InMemoryChatMessageHistory()\n",
"\n",
"\n",
"def chat(user_input):\n",
" history.add_user_message(user_input)\n",
" response = gemma_llm.invoke(history.messages) # 전체 대화 이력 같이 보냄\n",
" history.add_ai_message(response.content)\n",
" return response.content\n",
"\n",
"print(chat(\"파이썬이란?\"))\n",
"print(chat(\"방금 말한 내용의 장점 3가지는?\"))\n",
"print(chat(\"그 중 첫번째 장점에 대한 예시 코드 작성해줘\"))\n",
"print(chat(\"두 번째 장점에 대한 예시 코드 작성해줘\"))\n",
"\n",
"for m in history.messages:\n",
" print(f\"{m.content[:40]}...\")"
],
"id": "fb66178274d6381",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"파이썬(Python)은 오늘날 가장 인기 있고 널리 사용되는 프로그래밍 언어 중 하나입니다.\n",
"\n",
"쉽게 말해, **사람이 읽고 쓰기 쉬운 문법**을 사용하여 컴퓨터에게 원하는 작업을 지시할 수 있게 해주는 **고급(High-level) 프로그래밍 언어**입니다.\n",
"\n",
"파이썬이 왜 그렇게 유명하고 많은 분야에서 사용되는지, 그리고 어떤 특징을 가지고 있는지 자세히 설명해 드리겠습니다.\n",
"\n",
"---\n",
"\n",
"## 1. 파이썬의 핵심 특징\n",
"\n",
"### 1. 쉬운 문법 (Readability)\n",
"파이썬의 가장 큰 장점은 문법이 매우 간결하고 영어와 유사해서 초보자도 비교적 쉽게 배울 수 있다는 점입니다. 복잡한 명령어를 적는 대신, 자연어처럼 코드를 작성할 수 있어 코드의 이해와 유지보수가 매우 쉽습니다.\n",
"\n",
"### 2. 인터프리터 방식 (Interpreted Language)\n",
"파이썬은 코드를 한 줄씩 읽어서 즉시 실행하는 **인터프리터(Interpreter)** 방식으로 작동합니다. 이는 개발자가 코드를 컴파일(Compile)하는 복잡한 과정을 거치지 않고도 빠르게 결과를 확인하고 테스트할 수 있게 해줍니다.\n",
"\n",
"### 3. 방대한 라이브러리 및 생태계 (Vast Ecosystem)\n",
"파이썬의 가장 강력한 힘은 방대하고 활발한 **라이브러리(Library)**와 **프레임워크(Framework)** 생태계에 있습니다. 이미 수많은 개발자들이 만들어 놓은 모듈(라이브러리)을 가져와서 복잡한 기능을 아주 쉽게 구현할 수 있습니다. (예: NumPy, Pandas, Django, TensorFlow 등)\n",
"\n",
"### 4. 다목적성 (Versatility)\n",
"파이썬은 특정 분야에 국한되지 않고, 데이터 분석, 웹 개발, 인공지능, 자동화 등 거의 모든 종류의 프로그래밍 작업에 사용될 수 있습니다.\n",
"\n",
"---\n",
"\n",
"## 2. 파이썬은 어디에 사용되나요? (주요 활용 분야)\n",
"\n",
"파이썬의 높은 범용성 덕분에 현재 가장 활발하게 사용되는 분야는 다음과 같습니다.\n",
"\n",
"### 1. 데이터 과학 및 분석 (Data Science & Analytics)\n",
"* **활용:** 대량의 데이터를 처리, 분석하고 패턴을 찾는 데 압도적으로 많이 사용됩니다.\n",
"* **주요 라이브러리:** **Pandas** (데이터 조작), **NumPy** (수치 계산), **Matplotlib** (시각화).\n",
"\n",
"### 2. 인공지능 (AI) 및 머신러닝 (Machine Learning)\n",
"* **활용:** 인공지능 모델을 개발하고 훈련하는 데 핵심적인 언어입니다.\n",
"* **주요 라이브러리:** **TensorFlow**, **PyTorch**, **Scikit-learn**.\n",
"\n",
"### 3. 웹 개발 (Web Development)\n",
"* **활용:** 웹사이트의 백엔드(서버 로직) 개발에 사용됩니다.\n",
"* **주요 프레임워크:** **Django**, **Flask**.\n",
"\n",
"### 4. 자동화 및 스크립팅 (Automation & Scripting)\n",
"* **활용:** 반복적이거나 지루한 시스템 관리 작업을 자동화하는 데 매우 효율적입니다.\n",
"* **예시:** 파일 정리, 이메일 자동 발송, 웹 크롤링(정보 수집).\n",
"\n",
"### 5. 소프트웨어 테스트 및 QA\n",
"* **활용:** 소프트웨어의 오류를 찾고 테스트하는 자동화 스크립트를 작성하는 데 사용됩니다.\n",
"\n",
"---\n",
"\n",
"## 💡 요약 정리\n",
"\n",
"| 구분 | 내용 | 비고 |\n",
"| :--- | :--- | :--- |\n",
"| **정의** | 사람이 읽기 쉬운 문법을 사용하는 고급 프로그래밍 언어 | |\n",
"| **특징** | 문법이 간결하고, 라이브러리가 풍부하며, 다목적성이 높음 | |\n",
"| **주요 강점** | 배우기 쉽고, 코드를 빠르게 작성할 수 있음 | |\n",
"| **주요 분야** | 데이터 과학, AI/머신러닝, 웹 개발, 시스템 자동화 | |\n",
"\n",
"**결론적으로,** 만약 프로그래밍을 처음 시작하거나, 데이터 분석, AI 등 미래 기술 분야에 관심이 있다면 **파이썬은 가장 먼저 배워야 할 강력한 언어**라고 할 수 있습니다.\n",
"방금 설명드린 내용을 바탕으로 파이썬의 가장 핵심적이고 강력한 장점 3가지를 정리해 드리겠습니다.\n",
"\n",
"---\n",
"\n",
"### 🥇 장점 1: 배우기 매우 쉽고 직관적이다 (쉬운 문법)\n",
"\n",
"파이썬의 가장 큰 장점은 **코드를 읽고 쓰는 것이 매우 쉽다**는 점입니다.\n",
"\n",
"* **설명:** 다른 언어들에 비해 문법이 간결하고 영어와 유사하여, 프로그래밍을 처음 시작하는 사람도 비교적 적은 시간 투자로 코드를 이해하고 작성할 수 있습니다.\n",
"* **효과:** 코딩에 대한 진입 장벽이 낮아 초보자가 빠르게 성취감을 느끼고 실제 문제 해결에 집중할 수 있습니다.\n",
"\n",
"### 🥈 장점 2: 방대하고 강력한 생태계 (풍부한 라이브러리)\n",
"\n",
"파이썬은 혼자 모든 것을 다 할 필요가 없습니다. 이미 수많은 사람들이 만들어 놓은 강력한 도구들(라이브러리, 프레임워크)이 존재합니다.\n",
"\n",
"* **설명:** 데이터 분석, 인공지능, 웹 개발 등 특정 분야에서 필요로 하는 수많은 기능을 이미 잘 만들어진 모듈(라이브러리) 형태로 제공합니다.\n",
"* **효과:** 개발자가 기본적인 기능 구현에 시간을 낭비하지 않고, **이미 검증된 강력한 도구들을 가져와서** 복잡하고 전문적인 작업(예: AI 모델 훈련, 대규모 데이터 분석)을 훨씬 빠르고 효율적으로 구현할 수 있게 해줍니다.\n",
"\n",
"### 🥉 장점 3: 뛰어난 범용성 (다목적성)\n",
"\n",
"파이썬은 특정 분야에 갇혀 있지 않고, 거의 모든 종류의 프로그래밍 작업에 활용될 수 있습니다.\n",
"\n",
"* **설명:** 웹사이트를 만들거나, 데이터를 분석하거나, 자동화 스크립트를 작성하거나, 인공지능 모델을 만들고, 게임을 만드는 등 원하는 거의 모든 분야에 적용이 가능합니다.\n",
"* **효과:** 하나의 언어만 배우면 여러 분야를 커버할 수 있어, 개발 분야를 바꾸거나 새로운 프로젝트를 시도할 때 유연하게 대처할 수 있는 큰 이점이 있습니다.\n",
"네, 첫 번째 장점인 **\"배우기 쉽고 직관적인 문법\"**을 보여주는 예시 코드를 작성해 드리겠습니다.\n",
"\n",
"이 코드는 파이썬의 가장 기본적인 개념(변수 할당, 출력)만으로도 하나의 작업을 수행하는 예시입니다.\n",
"\n",
"### 📝 예시 코드: 간단한 인사말 출력 및 계산\n",
"\n",
"이 코드는 사용자의 이름을 입력받아 환영 메시지를 출력하고, 나이를 5살 더한 나이를 계산하는 아주 간단한 작업을 수행합니다.\n",
"\n",
"```python\n",
"# 1. 사용자에게 이름 입력받기 (input 함수 사용)\n",
"name = input(\"당신의 이름은 무엇인가요? \")\n",
"\n",
"# 2. 사용자에게 나이 입력받기 (input을 받고 숫자로 변환)\n",
"age_str = input(\"당신의 나이는 몇 살인가요? \")\n",
"age = int(age_str) # 문자열을 숫자로 변환\n",
"\n",
"# 3. 계산 결과 만들기\n",
"new_age = age + 5\n",
"\n",
"# 4. 결과 출력하기 (print 함수 사용)\n",
"print(\"안녕하세요, \" + name + \"님!\")\n",
"print(\"당신은 \" + str(new_age) + \"살이고, 5살을 더하면 \" + str(new_age + 5) + \"살이 됩니다.\")\n",
"```\n",
"\n",
"### ✨ 이 코드가 첫 번째 장점을 보여주는 이유\n",
"\n",
"1. **직관적인 명령:** 코드가 마치 우리가 일상에서 사용하는 영어 문장처럼 읽히기 때문에, 프로그래밍 경험이 없어도 코드의 흐름을 쉽게 파악할 수 있습니다. (예: `print(...)`는 '화면에 이것을 보여줘'라는 뜻으로 매우 직관적입니다.)\n",
"2. **간결한 문법:** 복잡한 기호나 괄호 사용이 최소화되어 있어, 코드가 길어지더라도 논리적인 흐름을 따라가기 쉽습니다.\n",
"3. **쉬운 흐름:** 코드가 위에서 아래로 순서대로 실행되므로, 어떤 명령이 언제 실행되는지 예측하기가 매우 쉽습니다.\n",
"\n",
"**💡 핵심:** 파이썬 코드는 \"무엇을 하라\"고 명령하는 방식이 아니라, **\"이렇게 하라\"**는 자연스러운 문장으로 지시하는 방식에 가깝기 때문에, 초보자가 코딩의 논리 자체에 집중할 수 있도록 돕습니다.\n",
"두 번째 장점인 **\"방대하고 강력한 생태계 (풍부한 라이브러리)\"**를 보여주는 예시 코드를 작성해 드리겠습니다.\n",
"\n",
"이 예시에서는 데이터 분석에서 가장 강력한 라이브러리 중 하나인 **Pandas**를 사용하여, 복잡한 데이터 처리 작업을 단 몇 줄의 코드로 해결하는 모습을 보여줍니다.\n",
"\n",
"### 🛠️ 예시 코드: Pandas를 이용한 간단한 데이터 분석\n",
"\n",
"이 코드는 실제로 데이터를 읽어와서 평균을 계산하고, 단순히 명령 한 줄로 데이터를 처리하는 과정을 보여줍니다.\n",
"\n",
"**(참고: 이 코드를 실행하려면 컴퓨터에 `pandas` 라이브러리가 설치되어 있어야 합니다. `pip install pandas` 명령으로 설치할 수 있습니다.)**\n",
"\n",
"```python\n",
"# 1. 필요한 라이브러리 불러오기 (외부 도구 사용)\n",
"import pandas as pd\n",
"\n",
"# 2. 데이터 준비 (실제로는 파일에서 불러오지만, 예시를 위해 직접 데이터를 만듭니다.)\n",
"data = {\n",
" '제품': ['사과', '바나나', '오렌지', '포도', '수박'],\n",
" '판매량': [150, 200, 120, 350, 180],\n",
" '가격': [1000, 800, 1200, 1500, 2000]\n",
"}\n",
"\n",
"# 3. 데이터프레임(DataFrame) 생성 (Pandas 라이브러리 사용)\n",
"df = pd.DataFrame(data)\n",
"\n",
"print(\"--- 원본 데이터 테이블 ---\")\n",
"print(df)\n",
"print(\"\\n\" + \"=\"*30 + \"\\n\")\n",
"\n",
"\n",
"# 4. 강력한 라이브러리 기능을 사용한 데이터 분석 (복잡한 로직 대신 함수 호출)\n",
"# '판매량' 열의 평균을 계산\n",
"average_sales = df['판매량'].mean()\n",
"\n",
"# '가격' 열의 총합을 계산\n",
"total_price = df['가격'].sum()\n",
"\n",
"\n",
"# 5. 결과 출력\n",
"print(f\"🚀 계산 결과:\")\n",
"print(f\"모든 제품의 평균 판매량: {average_sales:.2f} 개\")\n",
"print(f\"모든 제품의 총 판매 가격: {total_price:,} 원\")\n",
"```\n",
"\n",
"### 💡 이 코드가 두 번째 장점을 보여주는 이유\n",
"\n",
"1. **단순한 명령으로 복잡한 작업 수행:**\n",
" * 만약 Pandas 라이브러리가 없었다면, 우리는 위에서 만든 데이터(`df`)를 반복문(Loop)을 사용하여 하나씩 꺼내서, 판매량을 더하고, 가격을 나누고, 평균을 구하는 **복잡한 수백 줄의 코드**를 작성해야 했을 것입니다.\n",
" * 하지만 Pandas라는 **도구(라이브러리)**를 사용함으로써, 우리는 단지 `df['판매량'].mean()`이라는 **단 한 줄의 명령**만으로 원하는 결과를 얻어냈습니다.\n",
"\n",
"2. **시간 절약 및 효율성:**\n",
" * 라이브러리는 이미 수많은 전문가들이 테스트하고 만든 최적화된 코드를 담고 있습니다. 개발자는 이러한 기본 코드를 다시 만들 필요 없이, **필요한 기능만 가져와서** 자신의 목적에 맞게 조합하기만 하면 됩니다.\n",
"\n",
"**핵심:** 파이썬은 기본적으로 강력한 '도구 상자'이며, 우리는 이 도구 상자에 이미 만들어진 수많은 전문가의 지혜(라이브러리)를 쉽게 빌려와서, 남들이 하기 어려운 전문적인 작업까지 손쉽게 처리할 수 있게 해줍니다.\n",
"파이썬이란?...\n",
"파이썬(Python)은 오늘날 가장 인기 있고 널리 사용되는 프로그래밍 ...\n",
"방금 말한 내용의 장점 3가지는?...\n",
"방금 설명드린 내용을 바탕으로 파이썬의 가장 핵심적이고 강력한 장점 3가...\n",
"그 중 첫번째 장점에 대한 예시 코드 작성해줘...\n",
"네, 첫 번째 장점인 **\"배우기 쉽고 직관적인 문법\"**을 보여주는 예...\n",
"두 번째 장점에 대한 예시 코드 작성해줘...\n",
"두 번째 장점인 **\"방대하고 강력한 생태계 (풍부한 라이브러리)\"**를...\n"
]
}
],
"execution_count": 22
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-28T01:44:33.443082277Z",
"start_time": "2026-05-28T01:44:16.764525701Z"
}
},
"cell_type": "code",
"source": [
"# 여러 사람과 대화하는 부분 저장 => 세선별로 저장\n",
"\n",
"# 세션별 이력 저장\n",
"store = {}\n",
"\n",
"def get_sesstion_history(session_id):\n",
" if session_id not in store:\n",
" store[session_id] = InMemoryChatMessageHistory()\n",
" return store[session_id]\n",
"\n",
"# 프롬프트 생성\n",
"prompt = ChatPromptTemplate.from_messages([\n",
" (\"system\", \"당신은 {role}입니다., 한국어로 답변하세요.\"),\n",
" MessagesPlaceholder(variable_name=\"history\"), # 대화이력 삽입될 위치임\n",
" (\"human\", \"{input}\")\n",
" # (\"human\", \"{input}\\n {history}\\n\")\n",
"])\n",
"\n",
"# LLM 생성\n",
"# 체인 생성\n",
"chain = prompt | gemma_llm | StrOutputParser()\n",
"\n",
"# 1. sesstion_id 이력 조회\n",
"# 2. history 키에 이력 삽입 -> prompt -> llm 실행 -> 대화 나눈 이력을 history 추가\n",
"\n",
"with_history = RunnableWithMessageHistory(chain, get_sesstion_history, input_messages_key=\"input\", history_messages_key=\"history\")\n",
"\n",
"# 세션 생성\n",
"cfg_a = {\"configurable\":{\"session_id\":\"user_alice\"}}\n",
"cfg_b = {\"configurable\":{\"session_id\":\"user_bob\"}}\n",
"\n",
"# Alice 대화\n",
"res1 = with_history.invoke({\"role\":\"파이썬 튜더\", \"input\":\"안녕\"}, config=cfg_a)\n",
"res2 = with_history.invoke({\"role\":\"파이썬 튜더\", \"input\":\"내 이름은 Alice야\"}, config=cfg_a)\n",
"res5 = with_history.invoke({\"role\":\"파이썬 튜더\", \"input\":\"내 이름은 기억해?\"}, config=cfg_a)\n",
"\n",
"# Bob 대화\n",
"res3 = with_history.invoke({\"role\":\"파이썬 튜더\", \"input\":\"안녕\"}, config=cfg_b)\n",
"res4 = with_history.invoke({\"role\":\"파이썬 튜더\", \"input\":\"내 이름은 Bob야\"}, config=cfg_b)\n",
"\n",
"print(\"alice \", res2)\n",
"print(\"bob \", res5)\n",
"\n",
"# # 세션 생성\n",
"# def create_session():\n",
"# sesstion_id = uuid.uuid4().hex\n",
"# return sesstion_id\n",
"#\n",
"# # 세션별 이력 조회\n",
"# def get_sesstion_history(sesstion_id):\n",
"# if sesstion_id not in store:\n",
"# store[sesstion_id] = InMemoryChatMessageHistory()\n",
"# return store[sesstion_id]\n"
],
"id": "a2ade04f6a51a29",
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/cooney/Source/.venv/lib/python3.12/site-packages/IPython/core/interactiveshell.py:3748: LangChainDeprecationWarning: RunnableWithMessageHistory is deprecated. Use LangGraph's built-in persistence instead.\n",
" exec(code_obj, self.user_global_ns, self.user_ns)\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"alice Alice님, 만나서 반갑습니다! 😊\n",
"\n",
"앞으로 파이썬 학습에 있어서 궁금한 점이나 도움이 필요한 부분이 있다면 언제든지 저에게 질문해주세요. 제가 알고 있는 모든 것을 동원해서 최대한 자세하고 친절하게 도와드리겠습니다!\n",
"\n",
"이제 파이썬으로 무엇을 해보고 싶으신가요? 예를 들어, 기본적인 문법부터 시작해 볼까요?\n",
"bob 네, 기억하고 있습니다! 😊\n",
"\n",
"당신이 **Alice**라는 이름을 알려주셨기 때문에, 지금 이 대화에서는 Alice님이시라는 것을 기억하고 있습니다.\n",
"\n",
"저는 대화의 맥락(context)을 기억하여 이전 내용을 바탕으로 더 자연스럽게 소통하려고 노력합니다.\n",
"\n",
"이제 Alice님과 함께 파이썬 공부를 계속할 준비가 되었습니다! 다음 질문이나 학습하고 싶은 주제가 있으신가요?\n"
]
}
],
"execution_count": 41
},
{
"metadata": {},
"cell_type": "markdown",
"source": [
"- 대화가 길어지면 이력 전체를 LLM에 넘기는 경우 ContextWindowExceededError 발생 = 즉 Context Window를 초과\n",
"- memory에 어떤 정보를 얼마나 보존할 지 결정\n",
"- 전략\n",
" - 최근 K 턴만 유지\n",
" - 오래된 대화 요약\n",
" - 요약 + 최근대화\n"
],
"id": "c83d8f23c50214c"
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-28T01:55:05.424326080Z",
"start_time": "2026-05-28T01:54:33.248920182Z"
}
},
"cell_type": "code",
"source": [
"# 세션별 이력 저장\n",
"store = {}\n",
"\n",
"def get_sesstion_history(session_id):\n",
" if session_id not in store:\n",
" store[session_id] = InMemoryChatMessageHistory()\n",
" return store[session_id]\n",
"\n",
" # 최근 몇 개만 유지\n",
" history = store[session_id]\n",
"\n",
" if len(history.messages) > 8:\n",
" history.messages[:] = history.messages[-8:]\n",
"\n",
" return history\n",
"\n",
"with_history = RunnableWithMessageHistory(chain, get_sesstion_history, input_messages_key=\"input\", history_messages_key=\"history\")\n",
"\n",
"for i in range(10):\n",
" with_history.invoke({\"role\":\"파이썬 튜터\", \"input\":f\"{i}번째 질문\"}, config=cfg_a)\n",
"\n",
"history = get_sesstion_history(\"user_alice\")\n",
"\n",
"for msg in history.messages:\n",
" print(msg)\n",
"\n",
"print(len(history.messages))"
],
"id": "4464efadb9ea0fc7",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"content='0번째 질문' additional_kwargs={} response_metadata={}\n",
"content='안녕하세요! 파이썬 튜터입니다. 😊\\n\\n**첫 번째 질문을 해주세요!** 어떤 것에 대해 궁금하신가요? 프로그래밍, 특정 개념, 코드 작성, 문제 해결 등 무엇이든 좋습니다. 편하게 질문해 주세요!' additional_kwargs={} response_metadata={} tool_calls=[] invalid_tool_calls=[]\n",
"content='1번째 질문' additional_kwargs={} response_metadata={}\n",
"content='네, 준비되었습니다! 😊\\n\\n**첫 번째 질문을 말씀해 주세요!** 제가 아는 범위 내에서 최대한 자세하고 명확하게 답변해 드리겠습니다.' additional_kwargs={} response_metadata={} tool_calls=[] invalid_tool_calls=[]\n",
"content='2번째 질문' additional_kwargs={} response_metadata={}\n",
"content='네, 이제 **두 번째 질문**을 해 주시면 됩니다! 😊\\n\\n어떤 주제가 궁금하신가요? 코딩, 라이브러리 사용법, 특정 개념 설명 등 무엇이든 좋습니다.\\n\\n**준비되셨다면, 편하게 질문해 주세요!** 기다리고 있겠습니다. ✨' additional_kwargs={} response_metadata={} tool_calls=[] invalid_tool_calls=[]\n",
"content='3번째 질문' additional_kwargs={} response_metadata={}\n",
"content='세 번째 질문을 기다리고 있겠습니다! 😊\\n\\n이제 **세 번째 질문**을 해주시면 됩니다. 어떤 것에 대해 알고 싶으신가요?\\n\\n궁금한 점을 구체적으로 말씀해 주시면, 제가 파이썬 지식을 활용하여 친절하게 설명해 드릴게요! 편하게 질문해 주세요. ✨' additional_kwargs={} response_metadata={} tool_calls=[] invalid_tool_calls=[]\n",
"content='4번째 질문' additional_kwargs={} response_metadata={}\n",
"content='네, **네 번째 질문**을 기다리고 있겠습니다! 😊\\n\\n지금까지 질문해주신 내용을 종합해 볼 때, 파이썬과 관련된 질문이 많을 것 같습니다.\\n\\n**마음 편하게 네 번째 질문을 해 주세요!** 제가 최선을 다해 답변해 드리겠습니다. 😊' additional_kwargs={} response_metadata={} tool_calls=[] invalid_tool_calls=[]\n",
"content='5번째 질문' additional_kwargs={} response_metadata={}\n",
"content='네, 이제 **다섯 번째 질문**을 기다리고 있겠습니다! 😊\\n\\n어떤 내용이 궁금하신가요?\\n\\n언제든지 편하게 질문해 주세요. 파이썬에 관한 것이든, 다른 것이든 제가 아는 선에서 최선을 다해 답변해 드리겠습니다! ✨' additional_kwargs={} response_metadata={} tool_calls=[] invalid_tool_calls=[]\n",
"content='6번째 질문' additional_kwargs={} response_metadata={}\n",
"content='네, **여섯 번째 질문**을 기다리고 있겠습니다! 😊\\n\\n이제 궁금한 것을 질문해 주시면 됩니다. 😊\\n\\n**질문해 주세요!** 기다리고 있겠습니다. 😄' additional_kwargs={} response_metadata={} tool_calls=[] invalid_tool_calls=[]\n",
"content='7번째 질문' additional_kwargs={} response_metadata={}\n",
"content='네, **일곱 번째 질문**을 기다리고 있겠습니다! 😊\\n\\n궁금한 점이 있으시면 언제든지 질문해 주세요.\\n\\n**편하게 질문해 주세요!** 제가 아는 모든 것을 동원해서 명쾌하게 답변해 드리겠습니다. 😊' additional_kwargs={} response_metadata={} tool_calls=[] invalid_tool_calls=[]\n",
"content='8번째 질문' additional_kwargs={} response_metadata={}\n",
"content='네, 이제 **여덟 번째 질문**을 기다리고 있겠습니다! 😊\\n\\n마지막 질문까지 모두 드려주셔서 감사합니다. 이제 **실제로 궁금한 내용을 질문해 주세요!**\\n\\n어떤 것이든 좋습니다. 파이썬에 관한 것이든, 알고 싶은 프로그래밍 개념이든, 어떤 것이든 좋습니다.\\n\\n**질문해 주세요!** 제가 자세히 설명해 드리겠습니다. 😊' additional_kwargs={} response_metadata={} tool_calls=[] invalid_tool_calls=[]\n",
"content='9번째 질문' additional_kwargs={} response_metadata={}\n",
"content='네, **아홉 번째 질문**을 기다리고 있겠습니다! 😊\\n\\n이제 모든 질문 요청을 마쳤으니, **정말로 알고 싶은 질문**을 던져주시면 됩니다!\\n\\n파이썬에 대해 궁금한 점, 특정 코드에 대한 설명, 개념 이해 등 무엇이든 좋습니다.\\n\\n**주저하지 마시고 지금 바로 질문해 주세요!** 제가 최고의 답변을 드리기 위해 준비하고 있겠습니다. ✨' additional_kwargs={} response_metadata={} tool_calls=[] invalid_tool_calls=[]\n",
"20\n"
]
}
],
"execution_count": 44
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-28T03:05:41.353949975Z",
"start_time": "2026-05-28T03:02:10.585619509Z"
}
},
"cell_type": "code",
"source": [
"# 오래된 대화 요약\n",
"\n",
"# history 요약\n",
"summary_prompt = ChatPromptTemplate.from_messages([\n",
" (\"system\", \"다음 대화 내용을 핵심만 3문장 이내로 한국어로 요약하세요.\"),\n",
" (\"human\", \"{converstaion}\"),\n",
"])\n",
"\n",
"summary_chain = summary_prompt | gemma_llm | StrOutputParser()\n",
"\n",
"# 요약 기능이 포함된 클래스\n",
"class SummarizedChatHistory(InMemoryChatMessageHistory):\n",
" \"\"\"대화가 max_turns 초과 시 오래된 메시지 요약하기\"\"\"\n",
" max_turns:int = Field(default=6)\n",
" summary:str = Field(default=\"\")\n",
"\n",
"def _maybe_summarize(self):\n",
" if len(self.add_message) > self.max_turns * 2:\n",
" # 오래된 내용 찾기\n",
" cutoff = len(self.messages)\n",
" old_megs = self.message[:cutoff]\n",
" new_msgs = self.message[cutoff:]\n",
"\n",
" # 요약할 텍스트 구성\n",
" conv_text = \"\\n\".join(f\"{'사용자' if isinstance(m, HumanMessage) else 'AI'}:{m.content}\" for m in old_megs)\n",
"\n",
" # 기존 요약이 있으면 함께 포함\n",
" if self.summary:\n",
" conv_text = f\"[이전 요약]\\n{self.summary}\\n\\n[새 대화]\\n{conv_text}\"\n",
"\n",
" # 요약 실행\n",
" self.summary = summary_chain.invoke({'converstation':conv_text})\n",
"\n",
" # 오래된 메시지 제거 후 요약본 SystemMessage 로 앞에 삽입\n",
" self.messages.clear()\n",
" self.messages.append(SystemMessage(content=f\"[이전 대화 요약]\\n{self.summary}\"))\n",
" self.messages.extend(new_msgs)\n",
"\n",
"def add_message(self, message):\n",
" super().add_message(message)\n",
" self._maybe_summarize()\n",
"\n",
"store = {}\n",
"\n",
"def get_sesstion_history(session_id) -> SummarizedChatHistory:\n",
" if session_id not in store:\n",
" store[session_id] = SummarizedChatHistory(max_turns=6)\n",
"\n",
" return store[session_id]\n",
"\n",
"# 프롬프트 생성\n",
"prompt = ChatPromptTemplate.from_messages([\n",
" (\"system\", \"친절한 ai 어시스턴트입니다., 한국어로 답변하세요.\"),\n",
" MessagesPlaceholder(variable_name=\"history\"), # 대화이력 삽입될 위치임\n",
" (\"human\", \"{input}\")\n",
" # (\"human\", \"{input}\\n {history}\\n\")\n",
"])\n",
"\n",
"# LLM 생성\n",
"# 체인 생성\n",
"chain = prompt | gemma_llm | StrOutputParser()\n",
"\n",
"with_history = RunnableWithMessageHistory(chain, get_sesstion_history, input_messages_key=\"input\", history_messages_key=\"history\")\n",
"\n",
"# 세션 생성\n",
"cfg_a = {\"configurable\":{\"session_id\":\"user_alice\"}}\n",
"\n",
"# 임의 대화 생성\n",
"question = [\n",
" \"파이썬이란?\",\n",
" \"방금 설명한 파이썬의 장점은?\",\n",
" \"단점은?\",\n",
" \"어떤 분야에 많이 쓰여?\",\n",
" \"입문자에게 추천하는 학습 순서는?\",\n",
" \"좋은 파이썬 책 추천해줘?\",\n",
" \"무료로 배울 수 있는 사이트는?\",\n",
" \"이전에 내가 뭘 물어봤는지 기억해?\",\\\n",
"]\n",
"\n",
"for i, q in enumerate(question, 1):\n",
" resonse = with_history.invoke({\"input\":q}, config=cfg_a)\n",
" print(f\"\\n{i}턴 Q: {q}\")\n",
" print(f\"\\n A: {resonse[:60]}....\")\n",
"\n",
" # 요약 여부 확인\n",
" history = get_sesstion_history(\"user_alice\")\n",
" if history.summary:\n",
" print(f\"\\n 요약 처리! 현재 메시지 수 {len(history.messages)}\")\n",
" print(f\"\\n 요약 내용 {history.summary[:200]}....\")"
],
"id": "eefbcb9dd8c9af32",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"1턴 Q: 파이썬이란?\n",
"\n",
" A: 파이썬(Python)은 오늘날 가장 인기 있고 널리 사용되는 **프로그래밍 언어** 중 하나입니다.\n",
"\n",
"쉽게 ....\n",
"\n",
"2턴 Q: 방금 설명한 파이썬의 장점은?\n",
"\n",
" A: 방금 설명드린 내용을 바탕으로 파이썬이 가진 **핵심적인 장점**들을 정리해 드리겠습니다. 이 장점들 때문에....\n",
"\n",
"3턴 Q: 단점은?\n",
"\n",
" A: 파이썬은 그 장점들이 매우 강력한 만큼, 모든 프로그래밍 언어와 마찬가지로 **단점**도 존재합니다. 단점은....\n",
"\n",
"4턴 Q: 어떤 분야에 많이 쓰여?\n",
"\n",
" A: 파이썬은 그 **뛰어난 범용성** 덕분에 현재 IT 업계에서 **가장 활발하게 사용되는 분야** 중 하나입니....\n",
"\n",
"5턴 Q: 입문자에게 추천하는 학습 순서는?\n",
"\n",
" A: 파이썬을 처음 배우시는 분이라면, **기초 문법을 탄탄하게 다진 후, 관심 있는 분야로 확장해 나가는 순서*....\n",
"\n",
"6턴 Q: 좋은 파이썬 책 추천해줘?\n",
"\n",
" A: 파이썬 학습을 시작하는 분들을 위한 책은 정말 많습니다. 어떤 책이 '가장 좋다'고 단정하기보다는, **학습....\n",
"\n",
"7턴 Q: 무료로 배울 수 있는 사이트는?\n",
"\n",
" A: 파이썬을 무료로 배울 수 있는 훌륭한 온라인 플랫폼과 자료들이 정말 많습니다! 어떤 학습 스타일(인터랙티브 ....\n",
"\n",
"8턴 Q: 이전에 내가 뭘 물어봤는지 기억해?\n",
"\n",
" A: 네, 저는 **이전 대화의 맥락(Context)**을 기억하고 있습니다.\n",
"\n",
"지금까지의 대화 내용을 바탕으로,....\n"
]
}
],
"execution_count": 52
}
],
"metadata": {