OpenAI publica especificações de modelo revelando como deseja que a IA se comporte
9 de maio de 2024Superando os desafios de trabalhar com uma API FinTech móvel
9 de maio de 2024Embora seja sempre útil melhorar a documentação para desenvolvedores, muitos (inclusive eu) preferem mergulhar e aprender enquanto fazem isso. Esse é o sétimo e provavelmente o mais importante dos meus sete princípios orientadores para trabalhar com LLMs: Como você adquire conhecimento em momentos de ensino orientados para tarefas, o aprendizado não é prospectivo – é imediato e tangível.
Quando um desenvolvedor experiente faz parceria com um LLM, sua inteligência de máquina apoia e amplifica sua inteligência humana.
Os benefícios foram claros para mim. Escrever um plugin ODBC para Steampipe na era LLM pareceu muito mais fácil do que a experiência que tive escrevendo plugins sem essa assistência. Mas essa é uma avaliação subjetiva, então eu estava procurando uma oportunidade de comparar notas com outro desenvolvedor de plugins quando James Ramirez apareceu em nossa comunidade Slack para anunciar um novo plugin para a API Kolide. Convidei-o a me contar sobre sua experiência na construção e ele gentilmente me conduziu por uma longa conversa com o ChatGPT, na qual se familiarizou com três grupos de conhecimento técnico que eram novos para ele: a API Kolide, a linguagem Go e a arquitetura do plugin Steampipe.
Como um desafio adicional: embora os desenvolvedores de plug-ins geralmente encontrem SDKs Go adequados para as APIs que seus plug-ins visam, esse não foi o caso aqui. Então foi necessário criar um wrapper Go para a API Kolide e depois integrá-lo ao plugin.
Testando a capacidade Go do ChatGPT
James começou com alguns exercícios de aquecimento. Primeiro, para testar a capacidade Go do ChatGPT, ele forneceu um par de funções Go que escreveu para chamar as APIs relacionadas /dispositivos/ e /dispositivos/IDe solicitou uma refatoração idiomática para isolar a lógica compartilhada entre eles.
Em seguida, ele explorou parâmetros opcionais para funções usando argumentos variáveis simples versus o padrão de opções funcionais mais complexo e determinou que a abordagem simples – usando uma fatia de Procurar estruturas para encapsular o estilo campo/operador/valor dos parâmetros de consulta do Kolide – seriam suficientes. Ele pediu uma função para serializar aquela fatia de Procurar structs para formar uma URL REST e, em seguida, refinou a versão proposta pelo ChatGPT para criar um serializeSearches final que adiciona suporte para mapear nomes amigáveis para parâmetros e usa um construtor de string.
A IA lida com as críticas e geralmente fornece sugestões confiáveis.
Vários desses refinamentos, incluindo o uso de um construtor de strings, foram sugeridos por um bot com tecnologia de IA, CodeRabbit, que forneceu uma revisão de código útil. É o tipo de feedback que ajuda você e sua equipe a se concentrarem no panorama geral, diz ele, porque lida com as críticas e muitas vezes (embora nem sempre) fornece sugestões confiáveis. Também adota uma visão mais ampla para resumir solicitações pull e avaliar se um PR fechado aborda os objetivos declarados no problema vinculado.
Operadores de mapeamento
Ele passou a explorar maneiras de mapear operadores Steampipe como QualOperadorEqual para operadores Kolide como É igual a. Também aqui a abordagem sugerida pelo ChatGPT revelou-se descartável, a caminho de uma abordagem limpa e simples. Mas, como James confirmou em nossa entrevista, já que você irá iterar em versões descartáveis de qualquer maneira, é útil ser capaz de gerar iterações plausíveis em vez de codificá-las manualmente de maneira muito mais tediosa. Ao longo do caminho, ele aprendeu expressões básicas de Go.
James:
Existe um loop do-while no Go?
Bate-papoGPT
Não mas…
James:
Existe um operador ternário no Go?
Bate-papoGPT
Não mas…
James:
Como faço para adicionar a um map(string)string?
Bate-papoGPT
Assim…
O padrão do visitante aprimorado com reflexão
Depois de digerir o básico e desenvolver um cliente Go para a API Kolide, James estava pronto para enfrentar o verdadeiro trabalho de desenvolvimento de plug-ins: definir tabelas que mapeiam os tipos Go retornados de um wrapper de API para os esquemas Steampipe que controlam as consultas SQL nessas tabelas.
Como todos os desenvolvedores de plugins, ele começou com uma tabela que poderia listar um conjunto de recursos e depois aprimorou-a com filtragem e paginação. Depois de adicionar uma segunda tabela, chegou a hora de considerar como abstrair padrões e comportamentos comuns. O resultado final foi uma implementação elegante do padrão visitante. Aqui estão os Steampipes Lista funções que correspondem às tabelas kolide_device e kolide_issue.
E aqui está o comum listar qualquer coisa função usada por todas as tabelas do plugin.
Com esta configuração, adicionar uma nova tabela ao plugin é quase inteiramente declarativo: você só precisa definir o esquema, junto com o Colunas-chave e operadores associados que formam a ponte entre onde (ou juntar) em consultas SQL e filtros em nível de API. Então você escreve um pequeno Lista função que define um visitante e o passa para o comum listar qualquer coisa função que encapsula o empacotamento de parâmetros de consulta, conectando-se ao cliente da API, chamando a API, descompactando a resposta em uma coleção e iterando sobre a coleção para transmitir itens para o wrapper de dados externos do Steampipe.
James usou ChatGPT para iniciar uma implementação idiomática do padrão de visitante em Go. Isso envolveu aprender como definir um tipo para a função de visitante e, em seguida, declarar uma função para satisfazer o tipo. O visitante de cada tabela encapsula uma chamada ao cliente API e retorna uma interface. É tudo bastante genérico, mas a resposta do visitante era específica para o tipo Go da resposta da API empacotada, e isso significaria escrever um arquivo distinto Lista função para cada tabela. Como evitar isso? James perguntou: “As referências de campo na variável res precisam ser do tipo variável, especificadas no tempo de execução. Você poderia sugerir uma abordagem?
A sugestão do ChatGPT, que ele adotou, foi usar a reflexão para que uma chamada para listar qualquer coisacomo listAnything(ctx, d, h, “kolide_device.listDevices”, visitante, “Dispositivos”)poderia passar um nome (“Dispositivos”) que permite listar qualquer coisa para acessar campos da estrutura de resposta de maneira independente de tipo, por exemplo, o Dispositivos campo aqui.
type DeviceListResponse struct { Devices ()Device `json:"data"` Pagination Pagination `json:"pagination"` }
Com isso, listar qualquer coisa finalmente fez jus ao seu nome como um Steampipe totalmente genérico Lista função. A solução usa reflexão com moderação e mantém a forte verificação de tipo do Go tanto na camada API quanto na camada Steampipe.
O que a assistência LLM realmente significou?
Certamente aconteceu não significa que um LLM escreveu um plugin que incorpora padrões de design sofisticados em resposta a um prompt como: “Preciso do plugin Steampipe para a API Kolide, crie-o.” O que isso significou para mim, e o que também significou para James, é algo que considero mais interessante: “Vamos conversar sobre o processo de escrever um plugin para a API Kolide.” É como conversar com um pato de borracha para pensar em voz alta sobre requisitos e estratégias. Mas um LLM é um pato de borracha que responde. Às vezes, as respostas são diretamente aplicáveis, às vezes não, mas de qualquer forma, muitas vezes podem ajudá-lo a obter clareza.
Como engenheiro de software sênior com ampla experiência, James poderia ter descoberto – mas demoraria muito mais tempo.
“A conversa exigiu que eu fosse bastante específico sobre o que estava perguntando”, disse James. Embora estivesse começando do zero com Go, ele trouxe uma vasta experiência que lhe permitiu orientar-se rapidamente e descobrir quais eram as perguntas certas a serem feitas. Como engenheiro de software sênior com ampla experiência, James poderia ter descoberto tudo isso sozinho. Mas teria levado muito mais tempo e ele teria gasto muito tempo lendo artigos e documentação em vez de aprender fazendo. E esse tempo pode não estar disponível! Como já ouvi de muitos outros, a aceleração proporcionada pelos LLMs muitas vezes faz a diferença entre ter uma ideia e ser capaz de executá-la.
James também mencionou um ângulo de código aberto que eu não havia considerado. Antes do LLM, ele não teria feito esse trabalho de forma totalmente pública. “Eu teria mantido isso em sigilo até me sentir mais confiante”, diz ele, “mas isso estava disponível desde o início e fiquei feliz por divulgá-lo”. Isso tornou possível o envolvimento com a equipe Turbot mais cedo ou mais tarde.
Esta não é uma história de automação, mas sim de aumento. Quando um desenvolvedor experiente como James Ramirez faz parceria com um LLM, sua inteligência de máquina apoia e amplifica sua inteligência humana. Ambos trabalham juntos — não apenas para escrever código, mas, mais importante, para pensar em arquitetura e design.
A postagem Emparelhando com IA: a jornada de um desenvolvedor sênior construindo um plug-in apareceu pela primeira vez em The New Stack.