Skip to main content

Overview

Agent LoL’s AI Coaching feature uses OpenAI’s GPT-4 to analyze your early game performance and provide personalized coaching recommendations. The system compares your progression against your lane opponent, analyzing farm, gold, experience, and events to identify areas for improvement.
AI coaching requires an OpenAI API key and must be enabled with ENABLE_MATCH_AGENT=true in your environment variables.

How It Works

The AI coaching system uses a specialized endpoint that fetches match and timeline data, identifies lane matchups, and sends progression data to OpenAI for analysis.
1

Match Timeline Retrieval

The system fetches both match data and timeline data from the Riot API simultaneously.
// src/app/api/riot/match/timeline/compare/route.js:33-42
const [matchRes, timelineRes] = await Promise.all([
  fetch(RIOT_MATCH_URL(matchId), {
    headers: { 'X-Riot-Token': session.apiKey },
    cache: 'no-store',
  }),
  fetch(RIOT_TIMELINE_URL(matchId), {
    headers: { 'X-Riot-Token': session.apiKey },
    cache: 'no-store',
  }),
]);
2

Lane Opponent Identification

The system identifies your opponent in the same role/position.
// src/app/api/riot/match/timeline/compare/route.js:78-82
const enemySameRole = participants.find(
  (p) =>
    (p.teamPosition || p.individualPosition) === userRole &&
    Number(p.teamId) !== Number(userTeamId)
);
3

Progression Data Collection

Minute-by-minute data is collected from game start to the configured comparison time.
// src/app/api/riot/match/timeline/compare/route.js:94-101
const userFramesFromStart = [];
const enemyFramesFromStart = [];
for (let i = 0; i <= frameIndex && i < frames.length; i++) {
  const pf = frames[i]?.participantFrames ?? {};
  userFramesFromStart.push({ minute: i, ...(pf[userParticipantId] ?? {}) });
  enemyFramesFromStart.push({ minute: i, ...(pf[enemyParticipantId] ?? {}) });
}
4

GPT-4 Analysis

The progression data is sent to OpenAI’s GPT-4 model for analysis and coaching recommendations.

Timeline Comparison Configuration

The comparison window is configured using the TIMELINE_COMPARE environment variable:
// src/app/api/riot/match/timeline/compare/route.js:52-57
const compareMs = Math.max(0, parseInt(process.env.TIMELINE_COMPARE, 10) || 0);
const frameIndex = Math.min(
  Math.floor(compareMs / 60000),
  Math.max(0, frames.length - 1)
);
const frameMinute = frameIndex;
Set TIMELINE_COMPARE in milliseconds. Common values:
  • 300000 = 5 minutes (early laning phase)
  • 600000 = 10 minutes (extended laning phase)
  • 900000 = 15 minutes (pre-teamfight phase)

AI Prompt Engineering

The system uses a carefully crafted prompt to ensure relevant and actionable coaching:
// src/app/api/riot/match/timeline/compare/route.js:119-137
messages: [
  {
    role: 'system',
    content: `Eres un coach de League of Legends. Recibes la evolución minuto a minuto (desde el minuto 0 hasta el minuto ${frameMinute}) de dos jugadores en la misma posición/rol.
Analiza cómo fue la early game de cada uno: farm (minions), oro, nivel/XP a lo largo del tiempo. Responde en español, en 4-6 frases: quién se fue adelantando y en qué momento, tendencias (quién mejoró o empeoró), y una conclusión breve con qué podría mejorar el que va atrás. Sé directo y útil.`,
  },
  {
    role: 'user',
    content: `Rol/lane: ${userRole}.

Mi jugador (${userChampion}) - evolución desde min 0 hasta min ${frameMinute}:
${JSON.stringify(userFramesFromStart)}

Rival en la misma lane (${enemyChampion}) - evolución desde min 0 hasta min ${frameMinute}:
${JSON.stringify(enemyFramesFromStart)}

Dame feedback de la early game: cómo fue desde el inicio hasta el minuto ${frameMinute}.`,
  },
],

Prompt Breakdown

The AI coaching prompt is designed to:
  1. Set the role: “You are a League of Legends coach”
  2. Define the input: Minute-by-minute progression data for both players
  3. Specify analysis focus: Farm, gold, level/XP over time
  4. Request format: 4-6 sentences in Spanish
  5. Required insights:
    • Who got ahead and when
    • Performance trends over time
    • Specific improvement suggestions for the player who fell behind

Model Configuration

The OpenAI API call uses specific parameters for optimal coaching quality:
// src/app/api/riot/match/timeline/compare/route.js:116-118
body: JSON.stringify({
  model: 'gpt-4o-mini',
  temperature: 0.4,
  messages: [...]
}),

