はじめに

LLMを使っていると、「毎回似たような指示を書いているのに、出力が安定しない」という課題に直面することがあります。これは、入力の書き方や順序のわずかな違いによって出力が変わってしまうためです。安定した結果を得るためには、うまく書くことよりも一貫した構造でプロンプトを設計することが重要です。

この記事では、生成AI開発で注目されている LangChain を使い、再現性・保守性の高いプロンプトを設計する方法を紹介します。

LangChainとは

LangChain(ランチェーン) は、OpenAIやGoogle Geminiなどの大規模言語モデル(LLM)を効率的に活用するためのPythonライブラリです。プロンプト設計・外部ツール連携・メモリ管理・出力制御などを体系的に扱うことができ、AIアプリケーション開発の土台として広く使われています。

その中でもプロンプト設計に重要なのが PromptTemplate 機能 です。これはプロンプトをテンプレート化し、「固定ルール」と「変動要素」を分離することで、再利用性と安定性を高める機能です。

たとえば、「口調や出力形式は固定」「質問内容だけ毎回変える」といった使い方が簡単にできます。

LangChainでできること

LangChainでは、主に次のような機能を利用できます。

機能カテゴリ説明主なクラス活用例
プロンプト設計テンプレートで一貫性を保つPromptTemplate​ChatPromptTemplate役割・口調・出力形式を固定
モデル接続各種LLMを統一的に扱うChatOpenAI​, ChatGoogleGenerativeAIOpenAI ⇔ Gemini の切り替え
チェーン構築複数プロンプトを連携LLMChain​, SequentialChain生成→要約→整形 などの分割
出力制御JSONなど構造化出力に対応PydanticOutputParserAPIで安全なデータ返却
メモリ管理会話履歴を保持ConversationBufferMemoryチャットボット開発
外部連携APIやDBと接続Tool​, Agent検索・ファイル操作・自動化

再現性を高めるプロンプト設計

プロンプト設計の基本

プロンプト設計では、固定部分変動部分を分けて考えることが重要です。LangChainの PromptTemplate を使うと、これらを明確に分離でき、同じ構造で安定した出力が得られます。

区分内容
固定部分役割・口調・出力形式など常に同じルール役割: 専門家、口調: 丁寧、形式: 箇条書き
変動部分質問や条件など、毎回変わる部分「ダイエット中でも筋肉を落とさない食事は?」

PromptTemplateの使い方とコード例

以下は、Google Gemini モデルを使ってプロンプトテンプレートを作成する例です。

!pip install -U langchain langchain-google-genai protobuf==4.21.6
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash", api_key="API KEYを入力")

prompt = ChatPromptTemplate.from_messages([
  ("system", "あなたは{role}です。回答は{tone}で、出力形式は{format}です。"),
  ("human", "質問: {question}")
])
chain = prompt | llm | StrOutputParser()

result = chain.invoke({
  "role": "スポーツ栄養士",
  "tone": "科学的",
  "format":"簡潔な3つの箇条書き",
  "question": "ダイエット中でも筋肉を落とさない食事の工夫は?"
})
print(result)

 

■ 出力結果

このように、テンプレートを使うと構造を保ちながら質問だけを変えることができ、再現性が向上します。

テンプレートを使わない場合との比較

同じ内容を文字列連結で書くと次のようになります。

llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash", api_key="API KEYを入力")

role = "スポーツ栄養士"
tone = "科学的"
format = "簡潔な3つの箇条書き"
question = "ダイエット中でも筋肉を落とさない食事の工夫は?"

prompt = f"あなたは{role}です。回答は{tone}で、出力形式は{format}です。\n質問: {question}"

result = llm.invoke(prompt)
print(result.content)

この書き方だと、要素を追加・変更するたびに文字列全体を直す必要があり、system と human の役割構造も崩れやすくなってしまいます。固定部分と可変部分の区別がつきにくく、プロンプトの形が一定せず、結果の再現性も下がってしまう点が課題です。

安定した出力と再利用性を実現するには、PromptTemplateを使ってプロンプトを構造化する設計が効果的です。

PromptTemplateの応用

1. 出力形式を制御

PydanticOutputParser​ を使うと、AIの出力をJSON構造に固定できます。この方法を使えば、「AIが返すデータの形」を決めておけるため、システム側での処理が安定します。

