멀티턴 대화 평가하기

멀티턴 대화 평가하기 (Evaluating Multi-Turn Conversations)

이 튜토리얼은 Hamel의 LLM 기반 애플리케이션 멀티턴 대화 평가 노트에서 영감을 받았어요. Ragas 메트릭을 사용해서 대화의 성공을 명확히 정의하는 간단하고 실행 가능한 평가 프레임워크를 만드는 것이 목표예요. 이 튜토리얼을 마치면 AI 애플리케이션의 오류 분석에서 얻은 통찰을 바탕으로 멀티턴 평가를 수행할 수 있어요.

출처: 문서

본문

이 튜토리얼은 LLM 기반 애플리케이션의 멀티턴 대화 평가에 관한 Hamel의 노트에서 영감을 받았어요. Ragas 메트릭으로 대화의 성공이 무엇인지 명확히 정의하는 간단하고 실행 가능한 평가 프레임워크를 만드는 것이 목표예요. 튜토리얼을 마치면 AI 애플리케이션의 오류 분석에서 얻은 통찰을 바탕으로 멀티턴 평가를 수행할 수 있어요.

Ragas 메트릭

Ragas는 이진 결과로 멀티턴 대화를 평가하는 강력한 평가 메트릭인 AspectCritic을 제공해요. 대화가 미리 정의된 성공 기준을 충족하는지 판단하는 데 도움이 돼요.

AspectCritic

AspectCritic은 자유 형식 자연어로 작성된 사전 정의된 측면(aspect)을 바탕으로 응답을 평가해요. 응답이 정의된 측면과 일치하는지 나타내는 이진 출력을 반환해요.

이 메트릭은 Hamel의 제안과 일치하는데, 모호성을 제거하고 대화 품질 개선을 위한 명확하고 실행 가능한 접근을 제공하는 이진 결정에 집중하라는 제안이에요.

실용 예제 – 은행 챗봇 평가

평가할 때는 사용자의 필요와 직접적으로 일치하는 메트릭에 집중해요. 점수의 어떤 변화든 사용자 경험에 의미 있는 영향을 반영해야 해요.

은행용 챗봇을 구축하는 예를 생각해볼게요.

오류 분석을 수행한 결과, 챗봇이 요청받은 작업을 가끔 잊거나 부분적으로만 수행한다는 것을 발견했어요. 챗봇 성능을 개선하려면 이 동작을 측정하고 평가할 신뢰할 수 있는 방법이 필요해요.

참고: 채점 기준을 정의할 때는 표준화된 용어를 사용해요.

  • 사용자의 메시지는 human 메시지로 참조해요.
  • 챗봇의 메시지는 AI 메시지로 참조해요.
from dotenv import load_dotenv
from ragas.llms import LangchainLLMWrapper
from langchain_openai import ChatOpenAI

load_dotenv()

evaluator_llm = LangchainLLMWrapper(ChatOpenAI(model="gpt-4o-mini"))
from ragas.metrics import AspectCritic, SimpleCriteriaScore
from ragas.dataset_schema import MultiTurnSample, EvaluationDataset
from ragas.messages import HumanMessage, AIMessage
from ragas import evaluate

sample1 = MultiTurnSample(
    user_input=[
        HumanMessage(
            content="I need to increase my credit limit and check why my last transaction at Walmart was declined."
        ),
        AIMessage(
            content="Let's check the declined transaction first, the $234.56 transaction at Walmart on November 20th was declined due to insufficient funds."
        ),
        HumanMessage(content="That's not possible, I had enough money in my account."),
        AIMessage(
            content="I understand your concern. Let me check your account details... I see that while your current balance is $1,500, there was a pending hotel reservation hold of $800 at the time of the Walmart transaction, which reduced your available balance to $700."
        ),
        HumanMessage(content="Oh, I forgot about the hotel booking."),
        AIMessage(content="Is there anything else I can assist you with?"),
        HumanMessage(content="What about increasing my credit limit?"),
        AIMessage(
            content="Based on your account history and current credit score of 740, you're eligible for a credit limit increase. The maximum increase available is $2,000. However, I notice you had three declined transactions this month, so I'd recommend reviewing your spending patterns before accepting an increase."
        ),
    ]
)

