Durante los últimos meses hemos convertido la palabra agente en una etiqueta demasiado cómoda.

Llamamos agente a un prompt. Llamamos agente a un modelo con dos funciones. Llamamos sistema multiagente a varios modelos enviándose texto sin estado, sin gobierno y sin una definición verificable de cuándo han terminado.

El problema no es únicamente terminológico.

Cuando confundimos el modelo con el sistema completo, terminamos construyendo soluciones que funcionan en una demo, pero que no pueden responder preguntas básicas de arquitectura:

  • ¿Qué tarea está ejecutando?
  • ¿Qué pasos ha completado?
  • ¿Qué información ha conservado?
  • ¿Qué herramientas puede utilizar?
  • ¿Qué operación requiere aprobación?
  • ¿Qué sucede cuando una herramienta falla?
  • ¿Cuándo debe detenerse?
  • ¿Cómo podemos reconstruir lo ocurrido?

Microsoft Agent Framework introduce dos conceptos que ayudan a separar correctamente estas responsabilidades:

  • Agent Harness, como entorno operativo que gobierna al agente.
  • CodeAct, como mecanismo para que el modelo exprese una parte del trabajo como código y la ejecute en una sandbox.

No son dos alternativas.

No debemos elegir entre Harness o CodeAct.

Agent Harness controla el trabajo. CodeAct ejecuta determinadas partes de ese trabajo de forma compacta.

No son dos capas paralelas ni dos formas alternativas de construir un agente. CodeAct se incorpora dentro del Harness como una capacidad especializada para ejecutar una parte concreta del trabajo.

El modelo no es el agente

Un modelo de lenguaje puede recibir una instrucción y producir una respuesta.

Eso no significa que pueda sostener por sí solo una tarea empresarial larga.

Supongamos que solicitamos:

Analiza ochenta aplicaciones, recupera sus incidentes, costes y dependencias, calcula un índice de riesgo, explica el ranking y crea una iniciativa para las tres primeras.

La respuesta no depende únicamente de la capacidad del modelo para razonar.

Necesitamos resolver:

  • cómo descomponer el objetivo;
  • cómo conservar el estado;
  • cómo registrar lo completado;
  • cómo administrar el contexto;
  • cómo llamar a las herramientas;
  • cómo solicitar aprobaciones;
  • cómo recuperarse de errores;
  • cómo decidir que el trabajo ha terminado.

Podemos expresar la diferencia así:

Modelo
  = generación y razonamiento

Agente
  = modelo
  + instrucciones
  + herramientas
  + estado
  + memoria
  + políticas
  + bucle de ejecución
  + observabilidad
  + criterio de finalización

El modelo aporta capacidad cognitiva. El Harness aporta capacidad operativa y CodeAct proporciona una forma compacta de ejecutar determinadas subtareas intensivas en herramientas.

Agent Harness: el plano de control

Microsoft define un agent harness como el andamiaje que convierte un modelo en un agente capaz de trabajar sobre tareas largas y de varios pasos.

En C#, el Harness envuelve un IChatClient mediante AsHarnessAgent(...).

Su responsabilidad no es calcular el scoring de nuestro portfolio. Su responsabilidad es controlar el proceso completo:

  • planificación;
  • modos de plan y ejecución;
  • lista de tareas;
  • sesión;
  • historial;
  • compactación de contexto;
  • memoria;
  • acceso a archivos;
  • aprobaciones;
  • llamadas a herramientas;
  • evaluación del bucle;
  • OpenTelemetry.

Ésta es la primera separación importante del artículo:

El Harness no es una herramienta que el agente llama. Es el entorno que decide cómo progresa el agente.

El flujo conceptual es:

Usuario
  |
  v
Harness
  |
  +-- interpreta la intención
  +-- construye el plan
  +-- crea los todos
  +-- conserva el estado
  +-- aplica políticas
  +-- ejecuta herramientas
  +-- comprueba el progreso
  |
  v
Resultado

Esta separación encaja con un principio que utilizo de forma recurrente en arquitectura empresarial de IA:

Elevate before Delegate.

