Skip to main content

W&B Weave로 Azure AI Foundry에서 GPT 모델 비교하기

Azure의 관리형 인프라와 Weave의 맞춤형 평가 도구를 활용해 텍스트 요약 작업에서 OpenAI의 GPT 모델을 W&B Weave로 비교·평가하는 방법을 알아보세요. 이 글은 AI 번역 본문입니다. 오역 가능성이 있으면 댓글로 알려주세요.
Created on September 12|Last edited on September 12
조직들이 운영 효율화를 위해 AI에 점점 더 의존함에 따라, 언어 모델을 효과적으로 비교·평가하는 능력이 필수적이 되었습니다. 연구 논문 요약과 같은 특정 사용 사례에 적합한 모델을 선택하는 일은 특히 중요합니다. 재무 보고서또는 비즈니스 문서의 요약 등은 효율성과 결과에 상당한 영향을 미칠 수 있습니다. 그러나 텍스트 요약 은 설득력 있는 사례이지만, 보다 넓은 초점은 도구를 활용해 모델 성능을 체계적으로 분석하고 비교하는 데 있습니다.
이 글은 평가와 비교를 위한 가이드를 제공합니다 대규모 언어 모델(LLM) 에서 OpenAI의 GPT 모델을 사용해 Azure AI Foundry, W&B Weave의 견고한 평가 플랫폼과 통합되어 있습니다. Azure AI Foundry의 확장 가능한 인프라와 Weave의 시각화 및 분석 도구를 결합하면, 조직은 모델 전반에 걸쳐 세밀한 비교를 수행하고, 구성을 정교화하며, 고유한 목표와 운영 요구에 맞춰 워크플로를 최적화할 수 있습니다.


목차



Azure AI Foundry에서 사용할 수 있는 파운데이션 모델

Azure AI Foundry는 다양한 종류의에 접근할 수 있는 종합 플랫폼을 제공합니다 파운데이션 모델, 조직이 요약 및 기타 언어 작업을 손쉽게 수행할 수 있도록 합니다. 이어서 Azure, 관리형 인프라의 이점을 통해 유지 관리의 복잡성을 없애고 AI 시스템 확장, 인사이트 도출과 워크플로 최적화에 집중할 수 있도록 합니다.
이 플랫폼은 상용 모델과 오픈 소스 모델을 함께 지원하여 다양한 사용 사례에 유연하게 대응할 수 있습니다. Azure의 카탈로그에는 다음과 같은 제공업체의 고급 옵션이 포함됩니다. OpenAI, Meta, 및 Mistral, Microsoft 자체 모델까지 Phi 시리즈 모델이들 모델은 대화형 AI, 요약, 문서 처리부터 고처리량 애플리케이션에 이르기까지 다양한 작업에 최적화되어 있습니다. 복잡한 작업을 위한 최첨단 성능이 필요하든, 단순한 요구에 맞는 비용 효율적인 대안을 원하든, Azure의 방대한 선택지는 폭넓은 운영 요구 사항을 충족합니다.
Weights & Biases Weave의 고급 평가 도구와 결합하면, Azure AI Foundry는 모델을 나란히 비교하고, 성능 지표를 시각화하며, 강점과 한계를 파악할 수 있도록 도와줍니다. 이러한 매끄러운 통합을 통해 조직은 자신들의 고유한 목표와 워크플로에 가장 잘 부합하는 모델을 선택하는 데 필요한 근거 있는 결정을 내릴 수 있습니다.

Azure에서 W&B Weave로 GPT 모델 요약 성능 비교

W&B Weave는 평가 과정에서 생성된 요약을 기록하고 분석할 수 있는 강력한 플랫폼을 제공하여 성능 비교를 위한 중앙화된 대시보드를 가능하게 합니다. 이를 통해 모델 출력물을 나란히 상세히 분석하고, 일관성, 관련성, 전반적 품질의 차이를 명확히 드러낼 수 있습니다.
철저한 평가를 위해 다양한 지표를 활용하겠습니다:
  • ROUGE: 생성된 요약과 기준 요약 사이에서 핵심 구와 단어 시퀀스의 중복 정도를 측정합니다.
  • BERTScore: 텍스트의 문맥 임베딩을 비교하여 의미적 유사성을 평가합니다.
  • 압축 비율: 생성된 요약이 얼마나 간결한지 평가합니다.
  • 커버리지: 요약이 핵심 내용을 얼마나 효과적으로 포착하는지 평가합니다.
또한, 특화된 GPT-4o 평가 방식은 요약본에 대한 정성적 평가를 제공하여 분석을 한층 강화합니다. 이 방식은 정확성, 완전성, 기준 요약과의 일치도와 같은 요소를 고려해 각 출력을 1점부터 5점까지의 척도로 평가합니다. 이러한 지표들을 함께 활용하면 모델 성능을 종합적으로 파악할 수 있으며, 팀이 강점을 식별하고 약점을 보완하며 요약 요구에 가장 적합한 모델을 선택할 수 있습니다.

