This guide is designed to help developers understand, extend, and contribute to the EvalForge codebase.
EvalForge is structured as a monorepo containing:
backend/: A FastAPI-based asynchronous application serving the REST APIs, evaluation engine, and Celery tasks.frontend/: A React 19 single-page application built with TypeScript, Vite, Recharts, and Framer Motion.docker/: Deployment and local development Docker configuration files.docs/: Platform documentation and architectural decisions.examples/: Code snippets demonstrating integrations.
To add a new LLM judge or evaluation metric, follow the pluggable repository pattern:
All judges inherit from the abstract base class JudgeBase located at backend/app/evaluation/prompts/engine.py.
Example of creating a custom judge class:
from typing import Dict, Any
from app.evaluation.prompts.engine import JudgeBase, EvalResult
class CustomHumorJudge(JudgeBase):
"""Evaluates how humorous or engaging an LLM output is based on a structured rubric."""
def __init__(self, model_name: str = "gpt-4o-mini", api_key: str = None):
super().__init__(model_name=model_name, api_key=api_key)
async def evaluate(self, output: str, reference: str = None, config: Dict[str, Any] = None) -> EvalResult:
# 1. Compile prompt using Jinja templates
prompt = self.compile_template("humor_rubric.j2", output=output, reference=reference)
# 2. Call external LLM client
raw_response = await self.llm_client.generate(prompt)
# 3. Parse and calibrate score
score, reasoning = self.parse_json_result(raw_response)
normalized_score = self.calibrate_score(score, scale=(1, 5))
return EvalResult(
score=normalized_score,
reasoning=reasoning,
raw_output=raw_response
)Add your new judge implementation to the MetricRegistry class in backend/app/evaluation/pipelines/pipeline.py:
self.registry.register("humor", CustomHumorJudge)EvalForge follows a strict Repository-Service-Controller layered architecture:
- Schemas (
app/schemas/): Define the Pydantic v2 validation classes. - Repositories (
app/evaluation/repositories/): Encapsulate SQL queries and database operations. - Services (
app/services/orapp/evaluation/services/): Orchestrate transactions, validate quotas, and trigger async workers. - Routers (
app/api/v1/): Define HTTP verbs, parameters, and inject services.
Ensure your code is clean before committing:
cd backend
.venv/Scripts/ruff check app
.venv/Scripts/ruff format --check app
.venv/Scripts/pytestcd frontend
npm run lint
npm run build