Antes de delegar una ejecución autónoma, elevamos la intención:

  • la hacemos explícita;
  • identificamos restricciones;
  • establecemos contratos;
  • definimos evidencias;
  • acordamos qué puede cambiarse.

El Harness proporciona el plano de control donde podemos implementar esa disciplina: intención explícita, planificación, seguimiento, políticas y aprobación.

Planificar no significa ejecutar

El Harness incorpora un patrón de modos que separa dos comportamientos.

Plan mode

El agente:

  • comprende la solicitud;
  • pregunta cuando falta una restricción imprescindible;
  • propone una estrategia;
  • crea una lista de tareas;
  • expone qué acciones pretende ejecutar.

Execute mode

El agente:

  • trabaja sobre las tareas;
  • utiliza herramientas;
  • actualiza el progreso;
  • produce artefactos;
  • continúa hasta alcanzar la condición de terminación.

Esta separación es mucho más que una mejora de experiencia de usuario.

Es una frontera de gobierno.

Cuando el usuario dice:

Ayúdame a modernizar Payments Legacy.

no debemos traducir esa frase directamente a:

crear épica
modificar repositorio
desplegar infraestructura
notificar al equipo

Primero debemos determinar qué significa modernizar:

  • rehost;
  • replatform;
  • refactor;
  • replace;
  • retire;
  • encapsular;
  • estrangular progresivamente;
  • conservar temporalmente.

El Harness controla ese proceso.

CodeAct todavía no ha aparecido, y ése es precisamente el punto.

CodeAct no resuelve intención, planificación ni gobierno. Solo debe entrar cuando el Harness ya ha determinado qué trabajo hay que ejecutar, con qué herramientas y bajo qué restricciones.

El problema de la orquestación herramienta a herramienta

Una vez aprobado el análisis, necesitamos procesar el portfolio.

Para cada aplicación debemos:

  • recuperar sus datos;
  • consultar incidentes;
  • consultar costes;
  • normalizar métricas;
  • calcular una puntuación;
  • agregar resultados;
  • ordenar el ranking.

Con function calling tradicional, el flujo puede convertirse en:

Modelo -> get_applications
Modelo -> get_incidents(APP-001)
Modelo -> get_costs(APP-001)
Modelo -> get_incidents(APP-002)
Modelo -> get_costs(APP-002)
...

Cada llamada vuelve al modelo.

El modelo decide la siguiente herramienta, recibe el resultado, vuelve a inferir y repite.

Esto introduce:

  • más turnos;
  • más tokens;
  • más latencia;
  • más estado conversacional;
  • más posibilidades de desviación;
  • más dificultad para revisar el workflow como una unidad.

El cuello de botella no siempre es la inteligencia del modelo.

En muchos casos es la sobrecarga de orquestación.

CodeAct: expresar el workflow como código

CodeAct introduce una herramienta llamada execute_code.

En lugar de pedir al modelo que emita una llamada de herramienta cada vez, le permitimos escribir un programa corto que:

  • utiliza bucles;
  • aplica condiciones;
  • transforma datos;
  • agrega resultados;
  • llama a herramientas del host;
  • imprime un resultado estructurado.

El flujo pasa a ser:

Modelo
  |
  v
execute_code(programa)
  |
  v
Sandbox
  |
  +-- call_tool("get_applications")
  +-- for application in applications
  +-- call_tool("get_incidents", ...)
  +-- call_tool("get_costs", ...)
  +-- normalizar
  +-- scoring
  +-- ordenar
  |
  v
Resultado

La diferencia fundamental no es Python frente a C#.

La aplicación, las herramientas, las credenciales, los contratos y las integraciones empresariales siguen estando en C#.

Python es el lenguaje invitado que el modelo utiliza dentro de la sandbox para expresar una composición dinámica.

C# conserva el control de las capacidades. El código invitado controla el flujo dentro de esas capacidades.

Cómo encajan Harness y CodeAct

Ahora podemos conectar ambos conceptos sin mezclarlos.

Harness responde a estas preguntas:

  • ¿Cuál es el objetivo?
  • ¿Qué falta por hacer?
  • ¿En qué modo estamos?
  • ¿Qué información debe conservarse?
  • ¿Qué operación requiere aprobación?
  • ¿Cuándo finaliza la tarea?
  • ¿Cómo observamos la ejecución?

