Complete "Lesson 5: Error Handling and Reliability in Agent Systems" first to unlock this lesson.Go to previous lesson

Introduction

In the previous lessons you learned how to design prompts, connect to an AI API, and structure an agent workflow. This lesson ties everything together: you will build a complete AI-powered feature inside a real web app, from the user interface all the way to evaluation. The example feature we use throughout is an AI-powered code reviewer that takes a code snippet pasted by the user and returns feedback plus a quality score.

The goal is not to write perfect production code. The goal is to understand every layer of the stack — frontend form, backend endpoint, prompt, API call, response parsing, and testing — so you can repeat the pattern for any feature.

Project Structure

A small Node.js/Express app is enough to demonstrate the full flow. The backend exposes one route that accepts code text, sends it to the AI model, and returns structured feedback. The frontend is a simple HTML form that posts the snippet and renders the result.

sơ đồ kiến trúc 4 tầng của tính năng AI gồm frontend form, backend endpoint, AI API call, và response rendering
javascript
// server.js
import express from "express";
import { reviewCode } from "./agent.js";
const app = express();
app.use(express.json());
app.use(express.static("public"));
app.post("/api/review", async (req, res) => {
const { code } = req.body;
if (!code || code.length < 5) {
return res.status(400).json({ error: "Code snippet required" });
}
const result = await reviewCode(code);
res.json(result);
});
app.listen(3000, () => console.log("Server on http://localhost:3000"));

The Agent Layer

The agent is a plain module that owns the prompt template and the API call. Keeping it separate from the route handler makes it easy to test in isolation. The prompt asks the model to return JSON with a score and a list of issues, which removes the need for fragile string parsing later.

javascript
// agent.js
import OpenAI from "openai";
const client = new OpenAI();
export async function reviewCode(code) {
const prompt = `You are a senior code reviewer. Analyze the following code and respond ONLY with valid JSON in this exact shape:
{"score": <number 0-100>, "issues": [{"line": <number or null>, "severity": "low|medium|high", "message": "<text>"}], "summary": "<one sentence>"}
Code:
${code}`;
const response = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: prompt }],
temperature: 0.2,
response_format: { type: "json_object" }
});
return JSON.parse(response.choices[0].message.content);
}

The Frontend

The UI is intentionally minimal. A textarea for the code, a submit button, and a result panel. Posting JSON keeps the code consistent with the backend and avoids surprises with form encoding.

html
<form id="review-form">
<textarea id="code" rows="10" placeholder="Paste your code here"></textarea>
<button type="submit">Review</button>
</form>
<pre id="result"></pre>
<script>
document.getElementById("review-form").onsubmit = async (e) => {
e.preventDefault();
const code = document.getElementById("code").value;
const res = await fetch("/api/review", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ code })
});
const data = await res.json();
document.getElementById("result").textContent = JSON.stringify(data, null, 2);
};
</script>

Testing the Feature

Unit testing the agent directly is the fastest way to catch prompt regressions. Build a small test set of code snippets with expected score ranges and run them in a loop. If a prompt tweak makes one case worse, you will see it immediately.

sơ đồ vòng lặp test gồm 4 bước chạy test case, gọi agent, so sánh output với expected range, log kết quả
javascript
// test.js
import { reviewCode } from "./agent.js";
const cases = [
{ code: "def add(a,b): return a+b", expectMin: 70 },
{ code: "eval(input())", expectMax: 30 },
{ code: "function f(){ while(true){} }", expectMax: 40 }
];
for (const c of cases) {
const r = await reviewCode(c.code);
const ok = (c.expectMin ? r.score >= c.expectMin : true) &&
(c.expectMax ? r.score <= c.expectMax : true);
console.log(`${ok ? "PASS" : "FAIL"} score=${r.score} code=${c.code.slice(0,30)}`);
}

Common Pitfalls

Three issues come up again and again. First, not setting response_format to json_object when you need structured output, which causes silent parsing failures. Second, forgetting to validate input length on the server, which lets users send huge prompts and rack up costs. Third, testing only with perfect code, which never reveals how the model handles bugs. Always include at least one clearly bad snippet in your test set.

Summary

You now have a working pattern for shipping an AI feature: a thin frontend, an Express route, an isolated agent module that owns the prompt and the API call, and a small test suite that guards against regressions. Reuse this layout for summarizers, classifiers, chat assistants, or any other AI-powered tool you add to a web app.

Lesson practice

Lesson Checkpoint

Review what you learned and get feedback on your work.

0/1
Answered · 0/1