汎用AIエージェントを使うべきか、自前実装すべきか 〜 その判定軸とLangGraphによる特化型エージェントの設計事例〜

汎用AIエージェントを使うべきか、自前実装すべきか 〜 その判定軸とLangGraphによる特化型エージェントの設計事例〜

はじめに:なぜ今この問いが重要か

AIエージェントの開発基盤は急速に揃いつつあります。MCPやA2Aに加え、OpenAI・Google・Anthropicなど各社からエージェント構築用SDKが提供され、選択肢は大きく広がりました。一方で、業務適用では重要な判断が必要になります。
汎用エージェント(Claude CodeやChatGPT等)をそのまま使えばいいのか、自前で実装すべきなのか。自前で作るなら、どのフレームワークを使うべきか。
この判断を誤ると、汎用で十分な業務に過剰な実装コストをかけたり、逆に汎用では対応しにくい課題をプロンプトだけで解決しようとして精度が出なかったりします。

本記事では、この判断軸となる3つのレイヤーを提示し、各社のエージェント基盤を比較します。さらに、顧客データ統合を題材にLangGraphで特化型エージェントを設計・検証し、自前実装が必要になる条件と得られた示唆を整理します。

判定軸:3つのレイヤーで考える

AIエージェントの実装手段は、解く問題の性質によって適するアプローチが異なります。
本記事ではこれを、抽象度の異なる3つのレイヤーに整理します。

レイヤー1:製品をそのまま使う

ChatGPT(Deep Research含む)、Claude、Gemini等の完成品エージェントです。ユーザーはプロンプトを書くだけで、エージェントとしての振る舞い(ツール呼び出し、判断、ループ)は製品側が担います。

  • 向いているケース: 社内文書の要約、ドキュメント検索、記録の整形など、プロンプトの工夫で解決できる範囲の業務。

例えば、Googleが2026年3月に公開した「ケア記録アシスト」は、Geminiアプリ上のプロンプトテンプレート(Gem機能)として提供されており、音声メモや手書きメモからSOAP形式の介護記録を生成します。コードは一切不要で、プロンプトの調整だけで各施設の記録フォーマットに対応できます。

レイヤー2:プロバイダーSDKで構築する

OpenAI Agents SDK、Claude Agent SDK、Google ADK等。コードを書いてエージェントを構築しますが、実行基盤やトレーシングはプロバイダーのエコシステムに組み込まれています。

  • 向いているケース: 業務固有のツールを組み込みたい、エージェント間のhandoffやワークフローを自分で定義したい、でもインフラはプロバイダーに任せたい場合。

レイヤー3:モデル非依存フレームワークで構築する

LangGraph等。特定のLLMプロバイダーに依存せず、グラフ構造やステート管理を自分で設計し、処理の流れを設計者が完全にコントロールします。

  • 向いているケース: 共有状態を各ステップで読み書きしながら、状態の中身に基づいて次の遷移先を動的に決める必要がある場合。また、エージェントの判断に自社固有のナレッジやドメイン知識を組み込みたい場合や、将来的な拡張に向けた基盤を構築したい場合。

各レイヤーの代表的なSDK・サービスの比較

各SDK・サービスには、設計者が想定した「問題の形」があります。技術的な優劣ではなく、
前提としている問題の形の違いを理解することが選定の手がかりになります。

レイヤー

SDK / サービス (例)

前提とする問題の形

得意なパターン

1

ChatGPT / Claude Code / Gemini

対話ベースの問題解決

プロンプト完結型の業務支援

2

OpenAI Agents SDK

委譲の連鎖

トリアージ→専門家→エスカレーション

2

Claude Agent SDK

サブエージェントへの委譲とツール呼び出し

コーディング・調査などの長期タスクを自律的に分解・実行

2

Google ADK

階層的な指揮系統

親→子のマルチエージェント

3

LangGraph

状態を中心とした遷移

共有Stateを各ノードが読み書きし条件分岐

3

CrewAI

役割ベースの協調

専門役割を持つエージェント同士が分担・連携

ここからは、具体的なケースを通じてレイヤーの選定を考えていきます。

ユースケース:部署再編に伴う顧客データ統合

※本記事に登場する企業名・人名・データは全て架空のものです。

背景と検証のゴール

ある企業がDX推進の一環で「営業部」と「カスタマーサクセス部」を統合し、「顧客統括部」に再編しました。しかし、各部署が異なるシステムでデータを管理していたため、同一顧客の情報が3つのシステムに分散しているために異なるデータソースからデータを統合する必要がある状況です。

