Construção de um Agente AI Versátil

Nos últimos anos, houve uma revolução significativa na forma como usamos as aplicações, transformando a maneira como interagimos com a tecnologia e a experiência geral do usuário.

· Dev Rishi Khare

Um Guia para Iniciantes no Desenvolvimento de Modelos de Linguagem Personalizáveis para Resolver Casos de Uso Simples

Autora: Rachel Martinez | Função: Desenvolvedora | Marca: AI Agents


Introdução

Bem-vindo ao nosso blog técnico, onde tornamos conceitos complexos acessíveis a todos, independentemente de sua formação. Hoje, estamos mergulhando em um projeto emocionante: desenvolver um Agente de Modelo de Linguagem Grande (LLM) que possa se adaptar a várias tarefas.

Vamos criar uma infraestrutura robusta de Recuperação, Aumento e Geração (RAG) para nos ajudar a selecionar o LLM mais adequado para cada tarefa. Empresas como a H2O e a HuggingFace já lançaram sistemas semelhantes, e recebemos interesse de startups ansiosas para integrar nossa tecnologia AI em suas aplicações.

Nosso caso de uso específico exige a capacidade de solicitar ao LLM usando uma única entrada (one-shot) ou encadeando várias solicitações. Isso exige a criação de módulos LLM personalizáveis e fáceis de usar para diversos cenários.

Fique ligado enquanto embarcamos nesta jornada, desvendando cada etapa de forma simples e envolvente.

Caso de Uso Atual

No nosso caso de uso atual, aprimoramos o conteúdo do currículo de um usuário por meio de um processo em duas etapas:

  1. O usuário insere as seções “Resumo Profissional” e “Experiência” de seu currículo no sistema e consulta o LLM para gerar uma versão mais refinada do texto.
  2. Revisão: O usuário revisa o conteúdo gerado pelo LLM e fornece instruções ou orientações adicionais para refinar e personalizar a saída, garantindo que esteja alinhada com suas habilidades e experiências únicas.

Ao seguir essa abordagem, os usuários podem aproveitar o poder do LLM para criar um currículo convincente que se destaque aos empregadores em potencial.

Alvo

Nosso objetivo é desenvolver um módulo LLM totalmente personalizável que atenda ao nosso caso de uso e automatize, pelo menos parcialmente, o processo de criação do currículo.

Implementação

Passo 1: Escolha do LLM

Ao selecionar o LLM adequado para suas necessidades, há duas categorias principais a considerar: LLMs de código aberto e LLMs proprietários. Discutiremos as opções populares de ambos os grupos, com foco nos benefícios de escolher LLMs de código aberto.

LLMs de código aberto

Mistral AI, Phi 3, LLaMa 3.

Vantagens:

LLMs proprietários

GPT-4.

Vantagens: Desempenho impressionante e recursos exclusivos.

Limitações:

Em conclusão, embora os LLMs de código aberto e os proprietários tenham suas vantagens e desvantagens, os LLMs de código aberto, como Mistral AI, Phi 3 e LLaMa 3, oferecem acessibilidade, customizabilidade e transparência que podem ser altamente benéficos para uma ampla gama de usuários.

Passo 2: Analisando os custos e as funcionalidades

Os LLMs de código aberto geralmente são econômicos, pois podem ser hospedados em seus próprios servidores ou com provedores como Azure ou AWS, utilizando um modelo de pagamento conforme o uso. Aqui está um resumo dos custos e recursos para hospedar vários modelos de linguagem (LLMs):