from pydantic import BaseModel, Field
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_google_genai import ChatGoogleGenerativeAI

class HealthAdvice(BaseModel):
    topic: str = Field(..., description="健康トピック名")
    tips: list[str] = Field(..., description="アドバイスを3つ")
    
llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash", api_key="API KEYを入力")
parser = PydanticOutputParser(pydantic_object=HealthAdvice)
prompt = ChatPromptTemplate.from_template(
    "トピック: {topic}\nについて、科学的根拠に配慮し一言で回答してください。\n"
    "JSON形式で出力してください。\n"
    "{format_instructions}"
).partial(format_instructions=parser.get_format_instructions())
chain = prompt | llm | parser

result = chain.invoke({"topic": "睡眠の質向上"})
result.model_dump()

 

■ 出力結果

2. プロンプトテストの自動化

LangChainを使えば、プロンプトをテンプレート化して構造的に扱えるため、自動テストが容易になります。文字列を直書きする場合と違い、出力の形式や再現性を機械的に検証でき、品質を安定して保てます。

from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash", api_key="API KEYを入力")
prompt = ChatPromptTemplate.from_messages([
    ("system", "あなたは{role}です。簡潔に3つ箇条書きで答えてください。"),
    ("human", "{question}")
])
chain = prompt | llm | StrOutputParser()

def test_prompt():
    result = chain.invoke({"role": "トレーナー", "question": "短時間でできる筋トレ方法"})
    print(result)
    bullets = sum(line.strip().startswith(("*", "・", "-")) for line in result.splitlines())
    if bullets != 3:
        raise AssertionError(f"異常終了:箇条書きが{bullets}個")
    print("正常終了")

test_prompt()

 

■ 出力結果

3. プロンプトチェーンで処理を分割

複数のプロンプトを「チェーン」でつなげ、以下のように「生成 → 要約」の2段階処理を自動化できます。このように「分業型のプロンプト設計」をすることで、結果の一貫性と開発効率が大きく向上します。

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_google_genai import ChatGoogleGenerativeAI

llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash", api_key="API KEYを入力")

# Step 1: 情報生成
prompt1 = ChatPromptTemplate.from_template("『{topic}』について詳しく説明してください。")

# Step 2: 要約
prompt2 = ChatPromptTemplate.from_template("以下の説明を読み、最も重要なポイントを1文で要約してください。\n\n{content}")

chain = (
    prompt1 | llm | StrOutputParser()
) | (
    prompt2 | llm | StrOutputParser()
)

result = chain.invoke({"topic": "筋トレが美容にもたらす効果"})
print(result)

 

■ 出力結果

 

さいごに

LangChainの PromptTemplate を活用することで、プロンプトの品質や再現性、保守性を着実に高めることができます。
プロンプトを構造的に整理し、テンプレートとして管理することで、誰でも同じ結果を再現しやすくなります。
さらに、出力形式の制御や処理の分割、外部連携などと組み合わせることで、より安定した仕組みを作ることも可能です。
こうした工夫を重ねることで、属人的なノウハウに頼らず、再利用しやすく継続的に改善できるプロンプト設計が実現できます。

お読みいただき、ありがとうございました。

はじめに

最近では、生成AIを自分のアプリケーションやシステムに組み込みたいと考える人が増えています。Googleの Gemini API を使えば、誰でも簡単に生成AIをAPIから呼び出しシステム化に活用することができます。また、Gemini APIには無料枠も用意されており、初めての方でも安心して試すことができます。

この記事では、Gemini APIの基本から、Pythonを使用した実際のコード例、応用的な使い方を紹介します。

Gemini APIとは?

GeminiはGoogleが提供する大規模生成AIモデルで、テキスト生成、コード補完、画像理解など幅広い用途に対応しています。
Gemini APIは、API Keyを取得するだけで、Pythonなどから簡単に呼び出すことができます。

特徴

  • 高精度な自然言語生成(文章・コード・説明など)
  • 無料利用枠あり(初期試用に最適)
  • シンプルなAPI構成で導入が容易

無料枠と料金体系

Gemini APIには、無料枠(Free Tier)が用意されており、個人や小規模プロジェクトであればほとんどコストをかけずに機能を試すことができます。
以下は2025年10月時点の無料枠の目安です。上限はモデル・地域・利用状況で変動する場合があるため詳細は公式ドキュメントを確認してください。

