このレッスンのロックを解除するには、まず「レッスン5: エージェントシステムにおけるエラー処理と信頼性」を完了してください。前のレッスンに戻る

はじめに

previousレッスンでは、promptの設計、AI APIへの接続、エージェントワークフローの構造化方法を学びました。このレッスンではすべてを結びつけます:ユーザーインターフェースから評価まで、実際のWebアプリ内に完全なAI搭載機能を構築します throughout。例として使うのは、ユーザーが貼り付けたコードスニペットを受け取り、フィードバックと品質スコアを返すAI搭載のコードレビュアーです。

目標は完璧なプロダクションコードを書くことではありません。目標は、スタックのすべての層 — フロントエンドフォーム、バックエンドエンドポイント、prompt、API呼び出し、レスポンス解析、テスト — を理解することで、どんな機能にもこのパターンを再現できるようにすることです。

プロジェクト構成

Node.js/Expressの小規模アプリで全体像を示すのに十分です。バックエンドは1つのルートを公開し、コードテキストを受け取ってAIモデルに送信し、構造化されたフィードバックを返します。フロントエンドはスニペットを投稿して結果を表示するシンプルなHTMLフォームです。

フロントエンドフォーム、Backend endpoint、AI API call、response renderingで構成されるAI機能の4層アーキテクチャ図
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"));

エージェント層

エージェントはpromptテンプレートとAPI呼び出しを所有するシンプルなモジュールです。ルートハンドラーから分離することで、単独でテストしやすくなります。promptは、scoreとissueのリストを含むJSONを返すようモデルに要求するため、後で脆い文字列解析をする必要がなくなります。

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);
}

フロントエンド

UIは意図的に最小限にしています。コード用のtextarea、送信ボタン、結果パネルです。JSONでpostすることで、バックエンドとのコードの一貫性が保たれ、フォームエンコーディングに関する問題を回避できます。

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>

機能のテスト

エージェントを直接ユニットテストするのが、promptのリグレッションを最も速く検出する方法です。期待されるscore範囲を持つコードスニペットの小さなテストセットを作成し、ループで実行します。promptの調整によってあるケースの性能が悪化すれば、すぐにそれを確認できます。

test caseの実行、エージェントの呼び出し、出力とexpected rangeの比較、結果のログ記録からなる4ステップのテストループ図
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)}`);
}

よくある落とし穴

繰り返し遭遇する3つの問題があります。1つ目は、構造化された出力が必要なときにresponse_formatをjson_objectに設定しないことで、これによりサイレントな解析エラーが発生します。2つ目は、サーバー側で入力長的を検証しないことで、ユーザーが巨大なpromptを送信してコストが膨らむ原因となります。3つ目は、完全なコードだけでテストを行うことで、モデルがバグをどのように処理するかが決して明らかになりません。テストセットには少なくとも1つの明確に悪いスニペットを必ず含めてください。

まとめ

これでAI機能を出荷するための実用的なパターンを手にしました:薄いフロントエンド、Expressルート、promptとAPI呼び出しを所有する独立したエージェントモジュール、そしてリグレッションを防ぐテストスイートです。このレイアウトをサマライザー、分類器、チャットアシスタント、その他Webアプリに追加するAI搭載ツールにも再利用してください。

レッスンの練習

レッスンのチェックポイント

学んだ内容を復習し、回答へのフィードバックを受けましょう。

0/1
回答済み · 0/1