- HOME >
- Jamstack用語集 >
- LLM
LLM
Large Language Model(大規模言語モデル)
LLM を分かりやすく
LLM(Large Language Model、大規模言語モデル)について、分かりやすく説明しますね。
想像してみてください。あなたが図書館の司書で、何千冊もの本を読んで内容を記憶しているとします。読書家のあなたは、様々なジャンルの本から得た知識を組み合わせて、訪問者の質問に答えることができます。小説の文体を真似て文章を書いたり、技術書の内容を要約したり、詩を作ったりすることも可能です。
LLM はまさにこの「超人的な司書」のような存在です。インターネット上の膨大なテキストデータ(ウェブページ、書籍、論文、コードなど)を学習して、人間のような自然な文章を生成したり、質問に答えたり、プログラムコードを書いたりできるようになりました。
LLM の仕組み
LLM は「Transformer」と呼ばれるニューラルネットワークアーキテクチャをベースにしています。簡単に言うと、「次に来る単語を予測する」という学習を何兆回も繰り返すことで、言語のパターンや構造を理解するようになります。
例えば、「今日の天気は」という文章を見せると、LLM は過去の学習から「晴れ」「曇り」「雨」などの単語が続く可能性が高いと予測します。しかし、これは単純な予測ではありません。文脈、前後の文章、話題の流れなどを総合的に判断して、最も適切な続きを生成します。
代表的な LLM
現在、いくつかの主要な LLM が存在します:
OpenAI GPT シリーズ
- GPT-4: 最も高性能な汎用モデル。複雑な推論、コード生成、画像理解が可能
- GPT-4 Turbo: GPT-4 の高速版。コンテキストウィンドウが広い(128K トークン)
- GPT-3.5 Turbo: より安価で高速。一般的なタスクに十分な性能
Anthropic Claude シリーズ
- Claude 3.5 Sonnet: コーディングと推論に優れる。200K トークンのコンテキスト
- Claude 3 Opus: 最も高性能なモデル
- Claude 3 Haiku: 高速で安価なモデル
Google Gemini シリーズ
- Gemini 1.5 Pro: 最大 2M トークンの超長文対応
- Gemini 1.5 Flash: 高速で効率的なモデル
Next.js × TypeScript で複数の LLM を活用する
実際のアプリケーション開発では、用途に応じて複数の LLM を使い分けることが重要です。Vercel AI SDK を使うと、統一的なインターフェースで複数の LLM を扱えます。
環境構築
npm install ai @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/google
環境変数を設定します。
# .env.local
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GOOGLE_GENERATIVE_AI_API_KEY=...
マルチプロバイダー対応のチャット API
// app/api/chat/route.ts
import { createOpenAI } from '@ai-sdk/openai'
import { createAnthropic } from '@ai-sdk/anthropic'
import { createGoogleGenerativeAI } from '@ai-sdk/google'
import { streamText } from 'ai'
export const runtime = 'edge'
// プロバイダーの初期化
const openai = createOpenAI({
apiKey: process.env.OPENAI_API_KEY,
})
const anthropic = createAnthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
})
const google = createGoogleGenerativeAI({
apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
})
// モデルマッピング
const models = {
'gpt-4': openai('gpt-4'),
'gpt-3.5-turbo': openai('gpt-3.5-turbo'),
'claude-3-5-sonnet': anthropic('claude-3-5-sonnet-20241022'),
'claude-3-haiku': anthropic('claude-3-haiku-20240307'),
'gemini-1.5-pro': google('gemini-1.5-pro-latest'),
} as const
type ModelName = keyof typeof models
export async function POST(req: Request) {
try {
const { messages, modelName = 'gpt-4' } = await req.json()
// 指定されたモデルを取得
const model = models[modelName as ModelName] || models['gpt-4']
// ストリーミングレスポンスを生成
const result = await streamText({
model,
messages,
temperature: 0.7,
maxTokens: 2000,
})
return result.toDataStreamResponse()
} catch (error) {
console.error('LLM API Error:', error)
return new Response('エラーが発生しました', { status: 500 })
}
}
フロントエンドでのモデル選択
// app/chat/page.tsx
'use client'
import { useChat } from 'ai/react'
import { useState } from 'react'
type ModelOption = {
id: string
name: string
description: string
provider: string
}
const modelOptions: ModelOption[] = [
{
id: 'gpt-4',
name: 'GPT-4',
description: '最も高性能な汎用モデル',
provider: 'OpenAI',
},
{
id: 'gpt-3.5-turbo',
name: 'GPT-3.5 Turbo',
description: '高速で安価なモデル',
provider: 'OpenAI',
},
{
id: 'claude-3-5-sonnet',
name: 'Claude 3.5 Sonnet',
description: 'コーディングと推論に優れる',
provider: 'Anthropic',
},
{
id: 'gemini-1.5-pro',
name: 'Gemini 1.5 Pro',
description: '超長文対応(2M トークン)',
provider: 'Google',
},
]
export default function ChatPage() {
const [selectedModel, setSelectedModel] = useState('gpt-4')
const { messages, input, handleInputChange, handleSubmit, isLoading, reload } = useChat({
api: '/api/chat',
body: {
modelName: selectedModel,
},
})
return (
<div className="container mx-auto max-w-4xl p-4">
<div className="flex justify-between items-center mb-6">
<h1 className="text-3xl font-bold">マルチモデルチャット</h1>
{/* モデル選択 */}
<select
value={selectedModel}
onChange={(e) => setSelectedModel(e.target.value)}
className="border border-gray-300 rounded-lg px-4 py-2"
disabled={isLoading}
>
{modelOptions.map((option) => (
<option key={option.id} value={option.id}>
{option.name} - {option.provider}
</option>
))}
</select>
</div>
{/* 選択中のモデル情報 */}
<div className="bg-blue-50 border border-blue-200 rounded-lg p-3 mb-4">
<p className="text-sm text-blue-900">
<span className="font-semibold">現在のモデル:</span>{' '}
{modelOptions.find((m) => m.id === selectedModel)?.description}
</p>
</div>
{/* メッセージ表示エリア */}
<div className="bg-gray-50 rounded-lg p-4 h-[500px] overflow-y-auto mb-4">
{messages.map((message) => (
<div
key={message.id}
className={`mb-4 ${message.role === 'user' ? 'text-right' : 'text-left'}`}
>
<div
className={`inline-block rounded-lg px-4 py-2 max-w-[80%] ${
message.role === 'user'
? 'bg-blue-500 text-white'
: 'bg-white border border-gray-200'
}`}
>
<p className="text-xs text-gray-500 mb-1">
{message.role === 'user' ? 'あなた' : selectedModel}
</p>
<p className="whitespace-pre-wrap">{message.content}</p>
</div>
</div>
))}
</div>
{/* 入力フォーム */}
<form onSubmit={handleSubmit} className="flex gap-2">
<input
type="text"
value={input}
onChange={handleInputChange}
placeholder="メッセージを入力..."
className="flex-1 border border-gray-300 rounded-lg px-4 py-2"
disabled={isLoading}
/>
<button
type="submit"
disabled={isLoading || !input.trim()}
className="bg-blue-500 text-white px-6 py-2 rounded-lg hover:bg-blue-600 disabled:bg-gray-300"
>
送信
</button>
</form>
</div>
)
}
LLM を用途別に使い分ける
実践的なアプリケーションでは、タスクの性質に応じて LLM を使い分けることでコストと性能を最適化できます。
// lib/model-selector.ts
type TaskType = 'simple' | 'complex' | 'code' | 'long-context'
export function selectOptimalModel(taskType: TaskType): string {
const modelMapping: Record<TaskType, string> = {
// 簡単なタスク: 安価で高速なモデル
simple: 'gpt-3.5-turbo',
// 複雑な推論: 高性能モデル
complex: 'gpt-4',
// コーディング: Claude が得意
code: 'claude-3-5-sonnet',
// 長文処理: Gemini の超長コンテキスト
'long-context': 'gemini-1.5-pro',
}
return modelMapping[taskType]
}
// 使用例
export async function POST(req: Request) {
const { messages, taskType = 'simple' } = await req.json()
const modelName = selectOptimalModel(taskType as TaskType)
const model = models[modelName as ModelName]
const result = await streamText({
model,
messages,
})
return result.toDataStreamResponse()
}
LLM のコンテキストウィンドウを理解する
LLM には「コンテキストウィンドウ」という制限があります。これは、一度に処理できるテキストの最大長です。
// lib/context-manager.ts
const contextLimits = {
'gpt-3.5-turbo': 16385, // 約 16K トークン
'gpt-4': 8192, // 約 8K トークン
'gpt-4-turbo': 128000, // 約 128K トークン
'claude-3-5-sonnet': 200000, // 約 200K トークン
'gemini-1.5-pro': 2000000, // 約 2M トークン
}
// トークン数を概算(1 トークン ≈ 4 文字と仮定)
export function estimateTokens(text: string): number {
return Math.ceil(text.length / 4)
}
// コンテキストウィンドウに収まるかチェック
export function checkContextLimit(
messages: Array<{ content: string }>,
modelName: string
): { withinLimit: boolean; estimatedTokens: number } {
const totalText = messages.map((m) => m.content).join('')
const estimatedTokens = estimateTokens(totalText)
const limit = contextLimits[modelName as keyof typeof contextLimits] || 8192
return {
withinLimit: estimatedTokens < limit * 0.9, // 安全のため 90% を上限とする
estimatedTokens,
}
}
ストリーミングと非ストリーミングの使い分け
LLM の応答には、ストリーミング(逐次的に返す)と非ストリーミング(全体を一度に返す)の 2 種類があります。
// app/api/generate/route.ts
import { generateText, streamText } from 'ai'
import { createOpenAI } from '@ai-sdk/openai'
const openai = createOpenAI({
apiKey: process.env.OPENAI_API_KEY,
})
// 非ストリーミング(構造化されたデータを返す場合に適している)
export async function POST(req: Request) {
const { prompt, useStreaming = true } = await req.json()
if (useStreaming) {
// ストリーミング: ユーザーに逐次表示
const result = await streamText({
model: openai('gpt-4'),
prompt,
})
return result.toDataStreamResponse()
} else {
// 非ストリーミング: JSON レスポンスとして返す
const result = await generateText({
model: openai('gpt-4'),
prompt,
})
return Response.json({
text: result.text,
finishReason: result.finishReason,
usage: result.usage,
})
}
}
LLM のパラメータ調整
LLM の出力は、パラメータによって大きく変わります。
// 創造的なコンテンツ生成
const creativeResult = await generateText({
model: openai('gpt-4'),
prompt: '短編小説を書いてください',
temperature: 0.9, // 高い値 = より創造的
topP: 0.95,
maxTokens: 2000,
})
// 事実に基づいた回答
const factualResult = await generateText({
model: openai('gpt-4'),
prompt: '第二次世界大戦について説明してください',
temperature: 0.3, // 低い値 = より決定的
topP: 0.9,
maxTokens: 1000,
})
// コード生成
const codeResult = await generateText({
model: anthropic('claude-3-5-sonnet-20241022'),
prompt: 'TypeScript でソート関数を実装してください',
temperature: 0.2, // 低い値 = より正確
maxTokens: 500,
})
まとめ
LLM は、現代の AI アプリケーション開発の中核を担う技術です。Next.js と TypeScript を組み合わせることで、複数の LLM を統一的に扱い、用途に応じて最適なモデルを選択できます。
重要なポイント:
- 適材適所でモデルを選択:タスクの複雑さに応じて GPT-4、Claude、Gemini を使い分ける
- コンテキストウィンドウを理解する:各モデルの処理可能なテキスト量を把握
- ストリーミングでUX向上:リアルタイムで応答を表示してユーザー体験を改善
- パラメータ調整でコントロール:temperature や topP で出力の特性を変更
- コスト管理:安価なモデルと高性能モデルを使い分けてコスト最適化
LLM を活用することで、これまで不可能だった機能を Web アプリケーションに追加できます。自然言語でのユーザーインタラクション、コンテンツ生成、データ分析など、可能性は無限大です。