법률적 질문에 대해 답을 주는 챗봇을 구현해보려고 한다.

 

 

이 챗봇을 만들게 된 이유는

실생활과 가장 밀접하게 사용할 수 있으면서 RAG 구조의 장점을 살리기에 적합하다고 생각했기 때문이다. 

 

법률 분야는 정답이 명확하고 판례와 조문에 근거한 설명이 요구되기 때문에,

생성형 AI의 대표적인 한계인 hallucination(사실과 다른 내용을 생성하는 문제)을 완화하는 데 RAG 구조가 특히 유리하다.

RAG에 대한 자세한 개념은 따로 정리하였다.

 

 

또한, 법학전문대학원협의회 사이트에서 제공하는 PDF 기반의 민법 표준판례연구자료는
법률적 질문에 대해 보다 신뢰성 있는 답변을 생성하는 데 적합한 기반이 되었다.

법학전문대학원협의회

 

 

 

 

먼저 필요한 라이브러리들을 설치한다.

pip install langchain langchain-community pypdf

 

 

  1. langchain
    • LangChain의 핵심 라이브러리.
    • 다양한 LLM(OpenAI, Claude 등)과 연결하고, 체인/에이전트/RAG 구조를 구축
    • 챗봇, 질문 응답, 요약 등 대부분의 고급 기능 해당
  2. langchain-community
    • LangChain 공식 확장 라이브러리.
    • 다양한 도구들(PDF 로더, 벡터스토어, 웹 크롤러 등)
    • 예: PyPDFLoader, WikipediaLoader, Chroma
  3. pypdf
    • PDF 파일을 다루기 위한 기본 Python 라이브러리.
    • LangChain 내부에서 PyPDFLoader 쓸 때, pypdf가 PDF 파싱을 담당

 

 

 

 

 

 

 

 

 

📖PDF 파싱

 

본 프로젝트에서 활용하는 민법 표준판례연구는 PDF 형식이다.

따라서 PDF를 불러와서 전처리하는 과정이 필요하다.

 

 

 

from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter


FILE_PATH = "230425민법표준판례.pdf"  # 파일 경로 (현재 위치 기준)

loader = PyPDFLoader(FILE_PATH)
docs = loader.load()


print(f"총 {len(docs)}개의 청크가 생성됨.\n")

# 앞의 3개 청크만 출력
for i, doc in enumerate(docs[:3]):
    print(f"[청크 {i+1}] (페이지: {doc.metadata.get('page', '알 수 없음')})")
    print(doc.page_content[:500])  # 길면 500자까지만 출력
    print("-" * 80)

 

 

 

결과

총 659개의 청크가 생성됨.

[청크 1] (페이지: 0)
2023년도  법학전문대학원협의회 
연구용역 과제 보고서
변호사시험의 자격시험을 위한 
민법표준판례연구
책임연구원:박동진 교수(연세대학교 법학전문대학원)
공동연구원:최우진 교수(고려대학교 법학전문대학원)
           이동진 교수(서울대학교 법학전문대학원 )
           서종희 교수(연세대학교 법학전문대학원 )
--------------------------------------------------------------------------------
[청크 2] (페이지: 1)

--------------------------------------------------------------------------------
[청크 3] (페이지: 2)
제  1  편   총   칙
  제 1 장  통  칙 ··········································································································  3
  제 2 장  인 ·················································································································  13
    제  1  절   능  력 ········································································································  13
    제 2 절  부재와 실종 ·····················································································
--------------------------------------------------------------------------------

 

 

 

 

 

 

 

 

 

 

 

 

📊데이터 전처리 및 분할

 

content 문서를 적절히 분할하여 RAG로 활용해야한다.

 

LLM이 읽을때 헷갈리지 않게 데이터를 가공할 것이고, 판례 기준으로 분할할 것이다.

 

잡다한 텍스트, 뉴스, FAQ 등은 글자 수 기반 분할만 사용해도 되지만

법률 문서같은 자료는 논리 단위 기반 분할을 선호한다.

판례 중간에 잘라버리면 문맥이 끊겨서 검색/응답 품질이 떨어지기 때문이다.

 

 

 

전처리 1. 불필요한 문구 제거

변호사시험의 자격시험을 위한 민법표준판례연구

라는 머릿말 문구가 페이지마다 반복됨.

 

→  특정 키워드 ("변호사시험의 자격시험을 위한 민법표준판례연구") 전처리 단계에서 제거

 