CodeAct responde a éstas:

  • ¿Cómo itero sobre cincuenta elementos?
  • ¿Cómo combino tres herramientas?
  • ¿Cómo filtro y agrego?
  • ¿Cómo normalizo valores?
  • ¿Cómo genero un resultado estructurado sin volver al modelo en cada paso?

La arquitectura completa es:

┌────────────────────────────────────────────┐
│ Usuario                                    │
└───────────────────┬────────────────────────┘
                    │
                    v
┌────────────────────────────────────────────┐
│ Agent Harness                              │
│                                            │
│ intención · plan · todos · sesión          │
│ contexto · memoria · aprobación · tracing  │
└───────────────────┬────────────────────────┘
                    │
                    v
┌────────────────────────────────────────────┐
│ Modelo                                     │
└───────────────┬─────────────────┬──────────┘
                │                 │
                v                 v
       execute_code       herramienta directa
                │                 │
                v                 v
┌──────────────────────┐  ┌───────────────────┐
│ Hyperlight sandbox   │  │ operación sensible│
│                      │  │                   │
│ bucles               │  │ crear work item   │
│ cálculos             │  │ enviar correo     │
│ call_tool(...)       │  │ modificar recurso │
└──────────┬───────────┘  └─────────┬─────────┘
           │                        │
           v                        v
┌────────────────────────────────────────────┐
│ Herramientas C# acotadas                   │
│ CMDB · observabilidad · FinOps · DevOps    │
└────────────────────────────────────────────┘

Ésta es la tesis del artículo:

Harness gobierna la autonomía. CodeAct comprime la ejecución.

En términos de implementación, CodeAct no se configura como un agente independiente…

Caso de uso: priorizar la modernización legacy

La demo trabaja con cuatro aplicaciones:

Aplicación Tecnología Antigüedad (años) Criticidad
Payments Legacy COBOL / Mainframe 28 100
Customer Operations VB6 / COM+ 22 85
Portfolio Reporting .NET Framework 4.6 11 65
Notification Service .NET 8 2 45

Para cada aplicación disponemos además de:

  • incidentes mensuales;
  • incidentes de severidad 1 y 2;
  • coste operativo anual;
  • lead time medio de cambio.

La fórmula de scoring:

  • 30% criticidad de negocio
  • 25% presión de incidentes
  • 20% coste operativo
  • 15% lead time de cambio
  • 10% antigüedad

La intención del usuario es decidir qué aplicación estudiar primero.

El análisis no debe crear automáticamente ningún elemento de trabajo. Esa operación será un paso posterior.

Primero validamos el dominio sin IA

Antes de introducir un modelo, debemos demostrar que el dominio es correcto.

La solución incluye:

src/
  ModernizationAgent.Core/
  ModernizationAgent.LocalDemo/

Los proyectos utilizan:

<TargetFramework>net10.0</TargetFramework>

La interfaz de lectura es deliberadamente pequeña:

public interface IPortfolioReader
{
    IReadOnlyList<ApplicationInfo> GetApplications();
    IncidentSummary GetIncidents(string applicationId);
    CostSummary GetCosts(string applicationId);
}

No exponemos:

ExecuteSql(string sql)
CallApi(string url, string body)
RunCommand(string command)

Esas funciones no son herramientas empresariales.

Son puertas traseras semánticas.

Una herramienta de agente debe representar una capacidad concreta y revisable.

El algoritmo de scoring se ejecuta localmente y valida el ranking:

1. Payments Legacy        100.00
2. Customer Operations     68.78
3. Portfolio Reporting     37.83
4. Notification Service    18.32

Este paso importa porque evita atribuir al modelo una lógica que debemos controlar nosotros.

Este paso importa porque evita atribuir al modelo una lógica que debemos controlar nosotros.

En la demo permitiremos que el código generado reproduzca esa fórmula para mostrar el funcionamiento de CodeAct. Sin embargo, en producción los pesos y las reglas deberían estar encapsulados en una función C#, una política versionada o un servicio de dominio.

El modelo puede decidir qué datos recuperar y cómo componer el análisis. No debería tener autoridad para redefinir silenciosamente cómo la organización calcula el riesgo.

