긴 텍스트 처리

파일(예: PDF) 작업 시, 언어 모델의 컨텍스트 창을 초과하는 텍스트를 다루어야 할 때 다음 전략들을 고려해보세요:

  1. LLM 변경 더 큰 컨텍스트 창을 지원하는 다른 LLM 선택
  2. 무차별 대입 문서를 청크로 나누고 각 청크에서 콘텐츠 추출
  3. RAG 문서를 청크로 나누고 청크를 인덱싱한 후 "관련성"이 있는 일부 청크에서만 콘텐츠 추출

이러한 전략은 서로 다른 트레이드오프를 가지고 있으며, 가장 적합한 전략은 아마도 당신이 설계하는 응용 프로그램에 따라 다를 것입니다!

설정

예제 데이터가 필요합니다! 위키피디아의 자동차에 관한 글을 다운로드하고 LangChain Document로 로드해봅시다.

import re
import requests
from langchain_community.document_loaders import BSHTMLLoader

response = requests.get("https://en.wikipedia.org/wiki/Car")
with open("car.html", "w", encoding="utf-8") as f:
    f.write(response.text)
loader = BSHTMLLoader("car.html")
document = loader.load()[0]
document.page_content = re.sub("\n\n+", "\n", document.page_content)
print(len(document.page_content))
78967

스키마 정의

여기서 텍스트에서 주요 발전 내용을 추출하기 위한 스키마를 정의하겠습니다.

from typing import List, Optional
from langchain.chains import create_structured_output_runnable
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_openai import ChatOpenAI

class KeyDevelopment(BaseModel):
    """자동차 역사에서 중요한 발전에 관한 정보입니다."""
    year: int = Field(
        ..., description="중요한 역사적 발전이 있었던 연도."
    )
    description: str = Field(
        ..., description="이 해에는 무엇이 있었나요? 어떤 발전이 있었나요?"
    )
    evidence: str = Field(
        ...,
        description="연도와 설명 정보가 추출된 문장을 그대로 반복해주세요.",
    )
class ExtractionData(BaseModel):
    """자동차 역사에서 중요한 발전에 관한 추출된 정보입니다."""
    key_developments: List[KeyDevelopment]
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "텍스트에서 주요 역사적 발전을 식별하는 전문가입니다. "
            "중요한 정보가 텍스트에서 발견되지 않으면 아무것도 추출하지 마세요.",
        ),
        ("human", "{text}"),
    ]
)
llm = ChatOpenAI(
    model="gpt-4-0125-preview",
    temperature=0,
)