そのため検証のゴールとして、統合エージェントを設計し、単にデータ統合ができたかどうかだけでなく、統合した結果を使って分断されたデータベースをまたいだ質問に答えられるかを確認します

業務の流れと、各部署が保持するデータの種類、データ統合時の課題は以下の通りです。

レイヤー選定の判断

このユースケースには以下の3つの特徴があります。

  • 3つのデータソースへ動的にアクセスし、統合結果に応じて特定のソースだけに再取得する選択的な制御が必要
  • 名寄せや矛盾検出にCS履歴の文脈推論など業務固有のロジックを処理フローに構造的に埋め込む必要がある
  • 名寄せ・文脈判断はLLM、ルーティングや再取得制御はルール、というようにノードごとに役割を切り分ける必要がある

LangGraph(レイヤー3)の状態遷移モデルでは、共有Stateに統合結果を書き込み、その中身を見て条件分岐で次のノードを決められ、どのノードでLLMを使い、どのノードをルールベースにするかを設計者がノード単位で制御できます。そのため、この問題の形にはLangGraphが自然にフィットすると判断し、レイヤー3を採用します。

アーキテクチャと判断設計

グラフ構造

エージェントはシングルエージェント構成で、共有State(IntegrationState)を中心に、各ノードが状態を読み書きしながら処理を進める構造に設計しました。

検証前提

項目

内容

使用モデル

GPT-5.4-mini

データソース

ローカルJSON(合成データ)

フレームワーク

LangGraph

検証データ

営業CRM・CS・経理の3ソース、合計15レコード相当

LLMとルールベースの役割分担

各ノードでLLMを使うかルールベースで処理するかを意図的に切り分けた
ことが、このエージェントの設計上の鍵であると考えています。
切り分けの基準は以下の通りです。

  • 名寄せ・文脈推論・自然言語回答が必要な処理 → LLM
    (plan_retrieval / merge_records / answer_query)
  • 確定的な動作が必要な処理 → ルールベース
    (fetch_*の3ノード / validate_confidence / route_after_validation)

LLMのコードイメージ

merge_recordsでは、3ソースから取得したデータをLLMに渡し、名寄せと矛盾
検出を一度に行います。プロンプトには各ソースのレコードと、出力フォーマット
(統合レコード/検出された矛盾)の指定を含めます。

def merge_records(state: IntegrationState) -> dict:
    fragments = state["fragments"]

    prompt = f"""
    以下の3つのソースから取得した顧客データを統合してください。
    - 同一顧客と判断できるレコードを名寄せする
    - 矛盾(営業で失注だが経理で契約中など)があれば指摘する
    - 経緯(CS履歴の文脈)から推論できる情報も補足する

    営業CRM: {fragments["sales_crm"]}
    CS: {fragments["cs_support"]}
    経理: {fragments["accounting"]}

    出力形式:
    {{ "merged_record": {{...}}, "inconsistencies": [...] }}
    """

    response = llm.invoke(prompt)
    return {
        "merged_record": response["merged_record"],
        "inconsistencies": response["inconsistencies"],
    }

ルールベースノードのコードイメージ:validate_confidence

特にvalidate_confidenceは、当初LLMで信頼度を判定していましたが、手動では
正しく紐づくケースでもLLMが誤判定する事象が発生したため、ルールベースに
変更しました。フィールド充足率・名前一致度・時系列整合性といった明確な基準
で評価できる処理は、ルールの方が安定するのではないかと考えています。

def validate_confidence(state: IntegrationState) -> dict:
    record = state["merged_record"]
    score = 0.0

    # 1. フィールド充足率(最大0.4)
    sources_present = sum(
        1 for s in ["sales", "cs", "accounting"] if record.get(s)
    )
    score += (sources_present / 3) * 0.4

    # 2. 名前一致度(最大0.3)
    if is_exact_match(record["names"]):
        score += 0.3
    elif is_partial_match(record["names"]):  # 法人格の有無のみ差異
        score += 0.2

    # 3. 時系列整合性(最大0.3)
    if check_timeline_consistency(record):
        score += 0.3

    return {"confidence": score, "missing_fields": find_missing(record)}

エージェントの動作イメージ

検証で実際にどのようにエージェントが動作したかを、
シナリオ1(経理→営業の時系列追跡)を例に、データを含めて示します。

質問:「経理データに請求情報がある顧客ノヴァクラフトについて、
営業CRMでの最初の商談日は?」

ステップ1:経理ソースから契約情報を取得