Herramientas C# para CodeAct

En la integración real registramos tres herramientas de lectura:

AIFunction getApplications = AIFunctionFactory.Create(
    () => applications,
    name: "get_applications",
    description:
        "Returns the application portfolio with ID, name, technology, " +
        "age in years, and business criticality (0-100). Read-only.");

AIFunction getIncidents = AIFunctionFactory.Create(
    (string applicationId) => GetIncidents(applicationId),
    name: "get_incidents",
    description:
        "Returns incident data for an application. " +
        "Parameter name: applicationId. Read-only.");

AIFunction getCosts = AIFunctionFactory.Create(
    (string applicationId) => GetCosts(applicationId),
    name: "get_costs",
    description:
        "Returns annual operating cost and change lead time. " +
        "Parameter name: applicationId. Read-only.");

Los nombres de parámetros y las formas de retorno son importantes.

En function calling tradicional el modelo selecciona una herramienta.

En CodeAct el modelo escribe código contra el contrato.

Una descripción ambigua no genera únicamente una mala llamada.

Puede generar un programa incorrecto.

Registrar las herramientas dentro de CodeAct

Creamos el proveedor Hyperlight:

var codeActOptions =
    HyperlightCodeActProviderOptions.CreateForWasm(
        PythonGuestModule.GetModulePath());

codeActOptions.Tools =
[
    getApplications,
    getIncidents,
    getCosts
];

using var codeAct =
    new HyperlightCodeActProvider(codeActOptions);

Estas herramientas quedan disponibles dentro de la sandbox mediante:

call_tool("get_applications")
call_tool("get_incidents", applicationId="APP-001")
call_tool("get_costs", applicationId="APP-001")

No necesitamos exponerlas también como herramientas directas al modelo.

Queremos que el agente utilice una composición coherente, no que vuelva al patrón de llamadas fragmentadas.

El programa que puede generar el modelo

CodeAct podría producir un programa equivalente a:

applications = call_tool("get_applications")

rows = []

for application in applications:
    application_id = application["id"]

    incidents = call_tool(
        "get_incidents",
        applicationId=application_id
    )

    costs = call_tool(
        "get_costs",
        applicationId=application_id
    )

    rows.append({
        "application": application,
        "incidents":   incidents,
        "costs":       costs
    })

max_incidents = max(row["incidents"]["monthlyIncidents"]         for row in rows)
max_cost      = max(row["costs"]["annualRunCost"]                for row in rows)
max_lead_time = max(row["costs"]["averageChangeLeadTimeDays"]    for row in rows)
max_age       = max(row["application"]["ageYears"]               for row in rows)

ranking = []

for row in rows:
    app       = row["application"]
    incidents = row["incidents"]
    costs     = row["costs"]

    incident_score  = incidents["monthlyIncidents"]         / max_incidents  * 100
    cost_score      = costs["annualRunCost"]                / max_cost       * 100
    lead_time_score = costs["averageChangeLeadTimeDays"]    / max_lead_time  * 100
    age_score       = app["ageYears"]                       / max_age        * 100

    final_score = (
        app["criticality"] * 0.30
        + incident_score   * 0.25
        + cost_score       * 0.20
        + lead_time_score  * 0.15
        + age_score        * 0.10
    )

    ranking.append({
        "applicationId": app["id"],
        "name":          app["name"],
        "technology":    app["technology"],
        "score":         round(final_score, 2)
    })

ranking.sort(key=lambda item: item["score"], reverse=True)

print(ranking)

El valor no está en que Python pueda dividir números.

El valor está en concentrar recuperación, iteración, transformación, normalización, scoring y ordenación en una única unidad ejecutable y revisable.

En esta demo, el programa generado contiene también la fórmula para que el flujo pueda entenderse de extremo a extremo. En producción, lo recomendable sería sustituir ese cálculo por una herramienta específica y versionada, por ejemplo `calculate_modernization_score`, manteniendo en CodeAct únicamente la composición dinámica.

Cuando entres en GitHub podrás localizar en Program.cs (\preview\HarnessCodeAct\) exactamente donde tiene lugar esto:

