
How to use Agent Skils
Agent Skills are one of the highest-leverage ways to use LLMs. They provide the appropriate context for the task you want to accomplish in a repeatable manner.
Haz una foto a una estatua. Identifica las figuras representadas. Después, conversa con ellas en tiempo real: cada personaje habla con una voz distinta y acorde a su época.
Esto es lo que puedes crear con las APIs de Diseño de Voz y ElevenAgents de ElevenLabs. En este artículo, te mostramos la arquitectura de una app web móvil que combina visión por ordenador con generación de voz para convertir monumentos públicos en experiencias interactivas. Todo lo que ves aquí se puede replicar con las APIs y los ejemplos de código que encontrarás a continuación.
Toda la app que ves abajo se ha creado a partir de un único prompt, probado con éxito enCursor con Claude Opus 4.5 (alto) desde un proyecto NextJS vacío. Si quieres ir directo y crear la tuya, pega esto en tu editor:
| 1 | We need to make an app that: |
| 2 | - is optimised for mobile |
| 3 | - allows the user to take a picture (of a statue, picture, monument, etc) that includes one or more people |
| 4 | - uses an OpenAI LLM api call to identify the statue/monument/picture, characters within it, the location, and name |
| 5 | - allows the user to check it's correct, and then do either a deep research or a standard search to get information about the characters and the statue's history, and it's current location |
| 6 | - then create an ElevenLabs agent (allowing multiple voices), that the user can then talk to as though they're talking to the characters in the statue. Each character should use voice designer api to create a matching voice. |
| 7 | The purpose is to be fun and educational. |
| 8 | |
| 9 | https://elevenlabs.io/docs/eleven-api/guides/cookbooks/voices/voice-design |
| 10 | https://elevenlabs.io/docs/eleven-agents/quickstart |
| 11 | https://elevenlabs.io/docs/api-reference/agents/create |
También puedes usar las Habilidades de ElevenLabs Agent en vez de enlazar a la documentación. Están basadas en la documentación y pueden dar resultados aún mejores.
El resto del artículo explica en detalle lo que genera ese prompt.
El proceso tiene cinco fases:
Cuando un usuario fotografía una estatua, la imagen se envía a un modelo de OpenAI con capacidad de visión. Un prompt estructurado extrae el nombre de la obra, ubicación, artista, fecha y, lo más importante, una descripción detallada de la voz de cada personaje. El prompt incluye el formato JSON esperado como salida:
| 1 | { |
| 2 | "statueName": "string - name of the statue, monument, or artwork", |
| 3 | "location": "string - where it is located (city, country)", |
| 4 | "artist": "string - the creator of the artwork", |
| 5 | "year": "string - year completed or unveiled", |
| 6 | "description": "string - brief description of the artwork and its historical significance", |
| 7 | "characters": [ |
| 8 | { |
| 9 | "name": "string - character name", |
| 10 | "description": "string - who this person was and their historical significance", |
| 11 | "era": "string - time period they lived in", |
| 12 | "voiceDescription": "string - detailed voice description for Voice Design API (include audio quality marker, age, gender, vocal qualities, accent, pacing, and personality)" |
| 13 | } |
| 14 | ] |
| 15 | } |
| 1 | const response = await openai.chat.completions.create({ |
| 2 | model: "gpt-5.2", |
| 3 | response_format: { type: "json_object" }, |
| 4 | messages: [ |
| 5 | { role: "system", content: SYSTEM_PROMPT }, |
| 6 | { |
| 7 | role: "user", |
| 8 | content: [ |
| 9 | { |
| 10 | type: "text", |
| 11 | text: "Identify this statue/monument/artwork and all characters depicted.", |
| 12 | }, |
| 13 | { |
| 14 | type: "image_url", |
| 15 | image_url: { |
| 16 | url: `data:image/jpeg;base64,${base64Data}`, |
| 17 | detail: "high", |
| 18 | }, |
| 19 | }, |
| 20 | ], |
| 21 | }, |
| 22 | ], |
| 23 | max_completion_tokens: 2500, |
| 24 | }); |
Para una foto de la estatua de Boudica en Westminster Bridge, Londres, la respuesta sería así:
| 1 | { |
| 2 | "statueName": "Boudica and Her Daughters", |
| 3 | "location": "Westminster Bridge, London, UK", |
| 4 | "artist": "Thomas Thornycroft", |
| 5 | "year": "1902", |
| 6 | "description": "Bronze statue depicting Queen Boudica riding a war chariot with her two daughters, commemorating her uprising against Roman occupation of Britain.", |
| 7 | "characters": [ |
| 8 | { |
| 9 | "name": "Boudica", |
| 10 | "description": "Queen of the Iceni tribe who led an uprising against Roman occupation", |
| 11 | "era": "Ancient Britain, 60-61 AD", |
| 12 | "voiceDescription": "Perfect audio quality. A powerful woman in her 30s with a deep, resonant voice and a thick Celtic British accent. Her tone is commanding and fierce, with a booming quality that projects authority. She speaks at a measured, deliberate pace with passionate intensity." |
| 13 | }, |
| 14 | // Other characters in the statue |
| 15 | ] |
| 16 | } |
La calidad de la descripción de voz determina directamente la calidad de la voz generada. La guía de prompts de Diseño de Voz lo explica en detalle, pero los atributos clave son: marcador de calidad de audio ("Calidad de audio perfecta."), edad y género, tono/timbre (profundo, resonante, áspero), acento preciso ("acento británico celta marcado" en vez de solo "británico") y ritmo. Cuanto más descriptivo sea el prompt, más preciso será el resultado: "neoyorquina cansada de unos 60 años con sentido del humor seco" siempre será mejor que "voz femenina mayor".
Algunos consejos de la guía: usa "marcado" en vez de "fuerte" para describir la intensidad del acento, evita términos vagos como "extranjero" y, para personajes históricos o ficticios, puedes sugerir acentos reales como inspiración (por ejemplo, "una reina celta antigua con acento británico marcado, voz regia y autoritaria").
La API de Diseño de Voz genera voces sintéticas nuevas a partir de descripciones de texto, sin necesidad de muestras de voz ni clonación. Es ideal para personajes históricos donde no existe audio original.
El proceso tiene dos pasos.
| 1 | const { previews } = await elevenlabs.textToVoice.design({ |
| 2 | modelId: "eleven_multilingual_ttv_v2", |
| 3 | voiceDescription: character.voiceDescription, |
| 4 | text: sampleText, |
| 5 | }); |
El parámetro de texto es importante. Un texto de muestra más largo y adaptado al personaje (más de 50 palabras) da resultados más estables: ajusta el diálogo al personaje en vez de usar un saludo genérico. La guía de prompts de Diseño de Voz lo explica con más detalle.
Cuando tengas las previsualizaciones, elige una y crea una voz permanente:
| 1 | const voice = await elevenlabs.textToVoice.create({ |
| 2 | voiceName: `StatueScanner - ${character.name}`, |
| 3 | voiceDescription: character.voiceDescription, |
| 4 | generatedVoiceId: previews[0].generatedVoiceId, |
| 5 | }); |
En estatuas con varios personajes, la creación de voces se hace en paralelo. Las voces de cinco personajes se generan en casi el mismo tiempo que una sola:
| 1 | const results = await Promise.all( |
| 2 | characters.map((character) => createVoiceForCharacter(character)) |
| 3 | ); |
Con las voces creadas, el siguiente paso es configurar un Agente ElevenLabs capaz de cambiar entre voces de personajes en tiempo real.
| 1 | const agent = await elevenlabs.conversationalAi.agents.create({ |
| 2 | name: `Statue Scanner - ${statueName}`, |
| 3 | tags: ["statue-scanner"], |
| 4 | conversationConfig: { |
| 5 | agent: { |
| 6 | firstMessage, |
| 7 | language: "en", |
| 8 | prompt: { |
| 9 | prompt: systemPrompt, |
| 10 | temperature: 0.7, |
| 11 | }, |
| 12 | }, |
| 13 | tts: { |
| 14 | voiceId: primaryCharacter.voiceId, |
| 15 | modelId: "eleven_v3", |
| 16 | supportedVoices: otherCharacters.map((c) => ({ |
| 17 | voiceId: c.voiceId, |
| 18 | label: c.name, |
| 19 | description: c.voiceDescription, |
| 20 | })), |
| 21 | }, |
| 22 | turn: { |
| 23 | turnTimeout: 10, |
| 24 | }, |
| 25 | conversation: { |
| 26 | maxDurationSeconds: 600, |
| 27 | }, |
| 28 | }, |
| 29 | }); |
El array supportedVoices indica al agente qué voces están disponibles. La plataforma Agents gestiona el cambio de voz automáticamente: cuando la respuesta del LLM indica que habla otro personaje, el motor TTS asigna ese fragmento a la voz correcta.
Para que varios personajes suenen como un grupo real (y no como un simple turno de preguntas y respuestas), hay que diseñar bien el prompt:
| 1 | const multiCharacterRules = ` |
| 2 | MULTI-CHARACTER DYNAMICS: |
| 3 | You are playing ALL ${characters.length} characters simultaneously. |
| 4 | Make this feel like a group conversation, not an interview. |
| 5 | |
| 6 | - Characters should interrupt each other: |
| 7 | "Actually, if I may -" / "Wait, I must say -" |
| 8 | |
| 9 | - React to what others say: |
| 10 | "Well said." / "I disagree with that..." / "Always so modest..." |
| 11 | |
| 12 | - Have side conversations: |
| 13 | "Do you remember when -" / "Tell them about the time you -" |
| 14 | |
| 15 | The goal is for users to feel like they are witnessing a real exchange |
| 16 | between people who happen to include them. |
| 17 | `; |
El último paso es la conexión del cliente. ElevenLabs Agents usa WebRTC para conversaciones por voz con baja latencia, mucho más rápido que conexiones basadas en WebSocket, lo que mejora la fluidez al hablar.
| 1 | const { token } = await client.conversationalAi.conversations.getWebrtcToken({ |
| 2 | agentId, |
| 3 | }); |
| 1 | import { useConversation } from "@elevenlabs/react"; |
| 2 | |
| 3 | const conversation = useConversation({ |
| 4 | onConnect: () => setIsSessionActive(true), |
| 5 | onDisconnect: () => setIsSessionActive(false), |
| 6 | onMessage: (message) => { |
| 7 | if (message.source === "ai") { |
| 8 | setMessages((prev) => [...prev, { role: "agent", text: message.message }]); |
| 9 | } |
| 10 | }, |
| 11 | }); |
| 12 | |
| 13 | await conversation.startSession({ |
| 14 | agentId, |
| 15 | conversationToken: token, |
| 16 | connectionType: "webrtc", |
| 17 | }); |
El hook useConversation gestiona la captura de audio, el streaming, la detección de voz y la reproducción.
Si quieres dar más contexto histórico antes de empezar la conversación, puedes añadir un modo de investigación avanzada usando la herramienta de búsqueda web de OpenAI:
| 1 | const response = await openai.responses.create({ |
| 2 | model: "gpt-5.2", |
| 3 | instructions: RESEARCH_SYSTEM_PROMPT, |
| 4 | tools: [{ type: "web_search_preview" }], |
| 5 | input: `Research ${identification.statueName}. Search for current information |
| 6 | including location, visiting hours, and recent news about the artwork.`, |
| 7 | }); |
Este proyecto demuestra que, al combinar distintas modalidades de IA —texto, investigación, visión y audio—, podemos crear experiencias que conectan el mundo digital y el real. Hay mucho potencial por explorar en agentes multimodales y nos encantaría ver cómo creadores lo aplican en educación, trabajo y ocio.
Las APIs usadas en este proyecto — Diseño de Voz,ElevenAgents y OpenAI— están disponibles desde ya.

Agent Skills are one of the highest-leverage ways to use LLMs. They provide the appropriate context for the task you want to accomplish in a repeatable manner.

From SOPs to production-ready support agents in minutes.