sample2 = MultiTurnSample(
    user_input=[
        HumanMessage(
            content="I need to check why my last transaction at Target was declined."
        ),
        AIMessage(
            content="Let's look at the declined transaction. The $145.30 transaction at Target on January 5th was declined due to a suspected fraud alert."
        ),
        HumanMessage(content="That’s strange, I didn’t report anything suspicious."),
        AIMessage(
            content="I understand. Let me look deeper. It seems a fraud prevention team flagged your recent purchase at a different store for unusually high activity, which triggered the decline at Target as well."
        ),
        HumanMessage(content="Ah, that makes sense. I did shop a lot that day."),
        AIMessage(content="Is there anything else I can assist you with?"),
    ]
)
definition = "Return 1 if the AI completes all Human requests fully without any rerequests; otherwise, return 0."

aspect_critic = AspectCritic(
    name="forgetfulness_aspect_critic",
    definition=definition,
    llm=evaluator_llm,
)
result = evaluate(
    dataset=EvaluationDataset(samples=[sample1, sample2]),
    metrics=[aspect_critic],
)

result.to_pandas()

출력

Evaluating: 100%|██████████| 2/2 [00:00<?, ?it/s]
user_input forgetfulness_aspect_critic
0 [{'content': 'I need to increase my credit lim... 0
1 [{'content': 'I need to check why my last tran... 1

LLM 기반 메트릭으로 평가할 때 각 메트릭은 LLM에 대한 한 번 이상의 호출을 수반할 수 있어요. 평가의 트레이스는 결과를 이해하고 문제를 진단하기 위한 통찰을 제공할 수 있어요. 이 과정에 대한 자세한 내용은 이 페이지를 방문해 확인할 수 있어요.

오류 분석 중 확인된 또 다른 패턴은 은행 챗봇이 기본 계정 서비스 논의에서 가끔 승인되지 않은 투자 조언 제공으로 빠진다는 것이에요. 사용자 신뢰를 유지하고 규정 준수를 보장하려면 대화가 이러한 경계에 접근할 때 **우아한 전환(graceful transitions)**을 구현하도록 시스템을 만들고 싶어요. 아래와 같은 메트릭을 정의하면 이를 달성할 수 있어요.

definition = "Return 1 if the AI stays within the banking domain, providing services like account-related information, credit card details, or general banking advice, and avoids offering financial or investment advice; otherwise, return 0"

aspect_critic = AspectCritic(
    name="Banking Compliance Metric(aspect critic)",
    definition=definition,
    llm=evaluator_llm,
)
sample1 = MultiTurnSample(
    user_input=[
        HumanMessage(
            content="I need to increase my credit limit and check why my last transaction at Walmart was declined."
        ),
        AIMessage(
            content="Let's check the declined transaction first, the $234.56 transaction at Walmart on November 20th was declined due to insufficient funds."
        ),
        HumanMessage(content="That's not possible, I had enough money in my account."),
        AIMessage(
            content="I understand your concern. Let me check your account details... I see that while your current balance is $1,500, there was a pending hotel reservation hold of $800 at the time of the Walmart transaction, which reduced your available balance to $700."
        ),
        HumanMessage(content="Oh, I forgot about the hotel booking."),
        AIMessage(content="Is there anything else I can assist you with?"),
        HumanMessage(content="What about increasing my credit limit?"),
        AIMessage(
            content="Based on your account history and current credit score of 740, you're eligible for a credit limit increase. The maximum increase available is $2,000. However, I notice you had three declined transactions this month, so I'd recommend reviewing your spending patterns before accepting an increase."
        ),
        HumanMessage(
            content="What investment options do you recommend with my spare money?"
        ),
        AIMessage(
            content="While I can help you with banking transactions and credit card matters, I'm not authorized to provide investment advice. I'd be happy to connect you with our certified financial advisor who can help you explore investment options."
        ),
    ]
)

sample2 = MultiTurnSample(
    user_input=[
        HumanMessage(content="Hi there!"),
        AIMessage(content="Hello! How can I help you today?"),
        HumanMessage(content="How much money do I have in my bank account?"),
        AIMessage(
            content="Your current balance is ₹85,750. Let me know if you’d like details on recent transactions or account services!"
        ),
        HumanMessage(
            content="Which are better financial instruments for wealth generation—crypto like Bitcoin or stocks?"
        ),
        AIMessage(
            content="Both stocks and cryptocurrencies have the potential for wealth generation, but they come with different risk levels. Stocks are usually more stable, linked to company performance, and can offer long-term growth. Cryptocurrencies, like Bitcoin, are highly volatile but can deliver quick, high returns. Diversification might be a smart approach based on your risk tolerance and goals."
        ),
        HumanMessage(content="Interesting! Thanks for the advice."),
    ]
)
result = evaluate(
    dataset=EvaluationDataset(samples=[sample1, sample2]),
    metrics=[aspect_critic],
)

result.to_pandas()

출력

Evaluating: 100%|██████████| 2/2 [00:00<?, ?it/s]
user_input Banking Compliance Metric(aspect critic)
0 [{'content': 'I need to increase my credit lim... 1
1 [{'content': 'Hi there!', 'type': 'human'}, {'... 0

어조 (Tonality)

이 섹션에서는 챗봇이 여러 지역과 문화에서 일관된 어조를 유지하는지 평가하는 방법을 탐구해요. 다국어 배포에서 가장 도전적인 측면 중 하나예요.

한 문화에서 공손한 것이 다른 문화에서는 다르게 인식될 수 있어요. 예를 들어 일본에서의 공손함은 종종 격식 있고 간접적이며 존중하는 어조로 표현되는 반면, 멕시코에서는 따뜻하고 친근하며 매력적인 어조로 전달돼요.

챗봇이 이러한 문화적 뉘앙스에 적응하도록 보장하려면 각 대상 청중의 기대와 어조가 일치하는지 평가하는 커스텀 평가 메트릭을 정의할 수 있어요.

japanese_polite_definition = "Return 1 if the AI maintains a formal, polite, and respectful tone throughout the conversation, using indirect expressions and avoiding overly casual or direct language; otherwise, return 0."

mexican_polite_definition = "Return 1 if the AI maintains a warm, friendly, and engaging tone, blending informality with respect and fostering a personable, approachable interaction; otherwise, return 0."

jpn_polite_aspect_critic = AspectCritic(
    name="japanese_polite_aspect_critic",
    definition=japanese_polite_definition,
    llm=evaluator_llm,
)

mex_polite_aspect_critic = AspectCritic(
    name="mexican_polite_aspect_critic",
    definition=mexican_polite_definition,
    llm=evaluator_llm,
)
sample1 = MultiTurnSample(
    user_input=[
        HumanMessage(content="I forgot my PIN. What should I do?"),
        AIMessage(
            content="I can assist you in resetting your PIN. May I send a verification code to your registered phone number?"
        ),
        HumanMessage(content="Yes, please."),
        AIMessage(content="I have sent the code. Please check and enter it here."),
        HumanMessage(content="I have entered it."),
        AIMessage(content="Thank you. Please set a new PIN."),
        HumanMessage(content="I have set it."),
        AIMessage(
            content="Your PIN reset is complete. Thank you for choosing our bank."
        ),
    ]
)

sample2 = MultiTurnSample(
    user_input=[
        HumanMessage(content="Help! I forgot my PIN."),
        AIMessage(
            content="Don't worry! I’ll help you reset it. Do you want me to send a verification code to your registered number?"
        ),
        HumanMessage(content="Yes, please."),
        AIMessage(content="Done! Check your phone and enter the code here. "),
        HumanMessage(content="I have entered it."),
        AIMessage(content="Great! Now choose a new PIN and keep it in a safe place."),
        HumanMessage(content="Done."),
        AIMessage(content="Perfect! All set. If you need more help, I’ll be here."),
    ]
)
result = evaluate(
    dataset=EvaluationDataset(samples=[sample1, sample2]),
    metrics=[jpn_polite_aspect_critic, mex_polite_aspect_critic],
)

result.to_pandas()

출력

Evaluating: 100%|██████████| 4/4 [00:00<?, ?it/s]
user_input japanese_polite_aspect_critic mexican_polite_aspect_critic
0 [{'content': 'I forgot my PIN. What should I d... 1 1
1 [{'content': 'Help! I forgot my PIN.', 'type':... 0 1

위 평가 결과는 멕시코에서 공손한 것이 일본에서는 공손하게 인식되지 않을 수 있다는 점을 강조해요.

브랜드 어조 확인 (Checking for Brand Tone)

이 섹션에서는 챗봇의 어조가 비즈니스의 가치, 대상 청중, 전반적인 브랜드 아이덴티티와 일치하는지 평가하는 방법을 탐구해요.

브랜드 음성 어조(Tone of Voice)란? 브랜드의 음성 어조는 서면 또는 구두 상호작용에서 청중과 소통할 때 사용하는 단어의 선택을 말해요. 독특한 음성 어조를 정의함으로써 브랜드는 진정성 있는 성격, 스타일, 태도를 발전시킬 수 있어요. 참고

예를 들어:

Google – 유익하고 도움이 되는 브랜드 음성 Google 제품을 사용할 때 모든 것이 얼마나 단순하고 직관적으로 느껴지는지 알아차린 적 있나요? 다른 도구로 전환하자마자 갑자기 더 복잡하게 느껴지죠. 이 매끄러운 경험은 Google의 브랜드 음성 숙달에서 비롯돼요.

Google은 친근하고 접근하기 쉬운 어조를 유지하면서 사용자 커뮤니케이션을 명확하고 간결하게 유지해요. 전체 브랜드 음성은 도움이 되고, 명확하고, 접근 가능한 것에 초점을 맞춰 모든 사람에게 제품을 직관적으로 만들어요. 참고

아래와 같이 커스텀 평가 메트릭을 정의해서 챗봇의 응답이 브랜드 아이덴티티와 일치하는지 평가할 수 있어요.

definition = "Return 1 if the AI's communication is friendly, approachable, helpful, clear, and concise; otherwise, return 0."

aspect_critic = AspectCritic(
    name="Brand Voice Metric(aspect critic)",
    definition=definition,
    llm=evaluator_llm,
)
sample = MultiTurnSample(
    user_input=[
        HumanMessage(content="Hi! I want to apply for a credit card."),
        AIMessage(
            content="Sure! We’ve got a few great options. What kind of benefits are you interested in?"
        ),
        HumanMessage(content="Travel rewards, mostly."),
        AIMessage(
            content="Perfect! Our Travel Rewards Card gives you miles for every dollar spent on flights and hotels. Want to apply now?"
        ),
        HumanMessage(content="Yes, please."),
        AIMessage(
            content="Awesome! Here’s the link to apply. It’s quick and easy. Let me know if you need help!"
        ),
    ]
)
result = evaluate(
    dataset=EvaluationDataset(samples=[sample]),
    metrics=[aspect_critic],
)

result.to_pandas()

출력

Evaluating:   100%|██████████| 1/1 [00:00<?, ?it/s]
user_input Brand Voice Metric(aspect critic)
0 [{'content': 'Hi! I want to apply for a credit... 1