Línea Comentario
158 // Python generation happens here: PythonGuestModule supplies a WASM-compiled Python interpreter...
174 // The ## CodeAct section below is what causes the model to emit Python...

El primero explica el mecanismo de ejecución (el intérprete WASM). El segundo explica la causa del comportamiento (la instrucción en el system prompt). Son los dos momentos del flujo que puedes referenciar en el artículo.

La operación de escritura debe quedar fuera

Después del análisis, el usuario puede solicitar:

Crea un work item para Payments Legacy.

La herramienta C# es:

AIFunction createModernizationWorkItem =
    new ApprovalRequiredAIFunction(
        AIFunctionFactory.Create(
            (
                string applicationId,
                string title,
                string rationale,
                decimal priorityScore
            ) => CreateWorkItem(...),
            name: "create_modernization_work_item",
            description:
                "Creates a work item in an external system. " +
                "This is a side-effecting operation that requires explicit approval."));

Esta herramienta no se registra en codeActOptions.Tools.

Se añade directamente al agente:

ChatOptions = new ChatOptions
{
    Instructions = instructions,
    Tools = [createModernizationWorkItem]
}

¿Por qué?

Porque la aprobación de CodeAct se aplica actualmente a la llamada completa de execute_code.

Si una operación sensible queda escondida dentro de diez call_tool(...), perdemos la aprobación individual.

No todo lo que puede componerse debe componerse.

La escritura necesita una frontera distinta de la lectura: herramienta directa, identidad controlada, aprobación individual, idempotencia y trazabilidad.

Construir el HarnessAgent

La integración utiliza Microsoft Foundry:

AIAgent agent =
    new AIProjectClient(
        new Uri(endpoint),
        new DefaultAzureCredential(),
        new AIProjectClientOptions
        {
            RetryPolicy = new ClientRetryPolicy(3)
        })
    .GetProjectOpenAIClient()
    .GetResponsesClient()
    .AsIChatClient(deploymentName)
    .AsHarnessAgent(
        new HarnessAgentOptions
        {
            MaxContextWindowTokens  = MaxContextWindowTokens,
            MaxOutputTokens         = MaxOutputTokens,
            Name                    = "LegacyModernizationAgent",
            OpenTelemetrySourceName = TracingSourceName,
            FileMemoryStore =
                new FileSystemAgentFileStore("agent-files"),
            AIContextProviders = [codeAct],
            ChatOptions = new ChatOptions
            {
                Instructions = instructions,
                Tools        = [createModernizationWorkItem]
            }
        });

En este bloque se ve la conexión completa:

  • Foundry proporciona el modelo;
  • AsIChatClient lo adapta;
  • AsHarnessAgent añade el plano de control;
  • AIContextProviders añade CodeAct;
  • ChatOptions.Tools conserva la herramienta sensible como llamada directa.

CodeAct no se ejecuta al lado del Harness como un agente independiente. Se incorpora dentro del Harness como un proveedor de contexto y ejecución especializado.

Ésta es la conexión técnica entre ambos conceptos y la razón por la que no compiten.

Sesión, modos y tareas

El ejemplo oficial utiliza una consola interactiva.

Esto es importante porque un Harness no está pensado únicamente para una llamada stateless.

Necesita una sesión donde conservar:

  • el plan;
  • los todos;
  • el historial;
  • las decisiones;
  • las aprobaciones;
  • el progreso.

La consola permite utilizar:

/mode
/todos

Un flujo de prueba razonable es:

Analiza el portfolio completo. Calcula el índice de prioridad de
modernización, ordena los resultados y explica la primera posición.
No crees ningún work item.

Después

/todos

Y finalmente:

Crea el work item para la primera aplicación.

El análisis debe ejecutarse mediante CodeAct.

La escritura debe detenerse para solicitar aprobación.

Ésa es la demo arquitectónica: comprobar que el Harness conserva el control del proceso, CodeAct ejecuta el análisis y la operación de escritura se detiene para solicitar aprobación. El objetivo no es únicamente obtener el número 100.

La sandbox no hace segura una herramienta insegura

Hyperlight ejecuta el código invitado en un entorno aislado.

Sin embargo, call_tool(...) vuelve al proceso host.

