Er març qu'èi escrit sus per qué auem botat un agent d'IA en WhatsApp entà Lueira: er apòsta de produit que ua escòla d'espòrts de montanha non aurie de pèrder ua resèrva sonque pr'amor que son es onze dera net d'un dimars e non i a arrés ath taulèr. Aqueth article parlaue deth perqué: era recèrca de clients, era tria de canau, era question dera fisança. Aguest parle deth cossí, e ei era part que vertadèraments me trè eth sòm: hèr qu'un modèl de lengatge compde disponibilitat reau, cree ua resèrva reau e envie un ligam de pagament reau, sense apressar-lo ara logica atomica d'instructor-mès-material-mès-franja orària qu'auem bastit entath motor de resèrves en junh de 2023. Er agent avie de vier un client nau d'aqueth motor, non ua nauèra font de vertat.
1. Balhar ath modèl un conjunt petit d'aisines, non via liura
Era prumèra decision, e era que condicione tot çò que vien après, ei arrefusar de deishar qu'eth modèl generi accions en tèxt liure e dempús analizar-les. Ei temptaire: eth modèl torne quauquarren coma "resèrva eth dimars a les 10 damb Marc entà dues personas" e escrius ua expression regulara entà convertir açò en ua escritura en basa de dades. Èi vist aguest patron en pro demòs entà saber exactament com falhe en produccion: dates ambigües, noms d'instructors inventadi, ids que non existissen, formats que se desvien cada còp que tòques eth prompt.
Çò que hèm en sòn lòc ei definir un conjunt petit e explicit de foncions qu'eth modèl pòt cridar —check_availability, create_booking, send_payment_link— cada ua damb un esquèma JSON estricte. Er unic trabalh deth modèl ei compréner çò que vò eth client en lengatge naturau e traduir-ac en ua cridada plan tipada a ua d'aguestes foncions. Non escriu SQL, non invente un id de franja, e non decidís pera sua compda qu'ua resèrva ei confirmada. Ua version simplificada der esquèma de create_booking a aguest aspècte:
{
"name": "create_booking",
"description": "Cree ua resèrva entà ua franja, instructor e material concrèts. Torne un id de resèrva e un ligam de pagament, o un error de conflicte se era franja ja non ei disponibla.",
"parameters": {
"type": "object",
"properties": {
"school_id": { "type": "string" },
"activity_id": { "type": "string" },
"slot_id": {
"type": "string",
"description": "Identificador opac tornat per check_availability. Eth modèl non pòt inventar aguest valor."
},
"customer": {
"type": "object",
"properties": {
"name": { "type": "string" },
"phone": { "type": "string" },
"email": { "type": "string" }
},
"required": ["name", "phone"]
},
"party_size": { "type": "integer", "minimum": 1 }
},
"required": ["school_id", "activity_id", "slot_id", "customer", "party_size"]
}
}
Guarda eth camp slot_id. Ei un identificador opac que sonque existís pr'amor que check_availability lo tornèc moments abans: eth modèl non ne pòt bastir un deth non-arren, e non pòt convertir en silenci "les 10 deth dimars" en ua franja sense qu'i age pel miei ua consulta de disponibilitat reau. Aguesta soleta decision de disseny elimine tota ua categoria de resèrves alucinades abans quitament d'arribar ara validacion.
2. Er agent non se pòt sautar era coa
Auer ua cridada a aisina tipada non vò díder que i fisem. Eth modèl pòt èster extremadament segur e totun s'equivocar: sus quin instructor ei vertadèraments liure, sus se eth material contunhe en estòc, sus se quauquarrés a resèrvat era madeisha franja hè quate segondes en un aute hiu de WhatsApp diferent. Atau, cada cridada qu'eth modèl prepause passe exactament pera madeisha logica de validacion e transaccion qu'ua resèrva normau hèta dès era web: era madeisha compdada atomica d'instructor, material e franja amassa que descriuérem en dissenhar eth motor de resèrves. Er LLM prepause; eth motor disposa.
En còdi, aguesta frontèra se vei mès o mens atau:
func handleCreateBooking(ctx context.Context, call ToolCall) (ToolResult, error) {
var args CreateBookingArgs
if err := json.Unmarshal(call.Arguments, &args); err != nil {
return ToolResult{}, fmt.Errorf("invalid arguments from model: %w", err)
}
// Eth trabalh deth modèl s'acabe ací. A compdar d'aguest punt, era
// madeisha transaccion atomica de compdar-e-resèrvar qu'emplegue
// eth flux de resèrva web ei era soleta causa que pòt tocar er
// estat des resèrves.
booking, err := bookingEngine.CreateBooking(ctx, CreateBookingInput{
SlotID: args.SlotID,
Customer: args.Customer,
PartySize: args.PartySize,
})
if errors.Is(err, ErrSlotNoLongerAvailable) {
return ToolResult{
Content: "Aguesta franja ja non ei disponibla.",
Retryable: true,
}, nil
}
if err != nil {
return ToolResult{}, err
}
return ToolResult{
BookingID: booking.ID,
PaymentLink: booking.PaymentLink,
}, nil
}
Eth comentari d'aguest handler resumís tota era filosofia deth projècte: a compdar deth moment qu'eth modèl liure ua cridada estructurada, demore fòra deth cicle. Arren de çò que ditz ei pro fisable entà tocar er estat des resèrves dirèctament. Se açò semble fòrça ceremonia entà çò que semble un chatbot, ac ei, pr'amor qu'eth chatbot non ei çò qu'importe. Era resèrva sí.
3. Quan era franja desapareish a mieja conversacion
Coma revalidem tot, tanben auem de gerir eth cas qu'ensajàvem d'evitar: era franja qu'eth modèl prepausèc hè cinc segondes a desapareishut quan create_booking s'executa de vertat. Quauquarrés l'a presa dès era aplicacion, o ua auta conversacion de WhatsApp s'a avançat ad aguesta. En ua integracion ingenua açò torne coma un error, e un error en ua interfàcia de chat ei un carrèr sense gessida: eth client sonque ve "quauquarren a anat mau" e a de tornar a començar, normaument enfadant-se e trucant dirèctament ara escòla, çò que trè tot eth sens d'auer bastit açò.
Atau, eth resultat dera aisina create_booking non ei sonque exit o fracàs: pòrte pro estructura entà qu'er agent se recupèri damb elegància. Quan eth motor de resèrves torne un conflicte, era responsa dera aisina ditz ath modèl qu'era franja ja non ei disponibla e li torne ua nauèra cridada a check_availability damb es madeishi paramètres. Eth messatge següent deth modèl entath client se genère alavetz a partir de dades reaus e actuaus —"aquera franja des 10 damb Marc s'a justament ocupat, mès a liures es 11:30 e es 15:00 uei"— en lòc d'ua desencusa generica. Eth client jamès ve eth reïntent; sonque ve un agent que semble saber çò que se passe en temps reau. Aguest compòrtament non ei eth modèl estant intelligent. Ei eth resultat dirècte de balhar-li ua fallada estructurada sus era quau pòt actuar, en lòc d'ua traça d'error sus era quau non pòt.
4. Conversacions que sobreviuen a un trauc de tres òres
Er auta causa que trinque es agents de qualitat demo en produccion ei supausar qu'ua conversacion ei un solet cicle de peticion-responsa, coma ua session web. WhatsApp non fonccione atau. Un client pòt preguntar per disponibilitat a les 9 deth maitin, distréner-se, e respóner ath miejorn dès un aute telefòn après cambiar de dispositiu. Dès eth punt de vista deth modèl, açò a de semblar ua conversacion contunha, quitament se arren en transpòrt garantís aguesta continuitat.
Ena practica açò vò díder qu'er estat qu'er agent a besonh —çò qu'eth client ja a preguntat, quina franja se discutec era darrèra viatge, se un ligam de pagament ei encara pendent— non pòt víuer en memòria estacada a un solet procès que gerís un messatge. A de reconstruir-se a partir d'un istoric de conversacion persistent, indexat pera identitat de WhatsApp deth client, non per cap session concreta. Cada còp qu'arribe un messatge, reconstruïm pro contèxte entà qu'eth modèl repreni exactament a on es causes èren demoradas, incluent quin ei vertadèraments er estat deth motor de resèrves ara madeish, non çò qu'auie hè tres òres. Aguest darrèr detalh importe mès de çò que semble: se balhàvem ath modèl ua fotografia de disponibilitat de hè tres òres, tornaríem exactament a fisar-mos d'informacion vielha, justament çò que decidírem de non hèr. Era conversacion ei recuperabla; era disponibilitat que i a laguens non ei quauquarren que cachem e reemplegam: se torne a compdar, cada còp, contra eth motor en viu.
Arren d'açò hè mès intelligent er agent. Se de cas, tot eth disseny ei un exercici entà assegurar-se que non ac age de besonh d'èster. Er unica contribucion deth modèl ei convertir "pòdi resèrvar ua classa damb Marc eth pròche dimars ath maitin" en ua pregunta estructurada qu'eth motor de resèrves ja sap respóner de manèra segura. Tot çò que vertadèraments mòu sòs o retien ua plaça contunhe passant pes madeishes garanties qu'auem bastit entath flux web. Aguest èra er objectiu dès eth principi: er agent ei ua manèra nauva de parlar damb Lueira, non ua manèra nauva d'esquivar-lo.
