paint-brush
Daha İyi - Yapay Zeka Destekli Kod İncelemecisiile@murtuzaalisurti
Yeni tarih

Daha İyi - Yapay Zeka Destekli Kod İncelemecisi

ile Murtuza8m2024/11/20
Read on Terminal Reader
Read this story w/o Javascript

Çok uzun; Okumak

Kod incelemeleri, bir projedeki kodun en iyi uygulamalarına vurgu yapmak ve bir standardı sürdürmek için her zaman önemli olmuştur. Bu, geliştiricilerin kodu nasıl incelemesi gerektiğiyle ilgili bir gönderi değil, daha çok bir kısmını AI'ya devretmekle ilgilidir. Bu yüzden, bir çekme isteği farkını inceleyen ve AI kullanarak öneriler üreten bir github eylemi (github.com/murtuzaalisurti/better) oluşturmaya karar verdim.

People Mentioned

Mention Thumbnail
Mention Thumbnail

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Daha İyi - Yapay Zeka Destekli Kod İncelemecisi
Murtuza HackerNoon profile picture
0-item
1-item

Kod incelemeleri, bir kodlama projesinde yüksek standartları korumak ve en iyi uygulamaları güçlendirmek için her zaman önemli olmuştur. Bu, geliştiricilerin kodu nasıl incelemesi gerektiğiyle ilgili bir gönderi değil, daha çok bir kısmını yapay zekaya devretmekle ilgilidir.


Michael Lynch'in "İnsan Gibi Kod İncelemeleri Nasıl Yapılır" başlıklı yazısında belirttiği gibi, kod incelemesinin sıkıcı kısımlarıyla bilgisayarların ilgilenmesine izin vermeliyiz . Michael bir biçimlendirme aracını vurgularken, ben bunu bir adım öteye taşıyıp yapay zekanın çözmesine izin vermek istiyorum. Yani, sektördeki yapay zeka patlamasından neden faydalanmayalım ki?


Şimdi AI'nın biçimlendirme araçları ve lint araçları yerine kullanılması gerektiğini söylemiyorum. Bunun yerine, bir insanın kaçırabileceği önemsiz şeyleri yakalamak için bunun üstüne kullanılmalıdır. Bu yüzden, bir çekme isteği farkını inceleyen ve AI kullanarak öneriler üreten bir github eylemi oluşturmaya karar verdim. Size yol göstereyim.


🚨 NOT:


Farkı almak

Github API'siyle etkileşime girebilmek için, Github API'siyle deyimsel bir şekilde etkileşime girmek için bir tür SDK veya istemci kütüphanesi olan octokit kullandım.


Çekme isteğinin farkını alabilmeniz için Accept başlığına application/vnd.github.diff değerini ve gerekli parametreleri geçirmeniz gerekiyor.


 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, }, }); }



Eğer github action'larına hiç aşina değilseniz, Victoria Lo'nun github actions 101 serisi iyi bir başlangıç olabilir.



Diff'i aldıktan sonra onu ayrıştırıp istenmeyen değişiklikleri kaldırıyorum ve ardından aşağıda gösterilen şemaya döndürüyorum:


 /** 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(), })

Dosyaları Yoksayma

Dosyaları yok saymak oldukça basittir. Kullanıcı girdi listesi, noktalı virgülle ayrılmış bir glob desenleri dizisi gerektirir. Daha sonra ayrıştırılır, yok sayılan dosyaların varsayılan listesiyle birleştirilir ve çoğaltılmaz.


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


Yoksayılan dosyalar listesi daha sonra, bu yoksayılan dosyalara atıfta bulunan diff değişikliklerini kaldırmak için kullanılır. Bu size yalnızca istediğiniz değişiklikleri içeren ham bir yük verir.

Öneriler oluşturuluyor

Diff'i ayrıştırdıktan sonra ham veriyi aldığımda, bunu platform API'sine iletirim. İşte OpenAI API'sinin bir uygulaması.


 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; }


API uygulamasında yanıt biçiminin kullanıldığını fark edebilirsiniz. Bu, birçok LLM platformu tarafından sağlanan ve modele yanıtı belirli bir şema/biçimde oluşturmasını söylemenize olanak tanıyan bir özelliktir. Bu durumda özellikle yararlıdır çünkü modelin halüsinasyon görmesini ve çekme isteğindeki yanlış dosyalar veya konumlar için öneriler oluşturmasını veya yanıt yüküne yeni özellikler eklemesini istemiyorum.


Sistem istemi, modele kod incelemesini nasıl yapması gerektiği ve akılda tutulması gereken bazı şeyler hakkında daha fazla bağlam sağlamak için vardır. Sistem istemini buradan görüntüleyebilirsiniz github.com/murtuzaalisurti/better . Kullanıcı istemi gerçek diff'i, kuralları ve çekme isteğinin bağlamını içerir. Kod incelemesini başlatan şeydir.


Bu github eylemi hem OpenAI hem de Anthropic modellerini destekler. Anthropic API'yi şu şekilde uygular:


 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; }

Yorum Ekleme

Son olarak önerileri aldıktan sonra onları temizleyip yorumların incelemenin bir parçası olarak eklenmesi için GitHub API'sine iletiyorum.

Aşağıdaki yorum ekleme yolunu seçtim çünkü yeni bir inceleme oluşturarak tek seferde tek yorum eklemek yerine tüm yorumları tek seferde ekleyebilirsiniz. Yorumları tek tek eklemek ayrıca oran sınırlamasını da tetikleyebilir çünkü yorum eklemek bildirimleri tetikler ve kullanıcıları bildirimlerle spamlamak istemezsiniz.


 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; } }

Çözüm

GitHub eylemini açık uçlu ve entegrasyonlara açık tutmak istedim ve bu yüzden dilediğiniz modeli kullanabilirsiniz ( desteklenen modeller listesine bakın) veya desteklenen temel modeller üzerine kendi özel modelinizi ince ayar yapıp oluşturabilir ve bu GitHub eylemiyle birlikte kullanabilirsiniz.


Herhangi bir token sorunu veya oran sınırlamasıyla karşılaşırsanız, ilgili platformun belgelerine başvurarak model sınırlarınızı yükseltmek isteyebilirsiniz.


Peki, daha ne bekliyorsunuz? Github'da deponuz varsa, eylemi şimdi deneyin - Github Action Marketplace'te .