Panel
14 de septiembre de 2026

Los subagentes están simplemente equivocados

Explore with AI

El agente de autofix de Polylane se construyó originalmente como un flujo de trabajo de múltiples subagentes, cada uno responsable de una sola tarea:

  • un triaje para clasificar miles de alertas y señales
  • un coordinador para operar los subagentes
  • hasta quince subagentes para investigar todas las hipótesis posibles del issue
  • y un agente de programación para finalmente enviar un pull request

graph TB
    S["Alerts and signals"] --> T["Triage agent"]
    T -->|"confirmed issue"| C["Coordinator agent"]
    C -->|"hypotheses"| H["Up to 15 hypothesis sub-agents"]
    H -->|"verdicts"| C
    C -->|"plan"| A["Coding agent"]
    A --> PR["Pull request"]
    style C fill:#fee2e2,stroke:#fca5a5,color:#7f1d1d
    style H fill:#fee2e2,stroke:#fca5a5,color:#7f1d1d

Un issue confirmado podía llevar hasta 18 agentes y subagentes para la investigación y el arreglo. Hoy el mismo trabajo lo hace un solo agente.

El flujo de trabajo era un diseño sólido basado en lo que sabíamos en ese momento: prompts pequeños, conjuntos de herramientas pequeños, un orquestador para transportar resultados entre especialistas. Sin embargo, era extremadamente costoso y difícil de operar y de razonar.

¿qué es un issue?

Polylane escanea logs, métricas y trazas de cada recurso de nube (Lambda Function, Cloudflare Worker, proyecto de Vercel, etc.) en cada proveedor conectado. Para cada recurso guardamos líneas base a lo largo de múltiples horizontes, de manera que podamos capturar la estacionalidad de los datos. Luego evaluamos el estado actual del recurso de nube y lo comparamos con datos históricos. Los valores que rompen la línea base se registran como issues.

Los issues también pueden crearse a partir de alertas que recibimos de soluciones de observabilidad y seguimiento de errores.

graph TB
    R["Cloud resource"] -->|"telemetry"| B["Compare with its baselines"]
    A["Alert from an observability<br/>or error tracking provider"] --> I
    B -->|"breaks the baseline"| I["Issue"]
    B -->|"within the baseline"| N["No issue"]
    style I fill:#fee2e2,stroke:#fca5a5,color:#7f1d1d

¿cómo resolvemos los issues?

Para resolver un issue, necesitamos:

  1. Triaje: recopilar datos para confirmar o rechazar el issue.
  2. Investigar: evaluar múltiples hipótesis y determinar la causa raíz.
  3. Abrir un pull request o escalar. Escribir un pull request para resolver el issue, escalar a un ingeniero si el arreglo no es un cambio de código, o escribir un informe que destaque los hallazgos y detenerse.

La gran mayoría de las ejecuciones terminan antes de un pull request o un escalado, cuando Polylane concluye que el issue es un falso positivo o benigno.

graph TB
    I["Triage the issue"] --> V["Investigate the root cause"]
    V -->|"dismiss, fold, or reopen"| E["Report and stop"]
    V -->|"confirm"| X["Open a pull request"]
    V -->|"confirm, no code change"| Z["Escalate to an engineer"]
    style V fill:#fef3c7,stroke:#fcd34d,color:#78350f
    style X fill:#d1fae5,stroke:#6ee7b7,color:#065f46

arquitectura de subagentes

Nuestra arquitectura inicial se basaba en múltiples subagentes.

graph TB
    F["Finding"] --> T["Triage agent"]
    T -->|"confirm"| C["Orchestrator agent"]
    C -->|"hypotheses"| W["Fan-out workflow"]
    W --> H1["Hypothesis agent 1"]
    W --> H2["Hypothesis agent 2"]
    W --> H3["Hypothesis agent ..."]
    W --> H15["Hypothesis agent 15"]
    H1 --> AG["Vote and summarize"]
    H2 --> AG
    H3 --> AG
    H15 --> AG
    AG -->|"summary as a message"| C
    C -->|"confirmed hypothesis"| AF["Coding agent"]
    AF --> PR["Pull request"]
    style C fill:#fee2e2,stroke:#fca5a5,color:#7f1d1d
    style AG fill:#fee2e2,stroke:#fca5a5,color:#7f1d1d

Usábamos un agente orquestador para coordinar el trabajo entre múltiples subagentes. Se instanciaban subagentes para investigar hipótesis, tratando de probar o refutar cada hipótesis con distintos puntos de partida (por ejemplo, empezando por revisar los logs, o empezando por el código, etc.).

Los hallazgos de los subagentes se votaban con aritmética simple y los resumía otro agente antes de trasladarlos al agente coordinador.

El veredicto de cada hipótesis era un voto ponderado por confianza a lo largo de sus pasadas.

const CONFIDENCE_RANK = { definitive: 4, strong: 3, moderate: 2, weak: 1, speculative: 0 };