La herramienta C# puede tener:

  • credenciales;
  • acceso a red;
  • acceso a Azure;
  • clientes de bases de datos;
  • acceso a sistemas corporativos.

Por tanto, la sandbox protege al host del código invitado, pero no protege nuestros sistemas de una herramienta host mal diseñada.

Una herramienta como:

RunSql(string sql)

sigue siendo peligrosa aunque sea llamada desde una micro-VM.

La seguridad real necesita:

  • contratos estrechos;
  • validación;
  • autorización;
  • mínimo privilegio;
  • límites de tasa;
  • timeouts;
  • auditoría;
  • idempotencia;
  • protección frente a prompt injection indirecta.

La sandbox es una capa de aislamiento.

No es un modelo completo de gobierno.

La regla práctica es sencilla: no concedas a una herramienta más capacidad de la que estarías dispuesto a conceder a cualquier otro componente no confiable de la aplicación.

Infraestructura Azure con Bicep

La demo incluye dos plantillas.

main.bicep

Despliega:

  • recurso Microsoft.CognitiveServices/accounts con kind: AIServices;
  • proyecto Foundry;
  • identidad administrada;
  • autenticación local deshabilitada;
  • asignación opcional del rol Foundry User.

La salida principal es foundryProjectEndpoint con la forma:

https://<resource>.services.ai.azure.com/api/projects/<project>

model.bicep

Despliega un modelo sobre el recurso existente.

La plantilla no codifica rígidamente una combinación de modelo, versión, formato y SKU.

La disponibilidad depende de la región, suscripción, cuota y catálogo. Primero debemos consultar:

az cognitiveservices account list-models \
  --name <foundry-name> \
  --resource-group <resource-group>

Después pasamos a Bicep: modelName, modelVersion, modelFormat, skuName, capacity.

Esto evita otra forma habitual de falsa reproducibilidad: publicar una plantilla que compila, pero que solo funciona en la suscripción de quien escribió el artículo.

El Bicep de la demo despliega Foundry, pero no el host de Hyperlight. Son dos planos de infraestructura distintos: Foundry proporciona el modelo y el proyecto; el backend .NET de Hyperlight en preview requiere hoy un host Linux con KVM.

¿Dónde ejecutar Hyperlight?

La infraestructura Bicep despliega Foundry.

No despliega de forma automática el host de CodeAct.

El backend .NET de Hyperlight en preview solo está disponible hoy para Linux con KVM. Hyperlight como runtime también soporta MSHV y Windows Hypervisor Platform (WHP), pero el conector de CodeAct para .NET aún no publica esas variantes.

Por tanto, podemos ejecutar la demo en:

  • estación Linux compatible;
  • VM Linux con virtualización adecuada;
  • entorno de desarrollo que exponga KVM;
  • host corporativo preparado para micro-VMs.

No debemos desplegarla de forma arbitraria en cualquier PaaS y asumir que KVM estará disponible.

En producción, la selección del host forma parte de la arquitectura:

  • compatibilidad de virtualización;
  • identidad administrada;
  • conectividad;
  • observabilidad;
  • hardening;
  • parcheado;
  • aislamiento;
  • coste.

Por tanto, no debemos afirmar que la solución completa es serverless ni que puede trasladarse sin cambios a cualquier servicio administrado de Azure. La compatibilidad de virtualización (KVM en el backend .NET actual) es un requisito de arquitectura, no un detalle de despliegue, que mantiene tu argumento sin cerrar la puerta a WHP.

Observabilidad

Un resultado correcto no demuestra que el proceso haya sido correcto.

Necesitamos conocer:

  • qué plan generó el agente;
  • qué herramientas utilizó;
  • qué código ejecutó;
  • qué argumentos proporcionó;
  • qué errores encontró;
  • qué aprobaciones recibió;
  • cuántos tokens consumió;
  • cuánto tardó;
  • qué resultado devolvió.

La demo configura:

OpenTelemetrySourceName = TracingSourceName

y el ejemplo oficial escribe trazas mediante OpenTelemetry.

