LLM変換ハンドラ

各プロバイダには、リクエスト・ペイロード、レスポンス・ペイロードおよびエラー・ペイロードの独自の形式があります。このため、LLMプロバイダとOracle Digital Assistantは直接通信できないため、スキルとそのLLMプロバイダ間の交換を容易にするために、これらのペイロードをOracle Digital Assistantの共通LLMインタフェースに変換し、再度戻す必要があります。

この変換を有効にするには、LLM変換ハンドラ(transformRequestPayloadtransformResponsePayloadおよびtransformErrorResponsePayloadメソッドがペイロード変換を実行するスクリプト)を作成します。これらの変換方法には、2つのシグネチャがあります。
  • event: このオブジェクトに使用されるプロパティは、イベント・タイプ(transformRequestPayloadtransformResponsePayloadtransformErrorResponsePayload)によって異なります。
  • context: LlmTransformationContextクラスを参照します。このクラスは、イベント・ハンドラ・ロジックの作成に使用できるコンビニエンス・メソッドへのアクセスを提供します。

LLM変換ハンドラの作成

LLM変換イベント・ハンドラを作成するには:
  1. 左側のナビゲーション・バーで「コンポーネント」をクリックします。
  2. +New「サービス」をクリックします
  3. 「サービスの作成」ダイアログを完了します:
    • 名前: サービス名を入力します。
    • サービス・タイプ: 埋込みコンテナ
    • コンポーネント・サービス・パッケージ・タイプ: 新規コンポーネント
    • コンポーネント・タイプ: LLM変換
    • コンポーネント名: エンティティ・イベント・ハンドラの識別しやすい名前を入力します。この名前は、スキルのLLMサービスを作成するときに参照します。
    • テンプレート: Cohereを直接またはOracle Generative AIサービスを介して呼び出すスキルのテンプレートを提供します。これらのテンプレートを編集する必要はありません。スキルがAzure Open AIなどのCohere/Oracle以外の生成AIモデルをコールする場合、適切なコードを追加する必要があります。

      Oracle Generative AI Cohere (テキスト生成と要約)およびLlama (テキスト要約)のテンプレートは、「テンプレート」リスト・メニューの生成AIでソートされます。Cohereに直接アクセスするためのテンプレートは、「その他」の下にあります。他のモデルのスタータ・コードを含むテンプレートにアクセスするには、「カスタム」を選択します(「その他」の下にもあります)。

  4. 「作成」をクリックして、イベント・ハンドラ・コードを生成します。
  5. デプロイメントの完了後、サービスを展開し、変換ハンドラを選択してそのプロパティ・ページを開きます。このページには、3つのLLMプロバイダ-CLMI変換メソッド(transformRequestPayloadtransformResponsePayloadおよびtransformErrorResponsePayload)がリストされます。

    デジタル・アシスタント・インスタンスと同じテナンシでホストされているCohereサービスまたはOracle生成AIサービスを作成する場合は、ハンドラ・コードが完了します。

  6. 別のOCIテナンシでホストされているOracle生成AIサービスを作成する場合は、「編集」をクリックして「コンポーネントの編集」ダイアログを開き、変数event.compartmentIdを生成AIサービスがサブスクライブされているOCIテナンシのコンパートメントIDに置き換えます。
  7. カスタム・テンプレートを使用している場合は、「編集」をクリックして「コンポーネントの編集」ダイアログを開き、次のプレースホルダ・コードをプロバイダ固有のコードで更新します:
    Method エディタでの場所(カスタム・テンプレート) プレースホルダ・コード(カスタム・テンプレート)
    transformRequestPayload 線23-25
    transformRequestPayload: async (event, context) => {
          return event.payload;
        },
    transformResponsePayload 線33-35
        transformResponsePayload: async (event, context) => {
          return event.payload;
        },
    transformErrorResponsePayload 線44-46
        transformErrorResponsePayload: async (event, context) => {
          return event.payload;
        }
  8. 「検証」をクリックして、更新のsysnaxを確認します。検証エラー(ある場合)を修正し、「保存」をクリックします。次に、「クローズ」をクリックします。

LLMプロバイダ変換コード・サンプル

Azure OpenAI