function aggregatePassVerdicts(passes: PassResult[]): Verdict {
  const weights: Record<string, number> = {};
  const counts: Record<string, number> = {};
  for (const p of passes) {
    weights[p.verdict] = (weights[p.verdict] ?? 0) + CONFIDENCE_RANK[p.confidence];
    counts[p.verdict] = (counts[p.verdict] ?? 0) + 1;
  }
  const totalWeight = Object.values(weights).reduce((a, b) => a + b, 0);
  const [winner, winnerWeight] = Object.entries(weights).sort((a, b) => b[1] - a[1])[0];

  const countMajority = counts[winner] > passes.length / 2;
  const weightMajority = winnerWeight > totalWeight / 2;
  if (!countMajority && !weightMajority) {
    return { verdict: "inconclusive", confidence: "weak", summary: `No consensus across ${passes.length} passes.` };
  }

  const majority = passes.filter((p) => p.verdict === winner);
  const confidence = majority.reduce((min, p) => (CONFIDENCE_RANK[p.confidence] < CONFIDENCE_RANK[min] ? p.confidence : min), majority[0].confidence);
  const lead = majority.reduce((best, p) => (CONFIDENCE_RANK[p.confidence] > CONFIDENCE_RANK[best.confidence] ? p : best));
  return { verdict: winner, confidence, summary: lead.summary };
}

Una vez investigadas todas las hipótesis, si se identificaba una causa raíz, el coordinador escalaba a un ingeniero o escribía un plan para el arreglo. Este plan se entregaba a un subagente de programación para implementar el arreglo y enviar el pull request.

El principal problema de esta arquitectura es la pérdida de contexto entre subagentes. Cada agente transmitía hacia arriba o hacia abajo solo fracciones de su contexto, mediante resúmenes, y tanto los agentes anteriores como los posteriores tenían que rehacer regularmente el mismo trabajo.

graph TB
    I["Issue"] --> O["Orchestrator<br/>splits the issue into briefs"]
    O -->|"brief A"| A["Sub-agent A<br/>investigates brief A"]
    O -->|"brief B"| B["Sub-agent B<br/>investigates brief B"]
    A -.->|"summary A"| M["Orchestrator, later<br/>writes the plan from the summaries"]
    B -.->|"summary B"| M
    M -.->|"plan"| F["Coding agent<br/>writes the fix"]
    F --> PR["Pull request"]
    style I fill:none,stroke:none
    style PR fill:none,stroke:none
    style O stroke:#4C8C57,color:#3d7046
    style A stroke:#3b7dd8,color:#2b5fa8
    style B stroke:#7c5cd6,color:#5b3fb0
    style M stroke:#a07d1c,color:#7a5f14
    style F stroke:#6b7280,color:#4b5563
    %% aside O right #4C8C57 Issue, alerts and history
    %% aside A left #3b7dd8 Brief A and its evidence
    %% aside B right #7c5cd6 Brief B and its evidence
    %% aside M right #a07d1c History and two summaries, no evidence
    %% aside F right #6b7280 The plan, nothing else

Además, el agente que escribía el arreglo solo tenía el plan, sin contexto sobre el issue original ni sobre la evidencia recopilada en la investigación. Esto llevaba a pull requests de baja calidad que a menudo se enfocaban en los síntomas en lugar de la causa raíz.

Elegimos esta arquitectura principalmente porque, cuando la diseñamos por primera vez en marzo de 2026, los modelos de frontera no siempre eran capaces de llevar a cabo una investigación de principio a fin, incluida la escritura del arreglo, y, sencillamente, nuestro harness tampoco era tan bueno.

Cada vez era más difícil construir sobre esta base, porque:

  • Depurar requería muchas trazas. Razonar sobre una investigación de principio a fin requería revisar múltiples trazas, a veces docenas.
  • La evaluación era por etapa. Cada subagente podía evaluarse individualmente y aprobar, mientras que el resultado final era pobre, porque los fallos vivían en los traspasos.

Iteramos sobre esta arquitectura durante meses, mejorando cada agente individualmente y ajustando los prompts y los traspasos, pero los resultados nunca estuvieron a la altura del esfuerzo. Era costoso, difícil de depurar, y los pull requests no eran suficientemente buenos.

un solo agente

El 3 de septiembre reemplazamos el flujo de trabajo de subagentes por un solo agente que hace todo, desde el triaje hasta el pull request. El mismo agente recopila la evidencia, investiga todas las hipótesis y envía el pull request.

graph TB
    F["Issue"] --> A["Single agent"]
    A --> I["Triage"]
    I --> B["Investigate"]
    B --> V["One verdict"]
    V -->|"confirm"| X["Clone, edit, validate in the sandbox"]
    X --> PR["Open the pull request"]
    V -->|"dismiss, fold, or reopen"| E["Report and stop"]
    V -->|"confirm, no code change"| Z["Escalate to an engineer"]
    style A fill:#d1fae5,stroke:#6ee7b7,color:#065f46
    style PR fill:#d1fae5,stroke:#6ee7b7,color:#065f46

Eliminamos el agente de triaje, el coordinador, los agentes de hipótesis y el agente de autofix, junto con los flujos de trabajo que transportaban resultados entre ellos y las puertas de control que precedían al pull request. Los beneficios operativos fueron inmediatos: una sola traza para evaluar, y sin resúmenes entre subagentes.

