fbpx
Adicionando ChatGPT na sua aplicação
Publicado em: sexta-feira, 28 de abr de 2023
Categorias: .NET

A primeira vez que ouvi falar em chatGPT fiquei empolgado com o avanço das IA’s Generativas, mas nem passou pela minha cabeça que já fosse possível usar em uma aplicação real.

Ao encontrar no ChatGPT inputs e outputs em texto livre, que hora traz texto normal, hora markdown, hora outros formatos, sem a capacidade de forçar o tipo de dado, via parâmetros, me pareceu uma realidade distante.

Uma vez que as API’s foram liberadas, não conseguia sequer pensar em uma utilização que não fosse simplória.

Hoje eu vou mostrar todo o caminho até conseguir produzir
insights,
predições,
recomendações
e expectativas
usando ChatGPT de forma estruturada produzindo JSON como output.

Embora esse projeto de referência seja feito em C# com .NET, você consegue replica em qualquer lugar, com qualquer linguagem/plataforma que consiga fazer uma requisição para um endpoint HTTP.

Contexto

A adoção de uma tecnologia em geral começa com a liberação de SDK’s para desenvolvedores, depois surgem as primeiras aplicações utilizando a tecnologia, elas chegam ao mercado, fazem sucesso e assim a disseminação começa gradativamente do técnico para o negócio.

Oferecer o GPT na forma de Chat foi uma sacada de marketing incrível.
Com os 2 pés na porta, trouxeram a tecnologia direto do laboratório para o usuário final.

Ter o primeiro contato com o GPT via ChatGPT atrapalha quem é técnico, porque quando vemos input texto livre e output também texto livre, logo descartamos o uso da solução.

Essas entradas e saídas, como não são estruturadas, sugerem certa fragilidade.

Assim, quando as API’s foram liberadas, as primeiras perguntas que me vieram à cabeça foram:

  • Será que é possível?
  • Ok, mas para quê? O que consigo criar com input e output não estruturados?

Pulando alguns meses à frente, no TDC, recebi o desafio de falar de Azure Open AI Services , 30 horas antes da hora da apresentação.

Quinze dias depois eu fiz essa apresentação no canal .NET, mostrando como usar o GPT como advisor para o comportamento assíncrono em uma aplicação de demonstração de mensageria.

Minha parte começa em 1h6min

Recomendo assistir porque vai abrir sua cabeça sobre as possibilidades.

Esse post não é sobre a live, mas como cheguei a esse resultado, portanto é relevante assistir o resultado!

Entendendo os princípios de cada assunto

A gente tem 2 assuntos interligados, uma aplicação de referência e a adição do advisor, que usa o GPT.

Aliás, daqui para frente no texto, vamos usar os termos corretos: GPT é o motor, ChatGPT é a ferramenta de chat da OpenAI. Daqui para frente respeitaremos com precisão a terminologia.

A aplicação

A aplicação de referência já existia. Ela foi criada durante a pandemia como ferramenta para demonstrar como aplicações assíncronas se comportam. Em especial, aplicações que usam RabbitMQ.

Quando se começa com RabbitMQ e mensageria, todos os holofotes se voltam para a estrutura de dados:
No caso FILAS.

Isso é um dos maiores problemas para quem está começando, afinal, como filas entregam resiliência, escalabilidade, eficiência e disponibilidade?

O problema é dizer ou pensar porque RabbitMQ é fila, é o mesmo que dizer que o Facebook é código.
Por ser código, coloca em qualquer patamar de semelhança com qualquer outra solução baseada em código. Ignorando todo o resto.

O fato da estrutura de dados ser o único assunto familiar, faz com que seja necessário usar recursos mais didáticos para mostrar que o uso de filas é a característica menos relevantes entre todas, quando o assunto é RabbitMQ e Mensageria.

Essa aplicação tem a função de apresentar quais novos recursos você ganha, onde perde, e dar o conforto mostrando com gráficos reais, de uma aplicação real que consome e publica mensagens, demonstrando quais expectativas você pode nutrir para que você sabia exatamente o que esperar.

Na jornada de conforto e segurança é necessário demonstrar como aplicações assíncronas funcionam.

Saber o que acontece em cada um dos momentos, ajuda a ter clareza.

Do lado esquerdo nós colocamos cargas de trabalho: Públishers que publicam mensagens no RabbitMQ.

Do lado direito, nós temos os Consumidores.

A função dessa aplicação é permitir que publishers e consumers sejam criados, com balanceamentos diversos, proporções diversas, para podemos simular todos os cenários comuns de uma aplicação em produção.

As análises são exibidas pelo grafana, conforme o exemplo abaixo.

Esses gráficos só são possíveis graças às métricas coletadas e armazenada sem banco.

Métricas

Então aqui está o primeiro ponto importante.

Esse projeto foi baseado na geração e exibição de métricas, portanto os dados já estavam em um banco de dados, de foma estruturada, prontos para serem consultados.

