Un agente React bien diseñado acelera el booking de citas médicas con precisión. Aquí verás cómo estructurar un nodo, definir sus tools, preparar un prompt con reglas claras y probarlo en standalone con LangGraph Studio. El enfoque combina razonamiento del language model con salidas de APIs formateadas en texto plano para una experiencia fluida.
¿Cómo se arma un agente React con tools y prompt?
La base es un nodo tipo React: un agente, sus tools y un system prompt. Se crea con create React Agent, pasando el modelo, el arreglo de tools y el prompt. El modelo se inyecta directo: no hace falta un init especial. El prompt guía pasos, reglas y variables como today para interpretar expresiones temporales relativas.
¿Qué estructura de archivos usa el nodo booking?
Estructura mínima ordenada por responsabilidad: un node, su prompt y sus tools.
booking/
__init__.py
node.py
prompt.py
tools.py
Un nodo por responsabilidad: extractor, conversation y booking.
Reutiliza tools existentes cuando convenga.
Mantén ejemplos de React separados para no afectar el booking real.
¿Cómo se carga el prompt con reglas y today?
El prompt define el rol: asistente que agenda citas médicas. Incluye today como variable calculada si no se envía. Añade pasos y reglas para reducir errores del agente.
system_prompt ="""
Eres un asistente que agenda citas médicas.
today: {today}
pasos:
1) obtener información del paciente.
2) obtener fecha y hora deseadas.
3) obtener información del doctor.
4) check de availability.
5) enviar sugerencias.
6) hacer booking.
reglas:
- usa book appointment solo si ya verificaste availability.
- no agendar a más de 30 días.
"""
El prompt sigue siendo fundamental, incluso con patrón React.
Los pasos guían el razonamiento y el orden de llamadas a tools.
Reglas explícitas: primero check de availability, luego book appointment.
¿Cómo se integran tools existentes como getweather y getproducts?
Se importan, se agrupan en un array y se pasan al agente. Sirven para validar la arquitectura React antes del booking real.
El agente formatea la salida de las tools y genera la respuesta final.
Ejemplo práctico: listó productos y categorizó por tipo de prenda de forma autónoma.
También combinó clima con catálogo y sugirió productos acordes a la temperatura.
¿Cómo se prueban el nodo y el agente en standalone?
El nodo booking se puede ejecutar en standalone: funciona como mini-nodo de LangGraph y como agente individual. Así se valida el flujo antes de integrarlo con extractor y conversation. En LangGraph Studio se inspeccionan llamadas a tools, state y mensajes del chat.
Respuesta inicial: saluda, confirma nombre del paciente y pide fecha, hora y doctor.
Entiende expresiones relativas: mañana, tarde, etc., gracias a today.
Secuencia observada: primero usa get appointment availability, luego hace booking appointment y confirma.
¿Qué habilidades técnicas se aplican en la implementación?
Diseño de nodos con patrón React: agente + tools + prompt.
Prompting con pasos, reglas y variables como today.
Reutilización e incorporación de tools externas.
Mocking de APIs para acelerar pruebas.
Control de errores en tools: devolver texto claro al modelo.
Formateo en texto plano: respuestas legibles para el language model.
Pruebas en standalone antes de integrar con routing y chain.
¿Qué herramientas de booking se definieron y qué parámetros aceptan?
Dos tools con foco en disponibilidad y reserva. Por ahora hacen mocking, listas para conectarse a tu API o calendario.
defbooking_appointment(fecha:str, tiempo:str, doctor:str, paciente:str)->str:# lógica real: validar, reservar y manejar erroresreturn(f"Cita confirmada: paciente {paciente}, doctor {doctor}, "f"fecha {fecha}, hora {tiempo}.")defget_appointment_availability(fecha:str, tiempo:str, doctor:str)->str:# lógica real: consultar agenda y formatear 'slots' útilesreturn(f"Disponibilidad para {doctor} en {fecha}{tiempo}: 14:00, 15:00, 16:00. ""Indica tu hora preferida.")
booking appointment: requiere fecha, tiempo, doctor y paciente.
get appointment availability: requiere fecha, tiempo y doctor.
Devuelven texto plano: fácil de interpretar y reformatear por el agente.
¿Cómo diseñar las tools de booking y el flujo de decisión?
El flujo se guía por el prompt template: primero recopilar datos, luego check de availability, sugerir horarios y finalmente reservar. Añade reglas como no agendar más de treinta días.
Diseña salidas en texto claro: el modelo debe poder decidir con esa información.
Si falla una tool: devuelve un mensaje de error en texto para que el agente lo comunique.
Integra después con routing para derivar entre extractor, conversation y booking.
¿Te gustaría comentar cómo conectar estas tools a tu API o calendario y qué validaciones agregarías?
Implementación de agente ReAct para booking de citas médicas
En los vídeos del curso se usaba una versión antigua de LangGraph que permitía exportar el agente creado con create_agent tal cual.
Desde la versión 0.2 (y la 0.3 de LangChain) eso ya no vale: el CLI sólo acepta un grafo compilado (StateGraph.compile()) o una función que lo devuelva.
Les comparto una prueba local, algo extensa pero funciona
importrequestsfrom langchain_core.toolsimporttoolfrom datetime import date asDate, datetime, timedelta
from zoneinfo importZoneInfofrom langchain_core.toolsimport tool
MX_TZ=ZoneInfo("America/Mexico_City")AFTERNOON_SLOTS=["15:00","16:00","17:00","18:00"]MAX_DAYS_AHEAD=30WEEKDAYS=["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]# Citas agendadas en memoria:(doctor, fecha, hora)-> paciente
_bookings: dict[tuple[str, str, str], str]={}# ----------Helpers internos ----------def _now()-> datetime:return datetime.now(MX_TZ)def _is_prime(n: int)-> bool:if n <2:returnFalsereturnall(n % i for i inrange(2,int(n**0.5)+1))def _is_open_day(d:Date)-> bool: # Lunes a viernes y día del mes primo
return d.weekday()<5 and _is_prime(d.day)def _parse_date(value: str)->Date:returnDate.fromisoformat(value.strip()) # YYYY-MM-DDdef _parse_time(value: str)-> str:return datetime.strptime(value.strip(),"%H:%M").strftime("%H:%M")def _key(doctor: str,d:Date,t: str)-> tuple[str, str, str]:return(doctor.strip().lower(), d.isoformat(), t)def _free_slots(doctor: str,d:Date)-> list[str]: now =_now() today = now.date()if not _is_open_day(d):return[]ifnot(today <= d <= today +timedelta(days=MAX_DAYS_AHEAD)):return[] slots =[]for t inAFTERNOON_SLOTS:if_key(doctor, d, t)in_bookings:continueif d == today and t <= now.strftime("%H:%M"):continue # ya pasó esa hora hoy
slots.append(t)return slots
def _upcoming(doctor: str,limit: int |None=None)-> list[tuple[Date, list[str]]]: today =_now().date() result =[]for i inrange(MAX_DAYS_AHEAD+1): d = today +timedelta(days=i) slots =_free_slots(doctor, d)ifslots: result.append((d, slots))if limit and len(result)>= limit:breakreturn result
def _fmt_day(d:Date,slots: list[str])-> str:return f"- {WEEKDAYS[d.weekday()]} {d.isoformat()}: {', '.join(slots)}"# ----------Tools----------@tool("get_appointment_availability", description=("Get the availability of a medical appointment for a doctor. ""Optionally filter by date (YYYY-MM-DD) and time (HH:MM, Mexico City time)."),)def get_appointment_availability(doctor: str,date: str |None=None,time: str |None=None)-> str:if not date: days =_upcoming(doctor)if not days:return f"There is no availability for {doctor} in the next {MAX_DAYS_AHEAD} days." lines ="\n".join(_fmt_day(d, s)for d, s in days)return f"The availability slots for {doctor} (Mexico City time) are:\n{lines}"try: d =_parse_date(date) except ValueError:return"Invalid date format. Use YYYY-MM-DD." slots =_free_slots(doctor, d)iftime:try: t =_parse_time(time) except ValueError:return"Invalid time format. Use HH:MM (24h)."if t inslots:return f"{doctor} is available on {d.isoformat()} at {t}."ifslots: prefix = f"{time} is not available. "if time else""return f"{prefix}Available slots for {doctor} on {d.isoformat()}: {', '.join(slots)}" alternatives ="\n".join(_fmt_day(x, s)for x, s in_upcoming(doctor, limit=3))return( f"{doctor} has no availability on {d.isoformat()}.\n" f"Next available days:\n{alternatives or '- None in the next 30 days'}")@tool("book_appointment", description="Book a medical appointment for a given date (YYYY-MM-DD), time (HH:MM), doctor and patient.",)def book_appointment(date: str,time: str,doctor: str,patient: str)-> str:try: d =_parse_date(date) t =_parse_time(time) except ValueError:return"Invalid date or time format. Use YYYY-MM-DD and HH:MM (24h)."if t not in_free_slots(doctor, d):return( f"The slot {d.isoformat()} at {t} with {doctor} is not available. ""Check availability with get_appointment_availability first.") _bookings[_key(doctor, d, t)]= patient
return f"Appointment booked for {d.isoformat()} at {t} with {doctor} for {patient}!"tools =[book_appointment, get_appointment_availability]