re.sub(r"변호사시험의 자격시험을 위한 민법표준판례연구", "", raw_text)

 

 

 

 

 

전처리 2. 페이지 번호 제거

ex)

3
4
5

➡ 줄에 숫자만 있는 페이지 번호들
➡ 의미 없고 LLM이 헷갈리게만 함

→ 해결책: 숫자만 있는 줄 제거

 

re.sub(r"\n\s*\d+\s*\n", "\n", raw_text) # 페이지 번호 제거(줄바꿈 사이 숫자만 남아있는 경우)

 

 

 

 

분할 1. 판례별로 분할

 

텍스트 출력 시 

\n 숫자. \n 형태의 경우

1.
 민법의 법원:관습법 (1)
...
<판례선정이유>
...
2.
 민법의 법원:관습법 (2)

 

pdf로 봐도 번호로 시작하는것을 알 수 있다.

 

 

➡ 1., 2., 3. 이런 번호는 새로운 판례가 시작된다는 신호
  해결책: \n숫자.\n 을 기준으로 텍스트를 나누어 각 판례를 하나의 chunk로 만들자.

 

re.split(r"\n\d+\.\s*\n", raw_text) #숫자+마침표 형태 + 그 앞뒤가 줄바꿈인 경우 기준으로 청크 분할

 

 

 

 

 

 

전체코드

from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
import re


FILE_PATH = "230425민법표준판례.pdf"  # 파일 경로 (현재 위치 기준)

loader = PyPDFLoader(FILE_PATH)
docs = loader.load()

# 모든 페이지를 하나의 문자열로 합침
raw_text = "\n".join([doc.page_content for doc in docs])


# 전처리 함수
def preprocess_raw_text(raw_text: str) -> list[str]:
    raw_text = re.sub(r"변호사시험의 자격시험을 위한 민법표준판례연구", "", raw_text)
    raw_text = re.sub(r"\n\s*\d+\s*\n", "\n", raw_text) # 페이지 번호 제거(줄바꿈 사이 숫자만 남아있는 경우)
    chunks = re.split(r"\n\d+\.\s*\n", raw_text) #숫자+마침표 형태 + 그 앞뒤가 줄바꿈인 경우 기준으로 청크 분할
    return chunks

# 전처리
clean_chunks = preprocess_raw_text(raw_text)

print(f"총 {len(clean_chunks)}개의 판례 단위로 분할됨.")

for i, chunk in enumerate(clean_chunks[:5]):
    print(f"[청크 {i+1}]")
    print(chunk[:50])
    print("-" * 80)
    
# 마지막 청크도 출력
print(f"[마지막 청크 {len(clean_chunks)}]")
print(clean_chunks[-1][:500])
print("-" * 80)

 

 

 

 

결과

총 931개의 판례 단위로 분할됨.
[청크 1]
2023년도  법학전문대학원협의회 
연구용역 과제 보고서
변호사시험의 자격시험을 위한 
민법표준판례연구
책임연구원:박동진 교수(연세대학교 법학전문대학원)
공동연구원:최우진 교수(고려대학교 법학전문대학원)
           이동진 교수(서울대학교 법학전문대학원 )
           서종희 교수(연세대학교 법학전문대학원 )

제  1  편   총   칙
  제 1 장  통  칙 ··········································································································  3
  제 2 장  인 ·················································································································  13
    제  1  절   능  력 ·····························
--------------------------------------------------------------------------------
[청크 2]
 민법의 법원:관습법 (1)
(대법원 2003. 7. 24. 선고 2001다48781 전원합의체 판결)
<쟁점>
  제정민법이 시행되기 전에 존재하던 ‘상속회복청구권은 상속이 개시된 날부터 20년이 경과하면
소멸한다’는 관습에 관습법으로의 효력을 인정할 수 있는지 여부
<판결요지>
  [1] 사회의 거듭된 관행으로 생성한 어떤 사회생활규범이 법적 규범으로 승인되기에 이르렀다고
