Advanced

Evaluating and Optimizing LLM Agents

Measure agent quality and move from custom metrics to production observability dashboards.

Table of Contents

  1. Course Overview
  2. Key Technologies
  3. Prerequisites and Installation
  4. Module 1 — Measuring Agent Quality
  5. Module 2 — From Custom Metrics to Production Dashboards
  6. Overall Pipeline Architecture
  7. Best Practices
  8. Common Challenges and Solutions

Course Overview

This course covers essential techniques for evaluating and optimizing LLM (Large Language Model) agents in production environments, focusing on performance, reliability, and cost-effectiveness.

What You Will Learn

  • Evaluate LLM agents with industry-standard tools (G-Eval, DeepEval, LangSmith)
  • Apply comprehensive metrics for quality, cost, and latency evaluation
  • Build custom evaluation tests and benchmarks
  • Optimize agent performance for real production deployment
  • Set up monitoring and observability for LLM agents

Course Structure

Module 1: Measuring Agent Quality         (23m 7s)
 ├── Clip 1: Why and What to Measure
 └── Clip 2: Advanced Evaluation with G-Eval and DeepEval

Module 2: From Custom Metrics to Production Dashboards  (19m 49s)
 ├── Clip 1: Task-specific Testing and Open-RAG-Eval
 └── Clip 2: Holistic Tuning + LangSmith Observability

Key Technologies

ToolRole
DeepEvalReal-time evaluation framework (relevance, hallucination)
G-EvalLLM-as-a-Judge method (GPT-4o as judge)
Open-RAG-EvalCustom evaluation for RAG pipelines
LangSmithObservability, traces, costs, and production metrics
LangChainFramework for LLM applications
StreamlitWeb interface for interactive demos
ChromaVector database for embeddings
OpenAI APIGPT models and embeddings

Prerequisites and Installation

git clone https://github.com/example/Evaluate-Optimize-LLM-Agents.git
cd Evaluate-Optimize-LLM-Agents

python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

pip install -r requirements.txt

API Keys Configuration

OPENAI_API_KEY=your_openai_api_key_here
LANGCHAIN_API_KEY=your_langsmith_api_key_here
LANGCHAIN_TRACING_V2=true
LANGCHAIN_PROJECT=your_project_name

Never commit API keys to version control. Always use environment variables.


Module 1 — Measuring Agent Quality

1.1 Why and What to Measure

5 essential reasons to evaluate:

  1. Trust, quality, and adoption are directly linked — no trust → no usage → no value
  2. LLMs are probabilistic by nature — results vary even with excellent prompts
  3. “You can’t optimize what you don’t measure” — without metrics, you guess instead of guide
  4. Hallucinations and off-topic responses quickly erode credibility
  5. Evaluation creates a feedback loop to detect regressions and continuously improve

Key Metrics to Measure

MetricDescription
RelevanceDoes the response directly address the question?
CorrectnessIs the content factually correct?
Hallucination rateHow often does the agent invent facts?
Contextual fitIs the response supported by the retrieved context?

Evaluation Approach Comparison

graph LR
    subgraph Traditional Methods
        A[BLEU] --> D[Token overlap comparison]
        B[ROUGE] --> D
    end
    subgraph Semantic Methods
        E[Vector Embeddings] --> F[Cosine Similarity]
    end
    subgraph LLM-as-a-Judge
        G[G-Eval / GPT-4o] --> H[Score 1-10 + Explainable rationale]
    end
ApproachStrengthsWeaknesses
BLEU/ROUGE/F1Fast, reproducible, no LLM neededDoesn’t capture LLM creative variability
Semantic embeddingsCompares meaning, not just tokensNot always aligned with human judgment
LLM-as-a-Judge (G-Eval)Scalable, explainable, no reference labels neededDepends on another LLM, additional cost

1.2 Demo — DeepEval Integration

pip install deepeval
from deepeval import evaluate
from deepeval.test_case import LLMTestCase
from deepeval.metrics import AnswerRelevancyMetric, HallucinationMetric

def evaluate_response(prompt, answer, retriever):
    context_docs = retriever.invoke(prompt)
    context_chunks = [doc.page_content for doc in context_docs]

    test_case = LLMTestCase(
        input=prompt,
        actual_output=answer,
        retrieval_context=context_chunks
    )

    metrics = [
        AnswerRelevancyMetric(),
        HallucinationMetric()
    ]

    result = evaluate(
        test_cases=[test_case],
        metrics=metrics
    )

    return result

