Crea un chatbot contestuale per servizi finanziari utilizzando Amazon SageMaker JumpStart, Llama 2 e Amazon OpenSearch Serverless con Vector Engine

Crea un chatbot contestuale per servizi finanziari con Amazon SageMaker JumpStart, Llama 2 e Amazon OpenSearch Serverless con Vector Engine

L’industria dei servizi finanziari (FinServ) ha esigenze uniche di intelligenza artificiale generativa legate a dati specifici del settore, sicurezza dei dati, controlli normativi e standard di conformità del settore. Inoltre, i clienti cercano opzioni per selezionare il modello di apprendimento automatico (ML) più performante ed economico e la capacità di effettuare la personalizzazione necessaria (ottimizzazione) per adattarlo ai loro casi d’uso aziendali. Amazon SageMaker JumpStart è ideale per i casi d’uso di AI generativa per i clienti FinServ in quanto fornisce i necessari controlli di sicurezza dei dati e soddisfa i requisiti degli standard di conformità.

In questo articolo, dimostriamo l’utilizzo di modelli di generazione basati su Retrieval Augmented Generation (RAG) per attività di risposta alle domande utilizzando large language models (LLM) in SageMaker JumpStart utilizzando un semplice caso d’uso nel settore finanziario. RAG è un framework per migliorare la qualità della generazione di testo combinando un LLM con un sistema di reperimento delle informazioni (IR). Il testo generato dal LLM e il sistema di IR recuperano informazioni rilevanti da una base di conoscenza. Le informazioni recuperate vengono quindi utilizzate per integrare l’input del LLM, il che può contribuire a migliorare l’accuratezza e la pertinenza del testo generato dal modello. RAG si è dimostrato efficace per una varietà di compiti di generazione di testo, come la risposta alle domande e la sintesi. È un approccio promettente per migliorare la qualità e l’accuratezza dei modelli di generazione di testo.

Vantaggi dell’utilizzo di SageMaker JumpStart

Con SageMaker JumpStart, gli specialisti di ML possono scegliere tra una vasta selezione di modelli all’avanguardia per casi d’uso come scrittura di contenuti, generazione di immagini, generazione di codice, risposta alle domande, copywriting, sintesi, classificazione, reperimento delle informazioni e altro ancora. Gli specialisti di ML possono distribuire modelli di base su istanze dedicate di Amazon SageMaker da un ambiente isolato di rete e personalizzare modelli utilizzando SageMaker per addestramento e distribuzione dei modelli.

SageMaker JumpStart è ideale per i casi d’uso di AI generativa per i clienti FinServ perché offre quanto segue:

  • Capacità di personalizzazione – SageMaker JumpStart fornisce appunti di esempio e articoli dettagliati per una guida passo passo all’adattamento al dominio dei modelli di base. È possibile seguire queste risorse per l’ottimizzazione, l’adattamento al dominio e l’istruzione dei modelli di base o per la creazione di applicazioni basate su RAG.
  • Sicurezza dei dati – Garantire la sicurezza dei dati di payload di inferenza è essenziale. Con SageMaker JumpStart, è possibile distribuire i modelli in isolamento di rete con endpoint a occupazione singola. Inoltre, è possibile gestire il controllo dell’accesso a modelli selezionati tramite la funzionalità di hub di modelli privati, in conformità ai requisiti di sicurezza individuali.
  • Controlli normativi e conformità – La conformità agli standard come HIPAA BAA, SOC123, PCI e HITRUST CSF è una caratteristica principale di SageMaker, garantendo l’allineamento con il rigoroso panorama normativo del settore finanziario.
  • Scelta dei modelli – SageMaker JumpStart offre una selezione di modelli di ML all’avanguardia che si posizionano costantemente ai primi posti nei benchmark HELM riconosciuti dal settore. Questi includono, ma non sono limitati a, Llama 2, Falcon 40B, AI21 J2 Ultra, AI21 Summarize, Hugging Face MiniLM e modelli BGE.