하기 위하여는 그 사회생활규범은 헌법을 최상위 규범으로 하는 전체 법질서에 반하지 아니하는
것으로서 정당성과 합리성이 있다고 인정될 수 있는 것이어야 하고, 그렇지 아니한 사회생활규범은
비록 그것이 사회의 거듭된 관행으로 생성된 것이라고 할지라도 이를 법적 규범으로 삼아 관습법
으로서의 효력을 인정할 수 없는바, 제정 민법이 시행되기 전에 존재하던 관습 중 “ 상속회복청구권
은 상속이 개시된 날부터 20년이 경과하면 소멸한다.”는 내용의 관습은 이를 적용하게 되면 20 년
의 경과 후에 상속권침해가
--------------------------------------------------------------------------------
[청크 3]
 민법의 법원:관습법 (2)
(대법원 2005. 7. 21. 선고 2002다1178 전원합의체 판결 )
<쟁점>
  종중 구성원의 자격을 성년 남자만으로 제한하는 관습법의 효력 여부
<판결요지>
  [1] 관습법이란 사회의 거듭된 관행으로 생성한 사회생활규범이 사회의 법적 확신과 인식에 의하
여 법적 규범으로 승인·강행되기에 이른 것을 말하고, 그러한 관습법은 법원(法源)으로서 법령에
저촉되지 아니하는 한 법칙으로서의 효력이 있는 것이고, 또 사회의 거듭된 관행으로 생성한 어떤
사회생활규범이 법적 규범으로 승인되기에 이르렀다고 하기 위하여는 헌법을 최상위 규범으로 하
는 전체 법질서에 반하지 아니하는 것으로서 정당성과 합리성이 있다고 인정될 수 있는 것이어야
하고, 그렇지 아니한 사회생활규범은 비록 그것이 사회의 거듭된 관행으로 생성된 것이라고 할지라
도 이를 법적 규범으로 삼아 관습법으로서의 효력을 인정할 수 없다 .
  [2] 사회의 거듭된 관행으로 생성된 사회생활규범이 관
--------------------------------------------------------------------------------
[청크 4]
 민법의 법원: 헌법
(대법원 2011. 1. 27. 선고 2009다19864 판결 )
<쟁점>
  사인에 의한 평등권 침해가 불법행위를 구성하는 형태
<판결요지>
  헌법상의 기본권은 제1차적으로 개인의 자유로운 영역을 공권력의 침해로부터 보호하기 위한 방
어적 권리이지만 다른 한편으로 헌법의 기본적인 결단인 객관적인 가치질서를 구체화한 것으로서 ,
사법을 포함한 모든 법 영역에 그 영향을 미치는 것이므로 사인간의 사적인 법률관계도 헌법상의
기본권 규정에 적합하게 규율되어야 한다. 다만 기본권 규정은 그 성질상 사법관계에 직접 적용될
수 있는 예외적인 것을 제외하고는 사 법상의 일반원칙을 규정한 제2조, 제103조, 제750조, 제 751
조 등의 내용을 형성하고 그 해석 기준이 되어 간접적으로 사법관계에 효력을 미치게 된다. 헌법
제11조는 “모든 국민은 법 앞에 평등하다. 누구든지 성별·종교 또는 사회적 신분에 의하여 정치
적·경제적·사회적·문화적 생활의 모든 영역에 있
--------------------------------------------------------------------------------
[청크 5]
 신의성실의 원칙:사정변경의 원칙 (1)
(대법원 2007. 3. 29. 선고 2004다31302 판결 )
<쟁점>
  사정변경을 이유로 계약해제가 인정되는 경우
<판결요지>
  이른바 사정변경으로 인한 계약해제는, 계약성립 당시 당사자가 예견할 수 없었던 현저한 사정
의 변경이 발생하였고 그러한 사정의 변경이 해제권을 취득하는 당사자에게 책임 없는 사유로 생
긴 것으로서, 계약내용대로의 구속력을 인정한다면 신의칙에 현저히 반하는 결과가 생기는 경우에
계약준수 원칙의 예외로서 인정되는 것이고, 여기에서 말하는 사정이라 함은 계약의 기초가 되었던
객관적인 사정으로서, 일방당사자의 주관적 또는 개인적인 사정을 의미하는 것은 아니다. 또한, 계
약의 성립에 기초가 되지 아니한 사정이 그 후 변경되어 일방당사자가 계약 당시 의도한 계약목적
을 달성할 수 없게 됨으로써 손해를 입게 되었다 하더라도 특별한 사정이 없는 한 그 계약내용의
효력을 그대로 유지하는 것이 신의칙에 반한다고 볼
--------------------------------------------------------------------------------
[마지막 청크 931]
  유류분을 포함한 상속포기약정의 효력