Esse é o primeiro elemento que precisei.

Descobrindo as capacidades do GPT usando ChatGPT

O segundo ponto é um tanto quanto criativo.

Pensar nas métricas que já existem e tentar montar prompts com elas, manualmente, e ver o que o GPT me responde.

Depois de alguns minutos eu cheguei a essa aqui:

Eu criei consumidores de filas, que consomem uma única fila.

Nos últimos 5 minutos o consumo era de 5m/s, 
tinham 5000 mensagens na fila, 
e tínhamos 10 instâncias, 
a duração média nos 10 minutos é de  50 segundos. 

Nos últimos 1 minutos o consumo era de 10m/s, 
tinham 20000 mensagens na fila, 
e tínhamos 30 instâncias, 
a duração média nos 10 minutos é de  1 minuto e 30 segundos. 

Se comporte como um especialista em estatística e métricas e forneça insights sobre o processamento. 

 Faça predições com base nesses números 

Faça sugestão de mudança na quantidade de instâncias e diga qual o resultado esperado com a mudança 

Não explique nem repita meus dados.

Responda em JSON no formato:
{ 
	"insights": [ ], 
	"predictions": [ ], 
	"suggestions": [ ] ,  
	"expected_results": [ ] 
}
{
"insights": [
"O consumo da fila aumentou significativamente no último minuto em comparação com os últimos 5 minutos",
"A duração média do processamento também aumentou significativamente no último minuto em comparação com os últimos 5 minutos",
"A quantidade de mensagens na fila aumentou significativamente no último minuto em comparação com os últimos 5 minutos",
"A quantidade de instâncias disponíveis também aumentou significativamente no último minuto em comparação com os últimos 5 minutos"
],
"predictions": [
"Se o consumo da fila continuar aumentando, é provável que a duração média do processamento aumente ainda mais",
"Se a quantidade de instâncias disponíveis for reduzida, é provável que a duração média do processamento aumente"
],
"suggestions": [
"É recomendável monitorar continuamente o consumo da fila e ajustar a quantidade de instâncias disponíveis de acordo",
"Uma abordagem possível seria aumentar o número de instâncias disponíveis para melhorar o tempo de processamento"
],
"expected_results": [
"Reduzir a quantidade de instâncias disponíveis provavelmente aumentará o tempo de processamento",
"Aumentar a quantidade de instâncias disponíveis provavelmente reduzirá o tempo de processamento"
]
}

Foram várias tentativas até chegar nisso.

Era o suficiente para mostrar o potencial da solução.

Eu comecei no GPT4, e no meio me lembrei que ainda não tenho acesso ao modelo. Então da metade em diante, usei o GPT 3.5. O resultado acima foi concebido nele.

Queries

Uma vez que funcionou com dados imaginários e inconsistentes, era hora de fazer queries reais e testar para validar e ver se ele mantinha a qualidade da análise.

Resultado: Sucesso!

Versão final

Agora com queries reais, temos novos resultados, ligeiramente diferentes.

Eu criei consumidores de filas, que consomem uma única fila.
São 5239 mensagens pendentes, aguardando processamento.
São 794145 mensagens processadas.
As mensagens estão sendo processadas em 0 milissegundos, nos último 30 segundos.
As mensagens estão sendo processadas em 0 milissegundos, nos último 1 minutos.
As mensagens estão sendo processadas em 33147.023456014363 milissegundos, nos últimos 2 minutos.
As mensagens estão sendo processadas em 12494.2497751105954021 milissegundos, nos últimos 5 minutos.
Agora tínhamos 2 consumidores, estávamos com 5091 mensagens não publicadas. Recebendo 172.2m/s e consumindo 117.2m/s
Há 5 minutos atrás tínhamos 12 consumidores, estávamos com 1 mensagens não publicadas. Recebendo 5.8m/s e consumindo 5.8m/s
No último minuto tínhamos 2 consumidores, estávamos com 3096 mensagens não publicadas. Recebendo 182m/s e consumindo 123.2m/s
Há 10 minutos atrás tínhamos 12 consumidores, estávamos com 1 mensagens não publicadas. Recebendo 64.2m/s e consumindo 64.2m/s
Faça predições com base nesses números 

Faça sugestão de mudança na quantidade de instâncias e diga qual o resultado esperado com a mudança 

Não explique nem repita meus dados.