1단계: Azure AI Foundry를 통해 GPT 모델 액세스하기

Azure에서 GPT-4o와 GPT-4o Mini 같은 GPT 모델을 설정하고 배포하려면, 먼저 다음으로 이동하세요 Azure AI Foundry 그리고 Azure 자격 증명으로 로그인하세요. 로그인하면 대시보드로 이동하며, 여기에서 프로젝트 생성을 시작할 수 있습니다.

"Create project" 버튼을 클릭해 새 프로젝트를 초기화하세요. 표시되는 대화 상자에서 프로젝트 이름을 입력하고 연결할 허브를 선택하거나, 필요하다면 새 허브를 생성하세요. 완료되면 "Create"를 클릭해 설정을 마무리합니다.

프로젝트를 만든 뒤 열고, 왼쪽 사이드바에서 "Model catalog"로 이동하세요. 이 영역에서 사용 가능한 다양한 AI 모델을 찾아보고 살펴볼 수 있습니다.
모델 카탈로그에서 배포 옵션의 "Serverless API"를 선택해 옵션을 필터링하세요. 그러면 서버리스 인프라로 배포할 수 있는 모델만 목록에 표시됩니다. 표시된 모델 목록에서 GPT-4o와 GPT-4o Mini를 찾아 선택하세요.

GPT-4o를 선택해 상세 페이지를 연 뒤, 여기에서 "Deploy"를 클릭하고 "gpt-4o-deployment"처럼 배포 이름을 입력하세요. 배포 유형으로 "Global Standard"를 선택하고 설정을 확인합니다. 같은 과정을 GPT-4o Mini에도 반복하여 두 모델을 모두 배포하세요.

배포가 완료되면 왼쪽 사이드바에서 "Models + Endpoints" 섹션으로 이동하세요. 배포한 모델을 클릭해 상세 정보를 확인합니다. 각 모델의 엔드포인트 URL과 API 키를 복사하세요. 이는 이후 애플리케이션과의 통합에 필요합니다.

마지막 단계로 다음 파이썬 라이브러리를 설치하세요:
pip install openai==1.54.5 arxiv==2.1.3 PyMuPDF==1.24.9 weave==0.51.18 fitz==0.0.1.dev2 bert-score==0.3.13 rouge-score==0.1.2
이 시점에서 GPT-4o와 GPT-4o Mini는 모두 Azure에 성공적으로 배포되었으며, 각자의 API 엔드포인트를 통해 사용할 준비가 완료되었습니다. 이제 코드를 작성할 차례입니다!

2단계: 여러 GPT 모델로 요약을 테스트할 데이터셋 생성

원문 초록을 제거한 연구 논문에 대해 GPT-4o와 GPT-4o Mini 모델이 정확한 초록을 생성하는 능력을 테스트하여 텍스트 요약 성능을 벤치마크하겠습니다. 이 접근 방식은 각 논문의 본문에서 핵심 정보를 추출해 간결하고 관련성 높은 요약을 얼마나 효과적으로 만들어 내는지 모델 간 비교를 가능하게 합니다.
이 방법은 모델의 요약 능력을 효과적으로 검증합니다. 사람이 복잡한 정보를 요약할 때 수행하는 과제를 그대로 반영하기 때문입니다. 즉, 논문의 핵심 목적, 방법, 그리고 주요 결과를 간결하고 일관된 초록으로 응축하는 일과 같습니다. 초록을 의도적으로 제거하면, 모델이 논문의 가장 본질적인 요소를 스스로 식별하고 전달할 수 있는지 평가할 수 있으며, 이를 통해 학술 콘텐츠를 구조적이고 간결한 형식으로 처리·평가·요약하는 인간에 가까운 능력을 확인할 수 있습니다. 이러한 설정은 정보 포착의 정확도뿐 아니라, 인간 전문가처럼 내용을 간명하게 조직하는 능력까지 함께 평가할 수 있게 해 줍니다.
먼저, 모델로 추론을 실행하는 방법을 보여 줄 기본 스크립트를 공유하겠습니다.
import weave
import os
from openai import AzureOpenAI
import json

# Initialize Weave for logging
weave.init('azure-api')

# Initialize the AzureOpenAI client
client = AzureOpenAI(
azure_endpoint="your enpoint url",
api_key="your key",
api_version="2024-09-01-preview"
)

@weave.op
def run_inference(prompt, client):
"""
Function to perform inference using the provided client and prompt.
"""
try:
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "user", "content": prompt}
]
)
# Parse the response
response_json = json.loads(response.model_dump_json(indent=2))
choices = response_json.get("choices", [])
if choices:
content = choices[0].get("message", {}).get("content", "")
print("Generated Content:")
print(content)
return content
else:
print("No content found in response")
return None
except Exception as e:
print(f"Failed to get response: {e}")
return None

