Existe la tentación de que "una tool por caso" es lo correcto: queda explícito, queda granular, queda "limpio". Pero el modelo no vive en tu mundo de arquitectura. vive en la decisión de qué invocar cuando el usuario dice algo. Y esa decisión empeora cuando hay demasiadas opciones similares.
Imaginá que sos el modelo. El usuario dice: "ponéme a Em de medic en el turno de la noche del 14".
Con 30 tools de roster que incluyen assign_crewmate, update_role_in_shift, add_crewmate_to_existing_shift, set_shift_crewmate_role, tenés que leer 30 descripciones y comparar. Las decisiones cercanas a 50/50 son las peores: el modelo elige una con baja confianza, y si elige la "incorrecta" (todas hacen casi lo mismo, pero con distinta DB), rompe.
Con 3 tools (create_shift, update_shift_assignment, set_shift_status), elegís rápido: necesitás update_shift_assignment con action: "assign" y role: "medic". Decisión clara.
Patrones que funcionan:
assign_x, remove_x, change_x, usá update_x con action: "assign"|"remove"|"change".create_day_shift, create_night_shift, usá create_shift con shift_type enum.list_active_shifts, list_cancelled_shifts, usá list_shifts(status?) con default "active".Patrones que NO funcionan:
command string: do_action(command: string, payload: any). el modelo no sabe qué meter en payload y se rinde. Necesitás los parámetros tipados.create_shift y cancel_shift tienen 0 parámetros en común, son tools distintas. No las fuerces a una.Cada tool nueva cuesta tokens en el system prompt y precision en la elección. Antes de agregar una, preguntate: ¿esto se merece su propio nombre y schema, o es un valor de enum de otra tool?