Vercel AI SDK + Google Gemini で日本語要約 API を作る

2026.02.04
Share:

はじめに

長文を読むのが苦手なユーザーに、どうやって情報を届けるか?

私が自治会 DX(自治会業務デジタル化アプリ)を開発していたとき、この課題に直面しました。回覧板の内容は、時に数百文字、数千文字に及びます。特にシニア層のユーザーにとって、長文を最後まで読むのは負担が大きい。

そこで Claude Code に依頼して実装したのが、AI による自動要約機能です。

2026年1月27日の開発日記にはこう書いています:

AI 要約: 長文の回覧板をシニアが読みやすいように3行以内で要約

この記事では、Vercel AI SDK と Google Gemini を使って日本語要約 API を実装した経験を共有します。

なぜ Google Gemini を選んだのか

AI モデルの選定は、コスト、性能、使いやすさのバランスで決まります。

開発日記には、比較検討の結果をこう記録しています:

Google Gemini vs OpenAI:

  • Gemini 2.0 Flash を採用
  • 理由: 無料枠が大きい、日本語性能が良い、レスポンスが速い

Gemini 2.0 Flash の特徴

特徴内容
無料枠1日15リクエスト(開発には十分)
日本語性能自然な日本語を生成
レスポンス速度Flash モデルは高速
コスト有料枠でも比較的安価

個人開発やスタートアップのプロダクトには、この無料枠の大きさは魅力的です。OpenAI の GPT-4 も高性能ですが、コストを考えると Gemini は良い選択肢でした。

Vercel AI SDK とは

Vercel AI SDK は、AI モデルとのやり取りを簡単に実装できるライブラリです。特に以下の点が便利です:

  • 統一されたインターフェース: OpenAI、Anthropic、Google など複数のプロバイダーに対応
  • ストリーミングサポート: レスポンスをリアルタイムで表示
  • Next.js との統合: App Router と相性が良い

開発日記にはこう書いています:

Vercel AI SDK の streamText を使うとストリーミングレスポンスが簡単に実装できる

実装の全体像

自治会 DX での要約機能は、以下のような構成になっています:

ユーザー
  ↓ 要約リクエスト
Next.js API Route (/api/summarize)
  ↓ Vercel AI SDK
Google Gemini API
  ↓ ストリーミングレスポンス
ユーザー(リアルタイム表示)

API Route の実装

Next.js App Router で API Route を作成します。

// app/api/summarize/route.ts
import { streamText } from "ai";
import { google } from "@ai-sdk/google";

export async function POST(request: Request) {
  const { content } = await request.json();

  const result = await streamText({
    model: google("gemini-2.0-flash-exp"),
    system: `あなたは日本語の文章を要約するアシスタントです。
以下のルールに従って要約してください:
- 3行以内で要約する
- 重要なポイントを漏らさない
- シニア層が読みやすい平易な表現を使う
- 敬語は使わず、「です・ます」調で書く`,
    prompt: `以下の文章を要約してください:

${content}`,
  });

  return result.toDataStreamResponse();
}

ポイント: システムプロンプトの設計

要約の品質は、システムプロンプトの設計で大きく変わります。自治会 DX では、以下の要件を明示しました:

  • 3行以内: 長すぎると読まれない
  • 重要なポイント: 日時、場所、締切などを漏らさない
  • 平易な表現: シニア層がターゲット
  • です・ます調: 親しみやすさ

クライアント側の実装

Vercel AI SDK には、React 用のフックも用意されています。

// components/SummaryButton.tsx
"use client";

import { useCompletion } from "ai/react";

export function SummaryButton({ content }: { content: string }) {
  const { completion, complete, isLoading } = useCompletion({
    api: "/api/summarize",
  });

  const handleClick = async () => {
    await complete(content);
  };

  return (
    <div>
      <button onClick={handleClick} disabled={isLoading}>
        {isLoading ? "要約中..." : "AI で要約"}
      </button>
      {completion && (
        <div className="mt-4 p-4 bg-gray-100 rounded">
          <h3>要約</h3>
          <p>{completion}</p>
        </div>
      )}
    </div>
  );
}

ポイント: ストリーミング表示

useCompletion フックを使うと、レスポンスがストリーミングで返ってくるたびに completion が更新されます。ユーザーは、AI が文字を「打っている」ように見え、待ち時間のストレスが軽減されます。

環境変数の設定

Google Gemini API を使うには、API キーが必要です。