(대법원 1998. 7. 24. 선고 98다9021 판결 )
<쟁점>
  유류분을 포함한 상속포기의 약정만으로 상속권 행사를 신의칙 위반으로 볼 수 있는지 여부
<판결요지>
  [1] 유류분을 포함한 상속의 포기는 상속이 개시된 후 일정한 기간 내에만 가능하고 가정법원에
신고하는 등 일정한 절차와 방식을 따라야만 그 효력이 있으므로, 상속개시 전에 한 상속포기약정
은 그와 같은 절차와 방식에 따르지 아니한 것으로 효력이 없다 .
  [2] 상속인 중의 1인이 피상속인의 생존시에 피상속인에 대하여 상속을 포기하기로 약정하였다
고 하더라도, 상속개시 후 민법이 정하는 절차와 방식에 따라 상속포기를 하지 아니한 이상, 상속
개시 후에 자신의 상속권을 주장하는 것은 정당한 권리행사로서 권리남용에 해당하거나 또는 신의
칙에 반하는 권리의 행사라고 할 수 없다 .
<판례선정이유>
  상속개시 전에 유류분을 포함한 상속 포기의 약정이 무효임은 물론이며
--------------------------------------------------------------------------------

 

목차를 포함해 가장 마지막 판례인 930번까지 총 931개의 청크로 분리되었다.

전체 청크 수와 내용을 확인해 본 결과, 판례 단위로 정확히 분리되었고 전처리가 정상적으로 이루어진 것을 확인할 수 있었다.

 

마지막 판례

 

 

 

 

 

 

 

 

 

 

 

🛏️Embedding

이번 단계에서는 LangChain과 FAISS를 이용해 전처리된 텍스트 청크를 임베딩하고, 검색을 위한 벡터 DB로 저장할 것이다.

 

 

 

 

1. 라이브러리 설치

pip install langchain faiss-cpu sentence-transformers
pip install -U langchain-huggingface

 

 

 

 

2. 청크를 Document로 감싸야 한다.

📄 청크를 Document 형태로 감싸는 이유

LangChain의 벡터 검색 모듈(FAISS.from_documents() 등)은 단순 문자열 리스트가 아니라 Document 객체 리스트를 인자로 받는다.
Document는 텍스트(page_content)와 함께 페이지 번호, 출처 등 메타데이터(metadata)도 담을 수 있는 구조이를 통해 나중에 검색 결과에 "몇 번째 판례에서 나왔는지" 등도 함께 보여줄 수 있어 유용하다.

from langchain.schema import Document

Document(
    page_content="실제 텍스트 내용",
    metadata={"page": 123}
)​

 

 

# 2. LangChain의 Document 포맷으로 감싸기
documents = [Document(page_content=chunk) for chunk in clean_chunks]

 

 

 

 

 

3. 임베딩

여러 임베딩 모델이 있는데 이중 프로젝트의 특성에 따라 적합한것을 선정해야 한다.

 

나의 경우

1. 한글 성능이 준수할 것

2. 비교적 가벼운 모델

3. 무료로 사용 가능한 모델

이 세가지를 기준으로 두었다.

 

 

여러 임베딩 모델 성능이 비교되어있는 다음 자료를 참고하였다.
한글 텍스트 임베딩 모델 리더보드

 

 

최종적으로 bge-m3-korean  , text-embedding-3-small , intfloat/multilingual-e5-small 세가지 모델중 고민하였으나,

 

bge-m3-korean 는 한국어 전용 튜닝 모델이라 한국어 문맥 이해력이 최상이나, 1024차원으로, 모델이 무겁고 느리다는 단점이 있었다.

text-embedding-3-small도 무난하게 많이 사용하는 것 같았으나, 한국어 RAG에는 적합하지 않다고 판단되었다.

따라서 다국어 성능이 검증된  intfloat/multilingual-e5-small이 가장 효율적이라고 판단되었다. 384차원으로 경량에 GPU없이도 구동이 가능하다. 일단은 이걸로 하고, 나중에 임베딩 모델 몇개로 성능 비교하면서 리팩토링 해봐도 좋을 것 같다.

 

# 3. HuggingFace 임베딩 모델 설정
embedding_model = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-small")

 

 

 

 

 

4. 벡터 저장소 생성 및 저장

전처리한 판례 텍스트를 Document 형태로 감싼 뒤, FAISS를 사용해 벡터 저장소를 생성
생성된 벡터 DB는 로컬에 저장하여 추후 검색 시 재사용할 수 있다.

 