# Define the prompt and perform inference
PROMPT = "What steps should I think about when writing my first Python API?"
run_inference(PROMPT, client)
여기에서는 모델의 입력과 출력도 Weave로 추적합니다. 이는 사용하는 방법을 보여 줍니다 Weave의 Traces 구성 요소나중에, 사용하는 방법을 보여 드리겠습니다 Weave 평가 동일한 데이터셋에서 모델을 비교하도록 특별히 설계되었습니다.
벤치마크 데이터셋을 만들기 위해 먼저 arXiv에서 AI와 머신러닝 주제의 연구 논문을 수집합니다. 각 논문에서 일반적으로 초록이 위치하는 첫 페이지만 추출하고, GPT-4o를 사용해 초록 부분을 분리한 뒤 JSON 객체로 구조화합니다. 이렇게 추출한 초록은 “골드 스탠더드” 기준으로 사용하며, 손쉬운 로딩과 일관된 평가를 위해 JSONL 파일 형식으로 저장합니다.
이 파일 형식을 사용하면 GPT-4o 모델을 평가할 때 요약본을 손쉽게 로드하고 처리할 수 있으며, 기준 데이터의 올바른 버전 관리와 손쉬운 공유도 보장할 수 있습니다. 아래 코드는 논문을 다운로드한 뒤, 각 논문의 첫 페이지에서 GPT-4o를 사용해 초록을 추출하는 예시입니다:
import os
import arxiv
import fitz # PyMuPDF
import json
from openai import AzureOpenAI
import weave
import re
from time import sleep

# Initialize Weave for logging
weave.init('azure_paper_abstract_gen')

# Set up Azure OpenAI
os.environ["AZURE_OPENAI_ENDPOINT"] = "your endpoint url"
os.environ["AZURE_OPENAI_API_KEY"] = "your api key"

client = AzureOpenAI(
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
api_key=os.getenv("AZURE_OPENAI_API_KEY"),
api_version="2024-09-01-preview"
)

# Directory to save downloaded papers
download_dir = "arxiv_papers"
os.makedirs(download_dir, exist_ok=True)

# Define AI-specific search queries
search_queries = [
"Large Language Models for vision tasks AND cat:cs.AI",
"Multimodal AI techniques AND cat:cs.CV",
"Applications of Transformers in healthcare AI AND cat:cs.LG",
"Few-shot learning in AI and ML AND cat:cs.LG",
"Vision and language models integration AND cat:cs.CV",
"Domain-specific fine-tuning for ML models AND cat:cs.LG",
"Foundational models in AI and CV applications AND cat:cs.AI",
"NLP in robotics and vision systems AND cat:cs.AI",
"Bias and fairness in AI for CV AND cat:cs.CV",
"Evaluation metrics for multimodal AI AND cat:cs.LG"
]

def download_papers(max_pages=15, max_attempts_per_query=20):
"""Download one suitable paper for each query, retrying if papers exceed page limit."""
papers = []
downloaded_titles = set()
client = arxiv.Client()

for query in search_queries:
paper_found = False
attempt = 0
while not paper_found and attempt < max_attempts_per_query:
search = arxiv.Search(
query=query,
max_results=100,
sort_by=arxiv.SortCriterion.SubmittedDate
)
try:
results = list(client.results(search))
start_idx = attempt * 5
end_idx = start_idx + 5
current_batch = results[start_idx:end_idx]
for result in current_batch:
if result.title not in downloaded_titles:
print(f"Downloading: {result.title}")
paper_id = result.entry_id.split('/')[-1]
pdf_filename = f"{paper_id}.pdf"
pdf_path = os.path.join(download_dir, pdf_filename)
result.download_pdf(dirpath=download_dir, filename=pdf_filename)
try:
with fitz.open(pdf_path) as pdf:
if pdf.page_count <= max_pages:
papers.append({
"title": result.title,
"file_path": pdf_path,
"arxiv_id": paper_id
})
downloaded_titles.add(result.title)
print(f"Accepted: {result.title}")
paper_found = True
break
else:
os.remove(pdf_path)
print(f"Skipped (too many pages: {pdf.page_count}): {result.title}")
except Exception as e:
print(f"Error checking PDF {pdf_path}: {e}")
if os.path.exists(pdf_path):
os.remove(pdf_path)
attempt += 1
if not paper_found:
print(f"Attempt {attempt}/{max_attempts_per_query} for query: {query}")
sleep(3)
except Exception as e:
print(f"Error during download: {e}")
sleep(3)
attempt += 1
continue
if not paper_found:
print(f"Failed to find suitable paper for query after {max_attempts_per_query} attempts: {query}")

print(f"\nSuccessfully downloaded {len(papers)} papers")
return papers

def extract_first_page_text(pdf_path):
"""Extract text from only the first page of the PDF."""
with fitz.open(pdf_path) as pdf:
if pdf.page_count > 0:
page = pdf[0]
return page.get_text()
return ""