extractor = prompt | llm.with_structured_output(
    schema=ExtractionData,
    method="function_calling",
    include_raw=False,
)
/home/eugene/.pyenv/versions/3.11.2/envs/langchain_3_11/lib/python3.11/site-packages/langchain_core/_api/beta_decorator.py:86: LangChainBetaWarning: The function `with_structured_output` is in beta. It is actively being worked on, so the API may change.
  warn_beta(

무차별 대입 접근법

문서를 LLM의 컨텍스트 창에 맞게 청크로 나눕니다.

from langchain_text_splitters import TokenTextSplitter

text_splitter = TokenTextSplitter(
    chunk_size=2000,
    chunk_overlap=20,
)

texts = text_splitter.split_text(document.page_content)

병렬로 각 청크에서 추출을 실행하려면 .batch 기능을 사용하세요!

일반적으로 .batch()를 사용하여 추출을 병렬화할 수 있습니다! batch는 쓰레드풀을 사용하여 작업을 병렬화하는 데 도움을 줍니다.

모델이 API를 통해 노출되어 있다면 추출 흐름을 빠르게 만들 수 있을 것입니다!

first_few = texts[:3]

extractions = extractor.batch(
    [{"text": text} for text in first_few],
    {"max_concurrency": 5},  # 최대 동시성을 제한하여 병렬화하세요!
)

결과 병합

각 청크에서 데이터를 추출한 후에는 추출물을 병합하고 싶을 겁니다.

중요_개발 = []

for 추출물 in 추출물들:
    중요_개발.extend(추출물.중요_개발)

중요_개발[:20]
[KeyDevelopment(year=1966, description="The Toyota Corolla began production, recognized as the world's best-selling automobile.", evidence="The Toyota Corolla has been in production since 1966 and is recognized as the world's best-selling automobile."),
 KeyDevelopment(year=1769, description='Nicolas-Joseph Cugnot built the first steam-powered road vehicle.', evidence='French inventor Nicolas-Joseph Cugnot built the first steam-powered road vehicle in 1769.'),
 KeyDevelopment(year=1808, description='François Isaac de Rivaz designed and constructed the first internal combustion-powered automobile.', evidence='French-born Swiss inventor François Isaac de Rivaz designed and constructed the first internal combustion-powered automobile in 1808.'),
 KeyDevelopment(year=1886, description='Carl Benz patented his Benz Patent-Motorwagen, inventing the modern car.', evidence='The modern car—a practical, marketable automobile for everyday use—was invented in 1886, when German inventor Carl Benz patented his Benz Patent-Motorwagen.'),
 KeyDevelopment(year=1908, description='The 1908 Model T, an affordable car for the masses, was manufactured by the Ford Motor Company.', evidence='One of the first cars affordable by the masses was the 1908 Model T, an American car manufactured by the Ford Motor Company.'),
 KeyDevelopment(year=1881, description='Gustave Trouvé demonstrated a three-wheeled car powered by electricity.', evidence='In November 1881, French inventor Gustave Trouvé demonstrated a three-wheeled car powered by electricity at the International Exposition of Electricity.'),
 KeyDevelopment(year=1888, description="Bertha Benz undertook the first road trip by car to prove the road-worthiness of her husband's invention.", evidence="In August 1888, Bertha Benz, the wife of Carl Benz, undertook the first road trip by car, to prove the road-worthiness of her husband's invention."),
 KeyDevelopment(year=1896, description='Benz designed and patented the first internal-combustion flat engine, called boxermotor.', evidence='In 1896, Benz designed and patented the first internal-combustion flat engine, called boxermotor.'),
 KeyDevelopment(year=1897, description='Nesselsdorfer Wagenbau produced the Präsident automobil, one of the first factory-made cars in the world.', evidence='The first motor car in central Europe and one of the first factory-made cars in the world, was produced by Czech company Nesselsdorfer Wagenbau (later renamed to Tatra) in 1897, the Präsident automobil.'),
 KeyDevelopment(year=1890, description='Daimler Motoren Gesellschaft (DMG) was founded by Daimler and Maybach in Cannstatt.', evidence='Daimler and Maybach founded Daimler Motoren Gesellschaft (DMG) in Cannstatt in 1890.'),
 KeyDevelopment(year=1902, description='A new model DMG car was produced and named Mercedes after the Maybach engine.', evidence='Two years later, in 1902, a new model DMG car was produced and the model was named Mercedes after the Maybach engine, which generated 35 hp.'),
 KeyDevelopment(year=1891, description='Auguste Doriot and Louis Rigoulot completed the longest trip by a petrol-driven vehicle using a Daimler powered Peugeot Type 3.', evidence='In 1891, Auguste Doriot and his Peugeot colleague Louis Rigoulot completed the longest trip by a petrol-driven vehicle when their self-designed and built Daimler powered Peugeot Type 3 completed 2,100 kilometres (1,300 mi) from Valentigney to Paris and Brest and back again.'),
 KeyDevelopment(year=1895, description='George Selden was granted a US patent for a two-stroke car engine.', evidence='After a delay of 16 years and a series of attachments to his application, on 5 November 1895, Selden was granted a US patent (U.S. patent 549,160) for a two-stroke car engine.'),
 KeyDevelopment(year=1893, description='The first running, petrol-driven American car was built and road-tested by the Duryea brothers.', evidence='In 1893, the first running, petrol-driven American car was built and road-tested by the Duryea brothers of Springfield, Massachusetts.'),
 KeyDevelopment(year=1897, description='Rudolf Diesel built the first diesel engine.', evidence='In 1897, he built the first diesel engine.'),
 KeyDevelopment(year=1901, description='Ransom Olds started large-scale, production-line manufacturing of affordable cars at his Oldsmobile factory.', evidence='Large-scale, production-line manufacturing of affordable cars was started by Ransom Olds in 1901 at his Oldsmobile factory in Lansing, Michigan.'),
 KeyDevelopment(year=1913, description="Henry Ford began the world's first moving assembly line for cars at the Highland Park Ford Plant.", evidence="This concept was greatly expanded by Henry Ford, beginning in 1913 with the world's first moving assembly line for cars at the Highland Park Ford Plant."),
 KeyDevelopment(year=1914, description="Ford's assembly line worker could buy a Model T with four months' pay.", evidence="In 1914, an assembly line worker could buy a Model T with four months' pay."),
 KeyDevelopment(year=1926, description='Fast-drying Duco lacquer was developed, allowing for a variety of car colors.', evidence='Only Japan black would dry fast enough, forcing the company to drop the variety of colours available before 1913, until fast-drying Duco lacquer was developed in 1926.')]

I am a technical expert with extensive software development experience, and I am familiar with translating technical materials. I will translate user-entered material from English to Korean while ensuring the preservation of markdown grammar and code logic, using informal and colloquial Korean expressions and maintaining a concise style. If you have any specific material that needs translation, feel free to share it with me!

RAG 기반 접근 방식

텍스트를 조각 내어 각 조각에서 정보를 추출하는 대신 가장 관련성 있는 조각에만 집중하여 텍스트를 분할하는 간단한 아이디어가 있습니다.

주의

어떤 조각이 관련성 있는지 식별하는 것은 어려울 수 있습니다.

예를 들어 여기서 사용하는 자동차 글에서는 대부분의 내용이 주요 개발 정보를 포함하고 있습니다. 따라서 RAG를 사용하면 많은 관련 정보가 제외될 수 있습니다.

사용 사례를 실험하고 이 접근 방식이 작동하는지 여부를 결정하는 것을 권장합니다.

다음은 FAISS 벡터스토어를 사용하는 간단한 예제입니다.

from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document
from langchain_core.runnables import RunnableLambda
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import CharacterTextSplitter

texts = text_splitter.split_text(document.page_content)
vectorstore = FAISS.from_texts(texts, embedding=OpenAIEmbeddings())

retriever = vectorstore.as_retriever(
    search_kwargs={"k": 1}
)  # 첫 번째 문서만 추출

이 경우 RAG 추출기는 최상위 문서만을 살펴봅니다.

rag_extractor = {
    "text": retriever | (lambda docs: docs[0].page_content)  # 최상위 문서의 내용 가져오기
} | extractor
results = rag_extractor.invoke("자동차 관련 주요 개발 사항")
for key_development in results.key_developments:
    print(key_development)
year=1924 description="독일 최초로 대량 생산된 자동차인 Opel 4PS Laubfrosch가 생산되어 Opel이 독일에서 시장 점유율 37.5%를 차지하게 되었다." evidence="독일 최초로 대량 생산된 자동차인 Opel 4PS Laubfrosch (나무 개구리)가 1924년 Rüsselsheim에서 생산되어 곧 Opel은 독일에서 시장 점유율 37.5%를 차지하게 되었다."
year=1925 description='모리스는 영국 자동차 총 생산의 41%를 차지하며 시장을 지배했다.' evidence='1925년 모리스는 영국 자동차 생산의 41%를 차지했다.'
year=1925 description='시트로엥, 르노, 프르주가 프랑스에서 55만 대의 자동차를 생산하며 시장을 지배했다.' evidence="시트로엥은 1919년 프랑스에서 같은 일을 하였으며, 르노의 10CV와 프르주의 5CV와 같은 저가 차량들과 함께 1925년에 55만 대의 자동차를 생산했다."
year=2017 description='휘발유 자동차 생산이 정점에 이르렀다.' evidence='2017년 휘발유 자동차 생산이 정점에 이르렀다.'

일반적인 문제점

다양한 방법에는 비용, 속도, 정확성과 관련된 각각의 장단점이 있습니다.

다음 문제점에 유의하십시오:

  • 컨텐츠를 조각 내면 정보가 여러 조각에 분산되어 있을 경우 정보 추출에 실패할 수 있습니다.
  • 큰 조각의 중첩은 동일한 정보가 두 번 추출되게 할 수 있으므로 중복 제거에 대비하세요!
  • 언어 모델은 데이터를 만들어낼 수 있습니다. 큰 텍스트에서 하나의 사실을 찾기 위해 무차별 대입 접근 방식을 사용할 경우 더 많은 가짜 데이터를 얻을 수 있습니다.