# 4. FAISS 벡터스토어 생성 전처리된 문서(Document)들을 임베딩해서, 검색이 가능한 벡터 데이터베이스(FAISS 벡터스토어)를 생성하는 과정
vectorstore = FAISS.from_documents(documents, embedding_model)

# 5. 로컬에 벡터 DB 저장
vectorstore.save_local("faiss_multilingual_e5_db")

 

 

 

함수설명 : 

FAISS.from_documents(...)

  • LangChain의 FAISS 래퍼 함수
  • documents를 임베딩 모델로 벡터화한 다음, 그걸 기반으로 FAISS 인덱스를 생성
  • 이 인덱스는 유사 문서 검색이 가능하게 만든다.

-> 문서들을 벡터로 바꾸고, 검색 가능한 형태(FAISS)로 만드는 과정

 

 

 

 

 

5. 최종 코드

 

from langchain_huggingface import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document 

....

# 1. 전처리
clean_chunks = preprocess_raw_text(raw_text)


# 2. Document 포맷으로 감싸기
documents = [Document(page_content=chunk) for chunk in clean_chunks]


# 3. HuggingFace 임베딩 모델 설정
embedding_model = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-small")

# 4. FAISS 벡터스토어 생성 전처리된 문서(Document)들을 임베딩해서, 검색이 가능한 벡터 데이터베이스(FAISS 벡터스토어)를 생성하는 과정
vectorstore = FAISS.from_documents(documents, embedding_model)

# 5. 로컬에 벡터 DB 저장
vectorstore.save_local("faiss_multilingual_e5_db")

 

 

이 과정을 거치면 RAG 기반 질의응답을 위한 벡터 검색 인프라가 완성된다.
이제 질문에 대해 의미적으로 가장 유사한 판례 내용을 효율적으로 찾아올 수 있다.

 

 

 

 

 

 

 

 

 

 

🔎Retriever

 

Retriever는 사용자의 질문(query)에 가장 관련 있는 문서들을 벡터 DB에서 찾아주는 역할을 한다.

 

LangChain에서는 .as_retriever() 메서드를 통해 Retriever 객체를 만들 수 있고,

이를 LangChain의 Chain에 연결하여 문서 검색 + 답변 생성을 자동화된 흐름으로 구성할 수 있다.

 

지금은 Chain을 쓰기 전 단계로, FAISS 벡터스토어의 similarity_search_with_score() 메서드를 통해 간단하게 유사도가 높은 문서를 검색해보자.

 

 

  • similarity_search_with_score(query, k=3)는 단순히 유사 문서와 유사도 점수를 함께 반환하는 방법
  • .as_retriever()는 LangChain 체인과 함께 쓸 수 있는 표준화된 인터페이스(Runnable 객체)로 변환해주는 도구

 

 

# 벡터 DB 로드
new_vectorstore = FAISS.load_local("faiss_multilingual_e5_db", embedding_model)


#  검색할 질문 입력
query = "임대차 계약에서 연체된 차임을 상계할 수 있는가?"


#  유사한 청크 상위 3개 검색 (with 유사도 점수 포함)
results = vectorstore.similarity_search_with_score(query, k=3)

# 4. 결과 출력
for i, (doc, score) in enumerate(results):
    print(f"\n🔍 Top {i+1} | 유사도 점수: {round(score, .4f)}")
    print(doc.page_content[:500])  # 앞부분만 출력
    print("-" * 80)

 

 

 

 

유사도 검색 결과

🔍 Top 1 | 유사도 점수: 0.2019
  임차보증금과 연체차임
(대법원 2016. 11. 25. 선고 2016다211309 판결 )
<쟁점>
  임대차계약 종료 전에 별도의 의사표시 없이 연체차임이 임대차보증금에서 당연히 공제되는지
여부 및 임차인이 임대차보증금의 존재를 이유로 차임 지급을 거절할 수 있는지의 여부
<판결요지>
  임대인에게 임대차보증금이 교부되어 있더라도 임대인은 임대차관계가 계속되고 있는 동안에는
임대차보증금에서 연체차임을 충당할 것인지를 자유로이 선택할 수 있다. 따라서 임대차계약 종료
전에는 공제 등 별도의 의사표시 없이 연체차임이 임대차보증금에서 당연히 공제되는 것은 아니고 ,
임차인도 임대차보증금의 존재를 이유로 차임의 지급을 거절할 수 없다 .
<판례선정이유>
  임대차계약이 종료하기 전에는 별도의 의사표시 없이 연체차임이 임대차보증금에서 당연히 공제