In questo articolo, esploriamo la creazione di un chatbot contestuale per organizzazioni di servizi finanziari utilizzando un’architettura RAG con il modello di base Llama 2 e il modello di embedding Hugging Face GPTJ-6B-FP16, entrambi disponibili in SageMaker JumpStart. Utilizziamo anche Vector Engine per Amazon OpenSearch Serverless (attualmente in anteprima) come archivio dati vettoriale per memorizzare gli embedding.

Limitazioni dei modelli di lingua ampia

LLM sono stati addestrati su vasti volumi di dati non strutturati ed eccellono nella generazione di testo generale. Attraverso questo addestramento, LLM acquisiscono e memorizzano conoscenze di fatto. Tuttavia, i modelli LLM disponibili presentano alcune limitazioni:

  • Il loro addestramento offline li rende inconsapevoli delle informazioni più recenti.
  • Il loro addestramento su dati prevalentemente generali ne diminuisce l’efficacia nelle attività specifiche di un settore. Ad esempio, una società finanziaria potrebbe preferire che il suo bot Q&A prelevi risposte dai suoi ultimi documenti interni, garantendo l’accuratezza e la conformità alle sue regole aziendali.
  • La loro dipendenza dalle informazioni incorporate compromette l’interpretabilità.

Per utilizzare dati specifici nei LLM, esistono tre metodi prevalenti:

  • Incorporare i dati all’interno dei prompt del modello, consentendo di utilizzare questo contesto durante la generazione dell’output. Questo può essere zero-shot (senza esempi), few-shot (con pochi esempi) o many-shot (con numerosi esempi). L’utilizzo di prompt contestuali guida i modelli verso risultati più sfumati.
  • Aggiustare il modello utilizzando coppie di prompt e completamenti.
  • RAG, che recupera dati esterni (non parametrici) e integra questi dati nei prompt, arricchendo il contesto.

Tuttavia, il primo metodo si scontra con i vincoli del modello sulla dimensione del contesto, rendendo difficile l’inserimento di documenti lunghi e aumentando eventualmente i costi. L’approccio di affinamento, sebbene potente, richiede molte risorse, soprattutto con l’evolversi continuo dei dati esterni, con conseguenti ritardi nelle distribuzioni e aumento dei costi. RAG combinato con LLM offre una soluzione alle limitazioni precedentemente menzionate.

Generazione potenziata dal recupero

RAG recupera dati esterni (non parametrici) e integra questi dati nei prompt del ML, arricchendo il contesto. Lewis et al. hanno introdotto i modelli RAG nel 2020, concettualizzandoli come una fusione di un modello sequenza-di-sequenze preaddestrato (memoria parametrica) e un indice vettoriale denso di Wikipedia (memoria non parametrica) accessibile tramite un recuperatore neurale.

Ecco come funziona RAG:

  • Fonti di dati: RAG può attingere da diverse fonti di dati, inclusi archivi di documenti, database o API.
  • Formattazione dei dati: Sia la query dell’utente che i documenti vengono trasformati in un formato adatto per confronti di rilevanza.
  • Embedding: Per facilitare questo confronto, la query e la collezione di documenti (o libreria di conoscenza) vengono trasformate in embedding numerici utilizzando modelli di linguaggio. Questi embedding racchiudono concetti testuali in modo numerico.
  • Ricerca di rilevanza: L’embedding della query dell’utente viene confrontato con gli embedding della collezione di documenti, identificando il testo rilevante tramite una ricerca di similarità nello spazio di embedding.
  • Arricchimento del contesto: Il testo rilevante identificato viene aggiunto al prompt originale dell’utente, migliorandone il contesto.
  • Elaborazione LLM: Con un contesto arricchito, il prompt viene fornito all’LLM, che, grazie all’inclusione di dati esterni pertinenti, produce output pertinenti e precisi.
  • Aggiornamenti asincroni: Per garantire che i documenti di riferimento rimangano aggiornati, è possibile aggiornarli in modo asincrono insieme alle loro rappresentazioni di embedding. Ciò garantisce che le future risposte del modello siano basate sulle informazioni più recenti, garantendo l’accuratezza.

In sostanza, RAG offre un metodo dinamico per infondere LLM con informazioni attuali e pertinenti, garantendo la generazione di output precisi e tempestivi.

Il diagramma seguente mostra il flusso concettuale dell’utilizzo di RAG con LLM:

Panoramica della soluzione