@weave.op
def extract_abstract_with_azure(text, title):
"""Extract abstract using Azure GPT-4o with JSON output."""
try:
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "You are a research paper analysis assistant. Extract ONLY the abstract section from the paper content provided. Return the result in JSON format with 'abstract' as the key. If you cannot find the abstract, return an empty string as the value."},
{"role": "user", "content": f"Paper title: {title}\n\nPaper content:\n\n{text}"}
],
response_format={"type": "json_object"}
)
content = response.choices[0].message.content
return json.loads(content)
except Exception as e:
print(f"Error extracting abstract for {title}: {e}")
sleep(3)
return {"abstract": ""}

def count_words(text):
"""Count words excluding punctuation and special characters."""
cleaned_text = re.sub(r'[^\w\s]', ' ', text.lower())
words = [word for word in cleaned_text.split() if word.strip()]
return len(words)

def main():
# Download papers
papers = download_papers()
print(f"\nDownloaded {len(papers)} papers. Processing abstracts...\n")
# Process papers and extract abstracts
paper_data = []
for paper in papers:
title = paper["title"]
pdf_path = paper["file_path"]
print(f"Processing: {title}")
first_page_text = extract_first_page_text(pdf_path)
abstract_json = extract_abstract_with_azure(first_page_text, title)
abstract_text = abstract_json.get('abstract', '')
word_count = count_words(abstract_text)
paper_data.append({
"title": title,
"file_path": pdf_path,
"abstract": abstract_text,
"word_count": word_count,
"arxiv_id": paper["arxiv_id"]
})
sleep(2)

# Save to JSONL file
output_file = "paper_abstracts.jsonl"
with open(output_file, "w") as f:
for entry in paper_data:
json.dump(entry, f)
f.write("\n")

print(f"\nProcessed {len(paper_data)} papers. Results saved to {output_file}")

if __name__ == "__main__":
main()
이 스크립트는 Azure GPT-4o 모델을 평가하기 위한 기준 요약본 데이터셋을 구축합니다. 우리는 arXiv에서 수집한 AI 연구 논문에서 원문 초록을 그대로 추출하여, 평가에 일관되고 신뢰할 수 있는 기준 진실 데이터를 제공합니다. 이러한 초록은 JSONL 형식으로 저장되며, 비교를 위한 벤치마크로 사용됩니다.
이 과정은 연구 논문을 다운로드하고, 각 PDF에서 초록만 추출한 뒤, 이를 구조화된 형식으로 정리하는 것을 포함합니다. 이렇게 구조화된 데이터셋을 구축하면 GPT-4o 모델의 성능을 평가할 수 있는 신뢰할 수 있고 표준화된 기반이 마련됩니다. 이 기준 진실 데이터셋을 바탕으로 이제 GPT-4o 모델이 생성한 요약을 원본 초록과 나란히 비교하여, 요약 능력을 종합적으로 평가할 수 있습니다.

Weave Evaluations로 모델 평가하기

Azure AI Foundry에서 GPT-4o 모델의 텍스트 요약 성능을 평가하기 위해 종합적인 분석을 제공하는 다양한 지표를 사용합니다. 이 지표들은 전통적인 텍스트 유사도, 신경망 기반의 의미 유사도, 그리고 LLM 기반 채점 체계를 결합하여 성능을 효과적으로 평가합니다.
GPT-4o는 자동 평가자로서 작동하며, 생성된 초록이 목적, 방법론, 그리고 주요 발견과 같은 핵심 요소를 얼마나 잘 포착했는지에 따라 1–5점 척도로 평가합니다. 신경망 기반 의미 유사도 평가는 BERTScore를 사용하여 문맥적 정합성을 측정하고, ROUGE 점수는 어휘 및 구조적 중복도를 측정합니다. 또한 coverage와 compression ratio와 같은 추가 지표를 통해 정보 보존 정도와 요약의 간결성을 평가합니다.
저는 설정할 것을 추천합니다 WEAVE_PARALLELISM 평가 코드를 실행하기 전에 환경 변수를 낮은 값으로 설정할 것을 권합니다. 이는 다음 명령으로 수행할 수 있습니다. export WEAVE_PARALLELISM=1원활한 실행을 보장합니다. 이러한 지표는 Weave의 평가 대시보드에서 시각화되어 성능을 다차원적으로 보여 주고 개선이 필요한 영역을 강조합니다. 아래는 평가에 사용할 코드입니다:
import weave
from weave import Model
import json
from time import sleep
import asyncio
from rouge_score.rouge_scorer import RougeScorer
from typing import Dict, Any
import bert_score
import fitz
from weave.trace.box import unbox
import time
from openai import AzureOpenAI
import time
import json

from weave import Scorer
import json


# Initialize Weave
weave.init('azure_abstract_eval')


gpt4o_client = AzureOpenAI(
azure_endpoint="https://<your-resource-name>.openai.azure.com/openai/deployments/<gpt-4o-deployment-name>/chat/completions?api-version=2024-08-01-preview",
api_key="<your-api-key>",
api_version="2024-08-01-preview"
)

