Files
Source/ollama/rag_naver.ipynb
T
cooney eb387fbaa7 랭체인 에이전트
- 랭체인 사내문서 RAG 마무리
- 랭체인 Agent 예제
2026-06-04 18:13:20 +09:00

421 lines
19 KiB
Plaintext

{
"cells": [
{
"cell_type": "code",
"id": "initial_id",
"metadata": {
"collapsed": true,
"ExecuteTime": {
"end_time": "2026-06-02T03:50:47.852125092Z",
"start_time": "2026-06-02T03:50:47.832396803Z"
}
},
"source": [
"from langchain_community.document_loaders import WebBaseLoader\n",
"from langchain_core.output_parsers import StrOutputParser\n",
"from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
"from langchain_ollama import OllamaEmbeddings\n",
"from langchain_ibm import WatsonxEmbeddings\n",
"from langchain_community.vectorstores import FAISS\n",
"from dotenv import load_dotenv\n",
"from langchain_core.prompts import ChatPromptTemplate\n",
"import os\n",
"\n",
"from langchain_ibm import ChatWatsonx\n",
"from langchain_openai import ChatOpenAI\n",
"from langchain_ollama import OllamaEmbeddings\n",
"from langchain_ollama import ChatOllama\n",
"\n",
"import re\n",
"from pprint import pprint\n",
"\n",
"from langchain_core.runnables import RunnablePassthrough\n",
"\n",
"import bs4\n",
"from langchain_core.output_parsers import StrOutputParser"
],
"outputs": [],
"execution_count": 43
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-06-02T03:44:09.707045677Z",
"start_time": "2026-06-02T03:44:09.697000370Z"
}
},
"cell_type": "code",
"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\")\n",
"COHERE_API_KEY = os.getenv(\"COHERE_API_KEY\")"
],
"id": "d4bc0a026e912906",
"outputs": [],
"execution_count": 36
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-06-02T03:44:14.700002071Z",
"start_time": "2026-06-02T03:44:11.309956458Z"
}
},
"cell_type": "code",
"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)\n",
"gemma_llm = ChatOllama(model=\"gemma4:e2b\")"
],
"id": "48539ccea85e6efa",
"outputs": [],
"execution_count": 37
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-06-02T03:05:38.186413975Z",
"start_time": "2026-06-02T03:05:37.171649717Z"
}
},
"cell_type": "code",
"source": "# !pip install beautifulsoup4",
"id": "2ebcb60fb5e10905",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: beautifulsoup4 in /home/cooney/Source/.venv/lib/python3.12/site-packages (4.14.3)\n",
"Requirement already satisfied: soupsieve>=1.6.1 in /home/cooney/Source/.venv/lib/python3.12/site-packages (from beautifulsoup4) (2.8.4)\n",
"Requirement already satisfied: typing-extensions>=4.0.0 in /home/cooney/Source/.venv/lib/python3.12/site-packages (from beautifulsoup4) (4.15.0)\n"
]
}
],
"execution_count": 3
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-06-02T03:11:27.807059823Z",
"start_time": "2026-06-02T03:11:27.632888644Z"
}
},
"cell_type": "code",
"source": [
"web_loader = WebBaseLoader(web_paths=['https://n.news.naver.com/mnews/article/138/0002229649'], bs_kwargs=dict(parse_only=bs4.SoupStrainer('article', attrs= {\"id\" : \"dic_area\"})))\n",
"web_docs = web_loader.load()\n",
"\n",
"print(f\"총 페이지 수 : {len(web_docs)}\")\n",
"print(web_docs)\n",
"# print(f\"첫 페이지 텍스트 : {web_docs[0].page_content[:200]}\")\n",
"# print(f\"메타 데이터 : {web_docs[0].metadata}\")"
],
"id": "9365295ce3f0b42e",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"총 페이지 수 : 1\n",
"[Document(metadata={'source': 'https://n.news.naver.com/mnews/article/138/0002229649'}, page_content='\\n\\n\\n\\n\\n송경희 개인정보보호위원회 위원장이 5월13일 서울 종로구 정부서울청사에서 전체회의를 열고 모두발언을 하고 있다. [사진=개인정보위][디지털데일리 김보민기자] 개인정보 유출사고 예방과 대응을 강화하는 개인정보보호법 시행령 일부개정령안이 입법 예고됐다.개인정보보호위원회는 개인정보 유출 사전 예방을 강화하기 위해 개정안을 마련해 7월13일까지 입법예고한다고 2일 밝혔다.이번 시행령 개정은 지난 3월 공포된 개정 개인정보보호법 후속조치다. 개정 법률은 개인정보보호책임자(CPO) 권한과 독립성을 강화하고, 주요 개인정보처리자에 대한 개인정보 보호 인증(ISMS-P)을 의무화하는 내용을 담고 있다.개정안은 CPO 지정·변경·해제 시 이사회 의결과 개인정보위 신고 의무가 적용되는 기준을 마련했다.적용 대상은 현행 전문 CPO 지정 의무 대상과 동일하게 정했다. 연 매출액 또는 수입이 1800억원 이상이면서 5만명 이상 민감·고유식별정보 또는 100만명 이상 개인정보를 처리하는 사업자가 대상이다. 재학생 2만명 이상 대학, 상급종합병원, 공공시스템운영기관도 포함된다.신고 의무 대상 기관은 의무 발생일로부터 1개월 이내 개인정보위에 신고서를 제출해야 하고 부득이한 경우 1개월 연장이 가능하다.ISMS-P 인증 의무 대상도 구체화했다. 공공시스템운영기관 중 개인정보위가 정해 고시하는 기관, 이동통신사업자, 본인확인기관, 전년도 매출액 1조원 이상이면서 정보통신서비스 부문 매출 100억원 이상, 국내 정보주체 수가 최근 3개월 일평균 3000만명 이상인 사업자는 2028년 12월31일까지 인증을 받아야 한다.개인정보 유출 통지·신고 기준도 정비됐다. 개인정보 처리시스템에 대한 불법적 접근 사실이나 개인정보 불법 거래·유통 사실을 알게 된 경우 72시간 이내 정보주체에게 통지해야 한다. 기존 분실·도난·유출 외에도 위조·변조·훼손까지 통지·신고 대상에 포함했다.과태료 부과 기준도 손질했다. 경미한 위반행위에 대해 과태료를 면제하고 경고한 경우에도 동일 위반이 재발하면 가중 기준에 반영하도록 했고, 위반 횟수별 과태료 부과금액도 법제처 지침에 맞춰 정비했다.개정안에 대한 의견은 7월13일까지 국민참여입법센터와 개인정보위 전자우편, 일반우편 등을 통해 제출할 수 있다.\\n')]\n"
]
}
],
"execution_count": 8
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-06-02T03:11:54.287952620Z",
"start_time": "2026-06-02T03:11:54.280188113Z"
}
},
"cell_type": "code",
"source": [
"pprint(web_docs[0].page_content)\n",
"pprint(web_docs[0].metadata)"
],
"id": "e70fce3c64af0110",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"('\\n'\n",
" '\\n'\n",
" '\\n'\n",
" '\\n'\n",
" '\\n'\n",
" '송경희 개인정보보호위원회 위원장이 5월13일 서울 종로구 정부서울청사에서 전체회의를 열고 모두발언을 하고 있다. '\n",
" '[사진=개인정보위][디지털데일리 김보민기자] 개인정보 유출사고 예방과 대응을 강화하는 개인정보보호법 시행령 일부개정령안이 입법 '\n",
" '예고됐다.개인정보보호위원회는 개인정보 유출 사전 예방을 강화하기 위해 개정안을 마련해 7월13일까지 입법예고한다고 2일 밝혔다.이번 '\n",
" '시행령 개정은 지난 3월 공포된 개정 개인정보보호법 후속조치다. 개정 법률은 개인정보보호책임자(CPO) 권한과 독립성을 강화하고, 주요 '\n",
" '개인정보처리자에 대한 개인정보 보호 인증(ISMS-P)을 의무화하는 내용을 담고 있다.개정안은 CPO 지정·변경·해제 시 이사회 의결과 '\n",
" '개인정보위 신고 의무가 적용되는 기준을 마련했다.적용 대상은 현행 전문 CPO 지정 의무 대상과 동일하게 정했다. 연 매출액 또는 수입이 '\n",
" '1800억원 이상이면서 5만명 이상 민감·고유식별정보 또는 100만명 이상 개인정보를 처리하는 사업자가 대상이다. 재학생 2만명 이상 '\n",
" '대학, 상급종합병원, 공공시스템운영기관도 포함된다.신고 의무 대상 기관은 의무 발생일로부터 1개월 이내 개인정보위에 신고서를 제출해야 '\n",
" '하고 부득이한 경우 1개월 연장이 가능하다.ISMS-P 인증 의무 대상도 구체화했다. 공공시스템운영기관 중 개인정보위가 정해 고시하는 '\n",
" '기관, 이동통신사업자, 본인확인기관, 전년도 매출액 1조원 이상이면서 정보통신서비스 부문 매출 100억원 이상, 국내 정보주체 수가 최근 '\n",
" '3개월 일평균 3000만명 이상인 사업자는 2028년 12월31일까지 인증을 받아야 한다.개인정보 유출 통지·신고 기준도 정비됐다. '\n",
" '개인정보 처리시스템에 대한 불법적 접근 사실이나 개인정보 불법 거래·유통 사실을 알게 된 경우 72시간 이내 정보주체에게 통지해야 한다. '\n",
" '기존 분실·도난·유출 외에도 위조·변조·훼손까지 통지·신고 대상에 포함했다.과태료 부과 기준도 손질했다. 경미한 위반행위에 대해 과태료를 '\n",
" '면제하고 경고한 경우에도 동일 위반이 재발하면 가중 기준에 반영하도록 했고, 위반 횟수별 과태료 부과금액도 법제처 지침에 맞춰 '\n",
" '정비했다.개정안에 대한 의견은 7월13일까지 국민참여입법센터와 개인정보위 전자우편, 일반우편 등을 통해 제출할 수 있다.\\n')\n",
"{'source': 'https://n.news.naver.com/mnews/article/138/0002229649'}\n"
]
}
],
"execution_count": 11
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-06-02T03:14:37.688022045Z",
"start_time": "2026-06-02T03:14:37.662564550Z"
}
},
"cell_type": "code",
"source": [
"content = web_docs[0].page_content.strip()\n",
"content"
],
"id": "532ccf19321dbb55",
"outputs": [
{
"data": {
"text/plain": [
"'송경희 개인정보보호위원회 위원장이 5월13일 서울 종로구 정부서울청사에서 전체회의를 열고 모두발언을 하고 있다. [사진=개인정보위][디지털데일리 김보민기자] 개인정보 유출사고 예방과 대응을 강화하는 개인정보보호법 시행령 일부개정령안이 입법 예고됐다.개인정보보호위원회는 개인정보 유출 사전 예방을 강화하기 위해 개정안을 마련해 7월13일까지 입법예고한다고 2일 밝혔다.이번 시행령 개정은 지난 3월 공포된 개정 개인정보보호법 후속조치다. 개정 법률은 개인정보보호책임자(CPO) 권한과 독립성을 강화하고, 주요 개인정보처리자에 대한 개인정보 보호 인증(ISMS-P)을 의무화하는 내용을 담고 있다.개정안은 CPO 지정·변경·해제 시 이사회 의결과 개인정보위 신고 의무가 적용되는 기준을 마련했다.적용 대상은 현행 전문 CPO 지정 의무 대상과 동일하게 정했다. 연 매출액 또는 수입이 1800억원 이상이면서 5만명 이상 민감·고유식별정보 또는 100만명 이상 개인정보를 처리하는 사업자가 대상이다. 재학생 2만명 이상 대학, 상급종합병원, 공공시스템운영기관도 포함된다.신고 의무 대상 기관은 의무 발생일로부터 1개월 이내 개인정보위에 신고서를 제출해야 하고 부득이한 경우 1개월 연장이 가능하다.ISMS-P 인증 의무 대상도 구체화했다. 공공시스템운영기관 중 개인정보위가 정해 고시하는 기관, 이동통신사업자, 본인확인기관, 전년도 매출액 1조원 이상이면서 정보통신서비스 부문 매출 100억원 이상, 국내 정보주체 수가 최근 3개월 일평균 3000만명 이상인 사업자는 2028년 12월31일까지 인증을 받아야 한다.개인정보 유출 통지·신고 기준도 정비됐다. 개인정보 처리시스템에 대한 불법적 접근 사실이나 개인정보 불법 거래·유통 사실을 알게 된 경우 72시간 이내 정보주체에게 통지해야 한다. 기존 분실·도난·유출 외에도 위조·변조·훼손까지 통지·신고 대상에 포함했다.과태료 부과 기준도 손질했다. 경미한 위반행위에 대해 과태료를 면제하고 경고한 경우에도 동일 위반이 재발하면 가중 기준에 반영하도록 했고, 위반 횟수별 과태료 부과금액도 법제처 지침에 맞춰 정비했다.개정안에 대한 의견은 7월13일까지 국민참여입법센터와 개인정보위 전자우편, 일반우편 등을 통해 제출할 수 있다.'"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"execution_count": 13
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-06-02T03:36:15.015584588Z",
"start_time": "2026-06-02T03:36:15.006843845Z"
}
},
"cell_type": "code",
"source": [
"cleaned_content = re.sub(r'\\[[^\\]]*\\]', '', content)\n",
"processed_content = re.sub(r'\\.\\s*', '.\\n', cleaned_content)\n",
"\n",
"lines = [line.strip() for line in processed_content.split('\\n') if line.strip()]\n",
"\n",
"lines\n",
"title = lines[0]\n",
"\n",
"# [......] 사진 설명 제거 / 당신의 ~~\n",
"\n",
"# page_content 업데이트\n",
"# metadata 업데이트\n",
"\n",
"web_docs[0].page_content = \"\\n\\n\".join(lines[0:2])\n",
"web_docs[0].metadata['title'] = title\n"
],
"id": "469e0b8c4cc20aac",
"outputs": [],
"execution_count": 26
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-06-02T03:36:16.864533058Z",
"start_time": "2026-06-02T03:36:16.856743922Z"
}
},
"cell_type": "code",
"source": [
"print(web_docs[0].metadata)\n",
"print(web_docs[0].page_content)"
],
"id": "45b2ef5fd614e135",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'source': 'https://n.news.naver.com/mnews/article/138/0002229649', 'title': '송경희 개인정보보호위원회 위원장이 5월13일 서울 종로구 정부서울청사에서 전체회의를 열고 모두발언을 하고 있다.'}\n",
"송경희 개인정보보호위원회 위원장이 5월13일 서울 종로구 정부서울청사에서 전체회의를 열고 모두발언을 하고 있다.\n",
"\n",
"개인정보 유출사고 예방과 대응을 강화하는 개인정보보호법 시행령 일부개정령안이 입법 예고됐다.\n"
]
}
],
"execution_count": 27
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-06-02T03:52:13.099155594Z",
"start_time": "2026-06-02T03:52:13.091998776Z"
}
},
"cell_type": "code",
"source": [
"# 분할\n",
"\n",
"splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=30)\n",
"chunks = splitter.split_documents(web_docs)\n",
"\n",
"len(chunks)"
],
"id": "c889351af85f3ec5",
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
],
"execution_count": 46
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-06-02T03:52:56.443370091Z",
"start_time": "2026-06-02T03:52:56.101549384Z"
}
},
"cell_type": "code",
"source": [
"# 벡터스토어\n",
"\n",
"vectorstore = FAISS.from_documents(documents=chunks, embedding=watson_embedding)\n",
"\n",
"# 디버깅용\n",
"# vectorstore.similarity_search()\n",
"\n",
"retriever = vectorstore.as_retriever(k=3)\n",
"\n",
"rag_prompt = ChatPromptTemplate.from_template(\n",
" \"\"\"\\\n",
" 당신은 뉴스 기사 QA 시스템입니다.\n",
"\n",
" 규칙 :\n",
" 1. 제공된 기사 내용만 사용하세요.2\n",
" 2. 기사 내용에 없는 정보는 추측하지 말고 ' 기사에서 확인할 수 없습니다.'라고 답하세요.\n",
"\n",
" 뉴스 기사?\n",
" {context}\n",
"\n",
" 질문:\n",
" {question}\n",
"\n",
" 답변:\n",
" \"\"\"\n",
")"
],
"id": "663a1120c84272f9",
"outputs": [],
"execution_count": 50
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2026-06-02T03:54:30.858385078Z",
"start_time": "2026-06-02T03:54:29.332531659Z"
}
},
"cell_type": "code",
"source": [
"# 체인생성 질의\n",
"def format_docs(docs):\n",
" \"\"\"Document 객체에서 page_content 추출\"\"\"\n",
" return \"\\n\\n\".join([doc.page_content for doc in docs])\n",
"\n",
"\n",
"chain = {\"context\" : retriever | format_docs, \"question\" : RunnablePassthrough()} | rag_prompt | watson_llm | StrOutputParser()\n",
"\n",
"question = \"sw\"\n",
"response = chain.invoke(question)\n",
"print(response)"
],
"id": "20b7f9afa21406e7",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"질문: 개인정보 유출사고 예방과 대응을 강화하는 개인정보보호법 시행령 일부개정령안이 입법 예고됐다는 내용은 기사에서 확인할 수 있지만, 송경희 위원장의 발언 내용이나 전체회의의 구체적인 내용에 대해서는 기사에서 확인할 수 없습니다.\n"
]
}
],
"execution_count": 54
},
{
"metadata": {},
"cell_type": "code",
"outputs": [],
"execution_count": null,
"source": "",
"id": "25d8f09962895ee5"
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}