fix(umind): el agente se quedaba sin rondas buscando y nunca llegaba a responder
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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
97e66b82e3
commit
cdfbff605e
@@ -290,8 +290,20 @@ func ProcessWidgetMessage(agente *models.UmindAgente, sessionID, userText string
|
||||
// ronda, "se agotaron las rondas" no dice dónde mirar.
|
||||
var herramientasPedidas []string
|
||||
|
||||
for round := 0; round < 3; round++ {
|
||||
aiMsg, tokens, err := callAI(&ai, messages, tools)
|
||||
// La última vuelta se llama SIN herramientas. Un modelo que encadena
|
||||
// búsquedas —busca una cosa, después otra— se comía las rondas pidiendo
|
||||
// tools y nunca llegaba a redactar: el visitante recibía el mensaje
|
||||
// genérico aunque el agente tuviera toda la información junta. Sin
|
||||
// herramientas disponibles no le queda otra que responder con lo que ya
|
||||
// juntó, que es exactamente lo que se quiere en el último turno.
|
||||
const maxRondas = 4
|
||||
|
||||
for round := 0; round < maxRondas; round++ {
|
||||
disponibles := tools
|
||||
if round == maxRondas-1 {
|
||||
disponibles = nil
|
||||
}
|
||||
aiMsg, tokens, err := callAI(&ai, messages, disponibles)
|
||||
if err != nil {
|
||||
log.Printf("[UMIND] Error llamando AI (agente %d) round %d: %v", agente.ID, round, err)
|
||||
models.RegistrarEventoUmind(agente.ID, "error", "ai", fmt.Sprintf("Error contactando el AI (ronda %d)", round), err.Error())
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user