이것은 대화형 노트북입니다. 로컬에서 실행하거나 아래 링크를 사용할 수 있습니다:

Chain of Density를 사용한 요약

중요한 세부 정보를 보존하면서 복잡한 기술 문서를 요약하는 것은 어려운 작업입니다. Chain of Density(CoD) 요약 기술은 요약을 반복적으로 개선하여 더 간결하고 정보가 풍부하게 만드는 솔루션을 제공합니다. 이 가이드는 Weave를 사용하여 애플리케이션을 추적하고 평가하는 CoD를 구현하는 방법을 보여줍니다.

Chain of Density 요약이란 무엇인가요?

arXiv Chain of Density(CoD)는 점점 더 간결하고 정보가 풍부한 요약을 생성하는 반복적인 요약 기술입니다. 다음과 같이 작동합니다:
  1. 초기 요약으로 시작
  2. 핵심 정보를 보존하면서 요약을 더 간결하게 만들어 반복적으로 개선
  3. 각 반복마다 엔티티와 기술적 세부 사항의 밀도 증가
이 접근 방식은 특히 상세한 정보 보존이 중요한 과학 논문이나 기술 문서를 요약하는 데 유용합니다.

Weave를 사용하는 이유는 무엇인가요?

이 튜토리얼에서는 Weave를 사용하여 ArXiv 논문을 위한 Chain of Density 요약 파이프라인을 구현하고 평가할 것입니다. 다음을 배우게 됩니다:
  1. LLM 파이프라인 추적: Weave를 사용하여 요약 프로세스의 입력, 출력 및 중간 단계를 자동으로 기록하세요.
  2. LLM 출력 평가하기: Weave의 내장 도구를 사용하여 엄격하고 동등한 조건에서의 요약 평가를 생성하세요.
  3. 구성 가능한 작업 구축하기: Weave 작업을 요약 파이프라인의 다양한 부분에서 결합하고 재사용하세요.
  4. 원활한 통합: 최소한의 오버헤드로 기존 Python 코드에 Weave를 추가하세요.
이 튜토리얼을 마치면 모델 서빙, 평가 및 결과 추적을 위한 Weave의 기능을 활용하는 CoD 요약 파이프라인을 만들게 됩니다.

환경 설정하기

먼저, 환경을 설정하고 필요한 라이브러리를 가져오겠습니다:
!pip install -qU anthropic weave pydantic requests PyPDF2 set-env-colab-kaggle-dotenv
Anthropic API 키를 얻으려면:
  1. 다음에서 계정에 가입하세요 https://www.anthropic.com
  2. 계정 설정에서 API 섹션으로 이동하세요
  3. 새 API 키를 생성하세요
  4. API 키를 .env 파일에 안전하게 저장하세요
import io
import os
from datetime import datetime, timezone

import anthropic
import requests
from pydantic import BaseModel
from PyPDF2 import PdfReader
from set_env import set_env

import weave

set_env("WANDB_API_KEY")
set_env("ANTHROPIC_API_KEY")

weave.init("summarization-chain-of-density-cookbook")
anthropic_client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
우리는 실험을 추적하기 위해 Weave를 사용하고 텍스트 생성을 위해 Anthropic의 Claude 모델을 사용하고 있습니다. weave.init(<project name>) 호출은 요약 작업을 위한 새로운 Weave 프로젝트를 설정합니다.

ArxivPaper 모델 정의하기

간단한 ArxivPaper 클래스를 만들어 데이터를 표현하겠습니다:
# Define ArxivPaper model
class ArxivPaper(BaseModel):
    entry_id: str
    updated: datetime
    published: datetime
    title: str
    authors: list[str]
    summary: str
    pdf_url: str

# Create sample ArxivPaper
arxiv_paper = ArxivPaper(
    entry_id="http://arxiv.org/abs/2406.04744v1",
    updated=datetime(2024, 6, 7, 8, 43, 7, tzinfo=timezone.utc),
    published=datetime(2024, 6, 7, 8, 43, 7, tzinfo=timezone.utc),
    title="CRAG -- Comprehensive RAG Benchmark",
    authors=["Xiao Yang", "Kai Sun", "Hao Xin"],  # Truncated for brevity
    summary="Retrieval-Augmented Generation (RAG) has recently emerged as a promising solution...",  # Truncated
    pdf_url="https://arxiv.org/pdf/2406.04744",
)
이 클래스는 ArXiv 논문의 메타데이터와 내용을 캡슐화하며, 이는 요약 파이프라인의 입력이 될 것입니다.

PDF 내용 로드하기