gpt4o_mini_client = AzureOpenAI(
azure_endpoint="https://<your-resource-name>.openai.azure.com/openai/deployments/<gpt-4o-mini-deployment-name>/chat/completions?api-version=2024-08-01-preview",
api_key="<your-api-key>",
api_version="2024-08-01-preview"
)

def create_prediction_prompt(text, title, target_length):
"""Create a prompt for abstract generation with target length."""
return (
f"You are tasked with generating an abstract for a research paper titled '{title}'. "
f"The abstract should be approximately {target_length} words long.\n\n"
f"Generate an abstract that summarizes the key points of the paper, including the "
f"research objective, methodology, and main findings. The abstract should be "
f"self-contained and clearly communicate the paper's contribution. Respond only with the ABSTRACT, and NOT the title\n\n"
f"Paper content:\n\n{text}"
f"Respond only with the ABSTRACT!"
)

def create_evaluation_prompt(gt_abstract: str, generated_abstract: str) -> str:
"""Create standardized evaluation prompt."""
return f'''You are evaluating how well a generated abstract captures the information from a ground truth abstract.

Ground Truth Abstract:
{gt_abstract}

Generated Abstract:
{generated_abstract}

Rate the generated abstract on a scale from 1-5, where:
1: Poor - Missing most key information or seriously misrepresenting the research
2: Fair - Captures some information but misses crucial elements
3: Good - Captures most key points but has some gaps or inaccuracies
4: Very Good - Accurately captures nearly all key information with minor omissions
5: Excellent - Perfectly captures all key information and maintains accuracy

Respond ONLY with a JSON object containing a single "score" field with an integer value from 1-5.
Example response format:
{{"score": 4}}'''


def extract_text_after_page_one(pdf_path: str) -> str:
"""Extract text from page 2 onwards."""
if isinstance(pdf_path, weave.trace.box.BoxedStr):
pdf_path = unbox(pdf_path)
text = ""
try:
with fitz.open(pdf_path) as pdf:
if pdf.page_count > 1:
for page_num in range(1, pdf.page_count): # Start from page 2
page = pdf[page_num]
text += page.get_text()
except Exception as e:
print(f"Error extracting text from PDF {pdf_path}: {e}")
return text


def run_inference(client: AzureOpenAI, model: str, prompt: str, max_retries: int = 10, base_wait: int = 10) -> str:
"""
Function to perform inference using specified Azure model with exponential backoff retry.
Args:
client: AzureOpenAI client
model: Model name/id
prompt: Input prompt
max_retries: Maximum number of retry attempts (default: 10)
base_wait: Initial wait time in seconds (default: 10)
"""
for attempt in range(max_retries):
try:
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": "You are a research paper abstract writer. Write clear, concise, and informative abstracts."},
{"role": "user", "content": prompt}
],
temperature=0.0
)
response_json = json.loads(response.model_dump_json(indent=2))
choices = response_json.get("choices", [])
if choices:
content = choices[0].get("message", {}).get("content", "")
return content
else:
print("No content found in response")
except Exception as e:
wait_time = base_wait * (2 ** attempt) # Exponential backoff
print(f"Attempt {attempt + 1}/{max_retries} failed: {e}")
print(f"Waiting {wait_time} seconds before retrying...")
time.sleep(wait_time)
continue
print(f"Failed to get response after {max_retries} retries")
return None




class GPT4o(Model):
@weave.op
def predict(self, title: str, pdf_path: str, word_count: int) -> dict:
"""Predict abstract using GPT-4O."""
paper_text = extract_text_after_page_one(pdf_path)
prompt = create_prediction_prompt(title, paper_text, word_count)
prediction = run_inference("gpt-4o-2024-08-06", prompt)
return {"model_output": prediction}

class GPT4oMini(Model):
@weave.op
def predict(self, title: str, pdf_path: str, word_count: int) -> dict:
"""Predict abstract using GPT-4O-mini."""
paper_text = extract_text_after_page_one(pdf_path)
prompt = create_prediction_prompt(title, paper_text, word_count)
prediction = run_inference("gpt-4o-mini", prompt)
return {"model_output": prediction}

@weave.op
def bert_scorer(gt_abstract: str, model_output: dict) -> Dict[str, float]:
"""Calculate BERTScore for the abstract."""
if not model_output or 'model_output' not in model_output:
return {'bert_score': 0.0}
try:
P, R, F1 = bert_score.score(
[model_output['model_output']],
[gt_abstract],
lang='en',
model_type='microsoft/deberta-xlarge-mnli'
)
return {'bert_score': float(F1.mean())}
except Exception as e:
print(f"Error calculating BERTScore: {e}")
return {'bert_score': 0.0}


