
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.
Fotografe uma estátua. Identifique as figuras retratadas. Depois, converse por voz em tempo real com elas – cada personagem falando com uma voz única e adequada à época.
É isso que você pode criar com as APIs de Design de Voz e de Agentes da ElevenLabs. Neste post, mostramos a arquitetura de um app móvel para web que combina visão computacional com geração de voz para transformar monumentos públicos em experiências interativas. Tudo aqui pode ser reproduzido usando as APIs e os exemplos de código abaixo.
O app abaixo foi criado a partir de um único prompt, testado e funcionando de primeira noCursor com Claude Opus 4.5 (alto) a partir de um projeto NextJS vazio. Se quiser ir direto ao ponto e criar o seu, cole isto no seu 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 |
Você também pode usar as Habilidades do ElevenLabs Agent em vez de consultar a documentação. Elas são baseadas nos docs e podem trazer resultados ainda melhores.
O restante deste post explica o que esse prompt produz.
O fluxo tem cinco etapas:
Quando o usuário fotografa uma estátua, a imagem é enviada para um modelo da OpenAI com capacidade de visão. Um prompt estruturado extrai o nome da obra, localização, artista, data e – o mais importante – uma descrição detalhada da voz de cada personagem. O prompt inclui o formato de saída JSON esperado:
| 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 uma foto da estátua de Boudica na ponte de Westminster, em Londres, a resposta fica assim:
| 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 | } |
A qualidade da descrição da voz determina diretamente a qualidade da voz gerada. O guia de prompts do Voice Design explica isso em detalhes, mas os principais atributos são: indicação de qualidade de áudio ("Qualidade de áudio perfeita."), idade e gênero, tom/timbre (grave, ressonante, rouca), sotaque preciso ("sotaque celta britânico carregado" em vez de apenas "britânico") e ritmo. Prompts mais detalhados geram resultados mais fiéis – "uma nova-iorquina cansada de 60 e poucos anos com senso de humor seco" funciona muito melhor do que "voz feminina mais velha".
Algumas dicas do guia: use "carregado" em vez de "forte" para descrever a intensidade do sotaque, evite termos vagos como "estrangeiro" e, para personagens fictícios ou históricos, você pode sugerir sotaques reais como referência (ex: "uma rainha celta antiga com sotaque britânico carregado, imponente e autoritária").
A API de Voice Design gera vozes sintéticas novas a partir de descrições em texto – não precisa de amostras de voz nem de clonagem. Isso é ideal para figuras históricas sem registros de áudio.
O processo tem dois passos.
| 1 | const { previews } = await elevenlabs.textToVoice.design({ |
| 2 | modelId: "eleven_multilingual_ttv_v2", |
| 3 | voiceDescription: character.voiceDescription, |
| 4 | text: sampleText, |
| 5 | }); |
O parâmetro de texto faz diferença. Um texto de amostra mais longo e adequado ao personagem (mais de 50 palavras) gera resultados mais estáveis – combine o diálogo com o personagem, em vez de usar uma saudação genérica. O guia de prompts do Voice Design traz mais detalhes sobre isso.
Depois de gerar as prévias, escolha uma e crie a voz permanente:
| 1 | const voice = await elevenlabs.textToVoice.create({ |
| 2 | voiceName: `StatueScanner - ${character.name}`, |
| 3 | voiceDescription: character.voiceDescription, |
| 4 | generatedVoiceId: previews[0].generatedVoiceId, |
| 5 | }); |
Para estátuas com vários personagens, a criação das vozes acontece em paralelo. As vozes de cinco personagens são geradas quase no mesmo tempo que uma só:
| 1 | const results = await Promise.all( |
| 2 | characters.map((character) => createVoiceForCharacter(character)) |
| 3 | ); |
Com as vozes prontas, o próximo passo é configurar umAgente ElevenLabs que consiga alternar entre as vozes dos personagens em tempo 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 | }); |
O array supportedVoices informa ao agente quais vozes estão disponíveis. A plataforma Agents faz a troca de vozes automaticamente – quando a resposta do LLM indica que outro personagem está falando, o mecanismo TTS direciona aquele trecho para a voz correta.
Para que vários personagens soem como um grupo de verdade – e não apenas um bate-papo em sequência – é preciso criar prompts específicos:
| 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 | `; |
A última etapa é a conexão do cliente. Os Agents da ElevenLabs suportam WebRTC para conversas por voz com baixa latência – bem mais rápido que conexões via WebSocket, o que faz diferença para conversas naturais.
| 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 | }); |
O hook useConversation cuida da captura de áudio, transmissão, detecção de atividade de voz e reprodução.
Para quem quiser mais contexto histórico antes de começar a conversa, é possível adicionar um modo de pesquisa avançada usando a ferramenta de busca na web da 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 projeto mostra que, ao combinar diferentes modalidades de IA – texto, pesquisa, visão e áudio – conseguimos criar experiências que conectam o mundo digital ao real. Há muito potencial inexplorado em agentes multimodais, e queremos ver mais pessoas explorando isso para educação, trabalho e diversão.
As APIs usadas neste projeto –Design de Voz,ElevenAgents e OpenAI – já estão disponíveis.

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.