Method イベント・ハンドラ変換コード
リクエスト
transformRequestPayload: async (event, context) => {
  let payload = { "model": "gpt-4-0314",
                    "messages": event.payload.messages.map(m => { return {"role": m.role, "content": m.content}; }),                     "max_tokens": event.payload.maxTokens,
                    "temperature": event.payload.temperature,
                    "stream": event.payload.streamResponse
                  };
  return payload;
},
レスポンス(非ストリーミング)
transformResponsePayload: async (event, context) => {
     let llmPayload = {};      
     if (event.payload.responseItems) {
       // streaming case
       llmPayload.responseItems = [];
       event.payload.responseItems
           .filter(item => item.choices.length > 0)
           .forEach(item => {
         llmPayload.responseItems.push({"candidates": item.choices.map( c => {return {"content": c.delta.content || "" };})});
       });
     } else {
        // non-streaming case
        llmPayload.candidates = event.payload.choices.map( c => {return {"content": c.message.content || "" };});
     } 
     return llmPayload;
   }
ストリーミングが有効な場合、レスポンス変換イベント・ハンドラは、20個のストリーム・メッセージのバッチでコールされます。このバッチ処理されたストリーム・レスポンスの配列は、responseItemsキーの下に格納されます。
エラー
transformErrorResponsePayload: async (event, context) => {
  let errorCode = 'unknown';
  if (event.payload.error) {
    if ( 'context_length_exceeded' === event.payload.error.code) {
      errorCode = 'modelLengthExceeded';
    }  else if ('content_filter' === event.payload.error.code) {
      errorCode = 'flagged'; 
    } 
    return {"errorCode" : errorCode, "errorMessage": event.payload.error.message};
  } else {
    return {"errorCode" : errorCode, "errorMessage": JSON.stringify(event.payload)};
  }   
}

Oracle生成AIサービス –Cohere

ノート

コマンド・モデルは廃止されました/chatエンドポイントに移行することをお薦めします。これには、より新しいチャット・モデルを宣言し、コマンド固有のパラメータをチャット固有のパラメータに置き換える必要があります。
Method イベント・ハンドラ・コード
リクエスト
transformRequestPayload: async (event, context) => {
      // Cohere doesn't support chat completions, so we first print the system prompt, and if there
      // are additional chat entries, we add these to the system prompt under the heading CONVERSATION HISTORY
      let prompt = event.payload.messages[0].content;
      if (event.payload.messages.length > 1) {
         let history = event.payload.messages.slice(1).reduce((acc, cur) => `${acc}\n${cur.role}: ${cur.content}` , '');
         prompt += `\n\nCONVERSATION HISTORY:${history}\nassistant:`
      }
      // using Cohere
      let modelId = "cohere.command"
      let runtimeType = "COHERE";
       return {
        "compartmentId": event.compartmentId,
        "servingMode": {
          "servingType": "ON_DEMAND",
            "modelId": modelId
        },
        "inferenceRequest": {
          "runtimeType": runtimeType,
          "prompt": prompt,
          "isStream": event.payload.streamResponse,
          "maxTokens": event.payload.maxTokens,
          "temperature": event.payload.temperature,
          // parameters set to default values
          "frequencyPenalty": 0,
          "isEcho": false,
          "numGenerations": 1,
          "presencePenalty": 0,
          "returnLikelihoods": "NONE",
          "topK": 0,
          "topP": 0.75,
          "truncate": "NONE"
        }
      };
}
レスポンス
transformResponsePayload: async (event, context) => {      
    let llmPayload = {};
    if (event.payload.responseItems) {
        // streaming case
        llmPayload.responseItems = [];
        event.payload.responseItems.forEach(item => {
          llmPayload.responseItems.push({"candidates": [{"content": item.text || "" }]});
        });
      } else {
        // non-streaming
        llmPayload.candidates = event.payload.inferenceResponse.generatedTexts.map( item => {return {"content": item.text || "" };});
      }
      return llmPayload;
 }
エラー
transformErrorResponsePayload: async (event, context) => {      
      const error = event.payload.message || 'unknown error';
      if (error.startsWith('invalid request: total number of tokens')) {
        // returning modelLengthExceeded error code will cause a retry with reduced chat history
        return {"errorCode" : "modelLengthExceeded", "errorMessage": error};
      } else {
        return {"errorCode" : "unknown", "errorMessage": error};
      }
}

Oracle生成AI - Llama

ノート