되지 않으며, 더 나아가 임차보증금의 존재를 이유로 임차인이 차임지급을 거절할 수 없다는 점을
밝힌 판결
--------------------------------------------------------------------------------

🔍 Top 2 | 유사도 점수: 0.2041
 상가임차권자의 차임연체와 임대인의 계약갱신 거부
(대법원 2021. 5. 13. 선고 2020다255429 판결 )
<쟁점>
  [1] 상가건물 임대차보호법의 적용을 받는 상가건물의 임대차기간 중 어느 때라도 차임이 3 기분
에 달하도록 연체된 사실이 있는 경우, 임대인이 임차인의 계약갱신 요구를 거부할 수 있는지 여부
  [2] 차임에 대한 부가가치세 상당액을 임차인이 부담하기로 하는 약정이 있는 경우, 임대차계약
종료 후 계속점유로 인한 차임 상당 부당이득에 대한 부가가치세 상당액도 임차인이 부담하는지
여부
<판결요지>
  [1] 상가건물 임대차보호법(이하 ‘상가임대차법’이라고 한다) 제10조의8은 임대인이 차임연체를
이유로 계약을 해지할 수 있는 요건을 ‘차임연체액이 3기의 차임액에 달하는 때’라고 규정하였다 .
반면 임대인이 임대차기간 만료를 앞두고 임차인의 계약갱신 요구를 거부할 수 있는 사유에 관해
서는 ‘3기의 차임액에 해당하는 금액에 이르도록 차임을 연체한 사
--------------------------------------------------------------------------------

🔍 Top 3 | 유사도 점수: 0.2249
  임차보증금의 법적 성질
(대법원 2005. 9. 28. 선고 2005다8323, 8330 판결 )
<쟁점>
  ① 임대차계약에 있어 임대차보증금이 담보하는 채무가 임대차관계 종료 후 목적물 반환시 별도
의 의사표시 없이 임대차보증금에서 당연히 공제되는지 여부
  ② 임대차보증금에서 공제될 차임채권 등의 발생원인에 관한 주장·증명책임의 소재(=임대인) 및
제3편 제 2 장  계  약
그 발생한 채권의 소멸에 관한 주장·증명책임의 소재(=임차인 )
<판결요지>
  [1] 임대차계약에 있어 임대차보증금은 임대차계약 종료 후 목적물을 임대인에게 명도할 때까지
발생하는, 임대차에 따른 임차인의 모든 채무를 담보하는 것으로서, 그 피담보채무 상당액은 임대
차관계의 종료 후 목적물이 반환될 때에, 특별한 사정이 없는 한, 별도의 의사표시 없이 보증금에
서 당연히 공제되는 것이므로, 임대인은 임대차보증금에서 그 피담보채무를 공제한 나머지만을 임
차인에게 반환할 의무가 있다 .
--------------------------------------------------------------------------------

 

 

참고로 

similarity_search_with_score()는

정확히는 유사도보다는 Euclidean Distance(벡터 공간에서 두 점 사이의 직선 거리)를 나타내기 때문에

값이 작을수록 유사도가 높은것이 맞다.

 

 

참고 :  Euclidean Distance vs Cosine Similarity

 

 

 

 

 

 

 

 

 

 

 

➰Chain

 

 

지금까지 Chain으로 묶기 전 전처리 + 벡터DB 구축 + 유사도 검색까지 완성하였다.

 

여기에 LangChain의 Chain을 만들고 llm, retriever, prompt 등을 붙여 하나의 워크플로우로 만들 수 있다.

그럼 사용자가 질문만 하면 검색 + LLM 응답까지 자동으로 이어주는 RAG Pipeline이 완성된다.

 

 

LangChain의 체인의 내부 순서

 
(질문 입력)
     ↓
[Retriever] ← 벡터 DB + 임베딩 모델 결과물 기반
     ↓
[LLM (GPT 등)] → 답변 생성
     ↓
(결과 출력)
 

 

 

LangChian의 핵심 구성요소들

