paint-brush
Melhor - Um revisor de código com tecnologia de IApor@murtuzaalisurti

Melhor - Um revisor de código com tecnologia de IA

por Murtuza
Murtuza HackerNoon profile picture

Murtuza

@murtuzaalisurti

Software Engineer, Building syntackle.com

8 min read2024/11/20
Read on Terminal Reader
Read this story in a terminal
Print this story
Read this story w/o Javascript
Read this story w/o Javascript
tldt arrow
pt-flagPT
Leia esta história em português!
en-flagEN
Read this story in the original language, English!
ru-flagRU
Прочтите эту историю на русском языке!
tr-flagTR
Bu hikayeyi Türkçe okuyun!
ko-flagKO
이 이야기를 한국어로 읽어보세요!
de-flagDE
Lesen Sie diese Geschichte auf Deutsch!
bn-flagBN
এই গল্পটি বাংলায় পড়ুন!
es-flagES
Lee esta historia en Español!
hi-flagHI
इस कहानी को हिंदी में पढ़ें!
zh-flagZH
用繁體中文閱讀這個故事!
vi-flagVI
Đọc bài viết này bằng tiếng Việt!
fr-flagFR
Lisez cette histoire en Français!
ja-flagJA
この物語を日本語で読んでください!
PT

Muito longo; Para ler

As revisões de código sempre foram cruciais para manter um padrão e enfatizar as melhores práticas de código em um projeto. Este não é um post sobre como os desenvolvedores devem revisar o código, é mais sobre delegar uma parte dele para a IA. É por isso que decidi criar uma ação no github (github.com/murtuzaalisurti/better) que revisa o código de um diff de pull request e gera sugestões usando IA.

People Mentioned

Mention Thumbnail

Michael Lynch

@mtlynch

Mention Thumbnail

Code Review

@codereview

Companies Mentioned

Mention Thumbnail
GitHub
Mention Thumbnail
Human
featured image - Melhor - Um revisor de código com tecnologia de IA
Murtuza HackerNoon profile picture
Murtuza

Murtuza

@murtuzaalisurti

Software Engineer, Building syntackle.com

0-item
1-item

STORY’S CREDIBILITY

AI-assisted

AI-assisted

This story contains AI-generated text. The author has used AI either for research, to generate outlines, or write the text itself.

Product Launch

Product Launch

This post provides insights into new product.

Revisões de código sempre foram cruciais para manter altos padrões e reforçar as melhores práticas em um projeto de codificação. Este não é um post sobre como os desenvolvedores devem revisar o código, é mais sobre delegar uma parte dele para a IA.


Como Michael Lynch menciona em seu post - "Como fazer revisões de código como um humano" - devemos deixar os computadores cuidarem das partes chatas da revisão de código. Enquanto Michael enfatiza uma ferramenta de formatação, eu gostaria de dar um passo adiante e deixar a inteligência artificial descobrir. Quer dizer, por que não aproveitar o boom da IA na indústria?


Agora, não estou dizendo que a IA deve ser usada no lugar de ferramentas de formatação e linters. Em vez disso, ela deve ser usada em cima disso, para capturar coisas triviais que podem passar despercebidas por um humano. É por isso que decidi criar uma ação do github que revisa o código de um diff de pull request e gera sugestões usando IA. Deixe-me explicar isso.


🚨 NOTA:


Obtendo a diferença

Para interagir com a API do GitHub, usei octokit , que é uma espécie de SDK ou biblioteca cliente para interagir com a API do GitHub de forma idiomática.


Para que você obtenha o diff da solicitação de pull gerada, você precisa passar o cabeçalho Accept com o valor application/vnd.github.diff junto com os parâmetros necessários.


 async function getPullRequestDetails(octokit, { mode }) { let AcceptFormat = "application/vnd.github.raw+json"; if (mode === "diff") AcceptFormat = "application/vnd.github.diff"; if (mode === "json") AcceptFormat = "application/vnd.github.raw+json"; return await octokit.rest.pulls.get({ owner: github.context.repo.owner, repo: github.context.repo.repo, pull_number: github.context.payload.pull_request.number, headers: { accept: AcceptFormat, }, }); }



Se você não está familiarizado com as ações do GitHub, aqui está uma série de ações do GitHub 101 de Victoria Lo , que é um bom começo.



Depois de obter o diff, eu o analiso e removo as alterações indesejadas e, em seguida, o retorno em um esquema mostrado abaixo:


 /** using zod */ schema = z.object({ path: z.string(), position: z.number(), line: z.number(), change: z.object({ type: z.string(), add: z.boolean(), ln: z.number(), content: z.string(), relativePosition: z.number(), }), previously: z.string().optional(), suggestions: z.string().optional(), })

Ignorando arquivos

