LangChain.jsとは? AIエージェント開発の定番フレームワークを活用例とコードで解説

LangChain.jsとは? AIエージェント開発の定番フレームワークを活用例とコードで解説

作成日:
更新日:

ChatGPTやClaudeなどのLLM(大規模言語モデル)をアプリケーションに組み込みたい。でも、各プロバイダーのAPIは仕様がバラバラで、ツール呼び出し・会話履歴の管理・ストリーミングなど、考えることが多すぎる――。

そんな課題を解決するのが LangChain.js です。

LangChain.jsとは

LangChain.jsは、LLMを活用したAIエージェントやアプリケーションを構築するためのオープンソースフレームワークです。TypeScript/JavaScriptで書かれており、Node.js・Deno・Bunなどの環境で動作します。

主な特徴

特徴説明
標準化されたモデルインターフェースOpenAI・Anthropic・Googleなど、異なるプロバイダーのAPIを統一的に扱える
プリビルトのエージェント構成createAgent()で10行以下のコードからエージェントを構築可能
ツール統合外部API・データベース・Web検索など、エージェントに「行動力」を与える
LangGraphベース永続実行・ヒューマンインザループ・ストリーミングなどの高度な機能を標準搭載
プロバイダーロックインなしモデル名を変えるだけでプロバイダーを切り替え可能

LangChain vs LangGraph vs Deep Agents

LangChainエコシステムには複数のレイヤーがあります。

Deep Agents  ← バッテリー同梱の高機能エージェント(会話圧縮・仮想FS・サブエージェント)
    ↑
LangChain    ← エージェント構築の標準レイヤー(本記事のメイン)
    ↑
LangGraph    ← 低レベルのオーケストレーション基盤(決定論的+エージェント的ワークフロー)
  • LangChain: 素早くエージェントを構築したいときの第一選択肢
  • LangGraph: 決定論的なワークフローとエージェント的な処理を組み合わせたい場合
  • Deep Agents: 長時間の会話圧縮やサブエージェント生成など、フル機能が必要な場合

セットアップ

インストール

npm install langchain @langchain/core zod

使用するLLMプロバイダーに応じて追加パッケージをインストールします。

# OpenAIを使う場合
npm install @langchain/openai
 
# Anthropic(Claude)を使う場合
npm install @langchain/anthropic
 
# Google(Gemini)を使う場合
npm install @langchain/google-genai

環境変数の設定

# 使うプロバイダーのAPIキーを設定
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."

基本: 最小構成のエージェント

まずは最もシンプルなエージェントを作ってみましょう。

import { createAgent, tool } from "langchain";
import * as z from "zod";
 
// ツールを定義
const getWeather = tool(
  ({ city }) => `${city}の天気は晴れ、気温25℃です。`,
  {
    name: "get_weather",
    description: "指定された都市の天気を取得する",
    schema: z.object({
      city: z.string().describe("天気を取得する都市名"),
    }),
  }
);
 
// エージェントを作成
const agent = createAgent({
  model: "claude-sonnet-4-5-20250929",
  tools: [getWeather],
});
 
// 実行
const result = await agent.invoke({
  messages: [{ role: "user", content: "東京の天気を教えて" }],
});
 
console.log(result);

たったこれだけで、ユーザーの質問に応じてツールを呼び出し、結果をもとに回答するエージェントが完成します。

ReActパターン

LangChain.jsのエージェントは ReAct(Reasoning + Acting)パターン に従います。

ユーザー: 「東京の天気を教えて」
    ↓
[推論] ユーザーは天気を知りたい → get_weatherツールを使おう
    ↓
[行動] get_weather({ city: "東京" }) を呼び出し
    ↓
[観測] 「東京の天気は晴れ、気温25℃です。」
    ↓
[推論] 結果を得た → ユーザーに回答しよう
    ↓
エージェント: 「東京の天気は晴れで、気温は25℃です。」

推論と行動を交互に繰り返し、最終的な回答に到達するまでループします。


活用例 1: 会話メモリ付きアシスタント

実用的なチャットボットには会話履歴の管理が欠かせません。MemorySaverを使うと、スレッド単位で会話を記憶できます。

import { createAgent, tool } from "langchain";
import { MemorySaver } from "@langchain/langgraph";
import * as z from "zod";
 
const searchWeb = tool(
  ({ query }) => `${query}」の検索結果: LangChain.jsは2022年に公開されたフレームワークです。`,
  {
    name: "search_web",
    description: "Webを検索して情報を取得する",
    schema: z.object({
      query: z.string().describe("検索クエリ"),
    }),
  }
);
 
// メモリを設定
const checkpointer = new MemorySaver();
 