model主な特徴1分あたりリクエスト数(RPM)1分あたり入力トークン数(TPM)1日あたりリクエスト数(RPD)
Gemini 2.5 Pro高精度・汎用型。文章生成やプログラム補完に最適。5125,000100
Gemini 2.5 Flash高速処理タイプ。応答スピードを重視するアプリに。10250,000250
Gemini 2.5 Flash-Lite軽量モデル。小規模処理・チャットボットなどに適用しやすい。15250,0001,000

補足:

  • リクエスト数(Requests):APIを呼び出した回数、
  • トークン数(Tokens):モデルが処理するテキスト量の単位

 

セットアップ手順

GeminiをAPI利用する場合は、まずAPI Keyを取得し、コード上でキーを指定する必要があります。

API Keyの取得

まず、Google AI Studio にアクセスし、以下の手順でAPI Keyを取得します。

  1. 左メニューから 「Get API key」 をクリック
  2. 右上の「APIキーを作成」ボタンをクリック
  3. 「キー名」と「プロジェクト」を設定
    キー名:任意の名前を付ける
    プロジェクト:任意のプロジェクトを設定(なければ「Create Project」で作成)
  4. 表示されたキーをコピーして安全に保管(※GitHubなどに公開しないよう注意)

ライブラリのインストールと初期設定

以下のコードを実行して、Gemini APIのインストール、APIキーの入力、モデル選択を実施します。

%pip install -U -q 'google-genai>=1.0.0'

from google import genai
from google.genai import types

GEMINI_API_KEY = "APIキーを入力"
client = genai.Client(api_key=GEMINI_API_KEY)

MODEL_ID = "gemini-2.5-flash" # モデルを選択

 

基本のテキスト生成

Gemini APIは、以下のコードだけでテキスト生成を行うことができます。

response = client.models.generate_content(
    model=MODEL_ID,
    contents="リモートワークの生産性を上げるコツを教えて"
)
print(response.text)

 

出力例:

 

出力のカスタマイズ

Geminiの出力はパラメータ設定により、創造性や安定性を自在に調整できます。

response = client.models.generate_content(
    "リモートワークの生産性を上げるコツを一文で教えて",
    generation_config={
        "temperature": 0.2,
        "max_output_tokens": 512,
        "top_p": 0.9
    }
)
print(response.text)

 

主なオプション

パラメータ種別説明
temperaturefloat出力の創造性を制御(高いほど多様で、低いほど安定した出力)0.7
top_pfloat確率分布の上位を使用(高いほど多様で、低いほど安定した出力)0.9
max_output_tokensint出力の最大トークン数512

 

Gemini APIの応用例

Gemini APIは単純なテキスト生成だけでなく、Google検索結果の利用、出力形式の指定、ファイル入力など、より高度な操作にも対応しています。

 

Google検索の結果を利用

Googleでの検索結果を用いて最新情報を反映させたい場合は、外部ツール連携が有効です。

response = client.models.generate_content(
    model=MODEL_ID,
    contents="明日(2025/10/11)の東京都港区の予想最高気温と最低気温を教えて",
    config={
        "tools":[{ "google_search": {} }]
    }
)
print(response.text)

 

出力例:

DataFrameとして出力

結果はテキストだけでなく、構造化データとしても取得できます。受け取ったJSONはDataFrameに変換でき、生成されたJSONデータを直接Pandasで扱うことで、AIが作成した情報を簡単に分析や可視化に利用できます。

import pandas as pd
import json

response = client.models.generate_content(
    model=MODEL_ID,
    contents="日本、韓国、タイの人口と面積をJSON形式で出力して",
    config={
        "response_mime_type": "application/json"
    }
)
data = json.loads(response.text)
df = pd.DataFrame(data)
df

 

出力例:

ファイルの入力

Gemini APIは、以下のコードで画像や音声・動画、ドキュメントファイルを入力として扱うことができます。

myfile = client.files.upload(file="example.pdf")

response = client.models.generate_content(
    model=MODEL_ID,
    contents=[
        myfile,
        "このPDFを要約してください",
    ]
)

 

まとめ

Gemini API は、無料で・すぐに・簡単に使える生成AIプラットフォームです。
無料枠でも十分に実用レベルの機能を体験できるので、まずは触ってみるのがおすすめです。
また、Gemini APIは、Python以外の言語(JavaScriptやGoなど)からも利用できるため、様々な開発環境に組み込みやすい点も魅力です。
生成AIを自社システムや個人開発に取り入れたいエンジニアにとって、Gemini APIは非常に有用な選択肢です。