Ignorar arquivos é bem direto. A lista de entrada do usuário requer uma sequência separada por ponto e vírgula de padrões glob. Ela é então analisada, concatenada com a lista padrão de arquivos ignorados e desduplicada.


 **/*.md; **/*.env; **/*.lock; const filesToIgnoreList = [ ...new Set( filesToIgnore .split(";") .map(file => file.trim()) .filter(file => file !== "") .concat(FILES_IGNORED_BY_DEFAULT) ), ];


A lista de arquivos ignorados é então usada para remover as alterações diff que se referem a esses arquivos ignorados. Isso lhe dá uma carga bruta contendo apenas as alterações que você deseja.

Gerando sugestões

Assim que obtenho o payload bruto após analisar o diff, passo-o para a API da plataforma. Aqui está uma implementação da API OpenAI.


 async function useOpenAI({ rawComments, openAI, rules, modelName, pullRequestContext }) { const result = await openAI.beta.chat.completions.parse({ model: getModelName(modelName, "openai"), messages: [ { role: "system", content: COMMON_SYSTEM_PROMPT, }, { role: "user", content: getUserPrompt(rules, rawComments, pullRequestContext), }, ], response_format: zodResponseFormat(diffPayloadSchema, "json_diff_response"), }); const { message } = result.choices[0]; if (message.refusal) { throw new Error(`the model refused to generate suggestions - ${message.refusal}`); } return message.parsed; }


Você pode notar o uso do formato de resposta na implementação da API. Esse é um recurso fornecido por muitas plataformas LLM, que permite que você diga ao modelo para gerar a resposta em um esquema/formato específico. É especialmente útil neste caso, pois não quero que o modelo tenha alucinações e gere sugestões para arquivos ou posições incorretas na solicitação de pull, ou adicione novas propriedades à carga útil da resposta.


O prompt do sistema está lá para dar ao modelo mais contexto sobre como ele deve fazer a revisão de código e quais são algumas coisas para manter em mente. Você pode visualizar o prompt do sistema aqui github.com/murtuzaalisurti/better . O prompt do usuário contém o diff real, as regras e o contexto da solicitação de pull. É o que inicia a revisão de código.


Esta ação do github suporta os modelos OpenAI e Anthropic. Veja como ela implementa a API Anthropic:


 async function useAnthropic({ rawComments, anthropic, rules, modelName, pullRequestContext }) { const { definitions } = zodToJsonSchema(diffPayloadSchema, "diffPayloadSchema"); const result = await anthropic.messages.create({ max_tokens: 8192, model: getModelName(modelName, "anthropic"), system: COMMON_SYSTEM_PROMPT, tools: [ { name: "structuredOutput", description: "Structured Output", input_schema: definitions["diffPayloadSchema"], }, ], tool_choice: { type: "tool", name: "structuredOutput", }, messages: [ { role: "user", content: getUserPrompt(rules, rawComments, pullRequestContext), }, ], }); let parsed = null; for (const block of result.content) { if (block.type === "tool_use") { parsed = block.input; break; } } return parsed; }

Adicionando Comentários

Por fim, depois de recuperar as sugestões, eu as higienizo e as passo para a API do GitHub para adicionar comentários como parte da revisão.

Escolhi a maneira abaixo para adicionar comentários porque, ao criar uma nova avaliação, você pode adicionar todos os comentários de uma vez em vez de adicionar um único comentário por vez. Adicionar comentários um por um também pode acionar a limitação de taxa porque adicionar comentários aciona notificações e você não quer enviar spam para os usuários com notificações.


 function filterPositionsNotPresentInRawPayload(rawComments, comments) { return comments.filter(comment => rawComments.some(rawComment => rawComment.path === comment.path && rawComment.line === comment.line) ); } async function addReviewComments(suggestions, octokit, rawComments, modelName) { const { info } = log({ withTimestamp: true }); // eslint-disable-line no-use-before-define const comments = filterPositionsNotPresentInRawPayload(rawComments, extractComments().comments(suggestions)); try { await octokit.rest.pulls.createReview({ owner: github.context.repo.owner, repo: github.context.repo.repo, pull_number: github.context.payload.pull_request.number, body: `Code Review by ${modelName}`, event: "COMMENT", comments, }); } catch (error) { info(`Failed to add review comments: ${JSON.stringify(comments, null, 2)}`); throw error; } }

Conclusão

Eu queria manter a ação do GitHub aberta e aberta a integrações, e é por isso que você pode usar qualquer modelo de sua escolha (veja a lista de modelos suportados ) , ou você pode ajustar e criar seu próprio modelo personalizado com base nos modelos base suportados e usá-lo com esta ação do GitHub.


Se você encontrar algum problema de token ou limitação de taxa , talvez seja necessário atualizar os limites do seu modelo consultando a documentação da respectiva plataforma.


Então, o que você está esperando? Se você tem um repositório no github, experimente a ação agora - ela está no mercado de ações do github .


L O A D I N G
. . . comments & more!

About Author

Murtuza HackerNoon profile picture
Software Engineer, Building syntackle.com

Rótulos

ESTE ARTIGO FOI APRESENTADO EM...

Permanent on Arweave
Read on Terminal Reader
Read this story in a terminal
 Terminal
Read this story w/o Javascript
Read this story w/o Javascript
 Lite
Also published here

Mentioned in this story

profiles
X REMOVE AD