🧩 Copilot Studio: un contrato de contexto para no responder dos veces
🧩 Copilot Studio: un contrato de contexto para no responder dos veces
El agente muestra una tarjeta, eliges una opción y, unos segundos después, vuelve a preguntarte lo mismo. Antes de añadir otro «no te repitas» a las instrucciones, conviene mirar qué devolvió realmente el tema.
El 28 de agosto de 2026, Microsoft incorporó a su hub de orientación una nueva serie sobre contexto y mensajes duplicados. Es una novedad de arquitectura documentada y un patrón implementable, no el anuncio de una nueva API, una preview ni una disponibilidad general. Tampoco demuestra que el runtime haya cambiado ese día.
La propuesta merece atención porque convierte un problema aparentemente conversacional en algo que podemos diseñar y probar: un contrato entre componentes.
El chat y el contexto no son lo mismo
En el standard harness, el orquestador cede el control a ciertos componentes. Mientras estos trabajan, no ve sus mensajes al usuario; tampoco reconcilia automáticamente todo el contexto. En particular, las interacciones con botones de Adaptive Cards no llegan como tales al contexto del orquestador. Mostrar algo en pantalla no equivale a devolverlo como resultado. Modelo de contexto oficial.
Diagrama original del ejemplo de este artículo. Las flechas separan la comunicación visible de los outputs devueltos al plan.
Mi recomendación: revisar las fronteras de cada tema como revisaríamos el contrato de una función. ¿Qué recibe? ¿Qué devuelve? ¿Quién informa del resultado?
Alcance y requisitos
El laboratorio utiliza un agente del standard harness con orquestación generativa. Si estás en la nueva experiencia, Microsoft documenta Other ways to build y el selector New experience para acceder a los agentes estándar. No confundas este patrón con el comportamiento del GitHub Copilot harness. Acceso al standard harness.
En Settings → Generative AI → Orchestration, comprueba que la orquestación generativa está activada. Anota el modelo: Microsoft advierte que cambiarlo puede alterar las repeticiones. Configuración y comportamiento.
Necesitas permisos de edición y un entorno de pruebas. El ejemplo siguiente no consulta ni modifica D365FO: los datos son ficticios. Es una receta de configuración, no una solución exportada ni una prueba ejecutada en tu tenant.
Laboratorio: elegir entrega sin repetir la pregunta
Vamos a separar dos intenciones:
«Quiero elegir cómo recibir mi pedido y saber el horario de soporte».
El tema Elegir modalidad recoge y confirma la elección. Otro tema, Horario de soporte demo, devuelve como output de texto supportHours el valor ficticio «Lunes a viernes, 09:00–17:00» y el booleano answered=false. Este segundo tema no envía mensajes; el orquestador comunica su resultado.
Crea ambos desde Topics → Add a topic → From blank y dales descripciones diferentes: elección de entrega y consulta de horario. Con orquestación generativa, la descripción informa de cuándo utilizar cada tema. Creación y selección de temas.
1. Declarar los outputs del primer tema
Abre Details → Outputs → Create a new variable. Cada salida necesita nombre, tipo y descripción. La documentación distingue estos parámetros de las variables que simplemente existen dentro del tema. Gestión de entradas y salidas.
Para nuestro ejercicio:
| Output | Tipo | Significado en este contrato |
|---|---|---|
deliveryMode | Text | Modalidad válida seleccionada: pickup o delivery. |
choiceReceived | Boolean | Se recibió y validó la elección. |
answered | Boolean | El tema ya confirmó al usuario esa elección. No significa que haya resuelto el horario. |
messageSummary | Text | Resumen de la confirmación mostrada. |
answered y choiceReceived son nombres recomendados para salidas que crea el autor, no propiedades mágicas que activen un filtro del runtime. Microsoft propone acompañarlas de valores útiles y de instrucciones que las interpreten. Diseño de temas.
2. Inicializar antes de preguntar
Añade nodos Variable management → Set a variable value: answered=false, choiceReceived=false, deliveryMode="" y messageSummary="". Asigna booleanos reales, no el texto "false". El nodo admite literales, variables y fórmulas. Asignación de variables.
Esta inicialización es una decisión del ejemplo: queremos que cada ejecución empiece sin una confirmación anterior. No utilices una variable global como bandera universal de «usuario respondido».
3. Añadir una tarjeta mínima
Inserta Ask with Adaptive Card y, en sus propiedades, abre Edit adaptive card. Pega este JSON original:
{
"$schema": "https://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.5",
"body": [
{
"type": "Input.ChoiceSet",
"id": "deliveryMode",
"label": "¿Cómo quieres recibir el pedido de prueba?",
"style": "expanded",
"isRequired": true,
"errorMessage": "Selecciona una modalidad.",
"choices": [
{ "title": "Recogida", "value": "pickup" },
{ "title": "Envío", "value": "delivery" }
]
}
],
"actions": [
{ "type": "Action.Submit", "title": "Elegir" }
]
}
Guarda y comprueba que la salida del nodo deliveryMode es de texto; Edit Schema permite corregir las salidas generadas. Si el diseñador crea otra variable, úsala como entrada y copia su valor validado al output del tema. La salida del nodo no sustituye la declaración en Details → Outputs. Configuración de tarjetas.
4. Validar y confirmar
Con nodos Condition, admite únicamente pickup o delivery. En cualquier otra rama, no marques éxito: solicita una elección válida o termina esa operación sin confirmarla.
En cada rama válida, configura esta secuencia:
- Guarda el valor aceptado en
deliveryMode. - Asigna
choiceReceived=true. - Envía «Has elegido recogida para este ejemplo» o «Has elegido envío para este ejemplo».
- Después del mensaje, asigna
answered=truey el resumen correspondiente. - Finaliza el tema dejando disponibles sus cuatro outputs.
No hay reserva ni actualización de pedido. Confirmar una preferencia en el chat no acredita una transacción en el ERP.
5. Conectar el contrato con las instrucciones
Descripción propuesta para Elegir modalidad:
Gestiona la elección de entrega del pedido de prueba.
Devuelve deliveryMode y el estado de su confirmación.
No informa sobre horarios ni realiza cambios en pedidos.
Instrucción propuesta para el agente:
Tras ejecutar un componente, interpreta sus outputs.
Si answered es true, no repitas lo descrito en messageSummary.
Si choiceReceived es true, reutiliza deliveryMode.
Responde a las demás peticiones pendientes con sus fuentes o herramientas.
Si falta un resultado, no lo inventes ni lo declares completado.
Son instrucciones de ejemplo, no una garantía. La guía recomienda combinar outputs, descripción del componente e instrucciones del agente; no basta con añadir una bandera sin explicar su significado. Patrón de diseño oficial.
Para Horario de soporte demo, describe que devuelve un horario ficticio y que corresponde al orquestador comunicarlo. Así podremos detectar si la elección hace desaparecer la segunda intención.
¿Y si intervienen otros agentes?
Los agentes conectados permiten desactivar Pass conversation history to this agent; los agentes hijo no tienen ese interruptor. La guía propone delimitar la tarea mediante scopedRequest. Si un subagente debe trabajar sin hablar al usuario, hay que indicárselo a él: After running no impide los mensajes durante su ejecución. Diseño de subagentes.
Para este laboratorio no añadiría un subagente. Primero probaría el contrato con dos temas; ampliaría la arquitectura solo cuando hubiera una responsabilidad que justificara separarlo.
Pruebas que sí detectan el problema
Microsoft recomienda cruzar transcripción, mapa de actividad y outputs, no diagnosticar únicamente por lo que aparece en el chat. Procedimiento de diagnóstico.
Esta es mi matriz de aceptación propuesta:
| Caso | Qué comprobar |
|---|---|
| Elegir recogida | Una confirmación; pickup devuelto; ninguna segunda pregunta equivalente. |
| Elegir envío + pedir horario | Se conserva la elección y se responde también al horario ficticio. |
| Valor vacío o distinto de los admitidos | No se devuelve éxito ni se afirma que exista un pedido actualizado. |
| Preguntar otra cosa con la tarjeta pendiente | Registrar interrupción y reanudación; no confundirlas con una respuesta ya completada. |
| Repetir explícitamente la consulta | El agente puede responder de nuevo cuando el usuario lo pide. |
| Reejecutar el tema con otra elección | No arrastra el estado de la primera ejecución. |
Guarda modelo, instrucciones, transcripción y outputs de cada caso. Repite las pruebas con varias formulaciones; una conversación correcta no demuestra ausencia de regresiones.
Límites, seguridad y coste
No uses End all topics como parche general: cancela los pasos restantes del plan y puede dejar sin resolver el horario. Tampoco interpretes este contrato como entrega exactly-once, memoria duradera o idempotencia de una API. Control del plan.
El estado conversacional no autoriza operaciones. Si adaptas el ejemplo a pedidos reales, valida identidad, permisos y datos en la operación de negocio. No incluyas secretos ni datos innecesarios en resúmenes. Las políticas de datos y autenticación son controles independientes del prompt. Seguridad y gobierno.
No se anuncia una licencia nueva para este patrón. Se aplican las condiciones de Copilot Studio: las pruebas con licencia trial no habilitan publicación y el consumo depende de las capacidades utilizadas. No presupuestes «un mensaje menos = una cantidad fija de créditos ahorrada». Licenciamiento estándar.
Qué llevaría a producción
Primero, un inventario de quién responde en cada operación. Después, outputs explícitos y pruebas de peticiones múltiples. Por último, sustituiría los datos ficticios por una integración autorizada, manteniendo separados resultado de negocio y respuesta visible.
La idea importante no es silenciar al agente. Es que el siguiente componente sepa qué queda por hacer.