전체 논문 내용으로 작업하기 위해 PDF에서 텍스트를 로드하고 추출하는 함수를 추가하겠습니다:
@weave.op()
def load_pdf(pdf_url: str) -> str:
    # Download the PDF
    response = requests.get(pdf_url)
    pdf_file = io.BytesIO(response.content)

    # Read the PDF
    pdf_reader = PdfReader(pdf_file)

    # Extract text from all pages
    text = ""
    for page in pdf_reader.pages:
        text += page.extract_text()

    return text

Chain of Density 요약 구현하기

이제 Weave 작업을 사용하여 핵심 CoD 요약 로직을 구현해 보겠습니다:
# Chain of Density Summarization
@weave.op()
def summarize_current_summary(
    document: str,
    instruction: str,
    current_summary: str = "",
    iteration: int = 1,
    model: str = "claude-3-sonnet-20240229",
):
    prompt = f"""
    Document: {document}
    Current summary: {current_summary}
    Instruction to focus on: {instruction}
    Iteration: {iteration}

    Generate an increasingly concise, entity-dense, and highly technical summary from the provided document that specifically addresses the given instruction.
    """
    response = anthropic_client.messages.create(
        model=model, max_tokens=4096, messages=[{"role": "user", "content": prompt}]
    )
    return response.content[0].text

@weave.op()
def iterative_density_summarization(
    document: str,
    instruction: str,
    current_summary: str,
    density_iterations: int,
    model: str = "claude-3-sonnet-20240229",
):
    iteration_summaries = []
    for iteration in range(1, density_iterations + 1):
        current_summary = summarize_current_summary(
            document, instruction, current_summary, iteration, model
        )
        iteration_summaries.append(current_summary)
    return current_summary, iteration_summaries

@weave.op()
def final_summary(
    instruction: str, current_summary: str, model: str = "claude-3-sonnet-20240229"
):
    prompt = f"""
    Given this summary: {current_summary}
    And this instruction to focus on: {instruction}
    Create an extremely dense, final summary that captures all key technical information in the most concise form possible, while specifically addressing the given instruction.
    """
    return (
        anthropic_client.messages.create(
            model=model, max_tokens=4096, messages=[{"role": "user", "content": prompt}]
        )
        .content[0]
        .text
    )

@weave.op()
def chain_of_density_summarization(
    document: str,
    instruction: str,
    current_summary: str = "",
    model: str = "claude-3-sonnet-20240229",
    density_iterations: int = 2,
):
    current_summary, iteration_summaries = iterative_density_summarization(
        document, instruction, current_summary, density_iterations, model
    )
    final_summary_text = final_summary(instruction, current_summary, model)
    return {
        "final_summary": final_summary_text,
        "accumulated_summary": current_summary,
        "iteration_summaries": iteration_summaries,
    }
각 함수가 하는 일은 다음과 같습니다:
  • summarize_current_summary: 현재 상태를 기반으로 단일 요약 반복을 생성합니다.
  • iterative_density_summarization: CoD 기법을 적용하기 위해 summarize_current_summary를 여러 번 호출합니다.
  • chain_of_density_summarization: 전체 요약 프로세스를 조율하고 결과를 반환합니다.
@weave.op() 데코레이터를 사용함으로써 Weave가 이러한 함수의 입력, 출력 및 실행을 추적하도록 보장합니다.

Weave 모델 만들기

이제 요약 파이프라인을 Weave 모델로 래핑해 보겠습니다:
# Weave Model
class ArxivChainOfDensityPipeline(weave.Model):
    model: str = "claude-3-sonnet-20240229"
    density_iterations: int = 3

    @weave.op()
    def predict(self, paper: ArxivPaper, instruction: str) -> dict:
        text = load_pdf(paper.pdf_url)
        result = chain_of_density_summarization(
            text,
            instruction,
            model=self.model,
            density_iterations=self.density_iterations,
        )
        return result
ArxivChainOfDensityPipeline 클래스는 요약 로직을 Weave 모델로 캡슐화하여 다음과 같은 주요 이점을 제공합니다:
  1. 자동 실험 추적: Weave는 모델의 각 실행에 대한 입력, 출력 및 매개변수를 캡처합니다.
  2. Versioning: Changes to the model’s attributes or code are automatically versioned, creating a clear history of how your summarization pipeline evolves over time.
  3. Reproducibility: The versioning and tracking make it easy to reproduce any previous result or configuration of your summarization pipeline.
  4. 하이퍼파라미터 관리: 모델 속성(예: modeldensity_iterations)이 명확하게 정의되고 다양한 실행에서 추적되어 실험을 용이하게 합니다.
  5. Weave 생태계와의 통합: weave.Model를 사용하면 평가 및 서빙 기능과 같은 다른 Weave 도구와 원활하게 통합할 수 있습니다.

