Los eventos de producción mostraban "se agotaron las rondas" tres veces seguidas en un agente que respondía bien en el chat de prueba. La diferencia no era el widget: era la conversación. Un modelo que encadena búsquedas —busca una cosa, con eso busca otra— se comía las tres rondas pidiendo herramientas y el bucle terminaba sin que hubiera redactado nada, aunque para entonces ya tuviera toda la información junta. En el chat de prueba las consultas eran más cortas y no encadenaban, así que ahí nunca se veía. Ahora son cuatro rondas y, sobre todo, la última se llama SIN herramientas: sin nada que pedir, al modelo no le queda otra que responder con lo que juntó. Que es exactamente lo que se quiere en el último turno. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
58 lines
1.8 KiB
Go
58 lines
1.8 KiB
Go
package services
|
|
|
|
import "testing"
|
|
|
|
// El bucle de herramientas tiene que garantizar que la última vuelta sea sin
|
|
// herramientas. Si no, un modelo que encadena búsquedas se come todas las
|
|
// rondas pidiendo tools y nunca redacta: el visitante recibe el mensaje
|
|
// genérico aunque el agente ya tenga toda la información junta.
|
|
//
|
|
// Es exactamente lo que pasaba en producción: tres eventos seguidos de
|
|
// "se agotaron las rondas" en un agente que respondía bien en el chat de
|
|
// prueba, donde la conversación era más corta y no encadenaba búsquedas.
|
|
func TestLaUltimaRondaVaSinHerramientas(t *testing.T) {
|
|
const maxRondas = 4
|
|
|
|
hubo := 0
|
|
ultimaConHerramientas := false
|
|
|
|
for round := 0; round < maxRondas; round++ {
|
|
conHerramientas := round != maxRondas-1
|
|
hubo++
|
|
if round == maxRondas-1 {
|
|
ultimaConHerramientas = conHerramientas
|
|
}
|
|
}
|
|
|
|
if hubo != maxRondas {
|
|
t.Errorf("se corrieron %d rondas, esperaba %d", hubo, maxRondas)
|
|
}
|
|
if ultimaConHerramientas {
|
|
t.Error("la última ronda ofreció herramientas: el modelo puede volver a pedir una y quedarse sin responder")
|
|
}
|
|
if maxRondas < 3 {
|
|
t.Errorf("con %d rondas no alcanza para buscar y después redactar", maxRondas)
|
|
}
|
|
}
|
|
|
|
// Con la última ronda sin herramientas, un modelo que pide búsquedas en todas
|
|
// las vueltas igual termina respondiendo.
|
|
func TestUnModeloQuePideBusquedasSiempreIgualResponde(t *testing.T) {
|
|
const maxRondas = 4
|
|
respondio := false
|
|
|
|
for round := 0; round < maxRondas; round++ {
|
|
hayHerramientas := round != maxRondas-1
|
|
// El modelo simulado pide herramienta siempre que pueda.
|
|
pideHerramienta := hayHerramientas
|
|
if !pideHerramienta {
|
|
respondio = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !respondio {
|
|
t.Error("el bucle terminó sin respuesta: es el fallback genérico que ve el visitante")
|
|
}
|
|
}
|