eaglelandsonce's picture
Update index.html
5507840 verified
Raw
History Blame Contribute Delete
13.5 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>LLM Workflow Evaluation Tic Tac Toe</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gradient-to-br from-indigo-50 via-sky-50 to-teal-100 min-h-screen flex items-center justify-center p-4">
<div class="max-w-6xl w-full bg-white rounded-2xl shadow-xl p-6">
<h1 class="text-3xl font-extrabold mb-3 text-center text-indigo-800">LLM Workflow Evaluation Tic Tac Toe</h1>
<p class="text-center mb-2 text-sm text-gray-600">
Reference: <a href="https://www.linkedin.com/pulse/evaluating-generative-ai-workflows-llm-inputs-michael-lively-okp7e/" class="text-indigo-600 hover:underline" target="_blank" rel="noopener noreferrer">Evaluating Generative AI Workflows: LLM Inputs</a>
</p>
<p class="text-center mb-4 text-sm text-gray-500">
Answer correctly to claim a square. Miss the question, and your turn passes.
</p>
<div id="banner" class="hidden bg-indigo-100 border border-indigo-300 text-indigo-800 font-bold text-center py-2 rounded mb-4"></div>
<div class="flex flex-col lg:flex-row items-center lg:items-start justify-center gap-5">
<!-- Game Board -->
<div id="board" class="grid grid-cols-3 gap-2 border-4 border-indigo-300 rounded-xl p-3 bg-indigo-50"></div>
<!-- Question Panel -->
<div id="questionPanel" class="w-full lg:w-1/2 bg-gray-50 rounded-xl shadow p-5 min-h-80">
<h2 id="panelQuestion" class="text-xl font-semibold text-gray-800">Select a square to view the question</h2>
<ul id="panelChoices" class="mt-4 space-y-2"></ul>
<p id="panelHint" class="mt-3 text-sm text-gray-600 hidden"></p>
<button id="hintBtn" class="mt-4 px-3 py-1 bg-gray-200 text-gray-700 rounded hover:bg-gray-300">Show Hint</button>
</div>
</div>
<div class="flex flex-col sm:flex-row justify-between items-center gap-3 mt-6">
<p id="status" class="text-lg font-medium text-gray-800"></p>
<button id="restartBtn" class="px-4 py-2 bg-indigo-600 text-white rounded hover:bg-indigo-700">Restart</button>
</div>
</div>
<script>
const questions = [
{
question: 'What is the main goal of moving from plausible outputs to reliable LLM systems?',
choices: [
'To make responses sound more confident',
'To make outputs verifiable, consistent, and governed by protocol',
'To remove the need for evaluation rubrics',
'To increase randomness in every response'
],
answer: 2,
hint: 'Reliability is about evidence, repeatability, and governance.'
},
{
question: 'Why can a plausible but incorrect LLM output be dangerous in production?',
choices: [
'It is always visibly broken',
'It costs fewer tokens',
'It earns trust before eventually breaking it',
'It prevents users from reading the answer'
],
answer: 3,
hint: 'A fluent answer can hide a factual problem.'
},
{
question: 'Which three controllable inputs must be tuned together in an LLM workflow?',
choices: [
'Model, parameters, and prompts',
'Users, browsers, and databases',
'Labels, dashboards, and invoices',
'Latency, font size, and color palette'
],
answer: 1,
hint: 'These are the core levers of the system.'
},
{
question: 'In the framework, what does model selection primarily set?',
choices: [
'The hard ceiling on intelligence density, cost, and latency',
'The final color of the user interface',
'The number of people on the review team',
'The exact wording of every future prompt'
],
answer: 1,
hint: 'The model is the substrate for every output.'
},
{
question: 'What does temperature control in LLM generation?',
choices: [
'The maximum number of users',
'The probability distribution and randomness of token selection',
'The length of the source document',
'The number of model providers available'
],
answer: 2,
hint: 'Higher values usually create more varied outputs.'
},
{
question: 'Which parameter acts as the hard length ceiling for a response?',
choices: ['Top-p', 'Frequency penalty', 'Max tokens', 'Presence penalty'],
answer: 3,
hint: 'It limits how long the output can be.'
},
{
question: 'What is the purpose of stop sequences?',
choices: [
'To increase factual recall',
'To halt generation when a specific string pattern appears',
'To change the model provider',
'To score a gold dataset'
],
answer: 2,
hint: 'They stop output based on a pattern, not just length.'
},
{
question: 'Which prompt layer provides source documents, retrieved context, and conversation history?',
choices: ['Instruction', 'Context', 'Constraints', 'Reasoning'],
answer: 2,
hint: 'This layer gives the model background material.'
},
{
question: 'Which prompt layer uses few-shot patterns to show the desired style, tone, and format?',
choices: ['Examples', 'Stop sequences', 'Gold datasets', 'Temperature'],
answer: 1,
hint: 'It gives the model a blueprint to imitate.'
},
{
question: 'Why should prompt quality not be judged from a single run?',
choices: [
'A single output is only one sample from a distribution',
'One run always uses too many tokens',
'Evaluation never applies to prompts',
'The model cannot answer twice'
],
answer: 1,
hint: 'Reliability requires repeated trials.'
},
{
question: 'Which evaluation quality measures how consistent outputs are across repeated trials?',
choices: ['Relevance', 'Variability', 'Coherence', 'Latency'],
answer: 2,
hint: 'It tracks how much the answer changes from run to run.'
},
{
question: 'For Q&A workflows, what should success be defined by?',
choices: [
'How polished the answer sounds',
'How long the answer is',
'Factual groundedness in the source',
'How creative the response feels'
],
answer: 3,
hint: 'Fluency is never a substitute for accuracy.'
},
{
question: 'What is a gold dataset used for?',
choices: [
'Changing the UI theme',
'Curated ground-truth examples for benchmarking',
'Randomizing token probabilities',
'Removing all human review'
],
answer: 2,
hint: 'It gives the team trusted examples to test against.'
},
{
question: 'Which lifecycle step tracks prompt_v1 versus prompt_v2 with names, timestamps, and deltas?',
choices: ['Define', 'Experiment', 'Version', 'Monitor'],
answer: 3,
hint: 'This creates traceability across iterations.'
},
{
question: 'If failures come from irrelevant retrieved context or truncated source material, what type of issue is it?',
choices: ['Prompt issue', 'Data/context issue', 'Model limit', 'UI issue'],
answer: 2,
hint: 'The fix is usually to improve the data pipeline.'
},
{
question: 'If the task exceeds reasoning capacity, complex arithmetic, or context-window constraints, what is the likely failure category?',
choices: ['Model limits', 'Prompt color', 'Version logs', 'Presence penalty'],
answer: 1,
hint: 'The fix may be to switch models or adjust scope.'
}
];
let currentPlayer, boardState, cellQuestions, selectedCell;
const boardEl = document.getElementById('board');
const statusEl = document.getElementById('status');
const bannerEl = document.getElementById('banner');
const hintBtn = document.getElementById('hintBtn');
const panelQuestion = document.getElementById('panelQuestion');
const panelChoices = document.getElementById('panelChoices');
const panelHint = document.getElementById('panelHint');
const restartBtn = document.getElementById('restartBtn');
function shuffle(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
}
function buildBalancedPositions(nQuestions, kChoices) {
const base = Math.floor(nQuestions / kChoices);
const remainder = nQuestions % kChoices;
const slots = [];
for (let pos = 1; pos <= kChoices; pos++) {
for (let c = 0; c < base; c++) slots.push(pos);
}
const extra = shuffle(Array.from({ length: kChoices }, (_, i) => i + 1)).slice(0, remainder);
slots.push(...extra);
return shuffle(slots);
}
function initGame() {
currentPlayer = 'X';
boardState = Array(9).fill('');
selectedCell = null;
bannerEl.classList.add('hidden');
statusEl.innerText = '';
const shuffledQs = shuffle([...questions]).slice(0, 9);
const kChoices = 4;
const targetPositions = buildBalancedPositions(shuffledQs.length, kChoices);
cellQuestions = shuffledQs.map((q, idx) => {
const originalCorrectIdx0 = q.answer - 1;
const correctText = q.choices[originalCorrectIdx0];
const wrongs = q.choices.filter((_, i) => i !== originalCorrectIdx0);
shuffle(wrongs);
const targetPos1 = targetPositions[idx];
const targetPos0 = targetPos1 - 1;
const newChoices = Array(kChoices).fill(null);
newChoices[targetPos0] = correctText;
let w = 0;
for (let i = 0; i < kChoices; i++) {
if (newChoices[i] === null) newChoices[i] = wrongs[w++];
}
return {
question: q.question,
choices: newChoices,
answer: targetPos1,
hint: q.hint
};
});
panelQuestion.innerText = 'Select a square to view the question';
panelChoices.innerHTML = '';
panelHint.classList.add('hidden');
panelHint.innerText = '';
renderBoard();
}
function renderBoard() {
boardEl.innerHTML = '';
boardState.forEach((mark, idx) => {
const btn = document.createElement('button');
let cls = 'bg-white h-24 w-24 sm:h-28 sm:w-28 flex items-center justify-center text-4xl font-extrabold rounded-lg shadow hover:bg-indigo-100 transition';
if (mark === 'X') cls += ' text-blue-600';
if (mark === 'O') cls += ' text-red-600';
btn.className = cls;
btn.innerText = mark;
btn.disabled = mark !== '';
btn.addEventListener('click', () => openQuestion(idx));
boardEl.appendChild(btn);
});
statusEl.innerText = `Current: ${currentPlayer}`;
}
function openQuestion(idx) {
if (boardState[idx] !== '') return;
selectedCell = idx;
const q = cellQuestions[idx];
panelQuestion.innerText = q.question;
panelChoices.innerHTML = '';
panelHint.classList.add('hidden');
panelHint.innerText = q.hint;
q.choices.forEach((choiceText, i) => {
const li = document.createElement('li');
const btn = document.createElement('button');
btn.innerText = choiceText;
btn.className = 'w-full text-left px-4 py-2 bg-indigo-50 rounded hover:bg-indigo-100 border border-indigo-100';
btn.addEventListener('click', () => handleAnswer(i + 1));
li.appendChild(btn);
panelChoices.appendChild(li);
});
}
function handleAnswer(choice) {
if (selectedCell === null) return;
const q = cellQuestions[selectedCell];
if (choice === q.answer) {
boardState[selectedCell] = currentPlayer;
panelChoices.innerHTML = '';
panelHint.classList.add('hidden');
panelQuestion.innerText = 'Correct! Select another open square.';
renderBoard();
if (checkWin()) return endGame(`${currentPlayer} wins!`);
if (boardState.every(c => c)) return endGame('Stalemate!');
} else {
alert('Incorrect! Turn missed.');
}
currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
statusEl.innerText = `Current: ${currentPlayer}`;
selectedCell = null;
}
function checkWin() {
const wins = [
[0,1,2], [3,4,5], [6,7,8],
[0,3,6], [1,4,7], [2,5,8],
[0,4,8], [2,4,6]
];
return wins.some(combo => combo.every(i => boardState[i] === currentPlayer));
}
function endGame(msg) {
bannerEl.innerText = `🎉 ${msg}`;
bannerEl.classList.remove('hidden');
document.querySelectorAll('#board button').forEach(b => b.disabled = true);
panelQuestion.innerText = msg;
panelChoices.innerHTML = '';
panelHint.classList.add('hidden');
}
hintBtn.addEventListener('click', () => {
if (selectedCell !== null) panelHint.classList.toggle('hidden');
});
restartBtn.addEventListener('click', initGame);
initGame();
</script>
</body>
</html>