Responda em JSON no formato:
{ 
	"insights": [ ], 
	"predictions": [ ], 
	"suggestions": [ ] ,  
	"expectedresults": [ ] 
}
{
	"insights": [
		"O número de mensagens pendentes é alto, indicando que o processamento não está acompanhando a velocidade de recebimento.",
		"Nos últimos 2 minutos, houve um aumento significativo no tempo de processamento das mensagens.",
		"A quantidade de consumidores afeta diretamente o número de mensagens não publicadas e a velocidade de recebimento e consumo."
	],
	"predictions": [
		"Se a velocidade de recebimento continuar em 172.2m/s e a velocidade de consumo não aumentar, o número de mensagens não publicadas pode aumentar ainda mais.",
		"Se o tempo de processamento continuar aumentando, pode haver um acúmulo ainda maior de mensagens pendentes.",
		"Se a quantidade de consumidores não for aumentada, é possível que a velocidade de processamento não acompanhe a velocidade de recebimento."
	],
	"suggestions": [
		"Aumentar a quantidade de instâncias para aumentar a velocidade de processamento e diminuir o número de mensagens não publicadas.",
		"Implementar um sistema de priorização de mensagens para garantir que as mensagens mais importantes sejam processadas primeiro.",
		"Rever a arquitetura do sistema para garantir que ele possa lidar com a quantidade de mensagens recebidas."
	],
	"expectedresults": [
		"Aumentando a quantidade de instâncias, espera-se que a velocidade de processamento aumente e o número de mensagens não publicadas diminua.",
		"Implementando um sistema de priorização de mensagens, espera-se que as mensagens mais importantes sejam processadas primeiro, reduzindo o tempo de espera para essas mensagens.",
		"Revisando a arquitetura do sistema, espera-se que ele possa lidar com a quantidade de mensagens recebidas sem afetar o tempo de processamento."
	]
}

Com isso é só realizar a chamada à API e juntar tudo.

Sobre a API a documentação mostra como chamar inclusive via CURL.

Aqui do meu lado criei classes e interfaces para usar com Refit e evitar a manipulação direta do HTTP Client.

CompletionResponse result =  await gagoGPT.Chat(new CompletionRequest()
	{
		Messages = new List<Message>() {
				new Message(){
					Role = Role.System,
					Content= "Se comporte como um especialista em estatística e métricas e forneça insights sobre o processamento."
				},
				new Message(){
					Role = Role.User,
					Content = stringBuilder.ToString()
				},
			},
		MaxTokens = 2000,
		Temperature = 0.5M,
		FrequencyPenalty = 0,
		PresencePenalty = 0,
		TopP = 0.5M,
		Stop = null
	}, 
	"<deployment-name>", 
	"<apiVersion-name>"
);

A demo ficou pronta durante a live, então ainda há bastante refactoring para ser realizado.

Enquanto ainda não tenho acesso ao GPT-4 via API vou aguardar para conseguir publicar essa parte do projeto.

No Nuget há 3 meses foi lançado o pacote Azure.AI.OpenAI que já está no beta 5 e já possui documentação.

Conclusão

Meu foco não foi no código em si, mas na construção do pensamento para conseguir reproduzir o mesmo resultado em qualquer código de qualquer linguagem, de qualquer plataforma moderna.

Da forma como foi feito, temos 100% das vezes o retorno estruturado em json, no formato esperado, pronto para uso.

Do ponto de vista de negócio é incrível poder criar análises desse tipo, com esse tipo de compreensão.

Claro que é preciso ir ajustando os parâmetros Temperature e TopP, e sugiro olhar a documentação, para chegar em um valor que se aproxime do perfeito.

E por hoje é só.

O Cloud Native .NET é meu principal projeto.

Onde empenho energia para ajudar, acompanhar, direcionar Desenvolvedores, Líderes Técnicos e jovens Arquitetos na jornada Cloud Native.

Conduzo entregando a maior e mais completa stack de tecnologias do mercado.

Ao trabalhar com desenvolvedores experientes, eu consigo usar seu aprendizado com .NET, banco de dados, e arquitetura para encurtar a jornada.

Ao restringir à desenvolvedores .NET eu consigo usar do contexto de tecnologias e problemas do seu dia-a-dia, coisas que você conhece hoje, como WCF, WebForms, IIS e MVC, por exemplo, para mostrar a comparação entre o que você conhece e o que está sendo apresentado.

É assim que construímos fundamentos sólidos, digerindo a complexidade com didática, tornando o complexo, simples.

É assim que conseguimos tornar uma jornada densa, em um pacote de ~4 meses.

Eu não acredito que um desenvolvedor possa entender uma tecnologia sem compreender seus fundamentos. Ele no máximo consegue ser produtivo, mas isso não faz desse desenvolvedor um bom tomador de decisões técnicas.

É preciso entender os fundamentos para conseguir tomar boas decisões.

2 Comentários

  1. ARIO LOVATO JUNIOR

    bom dia, terias um exemplo prático como posso subir uma base de dados (csv, etc) para realizar consultas?
    em C#

    Responder
    • Luiz Carlos Faria

      Leia o post com atenção plena, tem tudo aí para você fazer o que quer, exceto código pronto.

      Responder

Enviar um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.

[docker de a a z]

Lives

Fique de olho nas lives

Fique de olho nas lives no meu canal do Youtube, no Canal .NET e nos Grupos do Facebook e Instagram.

Aceleradores

Existem diversas formas de viabilizar o suporte ao teu projeto. Seja com os treinamentos, consultoria, mentorias em grupo.