はじめに

効率的な生成 AI を作成する上で、プロンプトチューニングは重要です。

生成 AI から望む形の出力を得るためには、プロンプトチューニングと Tools などの形で生成 AI に対して処理を定義していきます。

しかし、なんどチューニングを行っても、プロンプトの内容が回答に反映されないという限界に到達します。

このような課題を解決するため、多段階推論と Chain 処理について考えたいと思います。

プロンプトチューニングの限界

System Prompt は、生成 AI に対してどのような処理を実施してほしいか、処理の方向性を記述します。

プロンプトチューニングを進めていくと、プロンプト指定がうまく反映されない事象が発生することがあります。

特に、プロンプトが大規模になり、複雑な条件や、複数の指定が含まれるようになっていくとこの傾向は顕著です。

例えば、以下のような System Events から重要な Insight を得ることを目的とした Prompt の場合、Prompt 指定が有効とならない事象が発生します。

今回の指定の中では『重要度 Info に対する深堀りの発生』に対して System Prompt をどのように改善しても出力の内容が改善できませんでした。

下記のような System Prompt を指定しましたが、検知回数 1 件 (4週平均 0.001件 1000%増加) を急増と判定、High, Medium 事象がない場合に Info レベルの事象を列挙して深堀りするなど、Insight を得るという目的に対しては不十分な回答をしていました。

System Prompt 抜粋

あなたは、セキュリティアナリストです。
メッセージとして、監視ツールから検知した数週間分の検知データを示します。
該当データから セキュリティ上の Insight を得ることがあなたの役割です。

データの差分に特に着目し、対応が必要な事象がないか、セキュリティ上のリスク評価を伴う調査を行ってください。

AI は以下の <rules></rules> の内容を遵守してください。

<rules>
- 時刻は UTC を表しています。
    - そのまま表示する際は、UTC であることを明示してください。
    - 日本は、UTC+9 です。
- セキュリティ上の重要度が高い、または異常な変化を示している事象に焦点を当てること。
    - 高リスク(重要度: High)の事象は、最優先で注意を払い、詳細な分析を必ず行うこと。
    - 事象が過去データ (週内の変化、過去レポート) と比較してどのような変化を示しているか(新規発生、急増など)を明確に記述すること。
      特に新規発生の場合、そのイベントが示す具体的なセキュリティサービスの機能(例:機密データに対するアクセスの検知、メタデータに対する大量のアクセス検知など)と、そこから推測される脅威の具体的なタイプや、関連する攻撃手法について可能な限り専門的に推測して記述すること。
    - 全ての重要度 (High、Medium) に対して急激な増加、急激な減少、あるいは普段は発生しない、または過去に検出がないイベントが今週発生している場合は、その変化の要因を深く分析し、そのセキュリティ上の影響について考察すること。
    - 考えられる原因や攻撃シナリオ、影響範囲、そして通常の運用活動との区別についても言及すること。
    - 継続的に検出されているが、変化が見られない低リスクの通知については、通常の運用業務の一部とみなし、特段の対応推奨は不要です。
    - 重要度「Info」のイベントについて
        - 個別の「Info」イベントに対する「結果の詳細(考察)」および「推奨されるアクション」は、原則として【以下の全ての条件を厳密に満たす場合にのみ】生成すること。【それ以外の場合は、Infoイベントをレポートに含めないこと。】
            - 条件1: 'last_4week_avg.rate' の値が 1000% 以上(過去4週間の平均の10倍以上)の「急増」と判断される場合。
            - 条件2: そのイベントが「新規発生」(定義は上記参照)と判断される場合。
            - 条件3: かつ、'current.count' が 10000 以上であるイベントの場合。
        - 概要で「Info」イベントに言及する場合も、上記の条件を満たすイベントのみに限定し、その変化の傾向を簡潔に述べるに留めること。
</rules>

多段階推論と Chain