コマンド・モデルは廃止されました。/chatエンドポイントに移行することをお薦めします。これには、チャット・モデルの宣言、およびコマンド固有のパラメータのチャット固有パラメータへの置換が含まれます。
Method イベント・ハンドラ・コード
リクエスト
transformRequestPayload: async (event, context) => {
      // Cohere doesn't support chat completions, so we first print the system prompt, and if there
      // are additional chat entries, we add these to the system prompt under the heading CONVERSATION HISTORY
      let prompt = event.payload.messages[0].content;
      if (event.payload.messages.length > 1) {
         let history = event.payload.messages.slice(1).reduce((acc, cur) => `${acc}\n${cur.role}: ${cur.content}` , '');
         prompt += `\n\nCONVERSATION HISTORY:${history}\nassistant:`
      }
      // using Llama
      let modelId = "meta.llama-2-70b-chat"
      let runtimeType = "LLAMA";
       return {
        "compartmentId": event.compartmentId,
        "servingMode": {
          "servingType": "ON_DEMAND",
            "modelId": modelId
        },
        "inferenceRequest": {
          "runtimeType": runtimeType,
          "prompt": prompt,
          "isStream": event.payload.streamResponse,
          "maxTokens": event.payload.maxTokens,
          "temperature": event.payload.temperature,
          // parameters set to default values
          "frequencyPenalty": 0,
          "isEcho": false,
          "numGenerations": 1,
          "presencePenalty": 0,
          "returnLikelihoods": "NONE",
          "topK": 0,
          "topP": 0.75,
          "truncate": "NONE"
        }
      };
}
レスポンス
transformResponsePayload: async (event, context) => {      
    let llmPayload = {};
    if (event.payload.responseItems) {
        // streaming case
        llmPayload.responseItems = [];
        event.payload.responseItems.forEach(item => {
          llmPayload.responseItems.push({"candidates": [{"content": item.text || "" }]});
        });
      } else {
        // non-streaming
        llmPayload.candidates = event.payload.inferenceResponse.choices.map( item => {return {"content": item.text || "" };});
      }
      return llmPayload;
 }
エラー
transformErrorResponsePayload: async (event, context) => {      
      const error = event.payload.message || 'unknown error';
      if (error.startsWith('invalid request: total number of tokens')) {
        // returning modelLengthExceeded error code will cause a retry with reduced chat history
        return {"errorCode" : "modelLengthExceeded", "errorMessage": error};
      } else {
        return {"errorCode" : "unknown", "errorMessage": error};
      }
}

Oracle生成AI - 要約

ノート

