Gestionnaires de transformation LLM

Chaque fournisseur a son propre format pour la charge utile de demande, de réponse et d'erreur. Pour cette raison, le fournisseur de LLM et Oracle Digital Assistant ne peuvent pas communiquer directement. Par conséquent, pour faciliter l'échange entre la brique et ses fournisseurs de LLM, vous devez transformer ces charges utiles en interface LLM commune d'Oracle Digital Assistant, puis inversement.

Pour activer cette transformation, créez un gestionnaire de transformation LLM, un script dont les méthodes transformRequestPayload, transformResponsePayload et transformErrorResponsePayload exécutent les transformations de charge utile. Ces méthodes de transformation ont deux signatures :
  • event : les propriétés utilisées pour cet objet dépendent du type d'événement (transformRequestPayload, transformResponsePayload, transformErrorResponsePayload).
  • context : fait référence à la classe LlmTransformationContext, qui permet d'accéder aux méthodes pratiques que vous pouvez utiliser pour créer la logique du gestionnaire d'événements.

Créer un gestionnaire de transformation LLM

Pour créer un gestionnaire d'événements de transformation LLM, procédez comme suit :
  1. Cliquez sur Composants dans la barre de navigation de gauche.
  2. Cliquez sur +New Service.
  3. Renseignez la boîte de dialogue Create Service comme suit :
    • Nom : entrez le nom de service.
    • Type de service : Conteneur imbriqué
    • Type de package de services de composant : Nouveau composant
    • Type de composant : Transformation LLLM
    • Nom de composant : entrez un nom facilement identifiable pour le gestionnaire d'événements d'entité. Vous référencerez ce nom lorsque vous créerez le service LLM pour la brique.
    • Modèle : nous fournissons des modèles pour les briques qui appellent Cohere directement ou via le service d'IA générative Oracle. Il n'est pas nécessaire de modifier ces modèles. Si votre brique appelle un modèle d'IA générative non-Cohere/Oracle, tel qu'Azure Open AI, vous devrez ajouter le code approprié.

      Les modèles pour Oracle Generative AI Cohere (génération et synthèse de texte) et Llama (agrégation de texte) sont triés sous Generative AI dans le menu de liste Modèle. Le modèle permettant d'accéder directement à Cohere se trouve sous Other. Pour accéder au modèle contenant le code de démarrage d'autres modèles, sélectionnez Personnalisé (également situé sous Autre).

  4. Cliquez sur Créer pour générer le code de gestionnaire d'événements.
  5. Une fois le déploiement terminé, développez le service, puis sélectionnez le gestionnaire de transformation pour ouvrir sa page de propriétés, qui répertorie les trois méthodes de transformation LLM Provider-CLMI (transformRequestPayload, transformResponsePayload et transformErrorResponsePayload).

    Si vous créez un service Cohere ou un service Oracle Generative AI hébergé dans la même location que votre instance Digital Assistant, le code du gestionnaire est terminé.

  6. Si vous créez un service Oracle Generative AI hébergé dans une autre location OCI, cliquez sur Modifier pour ouvrir la boîte de dialogue Modifier le composant et remplacer la variable event.compartmentId par l'ID de compartiment de la location OCI dans laquelle le service Generative AI est abonné.
  7. Si vous utilisez le modèle personnalisé, cliquez sur Modifier pour ouvrir la boîte de dialogue Modifier le composant, puis mettez à jour le code d'espace réservé suivant avec le code propre au fournisseur :
    Méthode Emplacement dans l'éditeur (modèle personnalisé) Code d'espace réservé (modèle personnalisé)
    transformRequestPayload Courbes 23-25
    transformRequestPayload: async (event, context) => {
          return event.payload;
        },
    transformResponsePayload Courbes 33-35
        transformResponsePayload: async (event, context) => {
          return event.payload;
        },
    transformErrorResponsePayload Courbes 44-46
        transformErrorResponsePayload: async (event, context) => {
          return event.payload;
        }
  8. Vérifiez le sytnax de vos mises à jour en cliquant sur Valider. Corrigez les erreurs de validation (le cas échéant), puis cliquez sur Enregistrer. Cliquez ensuite sur Fermer.

LLM - Fournisseur - Exemples de code de transformation

Azure OpenAI