{
  "contract_number": "CNT-2024-0089",
  "client_name_formal": "株式会社ノヴァクラフト",
  "plan": "月額プラン",
  "monthly_amount": 500000,
  "start_date": "2024-08-01",
  "billing_status": "請求中"
}

経理側では「株式会社ノヴァクラフト」として登録されている。

↓ この顧客名を正規化(「ノヴァクラフト」)してCS・営業を遡る

ステップ2:CSソースから問い合わせ履歴を取得

[
  {
    "ticket_id": "TKT-2024-0312",
    "customer_name": "株式会社ノヴァクラフト",
    "category": "契約相談",
    "created_at": "2024-07-15",
    "resolution": "月額プラン(50万円/月)で契約締結。経理部に連携済み"
  },
  {
    "ticket_id": "TKT-2024-0289",
    "customer_name": "株式会社ノヴァクラフト",
    "category": "プラン相談",
    "created_at": "2024-06-20",
    "resolution": "別プラン提案を実施"
  }
]

CS側でも同一顧客の問い合わせが複数件存在する。

↓ さらに営業CRMを遡る

ステップ3:営業CRMから商談履歴を取得

{
  "account_id": "ACC-001",
  "company_name": "ノヴァクラフト",
  "deals": [
    {
      "deal_id": "DEAL-002",
      "deal_stage": "失注",
      "lost_reason": "予算凍結。経営方針変更により一旦見送り",
      "created_date": "2023-04-10"
    },
    {
      "deal_id": "DEAL-005",
      "deal_stage": "商談中",
      "created_date": "2024-05-12"
    },
    {
      "deal_id": "DEAL-001",
      "deal_stage": "受注",
      "created_date": "2022-06-15"
    }
  ]
}

営業側では「ノヴァクラフト」として登録されており、商談3件が存在する。

ステップ4:エージェントの推論と回答

エージェントは経理→CS→営業と3ソースを遡り、営業の3件の商談を created_date
で時系列ソートして最古の日付を特定。

回答:「2022-06-15」

このように、1つのデータベースだけでは答えられない問いに対して、
複数ソースを横断した推論によって正確な回答を出せたかを確認します。

他シナリオの動作概要

シナリオ1以外についても、同様に複数ソースを横断した推論ができているかを確認します。

  • シナリオ2(契約前後のCS接点):経理の start_date を基準に、
    CSの created_at を契約前後に分類して時系列で整理
  • シナリオ3(失注→再契約の検出):営業の deal_stage="失注"
    商談に対し、CSの resolution と経理の新規契約を突き合わせて経緯を推論
  • シナリオ4(該当なしのハンドリング):3ソースすべてに該当データが
    ない場合、エラーで落ちずに「該当なし」を返す

検証結果

検証シナリオと検証サマリ

4つの検証シナリオすべてで期待通りの動作を確認できました。

シナリオ

質問

エージェントの回答

判定

1: 経理→営業の時系列追跡

経理データに請求情報がある顧客の最初の商談日は?

2022-06-15

⭕️

2: 契約前後のCS接点

顧客の契約前後のCS問い合わせを時系列で

契約前3件・契約後1件、時系列で正しく整理

⭕️

3: 失注→再契約の検出

失注がCS経由で再契約に至ったケースは?

DEAL-002→CNT-2024-0089を特定、経緯説明あり

⭕️

4: 該当なしのハンドリング

存在しない顧客名での実行

「該当なし」を返却

⭕️

実行フローのログ

2つの代表的なケースで、想定通りのフロー制御が確認できました。

  • 正常統合(ノヴァクラフト):plan_retrieval → 3ソース並列取得 →
    merge_records → validate_confidence → 統合結果を出力
  • ループバック発生(セレンロジ):初回の信頼度判定で欠損を検出 →
    fetch_accountingに再取得 → 再度欠損のためretry_count上限到達 →
    human_reviewへエスカレーション

名寄せの具体例

ルールベースの正規化(法人格の除去)とmerge_recordsノードのLLMによる
最終判定の組み合わせで、表記揺れを吸収できました。

入力

営業CRM

CS

経理

結果

ノヴァクラフト

ノヴァクラフト

株式会社ノヴァクラフト

株式会社ノヴァクラフト

同一顧客として統合

セレンロジ

セレンロジ

セレンロジスティクス株式会社

セレンロジスティクス株式会社

営業のみヒット(吸収できず)