お読みいただきありがとうございました。

はじめに

今回の記事では、Keycloakを使ってユーザーを作成し、そのユーザー名を画面に表示できるところまでを実践していきます。

なぜ環境構築なのか?

日々の開発の中で、一番時間を取られるのは環境構築じゃないかと思います。
手順書が古かったり、追加の対応が必要だったりで「手順通りにやったのにエラー!」という経験、みなさんもあるのではないでしょうか?

自分自身、環境構築には苦手意識があり、そこで今回はあえて環境構築をテーマにして苦手意識を減らしていこうと記事をまとめていこうかと思います。

ただフロントだけだと簡単すぎるかもしれないので、少し複雑さを足すためにKeycloakを組み合わせようと思います。

Keycloakってなに?

Keycloakは、オープンソースの「認証・認可」を担うサービスです。
ログインやユーザー管理をアプリに組み込むのではなく、Keycloakに任せることで簡単に導入できます。

例えば、社内システムで勤怠管理や経費精算ツールなど複数のサービスを使う場合、毎回ログインするのは面倒ですよね。
そんな時にKeycloakを使えば「一度ログインすれば全部使える(SSO)」という仕組みが作れます。

今回の記事では細かい機能までは触れませんが、「ログイン処理をKeycloakに外注できる」ぐらいのイメージで読んでいただければと思います。

Keycloak側の設定

今回は手軽に環境を汚さないのでDockerで起動を行おうと思います。
Dockerをダウンロードしていない場合は公式ダウンロードページからダウンロードをしてください。

ダウンロードが完了したらターミナルで下記を実行してください。

`docker run --name keycloak -p 8080:8080 \
  -e KEYCLOAK_ADMIN=admin \
  -e KEYCLOAK_ADMIN_PASSWORD=admin \
  quay.io/keycloak/keycloak:latest start-dev`

実行後、http://localhost:8080 へアクセスするとkeycloak の画面が表示されると思うので、Usernameadmin Passwordadmin でログインをしてください。keycloak のversionは26.3.3

Realmの作成

Keycloakへログインできたら次はRealmの作成です。
左側にあるメニューのManage realmsCreate realmを押下後、Realm namedemoを入力しCreateを押下して作成完了です。

Clientsの作成

Realmの作成が完了したら次はClientsです。
左側にあるメニューのClientsCreate client を押下します。
①のGeneral settingsはClient IDtest-appを入力してnext
②のCapability configは何も設定せずにnext
③のLogin settingsはRoot URLhttp://localhost:4200/Valid redirect URIshttp://localhost:4200/*Web origins*を設定してSaveを押下してください。

Usersの作成

最後にUserを作成します。
左側にあるメニューのUsersAdd user を押下します。
Usernametestuserを入力してCreate
作成が完了するとUser detailsが表示されるので、Credentialsタブ→Set passwordを押して任意のパスワードを設定してください。

動作確認

ここまで色々と設定や作成を行ってきましたが、そもそも「Realm」とは何なのか?とイメージが付きにくい方もいるかと思います。
簡単に例えるとRealmは学校そのもので、その中で生徒(User)やクラス(Client)が管理されているイメージです。
学校ごとにルールや管理者が異なるため、Keycloakに最初から用意されているmasterRealmは触らず、
今回は「環境構築用の学校」を新しく設立した、という感覚で捉えると分かりやすいと思います。
それでは、実際に動作確認をしてみましょう。
下記をブラウザでアクセスしてみてください。※一行に繋げてアクセス

http://localhost:8080/realms/demo/protocol/openid-connect/auth
  ?client_id=test-app 
  &redirect_uri=http://localhost:4200/
  &response_type=code
  &scope=openid

?client_id=test-app:Keycloakに登録したクライアントID
&redirect_uri=http://localhost:4200/:認証後にリダイレクトするコールバックURL
&response_type=code:OIDCのレスポンスタイプ
&scope=openid:要求するスコープ(権限の範囲)

アクセスすると作成したrealm:demoのログイン画面が表示されるので、先ほど作成したUsertestuserでログインしてみてください。

ログインが成功すると先ほど設定したhttp://localhost:4200/にリダイレクトされるはずです。

