langchain / / 2024. 6. 27. 06:49

[langchain] 문맥 압축 검색기(ContextualCompressionRetriever)

검색할 때의 한 가지 문제점은 시스템에 저장되어 있는 내용이 검색하려는 내용과 무관한 텍스트가 포함되어 같이 검색이 된다는 것이다. 이 모든 결과로 LLM으로 요청을 할 때 원하는 결과를 못 얻을 수 있다는 것이다.

이러한 문제를 해결하기 위한 방법이 바로 컨텍스트 압축을 사용하는 것이다. 아이디어는 간단하다. 이전 예제(vector store retriever)처럼 검색된 문서를 즉시 LLM에 보내서 결과를 얻는 대신 쿼리의 컨텍스트를 사용하여 문서를 압축하여 관련정보만 반환하는 것이다. 여기서 '압축'은 개별 문서의 내용을 압축하는 것과 문서 전체를 필터링 하는 것을 모두 의미한다.

Vector store 기본검색을 해보자.

embeddings = OpenAIEmbeddings()
llm = ChatOpenAI()
vector_store = Chroma(persist_directory="chroma_emb", embedding_function=embeddings)

retriever = vector_store.as_retriever()

docs = retriever.invoke("박병호는 인천에서 몇 개의 홈런을 쳤나?")
print(f"####################### 기본 검색 결과 #################")
for i, doc in enumerate(docs):
    print(f"[문서 {i}] {doc.page_content.replace('\n', ' ')}")

아래는 기본 검색결과이다.

####################### 기본 검색 결과 #################
[문서 0] 박병호는 이번엔 원정에서 물오른 타격감을 이어가고자 한다. 이번 무대 역시 박병호에게 좋은 기억이 있는 인천이다. 박병호는 인천에서 통산 26개의 홈런을 쏘아 올렸다. 이는 원정 선수(인천 기준) 역대 3위에 해당하는 기록이다. 이범호 현 KIA 타이거즈 감독이 33개(132경기), KIA 외야수 최형우가 30개(132경기)를 쏘아 올린 가운데, 박병호와 강민호(삼성)가 이들의 뒤를 쫓고 있다.
[문서 1] 이적 후 5경기 홈런 세 방. 타자친화구장인 대구 삼성라이온즈파크에서 '홈런 자신감'을 되찾은 박병호(38·삼성 라이온즈)가 또 하나의 타자친화구장 인천 SSG랜더스필드에서도 홈런 감각을 이어갈 수 있을까.
[문서 2] 단연 박병호의 방망이에 눈길이 간다. 지난 28일 밤 KT 위즈와 일대일 트레이드를 통해 팀을 옮긴 박병호는 이적 후 5경기에서 타율 0.389(18타수 7안타)에 3홈런을 쏘아 올리며 8타점 4득점을 쓸어 담았다. 이적 전 44경기(선발 23경기)에서 타율 0.198(101타수 20안타) 3홈런 10타점 장타율 0.307로 부진한 모습과는 딴판이다. 타자친화구장 라팍에서 부활에 성공했다.
[문서 3] 삼성은 4일부터 6일까지 인천 SSG랜더스필드에서 SSG 랜더스와 2024 신한은행 SOL 뱅크 KBO리그 원정 3연전을 치른다. 삼성은 지난 주중 3연전에서 키움 히어로즈에 1승 2패 열세 시리즈(3연전 중 2패 이상)를 기록했으나, 주말 한화 이글스와의 3연전을 싹쓸이하며 4연승을 달리고 있다.

검색 결과를 보면 질문에 대한 내용을 포함하고 있지만 무관한 내용도 많이 포함되어 있음을 알 수 있다.

LLMChainExtractor으로 문맥 압축 추가하기

기본 검색기를 ContextualCompressionRetriever로 래핑한다. 처음 반환된 문서들을 반복적으로 검사하여 쿼리와 관련된 내용만 추출하는 LLMChainExtractor를 추가한다.

compressor = LLMChainExtractor.from_llm(llm)

compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor,
    base_retriever=retriever,
)
compressed_docs = compression_retriever.invoke("박병호는 인천에서 몇 개의 홈런을 쳤나?")
print(f"####################### 압축 검색 결과 #################")
for i, doc in enumerate(compressed_docs):
    print(f"[문서 {i}] {doc.page_content.replace('\n', ' ')}")