I seguenti passaggi sono necessari per creare un chatbot di risposta a domande contestuali per un’applicazione di servizi finanziari:

  1. Utilizzare il modello di embedding SageMaker JumpStart GPT-J-6B per generare embedding per ogni documento PDF nella directory di caricamento di Amazon Simple Storage Service (Amazon S3).
  2. Identificare i documenti rilevanti utilizzando i seguenti passaggi:
    • Generare un embedding per la query dell’utente utilizzando lo stesso modello.
    • Utilizzare OpenSearch Serverless con la funzione di motore vettoriale per cercare i K indici di documenti più rilevanti nello spazio degli embedding.
    • Recuperare i documenti corrispondenti utilizzando gli indici identificati.
  3. Unire i documenti recuperati come contesto con il prompt e la domanda dell’utente. Inviare tutto questo al SageMaker LLM per la generazione della risposta.

Utilizziamo LangChain, un framework popolare, per orchestrare questo processo. LangChain è progettato specificamente per migliorare le applicazioni alimentate da LLM, offrendo un’interfaccia universale per vari LLM. Semplifica l’integrazione di LLM multipli, garantendo una persistenza dello stato senza interruzioni tra le chiamate. Inoltre, migliora l’efficienza dello sviluppatore con funzionalità come modelli di prompt personalizzabili, agenti di creazione di applicazioni completi e indici specializzati per la ricerca e il recupero. Per una comprensione approfondita, fare riferimento alla documentazione di LangChain.

Prerequisiti

Hai bisogno dei seguenti prerequisiti per costruire il nostro chatbot consapevole del contesto:

Per istruzioni su come configurare un motore di vettori OpenSearch Serverless, consulta Presentazione del motore di vettori per Amazon OpenSearch Serverless, ora in anteprima.

Per una guida completa alla seguente soluzione, clona il repository GitHub e consulta il notebook Jupyter.

Deploy dei modelli di ML utilizzando SageMaker JumpStart

Per distribuire i modelli di ML, segui i seguenti passaggi:

  1. Distribuisci il modello Llama 2 LLM da SageMaker JumpStart:

    from sagemaker.jumpstart.model import JumpStartModelllm_model = JumpStartModel(model_id = "meta-textgeneration-llama-2-7b-f")llm_predictor = llm_model.deploy()llm_endpoint_name = llm_predictor.endpoint_name
  2. Distribuisci il modello di incorporamento GPT-J:

    embeddings_model = JumpStartModel(model_id = "huggingface-textembedding-gpt-j-6b-fp16")embed_predictor = embeddings_model.deploy()embeddings_endpoint_name = embed_predictor.endpoint_name

Esegui il segmentazione dei dati e crea un oggetto di incorporamento documento

In questa sezione, esegui la segmentazione dei dati in documenti più piccoli. La segmentazione è una tecnica per suddividere grandi testi in parti più piccole. È un passaggio essenziale perché ottimizza la rilevanza della query di ricerca per il nostro modello RAG, migliorando quindi la qualità del chatbot. Le dimensioni del segmento dipendono da fattori come il tipo di documento e il modello utilizzato. È stato selezionato un segmento di dimensioni chunk_size=1600 perché questa è la dimensione approssimativa di un paragrafo. Con il miglioramento dei modelli, la dimensione della finestra di contesto aumenterà, consentendo l’utilizzo di segmenti di dimensioni maggiori.