まだAngular側の設定をしていないので404になりますが、Keycloakでユーザーを作成し、そのユーザーでログインができる所まで確認できました!

Angularの設定

keycloak側の設定が完了したので、連携するためにAngularプロジェクトの新規作成を行います。

Angularプロジェクトの作成

使用しているAngular CLIの情報です。

任意のフォルダ配下にプロジェクトを新規作成します。

ng new keycloak-demo

作成したらプロジェクトに移動して起動できるか確認します。

cd keycloak-demo
ng serve -o

ブラウザでhttp://localhost:4200にアクセスしてください。
下記画面が表示されたら成功です。

Keycloak用のライブラリをインストール

Keycloakと連携するために必要なライブラリをインストールします。

npm install keycloak-angular keycloak-js

Keycloak初期設定ファイルを作成

src/app配下にinit-keycloak.tsを作成してください

import { KeycloakService } from 'keycloak-angular';

export function initializeKeycloak(keycloak: KeycloakService) {
  return () =>
    keycloak.init({
      config: {
        url: 'http://localhost:8080/',
        realm: 'demo',
        clientId: 'test-app',
      },
      initOptions: {
        onLoad: 'login-required',
        pkceMethod: 'S256',
        redirectUri: window.location.origin,
      },
    });
}

既存ファイルの修正

src/app配下のapp.config.tsapp.htmlapp.tsを以下の内容で書き換えてください。
app.config.tss

import { ApplicationConfig, APP_INITIALIZER, provideZoneChangeDetection, provideBrowserGlobalErrorListeners } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient } from '@angular/common/http';

import { routes } from './app.routes';

import { KeycloakAngularModule, KeycloakService } from 'keycloak-angular';
import { initializeKeycloak } from './init-keycloak';

export const appConfig: ApplicationConfig = {
  providers: [
    provideBrowserGlobalErrorListeners(),
    provideZoneChangeDetection({ eventCoalescing: true }),
    provideRouter(routes),
    provideHttpClient(),
    KeycloakAngularModule,
    KeycloakService,
    {
      provide: APP_INITIALIZER,
      useFactory: initializeKeycloak,
      multi: true,
      deps: [KeycloakService],
    },
  ],
};

app.html

<main class="main">
  @if (userName) {
    <div class="user-info">
      <p>ようこそ、{{ userName }} さん!</p>
    </div>
  }
</main>

app.ts

import { Component, signal, OnInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { KeycloakService } from 'keycloak-angular';

@Component({
  selector: 'app-root',
  imports: [RouterOutlet],
  templateUrl: './app.html',
  styleUrls: ['./app.css']
})
export class App implements OnInit {
  protected readonly title = signal('keycloak-demo');
  userName: string | null = null;

  constructor(private keycloakService: KeycloakService) {}

  async ngOnInit() {
    const isLoggedIn = await this.keycloakService.isLoggedIn();

    if (isLoggedIn) {
      try {
        const userProfile = await this.keycloakService.loadUserProfile();
        this.userName = userProfile.username ?? null;
      } catch (error) {
        console.error('ユーザープロファイルの取得に失敗しました', error);
      }
    }
  }
}

ここまで作成・修正ができたらng serve -oで起動してみてください。
ブラウザ http://localhost:4200にアクセスしたらKeycloakのログイン画面にリダイレクトされて、ログインが成功したら「ログインユーザー: ユーザー名」 が画面に表示されるはずです。

最後に

いかがだったでしょうか。
今回はKeycloakを使ってユーザーを作成し、ログインユーザー名をAngularの画面に表示するところまでを実施しました。

単なる手順書通りの環境構築では「なぜそうなるのか」が見えにくく、エラー時の原因特定も難しくなりがちです。
ですがシステムの流れを意識しながら進めることで理解が深まり、トラブル対応力も上がると感じています。

記事上では淡々と進んでいるように見えるかもしれませんが、実際には既存のAngular依存関係に悩まされたり、思わぬエラーに詰まったりしました。そうした対応も含めて、この記事がこれから環境構築に挑戦する方の「知識の引き出し」の一つになれば嬉しいです。

ここまで読んでいただき、ありがとうございました!
後半ではSpring Bootと連携してAPIを呼び出し、フロントとバックエンドを動かすところまで進める予定です。ぜひご期待ください!

Learn how we helped 100 top brands gain success