Files
Source/ollama/langchain3.ipynb
T
2026-05-29 18:35:36 +09:00

670 lines
23 KiB
Plaintext

{
"cells": [
{
"metadata": {},
"cell_type": "markdown",
"source": [
"#### RAG 심화\n",
"- 중복 문서 문제 : 비슷한 내용의 청크가 여러개 반환되어 컨텍스트 낭비 발생\n",
"- 검색 : 시맨틱 유사도만으로는 정확한 키워드 매칭이 어려움\n",
"- 구조적 질의 불가 : '2024년 이후 계약 금액이 1억이상인 제품 찾기' 같은 메타 필터 처리 불가\n",
"- 노이즈 청크 : 관련성이 낮은 청크가 LLM 에게 전달되어 환각 유발"
],
"id": "e7f0623c946dacf1"
},
{
"cell_type": "code",
"id": "7ed47758",
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-29T09:32:33.118160997Z",
"start_time": "2026-05-29T09:32:30.827718072Z"
}
},
"source": [
"from langchain_ollama import ChatOllama\n",
"from langchain_ibm import ChatWatsonx\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 pydantic import BaseModel, Field\n",
"from typing import Literal\n",
"from dotenv import load_dotenv\n",
"import os\n",
"\n",
"from langchain_community.document_loaders import PyPDFLoader, CSVLoader, WebBaseLoader, DirectoryLoader\n",
"from youtube_transcript_api import YouTubeTranscriptApi\n",
"from langchain_core.documents import Document\n",
"from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
"from langchain_ollama import OllamaEmbeddings\n",
"from langchain_ibm import WatsonxEmbeddings\n",
"from langchain_chroma import Chroma\n",
"from langchain_community.vectorstores import FAISS\n",
"from langchain_openai import ChatOpenAI\n",
"\n",
"from langchain_classic.chains.query_constructor.base import AttributeInfo\n",
"from langchain_classic.retrievers import EnsembleRetriever, ContextualCompressionRetriever,BM25Retriever\n",
"from langchain_classic.retrievers.self_query.chroma import ChromaTranslator\n",
"from langchain_classic.retrievers.self_query.base import SelfQueryRetriever\n",
"from langchain_community.cross_encoders import HuggingFaceCrossEncoder"
],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipykernel_117554/2207901163.py:14: DeprecationWarning: `langchain-community` is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration guidance toward standalone integration packages.\n",
" from langchain_community.document_loaders import PyPDFLoader, CSVLoader, WebBaseLoader, DirectoryLoader\n",
"USER_AGENT environment variable not set, consider setting it to identify your requests.\n"
]
}
],
"execution_count": 7
},
{
"cell_type": "code",
"id": "5e8adec3",
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-29T09:32:33.131396679Z",
"start_time": "2026-05-29T09:32:33.120394257Z"
}
},
"source": [
"# .env 내용 가져오기\n",
"load_dotenv()\n",
"\n",
"apikey = os.getenv(\"WATSONX_API_KEY\")\n",
"project_id = os.getenv(\"WATSONX_PROJECT_ID\")\n",
"watsonx_ai_url = os.getenv(\"WATSONX_URL\")\n",
"hf_token = os.getenv(\"HF_TOKEN\")"
],
"outputs": [],
"execution_count": 8
},
{
"cell_type": "code",
"id": "38308ea9",
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-29T09:32:37.470030012Z",
"start_time": "2026-05-29T09:32:33.133843674Z"
}
},
"source": [
"ollama_embedding = OllamaEmbeddings(model=\"nomic-embed-text-v2-moe\")\n",
"watson_embedding = WatsonxEmbeddings(\n",
" model_id=\"ibm/granite-embedding-278m-multilingual\",\n",
" url = f\"{watsonx_ai_url}\",\n",
" api_key = f\"{apikey}\",\n",
" project_id=f\"{project_id}\"\n",
")\n",
"\n",
"hugging_llm = ChatOpenAI(\n",
" model=\"Qwen/Qwen2.5-7B-Instruct:together\",\n",
" api_key=hf_token,\n",
" base_url=\"https://router.huggingface.co/v1\",\n",
" temperature=0\n",
")\n",
"\n",
"watson_llm = ChatWatsonx(\n",
" model_id=\"ibm/granite-4-h-small\",\n",
" url = f\"{watsonx_ai_url}\",\n",
" api_key = f\"{apikey}\",\n",
" project_id=f\"{project_id}\",\n",
" max_tokens = 2000,\n",
" params = {\n",
" \"temperature\":0\n",
" }\n",
")\n",
"\n",
"# 로컬 LLM\n",
"qwen_llm = ChatOllama(model=\"qwen3.5:4b\",temperature=0)\n",
"exaone_llm = ChatOllama(model=\"exaone3.5:2.4b\",temperature=0)"
],
"outputs": [],
"execution_count": 9
},
{
"cell_type": "code",
"id": "f0ea314f",
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-29T09:32:37.519275275Z",
"start_time": "2026-05-29T09:32:37.482764023Z"
}
},
"source": [
"# pdf => chunks 반환 함수\n",
"def create_chunks_from_pdf(pdf_path,chunk_size=500,chunk_overlap=50):\n",
" loader = PyPDFLoader(pdf_path)\n",
" splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)\n",
" chunks = splitter.split_documents(loader.load())\n",
"\n",
" # 공백 제거\n",
" chunks = [chunk for chunk in chunks if chunk.page_content.strip()]\n",
" return chunks\n",
"\n",
"def create_vectorstore(chunks,embeddings,collection_name,persist_directory='./db/chroma_db'):\n",
" return Chroma.from_documents(\n",
" documents=chunks, \n",
" embedding=embeddings, \n",
" persist_directory=persist_directory, \n",
" collection_name=collection_name)\n",
"\n",
"\n",
"def create_retriever(vectorstore,search_type=\"similarity\",k=3,fetch_k=20,lambda_mult=0.5):\n",
" kwargs = {\"k\":k}\n",
"\n",
" if search_type==\"mmr\":\n",
" kwargs['fetch_k'] = fetch_k\n",
" kwargs['lambda_mult'] = lambda_mult \n",
"\n",
"\n",
" return vectorstore.as_retriever(search_type=search_type, search_kwargs=kwargs)\n",
"\n",
"\n",
"def print_retrieved_docs(title, retriever, query):\n",
" docs = retriever.invoke(query)\n",
"\n",
" print(\"\\n\"+\"=\"*50)\n",
" print(title)\n",
" print(\"=\"*50)\n",
"\n",
" for i, doc in enumerate(docs):\n",
" print(f\"\\n[chunk {i}]\")\n",
" print(doc.page_content)\n",
" print(f\"\\nPage: {doc.metadata.get(\"page\")}\")"
],
"outputs": [],
"execution_count": 10
},
{
"cell_type": "markdown",
"id": "d74ac88b",
"metadata": {},
"source": [
"### 1. 임베딩 모델, 청크 사이즈, 오버랩 "
]
},
{
"cell_type": "code",
"id": "9bdff4a0",
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-29T09:32:38.289513200Z",
"start_time": "2026-05-29T09:32:37.531732515Z"
}
},
"source": [
"chunks1 = create_chunks_from_pdf(\"./data/Summary of ChatGPTGPT-4 Research.pdf\",1000, 100)\n",
"chunks2 = create_chunks_from_pdf(\"./data/Summary of ChatGPTGPT-4 Research.pdf\",300, 30)\n",
"\n",
"print(f\"분할된 청크 수 : {len(chunks1)}\")\n",
"print(f\"분할된 청크 수 : {len(chunks2)}\")"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"분할된 청크 수 : 118\n",
"분할된 청크 수 : 378\n"
]
}
],
"execution_count": 11
},
{
"cell_type": "code",
"id": "09b02dbc",
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-29T09:32:51.735295861Z",
"start_time": "2026-05-29T09:32:38.305096987Z"
}
},
"source": [
"vectorestore1 = create_vectorstore(chunks1,watson_embedding,collection_name=\"gpt_research_watson3\")\n",
"vectorestore2 = create_vectorstore(chunks1,ollama_embedding,collection_name=\"gpt_research_watson4\")\n",
"\n",
"watson1_retriever = create_retriever(vectorestore1)\n",
"watson2_retriever = create_retriever(vectorestore2)\n",
"\n",
"\n",
"query = 'where can i use chatGPT?'\n",
"\n",
"print_retrieved_docs('watson embedding',watson1_retriever, query)\n",
"print_retrieved_docs('ollama embedding',watson2_retriever,query)"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"==================================================\n",
"watson embedding\n",
"==================================================\n",
"\n",
"[chunk 0]\n",
"development.\n",
"2 Related work of ChatGPT\n",
"In this section, we review the latest research related to the application, ethics,\n",
"and evaluation of ChatGPT.\n",
"2.1 Application of ChatGPT\n",
"2.1.1 Question And Answering\n",
"In the education field\n",
"ChatGPT is commonly used for question and answers testing in the edu-\n",
"cation sector. Users can use ChatGPT to learn, compare and verify answers\n",
"for different academic subjects such as physics, mathematics, and chemistry,\n",
"4\n",
"\n",
"Page: 3\n",
"\n",
"[chunk 1]\n",
"development.\n",
"2 Related work of ChatGPT\n",
"In this section, we review the latest research related to the application, ethics,\n",
"and evaluation of ChatGPT.\n",
"2.1 Application of ChatGPT\n",
"2.1.1 Question And Answering\n",
"In the education field\n",
"ChatGPT is commonly used for question and answers testing in the edu-\n",
"cation sector. Users can use ChatGPT to learn, compare and verify answers\n",
"for different academic subjects such as physics, mathematics, and chemistry,\n",
"4\n",
"\n",
"Page: 3\n",
"\n",
"[chunk 2]\n",
"development.\n",
"2 Related work of ChatGPT\n",
"In this section, we review the latest research related to the application, ethics,\n",
"and evaluation of ChatGPT.\n",
"2.1 Application of ChatGPT\n",
"2.1.1 Question And Answering\n",
"In the education field\n",
"ChatGPT is commonly used for question and answers testing in the edu-\n",
"cation sector. Users can use ChatGPT to learn, compare and verify answers\n",
"for different academic subjects such as physics, mathematics, and chemistry,\n",
"4\n",
"\n",
"Page: 3\n",
"\n",
"==================================================\n",
"ollama embedding\n",
"==================================================\n",
"\n",
"[chunk 0]\n",
"development.\n",
"2 Related work of ChatGPT\n",
"In this section, we review the latest research related to the application, ethics,\n",
"and evaluation of ChatGPT.\n",
"2.1 Application of ChatGPT\n",
"2.1.1 Question And Answering\n",
"In the education field\n",
"ChatGPT is commonly used for question and answers testing in the edu-\n",
"cation sector. Users can use ChatGPT to learn, compare and verify answers\n",
"for different academic subjects such as physics, mathematics, and chemistry,\n",
"4\n",
"\n",
"Page: 3\n",
"\n",
"[chunk 1]\n",
"development.\n",
"2 Related work of ChatGPT\n",
"In this section, we review the latest research related to the application, ethics,\n",
"and evaluation of ChatGPT.\n",
"2.1 Application of ChatGPT\n",
"2.1.1 Question And Answering\n",
"In the education field\n",
"ChatGPT is commonly used for question and answers testing in the edu-\n",
"cation sector. Users can use ChatGPT to learn, compare and verify answers\n",
"for different academic subjects such as physics, mathematics, and chemistry,\n",
"4\n",
"\n",
"Page: 3\n",
"\n",
"[chunk 2]\n",
"development.\n",
"2 Related work of ChatGPT\n",
"In this section, we review the latest research related to the application, ethics,\n",
"and evaluation of ChatGPT.\n",
"2.1 Application of ChatGPT\n",
"2.1.1 Question And Answering\n",
"In the education field\n",
"ChatGPT is commonly used for question and answers testing in the edu-\n",
"cation sector. Users can use ChatGPT to learn, compare and verify answers\n",
"for different academic subjects such as physics, mathematics, and chemistry,\n",
"4\n",
"\n",
"Page: 3\n"
]
}
],
"execution_count": 12
},
{
"cell_type": "markdown",
"id": "85b489ff",
"metadata": {},
"source": [
"### 2. MMR(Maximal Marginal Relevace) Retriever\n",
"- 관련성(Relevace)과 다양성(Diversity) 고려\n",
"- 법률 문서, 기술 매뉴얼처럼 유사 내용이 반복되는 문서에서 효과적\n",
"- 동작과정\n",
" - 질문 => 임베딩\n",
" - 벡터 스토어에서 질문과 유사한 상위 fetch_K(후보 문서) 추출\n",
" - 후보문서에서 MMR 점수 계산 => 가장 높은 문서 추출\n",
" - 남은 후보에서 MMR 점수 계산 => 높은 문서 추출\n",
" - 추출한 높은 문서에서 최종 K 반환"
]
},
{
"cell_type": "code",
"id": "f6d1c603",
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-29T09:32:54.345812917Z",
"start_time": "2026-05-29T09:32:51.753992471Z"
}
},
"source": [
"chunks1 = create_chunks_from_pdf(\"./data/2026 상 삼성전자 DX부문 직무기술서.pdf\")\n",
"vectorestore1 = create_vectorstore(chunks1,watson_embedding,collection_name=\"samsung_watson1\",persist_directory=\"./db/watson_chroma\")\n",
"\n",
"\n",
"mmr_retriever = create_retriever(vectorestore1,search_type=\"mmr\",k=5)\n",
"similarity_retriever = create_retriever(vectorestore1,k=5)\n",
"\n",
"query = '마케팅 - 제품/서비스 마케팅 포지션은?'\n",
"\n",
"print_retrieved_docs('MMR',mmr_retriever, query)\n",
"print_retrieved_docs('similarity',similarity_retriever, query)\n"
],
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"==================================================\n",
"MMR\n",
"==================================================\n",
"\n",
"[chunk 0]\n",
"마케팅\n",
"마켓 센싱 및 정보 분석 결과를 바탕으로\n",
" 당사 제품과 서비스의 차별화 가치를 소비자에게 효과적인\n",
"커뮤니케이션 방법으로 전달하여 목표한 경영성과를 창출하고 브랜드 가치를 제고합니다\n",
"\n",
"Page: 14\n",
"\n",
"[chunk 1]\n",
"국내영업마케팅\n",
"국내의 각 분야별 영업 채널을 발굴\n",
" 지원하여 성과 창출과 지속 성장을 추구하는 동시에\n",
" 한국 시장에\n",
"대한 심도있는 분석을 통해 삼성전자\n",
" 부문 제품의 마케팅 전략을 수립 ⋅ 적용하고 글로벌\n",
"시장으로의 확산 기반을 마련합니다\n",
"\n",
"Page: 24\n",
"\n",
"[chunk 2]\n",
"해외영업\n",
"고객과 시장\n",
" 제품에 대한 이해를 바탕으로 시장 수요와 경쟁환경을 분석하여 국가\n",
" 거래선별 목표 설정\n",
"영업전략 수립\n",
" 신규 제품\n",
" 영업 채널을 발굴하고 판매전략 수립 및 실행을 통해 매출 극대화에\n",
"기여합니다\n",
"\n",
"Page: 18\n",
"\n",
"[chunk 3]\n",
"구매\n",
"제품 생산에 필요한 자원\n",
" 부품\n",
" 설비 및 제품\n",
" 을 최적의 품질과 가격으로\n",
"협상\n",
" 구매하고 시장의 수요 및 생산 계획에 맞춰 적기 공급하여 회사 경영에 기여합니다\n",
"\n",
"Page: 26\n",
"\n",
"[chunk 4]\n",
"•\n",
"•\n",
"•\n",
"•\n",
"•\n",
"•\n",
"•\n",
"•\n",
"•\n",
"•\n",
"•\n",
"\n",
"Page: 7\n",
"\n",
"==================================================\n",
"similarity\n",
"==================================================\n",
"\n",
"[chunk 0]\n",
"마케팅\n",
"마켓 센싱 및 정보 분석 결과를 바탕으로\n",
" 당사 제품과 서비스의 차별화 가치를 소비자에게 효과적인\n",
"커뮤니케이션 방법으로 전달하여 목표한 경영성과를 창출하고 브랜드 가치를 제고합니다\n",
"\n",
"Page: 14\n",
"\n",
"[chunk 1]\n",
"마케팅\n",
"마켓 센싱 및 정보 분석 결과를 바탕으로\n",
" 당사 제품과 서비스의 차별화 가치를 소비자에게 효과적인\n",
"커뮤니케이션 방법으로 전달하여 목표한 경영성과를 창출하고 브랜드 가치를 제고합니다\n",
"\n",
"Page: 14\n",
"\n",
"[chunk 2]\n",
"국내영업마케팅\n",
"국내의 각 분야별 영업 채널을 발굴\n",
" 지원하여 성과 창출과 지속 성장을 추구하는 동시에\n",
" 한국 시장에\n",
"대한 심도있는 분석을 통해 삼성전자\n",
" 부문 제품의 마케팅 전략을 수립 ⋅ 적용하고 글로벌\n",
"시장으로의 확산 기반을 마련합니다\n",
"\n",
"Page: 24\n",
"\n",
"[chunk 3]\n",
"국내영업마케팅\n",
"국내의 각 분야별 영업 채널을 발굴\n",
" 지원하여 성과 창출과 지속 성장을 추구하는 동시에\n",
" 한국 시장에\n",
"대한 심도있는 분석을 통해 삼성전자\n",
" 부문 제품의 마케팅 전략을 수립 ⋅ 적용하고 글로벌\n",
"시장으로의 확산 기반을 마련합니다\n",
"\n",
"Page: 24\n",
"\n",
"[chunk 4]\n",
"해외영업\n",
"고객과 시장\n",
" 제품에 대한 이해를 바탕으로 시장 수요와 경쟁환경을 분석하여 국가\n",
" 거래선별 목표 설정\n",
"영업전략 수립\n",
" 신규 제품\n",
" 영업 채널을 발굴하고 판매전략 수립 및 실행을 통해 매출 극대화에\n",
"기여합니다\n",
"\n",
"Page: 18\n"
]
}
],
"execution_count": 13
},
{
"cell_type": "markdown",
"id": "82d43df6",
"metadata": {},
"source": [
"### 3. SelfQuery Retriever\n",
"- 자연어 질문을 분석하여 시맨틱 검색쿼리와 메타데이터필터를 LLM이 자동으로 생성하게 하는 고급 Retriever\n",
"- 질문 : 2023년 이후 계약금액이 1억이상인 계약 찾아줘 => LLM \n",
" - 시맨틱 검색쿼리 : 계약\n",
" - filter : {year >= 2023, 계약금액 >= 100000 ~}"
]
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-29T09:32:55.741393823Z",
"start_time": "2026-05-29T09:32:54.370104104Z"
}
},
"cell_type": "code",
"source": "!pip install lark",
"id": "6b910cf56efea998",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: lark in ./.venv/lib/python3.12/site-packages (1.3.1)\r\n"
]
}
],
"execution_count": 14
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-29T09:32:55.778912756Z",
"start_time": "2026-05-29T09:32:55.758410087Z"
}
},
"cell_type": "code",
"source": [
"docs = [\n",
" Document(\n",
" page_content=\"삼성전자 제품 마케팅 직무입니다.\",\n",
" metadata={\n",
" \"year\":2025,\n",
" \"department\":\"marketing\"\n",
" }\n",
" ),\n",
" Document(\n",
" page_content=\"AI 연구 개발 직무입니다.\",\n",
" metadata={\n",
" \"year\":2024,\n",
" \"department\":\"ai\"\n",
" }\n",
" ),\n",
" Document(\n",
" page_content=\"백엔드 개발 직무입니다.\",\n",
" metadata={\n",
" \"year\":2025,\n",
" \"department\":\"developer\"\n",
" }\n",
" ),\n",
"]\n",
"\n",
"\n",
"metadata_field_info = [\n",
" AttributeInfo(name=\"year\", description=\"문서 작성 연도\", type=\"integer\"),\n",
" AttributeInfo(name=\"department\", description=\"직무 부서\", type=\"string\"),\n",
"]\n",
"\n",
"document_content_description = \"회사 내부 문서 및 직무 자료\"\n"
],
"id": "b3a603a71973fd7b",
"outputs": [],
"execution_count": 15
},
{
"cell_type": "code",
"id": "c0c3f024",
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-29T09:32:56.283073377Z",
"start_time": "2026-05-29T09:32:55.782236223Z"
}
},
"source": [
"vectorestore1 = create_vectorstore(docs,watson_embedding,collection_name=\"selfquery\",persist_directory=\"./db/watson_chroma\")\n",
"\n",
"self_query_retriever = SelfQueryRetriever.from_llm(\n",
" llm=watson_llm,\n",
" vectorstore=vectorestore1,\n",
" document_contents=document_content_description,\n",
" metadata_field_info=metadata_field_info,\n",
" verbose=True,\n",
" enable_limit=True,\n",
" structured_query_translator=ChromaTranslator()\n",
")"
],
"outputs": [],
"execution_count": 16
},
{
"cell_type": "code",
"id": "6eab886a",
"metadata": {
"ExecuteTime": {
"end_time": "2026-05-29T09:32:58.437857021Z",
"start_time": "2026-05-29T09:32:56.299326951Z"
}
},
"source": [
"question = \"2024년 이후 ai 부서 직무를 찾아줘\"\n",
"self_query_retriever.invoke(question)"
],
"outputs": [
{
"data": {
"text/plain": [
"[Document(id='7180400a-6f3a-4519-b4c8-b384e20e3159', metadata={'year': 2024, 'department': 'ai'}, page_content='AI 연구 개발 직무입니다.'),\n",
" Document(id='f2508f12-f99b-4084-88dd-8777a65e4596', metadata={'department': 'ai', 'year': 2024}, page_content='AI 연구 개발 직무입니다.'),\n",
" Document(id='cb43ff6b-94dc-4e4b-afbe-a025875ed087', metadata={'year': 2024, 'department': 'ai'}, page_content='AI 연구 개발 직무입니다.'),\n",
" Document(id='3fad052f-fabc-4417-88b8-fd0abf471385', metadata={'department': 'ai', 'year': 2024}, page_content='AI 연구 개발 직무입니다.')]"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"execution_count": 17
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
}