Consulta il notebook Jupyter nel repository GitHub per la soluzione completa.

  1. Espandi la classe SageMakerEndpointEmbeddings di LangChain per creare una funzione di incorporamento personalizzata che utilizza il punto di ingresso di SageMaker gpt-j-6b-fp16 creato in precedenza (come parte dell’utilizzo del modello di incorporamento):

    from langchain.embeddings import SagemakerEndpointEmbeddingsfrom langchain.embeddings.sagemaker_endpoint import EmbeddingsContentHandlerlogger = logging.getLogger(__name__)# estendi la classe SagemakerEndpointEmbeddings da langchain per fornire una funzione di incorporamento personalizzataclass SagemakerEndpointEmbeddingsJumpStart(SagemakerEndpointEmbeddings):    def embed_documents(        self, texts: List[str], chunk_size: int = 1    ) → List[List[float]]:        """Calcola l'incorporamento dei documenti utilizzando un punto di ingresso di Inferenza SageMaker.         Args:            texts: L'elenco di testi da incorporare.            chunk_size: La dimensione del segmento definisce quanti testi di input                saranno raggruppati insieme come richiesta. Se None, verrà utilizzata la                dimensione del segmento specificata dalla classe.        Returns:            Elenco di incorporamenti, uno per ogni testo.        """        risultati = []        _chunk_size = len(tests) if chunk_size > len(tests) else chunk_size        st = time.time()        for i in range(0, len(texts), _chunk_size):            response = self._embedding_func(texts[i : i + _chunk_size])            risultati.extend(response)        time_taken = time.time() - st        logger.info(            f"risultati ottenuti per {len(tests)} in {time_taken}s, lunghezza dell'elenco di incorporamenti è {len(risultati)}"        )        print(            f"risultati ottenuti per {len(tests)} in {time_taken}s, lunghezza dell'elenco di incorporamenti è {len(risultati)}"        )        return risultati# classe per la serializzazione e deserializzazione delle richieste/risposte dall'al modello di incorporamentoclass ContentHandler(EmbeddingsContentHandler):    content_type = "application/json"    accepts = "application/json"     def transform_input(self, prompt: str, model_kwargs={}) → bytes:         input_str = json.dumps({"text_inputs": prompt, **model_kwargs})        return input_str.encode("utf-8")     def transform_output(self, output: bytes) → str:         response_json = json.loads(output.read().decode("utf-8"))        embeddings = response_json["embedding"]        if len(embeddings) == 1:            return [embeddings[0]]        return embeddingsdef create_sagemaker_embeddings_from_js_model(    embeddings_endpoint_name: str, aws_region: str) → SagemakerEndpointEmbeddingsJumpStart:     content_handler = ContentHandler()    embeddings = SagemakerEndpointEmbeddingsJumpStart(        endpoint_name=embeddings_endpoint_name,        region_name=aws_region,        content_handler=content_handler,    )    return embeddings
  2. Crea l’oggetto di incorporamento e raggruppa la creazione degli incorporamenti dei documenti:

    embeddings = create_sagemaker_embeddings_from_js_model(embeddings_endpoint_name, aws_region)
  3. Questi incorporamenti vengono memorizzati nel motore di vettori utilizzando OpenSearchVectorSearch di LangChain. Si memorizzano questi incorporamenti nella sezione successiva. Memorizza l’incorporamento del documento in OpenSearch Serverless. Ora sei pronto per iterare sui documenti segmentati, creare gli incorporamenti e memorizzare questi incorporamenti nell’indice vettoriale di OpenSearch Serverless creato nelle raccolte di ricerca vettoriale. Vedi il seguente codice:

    docsearch = OpenSearchVectorSearch.from_texts(texts = [d.page_content for d in docs],embedding=embeddings,opensearch_url=[{'host': _aoss_host, 'port': 443}],http_auth=awsauth,timeout = 300,use_ssl = True,verify_certs = True,connection_class = RequestsHttpConnection,index_name=_aos_index)

Domande e risposte sui documenti

Fino ad ora, hai suddiviso un documento grande in più piccoli, creato embedding vettoriali e li hai memorizzati in un motore di vettori. Ora puoi rispondere alle domande riguardanti questi dati del documento. Poiché hai creato un indice sui dati, puoi effettuare una ricerca semantica; in questo modo, vengono passati al prompt solo i documenti più rilevanti necessari per rispondere alla domanda. Ciò ti consente di risparmiare tempo e denaro passando al LLM solo documenti pertinenti. Per ulteriori dettagli sull’utilizzo di catene di documenti, consulta Documenti.

