Langchain

Langchain

LangChain은 언어 모델로 구동되는 애플리케이션 개발을 위한 프레임워크예요. RAG 시스템(langchain에서는 QA 시스템이라고도 불러요)을 만드는 데도 사용할 수 있어요. langchain으로 RAG 시스템을 만드는 방법에 대해 더 알고 싶다면 문서를 확인할 수 있어요. 이 통합을 통해 ragas에서 제공하는 메트릭으로 QA 체인을 쉽게 평가할 수 있어요.

출처: 문서

본문

Langchain QA 체인 평가

#!pip install ragas langchain_openai python-dotenv
# attach to the existing event loop when using jupyter notebooks
import os

import nest_asyncio
import openai
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()
# IMPORTANT: Remember to create a .env variable containing: OPENAI_API_KEY=sk-xyz where xyz is your key

# Access the API key from the environment variable
api_key = os.environ.get("OPENAI_API_KEY")

# Initialize the OpenAI API client
openai.api_key = api_key

nest_asyncio.apply()

먼저 데이터셋을 로드해 보겠습니다. NYC 위키백과 페이지 위에 일반적인 QA 시스템을 만들 거예요. 데이터셋을 로드하고 여기서 VectorstoreIndexRetrievalQA 를 만드세요.

from langchain.chains import RetrievalQA
from langchain.indexes import VectorstoreIndexCreator
from langchain_community.document_loaders import TextLoader
from langchain_openai import ChatOpenAI

loader = TextLoader("./nyc_wikipedia/nyc_text.txt")
index = VectorstoreIndexCreator().from_loaders([loader])


