Bir kod inceleme promptu modele neye bakacağını, her bulgunun ne kadar ciddi olduğunu ve hangi kanıtı vereceğini söylemeli. "Bu kodu incele" bir güvenlik açığının bir docstring önerisiyle bir adlandırma tercihi arasında durduğu dost canlısı bir öneri listesi getirir. Kontrol listesi, önem dereceleri ve diff isteği olan bir inceleme promptu ise bulgu bulgu üzerine harekete geçebileceğin bir rapor getirir.
"Bunu incele"den önem dereceli bir kontrol listesine
İki sekmedeki kodda da iki gerçek hata var. Her yanıtın onları nasıl sunduğunu karşılaştır.
def get_user(conn, username):
cur = conn.cursor()
cur.execute(f"SELECT id, email FROM users WHERE name = '{username}'")
row = cur.fetchone()
return {"id": row[0], "email": row[1]}Genel olarak fonksiyon kısa ve takip etmesi kolay. Birkaç öneri:
- Tip ipuçları ekle, örneğin
username: str, imzayı daha net yapar. - Bir docstring ekle, fonksiyonun ne döndürdüğünü açıklasın.
- Parametreli sorgular kullan. SQL'i f-string'lerle kurmak SQL injection'a yol açabilir.
- Eksik kullanıcıları ele al.
fetchone()Nonedöndürebilir. - Adlandırma:
fetch_userveritabanı erişimini daha iyi anlatabilir.
İlk yanıt iki hatayı da buldu ve bir incelemeyi neden bahsettiklerine göre değerlendirmenin sorunu da bu. Injection beşli bir listenin üçüncü sırasında, "yol açabilir" diye yumuşatılmış, düzeltmesi olmadan, bir docstring önerisinin yanında duruyor. Göz gezdiren bir okur tip ipuçlarını ekleyip devam ederdi.
İkinci prompt dört şeyi değiştirdi:
- Kapsam. "Sadece hatalar, güvenlik ve hata yönetimi. Üslubu atla" gürültüyü kaldırır. Üslup, daha hızlı olan ve kendisiyle hiç çelişmeyen bir linter'ın ve formatter'ın işidir.
- Önem derecesi. Modeli sıralama yapmaya zorlar ve sıralı bir liste nereden başlayacağını söyler.
- Tetikleyen bir girdi. "
x' OR '1'='1" belirsiz bir riski çalıştırabileceğin bir gösterime çevirir. Son bölümde görüleceği gibi, yanlış alarmlara karşı en iyi filtren de budur. - Diff'ler. Bulgu başına küçük bir diff tek başına uygulanabilir ya da reddedilebilir. Yeniden yazılmış bir fonksiyon her düzeltmeyi kimsenin istemediği değişikliklerle karıştırır.
"Bir önem seviyesinde bir şey yoksa bir şey uydurma" göründüğünden daha önemlidir. Bir inceleme istendiğinde model, bulunacak pek bir şey olmasa bile bulgu üretmeye eğilimlidir ve en zayıfları listeyi şişirir. Bir seviyede hiçbir şey bildirmeme konusunda açık izin bu şişkinliği keser.
İnceleyicinin ihtiyaç duyduğu bağlam
Bir insan inceleyici kodun ne için olduğunu ve girdilerinin nereden geldiğini bilir. Model sadece senin yapıştırdığını bilir. "username doğrudan bir giriş formundan geliyor", SQL injection'ı teorik bir bulgu olmaktan çıkarıp yüksek önem dereceli bir bulgu yapan cümledir. Bir inceleme için faydalı bağlam:
- Girdilerin nereden geldiği: kullanıcılar, başka bir iç servis, senin kontrol ettiğin bir yapılandırma dosyası.
- Kodu neyin çağırdığı ve geri ne beklediği.
- Çalışma ortamı: dil sürümü, framework, veritabanı sürücüsü. Yukarıdaki injection düzeltmesi
?kullanıyor, çünkü sqlite3 bu yer tutucuyu kullanır; bazı başka sürücüler%skullanır. - Bu değişiklikte en çok neyi önemsediğin: doğruluk, güvenlik, performans ya da üçü birden.
Tekrar kullanılabilir bir inceleme promptu
Bu blok kontrol listesini bir şablona çeviriyor. Dili, odağı ve kodu değiştir, kuralları koru. Kısıtlar parçasını kapatmak, onsuz ne kadar gürültü geldiğini görmenin hızlı bir yoludur.
async function loadAll(ids) {
const results = [];
ids.forEach(async (id) => {
const res = await fetch(`/api/items/${id}`);
results.push(await res.json());
});
return results;
}1. Yüksek: fonksiyon herhangi bir istek bitmeden dönüyor (3. satır)
forEach async callback'leri beklemez. loadAll boş results dizisini hemen döndürür ve push işlemleri daha sonra olur. Her çağıran [] alır.
2. Orta: başarısız istekler veri gibi işleniyor (5. satır)
404 ya da 500 yanıtı fetch içinde bir exception değildir. JSON bir hata gövdesi ayrıştırılır ve bir öğeymiş gibi eklenir; JSON olmayan bir gövde ise res.json()'ın kimsenin beklemediği bir callback içinde hata fırlatmasına yol açar.
İkisi için de düzeltme; sonuçları ids ile aynı sırada da tutuyor:
async function loadAll(ids) {
- const results = [];
- ids.forEach(async (id) => {
- const res = await fetch(`/api/items/${id}`);
- results.push(await res.json());
- });
- return results;
+ return Promise.all(
+ ids.map(async (id) => {
+ const res = await fetch(`/api/items/${id}`);
+ if (!res.ok) throw new Error(`Item ${id}: HTTP ${res.status}`);
+ return res.json();
+ })
+ );
}
Rol satırı bir standart koyuyor ("gerçek sorunlar, başka hiçbir şey değil"); rol verme en çok burada işe yarar. İncelemeyi bir program okuyacaksa, örneğin bulguları bir pull request'e yorum olarak gönderen bir script, düzyazı yerine sabit alanları olan JSON iste; nasıl yapılacağını yapılandırılmış çıktı gösteriyor.
Yanlış alarmlarla başa çıkmak
Bazı bulgular yanlış olacaktır. Model girdiyi doğrulayan çağıranı, bir durumu imkânsız kılan veritabanı kısıtını ya da tuhaf görünen bir satırın neden bilerek öyle yazıldığını göremez. Bir kütüphanenin nasıl davrandığı konusunda da yanılabilir; kendinden emin bir iddianın neden kontrol edilmiş bir iddia olmadığını yapay zekâ halüsinasyonu açıklıyor.
Her bulguyu tetikleyen girdisiyle test et. Sisteminde soruna ulaşan bir girdi üretemiyorsan düzeltmeyi kabul etmek yerine eksik bağlamla itiraz et:
function formatPrice(cents) {
return `$${(cents / 100).toFixed(2)}`;
}
Sadece `renderCart` tarafından çağrılıyor ve o da `Number.isInteger(cents)` doğru olmadıkça erkenden dönüyor. Bu hâlâ bir sorun mu? Değilse bulguyu geri çek.O kontrol yerindeyken hayır: formatPrice her zaman bir tam sayı alıyor, yani bulgu geçerli değil ve onu geri çekiyorum.
Kontrolün kapsamadığı bir şey var: negatif tam sayılar Number.isInteger kontrolünden geçer ve formatPrice(-500) "$-5.00" döndürür. İadeler ya da indirimler bu fonksiyona ulaşabiliyorsa onun yerine "-$5.00" isteyebilirsin. Ulaşamıyorsa değiştirilecek bir şey yok.
Kendisine yeni kanıt gösterilen bir model ya bulguyu geri çekmeli ya da o kanıt göz önündeyken bulgunun neden hâlâ geçerli olduğunu açıklamalıdır. İkisi de faydalıdır. Her itiraza sadece katılan bir model inceleme yapmıyordur, bu yüzden yanıtı katılıp katılmadığına göre değil, gerekçelerine göre değerlendir. Modelin kendi yazdığı kod için incelemeyi yeni bir sohbette yap, böylece inceleme kodu üreten aynı akıl yürütmenin gözüyle okunmaz. Kapsam, bağlam ve test alışkanlıkları kodu en baştan daha iyi yapar; bkz. kod yazma promptları.
Sıkça Sorulan Sorular
Kod inceleme için iyi bir prompt nedir?
Neye bakılacağını söyle (hatalar, güvenlik, hata yönetimi), her bulgu için bir önem derecesi iste ve sorunu tetikleyen somut bir girdiyle onu düzelten bir diff talep et. Modele istenmedikçe biçimlendirme ve adlandırmayı atlamasını söyle. Ona bir insan inceleyicinin sahip olacağı bağlamı ver: kodun ne için olduğu ve onu neyin çağırdığı.
Yapay zekâ insan kod incelemesinin yerini alabilir mi?
Hayır, ama faydalı bir ilk turdur. Hızlıdır ve ele alınmamış None, eksik await'ler ve string'lerden kurulan SQL gibi yaygın hata kalıplarında iyidir. Ürününün kurallarını, kod tabanının geri kalanını ya da bir kararın neden verildiğini bilmez ve bulgularının bir kısmı yanlış olur. Onu insan incelemesinin yerine değil, öncesinde kullan.
Yapay zekâ kod incelemesi neden gerçek olmayan sorunlar bildiriyor?
Model sadece yapıştırdığın kodu görür. Bir değer çağıran tarafından doğrulanıyorsa ya da bir durum senin sisteminde hiç gerçekleşemiyorsa model bunu bilemez, bu yüzden riski yine de işaretler. Somut bir hatalı girdi istemek bunların çoğunu eler: onu tetikleyen gerçekçi bir girdisi olmayan bir bulgu genellikle yanlış alarmdır.
İnceleme sırasında yapay zekâdan kodumu yeniden yazmasını istemeli miyim?
Yeniden yazılmış bir dosya yerine her bulgu için bir tane olmak üzere küçük diff'ler iste. Tam bir yeniden yazım düzeltmeleri kimsenin istemediği değişikliklerle karıştırır ve yeniden yazımı da incelemen gerekir. Diff'ler her bulguyu tek başına kabul etmeni ya da reddetmeni sağlar.