Completa i seguenti passaggi per rispondere alle domande utilizzando i documenti:

  1. Per utilizzare il punto di accesso LLM di SageMaker con LangChain, utilizza langchain.llms.sagemaker_endpoint.SagemakerEndpoint, che astrae il punto di accesso LLM di SageMaker. Esegui una trasformazione per il payload di richiesta e risposta come mostrato nel codice seguente per l’integrazione di LangChain con SageMaker. Notare che potrebbe essere necessario modificare il codice in ContentHandler in base al content_type e al formato di accettazione del modello LLM che si sceglie di utilizzare.

    content_type = "application/json"accepts = "application/json"def transform_input(self, prompt: str, model_kwargs: dict) → bytes:        payload = {            "inputs": [                [                    {                        "role": "system",                        "content": prompt,                    },                    {"role": "user", "content": prompt},                ],            ],            "parameters": {                "max_new_tokens": 1000,                "top_p": 0.9,                "temperature": 0.6,            },        }        input_str = json.dumps(            payload,        )        return input_str.encode("utf-8")def transform_output(self, output: bytes) → str:    response_json = json.loads(output.read().decode("utf-8"))    content = response_json[0]["generation"]["content"]    return contentcontent_handler = ContentHandler()sm_jumpstart_llm=SagemakerEndpoint(        endpoint_name=llm_endpoint_name,        region_name=aws_region,        model_kwargs={"max_new_tokens": 300},        endpoint_kwargs={"CustomAttributes": "accept_eula=true"},        content_handler=content_handler,    )

Ora sei pronto per interagire con il documento finanziario.

  1. Utilizza la seguente query e il template di prompt per porre domande relative al documento:

    from langchain import PromptTemplate, SagemakerEndpointfrom langchain.llms.sagemaker_endpoint import LLMContentHandlerquery = "Sintetizza il rapporto sugli utili e di che anno è il rapporto"prompt_template = """Utilizza solo il contesto per rispondere alla domanda alla fine. {context} Domanda: {question}Risposta:"""prompt = PromptTemplate(    template=prompt_template, input_variables=["context", "question"])  class ContentHandler(LLMContentHandler):    content_type = "application/json"    accepts = "application/json"    def transform_input(self, prompt: str, model_kwargs: dict) → bytes:        payload = {            "inputs": [                [                    {                        "role": "system",                        "content": prompt,                    },                    {"role": "user", "content": prompt},                ],            ],            "parameters": {                "max_new_tokens": 1000,                "top_p": 0.9,                "temperature": 0.6,            },        }        input_str = json.dumps(            payload,        )        return input_str.encode("utf-8")     def transform_output(self, output: bytes) → str:        response_json = json.loads(output.read().decode("utf-8"))        content = response_json[0]["generation"]["content"]        return contentcontent_handler = ContentHandler() chain = load_qa_chain(    llm=SagemakerEndpoint(        endpoint_name=llm_endpoint_name,        region_name=aws_region,        model_kwargs={"max_new_tokens": 300},        endpoint_kwargs={"CustomAttributes": "accept_eula=true"},        content_handler=content_handler,    ),    prompt=prompt,)sim_docs = docsearch.similarity_search(query, include_metadata=False)chain({"input_documents": sim_docs, "question": query}, return_only_outputs=True)

Pulizia

Per evitare costi futuri, elimina i punti di accesso di inferenza di SageMaker che hai creato in questo notebook. Puoi farlo eseguendo quanto segue nel tuo notebook di SageMaker Studio:

# Elimina LLMllm_predictor.delete_model()llm_predictor.delete_predictor(delete_endpoint_config=True)# Elimina il Modello di Embeddingsembed_predictor.delete_model()embed_predictor.delete_predictor(delete_endpoint_config=True)

Se hai creato una collezione OpenSearch Serverless per questo esempio e non ne hai più bisogno, puoi eliminarla tramite la console di OpenSearch Serverless.

Conclusione

In questo post, abbiamo discusso l’utilizzo di RAG come approccio per fornire contesto specifico del dominio ai LLM. Abbiamo mostrato come utilizzare SageMaker JumpStart per costruire un chatbot contestuale basato su RAG per un’organizzazione di servizi finanziari utilizzando Llama 2 e OpenSearch Serverless con un motore vettoriale come archivio di dati vettoriali. Questo metodo affina la generazione di testo utilizzando Llama 2 e raccoglie dinamicamente il contesto rilevante. Siamo entusiasti di vederti utilizzare i tuoi dati personalizzati e innovare con questa strategia basata su RAG su SageMaker JumpStart!