const agent = createAgent({
  model: "claude-sonnet-4-5-20250929",
  tools: [searchWeb],
  systemPrompt: "あなたは親切な日本語のAIアシスタントです。",
  checkpointer,
});
 
// 同じthread_idを使うと会話が継続する
const config = { configurable: { thread_id: "session-1" } };
 
const res1 = await agent.invoke(
  { messages: [{ role: "user", content: "LangChain.jsって何?" }] },
  config,
);
console.log(res1.messages.at(-1)?.content);
 
// 会話の文脈を覚えている
const res2 = await agent.invoke(
  { messages: [{ role: "user", content: "それはいつ公開されたの?" }] },
  config,
);
console.log(res2.messages.at(-1)?.content);

thread_idを変えれば別の会話セッションになり、同じIDなら文脈を引き継ぎます。本番環境ではデータベースベースの永続チェックポインターを使うのが推奨です。


活用例 2: 構造化出力(Structured Output)

APIレスポンスやデータ抽出など、決まったフォーマットで出力してほしい場面は多いです。responseFormatにZodスキーマを渡すだけで実現できます。

import { createAgent } from "langchain";
import * as z from "zod";
 
// 出力スキーマを定義
const ContactInfo = z.object({
  name: z.string().describe("名前"),
  email: z.string().describe("メールアドレス"),
  phone: z.string().describe("電話番号"),
  company: z.string().optional().describe("会社名"),
});
 
const agent = createAgent({
  model: "gpt-4.1",
  responseFormat: ContactInfo,
});
 
const result = await agent.invoke({
  messages: [
    {
      role: "user",
      content: "山田太郎さん、yamada@example.com、03-1234-5678、株式会社テスト",
    },
  ],
});
 
console.log(result.structuredResponse);
// {
//   name: "山田太郎",
//   email: "yamada@example.com",
//   phone: "03-1234-5678",
//   company: "株式会社テスト"
// }

自由文から構造化データを抽出する処理が、たった数行で実装できます。


活用例 3: RAG(検索拡張生成)

LLMの知識に含まれない最新情報や社内ドキュメントを参照させるには、**RAG(Retrieval Augmented Generation)**パターンが有効です。

ツールとしてリトリーバーを組み込む

import * as z from "zod";
import { createAgent, tool } from "langchain";
 
// ベクトルストアからの検索をツール化
const retrieve = tool(
  async ({ query }) => {
    // vectorStoreは事前に構築済みのベクトルストア
    const docs = await vectorStore.similaritySearch(query, 3);
    return docs.map(
      (doc) => `[${doc.metadata.source}] ${doc.pageContent}`
    ).join("\n\n");
  },
  {
    name: "search_documents",
    description: "社内ドキュメントを検索して関連情報を取得する",
    schema: z.object({
      query: z.string().describe("検索クエリ"),
    }),
  }
);
 
const ragAgent = createAgent({
  model: "gpt-4.1",
  tools: [retrieve],
  systemPrompt: `あなたは社内ドキュメントに基づいて回答するアシスタントです。
必ずsearch_documentsツールで情報を検索してから回答してください。
情報が見つからない場合は、正直にその旨を伝えてください。`,
});
 
const result = await ragAgent.invoke({
  messages: [
    { role: "user", content: "有給休暇の申請方法を教えて" },
  ],
});

ミドルウェアでコンテキストを注入する方法

ツールを使わず、ミドルウェアでドキュメントを事前取得してシステムプロンプトに注入する方法もあります。

import { createAgent, dynamicSystemPromptMiddleware } from "langchain";
import { SystemMessage } from "@langchain/core/messages";
 
const agent = createAgent({
  model: "gpt-4.1",
  tools: [],
  middleware: [
    dynamicSystemPromptMiddleware(async (state) => {
      const lastQuery = state.messages[state.messages.length - 1].content;
 
      // ユーザーの質問でベクトル検索
      const docs = await vectorStore.similaritySearch(lastQuery, 3);
      const context = docs.map((d) => d.pageContent).join("\n\n");
 
      return new SystemMessage(
        `以下のコンテキストをもとに回答してください:\n\n${context}`
      );
    }),
  ],
});

ツール方式はエージェントが「いつ検索するか」を判断できる柔軟さがあり、ミドルウェア方式はすべてのクエリで必ず検索を実行するため確実性があります。


活用例 4: ストリーミング応答

長い回答をリアルタイムで表示したい場合は、ストリーミングが便利です。

const stream = await agent.stream(
  {
    messages: [
      { role: "user", content: "TypeScriptの主な特徴を5つ教えて" },
    ],
  },
  { streamMode: "values" },
);
 
