LLMに関する20のAI概念: 詳細な説明とコード例付き

この記事には短い動画があります:TikTok

1. 概要

JavaデベロッパーとしてLLM(ChatGPT、Gemini、Claude…)をシステムに統合し始めると、token、embedding、RAG、fine-tuning、hallucination…といった多くの見慣れない用語に遭遇することになります。この記事では、LLMに関連する最も重要な20のAI概念を紹介します。各概念には簡潔な説明と図解例(ほとんどJava/Spring AIで記述)が付いています。読み終わった時点で、OpenAIやAnthropicのAPIドキュメントを読んだり、基本的なRAGシステムを設計したりするための十分な知識が身に付きます。

2. トークンとトークン化

LLMは「文字」を読みません。トークンを読みます。トークンは単語より小さい単位で、1つの単語、単語の一部、または句読点である場合もあります。トークン化は、テキストをモデルに入力する前にテキストをこれらのトークンに分割するプロセスです。

入力:  "Spring Boot rất mạnh"
トークン: ["Spring", " Boot", " rất", " mạnh"]  (4トークン)

トークン数はAPI呼び出しのコスト(トークンベースの課金)と入力/出力の長さの制限を決定します。

注意: ベトナム語のアクセント記号付き文字は、英語と同じ文で比較するとより多くのトークンに分割される傾向があるため、ベトナム語のコンテンツに対するAPI呼び出しコストは通常、英語より高くなります。

3. エンベディング

エンベディングは、テキストの一部を実数ベクトル(例:1536次元)に変換するプロセスです。2つのテキスト部分が意味的に近い場合、ベクトルは近くなります。これはセマンティック検索の基盤です。

EmbeddingModel embeddingModel = ...; // Spring AIが自動設定するBean
EmbeddingResponse response = embeddingModel.embedForResponse(
        List.of("Khách hàng muốn hủy đơn hàng"));
float[] vector = response.getResult().getOutput();
System.out.println(vector.length); // 1536

embedForResponseはエンベディングモデルを呼び出してベクトルを返します。「hủy đơn hàng」と「cancel order」という2つの文は、言語が異なっていてもベクトルが近くなります。

意味の近さを比較するには、コサイン類似度を使用します:

double cosineSimilarity(float[] a, float[] b) {
    double dot = 0, normA = 0, normB = 0;
    for (int i = 0; i < a.length; i++) {
        dot += a[i] * b[i];
        normA += a[i] * a[i];
        normB += b[i] * b[i];
    }
    return dot / (Math.sqrt(normA) * Math.sqrt(normB));
}
@Test
void similarVectorsShouldScoreHigh() {
    float[] a = {1f, 0f, 1f};
    float[] b = {1f, 0.1f, 0.9f};
    assertThat(cosineSimilarity(a, b)).isGreaterThan(0.95);
}

1に近い値は、2つのベクトル(したがって2つの文)が非常に似た意味を持つことを意味します。

4. コンテキストウィンドウ

コンテキストウィンドウは、モデルが1回の呼び出しで「見える」最大トークン数(プロンプトと応答の両方を含む)です。この制限を超えると、モデルは開始部分を切り取るか、エラーを返します。

GPT-4o:        128,000 tokens
Claude 3.5:    200,000 tokens
Gemini 1.5 Pro: 1,000,000 tokens

長い会話履歴を持つチャットボット アプリケーションの場合は、コンテキストウィンドウがいっぱいになる前に、古い履歴をアクティブに削減/要約する必要があります。そうしないと、明確な警告なしに会話の開始情報が失われます。

5. プロンプトとプロンプトエンジニアリング

プロンプトは、LLMに対して何かを実行するよう要求するために送信するテキストのセクションです。プロンプトエンジニアリングは、モデルが望む形式と希望する内容で正しく回答するようにプロンプトを設計する技術です。

まず、Spring AI dependencyを追加します:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>
@Service
class OrderSummaryService {
    private final ChatClient chatClient;