# you can also use the "function" format for your scorer
# @weave.op
# def GPT4oScorer(gt_abstract: str, model_output: dict) -> dict:
# """Evaluate abstract using GPT-4o."""
# if not model_output or 'model_output' not in model_output:
# return {'gpt4o_score': 0.0}
# try:
# prompt = create_evaluation_prompt(gt_abstract, model_output["model_output"])
# response = run_inference(gpt4o_client, "gpt-4o", prompt)
# if response:
# # Clean the response text
# response_text = response.strip()
# # Remove any additional text before or after the JSON
# response_text = response_text.split('{')[1].split('}')[0]
# response_text = '{' + response_text + '}'
# try:
# result = json.loads(response_text)
# if 'score' in result and isinstance(result['score'], (int, float)):
# score = float(result['score'])
# if 1 <= score <= 5:
# return {'gpt4o_score': score}
# except json.JSONDecodeError:
# print(f"Invalid JSON response: {response_text}")
# print("Using default score due to invalid response")
# return {'gpt4o_score': 0.0}
# except Exception as e:
# print(f"Error in GPT-4o evaluation: {e}")
# return {'gpt4o_score': 0.0}


class GPT4oScorer(Scorer):
model_id: str = "gpt-4o"
system_prompt: str = "You are evaluating how well a generated abstract captures the information from a ground truth abstract."
@weave.op
def create_evaluation_prompt(self, gt_abstract: str, generated_abstract: str) -> str:
"""Create standardized evaluation prompt."""
return f'''Ground Truth Abstract:
{gt_abstract}

Generated Abstract:
{generated_abstract}

Rate the generated abstract on a scale from 1-5, where:
1: Poor - Missing most key information or seriously misrepresenting the research
2: Fair - Captures some information but misses crucial elements
3: Good - Captures most key points but has some gaps or inaccuracies
4: Very Good - Accurately captures nearly all key information with minor omissions
5: Excellent - Perfectly captures all key information and maintains accuracy

Respond ONLY with a JSON object containing a single "score" field with an integer value from 1-5.
Example response format:
{{"score": 4}}'''

@weave.op
def call_llm(self, gt_abstract: str, model_output: str) -> dict:
"""Call GPT-4o for evaluation."""
try:
prompt = self.create_evaluation_prompt(gt_abstract, model_output)
response = run_inference(gpt4o_client, self.model_id, prompt)
if response:
# Clean the response text
response_text = response.strip()
# Remove any additional text before or after the JSON
response_text = response_text.split('{')[1].split('}')[0]
response_text = '{' + response_text + '}'
try:
result = json.loads(response_text)
if 'score' in result and isinstance(result['score'], (int, float)):
score = float(result['score'])
if 1 <= score <= 5:
return {'gpt4o_score': score}
except json.JSONDecodeError:
print(f"Invalid JSON response: {response_text}")
print("Using default score due to invalid response")
return {'gpt4o_score': 0.0}
except Exception as e:
print(f"Error in GPT-4o evaluation: {e}")
return {'gpt4o_score': 0.0}

@weave.op
def score(self, model_output: dict, gt_abstract: str) -> dict:
"""Score the generated abstract against the ground truth.
Args:
model_output: Dictionary containing the generated abstract under 'model_output' key
gt_abstract: The ground truth abstract to compare against
"""
if not model_output or 'model_output' not in model_output:
return {'gpt4o_score': 0.0}
return self.call_llm(gt_abstract, model_output['model_output'])

@weave.op
def rouge_scorer(gt_abstract: str, model_output: dict) -> Dict[str, float]:
"""Calculate ROUGE scores for the abstract."""
if not model_output or 'model_output' not in model_output:
return {
'rouge1_f': 0.0,
'rouge2_f': 0.0,
'rougeL_f': 0.0
}
try:
scorer = RougeScorer(['rouge1', 'rouge2', 'rougeL'], use_stemmer=True)
scores = scorer.score(gt_abstract, model_output['model_output'])
return {
'rouge1_f': float(scores['rouge1'].fmeasure),
'rouge2_f': float(scores['rouge2'].fmeasure),
'rougeL_f': float(scores['rougeL'].fmeasure)
}
except Exception as e:
print(f"Error calculating ROUGE scores: {e}")
return {
'rouge1_f': 0.0,
'rouge2_f': 0.0,
'rougeL_f': 0.0
}

@weave.op
def compression_scorer(gt_abstract: str, model_output: dict) -> Dict[str, float]:
"""Calculate compression ratio of the abstract."""
if not model_output or 'model_output' not in model_output:
return {'compression_ratio': 0.0}
try:
gt_words = len(gt_abstract.split())
generated_words = len(model_output['model_output'].split())
compression_ratio = min(gt_words, generated_words) / max(gt_words, generated_words)
return {'compression_ratio': float(compression_ratio)}
except Exception as e:
print(f"Error calculating compression ratio: {e}")
return {'compression_ratio': 0.0}

@weave.op
def coverage_scorer(gt_abstract: str, model_output: dict) -> Dict[str, float]:
"""Calculate content coverage using word overlap."""
if not model_output or 'model_output' not in model_output:
return {'coverage_score': 0.0}
try:
gt_words = set(gt_abstract.lower().split())
generated_words = set(model_output['model_output'].lower().split())
intersection = len(gt_words.intersection(generated_words))
union = len(gt_words.union(generated_words))
coverage_score = intersection / union if union > 0 else 0.0
return {'coverage_score': float(coverage_score)}
except Exception as e:
print(f"Error calculating coverage score: {e}")
return {'coverage_score': 0.0}