이를 실행하면 아래와 같다.

####################### 압축 검색 결과 #################
[문서 0] 인천에서 통산 26개의 홈런을 쏘아 올렸다.
[문서 1] 인천에서
[문서 2] 인천

참고)

LLMChainExtractor은 LLM을 호출한다.

LLMChainFilter

LLMChainFilter는 좀 더 단순하지만 더 강력한 압축기로 LLM 체인을 사용하여 처음 검색된 문서 중에서 어떤 문서를 걸러내고 어떤 문서를 반환할지 결정하며, 문서 내용을 조작하지 않는다.

_filter = LLMChainFilter.from_llm(llm)

compression_retriever = ContextualCompressionRetriever(
    base_compressor=_filter,
    base_retriever=retriever,
)
compressed_docs = compression_retriever.invoke("박병호는 인천에서 몇 개의 홈런을 쳤나?")
print(f"####################### LLMChainFilter 압축 검색 결과 #################")
for i, doc in enumerate(compressed_docs):
    print(f"[문서 {i}] {doc.page_content.replace('\n', ' ')}")

실행결과

####################### LLMChainFilter 압축 검색 결과 #################
[문서 0] 박병호는 이번엔 원정에서 물오른 타격감을 이어가고자 한다. 이번 무대 역시 박병호에게 좋은 기억이 있는 인천이다. 박병호는 인천에서 통산 26개의 홈런을 쏘아 올렸다. 이는 원정 선수(인천 기준) 역대 3위에 해당하는 기록이다. 이범호 현 KIA 타이거즈 감독이 33개(132경기), KIA 외야수 최형우가 30개(132경기)를 쏘아 올린 가운데, 박병호와 강민호(삼성)가 이들의 뒤를 쫓고 있다.
[문서 1] 이적 후 5경기 홈런 세 방. 타자친화구장인 대구 삼성라이온즈파크에서 '홈런 자신감'을 되찾은 박병호(38·삼성 라이온즈)가 또 하나의 타자친화구장 인천 SSG랜더스필드에서도 홈런 감각을 이어갈 수 있을까.
[문서 2] 단연 박병호의 방망이에 눈길이 간다. 지난 28일 밤 KT 위즈와 일대일 트레이드를 통해 팀을 옮긴 박병호는 이적 후 5경기에서 타율 0.389(18타수 7안타)에 3홈런을 쏘아 올리며 8타점 4득점을 쓸어 담았다. 이적 전 44경기(선발 23경기)에서 타율 0.198(101타수 20안타) 3홈런 10타점 장타율 0.307로 부진한 모습과는 딴판이다. 타자친화구장 라팍에서 부활에 성공했다.

참고)

LLMChainFilter는 LLM을 호출한다.

EmbeddingsFilter

검색된 각 문서에 대해 추가로 LLM 호출을 하는 것은 비용이 많이 들고 느리다. EmbeddingsFilter는 문서와 쿼리를 임베딩하고 쿼리와 충분히 유사한 임베딩을 가진 문서만 반환함으로써 더 저렴하고 빠른 옵션을 제공한다.

embeddings_filter = EmbeddingsFilter(
    embeddings=embeddings, similarity_threshold=0.86
)

compression_retriever = ContextualCompressionRetriever(
    base_compressor=embeddings_filter,
    base_retriever=retriever,
)

compressed_docs = compression_retriever.invoke("박병호는 인천에서 몇 개의 홈런을 쳤나?")
print(f"####################### EmbeddingsFilter 압축 검색 결과 #################")
for i, doc in enumerate(compressed_docs):
    print(f"[문서 {i}] {doc.page_content.replace('\n', ' ')}")

실행결과