Model Parameters

  • Model: gpt-4o-mini - Fast, cost-effective GPT-4 variant
  • Temperature: 0.4 - Low temperature for consistent, focused analysis
  • Lower temperatures reduce creativity but increase reliability

API Response Handling

The coaching response is extracted and returned to the client:
// src/app/api/riot/match/timeline/compare/route.js:141-146
const openaiJson = await openaiRes.json();
if (openaiRes.ok) {
  comparison = openaiJson?.choices?.[0]?.message?.content?.trim() ?? null;
} else {
  console.error('OpenAI timeline compare error:', openaiJson);
}

Client-Side Integration

The coaching data is fetched on the client using React Query:
// src/components/LatestMatch.js:39-48
const timelineCompareQuery = useQuery({
  queryKey: queryKeys.matchTimelineCompare(firstMatchId, userGameName, userTagLine),
  queryFn: () =>
    fetchTimelineCompare(firstMatchId, {
      gameName: userGameName,
      tagLine: userTagLine,
    }),
  staleTime: 300000,
  enabled: !!firstMatchId && !!userGameName,
});

Service Function

// src/services/match.js:53-67
export async function fetchTimelineCompare(matchId, options = {}) {
  const params = new URLSearchParams({ matchId });
  if (options.gameName) params.set('gameName', options.gameName);
  if (options.tagLine) params.set('tagLine', options.tagLine);
  const response = await fetch(`/api/riot/match/timeline/compare?${params}`);
  const data = await response.json();
  if (!response.ok) throw data;
  return data;
}

Display in UI

Coaching recommendations are displayed below the timeline analysis:
// src/components/LatestMatch.js:143-163
{timelineCompare && (
  <div className="mt-6 rounded-xl bg-slate-800/50 border border-slate-700/50 overflow-hidden shadow-lg">
    <div className="px-5 py-4 sm:px-6 border-b border-slate-700/50">
      <h3 className="text-sm font-semibold text-slate-200 mb-1">
        Match Reviewer
      </h3>
      <p className="text-xs text-slate-500">
        {timelineCompare.userChampion} ({timelineCompare.role}) vs {timelineCompare.enemyChampion}
      </p>
    </div>
    <div className="px-5 py-4 sm:px-6">
      <TimelineReviewer
        timelineData={timelineData}
        participants={participants}
        userGameName={userGameName}
        userTagLine={userTagLine}
        timelineCompare={timelineCompare}
      />
    </div>
  </div>
)}

Recommendations Section

// src/components/TimelineReviewer.js:111-116
<div className="pt-2 border-t border-slate-700/50">
  <p className="font-medium text-slate-300 mb-1">Recomendations:</p>
  <p className="text-slate-400 leading-relaxed whitespace-pre-line">
    {comparison ?? '…'}
  </p>
</div>

Response Structure

The API returns a structured response with all relevant coaching data:
// src/app/api/riot/match/timeline/compare/route.js:152-160
return NextResponse.json({
  role: userRole,
  frameMinute,
  userChampion,
  enemyChampion,
  userFrame,
  enemyFrame,
  comparison,
});

Response Fields

  • role - Lane position (TOP, JUNGLE, MIDDLE, BOTTOM, UTILITY)
  • frameMinute - The frame/minute analyzed
  • userChampion - Your champion name
  • enemyChampion - Opponent’s champion name
  • userFrame - Your stats at the comparison frame
  • enemyFrame - Opponent’s stats at the comparison frame
  • comparison - GPT-4 coaching analysis (string)

Environment Variables

# Required for AI coaching
OPENAI_KEY=sk-proj-...
ENABLE_MATCH_AGENT=true

# Timeline comparison window (milliseconds)
TIMELINE_COMPARE=600000
If ENABLE_MATCH_AGENT is not set to true, AI coaching will be disabled even if OPENAI_KEY is present.

Error Handling

The system gracefully handles OpenAI API errors:
// src/app/api/riot/match/timeline/compare/route.js:147-149
catch (err) {
  console.error('Error calling OpenAI for timeline compare:', err);
}
If the OpenAI call fails, the response still includes match and timeline data, just without the AI-generated coaching text.

Best Practices

1

Set appropriate comparison windows

Early game (5-10 minutes) provides the most actionable coaching for laning phase.
2

Monitor API costs

Each coaching request uses GPT-4 tokens. Consider caching or rate limiting for production.
3

Handle API failures gracefully

Always provide useful data even if AI coaching is unavailable.

Next Steps

Stats Analysis

Understand the raw data behind AI coaching

Replay Viewer

Visualize the match in 2.5D

Build docs developers (and LLMs) love