DeepEval 을 사용하여 RAG 시스템 평가를 위한 Golden Question & Answer 을 만들 때 생각보다 관련 자료가 부족해 동작하는 코드를 작성하기까지 많은 시행착오에 부딪혀 이를 정리해보고자 한다.
DeepEval 공식 홈페이지의 예제 코드를 보면 model 만 변경해서 넣는 코드만 나온다. 그러나 내가 이를 실행해봤을때 Synthesizer 클래스는 지속해서 OpenAI API Key 가 없다는 에러를 발생시켰다.
결론은 DeepEvalBaseLLM 뿐만아니라 DeepEvalBaseEmbeddingModel 역시 정의되어 Synthesizer 에 넘겨주어야한다. (뒤돌아 생각해보면 너무 당연하다. 임베딩 모델이 있어야 텍스트를 임베딩해서 골든 문장을 만들던가 말던가..)
"""
공식 문서 예제를 사용해 DeepEvalBaseLLM 을 상속받는
커스텀 DeepEval LLM Model 클래스 작성
"""
from deepeval.models.base_model import DeepEvalBaseLLM
class TestGoogleGenerativeAI(DeepEvalBaseLLM):
"""Class to implementGoogle Geverative AI for DeepEval"""
def __init__(self, model):
self.model = model
def load_model(self):
return self.model
def generate(self, prompt: str) -> str:
chat_model = self.load_model()
return chat_model.invoke(prompt).content
async def a_generate(self, prompt: str) -> str:
chat_model = self.load_model()
res = await chat_model.ainvoke(prompt)
return res.content
def get_model_name(self):
return "Google Generative AI Model"
"""
langchain_google_genai 라이브러리를 사용해서 gemini 모델 객체를 생성한 후
위에서 작성한 커스텀 클래스를 사용해 deep eval LLM 모델 객체 생성
"""
from langchain_google_genai import ChatGoogleGenerativeAI
gemini = ChatGoogleGenerativeAI(
model="gemini-2.5-flash",
temperature=0
)
deep_eval_gemini = TestGoogleGenerativeAI(model=gemini)
"""
공식 문서의 DeepEvalBaseEmbeddingModel을 상속받는 예제코드를 사용해
gemini embedding model을 사용하는 embedding model 클래스 정의
"""
from langchain_google_genai import GoogleGenerativeAIEmbeddings
from deepeval.models import DeepEvalBaseEmbeddingModel
class GeminiEmbeddingModel(DeepEvalBaseEmbeddingModel):
def __init__(self):
pass
def load_model(self):
embeddings = GoogleGenerativeAIEmbeddings(
model="gemini-embedding-2-preview"
)
return embeddings
def embed_text(self, text: str) -> list[float]:
embedding_model = self.load_model()
return embedding_model.embed_query(text)
def embed_texts(self, texts: list[str]) -> list[list[float]]:
embedding_model = self.load_model()
return embedding_model.embed_documents(texts)
async def a_embed_text(self, text: str) -> list[float]:
embedding_model = self.load_model()
return await embedding_model.aembed_query(text)
async def a_embed_texts(self, texts: list[str]) -> list[list[float]]:
embedding_model = self.load_model()
return await embedding_model.aembed_documents(texts)
def get_model_name(self):
"Custom gemini Embedding Model"
import os
import chromadb
from deepeval.synthesizer import Synthesizer
from deepeval.synthesizer.config import ContextConstructionConfig
synthesizer = Synthesizer(model = deep_eval_gemini)
goldens = synthesizer.generate_goldens_from_docs(
document_paths=[os.path.join(workspace, "tax_refund_info.pdf")],
context_construction_config=ContextConstructionConfig(
critic_model=deep_eval_gemini,
embedder=GeminiEmbeddingModel()
)
)
langchain_google_genai._common.GoogleGenerativeAIError: Error embedding content (RESOURCE_EXHAUSTED): 429 RESOURCE_EXHAUSTED. {'error': {'code': 429, 'message': 'You exceeded your current quota, please check your plan and billing details. For more information on this error, head to: https://ai.google.dev/gemini-api/docs/rate-limits. To monitor your current usage, head to: https://ai.dev/rate-limit. \n* Quota exceeded for metric: generativelanguage.googleapis.com/embed_content_free_tier_requests, limit: 100, model: gemini-embedding-2\nPlease retry in 27.289403086s.', 'status': 'RESOURCE_EXHAUSTED', 'details': [{'@type': 'type.googleapis.com/google.rpc.Help', 'links': [{'description': 'Learn more about Gemini API quotas', 'url': 'https://ai.google.dev/gemini-api/docs/rate-limits'}]}, {'@type': 'type.googleapis.com/google.rpc.QuotaFailure', 'violations': [{'quotaMetric': 'generativelanguage.googleapis.com/embed_content_free_tier_requests', 'quotaId': 'EmbedContentRequestsPerMinutePerUserPerProjectPerModel-FreeTier', 'quotaDimensions': {'location': 'global', 'model': 'gemini-embedding-2'}, 'quotaValue': '100'}]}, {'@type': 'type.googleapis.com/google.rpc.RetryInfo', 'retryDelay': '27s'}]}}
[Confident AI Synthesizer Log] SUCCESS: Successfully deleted: /tmp/deepeval_chroma_o560xmvi
[Confident AI Synthesizer Log] SUCCESS: Context Construction: Utilizing 0 out of 0 chunks.
잘 되다가 429 와 함께 에러. Google AI Studio 에서 확인해보니 임베딩하려는 pdf 파일크기가 꽤나 커 무료티어 임베딩 시간당 요청 횟수가 초과가 되어있었다. 애초 목적은 model 을 gemini 로 사용해보는 것 이었기 때문에 embedding 모델은 다른 무료 모델을 사용하는 것으로 바꾸어도 무방할 것으로 보임.
임베딩 모델을 설정해서 넘겨주지 않으면 Synthesizer 은 계속해서 OpenAI 임베딩 모델 사용을 위해 API key 를 요청한다.