####################### EmbeddingsFilter 압축 검색 결과 #################
[문서 0] 박병호는 이번엔 원정에서 물오른 타격감을 이어가고자 한다. 이번 무대 역시 박병호에게 좋은 기억이 있는 인천이다. 박병호는 인천에서 통산 26개의 홈런을 쏘아 올렸다. 이는 원정 선수(인천 기준) 역대 3위에 해당하는 기록이다. 이범호 현 KIA 타이거즈 감독이 33개(132경기), KIA 외야수 최형우가 30개(132경기)를 쏘아 올린 가운데, 박병호와 강민호(삼성)가 이들의 뒤를 쫓고 있다.
[문서 1] 이적 후 5경기 홈런 세 방. 타자친화구장인 대구 삼성라이온즈파크에서 '홈런 자신감'을 되찾은 박병호(38·삼성 라이온즈)가 또 하나의 타자친화구장 인천 SSG랜더스필드에서도 홈런 감각을 이어갈 수 있을까.
[문서 2] 단연 박병호의 방망이에 눈길이 간다. 지난 28일 밤 KT 위즈와 일대일 트레이드를 통해 팀을 옮긴 박병호는 이적 후 5경기에서 타율 0.389(18타수 7안타)에 3홈런을 쏘아 올리며 8타점 4득점을 쓸어 담았다. 이적 전 44경기(선발 23경기)에서 타율 0.198(101타수 20안타) 3홈런 10타점 장타율 0.307로 부진한 모습과는 딴판이다. 타자친화구장 라팍에서 부활에 성공했다.

참고) LLM을 호출하지 않는다.

압축기와 문서 변환기 파이프라인 생성

DocumentCompressorPipeline를 사용하면 여러 압축키를 순서대로 쉽게 결합할 수 있다.

TextSplitters는 문서를 분할하는데 사용되고, EmbeddingsRedundantFilter는 중복문서를 필터링하는데 사용된다.

아래에서는 문서를 더 작은 조각으로 분할한 다음, 중복된 문서를 제거하고, 쿼리와의 관련성을 기준으로 필터링하여 압축기 파이프라인을 만든다.

splitter = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=0)
redundant_filter = EmbeddingsRedundantFilter(embeddings=embeddings)
relevant_filter = EmbeddingsFilter(embeddings=embeddings, similarity_threshold=0.86)
pipeline_compressor = DocumentCompressorPipeline(
    transformers=[splitter, redundant_filter, relevant_filter]
)
compression_retriever = ContextualCompressionRetriever(
    base_compressor=pipeline_compressor,
    base_retriever=retriever,
)

compressed_docs = compression_retriever.invoke("박병호는 인천에서 몇 개의 홈런을 쳤나?")
print(f"####################### 검색 결과 #################")
for i, doc in enumerate(compressed_docs):
    # print(doc.metadata)
    print(f"[문서 {i}] {doc.page_content.replace('\n', ' ')}")

위의 내용에서 EmbeddingsFilter를 사용해서 유사도 임계값이 0.86 이상인 내용만 필터링한다.

검색 결과

####################### 검색 결과 #################
[문서 0] 박병호는 이번엔 원정에서 물오른 타격감을 이어가고자 한다. 이번 무대 역시 박병호에게 좋은 기억이 있는 인천이다. 박병호는 인천에서 통산 26개의 홈런을 쏘아 올렸다. 이는 원정 선수(인천 기준) 역대 3위에 해당하는 기록이다. 이범호 현 KIA 타이거즈 감독이 33개(132경기), KIA 외야수 최형우가 30개(132경기)를 쏘아 올린 가운데, 박병호와 강민호(삼성)가 이들의 뒤를 쫓고 있다.
[문서 1] 이적 후 5경기 홈런 세 방. 타자친화구장인 대구 삼성라이온즈파크에서 '홈런 자신감'을 되찾은 박병호(38·삼성 라이온즈)가 또 하나의 타자친화구장 인천 SSG랜더스필드에서도 홈런 감각을 이어갈 수 있을까.
[문서 2] 단연 박병호의 방망이에 눈길이 간다. 지난 28일 밤 KT 위즈와 일대일 트레이드를 통해 팀을 옮긴 박병호는 이적 후 5경기에서 타율 0.389(18타수 7안타)에 3홈런을 쏘아 올리며 8타점 4득점을 쓸어 담았다. 이적 전 44경기(선발 23경기)에서 타율 0.198(101타수 20안타) 3홈런 10타점 장타율 0.307로 부진한 모습과는 딴판이다. 타자친화구장 라팍에서 부활에 성공했다.

참고

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유