LangChain Agentの種類完全ガイド:JavaScriptで学ぶ各エージェントの特徴と使い方
はじめに
LangChainでは、様々な種類のAgentが提供されており、それぞれ異なる思考プロセスと実行戦略を持っています。この記事では、LangChain.jsを使用して、主要なAgentの種類とその特徴、実装方法を詳しく解説します。各Agentの適切な使い分けを理解することで、より効果的なAIエージェントアプリケーションを構築できます。
Agentとは
Agentの基本概念
Agentは、LLMとツールを組み合わせて、複雑なタスクを自律的に実行するシステムです。Agentは以下の能力を持ちます:
- 思考: タスクを分析し、必要なアクションを決定
- ツール使用: 外部ツールを呼び出して情報を取得
- 観察: ツールの結果を観察し、次のアクションを決定
- 反復: 目標達成まで必要なアクションを繰り返し実行
Agentの基本構造
import { ChatOpenAI } from "@langchain/openai";
import { AgentExecutor, createOpenAIFunctionsAgent } from "langchain/agents";
import { ChatPromptTemplate } from "@langchain/core/prompts";
// LLMの初期化
const llm = new ChatOpenAI({
modelName: "gpt-4",
temperature: 0,
});
// ツールの定義
const tools = [/* ツールの配列 */];
// Agentの作成
const agent = await createOpenAIFunctionsAgent({
llm,
tools,
prompt: ChatPromptTemplate.fromMessages([/* プロンプト */]),
});
// AgentExecutorの作成
const agentExecutor = new AgentExecutor({
agent,
tools,
verbose: true,
});
主要なAgentの種類
1. ReAct Agent
特徴
ReAct(Reasoning + Acting)Agentは、推論と行動を交互に行うAgentです。思考プロセスを明示的に示しながら、ツールを使用してタスクを実行します。
特徴:
- 思考プロセスが透明
- 段階的な問題解決
- デバッグが容易
実装例
import { ChatOpenAI } from "@langchain/openai";
import { AgentExecutor, createReactAgent } from "langchain/agents";
import { ChatPromptTemplate, MessagesPlaceholder } from "@langchain/core/prompts";
import { pull } from "langchain/hub";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { z } from "zod";
// LLMの初期化
const llm = new ChatOpenAI({
modelName: "gpt-4",
temperature: 0,
});
// ツールの定義
const calculatorTool = new DynamicStructuredTool({
name: "calculator",
description: "数式を計算します。例: (2 + 2) * 3",
schema: z.object({
expression: z.string().describe("計算する数式"),
}),
func: async ({ expression }) => {
try {
return eval(expression).toString();
} catch (error) {
return `エラー: ${error.message}`;
}
},
});
const tools = [calculatorTool];
// ReAct Agentのプロンプト
const prompt = await pull<ChatPromptTemplate>("hwchase17/react");
// Agentの作成
const agent = await createReactAgent({
llm,
tools,
prompt,
});
// AgentExecutorの作成
const agentExecutor = new AgentExecutor({
agent,
tools,
verbose: true,
maxIterations: 15,
});
// Agentの実行
const result = await agentExecutor.invoke({
input: "2 + 2 の結果に 3 を掛けて、その結果を 2 で割ってください",
});
console.log(result.output);
実行例の出力
思考: まず 2 + 2 を計算する必要があります。
行動: calculator
行動入力: {"expression": "2 + 2"}
観察: 4
思考: 次に 4 * 3 を計算します。
行動: calculator
行動入力: {"expression": "4 * 3"}
観察: 12
思考: 最後に 12 / 2 を計算します。
行動: calculator
行動入力: {"expression": "12 / 2"}
観察: 6
思考: 計算が完了しました。答えは 6 です。
最終回答: 6
2. OpenAI Functions Agent
特徴
OpenAI Functions Agentは、OpenAIのFunction Calling機能を活用したAgentです。構造化されたツール定義を使用し、高精度なツール呼び出しが可能です。
特徴:
- OpenAIのFunction Callingを活用
- 構造化されたツール定義
- 高精度なツール選択
実装例
import { ChatOpenAI } from "@langchain/openai";
import { AgentExecutor, createOpenAIFunctionsAgent } from "langchain/agents";
import { ChatPromptTemplate, MessagesPlaceholder } from "@langchain/core/prompts";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { z } from "zod";
// LLMの初期化
const llm = new ChatOpenAI({
modelName: "gpt-4",
temperature: 0,
});
// 天気情報を取得するツール
const weatherTool = new DynamicStructuredTool({
name: "get_weather",
description: "指定された都市の天気情報を取得します",
schema: z.object({
city: z.string().describe("天気を取得する都市名"),
}),
func: async ({ city }) => {
// 実際の実装では、天気APIを呼び出す
return `${city}の天気は晴れ、気温は22度です`;
},
});
// 計算ツール
const calculatorTool = new DynamicStructuredTool({
name: "calculator",
description: "数式を計算します",
schema: z.object({
expression: z.string().describe("計算する数式"),
}),
func: async ({ expression }) => {
try {
return eval(expression).toString();
} catch (error) {
return `エラー: ${error.message}`;
}
},
});
const tools = [weatherTool, calculatorTool];
// プロンプトの作成
const prompt = ChatPromptTemplate.fromMessages([
["system", "あなたは親切なアシスタントです。利用可能なツールを使用して質問に答えてください。"],
["human", "{input}"],
new MessagesPlaceholder("agent_scratchpad"),
]);
// Agentの作成
const agent = await createOpenAIFunctionsAgent({
llm,
tools,
prompt,
});
// AgentExecutorの作成
const agentExecutor = new AgentExecutor({
agent,
tools,
verbose: true,
});
// Agentの実行
const result = await agentExecutor.invoke({
input: "東京の天気を教えて、その気温に10を足した値を計算してください",
});
console.log(result.output);
3. Structured Chat Agent
特徴
Structured Chat Agentは、構造化された出力を生成するAgentです。複雑なタスクを段階的に処理し、各ステップで構造化された情報を扱います。
特徴:
- 構造化された出力
- 複雑なタスクの段階的処理
- 明確なアクションプラン
実装例
import { ChatOpenAI } from "@langchain/openai";
import { AgentExecutor, createStructuredChatAgent } from "langchain/agents";
import { ChatPromptTemplate, MessagesPlaceholder } from "@langchain/core/prompts";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { z } from "zod";
// LLMの初期化
const llm = new ChatOpenAI({
modelName: "gpt-4",
temperature: 0,
});
// データベース検索ツール
const searchDatabaseTool = new DynamicStructuredTool({
name: "search_database",
description: "データベースから情報を検索します",
schema: z.object({
query: z.string().describe("検索クエリ"),
table: z.string().describe("検索するテーブル名"),
}),
func: async ({ query, table }) => {
// 実際の実装では、データベースクエリを実行
return `テーブル ${table} から "${query}" で検索した結果: 3件のレコードが見つかりました`;
},
});
// レポート生成ツール
const generateReportTool = new DynamicStructuredTool({
name: "generate_report",
description: "レポートを生成します",
schema: z.object({
data: z.string().describe("レポートに含めるデータ"),
format: z.enum(["json", "csv", "markdown"]).describe("レポートの形式"),
}),
func: async ({ data, format }) => {
return `${format}形式のレポートを生成しました: ${data}`;
},
});
const tools = [searchDatabaseTool, generateReportTool];
// プロンプトの作成
const prompt = ChatPromptTemplate.fromMessages([
["system", `あなたはデータ分析エージェントです。以下の手順でタスクを実行してください:
1. データベースから必要な情報を検索
2. 検索結果を分析
3. レポートを生成
利用可能なツール: {tool_names}`],
["human", "{input}"],
new MessagesPlaceholder("agent_scratchpad"),
]);
// Agentの作成
const agent = await createStructuredChatAgent({
llm,
tools,
prompt,
});
// AgentExecutorの作成
const agentExecutor = new AgentExecutor({
agent,
tools,
verbose: true,
});
// Agentの実行
const result = await agentExecutor.invoke({
input: "ユーザーテーブルからアクティブなユーザーを検索して、JSON形式のレポートを生成してください",
});
console.log(result.output);
4. Plan-and-Execute Agent
特徴
Plan-and-Execute Agentは、まず全体の計画を立て、その後計画に従って実行するAgentです。複雑なタスクを複数のステップに分解して処理します。
特徴:
- 事前計画の作成
- 段階的な実行
- 計画の調整が可能
実装例
import { ChatOpenAI } from "@langchain/openai";
import { PlanAndExecuteAgentExecutor } from "langchain/experimental/plan_and_execute";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { z } from "zod";
// LLMの初期化
const llm = new ChatOpenAI({
modelName: "gpt-4",
temperature: 0,
});
// ファイル読み込みツール
const readFileTool = new DynamicStructuredTool({
name: "read_file",
description: "ファイルの内容を読み込みます",
schema: z.object({
filepath: z.string().describe("読み込むファイルのパス"),
}),
func: async ({ filepath }) => {
// 実際の実装では、ファイルシステムから読み込む
return `ファイル ${filepath} の内容: サンプルデータ`;
},
});
// ファイル書き込みツール
const writeFileTool = new DynamicStructuredTool({
name: "write_file",
description: "ファイルに内容を書き込みます",
schema: z.object({
filepath: z.string().describe("書き込むファイルのパス"),
content: z.string().describe("書き込む内容"),
}),
func: async ({ filepath, content }) => {
return `ファイル ${filepath} に書き込みました`;
},
});
// データ処理ツール
const processDataTool = new DynamicStructuredTool({
name: "process_data",
description: "データを処理します",
schema: z.object({
data: z.string().describe("処理するデータ"),
operation: z.enum(["filter", "sort", "aggregate"]).describe("実行する操作"),
}),
func: async ({ data, operation }) => {
return `${operation} 操作を実行しました: 処理済みデータ`;
},
});
const tools = [readFileTool, writeFileTool, processDataTool];
// Plan-and-Execute AgentExecutorの作成
const executor = PlanAndExecuteAgentExecutor.fromLLMAndTools({
llm,
tools,
verbose: true,
});
// Agentの実行
const result = await executor.invoke({
input: "data.txtファイルを読み込んで、データをフィルタリングし、結果をoutput.txtに保存してください",
});
console.log(result.output);
5. Self-Ask-with-Search Agent
特徴
Self-Ask-with-Search Agentは、質問を自分自身に投げかけ、検索ツールを使用して情報を取得するAgentです。段階的な推論を行います。
特徴:
- 自己質問による推論
- 検索ツールの活用
- 段階的な情報収集
実装例
import { ChatOpenAI } from "@langchain/openai";
import { AgentExecutor, createSelfAskWithSearchAgent } from "langchain/agents";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { z } from "zod";
// LLMの初期化
const llm = new ChatOpenAI({
modelName: "gpt-4",
temperature: 0,
});
// 検索ツール
const searchTool = new DynamicStructuredTool({
name: "search",
description: "最新の情報を検索します",
schema: z.object({
query: z.string().describe("検索クエリ"),
}),
func: async ({ query }) => {
// 実際の実装では、検索APIを呼び出す
return `${query} に関する検索結果: 関連する情報が見つかりました`;
},
});
const tools = [searchTool];
// プロンプトの作成
const prompt = ChatPromptTemplate.fromMessages([
["system", `あなたは情報検索エージェントです。質問に答えるために、以下の手順で進めてください:
1. 質問を分解して、必要な情報を特定
2. 各情報について検索を実行
3. 検索結果を統合して回答
利用可能なツール: {tool_names}`],
["human", "{input}"],
]);
// Agentの作成
const agent = await createSelfAskWithSearchAgent({
llm,
tools,
prompt,
});
// AgentExecutorの作成
const agentExecutor = new AgentExecutor({
agent,
tools,
verbose: true,
});
// Agentの実行
const result = await agentExecutor.invoke({
input: "LangChainの最新バージョンと、その主な新機能について教えてください",
});
console.log(result.output);
6. Conversational Agent
特徴
Conversational Agentは、会話履歴を保持しながら、ツールを使用してタスクを実行するAgentです。継続的な対話が可能です。
特徴:
- 会話履歴の管理
- コンテキストの保持
- 継続的な対話
実装例
import { ChatOpenAI } from "@langchain/openai";
import { AgentExecutor, createConversationalRetrievalAgent } from "langchain/agents";
import { ChatPromptTemplate, MessagesPlaceholder } from "@langchain/core/prompts";
import { BufferMemory } from "langchain/memory";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { z } from "zod";
// LLMの初期化
const llm = new ChatOpenAI({
modelName: "gpt-4",
temperature: 0,
});
// メモリの初期化
const memory = new BufferMemory({
memoryKey: "chat_history",
returnMessages: true,
});
// カレンダーツール
const calendarTool = new DynamicStructuredTool({
name: "check_calendar",
description: "カレンダーを確認します",
schema: z.object({
date: z.string().describe("確認する日付(YYYY-MM-DD形式)"),
}),
func: async ({ date }) => {
return `${date} の予定: 会議が2件、タスクが3件あります`;
},
});
// メール送信ツール
const sendEmailTool = new DynamicStructuredTool({
name: "send_email",
description: "メールを送信します",
schema: z.object({
to: z.string().describe("送信先のメールアドレス"),
subject: z.string().describe("メールの件名"),
body: z.string().describe("メールの本文"),
}),
func: async ({ to, subject, body }) => {
return `メールを ${to} に送信しました: ${subject}`;
},
});
const tools = [calendarTool, sendEmailTool];
// プロンプトの作成
const prompt = ChatPromptTemplate.fromMessages([
["system", "あなたは親切なアシスタントです。会話履歴を参照しながら、利用可能なツールを使用してタスクを実行してください。"],
new MessagesPlaceholder("chat_history"),
["human", "{input}"],
new MessagesPlaceholder("agent_scratchpad"),
]);
// Agentの作成
const agent = await createConversationalRetrievalAgent({
llm,
tools,
prompt,
});
// AgentExecutorの作成
const agentExecutor = new AgentExecutor({
agent,
tools,
memory,
verbose: true,
});
// 継続的な対話
const conversation1 = await agentExecutor.invoke({
input: "今日の予定を教えてください",
});
console.log(conversation1.output);
const conversation2 = await agentExecutor.invoke({
input: "その会議の参加者にメールを送ってください",
});
console.log(conversation2.output);
7. Zero-shot Agent
特徴
Zero-shot Agentは、事前の例やトレーニングなしで、ツールの説明のみから適切なツールを選択して使用するAgentです。
特徴:
- 事前の例が不要
- ツールの説明から推論
- 柔軟なツール選択
実装例
import { ChatOpenAI } from "@langchain/openai";
import { AgentExecutor, createOpenAIFunctionsAgent } from "langchain/agents";
import { ChatPromptTemplate, MessagesPlaceholder } from "@langchain/core/prompts";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { z } from "zod";
// LLMの初期化
const llm = new ChatOpenAI({
modelName: "gpt-4",
temperature: 0,
});
// 多様なツールの定義
const tools = [
new DynamicStructuredTool({
name: "get_weather",
description: "指定された都市の天気情報を取得します",
schema: z.object({
city: z.string().describe("都市名"),
}),
func: async ({ city }) => `${city}の天気: 晴れ、22度`,
}),
new DynamicStructuredTool({
name: "translate",
description: "テキストを翻訳します",
schema: z.object({
text: z.string().describe("翻訳するテキスト"),
target_language: z.string().describe("翻訳先の言語"),
}),
func: async ({ text, target_language }) => `翻訳結果: ${text} (${target_language})`,
}),
new DynamicStructuredTool({
name: "calculate",
description: "数式を計算します",
schema: z.object({
expression: z.string().describe("計算する数式"),
}),
func: async ({ expression }) => {
try {
return eval(expression).toString();
} catch (error) {
return `エラー: ${error.message}`;
}
},
}),
];
// プロンプトの作成
const prompt = ChatPromptTemplate.fromMessages([
["system", "あなたは多機能アシスタントです。利用可能なツールの説明を読んで、適切なツールを選択してタスクを実行してください。"],
["human", "{input}"],
new MessagesPlaceholder("agent_scratchpad"),
]);
// Agentの作成
const agent = await createOpenAIFunctionsAgent({
llm,
tools,
prompt,
});
// AgentExecutorの作成
const agentExecutor = new AgentExecutor({
agent,
tools,
verbose: true,
});
// Agentの実行
const result = await agentExecutor.invoke({
input: "東京の天気を英語で翻訳してください",
});
console.log(result.output);
Agentの選択ガイド
用途別の推奨Agent
| 用途 | 推奨Agent | 理由 |
|---|---|---|
| シンプルなタスク | OpenAI Functions Agent | 高精度で使いやすい |
| 複雑な推論が必要 | ReAct Agent | 思考プロセスが透明 |
| 多段階のタスク | Plan-and-Execute Agent | 計画と実行を分離 |
| 検索が必要 | Self-Ask-with-Search Agent | 段階的な情報収集 |
| 会話型アプリ | Conversational Agent | 会話履歴の管理 |
| 構造化された出力 | Structured Chat Agent | 明確なアクションプラン |
パフォーマンス比較
// パフォーマンス測定関数
async function measureAgentPerformance(agentExecutor, input, iterations = 10) {
const times = [];
for (let i = 0; i < iterations; i++) {
const start = Date.now();
await agentExecutor.invoke({ input });
const end = Date.now();
times.push(end - start);
}
const avgTime = times.reduce((a, b) => a + b, 0) / times.length;
const minTime = Math.min(...times);
const maxTime = Math.max(...times);
return {
average: avgTime,
min: minTime,
max: maxTime,
};
}
// 各Agentのパフォーマンス測定
// const reactPerformance = await measureAgentPerformance(reactExecutor, "タスク");
// const openaiPerformance = await measureAgentPerformance(openaiExecutor, "タスク");
ベストプラクティス
1. 適切なAgentの選択
// タスクの複雑さに応じてAgentを選択
function selectAgent(taskComplexity) {
if (taskComplexity === "simple") {
return createOpenAIFunctionsAgent;
} else if (taskComplexity === "moderate") {
return createReactAgent;
} else {
return createPlanAndExecuteAgent;
}
}
2. ツールの最適化
// ツールの説明を明確に
const goodTool = new DynamicStructuredTool({
name: "get_user_info",
description: "ユーザーIDを指定して、ユーザーの名前、メールアドレス、登録日を取得します",
// ...
});
// 悪い例:説明が曖昧
const badTool = new DynamicStructuredTool({
name: "get_info",
description: "情報を取得します", // 曖昧すぎる
// ...
});
3. エラーハンドリング
// AgentExecutorのエラーハンドリング
try {
const result = await agentExecutor.invoke({
input: "タスク",
});
console.log(result.output);
} catch (error) {
console.error("Agent実行エラー:", error);
// フォールバック処理
}
4. コスト管理
// トークン使用量の監視
import { getTokenCount } from "@langchain/core/language_models/base";
const tokenCount = await getTokenCount(llm, "プロンプト");
console.log(`使用トークン数: ${tokenCount}`);
まとめ
LangChainでは、様々な種類のAgentが提供されており、それぞれ異なる特徴と用途を持っています。
主要なポイント
- ReAct Agent: 推論と行動を交互に行う、思考プロセスが透明
- OpenAI Functions Agent: OpenAIのFunction Callingを活用、高精度
- Structured Chat Agent: 構造化された出力、複雑なタスクの段階的処理
- Plan-and-Execute Agent: 事前計画の作成と段階的な実行
- Self-Ask-with-Search Agent: 自己質問と検索ツールの活用
- Conversational Agent: 会話履歴の管理、継続的な対話
- Zero-shot Agent: 事前の例なしでツールを選択
ベストプラクティス
- 適切なAgentの選択: タスクの性質に応じて最適なAgentを選択
- ツールの最適化: 明確な説明と適切なスキーマ定義
- エラーハンドリング: 適切なエラー処理とフォールバック
- パフォーマンス監視: 実行時間とコストの監視
適切なAgentを選択し、最適化することで、効果的なAIエージェントアプリケーションを構築できます。