DeepEval Data Flow

sequenceDiagram
    participant U as User
    participant S as Streamlit App
    participant R as Retriever (Chroma)
    participant L as LangChain LLM
    participant D as DeepEval (GPT-4o)

    U->>S: Asks a question
    S->>R: retriever.invoke(prompt)
    R-->>S: context_docs
    S->>L: llm_chain.invoke(question)
    L-->>S: answer
    S->>D: evaluate(LLMTestCase)
    D-->>S: scores + statuses
    S-->>U: Response + displayed metrics

1.3 G-Eval: LLM-as-a-Judge

Instead of relying on semantic metrics like BLEU, we ask another LLM (GPT-4o) to act as an impartial judge. It examines the original question, the retrieved context, and the generated response, then assigns a score from 1 to 10 with an explanation.

G-Eval Prompt Structure:

1. ROLE: "You are an impartial evaluator..."
2. INPUTS:
   • Original user question
   • Context retrieved from knowledge base
   • Response generated by LLM agent
3. CRITERIA: Relevance, Accuracy, Groundedness
4. OUTPUT FORMAT:
   • Numeric score from 1 to 10
   • Rationale in one sentence
5. temperature = 0  ← CRITICAL for reproducibility

Single Judge vs. Multi-Judge Ensemble

graph TB
    subgraph Single Judge
        SJ[GPT-4o] --> SR[Single score + Rationale]
    end
    subgraph Multi-Judge Ensemble
        MJ1[GPT-4o] --> MA[Average score or vote]
        MJ2[Claude] --> MA
        MJ3[Gemini] --> MA
    end

For critical domains (compliance, finance, healthcare), prefer a multi-judge ensemble.

1.4 Demo — G-Eval Implementation

import os
from openai import OpenAI

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def judge(question: str, context_docs: list, answer: str) -> str:
    context_texts = [doc.page_content for doc in context_docs]
    context_str = " ".join(context_texts)[:1500]

    prompt = f"""You are an impartial evaluator. Rate the following response
on a scale from 1 to 10 based on:
- Relevance: Does the response directly address the question?
- Accuracy: Are the facts correct?
- Groundedness: Is the response anchored in the provided context?

Question: {question}

Retrieved context:
{context_str}

Agent response:
{answer}

Provide ONLY: "Score: X/10 - Rationale: [one sentence explanation]"
"""

    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}],
        temperature=0   # CRITICAL: same prompt = same score every time
    )

    return response.choices[0].message.content

Module 2 — From Custom Metrics to Production Dashboards

2.1 Task-Specific Tests and Stress Tests

Limitations of generic metrics:

Generic metrics like accuracy and relevance scores are useful as a baseline but insufficient for enterprise use cases (regulatory compliance, citation fidelity, PII risks).

Open-RAG-Eval Use Cases:

Use CaseDescription
RobustnessSystematic tests on diverse and challenging situations
Domain specificityCitation accuracy and PII compliance evaluation
Stress testingBehavior under load (ambiguous queries, multi-step, edge cases)
CI/CDIntegration into continuous deployment pipelines

2.2 Demo — Open-RAG-Eval

Configuration file my_rag.yaml:

evaluator:
  type: TRECEvaluator
  model:
    type: OpenAIModel
    name: gpt-4o
    api_key: ${env:OPENAI_API_KEY}

results_folder: scored_results
generated_answers: "rag_results.csv"
eval_results_file: eval_results.csv

metrics:
  - answer_relevancy
  - hallucination
  - citation_accuracy

Results generation script:

import os
import pandas as pd
from dotenv import load_dotenv
import time

load_dotenv()

DELAY_BETWEEN_QUERIES = 4   # max ~15 requests/minute

# Load documents
docs = load_txt_files("data")
retriever = ensemble_retriever_from_docs(docs, embeddings=embeddings)
chain, _ = create_full_chain(retriever, openai_api_key=os.getenv("OPENAI_API_KEY"))

df = pd.read_csv("data/queries.csv")
rows = []