Méthode Code transformation du gestionnaire d'événements
Demande
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;
},
Réponse (sans streaming)
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;
   }
Lorsque la transmission en continu est activée, le gestionnaire d'événements de transformation de réponse est appelé par lots de 20 messages transmis en continu. Ce tableau en batch de réponses transmises en continu est stocké sous la clé responseItems.
Erreur
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)};
  }   
}

Service d'IA générative Oracle - Cohere

Remarque

Les modèles de commande ont été retraités. Nous vous recommandons de migrer vers l'adresse /chat, ce qui implique de déclarer un modèle de discussion plus récent et de remplacer les paramètres propres à la commande par des paramètres propres à la discussion.
Méthode Code gestionnaire d'événement
Demande
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"
        }
      };
}
Réponse
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;
 }
Erreur
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 Generative AI - Llama

Remarque

Les modèles de commande ont été abandonnés. Nous vous recommandons de migrer vers l'adresse /chat, ce qui implique de déclarer le modèle de discussion et de remplacer les paramètres spécifiques à la commande par des paramètres spécifiques à la discussion.
Méthode Code gestionnaire d'événement
Demande
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"
        }
      };
}
Réponse
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;
 }
Erreur
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 Generative AI - Synthèse

Remarque

Les modèles de commande ont été retraités. Nous vous recommandons de migrer vers l'adresse /chat, ce qui implique de déclarer un modèle de discussion plus récent et de remplacer les paramètres propres à la commande par des paramètres propres à la discussion.
Méthode Code gestionnaire d'événement
Demande
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"
      };
}
Réponse
transformResponsePayload: async (event, context) => {
      let llmPayload = {};
      // non-streaming only: streaming is not supported
      llmPayload.candidates = [{"content": event.payload.summary}];
      return llmPayload;
}
Erreur
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 (modèle de commande) - Accès direct à Cohere

Les gestionnaires de ce code de transformation prennent en charge l'API /generate et le modèle Cohere.command associé, et non l'API /chat utilisée pour le modèle cohere.command.R. Si vous effectuez la migration vers l'adresse /chat, vous devez mettre à jour manuellement les charges utiles de demande et de réponse, ainsi que le modèle de code généré.
Méthode Code gestionnaire d'événement
Demande
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
      };
 }
Ce gestionnaire gère l'historique des conversations pour tenir à jour le contexte de conversation.
Réponse
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;
}
Erreur
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};
      }
 
}

Interface LLM commune

Chaque fournisseur LLM a son propre format pour ses charges utiles de demande et de réponse. L'interface LLM commune, ou CLMI, permet au composant invokeLLM de gérer ces charges utiles de demande et de réponse propriétaires.

Le CMLI comprend les éléments suivants :
  • Spécification de corps de demande.
  • Spécification de corps de réponse de réussite, applicable lorsque l'appel REST LLM renvoie un statut HTTP 200.
  • Spécification de corps de réponse d'erreur, applicable lorsque l'appel REST LLM renvoie un statut HTTP autre que 200 mais que l'appel du service LLM a toujours réussi.
    Remarque

    En cas d'échec des appels, le composant invokeLLM gère les erreurs 401 (non autorisées) ou 500 (erreur de serveur interne).

Spécification du corps de demande CLMI

Le corps de la demande CLMI JSON contient les propriétés suivantes :
Propriété Type Valeur par défaut Description Requis ?
messages Tableau d'objets de message N/A Liste de messages. Le premier message est l'invite avec la propriété role définie sur system. Si la LLM prend en charge une conversation à plusieurs tours afin que la réponse LLM puisse être affinée ou améliorée, les messages suivants seront des paires de messages provenant des rôles user et assistant. Le message utilisateur contient les instructions de suivi ou la question pour le LLM. Le message de l'assistant contient la réponse LLM au message utilisateur (l'achèvement). Si la LLM ne prend pas en charge les conversations à plusieurs tours, le tableau messages ne contiendra qu'un seul message système contenant l'invite. Oui
streamResponse boolean false Détermine si la réponse de la LM sera retransmise en continu vers le composant LM. La définition de cette propriété sur true améliore l'expérience utilisateur, car la transmission en continu permet au composant LLM d'envoyer des messages de réponse partielle aux utilisateurs afin qu'ils n'aient pas à attendre que le LLM termine la réponse.