LLM OpenAI, Claude, HuggingFace 등 모델
PromptTemplate 프롬프트 포맷 관리
Document 텍스트 + 메타데이터 구조
VectorStore FAISS, Chroma 등 벡터 검색 DB
Retriever VectorStore에서 검색할 수 있는 인터페이스
Chain 위의 것들을 묶어서 파이프라인처럼 처리

 

 

 

gpt3.5 버전, 프롬포트, retriever를 연결하여 rag chain을 만들어보자

 

 

참고로,, gpt를 호출하려고 하니 한도초과 에러메세지가 떳다.

예전에는 3.5는 무료였던 것 같은데 open ai는 점점 부자가 될라나 보다.......

눈물을 머금고 10달러를 결제했다.

4달라,,,,

 

 

10,000자 입력 / 5,000자 출력 기준 요금은 다음과 같다:
• GPT-3.5 Turbo: 약 6원
• GPT-4.0: 약 200원

 

 

 

 

 

 

 

라이브러리 설치

pip install langchain-openai

 

 

# --- 3. 벡터 DB 로드 및 retriever 변환 ---
vectorstore = FAISS.load_local(
    "faiss_multilingual_e5_db", embedding_model, allow_dangerous_deserialization=True
)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

# --- 4. Prompt 구성 ---
prompt = PromptTemplate.from_template(
"""
당신은 대한민국 민법 분야의 법률 전문가입니다.

다음 판례 내용(Context)을 철저히 참고하여 사용자 질문(Question)에 정확하고 간결하게 답변하세요.

- 답변은 반드시 Context에 근거하여 작성하십시오.  
- Context에 명시적으로 기재되지 않은 법리나 추론은 포함하지 마세요.
- 질문과 관련된 법리는 판례가 인정한 범위 내에서만 서술하세요.
- 답변 마지막에 참고한 판례 정보를 다음 형식으로 포함해 주세요: (참고 판례: 대법원 [선고일] 선고 [사건번호] 판결)


    # Question:
    {question}

    # Context:
    {context}

    # Answer:
    """
)

# --- 5. LLM 설정 ---
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0, api_key=MY_API_KEY)

# --- 6. LangChain 구성 ---
chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)

# --- 7. 예시 질의 실행 ---
question = "미성년자가 부모 동의 없이 신용카드로 물건을 샀는데, 나중에 계약을 취소할 수 있나요?"
print("# 질문: \n" + question)

# 참고 판례 출력
for i, doc in enumerate(retriever.invoke(question)):
    print(f"\n\n# 참고 판례 {(i+1)}")
    print(doc.page_content[:700])

# 최종 답변 출력
print("\n\n# GPT-3.5 답변")
print(chain.invoke(question))

 

 

 

 

답변

# 질문: 
미성년자가 부모 동의 없이 신용카드로 물건을 샀는데, 나중에 계약을 취소할 수 있나요?


# 참고 판례 1
 미성년자의 행위능력 (1)
(대법원 2007. 11. 16. 선고 2005다 71659, 71666,  71673 판결 )
<쟁점>
  법정대리인의 동의 없이 신용구매계약을 체결한 미성년자가 그 동의 없음을 이유로 위 계약을
취소하는 것이 신의칙에 위배되는지 여부
<판결요지>
  행위무능력자 제도는 사적자치의 원칙이라는 민법의 기본이념, 특히, 자기책임 원칙의 구현을 가
능케 하는 도구로서 인정되는 것이고, 거래의 안전을 희생시키더라도 행위무능력자를 보호하고자
함에 근본적인 입법 취지가 있는바, 행위무능력자 제도의 이러한 성격과 입법 취지 등에 비추어
볼 때, 신용카드 가맹점이 미성년자와 신용구매계약을 체결할 당시 향후 그 미성년자가 법정대리인
의 동의가 없었음을 들어 스스로 위 계약을 취소하지는 않으리라고 신뢰하였다 하더라도 그 신뢰
가 객관적으로 정당한 것이라고 할 수 있을지 의문일 뿐만 아니라, 그 미성년자가 가맹점의 이러
한 신뢰에 반하여 취소권을 행사하는 것이 정의관념에 비추어 용인될 수 없는 정도의 상태라고 보
기도 어려우며, 미성년자의 법률행위에 법정대리인의 동의를 요하도록 하는 것은 강행규정인데, 위
제1편 제 2 장  인
규정에 반하여 이루어진 신용구매계약을 미성년자 스스로 취소하는 것을 신의칙 위반을 이유로 배
척한다면, 이는 오히려 위 규정에 의해 배제하려는 결과를 실현시키는 셈이 되어 미성년자 제도의