llm = ChatOpenAI(temperature=0)
qa_chain = RetrievalQA.from_chain_type(
    llm,
    retriever=index.vectorstore.as_retriever(),
    return_source_documents=True,
)
/home/jjmachan/.pyenv/versions/ragas/lib/python3.10/site-packages/langchain/indexes/vectorstore.py:128: UserWarning: Using InMemoryVectorStore as the default vectorstore.This memory store won't persist data. You should explicitlyspecify a vectorstore when using VectorstoreIndexCreator
  warnings.warn(
---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
...
ValidationError: 1 validation error for VectorstoreIndexCreator
embedding
  Field required [type=missing, input_value={}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.9/v/missing
# testing it out

question = "How did New York City get its name?"
result = qa_chain({"query": question})
result["result"]

이제 QA 시스템을 평가하기 위해 몇 가지 관련 질문을 만들었어요. 몇 개의 질문을 준비했지만 원하는 만큼 추가해도 됩니다.

eval_questions = [
    "What is the population of New York City as of 2020?",
    "Which borough of New York City has the highest population?",
    "What is the economic significance of New York City?",
    "How did New York City get its name?",
    "What is the significance of the Statue of Liberty in New York City?",
]

eval_answers = [
    "8,804,190",
    "Brooklyn",
    "New York City's economic significance is vast, as it serves as the global financial capital, housing Wall Street and major financial institutions. Its diverse economy spans technology, media, healthcare, education, and more, making it resilient to economic fluctuations. NYC is a hub for international business, attracting global companies, and boasts a large, skilled labor force. Its real estate market, tourism, cultural industries, and educational institutions further fuel its economic prowess. The city's transportation network and global influence amplify its impact on the world stage, solidifying its status as a vital economic player and cultural epicenter.",
    "New York City got its name when it came under British control in 1664. King Charles II of England granted the lands to his brother, the Duke of York, who named the city New York in his own honor.",
    "The Statue of Liberty in New York City holds great significance as a symbol of the United States and its ideals of liberty and peace. It greeted millions of immigrants who arrived in the U.S. by ship in the late 19th and early 20th centuries, representing hope and freedom for those seeking a better life. It has since become an iconic landmark and a global symbol of cultural diversity and freedom.",
]

examples = [
    {"query": q, "ground_truth": [eval_answers[i]]}
    for i, q in enumerate(eval_questions)
]

RagasEvaluatorChain 소개

RagasEvaluatorChain 은 ragas가 제공하는 메트릭(여기 문서화돼 있어요)을 감싸서, langchain과 langsmith로 이러한 평가를 더 쉽게 실행하게 해 줘요.

평가자 체인은 다음 API를 갖고 있어요.

  • __call__() : QA 체인의 결과에 RagasEvaluatorChain 을 직접 호출
  • evaluate() : 입력 쿼리의 예시 목록과 QA 체인의 출력(predictions)에 대해 평가
  • evaluate_run() : langsmith 평가자가 langsmith 데이터셋을 평가할 때 호출하는 메서드

각각을 실제로 살펴보겠어요.

result = qa_chain({"query": eval_questions[1]})
result["result"]

result = qa_chain(examples[4])
result["result"]

from ragas.langchain.evalchain import RagasEvaluatorChain
from ragas.metrics import (
    answer_relevancy,
    context_precision,
    context_recall,
    faithfulness,
)

# create evaluation chains
faithfulness_chain = RagasEvaluatorChain(metric=faithfulness)
answer_rel_chain = RagasEvaluatorChain(metric=answer_relevancy)
context_rel_chain = RagasEvaluatorChain(metric=context_precision)
context_recall_chain = RagasEvaluatorChain(metric=context_recall)
  • __call__()

QA 체인의 결과로 평가 체인을 직접 실행합니다. context_precision 이나 faithfulness 같은 메트릭은 source_documents 가 있어야 한다는 점에 주의하세요.

# Recheck the result that we are going to validate.
result

Faithfulness

eval_result = faithfulness_chain(result)
eval_result["faithfulness_score"]

높은 faithfulness_score 는 소스 문서와 답변 사이에 정확한 일관성이 있음을 의미해요.

결과(LLM의 답변)나 source_documents 를 다른 것으로 바꾸면 더 낮은 faithfulness 점수를 확인할 수 있어요.

fake_result = result.copy()
fake_result["result"] = "we are the champions"
eval_result = faithfulness_chain(fake_result)
eval_result["faithfulness_score"]

Context Recall

eval_result = context_recall_chain(result)
eval_result["context_recall_score"]

높은 context_recall_score 는 ground truth가 소스 문서에 있음을 의미해요.

source_documents 를 다른 것으로 바꾸면 더 낮은 context recall 점수를 확인할 수 있어요.

from langchain.schema import Document

fake_result = result.copy()
fake_result["source_documents"] = [Document(page_content="I love christmas")]
eval_result = context_recall_chain(fake_result)
eval_result["context_recall_score"]
  • evaluate()

QA 체인의 입력/쿼리 목록과 출력/predictions을 평가해요.

# run the queries as a batch for efficiency
predictions = qa_chain.batch(examples)

# evaluate
print("evaluating...")
r = faithfulness_chain.evaluate(examples, predictions)
r

# evaluate context recall
print("evaluating...")
r = context_recall_chain.evaluate(examples, predictions)
r

langsmith로 평가하기

Langsmith는 모든 LLM 프레임워크 위에 구축된 체인과 에이전트를 디버그, 테스트, 평가, 모니터링하는 데 도움을 주는 플랫폼이에요. LangChain과도 완벽하게 통합돼요.

Langsmith는 테스트 데이터셋을 만들고 그에 대해 평가를 실행하는 도구도 갖고 있어요. RagasEvaluatorChain 으로 ragas 메트릭을 langsmith 평가 실행에도 사용할 수 있어요. langsmith 평가에 대해 더 알고 싶다면 퀵스타트를 확인하세요.

eval_questions 에 나열된 NYC 질문으로 데이터셋을 만들어 보겠습니다. 새 langsmith 데이터셋을 만들고 질문을 업로드하세요.

# dataset creation

from langsmith import Client
from langsmith.utils import LangSmithError

client = Client()
dataset_name = "NYC test"

try:
    # check if dataset exists
    dataset = client.read_dataset(dataset_name=dataset_name)
    print("using existing dataset: ", dataset.name)
except LangSmithError:
    # if not create a new one with the generated query examples
    dataset = client.create_dataset(
        dataset_name=dataset_name, description="NYC test dataset"
    )
    for e in examples:
        client.create_example(
            inputs={"query": e["query"]},
            outputs={"ground_truth": e["ground_truth"]},
            dataset_id=dataset.id,
        )

    print("Created a new dataset: ", dataset.name)

보시다시피 질문이 업로드됐어요. 이제 이 테스트 데이터셋에 QA 체인을 실행하고 langchain 플랫폼에서 결과를 비교할 수 있어요.

run_on_dataset 을 호출하기 전에, 테스트하려는 QA 체인의 새 인스턴스를 만드는 팩토리 함수가 필요해요. 각 예시에 대해 실행할 때 내부 상태가 재사용되지 않도록 하기 위함이에요.

# factory function that return a new qa chain
def create_qa_chain(return_context=True):
    qa_chain = RetrievalQA.from_chain_type(
        llm,
        retriever=index.vectorstore.as_retriever(),
        return_source_documents=return_context,
    )
    return qa_chain

이제 평가를 실행해 볼게요.

from langchain.smith import RunEvalConfig, run_on_dataset

evaluation_config = RunEvalConfig(
    custom_evaluators=[
        faithfulness_chain,
        answer_rel_chain,
        context_rel_chain,
        context_recall_chain,
    ],
    prediction_key="result",
)

result = run_on_dataset(
    client,
    dataset_name,
    create_qa_chain,
    evaluation=evaluation_config,
    input_mapper=lambda x: x,
)

링크를 따라가면 langsmith에서 실행 결과를 열 수 있어요. 각 예시의 점수도 확인해 보세요.

점수의 이유와 개선 방법을 더 깊이 파고들고 싶다면 아무 예시나 클릭하고 feedback 탭을 여세요. 각 점수가 보일 거예요.

ragas가 왜 그렇게 점수를 매겼는지 알아보려면 해당 RagasEvaluatorChain trace도 볼 수 있어요.

더 알아보기 (Learn more)