Boilerplate completo para construir soluciones agénticas sobre IBM watsonx Orchestrate (ADK 2.x) con una capa web encima. Destilado de cotemar-poc-n1 y dun-casos-prueba. Incluye: - 11 docs (best practices, architecture patterns, ADK cheatsheet, observability, tool authoring, deployment, RUNBOOK, DEPLOY_TO_NEW_WOX, known-issues con 16 errores reales y fix, eval strategy, INDEX) - 13 templates WxO (orchestrator/specialist/single-meta agents, 3 connections, KB + runbook, observable_tool decorator, coercion helpers, Python tools, OpenAPI spec, backend filter endpoint, webhook validator HMAC, MCP connection) - 6 scripts (deploy idempotente con fallback ADK, undeploy, reset, check-adk-version, new-specialist scaffold, eval-agents runner) - 4 eval pieces (linter de best practices, runner, smoke-test, direct backend probe) + scenario templates - 8 subagentes Claude (.claude/agents/) — wxo-architect, wxo-agent-author, wxo-tool-author, runbook-author, mock-builder, backend-tool-builder, eval-author, web-layer-builder - Skill bundle fit-wxo-bootstrap/ (SKILL.md + 3 templates) listo para copiar a ~/.claude/skills/ - Web layer default FastAPI+HTMX con vista timeline observable + endpoint receptor de trazas - Docker compose Coolify-ready (healthcheck wget -qO-, sin labels Traefik, network split internal:true) - CI Gitea workflow con lint + smoke Best practices enforced por evals/lint_wxo_yaml.py: - A1: máx 10 tools por agente - A3: orchestrator sin tools de remediación - A6: agente sin propósito (react sin tools ni KB) - T1: @observable_tool obligatorio, no @tool directo - T3: _compat shim inline en tools.py - D1: docker-compose sin wget --spider - I-005: OpenAPI con description per-operation - I-009: sin labels Traefik manuales Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.9 KiB
Architecture Patterns
Árbol de decisión que usa el subagente wxo-architect cuando arrancás un
caso nuevo. Te llevo pregunta por pregunta.
Pregunta 1 — ¿Cuántos dominios distintos toca el caso?
Un "dominio" = una superficie funcional bien delimitada (identidad, operaciones, RRHH, finanzas, CRM, etc.).
- 0–1 dominio → 1 agente solo. Salí del árbol con la Topología Single.
- 2–5 dominios → N specialists + 1 orchestrator. Topología Multi-Specialist (estilo Cotemar).
- 6+ dominios → 2 capas: sub-orchestrators temáticos. Topología Multi-Capa.
Pregunta 2 — ¿El flujo es lineal o ramificado?
- Lineal y conocido (caso entra → A → B → C → D → resultado, siempre el mismo orden): aplicá Patrón Meta-Tool (estilo Dun). Una sola tool
run_full_caseque el backend orquesta internamente. El agente invoca esa tool y listo. - Ramificado (el agente decide qué hacer según el input): N tools individuales, agente razona. Cuidado con
recursion_limit=30(verknown-issues.md). - Mixto: parte lineal en meta-tool, parte ramificada en tools individuales. Es lo más común en casos reales.
Pregunta 3 — ¿Cada agente necesita razonar sobre procedimientos escritos?
Para cada agente, preguntate: "¿el LLM necesita citar un runbook para decidir bien?"
- Sí (procedural): este agente tiene KB con runbooks. Estilo Cotemar AD specialist.
- No (API-driven): este agente no tiene KB. El system prompt describe qué hace, las tools describen las acciones disponibles. Estilo Dun QA Studio.
- Mixto: KB para el "qué" + tools para el "cómo". Solo cuando los procedimientos son largos y variables.
Pregunta 4 — ¿Qué tipo de tools va a tener cada agente?
Por cada dominio, elegí el tipo de tool:
Opción A — OpenAPI (preferido si tenés backend propio)
Cuándo: tu solución incluye un backend (FastAPI, Express, lo que sea) que ya define endpoints REST.
Pros:
- Una sola fuente de verdad (el spec)
- ADK importa todo en un comando
- Cambios al backend = re-import del spec, no toques YAML de tool
Pattern del template (estilo Dun):
- Backend expone
/orchestrate-tools-spec.json(endpoint filtrado) - Filtra el openapi.json a una allowlist
PUBLIC_TOOLS - Fuerza
descriptionysecurityper-operation - Patch del
servers[0].urlen deploy time según env
Ver wxo/tools/openapi/_backend_filter_endpoint.py para el template.
Opción B — Python @tool (preferido para mocks/PoC)
Cuándo: estás prototipando, mocks externos, lógica simple por tool, sin backend que valga la pena mantener.
Pros:
- Rápido de escribir, una función = una tool
- Fácil de testear con pytest
- Bajo overhead
Pattern del template (estilo Cotemar):
- Una función
@observable_tool(name="x")por endpoint mockeado - Lee
BASE_URLdel environment de su connection requests.post(...)y devuelve dict_compat.pyinline al inicio del archivo
Ver wxo/tools/python/_template_tools.py.
Opción C — MCP (preferido si el sistema lo expone)
Cuándo: el sistema externo (HubSpot, Outline, una DB con MCP server, GitHub vía MCP, etc.) ya expone un MCP server.
Pros:
- Trae types + permisos del sistema
- Mantenido por el vendor
- Una sola connection MCP da acceso a todas las tools del server
Pattern del template:
- Una
connection.yamlde tipo MCP apuntando al server - ADK descubre las tools y las hace disponibles al agente
- Ver
wxo/tools/mcp/_template_mcp_connection.yaml
Decisión
| Situación | Recomendación |
|---|---|
| Es PoC, mocks externos | Python @tool |
| Tengo backend propio (FastAPI/Express) | OpenAPI |
| Conecto a SaaS con MCP server | MCP |
| Conecto a SaaS sin MCP server | OpenAPI (escribís el spec a mano) o Python |
| Mezcla | Cada agente puede usar más de uno |
Pregunta 5 — ¿Web layer: cuál stack?
Dos happy-paths probados:
Stack A — FastAPI + HTMX + Jinja (default)
Cuándo: demos, PoCs, control planes, kanbans, paneles operativos
Pros: SSR, sin build step, polling con hx-trigger es trivial,
una sola persona la mantiene
Contras: menos interactivo, menos componibilidad
Origen: estilo Cotemar (UNUS Kanban + Control Plane)
Stack B — FastAPI + React + Vite + Tailwind + zustand
Cuándo: app productiva con varios usuarios, mucha interacción, UI rica Pros: ecosistema React, lazy loading, state management decente Contras: build step, más superficie de mantenimiento Origen: estilo Dun (QA Studio)
Decisión
- Demo / interno / PoC → Stack A
- Producción / multi-usuario / app rica → Stack B
- Híbrido → Stack A para dashboards, Stack B para la app principal, unidos por reverse proxy
El template trae Stack A en web/_default_fastapi_htmx/. Stack B viene
documentado pero no implementado (el subagente Claude web-layer-builder
te lo arma según el caso).
Pregunta 6 — ¿Deploy: dónde corre esto?
Tres opciones soportadas:
| Target | Para qué | Ver |
|---|---|---|
| Coolify (FIT default) | Demos + PoCs productivos en *.fitlabs.dev |
docs/deployment-guide.md |
| Docker compose local | Dev / testing | docs/INSTRUCCIONES.md |
| K8s / Cloud Run / otro | Producción del cliente | docs/deployment-guide.md § "Other targets" |
Topologías resultantes
Topología Single (1 agente)
[user] → [agente único] ──tools──→ [sistema externo]
└──KB──→ [opcional]
Topología Multi-Specialist (Cotemar pattern)
┌──→ ad_specialist ──tools──→ AD
[user] → [N1] ────┼──→ ops_specialist ──tools──→ Ops
(orch) └──→ rrhh_specialist ──tools──→ HR
│
└─escalate→ runbook 03 (KB propia)
Topología Meta-Tool (Dun pattern)
[user] → [agente único] ──run_full_case(id)──→ [backend orquesta:
step 1, step 2, ...
write_audit cada paso]
Topología Multi-Capa (>5 dominios)
┌─→ [sub-orch identidad] ─→ ad, hr, vendors
[user] → [super-orch] ────┤
├─→ [sub-orch ops] ─→ dynatrace, k8s, db
└─→ [sub-orch finanzas] ─→ sap, billing
Cuando dudes
- ¿1 agente o varios? → Si los dominios son disjuntos, varios. Si todo es del mismo dominio, uno.
- ¿KB o no? → Si hay procedimiento escrito que el LLM debe seguir literal, sí. Si no, no.
- ¿OpenAPI o Python? → ¿Tenés backend? OpenAPI. ¿Mocks? Python.
- ¿Meta-tool o tools sueltas? → ¿El flujo es lineal y conocido? Meta-tool. ¿El agente decide? Sueltas.
Cuando dudes, arrancá con menos. Es más fácil splittear un agente en dos que mergear dos en uno.