Más importante aún, la calidad de los pull requests mejoró, y el tiempo entre detectar un issue y abrir el pull request que lo arregla se redujo drásticamente. Durante el mes en torno al cambio, la mediana pasó de 2.2 horas a 35 minutos y el p90 de nueve días a menos de dos horas. Con el pipeline, un hallazgo solía quedarse varias horas en una cadena de flujos de trabajo, cada uno esperando al anterior. Con el agente único, el pull request se abre solo minutos después de detectarse el issue.

15 min 1 h 4 h 1 d 4 d 2 sem 14 Aug 18 Aug 22 Aug 26 Aug 30 Aug 3 Sep 7 Sep 11 Sep 3 sep: un agente 30 min
Mediana diaria Mediana diaria to p90 Axis not to scale
Figura 1
Horas desde que se detecta un issue hasta que se abre su pull request

Ahora también abrimos muchos más pull requests. Cuando usábamos subagentes, el 0.6% de los issues detectados terminaba en un pull request. Con el agente único es el 4.2%, y sigue subiendo. La diferencia está en los modos de fallo. Un pipeline con múltiples subagentes tiene que sobrevivir a cada traspaso: el triaje tiene que promover el hallazgo, el coordinador tiene que producir hipótesis, el fan-out tiene que llegar a un veredicto, etc. Cada traspaso es un posible modo de fallo.

0% 2% 4% 6% 8% 10% 14 Aug 18 Aug 22 Aug 26 Aug 30 Aug 3 Sep 7 Sep 11 Sep 3 sep: un agente 9.1%
Figura 2
Proporción de issues detectados que terminaron en un pull request

El costo por pull request también bajó. Ahora cada ejecución comienza con el modelo más potente, así que un hallazgo descartado cuesta más de lo que costaba con el pipeline. Pero el costo promedio por pull request pasó de $111 a aproximadamente $18 en los primeros nueve días del agente único. Esta caída no es exclusivamente el resultado del cambio de arquitectura, ya que estamos iterando activamente en cada aspecto de Polylane. Parte de ella es la deriva normal de un sistema en iteración constante.

$1 $10 $100 $1,000 14 Aug 18 Aug 22 Aug 26 Aug 30 Aug 3 Sep 7 Sep 11 Sep 3 sep: un agente $2.88
Logarithmic scale
Figura 3
Gasto en modelos por pull request abierto
Todos los valores detrás de las tres gráficas, por día UTC
DíaIssues detectados con pull requestMedianap90Gasto por pull request
14 Aug 1.9% 2.3 h 2.7 h $144
15 Aug 1.1% 5.6 h 5.9 h $270
16 Aug 2.3% 1.2 h 4.2 d $121
17 Aug 1.5% 38 min 4.5 d $120
18 Aug 0.9% 20 min 27 min $57
19 Aug 0.7% 49 min 12.2 h $157
20 Aug 0.7% 1 h 35.9 h $202
21 Aug 0.8% 44.2 h 4.2 d $211
22 Aug 0.8% 7.7 d 10.4 d $563
23 Aug 1.3% 32 min 35.3 h $205
24 Aug 0.6% 2.5 d 5.6 d $90
25 Aug 1.4% 1.5 h 13.4 h $43
26 Aug 0.3% 1.5 h 2.1 h $45
27 Aug 0.7% 1.9 h 2.5 h $58
28 Aug 1% 11.7 d 14.1 d $49
29 Aug 1.5% 26.1 h 10.4 d $32
30 Aug 0.5% 2 d 2.8 d $51
31 Aug 0.2% 9 d 10.4 d $77
1 Sep 0.1% 4.2 d 4.2 d $169
2 Sep 0.1% 6.7 d 6.7 d $93
3 Sep · un agente 0.4% 29 min 2.6 d $69
4 Sep 2.4% 23 min 5.4 h $25
5 Sep 2.9% 34 min 3.4 d $15
6 Sep 1.4% 34 min 43.7 h $23
7 Sep 1.8% 32 min 4.5 h $16
8 Sep 4% 41 min 19.4 h $26
9 Sep 7.6% 34 min 1.2 h $15
10 Sep 5% 34 min 1.3 h $17
11 Sep 5.4% 56 min 2.1 h $12
12 Sep 9.1% 35 min 1.3 h $3.46
13 Sep · hasta las 16:00 8.2% 30 min 55 min $2.88

no construyas subagentes

  • Los traspasos pierden más de lo que ahorran. Cada resumen que pasa entre agentes es contexto que el siguiente agente nunca tendrá. El agente que recopila la evidencia debería ser el agente que actúa sobre ella.
  • Evalúa la ejecución, no los agentes. Las evaluaciones por agente aprueban mientras el sistema falla, porque los fallos viven entre los agentes.
  • Mantén una sola traza por ejecución. Una decisión equivocada repartida en una docena de trazas tarda una tarde en explicarse. En una sola traza basta con hacer scroll.

Nadie debería estar de guardia en 2026. Polylane vigila tu infraestructura, investiga y arregla lo que se rompe.

Únete a la lista de espera