    OrderSummaryService(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    String summarize(String orderNote) {
        return chatClient.prompt()
                .user("Tóm tắt yêu cầu khách hàng trong 1 câu: " + orderNote)
                .call()
                .content();
    }
}

ChatClientはSpring AIのラッパーで、HTTPを手動で処理する必要なくモデルを呼び出すのに役立ちます。.user(...)はプロンプトの内容を設定し、.call().content()は結果文字列を返します。

6. システムプロンプト対ユーザープロンプト

システムプロンプトは、会話全体を通じてモデルの役割とルールを形成する「暗黙の」指示です。ユーザープロンプトは、ユーザーの具体的な質問/要求です。

chatClient.prompt()
        .system("Bạn là trợ lý hỗ trợ khách hàng của shop giày. Luôn trả lời ngắn gọn, lịch sự.")
        .user("Đơn #1023 của tôi khi nào giao?")
        .call()
        .content();

システムプロンプトは一度だけ設定する必要があります。ユーザープロンプトはリクエストごとに変わります。この2つのタイプを分離すると、各質問で指示を繰り返さなくても、モデルの「性格」を制御できます。

7. ゼロショット、ワンショット、フューショット学習

これは、プロンプト内に(提供するか提供しないか)サンプル例を提供する方法です。モデルを再トレーニング(fine-tuning)することなく、望ましいフォーマットで回答する方法をモデルに学ばせます。

ゼロショット: 例がなく、要件の説明のみ。
フューショット:  実際の質問の前に、2~5の入力→出力サンプルの例があります。
String fewShotPrompt = """
    Phân loại cảm xúc review (positive/negative):
    Review: "Giao hàng nhanh, chất lượng tốt" -> positive
    Review: "Sản phẩm lỗi, giao trễ 1 tuần" -> negative
    Review: "%s" ->
    """.formatted(userReview);

フューショットは通常、特定のタスク(分類/形式設定)のゼロショットより安定した結果をもたらしますが、各呼び出しでより多くのトークンを消費します。

8. 思考の鎖(CoT)

CoTは、最終的な回答を提供する前に、モデルに「段階を追って考える」よう要求する技術です。これは、推論が必要な問題(数学、論理)の精度向上に役立ちます。

chatClient.prompt()
        .user("""
            Một đơn hàng có 3 sản phẩm giá 120k, 85k, 45k, giảm giá 10%.
            Hãy tính từng bước rồi đưa ra tổng tiền cuối cùng.
            """)
        .call()
        .content();

モデルに「段階を追って」計算するよう要求されると、問題を小さな計算に分解する傾向があり、「合計金額はいくらですか?」と直接尋ねる場合と比較して計算間違いの可能性が低くなります。

9. 温度とTop-p

温度とTop-pは、モデルが次の単語を選択するときの「ランダム性」の程度を調整する2つのパラメータです。温度が低い→一貫性のある、反復的な回答、高い→より創造的ですがトピックから逸脱しやすい。

ChatOptions options = OpenAiChatOptions.builder()
        .withTemperature(0.2)
        .withTopP(0.9)
        .build();
temperature = 0.0  -> 適切: データ抽出、正確な回答
temperature = 0.8  -> 適切: クリエイティブコンテンツ作成、ブレーンストーミング

注意: 再現可能な結果が必要なタスク(自動テストなど)の場合は、temperature = 0に設定して、呼び出し間の変動を減らします。

10. アテンションメカニズム

Attentionは、モデルが単語を処理するときに、文内のすべての単語を「見て」、どの単語が最も関連性があるかを自動的に計算する重みメカニズムです。これが、モデルが遠い文脈を理解できる理由です。例えば、代名詞「nó」がどの名詞を指すか。

文: "Đơn hàng bị hủy vì khách đổi ý, nó đã được hoàn tiền."
Attentionはモデルが「nó」->「Đơn hàng」に関連付けるのに役立ちます。「khách」ではなく。

APIを使用する場合、attentionを直接コーディングすることはありませんが、これを理解することで、モデルが「文脈を忘れる」理由を説明するのに役立ちます。特に、文が非常に遠い場合や非常に長い場合。

11. Transformer アーキテクチャ

Transformerは、現在ほぼすべてのLLMの基礎となるニューラルネットワークアーキテクチャです。RNNなどの古い方法とは異なり、attentionを使用して文全体を同時(並列)に処理します。これにより、巨大なデータセットの学習がより高速になります。

入力トークン -> Embedding -> [Attention + Feed-Forward] x N層 -> 出力確率

層の数(N)とパラメータの数は、モデルの「サイズ」を決定します。GPT-4、Claude、Llamaはすべて、層の数と学習方法が異なるTransformerのバリエーションです。

12. ファインチューニング

ファインチューニングは、事前学習済みのモデルを独自のデータで追加で学習させて、特定のタスク(例:ブランドのトーンで正しく答える)に特化させることです。

{"messages": [
  {"role": "user", "content": "Đơn #203 giao chưa?"},
  {"role": "assistant", "content": "Dạ đơn #203 đang trên đường giao, dự kiến đến trong hôm nay ạ."}
]}

このJSONLファイルは、ファインチューニング用トレーニングデータの1行です。複数行は会話のサンプルペアです。プロバイダのファインチューニングAPIに数千行送信します。

いつ使わないか: モデルが単純なルールに従って答えるだけで良い場合、プロンプトエンジニアリングまたはRAGの方がファインチューニングより遥かに安くて速いです。

13. LoRA(低ランク適応)

LoRAは、コスト効率的なファインチューニング技術です。モデル全体の数十億のパラメータをすべて更新する代わりに、LoRAは複数の層に「挿入」される小さなマトリックスをいくつか学習するだけで、元のモデルは変わりません。

元のモデル: 70億個のパラメータ(フリーズされ、変更されない)
LoRA adapter: 約1000万~5000万個のパラメータ(学習される)

この結果、LoRAでは通常のGPUで大規模モデルをファインチューニングでき、同じ元のモデルに対して複数の異なる用途に複数の異なるアダプターを「取り付け・取り外し」できます。

14. 量子化

量子化は、モデルパラメータの数値精度を低下させます(例えばfloat32からint8/int4へ)。これにより、推論を高速化し、サイズを縮小します。わずかな精度を失う代わりに。

FP32: 70億個のパラメータ x 4バイト = 約28 GB RAM
INT4: 70億個のパラメータ x 0.5バイト = 約3.5 GB RAM

量子化は、専用GPUサーバーではなく通常のラップトップで70億パラメータのLLMを実行できる理由です。代わりに、回答の品質は若干低下します。

15. RAG(検索拡張生成)

RAGは、検索(retrieval)と生成を組み合わせる技術です。回答する前に、システムは最も関連性の高いテキストセクション(エンベディングを介して)を検索し、プロンプトに「コンテキスト」として追加します。これにより、モデルがファインチューニングなしで独自のデータに基づいて正しく答えられるようになります。

List<Document> relevantDocs = vectorStore.similaritySearch(
        SearchRequest.query("chính sách đổi trả hàng").withTopK(3));

String context = relevantDocs.stream()
        .map(Document::getContent)
        .collect(Collectors.joining("\n---\n"));

String answer = chatClient.prompt()
        .system("Chỉ trả lời dựa trên ngữ cảnh được cung cấp.")
        .user("Ngữ cảnh:\n" + context + "\n\nCâu hỏi: Đổi trả trong bao nhiêu ngày?")
        .call()
        .content();

similaritySearchは、質問と最も意味的に類似した3つのドキュメントセクションを見つけ、プロンプトに結合してからモデルに送信します。これにより、回答は実際のポリシーに固く基づいており、モデルが事前学習時に学習した「一般的な」知識ではなくなります。

16. ベクトルデータベース

ベクトルデータベースは、エンベディングとメタデータを保存し、数百万個のベクター上で「k最近傍」(k-NN)検索をサポートします。これはRAGを大規模で実行するために不可欠なコンポーネントです(Pinecone、Milvus、PGVector…)。

CREATE TABLE documents (
    id SERIAL PRIMARY KEY,
    content TEXT,
    embedding VECTOR(1536)
);

SELECT content FROM documents
ORDER BY embedding <-> '[0.01, -0.02, ...]'
LIMIT 3;

演算子<->(pgvector拡張機能で提供)は、質問のベクトルと保存されたベクトルの間の距離を計算し、最も近いレコードを返します。これが正に、セクション15のsimilaritySearchステップです。

17. 関数呼び出し/ツール使用

関数呼び出しにより、LLMが必要な場合(価格の確認、天気の確認、DB照会)に、アプリケーションに特定の関数を呼び出すよう「要求」できます。モデルが自分でデータを作ったり、推測したりする代わりに。

@Tool(description = "Lấy trạng thái đơn hàng theo mã đơn")
String getOrderStatus(String orderId) {
    return orderRepository.findStatusById(orderId);
}
chatClient.prompt()
        .user("Đơn #1023 đang ở trạng thái gì?")
        .tools(this)
        .call()
        .content();

質問を送信する際、モデルは自動的にgetOrderStatusを呼び出す必要があることを認識し、Spring AIは実際のJava関数を実行して、結果を取得し、モデルに戻して最終的な回答を作成します。モデルはもう注文ステータスを「推測」する必要がありません。

18. AIエージェント

エージェントは、LLMを「脳」として使用して、複数のツールを自動的に計画し、順序立てて呼び出し、結果を観察し、目的が達成されるまで繰り返すシステムです。シンプルなチャットボットとは異なります。

ユーザー: "注文#1023を確認してください。3日以上遅れている場合は、お詫びメールを送信してください。"

エージェント自動実行:
1. ツールgetOrderStatus("1023")を呼び出す
2. 遅延日数を計算する
3. もし3日以上 -> sendEmail(...)ツールを呼び出す
4. ユーザーにレポートを返す

エージェントは通常、「思考→行動→観察」ループ(ReAct パターン)を使用して構築され、複数のステップを持つタスクを処理するために複数の関数呼び出しを組み合わせます。

19. ハルシネーション

ハルシネーションは、モデルが情報を自信を持って答えるが、その情報が間違っているか完全に作られている場合です。例えば、存在しない法律を引用したり、実在しないAPIを誤って思い出したり。

ユーザー: "API `OrderService.cancelAndRefund()`はどのように機能しますか?"
モデル: "このメソッドは24時間以内に自動的に払い戻しを行います..."(ただしこのメソッドはコードベースに存在しません)

ハルシネーションを減らすための最も一般的な方法は、RAG(セクション15)を使用してモデルを実際のドキュメントに固定すること、そして、コンテキストに十分な情報がない場合には、モデルが推測する代わりに「わかりません」と答えるよう要求することです。

20. ガードレール

ガードレールは、エンドユーザーに結果を返す前に、LLMの周りに設定された制御レイヤーのセット(入力/出力フィルター、形式の検証、機密コンテンツのブロック)で、システムが安全で基準を満たしていることを保証します。

String output = chatClient.prompt().user(userInput).call().content();

if (containsPersonalData(output) || !isValidJson(output)) {
    throw new UnsafeModelOutputException("出力はガードレール基準を満たしていません");
}

ガードレールは、入力(プロンプトインジェクション、有害なコンテンツをブロック)または出力(JSON形式を確認、銀行口座番号をマスク)に配置できます。デモで「正しく見えても」、実際の製品にLLMを導入するときはこのステップをスキップしないでください。

21. RLHF(人間のフィードバックからの強化学習)

RLHFは、人間のフィードバックに基づいてモデルを学習させる技術です。人間がモデルの複数の回答をランク付けし、その後、「リワードモデル」を学習させてさらにモデルを最適化し、より有用で安全な回答を提供するようにします。

ステップ1: 同じ質問に対してモデルが3~4つの異なる回答を生成
ステップ2: 人間がランク付け: 最高→最低
ステップ3: 人間がスコアを付けるための方法をリワードモデルに学習させる
ステップ4: リワードモデルを使用して、強化学習によってLLMをファインチューニング

RLHFは、ChatGPT、Claudeが「トーン」が丁寧で、危険な要求を拒否する理由です。これは、純粋に「次の単語を推測する」ように学習した元のモデルとは異なります。

22. まとめ

上記の20の概念は、LLMで真剣に作業するための最小限の語彙です。トークン、エンベディング、attentionなどの下位層から、RAG、関数呼び出し、エージェント、ガードレールなどのアプリケーション層まで。Transformerの数学を深く理解する必要がないかもしれませんが、Spring BootシステムにLLMを統合するには十分です。ただし、これらの概念を正しく理解することで、適切なソリューションを選択できます。例えば、いつファインチューニングの代わりにRAGを使用するか、いつモデルの出力を完全に信頼する代わりにガードレールが必要かなど。

llmainlpprompt-engineeringspring-ai