ハードルになった点
セレンロジのように略称と正式名称の差分が大きいケースでは、取得段階のルールベース照合では吸収できず、業務固有の知識を伴う名寄せには対応できないことがわかりました。略称の名寄せには、辞書による補助またはmerge_records側のLLMにより積極的に判断を委ねる設計が必要であると考えます。

矛盾検出の具体例

シナリオ3に該当するケースとして、3ソースの情報から失注→再契約の経緯が
検出できました。

  • 営業CRM:商談DEAL-002は「予算凍結」を理由に失注と記録
  • 経理:契約CNT-2024-0089が存在し、請求中ステータス
  • CS:「月額プラン(50万円/月)で契約締結。経理部に連携済み」の記述

エージェントはこれらを突き合わせ、「営業で失注した案件が、CS部経由で
別経路再契約に至った可能性が高い」と推論しました。1つのソースだけでは発見
できない矛盾であり、複数ソースを横断する統合エージェントの価値が最も
明確に表れたケース
であると考えます。

得られた示唆

  • 横断質問への回答能力:複数ソースの統合により、1つのデータベースでは
    答えられない問いに回答できる
  • LLM信頼度判定の不安定性:確定的な判断が必要な処理へのLLM使用は
    リスクがあり、ルールベース化により安定した
  • 名寄せの限界:ルールベースでは略称と正式名称の差分に対応できず、
    merge_records側のLLM判断や辞書ベースの補助との組み合わせが必要

自前実装のトレードオフ

メリット・デメリット

観点

メリット

デメリット

設計の自由度

LLMとルールをノード単位で切り分けられる

グラフ構造、State定義、各ノードの実装が必要

状態の制御

共有Stateで中間状態を可視化・制御できる

merge_records等の中核ノードはLLM依存で再現性に制約

業務適応

業務固有のロジックをグラフ構造に埋め込める

モデル更新・スキーマ変更のたびにメンテナンス対応が必要

自前実装の強み

特にvalidate_confidenceの判定方法をLLMからルールベースへ切り替えられた
ことは、ノード単位の制御性がもたらした自前実装の利点です。完成品エージェント
やhandoffモデルでは、内部処理を後から差し替えるような柔軟な調整は難しく、
こうしたノード単位の制御性は自前実装ならではの強みといえます。

また、AIエージェントを自前で実装すべきかどうかは、汎用エージェントとの優劣
ではなく、解きたい問題の形がどのレイヤーに適するかが重要であると考えます

まとめ

本記事では、AIエージェントの実装手段をの3つのレイヤーに整理し、レイヤー3(LangGraph)が必要となる条件を部署再編に伴う顧客データ統合というユースケースを通じて、検証を行い自前実装のトレードオフを整理しました。

そのうえで、自前実装で鍵となるのは、LLMに何を任せ、何を任せないかの設計判断であると考えます。名寄せなどの文脈推論が必要な処理はLLMに任せ、信頼度判定や条件分岐のような確定的な処理はルールベースに切り分けることで、安定して動作するエージェントを構築できました。

また部署再編に伴う顧客データ統合という1つのケースを題材にしましたが、同様の構造を持つ問題は他にも存在します。M&A後のマスタ統合、医療機関間の患者情報引き継ぎ、サプライチェーン上での発注・在庫・請求データの統合など、複数のシステムに分断された情報を業務文脈で繋ぎ直す必要がある領域では、本記事で示した判定軸と設計の考え方が応用できるのではないかと考えます。

宣伝

弊社ではデータ基盤策定からLLMまで、お客様にあったプロセスでの提案とご支援が可能です、お気軽にお問合せください。

また、中途採用やインターンの応募もお待ちしています!



お問い合わせ・資料請求

プロジェクトに関するご質問や詳細な情報が必要な場合は、お気軽にお問い合わせください。

サービス紹介資料

当社のサービスや実績について詳しく解説した資料をご覧いただけます。

資料をダウンロード

無料相談・お問い合わせ

お持ちの課題について、広くお問い合わせを受け付けています。

問い合わせをする

関連記事

2025年時点の「データ基盤×LLM」のサービス比較と考察(Snowflake x Databricks x Google)
2025年時点の「データ基盤×LLM」のサービス比較と考察(Snowflake x Databricks x Google)
記事を読む
Few-Shotプロンプトの「順序」を変えるだけで精度は上がるのか?
Few-Shotプロンプトの「順序」を変えるだけで精度は上がるのか?
記事を読む
LLM-as-a-Judge用にgpt-oss 20bをSFTし、専門的な指示をJudgeする
LLM-as-a-Judge用にgpt-oss 20bをSFTし、専門的な指示をJudgeする
記事を読む