for idx, q in enumerate(df["query"]):
    response = chain.invoke({"question": q, "chat_history": []})
    answer = response.content

    context_docs = retriever.invoke(q)
    context = " ".join([doc.page_content for doc in context_docs])[:1500]

    time.sleep(2)
    g_eval_score = judge(q, context_docs, answer)

    rows.append({
        "query": q,
        "generated_answer": answer,
        "passage_id": idx,
        "passage": context_docs[0].page_content if context_docs else "",
        "context": context,
        "g_eval": g_eval_score
    })

    time.sleep(DELAY_BETWEEN_QUERIES)

pd.DataFrame(rows).to_csv("rag_results.csv", index=False)

CI/CD Integration:

name: Evaluate RAG System
on: [push, pull_request]

jobs:
  evaluate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Install dependencies
        run: pip install -r requirements.txt
      - name: Generate RAG results
        run: python generate_rag_results.py
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      - name: Check metrics (quality gates)
        run: python check_metrics.py

2.3 Holistic Optimization: Cost, Latency, and Quality

The Observability Triad

graph TD
    CENTER((Observability\nTriad))
    CENTER --> Q[QUALITY\nRelevant, correct\nand useful responses]
    CENTER --> C[COST\nToken tracking\nper response]
    CENTER --> L[LATENCY\nSystem speed\nSmooth experience]
    Q -.->|tradeoff| C
    C -.->|tradeoff| L
    L -.->|tradeoff| Q
DimensionWhat to MeasureKey Question
QualityRelevance, correctness, actionabilityIs the response truly useful?
CostTokens per response, cost per requestIs the approach cost-effective at scale?
LatencyAverage response time, P95Does the experience feel responsive?

2.4 Demo — Monitoring with LangSmith

3-step integration:

# Step 1: Get a LangSmith API key (free registration at smith.langchain.com)
# Step 2: Install dependency
pip install langsmith

# Step 3: Configure in .env
LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=your_langsmith_api_key
LANGCHAIN_PROJECT=rag_system

Automatic tracing — Zero additional code:

import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = "rag_system"

# All LangChain operations are automatically traced
chain = create_full_chain(retriever, openai_api_key=openai_api_key)
result = chain.invoke({"question": "Is it healthy to eat broccoli every day?"})
# → The full trace appears automatically in LangSmith

Custom evaluation with LangSmith client:

from langsmith import Client
from langsmith.evaluation import evaluate

client = Client()

def custom_quality_evaluator(run, example):
    output = run.outputs.get("answer", "")
    input_text = example.inputs.get("question", "")

    score = judge(input_text, [], output)

    return {
        "key": "custom_quality",
        "score": int(score.split("/")[0].split(": ")[1]) / 10,
        "comment": score
    }

results = evaluate(
    lambda inputs: chain.invoke(inputs),
    data="my-test-dataset",
    evaluators=[custom_quality_evaluator],
    experiment_prefix="rag-evaluation"
)

Overall Pipeline Architecture

flowchart LR
    A[User Question] --> B[LangChain RAG Pipeline]
    B --> C[Chroma Vector Store]
    B --> D[OpenAI GPT-4o]
    C --> E[Generated Response]
    D --> E
    E --> F[DeepEval\nReal-time scoring]
    E --> G[G-Eval\nLLM-as-a-Judge]
    E --> H[LangSmith\nObservability]
    F --> I[Quality Dashboard]
    G --> I
    H --> I

Best Practices

AspectRecommendation
Clear criteriaExplicitly define evaluation criteria
Regular updatesKeep evaluations current with business needs
Multiple perspectivesCombine automated metrics, LLM-judge, and human feedback
Continuous improvementIterate on evaluation design
SecurityNever commit API keys; always use environment variables

Common Challenges and Solutions

ChallengeSolutionBest Practice
High trace volumeImplement sampling and filteringSmart sampling strategies
Evaluation biasUse diverse evaluation methodsRegular bias audits
Monitoring impactAsynchronous monitoringBalance depth vs performance
Ground truth qualityExpert annotations and consensusRegular review and updates
Metric selectionAlign metrics with business objectivesStart simple, add gradually
Context window limitsContext compression, sliding windowSemantic chunking

Search Terms

evaluating · optimizing · llm · agents · llmops · model · governance · artificial · intelligence · generative · ai · deepeval · g-eval · measure · metrics · quality

Interested in this course?

Contact us to book it or get a custom training plan for your team.