def create_evaluation_dataset(gt_file: str):
"""Create dataset from ground truth file."""
dataset = []
with open(gt_file, 'r') as f:
for line in f:
entry = json.loads(line)
dataset.append({
"title": entry["title"],
"gt_abstract": entry["abstract"],
"pdf_path": entry["file_path"],
"word_count": entry["word_count"]
})
return dataset


async def run_evaluations(gt_file: str):
"""Run evaluations for each model."""
eval_dataset = create_evaluation_dataset(gt_file)
# Initialize models
models = {
"gpt4o": GPT4o(),
"gpt4o_mini": GPT4oMini()
}

gpt_scorer = GPT4oScorer()
# Setup scorers
scorers = [
gpt_scorer, # class based scorer
rouge_scorer,
compression_scorer,
coverage_scorer,
bert_scorer
]
# Run evaluations
results = {}
for model_name, model in models.items():
print(f"\nEvaluating {model_name}...")
evaluation = weave.Evaluation(
dataset=eval_dataset,
scorers=scorers,
name=model_name + " Eval"
)
results[model_name] = await evaluation.evaluate(model)
# Print results
print("\nEvaluation Results:")
for model_name, result in results.items():
print(f"\n{model_name} Results:")
print(json.dumps(result, indent=2))
# Save results to file
output_file = "gpt4o_evaluation_results.json"
with open(output_file, 'w') as f:
json.dump(results, f, indent=2)
print(f"\nResults saved to {output_file}")
return results

if __name__ == "__main__":
gt_file = "paper_abstracts.jsonl"
asyncio.run(run_evaluations(gt_file))
우리의 평가는 Weave의 견고한 프레임워크를 활용하여 Azure의 GPT-4o 모델이 생성한 요약을 기준 진실 초록과 체계적으로 비교합니다. 사전에 생성된 출력물에 초점을 맞춤으로써, 추가 추론 비용 없이 반복 평가를 수행할 수 있는 간소화된 절차를 구현합니다. 이러한 설계는 디버깅을 단순화하고, 지표의 반복적 개선을 촉진하며, 생성된 ���약을 평가할 때 일관성을 보장합니다.
모델 성능을 구분하기 위해 두 가지 명확한 클래스를 정의합니다 — GPT4o 그리고 GPT4oMini 각자의 설정에 맞게 조정되며 W&B Weave의 평가 대시보드에서 개별 엔티티로 표시됩니다. 이를 통해 두 결과를 나란히 비교할 때 명확성과 정밀성이 보장됩니다.

종합적인 평가 지표

평가는 모델 성능을 전체적으로 파악할 수 있도록 다음과 같은 지표 모음을 포함합니다:
  • ROUGE: 포착 엔그램 그리고 생성된 요약과 정답 요약 간의 시퀀스 중복도입니다.
  • 커버리지: 생성된 요약에서 원문 초록의 핵심 콘텐츠가 얼마나 잘 보존되었는지를 측정합니다.
  • 압축 비율: 요약의 간결함과 세부 정보 보존 간의 균형을 평가합니다.
  • BERTScore: 텍스트의 문맥 임베딩을 비교하여 의미적 유사성을 평가합니다.
  • LLM 평가자: GPT-4o를 활용해 요약문의 정합성, 정확성, 완전성을 평가하는 맞춤형 채점 방식.
어휘적, 의미적, 구조적 평가를 결합함으로써, 이 프레임워크는 각 모델의 강점과 약점을 심층적으로 평가합니다.

맞춤형 점수화 통합

평가를 고도화하기 위해 맞춤형 LLM 평가자 점수기가 개발되었으며, 이를 통해 GPT-4o가 정답 초록과의 정합성을 기준으로 자신의 출력을 채점할 수 있습니다. 이 점수 방식은 Weave의 파이프라인에 매끄럽게 통합되어 데이터셋 전반에서 자동 로깅과 비교를 가능하게 하며, 반복적인 모델 분석에 필수적인 도구가 됩니다. 복잡한 워크플로에는 커스텀 클래스가 높은 유연성을 제공하지만, 더 단순한 시나리오에서는 기본 점수 함수도 사용할 수 있어 다양한 요구에 맞춘 적응성을 제공합니다.

Weave로 직관적인 시각화

Weave의 인터랙티브 대시보드는 평가 결과를 상세한 시각화로 제공하여 분석을 간소화합니다. 팀은 직관적인 인터페이스에서 모델 출력, 성능 지표, 비교 인사이트를 탐색할 수 있습니다. 이를 통해 개선이 필요한 영역을 명확히 파악하고 실용적인 의사결정을 내릴 수 있습니다.
구조화된 평가, 맞춤형 점수화 방식, 통찰력 있는 시각화의 조합은 Weave가 조직이 GPT 모델을 효과적으로 분석하고 개선하도록 어떻게 지원하는지 보여 줍니다. 정량적 엄밀성과 사용성을 연결함으로써, Weave는 다양한 사용 사례 전반에서 모델 성능을 최적화하기 위한 핵심 프레임워크를 제공합니다.


