🐈

DifyでLLMが議論するAI agentを構築してみた

はじめに

この記事では、Difyプラットフォームを使って構築したITプロジェクトというAI Agentについて解説します。このAI Agentは、5つの異なる役割を持つAIが協力して、ITプロジェクトの課題について多角的な議論を行うシステムです。
https://youtu.be/UYdPyYwbHVc
実際に動かしている様子

システムの概要

このシステムの核となるアイデアは非常にシンプルです。現実のIT開発チームと同様に、異なる専門性や視点を持つメンバーが集まって議論することで、より優れた意思決定ができるようにしています。

以下の5つの役割を持つAIエージェントが登場します:

  1. ファシリテーター: ユーザーの質問を理解し、最適な専門家AIに振り分ける司会者的役割
  2. プロジェクトマネージャー(PM): ビジネス価値やROIを重視した意見を提供
  3. リードエンジニア: 技術的実現可能性や実装方法の専門家
  4. QAエンジニア: 品質保証やテスト計画の観点から意見を提供
  5. ユーザー代表: エンドユーザーの視点から使いやすさや価値を評価

システムの技術構成

1. 使用しているAIモデル

このシステムでは、異なる役割に適したAIモデルを使い分けています:

  • Claude 3.7 Sonnet: ファシリテーター、PMなど複雑な役割の対話に使用
  • GPT-4o Mini: 質問分類や要約など、比較的シンプルなタスクに使用

両モデルの特性を活かして、コスト効率と性能のバランスを取っています。

2. ワークフローの構造

このAI Agentは以下のような流れで動作しています:

  1. ユーザーからの質問を受け取る
  2. ファシリテーターAIが質問を分析
  3. 質問分類器が適切な専門家AIを選択
  4. 選ばれた専門家AIが回答を生成
  5. 各専門家の意見を集約して表示
  6. 履歴を保存してループに戻る

なお、Loopを使って複数回の対話を可能にしている点です。これにより、継続的なディスカッションが実現できます。

主要部分の解説

1. 各AIの役割定義

各LLMでAIエージェントの「人格」や「視点」が明確に定義されています。例えば、プロジェクトマネージャーのプロンプト設定を見てみましょう:

プロジェクトマネージャのプロンプト
あなたはプロダクトマネージャー(PM)として回答してください。

常に以下の特性を持って発言してください:
- ビジネス価値とROIを最重視する
- 前向きで建設的な提案を行う
- 市場トレンドやユーザーニーズを理解している
- 長期的なビジョンと戦略を持っている
- データに基づいた意思決定を重視する

議論においては、新機能の可能性に焦点を当て、競合との差別化ポイントを強調し、ビジネス成長に貢献する側面を積極的に提案してください。技術的な制約よりも、まずは「何ができるか」「何をすべきか」の視点から発言してください。

このように、各AIには明確な「キャラクター設定」が与えられており、専門性の異なる意見を引き出せるようになっています。

2. 質問の振り分けロジック

ファシリテーターは、ユーザーの質問を分析し、最も適切な専門家に振り分けます。

プロジェクトマネージャのプロンプト
あなたはIT開発プロジェクトの議論ファシリテーターです。ユーザーの質問や提案に基づいて、適切な役割の専門家に質問や議題を振り分けてください。

【重要】必ず以下の4つの役割のうち1つだけを選び、その役割に直接質問や議題を提示してください。
【重要】会話履歴を参考に、意見を聞き先の役割に偏りがでないようにバランスよくファシリテートしてください。

[プロダクトマネージャー(PM)]
- ビジネス価値、市場戦略、ロードマップに関する質問
- 新機能の提案や優先順位付けに関する議題
- 収益性やROIに関する内容
- ビジョンや長期計画に関する相談

[リードエンジニア]
- 技術的実現可能性や実装方法に関する質問
- システムアーキテクチャや技術選定に関する議題
- 開発工数や技術的負債に関する内容
- スケーラビリティやパフォーマンスに関する技術的相談

[QAエンジニア]
- 品質保証やテスト計画に関する質問
- バグの可能性や品質リスクに関する議題
- セキュリティや安定性に関する内容
- エッジケースやテスト範囲に関する相談