# .env.local
GOOGLE_GENERATIVE_AI_API_KEY=your-api-key-here

API キーは Google AI Studio で無料で取得できます。

シニア向け UI への組み込み

自治会 DX はシニア層がメインターゲットです。要約機能も、シニアに使いやすい形で組み込む必要がありました。

開発日記から:

シニア向け UI 設計:

  • タップターゲット最小48px(WAI推奨44px以上)
  • フォントサイズ本文18px以上
  • 高コントラスト配色

要約ボタンのデザイン

<button
  onClick={handleSummarize}
  className="
    w-full py-4 px-6
    text-lg font-medium
    bg-blue-600 text-white
    rounded-lg
    active:bg-blue-700
  "
>
  AI で要約する
</button>
  • w-full: 画面幅いっぱいに広げる
  • py-4: 十分な高さを確保
  • text-lg: 読みやすいフォントサイズ

要約結果の表示

{summary && (
  <div className="mt-4 p-6 bg-yellow-50 border-2 border-yellow-200 rounded-lg">
    <h3 className="text-lg font-bold mb-2">📝 かんたんまとめ</h3>
    <p className="text-lg leading-relaxed">{summary}</p>
  </div>
)}
  • bg-yellow-50: 目立つ背景色
  • border-2: はっきりした境界線
  • text-lg leading-relaxed: 読みやすい文字サイズと行間

実装時に悩んだこと

要約の一貫性

同じ文章を要約しても、AI の出力は毎回少し異なります。これは LLM の特性上避けられませんが、ユーザーによっては混乱の原因になりえます。

対策として、以下を検討しました:

  • temperature を下げる: 出力のランダム性を抑える
  • キャッシュ: 同じ入力に対しては同じ結果を返す
const result = await streamText({
  model: google("gemini-2.0-flash-exp"),
  // temperature: 0.3, // 低めに設定すると一貫性が上がる
  // ...
});

レート制限

開発中は無料枠で十分でしたが、本番運用ではレート制限を考慮する必要があります。

  • クライアント側でのデバウンス: 連打を防止
  • サーバー側でのレート制限: IP ベースでリクエスト数を制限
  • キャッシュ活用: 同じ文章の再要約を防止

プロンプトエンジニアリングの試行錯誤

要約の品質を上げるために、プロンプトを何度も調整しました。

初期のプロンプト(NG)

以下の文章を要約してください:

このシンプルなプロンプトでは、要約が長くなったり、重要な情報が抜けたりしました。

改善後のプロンプト(OK)

あなたは日本語の文章を要約するアシスタントです。
以下のルールに従って要約してください:
- 3行以内で要約する
- 重要なポイント(日時、場所、締切、金額)を必ず含める
- シニア層が読みやすい平易な表現を使う
- 「です・ます」調で書く
- 専門用語は避け、平易な言葉に言い換える

具体的なルールを列挙することで、出力の品質が安定しました。

回覧板特有のルール

回覧板には「日時」「場所」「締切」など、絶対に漏らしてはいけない情報があります。これをプロンプトに明示することで、重要情報の抜け落ちを防ぎました。

まとめ

Vercel AI SDK と Google Gemini を使えば、日本語要約 API を簡単に実装できます。

ポイントをまとめると:

  • モデル選定: Gemini 2.0 Flash は無料枠が大きく、日本語性能も良い
  • Vercel AI SDK: streamText でストリーミングレスポンスが簡単
  • プロンプト設計: 具体的なルールを明示すると品質が安定する
  • シニア向け UI: 大きなボタン、読みやすいフォント、目立つ表示

開発日記から引用します:

Vercel AI SDK の streamText を使うとストリーミングレスポンスが簡単に実装できる

実際、Claude Code で API Route を実装したところ、数十行で済みました。AI の力を借りることで、ユーザー体験を大きく向上させられます。

長文を要約する機能が必要な場面は、自治会アプリに限らず多いはずです。ニュースアプリ、ドキュメント管理、メール要約... この記事が、皆さんのプロダクトに AI 要約機能を実装するきっかけになれば幸いです。

Zeronova avatar

Zeronovaゼロノバ

Product Manager / AI-Native Builder

Web/IT業界19年以上・20以上のWebサービスを担当したPdM。東証プライム上場企業の子会社代表として事業経営を経験。現在はAIを駆使して企画から実装まで完結させる個人開発を実践中。

関連プロダクト

自治会DX(仮)

回覧板も安否確認もスマホひとつで