여기서 우리는 GPT-4o 모델이 LLM judge 점수, ROUGE-L, ROUGE-1, 압축 비율, BERTScore를 포함한 여러 핵심 지표에서 GPT-4o Mini 모델을 소폭 상회함을 확인합니다. GPT-4o는 정답 초록과의 정합성이 더 높아 구조적 및 구문 수준의 유사성을 더 많이 포착하며, 간결성과 정보 보존 간의 균형에서도 우수한 성과를 보입니다. 이러한 결과는 의미적으로 정확하고 구조적으로 잘 정돈된 출력을 생성하는 데 있어 GPT-4o의 효과성을 강조합니다.
반면 GPT-4o Mini는 효율성과 세부 정보 보존 면에서 강점을 보입니다. 입력 세부 정보를 �� 잘 보존함을 나타내는 높은 coverage 점수를 유지하며, 추론 지연이 크게 낮아 속도가 훨씬 빠릅니다. 따라서 속도와 리소스 효율이 중요한 애플리케이션에 더 적합합니다.
Weave Evaluations는 이러한 인사이트를 발굴하는 데 매우 유용함이 입증되었으며, 모델이 뛰어난 점과 부족한 점을 드러내고 이러한 차이가 실제 의사결정에 어떤 영향을 미치는지 강조합니다. 지표와 출력물 전반에서 상세한 나란히 비교를 가능하게 함으로써, Weave는 조직이 성능과 효율성 목표에 가장 잘 부합하는 모델을 식별할 수 있는 실용적인 프레임워크를 제공합니다.
이러한 분석은 모델 간 트레이드오프를 이해하는 데 필수적이며, 조직이 AI 투자를 최적화할 수 있도록 합니다. Weave가 정량적·정성적 비교를 모두 제공하기 때문에, ML 엔지니어는 단순 지표를 넘어 운영상의 정합성에 집중하여 특정 사용 사례에 가장 적합한 모델을 선택할 수 있습니다. 다음은 비교 보기의 스크린샷입니다!

왜 Azure AI를 선택할까?

Azure AI는 다음과 같은 작업을 수행하기에 견고한 플랫폼을 제공합니다 대규모 언어 모델, 다양한 작업을 위해 설계된 폭넓은 모델에 접근할 수 있도록 합니다. 이러한 다양성 덕분에 고유한 요구 사항에 가장 잘 부합하는 모델을 선택할 수 있습니다. Microsoft Azure 에코시스템과의 매끄러운 통합을 통해 배포와 데이터 관리를 간소화하여 생산성과 운영 효율을 높일 수 있습니다.
Azure AI의 확장성은 모델 배포를 수요 변화에 맞춰 손쉽게 조정할 수 있도록 하여, 다양한 워크로드 전반에서 최적의 성능을 제공합니다. 이 플랫폼은 보안과 컴플라이언스를 최우선으로 하며, Microsoft의 엄격한 기준을 준수하는 강력한 데이터 보호 조치를 적용해 민감한 정보를 안전하게 보호합니다. Azure의 고성능 클라우드 인프라가 뒷받침되어, 안정적이고 효율적인 모델 운영을 보장하고 폭넓은 애플리케이션에 걸쳐 일관되고 고품질의 결과를 제공합니다.

Azure AI와 W&B Weave로 성능 평가

Azure AI와 W&B Weave를 활용하여 GPT-4o와 GPT-4o Mini의 성능을 LLM 기반 판정 점수를 포함한 핵심 지표 전반에서 평가했습니다. 그 결과, GPT-4o는 정확하고 간결한 요약을 생성하는 데서 두드러졌으며, ROUGE-L, ROUGE-1, 압축률(compression ratio) 및 LLM 판정 점수 등 여러 지표에서 GPT-4o Mini를 앞섰습니다.
하지만 GPT-4o Mini는 효율성 측면에서 강점을 보이며, 더 빠른 추론 시간과 더 높은 커버리지 점수를 달성해 핵심 입력 정보를 보존하는 능력을 보여줍니다. 따라서 속도에 민감하거나 리소스가 제한된 애플리케이션에 매우 효과적인 선택지입니다.
Azure AI의 확장 가능한 인프라와 Weave의 고급 평가 도구를 결합한 힘을 통해, 속도, 정확도, 전반적 효율성 등 무엇을 중시하든 사용자는 자신의 우선순위에 맞는 모델을 선택할 수 있는 통찰을 얻습니다.






이 글은 AI 번역본입니다. 오역이 의심되는 부분이 있으면 댓글로 알려주세요. 원문 보고서는 아래 링크에서 확인하실 수 있습니다: 원문 보고서 보기