コマンド・モデルは廃止されました/chatエンドポイントに移行することをお薦めします。これには、より新しいチャット・モデルを宣言し、コマンド固有のパラメータをチャット固有のパラメータに置き換える必要があります。
Method イベント・ハンドラ・コード
リクエスト
transformRequestPayload: async (event, context) => {
      // Cohere doesn't support chat completions, so we first print the system prompt, and if there
      // are additional chat entries, we add these to the system prompt under the heading CONVERSATION HISTORY
      let prompt = event.payload.messages[0].content;
      if (event.payload.messages.length > 1) {
         let history = event.payload.messages.slice(1).reduce((acc, cur) => `${acc}\n${cur.role}: ${cur.content}` , '');
         prompt += `\n\nCONVERSATION HISTORY:${history}\nassistant:`
      }
      let modelId = "cohere.command"
      return {
        "compartmentId": event.compartmentId,
        "servingMode": {
          "servingType": "ON_DEMAND",
          "modelId": modelId
        },
        "input" : prompt,
        "temperature": event.payload.temperature,
        // parameters set to default values
        "length": "AUTO",
        "extractiveness": "AUTO",
        "format": "PARAGRAPH",
        // natural language instructions
        "additionalCommand": "write in a conversational style"
      };
}
レスポンス
transformResponsePayload: async (event, context) => {
      let llmPayload = {};
      // non-streaming only: streaming is not supported
      llmPayload.candidates = [{"content": event.payload.summary}];
      return llmPayload;
}
エラー
transformErrorResponsePayload: async (event, context) => {             const error = event.payload.message ||
          'unknown error';      if(error.startsWith('invalid request:
          total number of tokens')) {        // returning modelLengthExceeded error
          code will cause a retry with reduced chat history        return{"errorCode": "modelLengthExceeded", "errorMessage": error};      }
          else{        return{"errorCode": "unknown", "errorMessage": error};      }}

Cohere(コマンドモデル) - Cohereへの直接アクセス

この変換コードのハンドラは、cohere.command.Rモデルに使用される/chat APIではなく、/generate APIおよび関連するCohere.commandモデルをサポートしています。/chatエンドポイントに移行する場合は、リクエスト・ペイロードとレスポンス・ペイロードおよび生成されたコード・テンプレートを手動で更新する必要があります。
Method イベント・ハンドラ・コード
リクエスト
transformRequestPayload: async (event, context) => {            
      // Cohere doesn't support chat completions, so we first print the system prompt, and if there
      // are additional chat entries, we add these to the system prompt under the heading CONVERSATION HISTORY
      let prompt = event.payload.messages[0].content;
      if (event.payload.messages.length > 1) {
         let history = event.payload.messages.slice(1).reduce((acc, cur) => `${acc}\n${cur.role}: ${cur.content}` , '');
         prompt += `\n\nCONVERSATION HISTORY:${history}\nassistant:`
      }
      return {
        "max_tokens": event.payload.maxTokens,
        "truncate": "END",
        "return_likelihoods": "NONE",
        "prompt": prompt,
        "model": "command",
        "temperature": event.payload.temperature,
        "stream": event.payload.streamResponse
      };
 }
このハンドラは、会話コンテキストを維持するために会話履歴を管理します。
レスポンス
transformResponsePayload: async (event, context) => {
  let llmPayload = {};      
  if (event.payload.responseItems) {
        // streaming case
        llmPayload.responseItems = [];
        event.payload.responseItems.forEach(item => {
          llmPayload.responseItems.push({"candidates": [{"content": item.text || "" }]});
        });
      } else {
        // non-streaming
        llmPayload.candidates = event.payload.generations.map( item => {return {"content": item.text || "" };});
      }
   return llmPayload;
}
エラー
transformErrorResponsePayload: async (event, context) => {      
    // NOTE: Depending on the Cohere version, this code might need to be updated
      const error = event.payload.message || 'unknown error';
      if (error.startsWith('invalid request: total number of tokens')) {
        // returning modelLengthExceeded error code will cause a retry with reduced chat history
        return {"errorCode" : "modelLengthExceeded", "errorMessage": error};
      } else {
        return {"errorCode" : "unknown", "errorMessage": error};
      }
 
}

共通LLMインタフェース

各LLMプロバイダには、リクエスト・ペイロードとレスポンス・ペイロードの独自の形式があります。共通LLMインタフェース(CLMI)を使用すると、invokeLLMコンポーネントでこれらの独自のリクエストおよびレスポンス・ペイロードを処理できます。

CMLIは、次のとおりです。
  • リクエスト本文の指定。
  • LLM RESTコールがHTTP 200ステータスを返す場合に適用可能な成功レスポンス本文仕様。
  • エラー・レスポンス本文の指定。LLM RESTコールが200以外のHTTPステータスを返したが、LLMサービスの起動がまだ成功した場合に適用されます。
    ノート

    呼出しが失敗した場合、invokeLLMコンポーネントは401 (認可されていません)または500 (内部サーバー・エラー)エラーを処理します。

CLMI要求本文仕様

JSON CLMIリクエストの本文には、次のプロパティーが含まれます。
プロパティ タイプ デフォルト 説明 必須?
messages メッセージ・オブジェクトの配列 N/A メッセージのリスト。最初のメッセージは、roleプロパティをsystemに設定したプロンプトです。LLMレスポンスを絞り込むか拡張できるように、LLMがマルチターン会話をサポートしている場合、後続のメッセージは、userおよびassistantロールからのメッセージのペアになります。ユーザー・メッセージには、LLMのフォローアップ手順または質問が含まれています。アシスタント・メッセージには、ユーザー・メッセージ(完了)に対するLLMレスポンスが含まれます。LLMがマルチターン会話をサポートしていない場合、messages配列には、プロンプトを保持する単一のシステム・メッセージのみが含まれます。 はい
streamResponse boolean false LLMのレスポンスをLLMコンポーネントにストリームバックするかどうかを決定します。このプロパティをtrueに設定すると、LLMコンポーネントが部分的にレスポンス・メッセージをユーザーに返すことができるため、ストリーミングによってLLMがレスポンスを完了するのを待機する必要がないため、ユーザー・エクスペリエンスが向上します。

レスポンス検証を使用する場合は、streamResponsefalseに設定します。検証を実行する前にメッセージ全体が必要であるため、メッセージは何度もユーザーに対してレンダリングされ、最初にストリームされてから検証され、次に再度ストリームされます。

いいえ
maxTokens 整数 1024 モデルは、結果に単語のトークンを生成します。トークンは単語の一部と考えることができます。たとえば、100トークンは英語で約75語に相当します。このプロパティは、レスポンスに対して生成されるトークンの最大数を設定することで、モデルによって生成されるコンテンツのサイズを制限します。 いいえ
temperature 数値 0 モデルは温度を使用して、応答のランダム性(つまり創造性)を測定します。これは、0 (予測可能な結果)から1 (よりランダム化された結果)までの範囲の値として設定します。0は、モデルが特定のプロンプトに同じ結果を送信することを意味します。1は、特定のレスポンスに対するモデルの結果が大きく異なる可能性があることを意味します。LLMプロバイダが0-1以外の範囲をサポートしている場合は、イベント・ハンドラを使用して乗数を適用します。 いいえ
user string N/A エンド・ユーザーを表す一意の識別子。この識別子は、虐待言語の監視および検出に使用できます。 いいえ
providerExtension object N/A CLMIの一部として定義されていないLLMプロバイダ固有の構成オプションを有効にします。 いいえ

メッセージ・オブジェクト構造

プロパティ タイプ 説明 必須?
role string メッセージ・クリエータ。値は、systemuserおよびassistantです。 はい
content string メッセージ・コンテンツ はい
turn 整数 チャット・メッセージ交換の現在の絞込みターンを示す番号。最初のプロンプトがLLMに送信されると、ターンは1になります。 はい
retry boolean レスポンスのエラーを修正するためにメッセージがLLMに送信されるかどうかを示すフラグ いいえ(デフォルトはfalse)
tag string 特定のプロンプトをマークするカスタム・タグ。Recursive Criticism and Improvement (RCI)を使用してLLMレスポンスを改善する場合は、validateResponsePayloadハンドラでカスタム・ロジックを有効にして、タグを"criticize"または"improve"に設定することでRCIプロセスの現在のステップを検出できます。 いいえ

成功レスポンス本文の仕様

プロパティ タイプ 説明 必須?
candidates candidateオブジェクトの配列 LLMによって返される候補メッセージのリスト はい

候補オブジェクト

JSON CLMIリクエストの本文には、次のプロパティーが含まれます。
プロパティ タイプ 説明 必須?
content string メッセージ・コンテンツ はい

エラー応答本体の仕様

JSON CLMIエラー・レスポンス本文には、次のプロパティが含まれます:
プロパティ タイプ 説明 必須?
errorCode 文字列
  • notAuthorized: LLMリクエストに適切な認可キーがないことを示します。
  • modelLengthExceeded: リクエスト・メッセージ(ユーザーおよびアシスタントの絞込みメッセージとともにシステム・プロンプト)とトークンの最大数がモデルのトークン制限を超えていることを示します。
  • requestFlagged: LLMプロバイダの管理ポリシーに違反するため、LLMがリクエストを処理できないことを示します。たとえば、人種差別的なコンテンツや性的虐待的なコンテンツを含むリクエストにはフラグが付けられます。
  • responseFlagged: LLMレスポンスがLLMプロバイダのモデレーション・ポリシーに違反することを示します。たとえば、人種差別的な言語や性的虐待的な言語などの有毒な内容を含む応答にはフラグが付けられます。
  • requestInvalid: LLMへのリクエストが無効であることを示します。たとえば、イベント・ハンドラで設定された検証ルールの一部に失敗したか、LLMで認識されない形式であるため、リクエストは有効ではありません。
  • responseInvalid: LLMで生成されたレスポンスが無効であることを示します。たとえば、検証イベント・ハンドラで定義された検証ルールの一部に失敗したため、レスポンスは有効ではありません。
  • unknown: その他のエラーが発生した場合。
はい
errorMessage 文字列 LLMプロバイダ固有のエラー・メッセージ。これは、文字列化されたJSONオブジェクトである可能性があります。 はい