En una arquitectura corporativa, esas trazas deberían correlacionarse con:

  • peticiones de aplicación;
  • llamadas a APIs;
  • operaciones de herramientas;
  • cambios en sistemas externos;
  • identidad ejecutora;
  • aprobador;
  • artefactos generados.

Un agente no debe ser una caja negra con un texto bonito al final.

Cuándo utilizar CodeAct

CodeAct encaja cuando la tarea necesita:

  • muchas herramientas de lectura;
  • bucles;
  • filtrado;
  • ramificaciones;
  • agregaciones;
  • cálculos;
  • transformaciones;
  • artefactos estructurados.

No encaja necesariamente cuando:

  • solo existe una llamada;
  • la operación es trivial;
  • cada acción requiere aprobación;
  • el flujo debe ser completamente determinista;
  • una función C# normal resuelve mejor el problema.

La decisión puede resumirse en la siguiente tabla:

Escenario Mecanismo
Consultar una aplicación Tool calling directo
Crear un ticket Tool directo con aprobación
Analizar cien aplicaciones CodeAct
Mantener el plan Harness
Conservar sesión y contexto Harness
Calcular ranking con varias fuentes Harness + CodeAct
Ejecutar lógica fija de negocio C#
Orquestación dinámica y acotada CodeAct

No debemos utilizar CodeAct porque sea nuevo.

Debemos utilizarlo cuando reduzca una sobrecarga real sin empeorar el gobierno.

De la demo a una solución corporativa

Las funciones en memoria pueden sustituirse por adaptadores:

get_applications
  -> CMDB / ServiceNow / catálogo corporativo

get_incidents
  -> Azure Monitor / App Insights / Splunk / Dynatrace

get_costs
  -> Azure Cost Management / repositorio FinOps

get_dependencies
  -> telemetría distribuida / repositorios / catálogo

create_modernization_work_item
  -> Azure DevOps / GitHub / Jira

Pero la frontera debe conservarse:

Lectura y agregación
  -> CodeAct

Cambio de estado
  -> herramienta directa aprobable

La transición desde la demo a producción no consiste en cambiar los datos en memoria por APIs reales. Consiste en conservar las mismas fronteras cuando aparecen identidades, permisos, redes, errores, concurrencia y efectos secundarios.

Limitaciones actuales

A fecha de 27 de julio de 2026:

  • Hyperlight CodeAct para .NET continúa en preview.
  • El backend requiere un host compatible con KVM. Hyperlight en sí soporta también Windows (WHP) y WSL2; la restricción a Linux con KVM es del conector .NET en preview, no del runtime.
  • La aprobación se aplica al bloque execute_code completo.
  • Las herramientas llamadas mediante call_tool(...) se ejecutan en el host.
  • Los contratos de herramientas deben ser muy precisos.
  • La disponibilidad de modelos y SKU cambia por región y suscripción.
  • La demo utiliza acceso público para simplificar la reproducción. Un entorno empresarial deberá evaluar Private Link, DNS privado, restricciones de salida y controles de red adicionales.
  • La demo real se aplica sobre el repositorio oficial mientras la cadena de paquetes Hyperlight no sea completamente autónoma desde NuGet.

Estas limitaciones no invalidan el patrón.

Definen dónde debemos poner las pruebas y las fronteras.

Conclusión

Agent Harness y CodeAct resuelven problemas distintos.

Agent Harness responde a cómo debe comportarse un agente durante una tarea:

  • planifica;
  • conserva estado;
  • administra contexto;
  • aplica políticas;
  • solicita aprobaciones;
  • observa;
  • continúa hasta terminar.

CodeAct responde a cómo ejecutar eficientemente una parte intensiva en herramientas:

  • itera;
  • filtra;
  • transforma;
  • calcula;
  • agrega;
  • produce resultados.

La arquitectura correcta no es:

Modelo con acceso a todo

La arquitectura correcta no es:

Harness que gobierna
  +
CodeAct que ejecuta
  +
herramientas C# acotadas
  +
aprobaciones visibles
  +
infraestructura declarativa
  +
trazabilidad

No se trata de conceder más autonomía. Se trata de hacer que la autonomía tenga límites, contratos y evidencias.

Ésa es la diferencia entre una demo de agente y una arquitectura agentic.

Código de la demo