LlamaIndex 에이전트 평가
LlamaIndex 에이전트 평가
도구를 지능적으로 사용하고 결정을 내릴 수 있는 에이전트를 만드는 것이 여정의 절반일 뿐이에요. 이 에이전트들이 정확하고 신뢰할 수 있으며 성능이 좋은지 보장하는 것이 그 성공을 정의하죠. LlamaIndex는 FunctionAgents, CodeActAgents, ReActAgents 를 포함한 다양한 방식으로 에이전트를 만들 수 있게 해줘요. 이 튜토리얼에서는 사전 구축된 Ragas 메트릭과 커스텀 평가 메트릭을 모두 사용해 이러한 다양한 에이전트 유형을 평가하는 방법을 살펴볼 거예요.
출처: 문서
본문
시작해 볼게요.
튜토리얼은 세 개의 포괄적인 섹션으로 나뉘어요.
- 즉시 사용 가능한 Ragas 메트릭으로 평가하기 : 여기서는 AgentGoalAccuracy(에이전트가 사용자의 의도한 목표를 얼마나 효과적으로 식별·달성하는지 측정)와 Tool Call Accuracy(작업을 완료하기 위해 올바른 순서로 적절한 도구를 선택·호출하는 에이전트의 능력 평가)라는 두 가지 기본 평가 도구를 살펴볼 거예요.
- CodeActAgent 평가를 위한 커스텀 메트릭 : 이 섹션은 LlamaIndex의 사전 구축된 CodeActAgent에 초점을 맞춰, 코드 생성 에이전트의 특정 요구사항과 기능을 다루는 맞춤형 평가 메트릭을 개발하는 방법을 보여줘요.
- Query Engine 도구 평가 : 마지막 섹션은 Ragas RAG 메트릭을 활용해 에이전트 내 query engine 기능을 평가하는 방법을 살펴봐요. 정보 시스템에 접근할 때 검색 효과성과 응답 품질에 대한 인사이트를 제공해요.
Ragas 에이전트 메트릭
Ragas 메트릭으로 평가를 시연하기 위해 단일 LlamaIndex Function Agent가 있는 간단한 워크플로우를 만들고, 그걸로 기본 기능을 다룰 거예요.
에이전트 목표 정확도
AI 에이전트의 진정한 가치는 사용자가 원하는 것을 이해하고 효과적으로 전달하는 능력에 있어요. 에이전트 목표 정확도는 에이전트가 사용자의 의도를 성공적으로 달성하는지 평가하는 기본 메트릭이에요. 이 측정은 에이전트가 사용자 요구를 얼마나 잘 해석하고 충족하기 위한 적절한 조치를 취하는지 직접 반영하기 때문에 중요해요.
Ragas는 이 메트릭의 두 가지 주요 변형을 제공해요.
AgentGoalAccuracyWithReference- 에이전트의 최종 결과를 미리 정의된 기대 결과와 비교하는 이진(1 또는 0) 평가예요.AgentGoalAccuracyWithoutReference- 미리 정의된 기대가 아니라 유추된 의도를 기반으로 에이전트가 사용자 목표를 달성했는지 평가하는 이진(1 또는 0) 평가예요.
With Reference는 기대 결과가 잘 정의된 시나리오, 예를 들어 통제된 테스트 환경이나 ground truth 데이터에 대해 테스트할 때 이상적이에요.
from llama_index.core.agent.workflow import (
AgentInput,
AgentOutput,
AgentStream,
ToolCall as LlamaToolCall,
ToolCallResult,
)
handler = agent.run(user_msg="Send a message to jhon asking for a meeting")
events = []
async for ev in handler.stream_events():
if isinstance(ev, (AgentInput, AgentOutput, LlamaToolCall, ToolCallResult)):
events.append(ev)
elif isinstance(ev, AgentStream):
print(f"{ev.delta}", end="", flush=True)
elif isinstance(ev, ToolCallResult):
print(
f"\nCall {ev.tool_name} with {ev.tool_kwargs}\nReturned: {ev.tool_output}"
)
response = await handler
I have successfully sent a message to Jhon asking for a meeting.
from ragas.integrations.llama_index import convert_to_ragas_messages
ragas_messages = convert_to_ragas_messages(events)
from ragas.metrics import AgentGoalAccuracyWithoutReference
from ragas.llms import LlamaIndexLLMWrapper
from ragas.dataset_schema import MultiTurnSample
from ragas.messages import ToolCall as RagasToolCall
evaluator_llm = LlamaIndexLLMWrapper(llm=llm)
sample = MultiTurnSample(
user_input=ragas_messages,
)
agent_goal_accuracy_without_reference = AgentGoalAccuracyWithoutReference(llm=evaluator_llm)
await agent_goal_accuracy_without_reference.multi_turn_ascore(sample)
1.0
from ragas.metrics import AgentGoalAccuracyWithReference
sample = MultiTurnSample(
user_input=ragas_messages,
reference="Successfully sent a message to Jhon asking for a meeting"
)
agent_goal_accuracy_with_reference = AgentGoalAccuracyWithReference(llm=evaluator_llm)
await agent_goal_accuracy_with_reference.multi_turn_ascore(sample)
도구 호출 정확도
에이전트 워크플로우에서 AI 에이전트의 효과성은 올바른 시기에 올바른 도구를 선택해 사용하는 능력에 크게 의존해요. 도구 호출 정확도 메트릭은 에이전트가 사용자의 요청을 완료하기 위해 올바른 순서로 적절한 도구를 식별·호출하는 정확도를 평가해요. 이 측정은 에이전트가 어떤 도구를 사용할 수 있는지 이해할 뿐 아니라 의도한 결과를 달성하기 위해 이를 효과적으로 오케스트레이션하는지 보장해요.
ToolCallAccuracy는 에이전트의 실제 도구 사용을 기대 도구 호출의 참조 시퀀스와 비교해요. 에이전트의 도구 선택이나 순서가 reference와 다르면 메트릭은 0의 점수를 반환해 작업 완료의 최적 경로를 따르지 못했음을 나타내요.
from ragas.metrics import ToolCallAccuracy
sample = MultiTurnSample(
user_input=ragas_messages,
reference_tool_calls=[
RagasToolCall(
name="send_message",
args={'to': 'jhon', 'content': 'Hi Jhon,\n\nI hope this message finds you well. I would like to schedule a meeting to discuss some important matters. Please let me know your availability.\n\nBest regards,\nJane'},
),
],
)
tool_accuracy_scorer = ToolCallAccuracy()
await tool_accuracy_scorer.multi_turn_ascore(sample)
LlamaIndex CodeAct 에이전트 평가
LlamaIndex는 원래 CodeAct 논문에서 영감을 받아 코드를 작성·실행하는 데 쓸 수 있는 사전 구축된 CodeAct 에이전트를 제공해요. 아이디어는: 단순한 JSON 객체를 출력하는 대신 Code 에이전트가 실행 가능한 코드 블록—보통 Python처럼 고급 언어로—을 생성한다는 거예요. JSON 같은 스니펫보다 코드로 행동을 작성하면 다음이 더 좋아져요.
- 합성 가능성(Composability) : 코드는 자연스럽게 함수의 중첩과 재사용을 허용해요. JSON 액션은 이런 유연성이 없어요.
- 객체 관리 : 코드는 작업 출력을 우아하게 처리해요(
image = generate_image()). JSON에는 깔끔한 대응물이 없어요. - 일반성(Generality) : 코드는 어떤 계산 작업이든 표현해요. JSON은 불필요한 제약을 부과해요.
- LLM 훈련 데이터에서의 표현 : LLM은 훈련 데이터에서 이미 코드를 이해하므로, 특수한 JSON보다 더 자연스러운 인터페이스예요.
CodeAct 에이전트 실행 및 평가
from llama_index.core.agent.workflow import (
AgentInput,
AgentOutput,
AgentStream,
ToolCall,
ToolCallResult,
)
handler = agent.run("Calculate the sum of the first 10 fibonacci numbers", ctx=ctx)
events = []
async for event in handler.stream_events():
if isinstance(event, (AgentInput, AgentOutput, ToolCall, ToolCallResult)):
events.append(event)
elif isinstance(event, AgentStream):
print(f"{event.delta}", end="", flush=True)
The first 10 Fibonacci numbers are 0, 1, 1, 2, 3, 5, 8, 13, 21, and 34. I will calculate their sum.
<execute>
def fibonacci(n):
fib_sequence = [0, 1]
for i in range(2, n):
next_fib = fib_sequence[-1] + fib_sequence[-2]
fib_sequence.append(next_fib)
return fib_sequence
# Calculate the first 10 Fibonacci numbers
first_10_fib = fibonacci(10)
# Calculate the sum of the first 10 Fibonacci numbers
sum_fib = sum(first_10_fib)
print(sum_fib)
</execute>The sum of the first 10 Fibonacci numbers is 88.
ToolCall 추출
CodeAct_agent_tool_call = events[2]
agent_code = CodeAct_agent_tool_call.tool_kwargs["code"]
print(agent_code)
def fibonacci(n):
fib_sequence = [0, 1]
for i in range(2, n):
next_fib = fib_sequence[-1] + fib_sequence[-2]
fib_sequence.append(next_fib)
return fib_sequence
# Calculate the first 10 Fibonacci numbers
first_10_fib = fibonacci(10)
# Calculate the sum of the first 10 Fibonacci numbers
sum_fib = sum(first_10_fib)
print(sum_fib)
CodeAct 에이전트를 평가할 때는 코드 컴파일 가능성이나 적절한 인자 선택 같은 기본 기능을 살펴보는 기초 메트릭으로 시작할 수 있어요. 이러한 간단한 평가는 더 정교한 평가 접근법으로 나아가기 전에 견고한 기반을 제공해요.
Ragas는 요구사항이 발전함에 따라 점점 더 미묘한 평가를 가능하게 하는 강력한 커스텀 메트릭 기능을 제공해요.
AspectCritic- 특정 사용자 정의 기준을 에이전트 응답이 충족하는지 결정하는 이진(pass/fail) 평가를 제공해요. LLM 기반 판단을 사용해 명확한 성공 지표를 제공해요.RubricScoreMetric- 이산 점수 수준이 있는 포괄적인 사전 정의 품질 루브릭에 대해 에이전트 응답을 평가해서 여러 차원에 걸쳐 일관된 성능 평가를 가능하게 해요.
def is_compilable(code_str: str, mode="exec") -> bool:
try:
compile(code_str, "<string>", mode)
return True
except Exception:
return False
is_compilable(agent_code)
True
from ragas.metrics import AspectCritic
from ragas.dataset_schema import SingleTurnSample
from ragas.llms import LlamaIndexLLMWrapper
llm = OpenAI(model="gpt-4o-mini")
evaluator_llm = LlamaIndexLLMWrapper(llm=llm)
correct_tool_args = AspectCritic(
name="correct_tool_args",
llm=evaluator_llm,
definition="Score 1 if the tool arguements use in the tool call are correct and 0 otherwise",
)
sample = SingleTurnSample(
user_input="Calculate the sum of the first 10 fibonacci numbers",
response=agent_code,
)
await correct_tool_args.single_turn_ascore(sample)
1
Query Engine 도구 평가
Ragas 메트릭으로 평가할 때 데이터가 평가에 적합하게 형식화되었는지 확인해야 해요. 에이전트 시스템 내에서 query engine 도구로 작업할 때는 다른 검색 증강 생성(RAG) 시스템과 동일하게 평가에 접근할 수 있어요.
사용자 상호작용 중 query engine 도구가 호출된 모든 인스턴스를 추출할 거예요. 이를 바탕으로 이벤트 스트림 데이터에서 Ragas RAG 평가 데이터셋을 구성할 수 있어요. 데이터셋이 준비되면 전체 Ragas 평가 메트릭 집합을 적용할 수 있어요. 이 섹션에서는 Query Engine 도구가 있는 Functional Agent를 설정할 거예요. 에이전트는 두 가지 "도구"에 접근할 수 있어요: 하나는 2021 Lyft 10-K를 쿼리하고, 다른 하나는 2021 Uber 10-K를 쿼리해요.
에이전트 실행 및 평가
from llama_index.core.agent.workflow import (
AgentInput,
AgentOutput,
ToolCall,
ToolCallResult,
AgentStream,
)
handler = agent.run("What's the revenue for Lyft in 2021 vs Uber?", ctx=ctx)
events = []
async for ev in handler.stream_events():
if isinstance(ev, (AgentInput, AgentOutput, ToolCall, ToolCallResult)):
events.append(ev)
elif isinstance(ev, AgentStream):
print(ev.delta, end="", flush=True)
response = await handler
In 2021, Lyft generated a total revenue of $3.21 billion, while Uber's total revenue was significantly higher at $17.455 billion.
사용자 상호작용 중 query engine 도구가 호출된 모든 ToolCallResult 인스턴스를 추출하고, 이를 바탕으로 이벤트 스트림 데이터에서 적절한 RAG 평가 데이터셋을 구성할 거예요.
from ragas.dataset_schema import SingleTurnSample
ragas_samples = []
for event in events:
if isinstance(event, ToolCallResult):
if event.tool_name in ["lyft_10k", "uber_10k"]:
sample = SingleTurnSample(
user_input=event.tool_kwargs["input"],
response=event.tool_output.content,
retrieved_contexts=[node.text for node in event.tool_output.raw_output.source_nodes]
)
ragas_samples.append(sample)
from ragas.dataset_schema import EvaluationDataset
dataset = EvaluationDataset(samples=ragas_samples)
dataset.to_pandas()
결과 데이터셋은 기본적으로 reference 답변을 포함하지 않으므로 reference가 필요 없는 메트릭으로 제한될 거예요. 하지만 reference 기반 평가를 실행하고 싶다면 데이터셋에 reference 컬럼을 추가한 뒤 관련 Ragas 메트릭을 적용할 수 있어요.
Ragas RAG 메트릭으로 평가
검색 품질과 환각 방지와 관련해 query engine의 효과성을 평가해 보겠습니다. 이 평가를 위해 faithfulness 와 context relevance 라는 두 가지 핵심 Ragas 메트릭을 사용할 거예요. 더 자세한 내용은 여기를 방문하세요.
이 평가 접근법은 전반적인 시스템 성능에 영향을 줄 수 있는 검색 품질이나 응답 생성의 잠재적 문제를 식별할 수 있게 해줘요.
Faithfulness- 생성된 응답이 검색된 컨텍스트에 제시된 사실을 얼마나 정확히 준수하는지 측정해, 시스템이 만든 주장이 제공된 정보에 의해 직접 뒷받침될 수 있도록 보장해요.Context Relevance- 이중 LLM 판단 메커니즘을 통한 관련성 평가로 검색된 정보가 사용자의 특정 쿼리를 얼마나 잘 다루는지 평가해요.
from ragas import evaluate
from ragas.metrics import Faithfulness, ContextRelevance
from ragas.llms import LlamaIndexLLMWrapper
from llama_index.llms.openai import OpenAI
llm = OpenAI(model="gpt-4o")
evaluator_llm = LlamaIndexLLMWrapper(llm=llm)
faithfulness = Faithfulness(llm=evaluator_llm)
context_precision = ContextRelevance(llm=evaluator_llm)
result = evaluate(dataset, metrics=[faithfulness, context_precision])
Evaluating: 100%|██████████| 4/4 [00:03<00:00, 1.19it/s]
result.to_pandas()