# 참고 판례 2
  이혼의 효과:자녀의 친권자 및 양육권자의 결정
(대법원 2012. 4. 13. 선고 2011므4719 판결 )
<쟁점>
  [1] 부모가 이혼하는 경우 부모 중에서 미성년인 자의 친권을 가지는 사람 및 양육자를 정할 때
에 고려하여야 할 요소
  [2] 이혼 후 부모와 자녀의 관계에서 친권과 양육권이 항상 동일인에게 귀속되어야 하는지 여부
및 일정한 조건을 충족하는 경우 이혼 후 자에 대한 양육권이 부모 중 어느 일방에, 친권이 다른
일방에 또는 부모에 공동으로 귀속되는 것으로 정할 수 있는지 여부
<판결요지>
  [1] 자의 양육을 포함한 친권은 부모의 권리이자 의무로서 미성년인 자의 복지에 직접적인 영향
을 미친다. 그러므로 부모가 이혼하는 경우에 부모 중에서 미성년인 자의 친권을 가지는 사람 및
양육자를 정함에 있어서는, 미성년인 자의 성별과 연령, 그에 대한 부모의 애정과 양육의사의 유무
는 물론, 양육에 필요한 경제적 능력의 유무, 부 또는 모와 미성년인 자 사이의 친밀도, 미성년인
자의 의사 등의 모든 요소를 종합적으로 고려하여 미성년인 자의 성장과 복지에 가장 도움이 되고
적합한 방향으로 판단하여야 한다 .
  [2] 제837조, 제909조 제4항, 가사소송법 제2 조 제1항 제2호 나목의 3) 및 5) 등이 부부의 이
혼 후 그 자의 친권자와 그 양육에 관한 사항을 각기 다른 조항에서 규정하고 있는


# 참고 판례 3
  제921조의 이해상반행위 (2)
(대법원 2001. 6. 29. 선고 2001다28299 판결 )
<쟁점>
  이해상반행위에 해당하는 공동상속인인 친권자와 미성년인 수인의 자 사이의 상속재산 분할협의
가 효력을 인정받기 위한 방법
<판결요지>
  상속재산에 대하여 그 소유의 범위를 정하는 내용의 공동상속재산 분할협의는 그 행위의 객관적
성질상 상속인 상호간의 이해의 대립이 생길 우려 가 있는 제921조 소정의 이해상반되는 행위에 해
당하므로 공동상속인인 친권자와 미성년인 수인의 자 사이에 상속재산 분할협의를 하게 되는 경우
에는 미성년자 각자마다 특별대리인을 선임하여 그 각 특별대리인이 각 미성년자인 자를 대리하여
상속재산분할의 협의를 하여야 하고, 만약 친권자가 수인의 미성년자의 법정대리인으로서 상속재산
분할협의를 한 것이라면 이는 제 921조에 위반된 것으로서 이러한 대리행위에 의하여 성립된 상속
재산 분할협의는 적법한 추인이 없는 한 무효라고 할 것이다 .
<판례선정이유>
  이해상반행위에 해당하는 공동상속인인 친권자와 미성년인 수인의 자 사이의 상속재산 분할협의
가 효력을 인정받기 위한 방법을 밝힌 판결
제4편 제4장 부모와 자
제 3 관  친권의 상실, 일시 정지 및 일부 제한


# GPT-3.5 답변
미성년자가 부모 동의 없이 신용카드로 물건을 샀다고 해도, 나중에 계약을 취소할 수 없습니다. 
법정대리인의 동의 없이 법률행위를 한 미성년자가 이후 그 동의 없음을 이유로 계약을 취소하는 것은 신의칙에 위배되지 않는다는 판결이 있습니다. 
따라서, 미성년자가 부모 동의 없이 신용카드로 물건을 샀 을 경우에도 계약을 취소할 수 없습니다. 
(참고 판례: 대법원 2007. 11. 16. 선고 2005다 71659, 71666, 71673 판결)

 

 

 

 

 

 

다음글
LangServe로 api화하기

MetaData, Chunking으로 효율성 높이기

 

 

 

 

 

 

 

 

 

 

 

참고자료

https://jinh0park.github.io/rag-law-project-1/

한글 텍스트 임베딩 모델 리더보드

법학전문대학원협의회

 

 

복사했습니다!