평가 지표 구현하기

요약의 품질을 평가하기 위해 간단한 평가 지표를 구현하겠습니다:
import json

@weave.op()
def evaluate_summary(
    summary: str, instruction: str, model: str = "claude-3-sonnet-20240229"
) -> dict:
    prompt = f"""
    Summary: {summary}
    Instruction: {instruction}

    Evaluate the summary based on the following criteria:
    1. Relevance (1-5): How well does the summary address the given instruction?
    2. Conciseness (1-5): How concise is the summary while retaining key information?
    3. Technical Accuracy (1-5): How accurately does the summary convey technical details?

    Your response MUST be in the following JSON format:
    {{
        "relevance": {{
            "score": <int>,
            "explanation": "<string>"
        }},
        "conciseness": {{
            "score": <int>,
            "explanation": "<string>"
        }},
        "technical_accuracy": {{
            "score": <int>,
            "explanation": "<string>"
        }}
    }}

    Ensure that the scores are integers between 1 and 5, and that the explanations are concise.
    """
    response = anthropic_client.messages.create(
        model=model, max_tokens=1000, messages=[{"role": "user", "content": prompt}]
    )
    print(response.content[0].text)

    eval_dict = json.loads(response.content[0].text)

    return {
        "relevance": eval_dict["relevance"]["score"],
        "conciseness": eval_dict["conciseness"]["score"],
        "technical_accuracy": eval_dict["technical_accuracy"]["score"],
        "average_score": sum(eval_dict[k]["score"] for k in eval_dict) / 3,
        "evaluation_text": response.content[0].text,
    }
이러한 평가 함수는 Claude 모델을 사용하여 관련성, 간결성 및 기술적 정확성을 기준으로 생성된 요약의 품질을 평가합니다.

Weave 데이터셋 생성 및 평가 실행하기

파이프라인을 평가하기 위해 Weave 데이터셋을 만들고 평가를 실행하겠습니다:
# Create a Weave Dataset
dataset = weave.Dataset(
    name="arxiv_papers",
    rows=[
        {
            "paper": arxiv_paper,
            "instruction": "What was the approach to experimenting with different data mixtures?",
        },
    ],
)

weave.publish(dataset)
평가를 위해 LLM-as-a-judge 접근 방식을 사용할 것입니다. 이 기법은 언어 모델을 사용하여 다른 모델이나 시스템에서 생성된 출력의 품질을 평가하는 것을 포함합니다. 이는 LLM의 이해 및 추론 능력을 활용하여 특히 전통적인 지표가 부족할 수 있는 작업에 대해 미묘한 평가를 제공합니다. arXiv
# Define the scorer function
@weave.op()
def quality_scorer(instruction: str, output: dict) -> dict:
    result = evaluate_summary(output["final_summary"], instruction)
    return result
python
# Run evaluation
evaluation = weave.Evaluation(dataset=dataset, scorers=[quality_scorer])
arxiv_chain_of_density_pipeline = ArxivChainOfDensityPipeline()
results = await evaluation.evaluate(arxiv_chain_of_density_pipeline)
이 코드는 샘플 ArXiv 논문으로 데이터셋을 생성하고, 품질 평가자를 정의하며, 요약 파이프라인의 평가를 실행합니다.

결론

이 예제에서는 Weave를 사용하여 ArXiv 논문을 위한 Chain of Density 요약 파이프라인을 구현하는 방법을 보여주었습니다. 다음과 같은 방법을 보여주었습니다:
  1. 요약 프로세스의 각 단계에 대한 Weave 작업 생성하기
  2. 쉬운 추적 및 평가를 위해 파이프라인을 Weave 모델로 래핑하기
  3. Weave 작업을 사용하여 사용자 정의 평가 지표 구현하기
  4. 데이터셋을 생성하고 파이프라인 평가 실행하기
Weave의 원활한 통합을 통해 요약 프로세스 전반에 걸쳐 입력, 출력 및 중간 단계를 추적할 수 있어 LLM 애플리케이션을 디버깅, 최적화 및 평가하기가 더 쉬워집니다. 이 예제를 확장하여 더 큰 데이터셋을 처리하거나, 더 정교한 평가 지표를 구현하거나, 다른 LLM 워크플로우와 통합할 수 있습니다. W&B에서 전체 보고서 보기