[ユーザー代表]
- ユーザー体験やユーザビリティに関する質問
- エンドユーザーの視点からの機能評価に関する議題
- 実際の使用シナリオや顧客ニーズに関する内容
- UI/UXデザインや使いやすさに関する相談

【出力形式】
役割: [選択した役割の名前]
質問: [選択した役割に向けた具体的な質問や議題]

ユーザーの入力から適切な役割を判断できない場合は、内容に最も近い専門家を選んでください。前回までの会話の流れも考慮し、異なる役割にも質問が振られるよう配慮してください。

ファシリテータは、質問のコンテキストを理解して、最適な専門家を選択します。例えば、コスト削減についての質問はPMに、技術的な実装についての質問はリードエンジニアに振り分けられる想定です。

3. 会話履歴の管理

会話の流れを保存して、一貫性のある対話を実現しています。

この部分は、会話履歴をlog_array変数に追加しており、過去の対話を参照できるようにしています。

YAMLファイル

このAIエージェントのYAMLファイルをエクスポートしました!「DSLをインポート」で皆さんのDifyに読み込めます。ぜひ参考にしてください。

このAIエージェントの定義ファイル
このAIエージェントの定義ファイル
app:
  description: ''
  icon: 🤖
  icon_background: '#FFEAD5'
  mode: advanced-chat
  name: ITプロジェクト
  use_icon_as_answer_icon: false
dependencies:
- current_identifier: null
  type: marketplace
  value:
    marketplace_plugin_unique_identifier: langgenius/openai:0.0.15@5f610705111ac49d93c4ea5eaac690abaeb3b4a87599c48e5165b549b4c47f10
- current_identifier: null
  type: marketplace
  value:
    marketplace_plugin_unique_identifier: langgenius/anthropic:0.0.13@3c4d4e14652baa9ce1f10e934da9995b3cde0f2ec94ee6638b73fecf1ed53288
