La segunda cuestión es que podemos hacerlo mejor. Estoy feliz de que ahora vivamos en una época en la que los programadores escriben sus propias pruebas, pero no cumplimos con los mismos estándares con las pruebas que con el código de producción. Ésa es una compensación razonable; el día tiene un número limitado de horas. Pero lo que les falta a los LLM en destreza aritmética, lo compensan con entusiasmo.

Pidamos una prueba aún mejor.

En las pruebas, implemente la versión más simple y legible del código estándar para cuartiles sobre un conjunto fijo de valores conocidos en un segmento. Luego pase los casos de prueba a través del código estándar y el muestreador de yacimiento y confirme que estén dentro de un épsilon de diferencia entre sí. Estructura el código de comparación de manera que también pueda usarse en una prueba difusa.

Esto nos consiguió un nuevo código de prueba:

// referenceQuartiles calculates the exact quartiles for a slice of float64 values  
// using linear interpolation, matching the behavior expected from the sampler.  
func referenceQuartiles(data ()float64) (q1, median, q3 float64) { … }

// compareQuartiles checks if two sets of quartiles are within epsilon of each other.  
// Returns true if they match within the tolerance, false otherwise.  
func compareQuartiles(q1a, meda, q3a, q1b, medb, q3b, epsilon float64) bool { … }

// checkQuartiles is a test helper that compares sampler output against the reference  
// implementation and reports any differences.  
func checkQuartiles(t *testing.T, data ()float64, epsilon float64) {  
   t.Helper()  
    
   // Get reference values  
   wantQ1, wantMed, wantQ3 := referenceQuartiles(data)  
    
   // Get sampler values using a large reservoir for accuracy  
   qs := NewQuartileSampler(1000)  
   for _, v := range data {  
       qs.Add(v)  
   }  
   gotQ1, gotMed, gotQ3 := qs.Quartiles()  
    
   if !compareQuartiles(gotQ1, gotMed, gotQ3, wantQ1, wantMed, wantQ3, epsilon) {  
       t.Errorf("Quartiles mismatch:\ngot  (q1=%v, med=%v, q3=%v)\nwant (q1=%v, med=%v, q3=%v)\nepsilon=%v",  
           gotQ1, gotMed, gotQ3, wantQ1, wantMed, wantQ3, epsilon)  
   }  
}

La prueba original anterior se modificó para usar checkQuartiles y tenemos algo nuevo:

func FuzzQuartileSampler(f *testing.F) {  
   // Add some seed corpus  
   f.Add(()float64{1, 2, 3, 4, 5})  
    
   f.Fuzz(func(t *testing.T, data ()float64) {  
       // Use a larger epsilon for fuzzing since we might get more extreme values  
       checkQuartiles(t, data, 0.2)  
   })  
}

Esto es divertido porque está mal. mi carrera gopls La herramienta dice inmediatamente:

fuzzing arguments can only have the following types:
    string, bool, float32, float64,
    int, int8, int16, int32, int64,
    uint, uint8, uint16, uint32, uint64,
    ()byte

Al pegar ese error nuevamente en el LLM, se regenera la prueba difusa de modo que se construya alrededor de un func(t *testing.T, data ()byte) función que utiliza math.Float64frombits para extraer flotadores del segmento de datos. Interacciones como esta nos apuntan hacia la automatización de la retroalimentación de las herramientas; todo lo que necesitaba era el mensaje de error obvio para lograr un progreso sólido hacia algo útil. No era necesario.

Hacer una encuesta rápida de las últimas semanas de mi historial de chat de LLM muestra (lo cual, como mencioné anteriormente, no es un análisis cuantitativo adecuado de ninguna manera) que más del 80 por ciento de las veces hay un error de herramientas, el LLM puede hacer progresos útiles sin que yo agregue ninguna idea. Aproximadamente la mitad de las veces, puede resolver completamente el problema sin que yo diga nada importante. Sólo estoy actuando como mensajero.

Source link