Définissez streamResponse sur false lorsque la validation de réponse est utilisée. Etant donné que l'intégralité du message est requise pour que la validation puisse avoir lieu, le message peut être affiché plusieurs fois pour les utilisateurs : d'abord diffusé en continu, puis validé, puis retransmis en continu.

Non
maxTokens Nombre entier 1024 Le modèle génère des jetons pour les mots dans ses résultats. Les jetons peuvent être considérés comme des morceaux de mots. 100 jetons équivaut à environ 75 mots en anglais, par exemple. Cette propriété limite la taille du contenu généré par le modèle en définissant le nombre maximal de jetons qu'il génère pour la réponse. Non
temperature nombre 0 Le modèle utilise la température pour mesurer le caractère aléatoire - et donc la créativité - de ses réponses. Vous définissez cette valeur comme allant de 0 (résultats prévisibles) à 1 (résultats plus aléatoires). 0 signifie que le modèle enverra les mêmes résultats à une invite donnée. 1 signifie que les résultats du modèle à une réponse donnée peuvent varier énormément. Utilisez un gestionnaire d'événements pour appliquer un multiplicateur si le fournisseur LLM prend en charge une plage autre que 0-1. Non
user chaîne N/A Identificateur unique représentant l'utilisateur final, qui peut être utilisé pour surveiller et détecter un langage abusif. Non
providerExtension Objet N/A Active les options de configuration propres au fournisseur LLM qui ne sont pas définies dans le cadre de CLMI. Non

Structure d'objet de message

Propriété Type Description Requis ?
role chaîne Créateur du message. Les valeurs sont system, user et assistant. Oui
content chaîne Contenu du message Oui
turn Nombre entier Nombre qui indique la rotation d'affinement actuelle de l'échange de messages de discussion. Lorsque la première invite est envoyée au LLM, la rotation est de 1. Oui
retry boolean Indicateur signalant si le message est envoyé au LLM pour corriger une erreur dans la réponse Non (valeur par défaut : false)
tag chaîne Balise personnalisée qui marque une invite spécifique. Si vous améliorez la réponse LLM à l'aide de RCI (Recursive Criticism and Improvement), vous pouvez activer la logique personnalisée dans le gestionnaire validateResponsePayload pour détecter l'étape en cours du processus RCI en définissant la balise sur "criticize" ou "improve". Non

Spécification du corps de réponse de succès

Propriété Type Description Requis ?
candidates Tableau d'objets candidate Liste des messages candidats renvoyés par la LLM Oui

Objets candidats

Le corps de la demande CLMI JSON contient les propriétés suivantes :
Propriété Type Description Requis ?
content chaîne Contenu du message Oui

Spécification du corps de réponse d'erreur

Le corps de réponse d'erreur CLMI JSON contient les propriétés suivantes :
Propriété Type Description Requis ?
errorCode Chaîne
  • notAuthorized : indique que la demande LLM ne dispose pas de la clé d'autorisation appropriée.
  • modelLengthExceeded : indique que la combinaison des messages de demande (invite système avec les messages d'affinement de l'utilisateur et de l'assistant) et du nombre maximal de jetons dépasse la limite de jetons du modèle.
  • requestFlagged : indique que le LLM ne peut pas exécuter la demande car elle viole les stratégies de modération du fournisseur LLM. Par exemple, les demandes qui contiennent du contenu raciste ou sexuellement abusif seront signalées.
  • responseFlagged : indique que la réponse LLM viole les stratégies de modération du fournisseur LLM. Par exemple, les réponses contenant du contenu toxique, comme un langage raciste ou sexuellement abusif, seraient signalées.
  • requestInvalid : indique que la demande au LLM n'est pas valide. Par exemple, la demande n'est pas valide car elle a échoué à certaines des règles de validation définies dans un gestionnaire d'événements ou dans un format qui n'est pas reconnu par la LM.
  • responseInvalid : indique que la réponse générée par LLM n'est pas valide. Par exemple, la réponse n'est pas valide car certaines des règles de validation définies dans un gestionnaire d'événements de validation ont échoué.
  • unknown : lorsque d'autres erreurs se produisent.
Oui
errorMessage Chaîne Message d'erreur propre au fournisseur LLM. Il peut s'agir d'un objet JSON sous forme de chaîne. Oui