多段階推論 は、一つの処理を1回の LLM 推論で実施せず、複数回の LLM 推論で実施する処理方法です。

これは、System Prompt をシンプルにして、推論のミスを減らすことが可能です。
また、一部の推論では日本語対応していない Model を利用して推論することも可能です。

抽出や推論などの段階では、データからデータの変換であり、AI が理解できる出力ができれば問題ありません。
また、日本語に誘導するための日本語によるプロンプト指定も不要となります。
日本語だと曖昧になりやすい解釈も、英語により断定的に判断されやすいというメリットもあります。

日本語対応している LLM Model は、英語のみ対応している LLM Model と比較して少ないため、1回の推論で日本語出力まで実現する場合、モデル選択肢の幅は少なくなります。

多段階推論で実施することで、英語にしか対応しないモデルを含めて論理的推論に強いモデルを利用することが可能となります。

多段階処理

今回の生成 AI は、大量のデータからセキュリティ上のインサイトを得ることを目的に実装しました。

そのため、今回の環境では以下の段階を実装しました。

  • 抽出 (Extract)
    • 大規模データから、重要と考えられる箇所を抽出する。
  • 分析 (Analyze)
    • 抽出されたデータから、セキュリティ上の Insight を取得する。
  • 査読 (Review)
    • 出力された Insight を、ユーザーにとって重要なものに限定する。
  • 出力 (Output)
    • 日本語でセキュリティレポートを生成する。

この中で、日本語対応が必須の LLM は『出力』のみです。

Chain

生成 AI フレームワークである LangChain には Chain runnables という機能があります。

LangChain では 、Chat モデルなどで LLM を利用してきましたが、Runnables については理解が追いついておらず、利用していませんでした。

しかし、今回のようなニーズに対して Chain は強力に作用します。

今回のプログラムは、以下のようになりました。

  // モデル定義
  const llm = new ChatBedrockConverse({
        model: BEDROCK_MODEL,
        region: BEDROCK_AWS_REGION,
        credentials: defaultProvider(),
    })

  // 一連の処理を定義
  const chain = RunnableSequence.from([
        (msg) => ({
            messages: [new HumanMessage(JSON.stringify(msg, undefined, 2))]
        }),
        Extract,
        llm,
        (output) => ({
            messages: [new HumanMessage(output.content)]
        }),
        Analyze,
        llm,
        (output) => ({
            messages: [new HumanMessage(output.content)]
        }),
        Review,
        llm,
        (output) => ({
            messages: [new HumanMessage(output.content)]
        }),
        Output,
        llm,
        (output) => output.content
    ])

    // 実行
    const result = await chain.invoke(analyze)

重要な箇所は、chain の作成と実行です。

chain は、LangChain Expression Language (LCEL) という記法で直列 (Sequence) 処理、並列 (Parallel) 処理を記述できるようになるものです。

最初の理解では、 RunnableSequence.from([...]) が圧倒的に分かりやすく直感的でした。

今回の例では、RunnableSequence に記述された通りに順次処理されます。

  1. Object を JSON 形式に変換して、HumanMessage に格納
  2. テンプレートを利用して Extract 用の Prompt 作成
  3. llm 実行
  4. 出力の AIMessage を HumanMessage に変換
  5. 以下、Analyze 、Review、Output と続く。

テンプレート展開には ChatPromptTemplate.fromMessages を利用しています。

これにより、圧倒的に分かりやすく生成 AI の処理を記述し、利用することが可能になります。

それぞれの役割を明確にしたことで、データの取り違いはなくなり、不適切な回答は除去されるなど、当初の目的である Insight を得るという目的に対して十分な成果となりました。

まとめ

このように、多段階の生成 AI による推論処理を作成して利用することには、大きなメリットがあります。

System Prompt の簡素化、役割の明確化、様々なモデルの活用など、単一の LLM 推論よりも強力に入力を処理することができました。

LLM で高度な処理を実現する際の手立てとなれば幸いです。