LLMDetalhesComprimento do contextoCusto
Mixtral 8x7BMoE LLM por Mistral ATreinado: 8192 tokens$0.7/1M tokens (chea
Mixtral 8x22BSucessor do MixtralTreinado: 32768 token$2/1M tokens (disponível
LLaMa 3 70BModelo Não-MoE por MetTreinado: 2048 tokens$0.02/1K tokens (Azu
Phi 3 128KMultimodal-SLM por mimTreinado e Total: 3$0.002/1K tokens (Az
Turbo GPT-4Proprietário LLM por O16K padrão, maiorNão disponível no AWS

Passo 3: Testes usando APIs públicas compatíveis com OpenRouter

Selecionar e testar o melhor LLM exige uma maneira simplificada de acessar e avaliar diferentes modelos. O OpenRouter, um padrão aberto do API, permite a alternância perfeita entre vários modelos e serviços do AI. Escolhemos a Fireworks AI como nossa provedora porque:

Aqui está uma função de exemplo para invocar respostas do modelo e os resultados de latência usando o mesmo hardware:

import json

def get_sanitized_json_response(user_input, guardrail):
    final = chain.invoke({"text": f"Sanitize {user_input}. Guardrail: {guardrail}"})
    final = chain.invoke({"text": final.content})
    return json.loads(final.content.replace("<json>", "").replace("</json>", "").replace("\n",""))
ModeloLatênciaObservações
Mixtral 8x7B2,1sModelo mais leve, perf
Mixtral 8x22B5,3sModelo sucessor, sim
LLaMa 3 70B2,6sResposta decente, mas
Phi 3 128K1.5 minModelo multimodal com

Foi utilizado um guarda-roupa e uma entrada muito simples para testar o acima:

guardrail = """Format details as bullets and use the XYZ method to format the relevant detail.
            For example:
            - I did X boosting Y percent resulting in Z.
"""

Recebemos a seguinte resposta JSON sanitizada após sua invocação:

get_sanitized_json_response("""I served as Junior as a Software Engineer at TechCorp in Sydney in January 2011 and worked there until December 2018. During my tenure,

                            Liderei a equipe que desenvolveu ferramentas avançadas de análise financeira baseadas em AI para processar centenas de milhões de registros em um
                            ambiente distribuído e criou a versão inicial do pipeline de dados proprietário da empresa. Na minha função, fui responsável por
                            desenvolvendo soluções e implementando múltiplas APIs. No meu último ano gerenciando uma equipe focada em soluções de blockchain.

{'experience': [{'title': 'Engenheiro de Software',
                'empresa': 'TechCorp',
                'localização': 'Sydney',
                'start_date': '2011-01',
                'end_date': '2018-12',
                '- Projetado sistemas de banco de dados escaláveis em um grande projeto que melhorou a velocidade de processamento de dados dos clientes em 40%.'
                              '- Liderou uma equipe focada em soluções impulsionadas por AI.',
                              '- Desenvolvi ferramentas de análise financeira baseadas em AI que processam mais de 100 milhões de registros em ambientes distribuídos.',
                              '- Criou o pipeline de dados proprietário da empresa.',
                              - Liderou equipe em soluções de blockchain no último ano.

In conclusion, since the response quality was fairly comparable among all these models, it came down to latency and cost. The experiment was run 3 times achieving very similar results. So we chose Mistral AI’s Mixtral 8x7B due to its favorable balance of latency and cost.

Step 4: Building an Orchestration Layer

Managing and coordinating multiple large-scale language models or a single model across various applications is crucial for optimal performance and adaptability. Instead of building from scratch using vanilla PyTorch, employing an orchestration framework is more practical and efficient. Here are three options:

Langchain

Advantages: Vast array of integrations, supports Python and JavaScript, extensive community support.

Drawbacks: Introduces an additional dependency, potential learning curve.

LlamaIndex

Advantages: Backed by Meta, offers interoperability with Langchain.

Drawbacks: Less developer-friendly syntax.

Haystack

Advantages: User-friendly syntax, supported by prominent tech corporations.

Drawbacks: Limited integrations as it’s still maturing.

Using an orchestration framework simplifies development, improves scalability, and provides access to a supportive community, making it a more favorable choice for our project.

Design and Data Flow

The following image shows the design diagram:

The data flow within our AI-driven system is an essential aspect of ensuring a seamless and efficient user experience. While the design diagram provides a visual representation of the process, a detailed explanation can help clarify the steps involved:

  1. User Input: The journey begins when the user enters their details, such as the “about” and “experience” sections of their resume, into the system.
  2. Prompt Generation: The user’s input is then processed and transformed into one or more prompts, which will be used to query the Large Language Model (LLM) for a more polished and impressive version of the text.
  3. LLM Integration via Langchain: The generated prompts are passed to Langchain, our chosen orchestrator framework, which facilitates the interaction with the LLM client. Langchain leverages a Pydantic schema in the form of a class to parse and validate the data using kor, ensuring that it adheres to the required format.
  4. JSONResponse Generation: Once the data is validated, it is converted into a final JSONResponse, a structured and easy-to-work-with data format that simplifies further processing and manipulation.
  5. Content Extraction and Indexing: The content part of the JSONResponse is extracted using kor and indexed by computing embeddings, which are mathematical representations of the text. These embeddings are then stored in a vector database, such as Qdrant, for efficient retrieval and comparison during subsequent queries.
  6. Caching for Context Module: The entire JSONResponse is cached for the context module to function correctly. This ensures that the system can maintain the context of the user’s input and the LLM’s output during follow-up queries.
  7. Follow-up Queries: When the user provides additional input or requests further refinement of the generated text, the cached JSONResponse is modified according to the new context and chained to the updated prompt. This modified prompt then goes through the entire process again, from LLM integration to content extraction and indexing, to provide the user with a tailored and accurate response.

By understanding the data flow within our system, we can appreciate the importance of each step and the role of the orchestrator framework in streamlining the process, ultimately resulting in an efficient and user-friendly AI-driven solution.

Construção e encadeamento de prompts usando LCEL

Este é um exemplo de uma amostra PromptTemplate:

from langchain.core.output_parsers import PydanticOutputParser
prompt = PromptTemplate(
    template="Please extract the following information from the given text and format it as a JSON object according to the schema:\n\n{format_instructions}\n{query}\n",
    input_variables=["query"],
    partial_variables={"format_instructions": output_parser.get_format_instructions()},
)

chain = prompt | chat_model | output_parser

Um modelo típico consiste em dois argumentos principais (existem outros, mas isso está fora do escopo deste blog): input_variables e template. O primeiro argumento aceita uma lista de strings que seriam injetadas no modelo de prompt em tempo de execução. Esta variável tipicamente age como as do Jinja2Template ou f-strings. O chat_model aqui seria o LLM que estamos usando e está sendo encadeado ao prompt. O operador | (pipe), semelhante ao operador | do BASH, representa uma cadeia. Esta é uma abreviação conveniente fornecida pela especificação LCEL (LangChain Expression Language). Isso nos permitiria encadear a resposta de um prompt com a entrada de outro. Também suporta chamadas de função, ou seja, é possível encadear expressões lambda ou algumas funções para tipicamente sanitizar a saída. Isso reduz a complexidade do código ao escrever cadeias em vez de funções grandes.

Passo 5: Usando VectorDBs

Bancos de dados vetoriais (VectorDBs) armazenam, gerenciam e buscam eficientemente vetores de alta dimensão, como embeddings de texto gerados por LLMs. Aqui está uma comparação das opções populares:

Qdrant

Vantagens: Alto desempenho, fácil integração, comunidade ativa.

Desvantagens: Nenhuma significativa.

Milvus

Vantagens: Múltiplas métricas de distância, ferramenta de visualização de dados.

Desvantagens: Curva de aprendizado mais acentuada.

Croma

Vantagens: Fácil de usar Python API, design modular.

Desvantagens: Relativamente novo, com suporte de comunidade menos extenso.

PGVector

Vantagens: Aproveita as capacidades do PostgreSQL, consultas baseadas em SQL.

Desvantagens: Menos eficiente para busca vetorial de alta dimensionalidade.

FAISS

Vantagens: Pesquisa de alto desempenho, suporte ao GPU.

Desvantagens: Requer integração com outros bancos de dados.

A escalabilidade, a facilidade de integração e o desenvolvimento ativo do Qdrant tornam-no uma escolha adequada para a nossa solução baseada em AI.

Aproveitando o VectorDBs como uma solução robusta de IR

Criar uma solução de Recuperação de Informação (IR) usando VectorDBs envolve:

  1. Pré-processamento de Texto: Limpar e pré-processar dados brutos.
  2. Geração de Incorporações de Texto: Converta o texto pré-processado em vetores de alta dimensão usando um LLM.
  3. Armazenamento de Embeddings em VectorDB: Indexação de embeddings para busca eficiente.
  4. Processamento de Consultas: Pré-processar e converter consultas de usuários em embeddings.
  5. Busca por similaridade: Realize uma busca por similaridade no VectorDB para encontrar embeddings relevantes.
  6. Classificação e Exibição de Resultados: Classifique as embeddings recuperadas e converta-as de volta para texto para exibição.

Ao seguir este processo e utilizar o VectorDBs, podemos construir um sistema IR eficiente e eficaz.

Ready to hire with precision?

Start free, invite your whole team, and see your first scored candidate in 15 minutes.

pt