for await (const chunk of stream) {
  const latestMessage = chunk.messages.at(-1);
 
  if (latestMessage?.tool_calls?.length) {
    // ツール呼び出し中
    const toolNames = latestMessage.tool_calls.map((tc) => tc.name);
    console.log(`ツール呼び出し中: ${toolNames.join(", ")}`);
  } else if (latestMessage?.content) {
    // テキスト応答
    console.log(latestMessage.content);
  }
}

streamMode: "values" を指定すると、各ステップの完全な状態が逐次返されます。ツール呼び出しの進捗やモデルの応答をリアルタイムに表示できるため、UXの向上に直結します。


活用例 5: 動的モデル選択(ミドルウェア)

コストを最適化するために、会話の複雑さに応じてモデルを切り替えるパターンです。

import { ChatOpenAI } from "@langchain/openai";
import { createAgent, createMiddleware } from "langchain";
 
const lightModel = new ChatOpenAI({ model: "gpt-4.1-mini" });
const powerModel = new ChatOpenAI({ model: "gpt-4.1" });
 
const dynamicModelSelection = createMiddleware({
  name: "DynamicModelSelection",
  wrapModelCall: (request, handler) => {
    const messageCount = request.messages.length;
    // 会話が10往復を超えたら高性能モデルに切り替え
    const model = messageCount > 20 ? powerModel : lightModel;
    return handler({ ...request, model });
  },
});
 
const agent = createAgent({
  model: lightModel,
  tools: [/* ... */],
  middleware: [dynamicModelSelection],
});

ミドルウェアは他にも、ツールのエラーハンドリング・レスポンスのバリデーション・ログ収集など、エージェントの振る舞いを柔軟にカスタマイズできます。


活用例 6: ランタイムコンテキストの活用

ユーザーIDやロールなどの実行時情報をエージェントやツールに渡すことで、パーソナライズされた応答を実現できます。

import * as z from "zod";
import { createAgent, tool, type ToolRuntime } from "langchain";
 
type AgentRuntime = ToolRuntime<unknown, { userId: string; role: string }>;
 
const getUserProfile = tool(
  (_, config: AgentRuntime) => {
    const { userId, role } = config.context;
    return JSON.stringify({
      userId,
      role,
      name: userId === "u001" ? "田中" : "不明",
      plan: role === "admin" ? "Enterprise" : "Free",
    });
  },
  {
    name: "get_user_profile",
    description: "現在のユーザーのプロフィールを取得する",
    schema: z.object({}),
  }
);
 
const contextSchema = z.object({
  userId: z.string(),
  role: z.string(),
});
 
const agent = createAgent({
  model: "gpt-4.1",
  tools: [getUserProfile],
  contextSchema,
});
 
const result = await agent.invoke(
  { messages: [{ role: "user", content: "私のプランは?" }] },
  { context: { userId: "u001", role: "admin" } },
);

対応プロバイダー

LangChain.jsは多数のLLMプロバイダーに対応しています。

プロバイダーパッケージ代表モデル
OpenAI@langchain/openaiGPT-4.1, GPT-4.1-mini
Anthropic@langchain/anthropicClaude Sonnet 4.5, Claude Haiku
Google@langchain/google-genaiGemini 2.5 Pro, Gemini 2.5 Flash
AWS Bedrock@langchain/aws各社モデルをAWS経由で利用
Azure OpenAI@langchain/openaiGPT-4.1(Azure版)
Cohere@langchain/cohereCommand R+

モデル指定の文字列フォーマットは provider:model です。

// プロバイダー指定の例
const agent1 = createAgent({ model: "openai:gpt-4.1", tools: [] });
const agent2 = createAgent({ model: "anthropic:claude-sonnet-4-5", tools: [] });

LangSmithでデバッグ・モニタリング

LangChain.jsで構築したエージェントは、LangSmith と連携してトレース・デバッグ・モニタリングが可能です。

  • 各ステップの入出力を可視化
  • ツール呼び出しのタイミングと結果を追跡
  • レイテンシーやトークン使用量の計測
  • プロンプトのA/Bテスト

本番環境でエージェントを運用する場合、LangSmithによるオブザーバビリティは非常に重要です。


まとめ

項目内容
フレームワーク名LangChain.js
言語TypeScript / JavaScript
対応ランタイムNode.js, Deno, Bun
ライセンスMIT
主な用途AIエージェント・チャットボット・RAG・データ抽出
特徴プロバイダー非依存・ミドルウェア拡張・構造化出力・ストリーミング

LangChain.jsは「LLMを使ったアプリケーションを最速で構築する」ことに特化したフレームワークです。createAgent()による手軽さと、ミドルウェア・LangGraphによる拡張性のバランスが魅力です。

まずは基本のエージェントを動かしてみて、そこから必要な機能(メモリ・RAG・構造化出力など)を段階的に追加していくのがおすすめです。


参考リンク