- はじめに
- 第 1 章:全体像と「何が起きているか」
- 第 2 章:FastAPI の「入口」—— main.py
- 第 3 章:設定の読み込み —— config.py
- 第 4 章:API の「型」—— schemas.py
- 第 5 章:エンドポイントの定義 —— api/routes.py
- 第 6 章:RAGAS 評価の核 —— services/ragas_service.py
- 第 7 章:Docker でバックエンドを動かす
- 第 8 章:Next.js と API クライアント —— lib/api.ts
- 第 9 章:画面の実装 —— app/page.tsx
- 第 10 章:動かす手順とトラブルシューティング
- まとめ
はじめに
この記事では、RAG(検索拡張生成) の評価ツール「RAGAS」を、FastAPI(バックエンド)と Next.js(フロントエンド)で使い、Docker で動かすまでの一連の流れを、初学者向けにコードの意味から丁寧に解説します。
「RAGAS って何?」「FastAPI や Next.js を触ったことがない」「Docker は聞いたことはあるが使ったことがない」という方でも、この記事を読みながら実際に手を動かせば、以下のことを身につけられます。
| 技術 | 学べること |
|---|---|
| FastAPI | REST API を設計・実装する流れ |
| Next.js | フロントエンドから API を呼び出し、結果を表示する流れ |
| Docker | バックエンドをコンテナ化し、同じ環境を再現する方法 |
| RAGAS | RAG パイプラインの評価の基本 |
各章で「なぜそう書くか」を意識しながら、主要なコードを丁寧に説明していきます。
第 1 章:全体像と「何が起きているか」
1.1 このプロジェクトでやること
このプロジェクトでは、次のような「評価用 Web アプリ」を作成します。
① ユーザーがブラウザで入力
└─ 質問 / RAGが取得したコンテキスト / RAGが生成した回答 / 正解(reference)
② フロントエンド(Next.js)→ バックエンド(FastAPI)へ送信
③ バックエンドが RAGAS で評価
└─ Faithfulness / Context Recall / Factual Correctness などを計算
④ 評価スコアがフロントエンドへ返り、画面に表示
つまり、「RAG の入出力サンプル」を送ると「RAGAS の評価スコア」が返ってくる API と、その API を呼ぶ UI を用意します。
1.2 ディレクトリ構成
ragas_fast_api/
├── backend/ # FastAPI(Python)
│ ├── app/
│ │ ├── api/ # ルート(URL と処理の対応)
│ │ ├── services/ # RAGAS 評価ロジック
│ │ ├── config.py # 設定
│ │ ├── main.py # アプリの入口
│ │ └── schemas.py # リクエスト・レスポンスの型
│ ├── Dockerfile # バックエンド用コンテナの設計図
│ ├── requirements.txt # Python の依存パッケージ
│ └── .env.example # 環境変数の例
├── frontend/ # Next.js(TypeScript)
│ └── src/
│ ├── app/ # ページとレイアウト
│ └── lib/ # API 呼び出しなど共通ロジック
├── docker-compose.yml # コンテナの起動設定
└── README.md
| ディレクトリ | 役割 |
|---|---|
backend/ | サーバー側。「評価 API」の実装 |
frontend/ | ブラウザで動く画面。backend の API を呼ぶ |
docker-compose.yml | ポートや環境変数などの起動設定をまとめたファイル |
次の章から、この中の主要なファイルを 1 つずつ開きながら説明していきます。
第 2 章:FastAPI の「入口」—— main.py
2.1 FastAPI とは
FastAPI は、Python で Web API(REST API) を書くためのフレームワークです。
- パス(URL)と HTTP メソッド(GET / POST など)で「どの関数を実行するか」を決められる
- リクエストの body やレスポンスを 型 で定義すると、自動でバリデーションやドキュメント生成をしてくれる
- 非同期(
async)にも対応しており、I/O の多い API に適している
2.2 main.py の全体
# backend/app/main.py
import logging
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from app.api.routes import router
from app.config import get_settings
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)
logger = logging.getLogger(__name__)
app = FastAPI(
title="RAGAS Evaluation API",
description="RAG パイプラインを RAGAS で評価するための API。",
version="1.0.0",
)
settings = get_settings()
app.add_middleware(
CORSMiddleware,
allow_origins=settings.cors_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(router)
@app.get("/")
def root() -> dict:
return {
"service": "RAGAS Evaluation API",
"docs": "/docs",
"health": "/api/health",
"evaluate": "POST /api/evaluate",
}
2.3 各部分の解説
ロギング設定
logging モジュールで、アプリの動作ログを標準出力に出します。本番環境ではファイルや JSON 形式に変えることもできます。
app = FastAPI(...)
FastAPI() で「API 」を 1 つ作成します。title / description / version は Swagger UI(/docs)に表示され、API の説明になります。
CORS ミドルウェア
ブラウザでは「別オリジン(別ドメイン・別ポート)へのリクエスト」が制限されています。フロントエンド(例:http://localhost:3000)からバックエンド(例:http://localhost:8001)へリクエストするには、バックエンド側で CORS(Cross-Origin Resource Sharing) を許可する必要があります。
CORSMiddleware で「どのオリジンを許可するか」「どの HTTP メソッド・ヘッダーを許可するか」を指定します。allow_origins=settings.cors_origins で、設定ファイル(または環境変数)で指定したオリジンのみ許可します。
app.include_router(router)
実際のエンドポイント(/api/health や POST /api/evaluate)は別ファイル(app.api.routes)で定義されているため、その「ルーター」をアプリに取り込みます。これにより、各エンドポイントにアクセスできるようになります。
@app.get("/") と root()
@app.get("/") は「パスが / で HTTP メソッドが GET のときにこの関数を実行する」という意味です。ブラウザで http://localhost:8001/ を開くと、戻り値の辞書が JSON として返ります。API の説明や他エンドポイントへの誘導に使えます。
第 3 章:設定の読み込み —— config.py
3.1 なぜ設定を別ファイルにするか
API キーや接続先などは、環境ごと(開発・本番)や開発者によって変えたいことが多いです。これらをコードに直接書くと、変更のたびに編集が必要になり、秘密情報がリポジトリに含まれるリスクもあります。そこで、環境変数 や .env ファイル から読み込み、1 か所(config.py)でまとめて管理します。
3.2 config.py の内容
# backend/app/config.py
from pydantic_settings import BaseSettings
from functools import lru_cache
class Settings(BaseSettings):
app_name: str = "RAGAS Evaluation API"
debug: bool = False
openai_api_key: str = ""
openai_model: str = "gpt-4o"
cors_origins: list[str] = ["http://localhost:3000"]
model_config = {"env_file": ".env", "extra": "ignore"}
@lru_cache
def get_settings() -> Settings:
return Settings()
3.3 解説
Pydantic と BaseSettings
Pydantic は Python で「型付きのデータ」を扱うライブラリです。FastAPI も内部で Pydantic を使ってリクエスト・レスポンスを検証しています。BaseSettings は、環境変数や .env の値を読み込み、指定した型に変換してくれるクラスです。
| フィールド | 用途 |
|---|---|
openai_api_key | RAGAS が評価時に OpenAI API を呼ぶためのキー |
openai_model | 評価に使う OpenAI モデル名(例:gpt-4o) |
cors_origins | CORS で許可するオリジンのリスト |
model_config
"env_file": ".env"で、同じディレクトリの.envを読み込みます。Docker ではdocker-compose.ymlのenvironmentで渡した値も環境変数として読み込まれます。"extra": "ignore"は、定義していない環境変数を無視するという意味です。
get_settings() と @lru_cache
get_settings() は Settings() を 1 回だけ生成し、2 回目以降は キャッシュ を返します(@lru_cache の効果)。設定の読み込みやバリデーションは起動時に 1 回で済むため、効率的です。
※「設定は環境変数と .env で渡し、コードでは Settings を通してのみ参照する」と決めておくと、後から本番用の設定に切り替えやすくなります。
第 4 章:API の「型」—— schemas.py
4.1 スキーマとは
スキーマ は、「リクエストやレスポンスの形(型)」を表す定義です。フロントエンドとバックエンドの間で事前にデータの形を決めておくことで、実装のずれを防げます。FastAPI では Pydantic の BaseModel でスキーマを定義すると、JSON との変換やバリデーションが自動で行われます。
4.2 評価用の 1 件分 —— EvaluationSample
# backend/app/schemas.py(抜粋)
from pydantic import BaseModel, Field
class EvaluationSample(BaseModel):
user_input: str = Field(..., description="ユーザーの質問(クエリ)")
retrieved_contexts: list[str] = Field(
default_factory=list,
description="RAG で取得したコンテキストのリスト",
)
response: str = Field(..., description="RAG システムが生成した回答")
reference: str = Field(..., description="正解(グラウンドトゥルース)")
| フィールド | 内容 |
|---|---|
user_input | ユーザーが投げた質問(RAG の「クエリ」) |
retrieved_contexts | RAG が検索して得たドキュメントの断片のリスト |
response | RAG が生成した回答そのもの |
reference | 正解(グラウンドトゥルース)文字列 |
Field(..., ...) の ... は「この項目は必須」、default_factory=list は「省略時は空リストを使う」という意味です。
4.3 評価リクエスト全体 —— EvaluateRequest
class EvaluateRequest(BaseModel):
samples: list[EvaluationSample] = Field(
...,
min_length=1,
description="評価するサンプルのリスト",
)
min_length=1 で「最低 1 件は必要」としています。0 件では評価を実行できないためです。
4.4 評価結果の 1 項目 —— MetricScore
class MetricScore(BaseModel):
name: str = Field(..., description="メトリクス名(例:faithfulness)")
score: float = Field(..., description="スコア(0〜1)")
description: str | None = Field(default=None, description="メトリクスの説明")
4.5 評価 API のレスポンス —— EvaluateResponse
class EvaluateResponse(BaseModel):
success: bool = Field(..., description="評価が正常に完了したか")
metrics: list[MetricScore] = Field(default_factory=list, description="各メトリクスのスコア一覧")
error_message: str | None = Field(default=None, description="失敗時のエラーメッセージ")
| フィールド | 成功時 | 失敗時 |
|---|---|---|
success | True | False |
metrics | スコアのリスト | 空リスト |
error_message | None | エラー内容 |
送るデータ(Request)と返すデータ(Response)を型で明文化しておくことが、FastAPI で API を書くときの基本です。
第 5 章:エンドポイントの定義 —— api/routes.py
5.1 ルーターとは
FastAPI では、URL パスと HTTP メソッドごとに「どの関数を実行するか」を ルーター でまとめて登録します。main.py で app.include_router(router) しているため、router に定義したパスがアプリに追加されます。
5.2 routes.py の構成
# backend/app/api/routes.py(抜粋)
from fastapi import APIRouter, Depends, HTTPException
from app.config import Settings, get_settings
from app.schemas import EvaluateRequest, EvaluateResponse, HealthResponse
from app.services.ragas_service import run_evaluation
router = APIRouter(prefix="/api", tags=["evaluation"])
APIRouter(prefix="/api", ...) で「このルーターのパスはすべて /api で始まる」と指定します。つまり、このファイルで @router.get("/health") と書くと、実際のパスは /api/health になります。
5.3 ヘルスチェック —— GET /api/health
@router.get("/health", response_model=HealthResponse)
def health_check() -> HealthResponse:
return HealthResponse(status="ok", service="ragas-evaluation-api")
ヘルスチェック は「サーバーが起動しているか」を確認するためのエンドポイントです。Docker のヘルスチェックやロードバランサーの死活監視で活用します。この URL に GET でアクセスできれば「API は起動している」と判断できます。
5.4 評価実行 —— POST /api/evaluate
@router.post("/evaluate", response_model=EvaluateResponse)
def evaluate_rag(
request: EvaluateRequest,
settings: Settings = Depends(get_settings)
) -> EvaluateResponse:
if not settings.openai_api_key:
raise HTTPException(
status_code=503,
detail="OPENAI_API_KEY が設定されていません。",
)
try:
metrics = run_evaluation(
samples=request.samples,
openai_api_key=settings.openai_api_key,
model=settings.openai_model,
)
return EvaluateResponse(success=True, metrics=metrics)
except ValueError as e:
logger.warning("Validation error in evaluate: %s", e)
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
logger.exception("Evaluation failed: %s", e)
return EvaluateResponse(
success=False,
metrics=[],
error_message=str(e),
)
引数の役割
request: EvaluateRequest… リクエストボディが Pydantic によって自動でパース・検証され、EvaluateRequestのインスタンスとして渡されますsettings: Settings = Depends(get_settings)… 依存性注入(DI) です。FastAPI がget_settings()を呼び、その戻り値(設定)をsettingsに渡します。テスト時に設定を差し替えやすくなります
処理の流れ
1. OPENAI_API_KEY が未設定 → 503 を返して終了
2. run_evaluation(...) で RAGAS による評価を実行
3. 成功 → EvaluateResponse(success=True, metrics=metrics) を返す
4. ValueError(入力の不備)→ 400 エラー
5. その他の例外 → success=False と error_message を返す
「エンドポイントは薄く保ち、実際の処理は services/ に任せる」とすると、どこで何をしているかが明確になります。
第 6 章:RAGAS 評価の核 —— services/ragas_service.py
6.1 RAGAS とは
RAGAS は、RAG パイプラインや LLM の出力を 定量的に評価 するためのライブラリです。
| メトリクス | 概要 |
|---|---|
| Faithfulness | 回答がコンテキストに忠実かどうか |
| Context Recall | 正解に必要な情報がコンテキストに含まれていたか |
| Factual Correctness | 回答と正解の事実一致度 |
6.2 データセットの構築 —— _build_ragas_dataset
def _build_ragas_dataset(samples: list[EvaluationSample]) -> EvaluationDataset:
raw_list: list[dict[str, Any]] = [
{
"user_input": s.user_input,
"retrieved_contexts": s.retrieved_contexts,
"response": s.response,
"reference": s.reference,
}
for s in samples
]
if hasattr(EvaluationDataset, "from_list"):
return EvaluationDataset.from_list(raw_list)
# from_list が存在しない旧バージョン向けのフォールバック
from ragas import SingleTurnSample
ragas_samples = [
SingleTurnSample(
user_input=s.user_input,
retrieved_contexts=s.retrieved_contexts,
response=s.response,
reference=s.reference,
)
for s in samples
]
return EvaluationDataset(samples=ragas_samples)
私たちの EvaluationSample を RAGAS が期待する形式に変換します。まず辞書のリスト(raw_list)に変換し、EvaluationDataset.from_list() で RAGAS 用データセットを作ります。from_list が存在しない古いバージョンでは、SingleTurnSample を 1 件ずつ作るフォールバックを使います。
6.3 評価の実行 —— run_evaluation
def run_evaluation(samples, *, openai_api_key, model="gpt-4o") -> list[MetricScore]:
if not openai_api_key:
raise ValueError("OPENAI_API_KEY が設定されていません")
# Step 1: RAGAS 用データセットを構築
eval_dataset = _build_ragas_dataset(samples)
# Step 2: LLM を準備(RAGAS は内部で LLM を使う)
llm = ChatOpenAI(model=model, api_key=openai_api_key)
evaluator_llm = LangchainLLMWrapper(llm)
# Step 3: メトリクスを指定して評価を実行
metrics = [Faithfulness(), LLMContextRecall(), FactualCorrectness()]
result = evaluate(
dataset=eval_dataset,
metrics=metrics,
llm=evaluator_llm,
show_progress=True,
)
# Step 4: result.scores を集計して MetricScore のリストに変換して返す
...
| ステップ | 処理 |
|---|---|
| Step 1 | _build_ragas_dataset() で RAGAS 用データセットを用意 |
| Step 2 | LangChain の ChatOpenAI で LLM を作り、LangchainLLMWrapper でラップ |
| Step 3 | 3 つのメトリクスを指定して evaluate() を呼ぶ |
| Step 4 | result.scores(list[dict])をメトリクス名ごとに平均をとり MetricScore のリストに変換 |
第 7 章:Docker でバックエンドを動かす
7.1 Docker とは
Docker は、アプリとその実行環境(OS・ランタイム・ライブラリ)をまとめた「イメージ」を作り、そのイメージから「コンテナ」という隔離されたプロセスを動かす技術です。
- 「自分の PC では動くが、別の環境では動かない」という 環境差 を減らせる
Dockerfileに条件を書いておけば、どこでも同じ環境を再現できる- 本番に近い形でローカル開発できる
7.2 Dockerfile の解説
# backend/Dockerfile
FROM python:3.12-slim
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app/ ./app/
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/api/health || exit 1
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
| 命令 | 役割 |
|---|---|
FROM python:3.12-slim | ベースイメージを「Python 3.12 入りの軽量 Linux」に指定 |
WORKDIR /app | コンテナ内の作業ディレクトリを /app に設定 |
RUN apt-get ... | ヘルスチェック用に curl をインストール(イメージを小さく保つ工夫あり) |
COPY requirements.txt → RUN pip install | 依存関係を先にインストールして レイヤーキャッシュ を活用 |
COPY app/ ./app/ | アプリのソースをコピー |
RUN useradd ... / USER appuser | root ではなく一般ユーザーで実行(セキュリティ向上) |
HEALTHCHECK | 定期的に /api/health を確認し、異常時はコンテナを「不健全」とみなす |
EXPOSE 8000 | コンテナが 8000 番ポートで待ち受けると宣言 |
CMD ["uvicorn", ...] | コンテナ起動時に uvicorn で FastAPI を立ち上げる |
--host 0.0.0.0 を指定することで、コンテナの外(ホストマシン)からもアクセスできるようになります。
7.3 docker-compose.yml の解説
# docker-compose.yml
services:
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: ragas-eval-api
ports:
- "8001:8000"
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- OPENAI_MODEL=${OPENAI_MODEL}
- CORS_ORIGINS=["http://localhost:3000","http://127.0.0.1:3000"]
env_file:
- ./backend/.env
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/api/health"]
...
| 設定項目 | 内容 |
|---|---|
ports: "8001:8000" | ホストの 8001 番をコンテナの 8000 番に接続。PC では http://localhost:8001 でアクセス |
environment | コンテナに渡す環境変数。CORS_ORIGINS は JSON 配列の文字列で渡す(Pydantic が解釈) |
env_file | ./backend/.env の内容を環境変数として読み込む |
restart: unless-stopped | クラッシュ時に自動で再起動(手動で停止した場合は再起動しない) |
healthcheck | コンテナ内の http://localhost:8000/api/health を定期的に確認 |
第 8 章:Next.js と API クライアント —— lib/api.ts
8.1 Next.js とは
Next.js は、React ベースのフロントエンドフレームワークです。ここでは クライアント側 から FastAPI の API を fetch で呼び出し、得たデータを画面に表示する構成をとります。
8.2 ベース URL の決め方
// frontend/src/lib/api.ts
const getBaseUrl = () =>
process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:8001";
NEXT_PUBLIC_ で始まる環境変数は、Next.js のビルド時にクライアント用 JavaScript に埋め込まれ、ブラウザから参照できます。未設定時は http://localhost:8001(Docker でバックエンドを動かす想定のデフォルト値)を使います。
8.3 型定義(バックエンドとの契約)
export interface EvaluationSample {
user_input: string;
retrieved_contexts: string[];
response: string;
reference: string;
}
export interface EvaluateRequest {
samples: EvaluationSample[];
}
export interface MetricScore {
name: string;
score: number;
description?: string | null;
}
export interface EvaluateResponse {
success: boolean;
metrics: MetricScore[];
error_message?: string | null;
}
バックエンドの Pydantic スキーマと 同じ形 にしておくことで、「送るデータ」「返ってくるデータ」を TypeScript 側でも型安全に扱えます。
8.4 ヘルスチェック —— fetchHealth
export async function fetchHealth(): Promise<HealthResponse> {
const res = await fetch(`${getBaseUrl()}/api/health`, {
method: "GET",
headers: { "Content-Type": "application/json" },
});
if (!res.ok) throw new Error(`Health check failed: ${res.status}`);
return res.json() as Promise<HealthResponse>;
}
8.5 評価実行 —— evaluateRag
export async function evaluateRag(
request: EvaluateRequest
): Promise<EvaluateResponse> {
const res = await fetch(`${getBaseUrl()}/api/evaluate`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(request),
});
const data = (await res.json()) as EvaluateResponse;
if (!res.ok) {
throw new Error(data.error_message ?? `Request failed: ${res.status}`);
}
return data;
}
フロントとバックの型を関数で 1 か所に書いておくと、変更時に追いかけやすくなります。
第 9 章:画面の実装 —— app/page.tsx
9.1 役割
- 評価サンプル(質問・コンテキスト・回答・正解)を 複数件 入力できるフォームを表示
- 「API 接続確認」でヘルスチェック、「評価を実行」で評価 API を呼び出す
- 返ってきたメトリクスをカード形式で表示
9.2 状態(useState)
const [samples, setSamples] = useState<EvaluationSample[]>(DEFAULT_SAMPLES);
const [apiStatus, setApiStatus] = useState<"idle" | "ok" | "error">("idle");
const [loading, setLoading] = useState(false);
const [result, setResult] = useState<{
metrics: MetricScore[];
error?: string;
} | null>(null);
| 状態変数 | 用途 |
|---|---|
samples | 現在入力されている評価サンプルの配列 |
apiStatus | ヘルスチェックの結果(idle / ok / error) |
loading | 評価 API 呼び出し中かどうか(ボタンの無効化に使用) |
result | 評価 API の戻り値。null のとき結果セクションは非表示 |
9.3 評価実行の流れ(handleEvaluate)
const handleEvaluate = useCallback(async () => {
setLoading(true);
setResult(null);
try {
const res = await evaluateRag({ samples });
if (res.success) {
setResult({ metrics: res.metrics });
} else {
setResult({
metrics: [],
error: res.error_message ?? "評価に失敗しました",
});
}
} catch (e) {
setResult({
metrics: [],
error: e instanceof Error ? e.message : "リクエスト中にエラーが発生しました",
});
} finally {
setLoading(false);
}
}, [samples]);
useCallback で samples が変わったときだけ関数を再生成します。実行中は loading を true に、結果表示を一度クリアしてから evaluateRag を呼び出します。finally で必ず setLoading(false) を呼んでボタンを再度有効にします。
9.4 サンプルの操作
| 関数 | 処理 |
|---|---|
addSample | 空の 1 件を samples の末尾に追加 |
updateSample | 指定インデックスのサンプルの指定フィールドを更新 |
updateContext | retrieved_contexts の特定要素を更新 |
addContext | コンテキストを 1 行追加 |
これらはすべて、状態を直接変更せず setSamples で新しい配列を渡して更新する という React の基本に従っています。
9.5 表示の構成
┌─────────────────────────────────────────┐
│ ヘッダー │
│ └─ 「API 接続確認」ボタン + 接続状態表示 │
├─────────────────────────────────────────┤
│ 入力フォーム(samples を map して表示) │
│ └─ user_input / contexts / response / │
│ reference の入力欄 × 件数分 │
│ └─ 「サンプルを追加」ボタン │
│ └─ 「評価を実行」ボタン │
├─────────────────────────────────────────┤
│ 評価結果(result が存在する場合のみ表示) │
│ └─ エラーがあればエラーメッセージ │
│ └─ メトリクスをカードで表示(% 表示等) │
└─────────────────────────────────────────┘
第 10 章:動かす手順とトラブルシューティング
10.1 前提
- Docker Desktop(または Docker Engine + docker compose)がインストール済みであること
- Node.js がインストール済みであること
- OpenAI API キー を用意していること
10.2 バックエンド(Docker)の起動
# 1. .env ファイルを作成し、API キーを記入
cp backend/.env.example backend/.env
# → OPENAI_API_KEY=sk-... を記入
# 2. バックエンドを起動
docker compose up -d backend
# 3. 動作確認
curl http://localhost:8001/api/health
# → {"status":"ok","service":"ragas-evaluation-api"} が返れば成功
10.3 フロントエンドの起動
# 1. frontend ディレクトリへ移動
cd frontend
# 2. 依存関係のインストール
npm install
# 3. 開発サーバーを起動
npm run dev
ブラウザで http://localhost:3000 を開き、「API 接続確認」で緑のメッセージが表示されれば疎通確認完了です。
10.4 よくあるトラブル
| 症状 | 確認箇所 |
|---|---|
| CORS エラー | CORS_ORIGINS にフロントの URL(例:http://localhost:3000)が含まれているか確認。docker-compose では JSON 配列の文字列で渡す |
metrics が空 | docker compose logs backend でエラーを確認。API キーとモデル名も確認 |
| バックエンドに接続できない | ports の設定(例:8001:8000)と NEXT_PUBLIC_API_URL(例:http://localhost:8001)が一致しているか確認 |
まとめ
この記事では、RAGAS 評価 API を FastAPI で作り、Next.js の画面から呼び出し、Docker でバックエンドを動かすまでを、初学者にも分かるようにコード単位で解説しました。
| 技術 | 学んだこと |
|---|---|
| FastAPI | 設定(config)・スキーマ(schemas)・ルート(routes)・サービス(ragas_service)の役割分担と、CORS・依存性注入の意味 |
| Next.js | API クライアント(api.ts)で型と関数をまとめ、ページ(page.tsx)で状態と UI を扱う流れ |
| Docker | Dockerfile の各命令の意味と、docker-compose でのポート・環境変数・ヘルスチェックの指定方法 |
| RAGAS | サンプルをデータセットに変換し、evaluate() でメトリクスを計算し、API 用に整形する流れ |
実際に clone して docker compose up -d backend と npm run dev で動かし、コードを少しずつ変えてみると、各パーツの役割がよりはっきり理解できるはずです。本記事が、FastAPI・Next.js・Docker を「動かして学ぶ」きっかけになれば幸いです。

