Recepcionista con IA para clínicas dentales con Claude

Cómo construir una recepcionista con IA para clínicas dentales con Claude y ElevenLabs
Las clínicas dentales no pierden pacientes por mal marketing.
Los pierden porque nadie contesta al teléfono.
Una llamada perdida durante un empaste. Un buzón de voz que nadie revisa hasta el lunes. Un paciente que quería reservar una limpieza se cansó de esperar en espera y llamó a la clínica de al lado en su lugar.
Si estás:
- construyendo agentes de IA para salud,
- integrando IA de voz con sistemas de negocio ya existentes,
- o explorando qué puede hacer realmente un LLM más allá del chat,
esta es una construcción concreta que vale la pena entender.
La recepción es el cuello de botella
La mayoría de las clínicas funcionan con la misma configuración. Uno o dos recepcionistas. Teléfonos sonando durante el horario de pacientes. Nada después de las 18:00 ni los fines de semana.
El resultado es predecible:
- Las llamadas en horas punta van al buzón de voz
- Las llamadas fuera de horario no van a ningún sitio
- Las preguntas de seguros se acumulan para un personal que ya está ocupado reservando citas
Los desarrolladores lo descubren demasiado tarde — después de que el dueño de una clínica diga "sé que estamos perdiendo pacientes, simplemente no sé cuántos".
Ya existe un mercado de herramientas que intentan arreglar esto. Arini, Weave, Adit, Goodcall — todas plataformas SaaS que cobran entre 49 $ y más de 800 $ al mes por un agente de voz de caja cerrada.
El problema real no es la calidad de la voz
Todos los proveedores afirman que su IA "suena natural" y "responde 24/7".
Eso ya no es el diferenciador.
El problema real es que la mayoría de estas plataformas son sistemas cerrados. No puedes tocar la lógica de reservas. No puedes personalizar qué pasa cuando un paciente pregunta algo fuera del guion. Y la función que de verdad importa — si la IA escribe directamente en el calendario de la consulta o solo deja una nota para el personal — varía muchísimo entre proveedores.
Constrúyelo tú mismo, y controlas tanto la lógica como el flujo de datos.
La solución: Claude como cerebro, ElevenLabs como capa de voz
Una recepcionista con IA tiene tres capas, y cada una hace un trabajo distinto:
- Orquestación de voz (ElevenLabs Conversational AI) — gestiona la llamada en sí: voz a texto, texto a voz de baja latencia, telefonía, y gestión de interrupciones
- Razonamiento + decisiones (Claude, vía function calling) — decide qué necesita quien llama y qué acción tomar
- Escritura en el sistema de gestión de la consulta (PMS) — la capa de API que realmente reserva, reprograma, o marca una llamada para el personal
ElevenLabs existe porque construir un pipeline de voz de baja latencia desde cero es un proyecto en sí mismo. Su plataforma Conversational AI gestiona el puente de telefonía, la transcripción en streaming y la síntesis de voz — incluyendo voces de sonido natural y baja latencia que son notablemente más difíciles de distinguir de una recepcionista humana que la mayoría de las alternativas del mercado. Conectas tu propia capa de razonamiento a través de su webhook de tool-calling para agentes.
Claude es la parte que decide qué hacer, usando las herramientas que tú definas.
¿Construyendo un producto de IA de voz? Empieza aquí.
El stack Conversational AI de ElevenLabs es la forma más rápida de lanzar agentes de voz de sonido natural y baja latencia sin construir tu propio pipeline de TTS/STT.
→ Prueba ElevenLabs
Implementación
El flujo de la llamada, con un presupuesto de latencia
Patient speaks → Twilio/PSTN → ElevenLabs Conversational AI (streaming STT)
↓ (~150-300ms)
your webhook (FastAPI/Node)
↓
Claude API (function calling)
↓
tool execution against the PMS
↓
text back → ElevenLabs (streaming TTS)
↓
Patient hears the response
La latencia total tiene que quedarse por debajo de aproximadamente 1,5 segundos o la conversación se siente rota. ElevenLabs ya gestiona STT+TTS con streaming, y sus modelos de voz de baja latencia están construidos específicamente para recortar milisegundos de ese tramo del pipeline. Eso deja 800ms-1s para tu webhook, la llamada a Claude, y la llamada al PMS. Es ajustado.
1. Define las herramientas que Claude puede llamar
tools = [
{
"name": "check_availability",
"description": "Check open appointment slots for a given date range and treatment type",
"input_schema": {
"type": "object",
"properties": {
"date_range": {"type": "string"},
"treatment_type": {"type": "string"}
},
"required": ["date_range", "treatment_type"]
}
},
{
"name": "book_appointment",
"description": "Book a confirmed appointment slot into the PMS calendar",
"input_schema": {
"type": "object",
"properties": {
"patient_name": {"type": "string"},
"slot_id": {"type": "string"},
"treatment_type": {"type": "string"}
},
"required": ["patient_name", "slot_id", "treatment_type"]
}
},
{
"name": "escalate_to_human",
"description": "Flag the call for staff follow-up when the request is outside scope",
"input_schema": {
"type": "object",
"properties": {"reason": {"type": "string"}},
"required": ["reason"]
}
}
]
2. El webhook — donde vive la lógica real
El agente Conversational AI de ElevenLabs envía una petición a tu webhook cada vez que el paciente termina un turno de conversación. Un esqueleto real en FastAPI:
from fastapi import FastAPI, Request
import anthropic
app = FastAPI()
client = anthropic.Anthropic()
# In-memory call state (use Redis once you scale past one instance)
call_sessions = {}
@app.post("/webhook/elevenlabs")
async def handle_call_turn(request: Request):
payload = await request.json()
call_id = payload["conversation_id"]
user_text = payload["message"]["content"]
session = call_sessions.setdefault(call_id, {"messages": []})
session["messages"].append({"role": "user", "content": user_text})
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=512,
system=SYSTEM_PROMPT,
tools=tools,
messages=session["messages"]
)
final_text = ""
for block in response.content:
if block.type == "text":
final_text += block.text
elif block.type == "tool_use":
result = execute_tool(block.name, block.input)
session["pending_tool_result"] = {
"tool_use_id": block.id,
"content": result
}
session["messages"].append({"role": "assistant", "content": response.content})
return {"response": final_text or "One moment, please."}
Aquí está la parte que casi todo el mundo se salta: cuando Claude devuelve un bloque tool_use, tienes que ejecutar esa herramienta y devolver el resultado como un mensaje tool_result en la siguiente llamada a la API, antes de que Claude pueda generar el texto que el paciente realmente escucha.
Eso significa que algunos turnos necesitan dos idas y vueltas a Claude — una para decidir qué herramienta llamar, otra para generar la respuesta hablada una vez tiene el resultado.
if session.get("pending_tool_result"):
session["messages"].append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": session["pending_tool_result"]["tool_use_id"],
"content": session["pending_tool_result"]["content"]
}]
})
final_response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=512,
system=SYSTEM_PROMPT,
tools=tools,
messages=session["messages"]
)
final_text = final_response.content[0].text
Dos idas y vueltas añaden latencia. Mantén max_tokens bajo (512, no 1024+) y haz streaming de la respuesta de Claude para que el TTS de ElevenLabs pueda empezar a hablar antes de que el texto completo esté listo.
3. Integración con el PMS — donde está el trabajo real
Esto es el 80% de la ingeniería real, no el prompt. Cada PMS expone algo distinto:
- Open Dental: su propia REST API, requiere una API key por clínica y su propio esquema de autenticación
- Dentrix Ascend: una API más cerrada, normalmente requiere estatus de partner certificado
- Cloud9: REST API, pero con límites de uso agresivos
execute_tool no es solo "llamar a una API limpia". Tiene que gestionar conflictos:
def execute_tool(name, input_data):
if name == "check_availability":
slots = pms_client.get_open_slots(
date_range=input_data["date_range"],
treatment_type=input_data["treatment_type"]
)
return format_slots_for_claude(slots) # readable text, not raw JSON
elif name == "book_appointment":
try:
confirmation = pms_client.create_appointment(...)
return f"Confirmed: {confirmation.id}"
except PMSConflictError:
return "That slot is no longer available, offer another one"
elif name == "escalate_to_human":
create_staff_ticket(input_data["reason"], session_transcript)
return "Escalated to staff"
La gestión de PMSConflictError importa. Los huecos pueden desaparecer entre el momento en que Claude comprueba disponibilidad y el momento en que confirma. Sin esa comprobación, el paciente se queda con una confirmación falsa.
4. Estado entre turnos
Un diccionario en memoria solo funciona para una única instancia. Los despliegues reales en producción necesitan varias instancias, lo que significa que call_sessions tiene que vivir en Redis (o similar), indexado por el conversation_id que te envía ElevenLabs, con un TTL corto — la llamada dura minutos, no días.
5. Lo que de verdad se rompe en la práctica
Interrupciones: si el paciente habla mientras Claude está generando una respuesta, el agente de ElevenLabs dispara un evento de interrupción. Tu webhook necesita cancelar la generación en curso, no encolarla.
Disponibilidad alucinada: nunca dejes que Claude "adivine" un horario. check_availability siempre tiene que ser la fuente de verdad, y el system prompt debería prohibir explícitamente confirmar una reserva sin llamarlo antes.
Fallback de voz: si Claude tarda más de ~2 segundos, configura una respuesta de relleno en el agente de ElevenLabs ("un momento, por favor") o el paciente cuelga.
Punto de control de cumplimiento antes de salir a producción:
- Cifra la capa de transporte de extremo a extremo
- Redacta o evita guardar PHI (datos de salud del paciente) en los logs
- Consigue un acuerdo de tratamiento de datos firmado con cada proveedor de la cadena (ElevenLabs, API de Claude, proveedor del PMS)
En la UE esto se traduce en el RGPD más la normativa nacional de datos de salud en lugar de HIPAA, pero los requisitos son funcionalmente los mismos: cifrado, auditabilidad, y un acuerdo de tratamiento documentado con cada proveedor.
Una llamada real, paso a paso
Un paciente llama a las 21:00, fuera de horario.
Quiere reservar una limpieza y menciona que su seguro cambió. La primera llamada a herramienta de Claude comprueba disponibilidad para la semana solicitada. La segunda llamada escala la actualización del seguro, ya que eso necesita que un humano verifique la cobertura antes de confirmar nada financiero.
El paciente consigue un horario confirmado antes de colgar. La pregunta del seguro queda en la cola de mañana del personal en lugar de en un buzón de voz perdido.
Ese es todo el valor: nada se cae entre las 21:00 y las 9:00.
¿Listo para construir esto tú mismo?
El Conversational AI de ElevenLabs te da la capa de voz lista para telefonía (STT, TTS, telefonía, gestión de interrupciones) para que puedas centrarte en la lógica de Claude y la integración con el PMS en lugar del pipeline de audio.
→ Empieza con ElevenLabs
Si estás construyendo infraestructura como esta y quieres profundizar en cómo estructurar el tool use de LLM para sistemas en producción, no dudes en escribirme — escribo regularmente sobre este tipo de proyectos.
Ideas clave
- Ser dueño del stack (Claude + ElevenLabs) le gana a alquilar una plataforma SaaS cerrada cuando necesitas lógica personalizada o estás construyendo esto para varias clínicas
- La profundidad de la escritura en el PMS es el diferenciador real — una voz de sonido natural que solo deja una nota para el personal no resuelve el problema
- El multicanal (SMS + voz) importa más que la calidad de voz por sí sola, ya que una parte creciente de los pacientes prefiere escribir para peticiones no urgentes
Preguntas frecuentes
❓ ¿Puede Claude gestionar una llamada telefónica en tiempo real directamente?
✅ No. Claude procesa texto, no audio en crudo ni telefonía. Necesitas una capa de orquestación de voz como ElevenLabs Conversational AI en medio para gestionar voz a texto, texto a voz, y la conexión telefónica en sí. Claude solo gestiona el paso de razonamiento.
❓ ¿Esta configuración cumple con HIPAA de fábrica?
✅ No. Ninguno de los componentes (API de Claude, ElevenLabs, tu PMS) cumple con HIPAA por defecto solo por usarlos. Necesitas acuerdos de socio comercial firmados con cada proveedor, transporte cifrado, y redacción de PHI en tu logging antes de gestionar llamadas reales de pacientes.
❓ ¿Esto sustituye al personal de recepción?
✅ No, y no debería intentarlo. Absorbe las llamadas fuera de horario y el desbordamiento en horas punta — las llamadas que hoy van al buzón de voz. Los casos complejos (disputas de seguros, preguntas sobre planes de tratamiento) deberían seguir escalando a un humano.
❓ ¿Cuánto cuesta esto comparado con una plataforma SaaS como Weave o Arini?
✅ Pagas costes basados en uso (tokens de Claude + minutos de voz de ElevenLabs) en lugar de una cuota fija de 49-800 $/mes. Para volúmenes bajos de llamadas esto puede salir más barato; para volúmenes altos, haz los cálculos contra los niveles de precio actuales de ElevenLabs antes de comprometerte.
¿Quieres probar la capa de voz detrás de esta construcción?
→ Empieza con ElevenLabs¿Buscas más proyectos como este?
→ kevinmeneses.com
¿Buscas contenido técnico para tu empresa? Puedo ayudarte — LinkedIn · kevinmenesesgonzalez@gmail.com