- HOME >
- Jamstack用語集 >
- AI Agent
AI Agent
AI エージェント
AI Agent を分かりやすく
AI Agent(AI エージェント)は、単なる「質問に答える AI」から一歩進んだ、「自律的に行動する AI」です。
例え話をしましょう。あなたが「週末の旅行を計画して」と頼んだとします:
通常の AI: 「いいですね!どこに行きたいですか?予算は?」
- 受動的で、すべてをユーザーに聞く
- 一問一答形式
AI Agent: 「承知しました。まず、あなたの過去の旅行履歴を確認します...温泉が好きなようですね。次に、今週末の天気を調べます...関東地方は晴れです。予算データベースを確認すると、3万円程度ですね。それでは、箱根の温泉宿を検索して、予約可能な宿を3つ提案します...」
- 能動的で、自分で情報を集める
- 複数のステップを自律的に実行
- ツールを使いこなす
AI Agent は、「目標」を与えられると、それを達成するために必要なステップを自分で考え、適切なツールを使って実行します。まるで有能な人間のアシスタントのように動くのです。
AI Agent のアーキテクチャ
AI Agent は通常、以下の要素で構成されます:
- Planner(計画者): タスクを分解して実行計画を立てる
- Executor(実行者): 計画に基づいてツールを実行
- Memory(記憶): 過去の会話や実行結果を記憶
- Tools(ツール): 検索、計算、API 呼び出しなどの機能
Next.js × TypeScript で AI Agent を実装する
ステップ 1: Agent の基本構造
// lib/agent/types.ts
export type AgentStep = {
thought: string // AI の思考プロセス
action: string // 実行するアクション
actionInput: any // アクションへの入力
observation: string // アクション実行後の観察結果
}
export type AgentResult = {
finalAnswer: string
steps: AgentStep[]
iterations: number
}
export type Tool = {
name: string
description: string
execute: (input: any) => Promise<any>
}
ステップ 2: ツールの定義
// lib/agent/tools.ts
import { Tool } from './types'
// ウェブ検索ツール(簡易実装)
export const searchTool: Tool = {
name: 'web_search',
description: 'インターネットで情報を検索します。最新情報や事実確認に使用してください。',
execute: async (query: string) => {
// 実際には Google Custom Search API などを使用
return {
results: [
{
title: '検索結果のタイトル',
snippet: '検索結果の要約...',
url: 'https://example.com',
},
],
}
},
}
// 計算ツール
export const calculatorTool: Tool = {
name: 'calculator',
description: '数学的な計算を実行します。複雑な計算式も処理できます。',
execute: async (expression: string) => {
try {
const result = Function('"use strict"; return (' + expression + ')')()
return { result }
} catch (error) {
return { error: '計算エラー' }
}
},
}
// データベース検索ツール
export const databaseSearchTool: Tool = {
name: 'database_search',
description: 'データベースから情報を検索します。製品情報、ユーザー情報などを取得できます。',
execute: async ({ table, query }: { table: string; query: string }) => {
// 実際には Prisma や SQL を使用
return {
results: [
{ id: 1, name: 'サンプルデータ', description: '...' },
],
}
},
}
// 全てのツールを配列にまとめる
export const availableTools: Tool[] = [
searchTool,
calculatorTool,
databaseSearchTool,
]
// ツール名から取得
export function getTool(name: string): Tool | undefined {
return availableTools.find((tool) => tool.name === name)
}
ステップ 3: ReAct パターンの実装
ReAct(Reasoning + Acting)は、AI Agent の代表的なパターンです。
// lib/agent/react-agent.ts
import OpenAI from 'openai'
import { AgentStep, AgentResult, Tool } from './types'
import { availableTools, getTool } from './tools'
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
})
const REACT_PROMPT = `あなたは自律的に行動できる AI エージェントです。以下のツールを使用できます:
{tools}
以下の形式で考え、行動してください:
Thought: 何を考えているか
Action: 使用するツール名
Action Input: ツールへの入力
Observation: ツールの実行結果
このサイクルを繰り返し、最終的な答えが分かったら以下の形式で返してください:
Thought: 最終的な答えが分かった
Final Answer: [答え]
それでは、以下の質問に答えてください:
{question}`
export async function runReActAgent(
question: string,
maxIterations: number = 10
): Promise<AgentResult> {
const steps: AgentStep[] = []
let currentIteration = 0
// ツール情報をプロンプトに埋め込む
const toolsDescription = availableTools
.map((tool) => `- ${tool.name}: ${tool.description}`)
.join('\n')
const initialPrompt = REACT_PROMPT.replace('{tools}', toolsDescription).replace(
'{question}',
question
)
let conversationHistory = initialPrompt
let finalAnswer = ''
while (currentIteration < maxIterations) {
// AI に次のステップを考えさせる
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages: [
{
role: 'system',
content: 'あなたは ReAct パターンに従って動作する AI エージェントです。',
},
{
role: 'user',
content: conversationHistory,
},
],
temperature: 0.3,
})
const agentResponse = response.choices[0].message.content || ''
console.log(`\n=== Iteration ${currentIteration + 1} ===`)
console.log(agentResponse)
// Final Answer がある場合は終了
if (agentResponse.includes('Final Answer:')) {
finalAnswer = agentResponse.split('Final Answer:')[1].trim()
break
}
// Thought、Action、Action Input を抽出
const thoughtMatch = agentResponse.match(/Thought:(.*?)(?=Action:|$)/s)
const actionMatch = agentResponse.match(/Action:(.*?)(?=Action Input:|$)/s)
const actionInputMatch = agentResponse.match(/Action Input:(.*?)(?=Observation:|$)/s)
if (!thoughtMatch || !actionMatch || !actionInputMatch) {
throw new Error('AI の応答形式が正しくありません')
}
const thought = thoughtMatch[1].trim()
const action = actionMatch[1].trim()
const actionInput = actionInputMatch[1].trim()
// ツールを実行
const tool = getTool(action)
if (!tool) {
throw new Error(`ツール「${action}」が見つかりません`)
}
let observation: string
try {
const result = await tool.execute(actionInput)
observation = JSON.stringify(result, null, 2)
} catch (error) {
observation = `エラー: ${error}`
}
// ステップを記録
steps.push({
thought,
action,
actionInput,
observation,
})
// 会話履歴に追加
conversationHistory += `\n\n${agentResponse}\nObservation: ${observation}\n`
currentIteration++
}
if (!finalAnswer && currentIteration >= maxIterations) {
finalAnswer = '最大反復回数に達しました。タスクを完了できませんでした。'
}
return {
finalAnswer,
steps,
iterations: currentIteration,
}
}
ステップ 4: Agent API の実装
// app/api/agent/run/route.ts
import { runReActAgent } from '@/lib/agent/react-agent'
export async function POST(req: Request) {
try {
const { question } = await req.json()
if (!question || typeof question !== 'string') {
return new Response('question が必要です', { status: 400 })
}
const result = await runReActAgent(question)
return Response.json(result)
} catch (error) {
console.error('Agent Error:', error)
return new Response('エラーが発生しました', { status: 500 })
}
}
ステップ 5: フロントエンドの実装
// app/agent/page.tsx
'use client'
import { useState } from 'react'
import { AgentResult, AgentStep } from '@/lib/agent/types'
export default function AgentPage() {
const [question, setQuestion] = useState('')
const [result, setResult] = useState<AgentResult | null>(null)
const [isLoading, setIsLoading] = useState(false)
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
if (!question.trim() || isLoading) return
setIsLoading(true)
setResult(null)
try {
const response = await fetch('/api/agent/run', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ question }),
})
if (!response.ok) {
throw new Error('API エラー')
}
const data = await response.json()
setResult(data)
} catch (error) {
console.error('Error:', error)
alert('エラーが発生しました')
} finally {
setIsLoading(false)
}
}
return (
<div className="container mx-auto max-w-4xl p-4">
<h1 className="text-3xl font-bold mb-6">AI Agent デモ</h1>
{/* 説明 */}
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-6">
<h2 className="font-semibold mb-2">AI Agent ができること:</h2>
<ul className="list-disc list-inside space-y-1 text-sm">
<li>ウェブ検索で最新情報を取得</li>
<li>複雑な計算を実行</li>
<li>データベースから情報を検索</li>
<li>複数のツールを組み合わせてタスクを完了</li>
</ul>
<p className="mt-2 text-sm text-gray-600">
例: 「2024年のノーベル物理学賞受賞者の年齢の合計を計算して」
</p>
</div>
{/* 入力フォーム */}
<form onSubmit={handleSubmit} className="mb-6">
<textarea
value={question}
onChange={(e) => setQuestion(e.target.value)}
placeholder="AI Agent に質問してください..."
className="w-full border border-gray-300 rounded-lg px-4 py-2 mb-2"
rows={4}
disabled={isLoading}
/>
<button
type="submit"
disabled={isLoading || !question.trim()}
className="bg-blue-500 text-white px-6 py-2 rounded-lg hover:bg-blue-600 disabled:bg-gray-300"
>
{isLoading ? '実行中...' : 'Agent を実行'}
</button>
</form>
{/* 結果表示 */}
{result && (
<div className="bg-white border border-gray-200 rounded-lg p-6">
<h2 className="text-xl font-semibold mb-4">実行結果</h2>
{/* 最終的な答え */}
<div className="bg-green-50 border border-green-200 rounded-lg p-4 mb-4">
<h3 className="font-semibold text-green-900 mb-2">最終的な答え:</h3>
<p className="text-green-900">{result.finalAnswer}</p>
</div>
{/* 実行ステップ */}
<div>
<h3 className="font-semibold mb-3">
実行ステップ({result.iterations} 回の反復):
</h3>
<div className="space-y-4">
{result.steps.map((step, index) => (
<div
key={index}
className="border border-gray-200 rounded-lg p-4 bg-gray-50"
>
<h4 className="font-semibold text-sm text-gray-600 mb-2">
ステップ {index + 1}
</h4>
<div className="space-y-2 text-sm">
<div>
<span className="font-semibold">💭 Thought:</span>
<p className="text-gray-700 ml-4">{step.thought}</p>
</div>
<div>
<span className="font-semibold">🔧 Action:</span>
<code className="ml-2 bg-blue-100 px-2 py-1 rounded">
{step.action}
</code>
</div>
<div>
<span className="font-semibold">📥 Action Input:</span>
<pre className="ml-4 bg-gray-100 p-2 rounded overflow-x-auto text-xs">
{step.actionInput}
</pre>
</div>
<div>
<span className="font-semibold">👁️ Observation:</span>
<pre className="ml-4 bg-yellow-50 p-2 rounded overflow-x-auto text-xs">
{step.observation}
</pre>
</div>
</div>
</div>
))}
</div>
</div>
</div>
)}
</div>
)
}
高度な AI Agent パターン
メモリ機能の追加
// lib/agent/memory.ts
export class AgentMemory {
private conversationHistory: Array<{ role: string; content: string }> = []
add(role: string, content: string) {
this.conversationHistory.push({ role, content })
}
get() {
return this.conversationHistory
}
clear() {
this.conversationHistory = []
}
// 要約して長期記憶に保存
async summarize() {
// 会話が長くなった場合、要約して記憶を圧縮
// 実装は省略
}
}
まとめ
AI Agent は、単なるチャットボットを超えた、自律的に行動できる AI システムです。Next.js と TypeScript を組み合わせることで、型安全で拡張可能な AI Agent を構築できます。
重要なポイント:
- ReAct パターン: 思考→行動→観察のサイクルで動作
- ツール連携: 複数のツールを組み合わせてタスクを完了
- 自律性: ユーザーの指示を受けて、自分で実行計画を立てる
- メモリ: 過去の会話や実行結果を記憶
- 無限ループ防止: 最大反復回数を設定して暴走を防ぐ
AI Agent を活用することで、カスタマーサポート、データ分析、タスク自動化など、様々な用途で AI を実用化できます。