kind: app
version: 0.1.5
workflow:
  conversation_variables:
  - description: ''
    id: bfa88f66-efd2-4238-a635-4f89b952ad6a
    name: log_array
    selector:
    - conversation
    - log_array
    value: []
    value_type: array[string]
  environment_variables: []
  features:
    file_upload:
      allowed_file_extensions:
      - .JPG
      - .JPEG
      - .PNG
      - .GIF
      - .WEBP
      - .SVG
      allowed_file_types:
      - image
      allowed_file_upload_methods:
      - local_file
      - remote_url
      enabled: false
      fileUploadConfig:
        audio_file_size_limit: 50
        batch_count_limit: 5
        file_size_limit: 15
        image_file_size_limit: 10
        video_file_size_limit: 100
        workflow_file_upload_limit: 10
      image:
        enabled: false
        number_limits: 3
        transfer_methods:
        - local_file
        - remote_url
      number_limits: 3
    opening_statement: ''
    retriever_resource:
      enabled: false
    sensitive_word_avoidance:
      enabled: false
    speech_to_text:
      enabled: false
    suggested_questions: []
    suggested_questions_after_answer:
      enabled: false
    text_to_speech:
      enabled: false
      language: ''
      voice: ''
  graph:
    edges:
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: loop-start
        targetType: llm
      id: 1743813274053start-source-1743813343457-target
      selected: false
      source: 1743813274053start
      sourceHandle: source
      target: '1743813343457'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: question-classifier
        targetType: llm
      id: 1743813387618-1-1743813533524-target
      source: '1743813387618'
      sourceHandle: '1'
      target: '1743813533524'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: question-classifier
        targetType: llm
      id: 1743813387618-2-1743813538562-target
      source: '1743813387618'
      sourceHandle: '2'
      target: '1743813538562'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: question-classifier
        targetType: llm
      id: 1743813387618-1743813473559-1743813542420-target
      source: '1743813387618'
      sourceHandle: '1743813473559'
      target: '1743813542420'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: question-classifier
        targetType: llm
      id: 1743813387618-1743813503448-1743813545102-target
      source: '1743813387618'
      sourceHandle: '1743813503448'
      target: '1743813545102'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: llm
        targetType: template-transform
      id: 1743813533524-source-1743819934143-target
      source: '1743813533524'
      sourceHandle: source
      target: '1743819934143'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: llm
        targetType: template-transform
      id: 1743813538562-source-1743820010384-target
      source: '1743813538562'
      sourceHandle: source
      target: '1743820010384'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: llm
        targetType: template-transform
      id: 1743813542420-source-1743820065116-target
      source: '1743813542420'
      sourceHandle: source
      target: '1743820065116'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: llm
        targetType: template-transform
      id: 1743813545102-source-1743820115180-target
      source: '1743813545102'
      sourceHandle: source
      target: '1743820115180'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: template-transform
        targetType: variable-aggregator
      id: 1743819934143-source-1743819640139-target
      source: '1743819934143'
      sourceHandle: source
      target: '1743819640139'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: template-transform
        targetType: variable-aggregator
      id: 1743820010384-source-1743819640139-target
      source: '1743820010384'
      sourceHandle: source
      target: '1743819640139'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: template-transform
        targetType: variable-aggregator
      id: 1743820065116-source-1743819640139-target
      source: '1743820065116'
      sourceHandle: source
      target: '1743819640139'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: template-transform
        targetType: variable-aggregator
      id: 1743820115180-source-1743819640139-target
      source: '1743820115180'
      sourceHandle: source
      target: '1743819640139'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInLoop: false
        sourceType: assigner
        targetType: loop
      id: 1743820282903-source-1743813274053-target
      source: '1743820282903'
      sourceHandle: source
      target: '1743813274053'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: assigner
        targetType: question-classifier
      id: 1743814532457-source-1743813387618-target
      source: '1743814532457'
      sourceHandle: source
      target: '1743813387618'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: variable-aggregator
        targetType: assigner
      id: 1743819640139-source-1743820695464-target
      source: '1743819640139'
      sourceHandle: source
      target: '1743820695464'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: assigner
        targetType: llm
      id: 1743820695464-source-1743821775718-target
      source: '1743820695464'
      sourceHandle: source
      target: '1743821775718'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: llm
        targetType: answer
      id: 1743821775718-source-1743814982892-target
      source: '1743821775718'
      sourceHandle: source
      target: '1743814982892'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: loop
        targetType: llm
      id: 1743813274053-source-1743830200503-target
      source: '1743813274053'
      sourceHandle: source
      target: '1743830200503'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: llm
        targetType: answer
      id: 1743830200503-source-1743830296471-target
      source: '1743830200503'
      sourceHandle: source
      target: '1743830296471'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInLoop: false
        sourceType: start
        targetType: template-transform
      id: 1743813238501-source-1743830928763-target
      source: '1743813238501'
      sourceHandle: source
      target: '1743830928763'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInLoop: false
        sourceType: template-transform
        targetType: assigner
      id: 1743830928763-source-1743820282903-target
      source: '1743830928763'
      sourceHandle: source
      target: '1743820282903'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: llm
        targetType: template-transform
      id: 1743813343457-source-1743831085445-target
      source: '1743813343457'
      sourceHandle: source
      target: '1743831085445'
      targetHandle: target
      type: custom
      zIndex: 1002
    - data:
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        sourceType: template-transform
        targetType: assigner
      id: 1743831085445-source-1743814532457-target
      source: '1743831085445'
      sourceHandle: source
      target: '1743814532457'
      targetHandle: target
      type: custom
      zIndex: 1002
    nodes:
    - data:
        desc: ''
        selected: false
        title: 開始
        type: start
        variables: []
      height: 54
      id: '1743813238501'
      position:
        x: 279.3816393220244
        y: 52
      positionAbsolute:
        x: 279.3816393220244
        y: 52
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        break_conditions: []
        desc: ''
        error_handle_mode: terminated
        height: 472
        logical_operator: and
        loop_count: 5
        selected: false
        start_node_id: 1743813274053start
        title: ループ
        type: loop
        width: 1719
      height: 472
      id: '1743813274053'
      position:
        x: 325
        y: 160.56913160698082
      positionAbsolute:
        x: 325
        y: 160.56913160698082
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 1719
      zIndex: 1
    - data:
        desc: ''
        isInLoop: true
        selected: false
        title: ''
        type: loop-start
      draggable: false
      height: 48
      id: 1743813274053start
      parentId: '1743813274053'
      position:
        x: 24
        y: 68
      positionAbsolute:
        x: 349
        y: 228.56913160698082
      selectable: false
      sourcePosition: right
      targetPosition: left
      type: custom-loop-start
      width: 44
      zIndex: 1002
    - data:
        context:
          enabled: false
          variable_selector: []
        desc: ''
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        model:
          completion_params: {}
          mode: chat
          name: claude-3-7-sonnet-20250219
          provider: langgenius/anthropic/anthropic
        prompt_template:
        - id: ed50054f-6ef8-4b72-ab3f-32e8800bbd13
          role: system
          text: 'あなたはIT開発プロジェクトの議論ファシリテーターです。ユーザーの質問や提案に基づいて、適切な役割の専門家に質問や議題を振り分けてください。


            【重要】必ず以下の4つの役割のうち1つだけを選び、その役割に直接質問や議題を提示してください。

            【重要】会話履歴を参考に、意見を聞き先の役割に偏りがでないようにバランスよくファシリテートしてください。


            [プロダクトマネージャー(PM)]

            - ビジネス価値、市場戦略、ロードマップに関する質問

            - 新機能の提案や優先順位付けに関する議題

            - 収益性やROIに関する内容

            - ビジョンや長期計画に関する相談


            [リードエンジニア]

            - 技術的実現可能性や実装方法に関する質問

            - システムアーキテクチャや技術選定に関する議題

            - 開発工数や技術的負債に関する内容

            - スケーラビリティやパフォーマンスに関する技術的相談


            [QAエンジニア]

            - 品質保証やテスト計画に関する質問

            - バグの可能性や品質リスクに関する議題

            - セキュリティや安定性に関する内容

            - エッジケースやテスト範囲に関する相談


            [ユーザー代表]

            - ユーザー体験やユーザビリティに関する質問

            - エンドユーザーの視点からの機能評価に関する議題

            - 実際の使用シナリオや顧客ニーズに関する内容

            - UI/UXデザインや使いやすさに関する相談


            【出力形式】

            役割: [選択した役割の名前]

            質問: [選択した役割に向けた具体的な質問や議題]


            ユーザーの入力から適切な役割を判断できない場合は、内容に最も近い専門家を選んでください。前回までの会話の流れも考慮し、異なる役割にも質問が振られるよう配慮してください。'
        - id: 83b1f4da-9677-4239-bb03-310c684c81cf
          role: user
          text: '{{#sys.query#}}

            ---

            # 会話履歴

            {{#conversation.log_array#}}'
        selected: false
        title: ファシリテータ
        type: llm
        variables: []
        vision:
          enabled: false
      height: 90
      id: '1743813343457'
      parentId: '1743813274053'
      position:
        x: 88
        y: 65
      positionAbsolute:
        x: 413
        y: 225.56913160698082
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        classes:
        - id: '1'
          name: プロジェクトマネージャ(PM)
        - id: '2'
          name: リードエンジニア
        - id: '1743813473559'
          name: QAエンジニア
        - id: '1743813503448'
          name: ユーザ代表
        desc: ''
        instruction: ''
        instructions: ''
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        model:
          completion_params:
            temperature: 0.7
          mode: chat
          name: gpt-4o-mini
          provider: langgenius/openai/openai
        query_variable_selector:
        - '1743813343457'
        - text
        selected: false
        title: 質問分類器
        topics: []
        type: question-classifier
        vision:
          enabled: false
      height: 248
      id: '1743813387618'
      parentId: '1743813274053'
      position:
        x: 356.49030914390505
        y: 65
      positionAbsolute:
        x: 681.490309143905
        y: 225.56913160698082
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        context:
          enabled: false
          variable_selector: []
        desc: ''
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        model:
          completion_params: {}
          mode: chat
          name: claude-3-7-sonnet-20250219
          provider: langgenius/anthropic/anthropic
        prompt_template:
        - id: f092b746-6ffd-4186-9e36-5e15aaa15bfc
          role: system
          text: 'あなたはプロダクトマネージャー(PM)として回答してください。


            常に以下の特性を持って発言してください:

            - ビジネス価値とROIを最重視する

            - 前向きで建設的な提案を行う

            - 市場トレンドやユーザーニーズを理解している

            - 長期的なビジョンと戦略を持っている

            - データに基づいた意思決定を重視する


            議論においては、新機能の可能性に焦点を当て、競合との差別化ポイントを強調し、ビジネス成長に貢献する側面を積極的に提案してください。技術的な制約よりも、まずは「何ができるか」「何をすべきか」の視点から発言してください。'
        - id: e7bac3fb-8002-434b-ab7a-bc7d9196f282
          role: user
          text: '{{#1743813343457.text#}}'
        selected: false
        title: プロジェクトマネージャ(PM)
        type: llm
        variables: []
        vision:
          enabled: false
      height: 90
      id: '1743813533524'
      parentId: '1743813274053'
      position:
        x: 636.4379198395859
        y: 65
      positionAbsolute:
        x: 961.4379198395859
        y: 225.56913160698082
      selected: true
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        context:
          enabled: false
          variable_selector: []
        desc: ''
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        model:
          completion_params: {}
          mode: chat
          name: claude-3-7-sonnet-20250219
          provider: langgenius/anthropic/anthropic
        prompt_template:
        - id: 766ebd51-52c6-4a36-9090-f64965fe81cb
          role: system
          text: 'あなたはリードエンジニアとして回答してください。


            常に以下の特性を持って発言してください:

            - 技術的な実現可能性を客観的に評価する

            - 開発工数とリソースを現実的に見積もる

            - 技術的課題やリスクを明確に指摘する

            - 代替案や技術的解決策を提案する

            - コードの品質と保守性を重視する


            議論においては、PMやユーザー代表の提案に対して技術的観点からフィードバックを行い、実装上の課題や懸念点を具体的に指摘してください。同時に、より効率的な代替案や技術的な改善策も提案してください。'
        - id: 43e8743e-d036-4809-b2a0-26c3f9efa4c8
          role: user
          text: '{{#1743813343457.text#}}'
        selected: false
        title: リードエンジニア
        type: llm
        variables: []
        vision:
          enabled: false
      height: 90
      id: '1743813538562'
      parentId: '1743813274053'
      position:
        x: 635.8160337142124
        y: 163.63509000055961
      positionAbsolute:
        x: 960.8160337142124
        y: 324.20422160754043
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        context:
          enabled: false
          variable_selector: []
        desc: ''
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        model:
          completion_params: {}
          mode: chat
          name: claude-3-7-sonnet-20250219
          provider: langgenius/anthropic/anthropic
        prompt_template:
        - id: 7502238c-1ac7-46ab-8f85-e6ebf0c145d6
          role: system
          text: 'あなたはQAエンジニアとして回答してください。


            常に以下の特性を持って発言してください:

            - 品質とテスト容易性を最重視する

            - 潜在的なバグやエッジケースを先回りして指摘する

            - システムの安定性とセキュリティに敏感である

            - ユーザー体験の一貫性を守る視点を持つ

            - テスト計画と品質保証の観点から発言する


            議論においては、新機能や変更に伴うリスクを慎重に評価し、品質担保のために必要な作業や懸念点を指摘してください。単に問題点を挙げるだけでなく、品質を向上させるための具体的な提案も行ってください。'
        - id: 8fe53748-c46a-434b-bd4d-fc18826a8fff
          role: user
          text: '{{#1743813343457.text#}}'
        selected: false
        title: QAエンジニア
        type: llm
        variables: []
        vision:
          enabled: false
      height: 90
      id: '1743813542420'
      parentId: '1743813274053'
      position:
        x: 633.1286927261056
        y: 258.0404993336798
      positionAbsolute:
        x: 958.1286927261056
        y: 418.6096309406606
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        context:
          enabled: false
          variable_selector: []
        desc: ''
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        model:
          completion_params: {}
          mode: chat
          name: claude-3-7-sonnet-20250219
          provider: langgenius/anthropic/anthropic
        prompt_template:
        - id: 585adfe4-2678-4047-9320-1130d636de01
          role: system
          text: 'あなたはエンドユーザーの代表として回答してください。


            常に以下の特性を持って発言してください:

            - 実際のユーザー視点で機能を評価する

            - 技術的な専門用語を避け、平易な言葉で話す

            - 使いやすさと価値を最重視する

            - 具体的な使用シナリオに基づいて意見を述べる

            - 時に感情的な反応(興奮や不満など)も率直に表現する


            議論においては、提案された機能がどのように自分の生活や業務に役立つか(または役立たないか)を具体的に述べ、実際のユーザーが何を求めているのかの視点を提供してください。競合製品との比較や、実体験に基づく意見も積極的に共有してください。'
        - id: 4c4c8841-ffba-4793-9e29-09d79344eb68
          role: user
          text: '{{#1743813343457.text#}}'
        selected: false
        title: ユーザ代表
        type: llm
        variables: []
        vision:
          enabled: false
      height: 90
      id: '1743813545102'
      parentId: '1743813274053'
      position:
        x: 629.6648520558845
        y: 356.35659024398547
      positionAbsolute:
        x: 954.6648520558845
        y: 516.9257218509663
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        desc: ''
        isInIteration: false
        isInLoop: true
        items:
        - input_type: variable
          operation: append
          value:
          - '1743813343457'
          - text
          variable_selector:
          - conversation
          - log_array
          write_mode: over-write
        loop_id: '1743813274053'
        selected: false
        title: 会話記録 ファシリテータ
        type: assigner
        version: '2'
      height: 88
      id: '1743814532457'
      parentId: '1743813274053'
      position:
        x: 89.0515103233405
        y: 253.7263028667998
      positionAbsolute:
        x: 414.0515103233405
        y: 414.29543447378063
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        answer: '思考過程 {{#1743813387618.class_name#}}:

          {{#1743821775718.text#}}

          '
        desc: ''
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        selected: false
        title: 思考過程
        type: answer
        variables: []
      height: 138
      id: '1743814982892'
      parentId: '1743813274053'
      position:
        x: 1444.917928633726
        y: 168.01310334047383
      positionAbsolute:
        x: 1769.917928633726
        y: 328.58223494745465
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        desc: ''
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        output_type: string
        selected: false
        title: 変数集約器
        type: variable-aggregator
        variables:
        - - '1743819934143'
          - output
        - - '1743820010384'
          - output
        - - '1743820065116'
          - output
        - - '1743820115180'
          - output
      height: 174
      id: '1743819640139'
      parentId: '1743813274053'
      position:
        x: 1186.4803153091948
        y: 67.18965534891635
      positionAbsolute:
        x: 1511.4803153091948
        y: 227.75878695589716
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        desc: ''
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        selected: false
        template: "\r\n---\r\n\r\n## プロジェクトマネージャ(PM)\r\n\r\n{{ LLM_output }}\r\n\r\
          \n"
        title: プロジェクトマネージャ(PM) ANS
        type: template-transform
        variables:
        - value_selector:
          - '1743813533524'
          - text
          variable: LLM_output
      height: 54
      id: '1743819934143'
      parentId: '1743813274053'
      position:
        x: 912.98160333654
        y: 65
      positionAbsolute:
        x: 1237.98160333654
        y: 225.56913160698082
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        desc: ''
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        selected: false
        template: "\r\n---\r\n\r\n## リードエンジニア\r\n\r\n{{ LLM_output }}\r\n\r\n"
        title: リードエンジニア ANS
        type: template-transform
        variables:
        - value_selector:
          - '1743813538562'
          - text
          variable: LLM_output
      height: 54
      id: '1743820010384'
      parentId: '1743813274053'
      position:
        x: 909.9990770642044
        y: 163.63509000055956
      positionAbsolute:
        x: 1234.9990770642044
        y: 324.2042216075404
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        desc: ''
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        selected: false
        template: "\r\n---\r\n\r\n## QAエンジニア\r\n\r\n{{ LLM_output }}\r\n\r\n"
        title: QAエンジニア ANS
        type: template-transform
        variables:
        - value_selector:
          - '1743813542420'
          - text
          variable: LLM_output
      height: 54
      id: '1743820065116'
      parentId: '1743813274053'
      position:
        x: 905.2361452469338
        y: 258.0404993336797
      positionAbsolute:
        x: 1230.2361452469338
        y: 418.6096309406605
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        desc: ''
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        selected: false
        template: "\r\n---\r\n\r\n## ユーザ代表\r\n\r\n{{ LLM_output }}\r\n\r\n"
        title: ユーザ代表 ANS
        type: template-transform
        variables:
        - value_selector:
          - '1743813545102'
          - text
          variable: LLM_output
      height: 54
      id: '1743820115180'
      parentId: '1743813274053'
      position:
        x: 903.0437362756113
        y: 356.35659024398547
      positionAbsolute:
        x: 1228.0437362756113
        y: 516.9257218509663
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        desc: ''
        items:
        - input_type: variable
          operation: append
          value:
          - '1743830928763'
          - output
          variable_selector:
          - conversation
          - log_array
          write_mode: over-write
        selected: false
        title: 会話記録 開始
        type: assigner
        version: '2'
      height: 88
      id: '1743820282903'
      position:
        x: 791.208374235543
        y: 52
      positionAbsolute:
        x: 791.208374235543
        y: 52
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        isInIteration: false
        isInLoop: true
        items:
        - input_type: variable
          operation: append
          value:
          - '1743819640139'
          - output
          variable_selector:
          - conversation
          - log_array
          write_mode: over-write
        loop_id: '1743813274053'
        selected: false
        title: 会話記録 専門家の意見
        type: assigner
        version: '2'
      height: 88
      id: '1743820695464'
      parentId: '1743813274053'
      position:
        x: 1180.2436763240407
        y: 252.54180449024142
      positionAbsolute:
        x: 1505.2436763240407
        y: 413.11093609722224
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        context:
          enabled: false
          variable_selector: []
        desc: ''
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        model:
          completion_params: {}
          mode: chat
          name: gpt-4o-mini
          provider: langgenius/openai/openai
        prompt_template:
        - id: c24280e5-6f61-4138-b4f1-439e1767a36b
          role: system
          text: メッセージを100文字にサマリして
        - id: a7907ab6-f740-4181-8ce1-e79075227d43
          role: user
          text: '{{#1743819640139.output#}}'
        selected: false
        title: 100文字にサマリ
        type: llm
        variables: []
        vision:
          enabled: false
      height: 90
      id: '1743821775718'
      parentId: '1743813274053'
      position:
        x: 1444.8676871932632
        y: 69.79185388794247
      positionAbsolute:
        x: 1769.8676871932632
        y: 230.36098549492328
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    - data:
        context:
          enabled: false
          variable_selector: []
        desc: ''
        model:
          completion_params: {}
          mode: chat
          name: claude-3-7-sonnet-20250219
          provider: langgenius/anthropic/anthropic
        prompt_template:
        - id: 31fe52bf-27bd-468c-8c06-7e4dee7e1f46
          role: system
          text: メッセージをサマリしてください。
        - id: 3f0e71bf-9505-4f79-adfe-293ab8c487da
          role: user
          text: '{{#conversation.log_array#}}'
        selected: false
        title: サマリ
        type: llm
        variables: []
        vision:
          enabled: false
      height: 90
      id: '1743830200503'
      position:
        x: 325
        y: 648.2750498965903
      positionAbsolute:
        x: 325
        y: 648.2750498965903
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        answer: '{{#1743830200503.text#}}'
        desc: ''
        selected: false
        title: 回答 サマリ
        type: answer
        variables: []
      height: 104
      id: '1743830296471'
      position:
        x: 592.6771604896334
        y: 648.2750498965903
      positionAbsolute:
        x: 592.6771604896334
        y: 648.2750498965903
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        selected: false
        template: "## 問い\r\n\r\n{{ Query }}\r\n\r\n"
        title: 開始 ANS
        type: template-transform
        variables:
        - value_selector:
          - sys
          - query
          variable: Query
      height: 54
      id: '1743830928763'
      position:
        x: 536.4482576135123
        y: 52
      positionAbsolute:
        x: 536.4482576135123
        y: 52
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        isInIteration: false
        isInLoop: true
        loop_id: '1743813274053'
        selected: false
        template: "\r\n---\r\n\r\n## ファシリテータ\r\n\r\n{{ LLM_output }}\r\n\r\n"
        title: ファシリテータ ANS
        type: template-transform
        variables:
        - value_selector:
          - '1743813343457'
          - text
          variable: LLM_output
      height: 54
      id: '1743831085445'
      parentId: '1743813274053'
      position:
        x: 92.08777138125606
        y: 179.00503301690287
      positionAbsolute:
        x: 417.08777138125606
        y: 339.5741646238837
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
      zIndex: 1002
    viewport:
      x: -178.36175912590647
      y: 65.37349796034047
      zoom: 0.9635810545596508

また、英語化したものですが、Githubにもアップロードしました。ぜひ、ご参考になさってください!
https://github.com/Masa1984a/Dify-multi-agent-project-template

このシステムの応用例

このようなマルチAIエージェントシステムは、以下のような場面で活用できると考えています。

  1. プロジェクト計画段階での多角的検討:新機能の追加や技術選定の際に、異なる視点からの意見を集約
  2. リスク分析とトレードオフの検討:技術的実現可能性、ビジネス価値、品質保証の観点からバランスの取れた判断を行う
  3. チームミーティングの事前準備:実際のミーティングの前に、考慮すべき様々な視点を洗い出す

「実装のポイントと学んだこと」セクションを、ご指摘いただいた課題を踏まえて改訂します。

実装のポイントと学んだこと

このシステムを構築する中で、いくつかの重要な洞察が得られました。

  1. 各AIの役割の明確化
    それぞれのAIが独自の視点と専門性を持つよう設計することで、多角的な意見を引き出すことができました。

  2. バランスの取れた意見収集
    一つの専門領域に偏らないよう、異なる専門家からの意見を引き出す仕組みが機能しました。

  3. 会話の流れの管理
    過去の対話を参照して一貫性のある会話を実現できました。

  4. 議論の欠如という課題
    現状のシステムでは、専門家たちが個別に意見を述べるだけで、それらの意見間での真の「議論」が発生していないことが大きな課題です。各専門家は独立して自分の視点を述べているものの、お互いの意見に対して反応したり、異なる視点をすり合わせたりする相互作用が不足しています。

  5. ファシリテーターの役割強化の必要性
    ファシリテーターは現在、質問の振り分けに重点を置いていますが、本来は異なる意見をぶつけ合わせ、議論を深める役割も担うべきです。例えば下記のような形で専門家間の意見の対立点や共通点を見出し、より深い議論に導くプロンプト設計が必要です。

    • 「PMの視点とエンジニアの視点が異なりますが、この相違についてユーザー代表としてどう考えますか?」
    • 「QAエンジニアが指摘した品質リスクに対して、PMとして別の優先順位づけを提案できますか?」
  6. Difyのワークフロー改善の可能性
    現在のワークフローでは、各専門家の意見が一方向に集約されるだけですが、これを改善するためには下記が考えられます。

    • 専門家間で意見を共有するフィードバックループの設計
    • 前の専門家の意見を次の専門家に入力として渡す連鎖的な設計
    • 意見の対立点を自動検出して焦点を当てる仕組み
  7. 議論の進行管理
    単に意見を集めるだけでなく、「問題定義→各専門家の視点提示→意見の対立点の特定→解決策の提案→合意形成」といった議論のステージを明示的に設計することで、より構造化された議論が可能になるでしょう。

このような課題と可能性を認識することで、次のバージョンでは真のマルチエージェント討議システムへと進化させることができるはずです。特にファシリテーターのプロンプト設計は、単なる司会者から議論の触媒へと役割を拡張する鍵となるでしょう。

おわりに

Difyを使ったこのマルチエージェントシステムは、AIの活用方法として非常に興味深いアプローチと考えています。単一のAIに全てを任せるのではなく、専門性や視点の異なる複数のAIを組み合わせることで、より包括的な検討が可能になります。

Accenture Japan (有志)

Discussion