Qué vas a crear
Una aplicación Agent-Lab completa y ejecutable: un servicio FastAPI que aloja un agente de eco, un servidor MCP, persistencia en PostgreSQL e instrumentación con OpenTelemetry, todo generado con un solo comando y sin nada conectado a mano. Por el camino crearás una instancia de agente por REST, le enviarás un mensaje y observarás las trazas del framework.
Requisitos previos
- Python 3.12+ y uv (
pip install uv) - Docker (u otro entorno de ejecución de contenedores) en funcionamiento
Este tutorial no necesita claves de API: el agente de eco no llama a ningún LLM. Los agentes basados en LLM vienen después (consulta ¿Y ahora qué?).
1. Genera el proyecto
uvx cookiecutter gh:btech-software/agent-lab --directory cookiecutterResponde a las preguntas; los valores por defecto te dan un proyecto llamado My Agent App:
cd my-agent-appEl scaffold es un consumidor ligero del framework, no un fork. btech-agent-lab
es una dependencia normal en pyproject.toml; tu código vive a su lado y lo amplía
mediante la API pública.
2. Entiende lo que has obtenido
my-agent-app/
├── my_agent_app/
│ ├── main.py # the composition root — one create_app() call
│ ├── core/container.py # your DI container — add providers here
│ ├── agents/echo/agent.py # your first agent (echo)
│ └── mcp/tools.py # your first MCP tool
├── config-dev.yml / config-test.yml / config-docker.yml
├── tests/ # unit tests (no infra) + optional testcontainers suite
├── compose.yml # app + postgres (pgvector) + redis + vault
└── Makefile, docker/, .github/, pyproject.tomlAbre my_agent_app/main.py: esta es toda la aplicación:
from agent_lab import create_app
from my_agent_app.core.container import Container
# An explicit scan_packages list replaces agent_lab's DEFAULT_SCAN_PACKAGES:
# only this project's agents, MCP tools, and prompts are discovered — none of
# the framework's built-in examples. Add "agent_lab.services.agent_types" or
# "agent_lab.interface.mcp" here if you want the built-ins back.
app = create_app(
container=Container(),
scan_packages=[
"my_agent_app.agents",
"my_agent_app.mcp",
],
)Y my_agent_app/agents/echo/agent.py, el propio agente:
from langchain_core.messages import AIMessage
from langgraph.graph import MessagesState
from agent_lab import AgentBase, AgentUtils, discoverable_agent
from agent_lab.interface.api.messages.schema import Message, MessageRequest
from agent_lab.services.tasks import TaskProgress
@discoverable_agent("my_agent_app_echo")
class EchoAgent(AgentBase):
"""Minimal agent: echoes the incoming message without calling an LLM."""
def __init__(self, agent_utils: AgentUtils):
super().__init__(agent_utils)
def create_default_settings(self, agent_id: str, schema: str):
pass
def get_input_params(self, message_request: MessageRequest, schema: str) -> dict:
return message_request.model_dump()
def process_message(self, message_request: MessageRequest, schema: str) -> Message:
message_content, response_data = self.format_response(
MessagesState(
messages=[AIMessage(content=f"Echo: {message_request.message_content}")]
)
)
self.task_notification_service.publish_update(
task_progress=TaskProgress(
agent_id=message_request.agent_id,
status="completed",
message_content=message_content,
response_data=response_data,
)
)
return Message(
message_role="assistant",
message_content=message_content,
response_data=response_data,
agent_id=message_request.agent_id,
)Dos cosas que conviene observar:
@discoverable_agent("my_agent_app_echo"): ese único decorador registra la clase con unagent_type. Sin modificar el registro ni cambiar esquemas: la API REST validaagent_typecontra el registro de forma dinámica.AgentUtilsse inyecta a través del constructor mediante el contenedor de DI. Declara más dependencias conextra_deps=("my_provider",)y añade los proveedores correspondientes acore/container.py(consulta la Guía para desarrolladores).
3. Pruébalo antes de ejecutarlo
Las pruebas unitarias del scaffold arrancan toda la aplicación sin ninguna infraestructura:
uv lock && uv sync --group dev --group test
make test_unitTambién tienes la variante de integración: make test_integration levanta contenedores reales de Postgres,
Redis y Vault mediante testcontainers (requiere Docker).
4. Ejecuta la aplicación
docker compose up --build -d
curl http://localhost:18000/status/livenessEl stack lo forman la aplicación (puerto 18000), PostgreSQL con pgvector (tres bases de datos: relacional, vectores y checkpoints de LangGraph), Redis para las actualizaciones de estado pub/sub y Vault para los secretos. La documentación interactiva de OpenAPI está en http://localhost:18000/docs.
La autenticación está desactivada en el scaffold (
auth.enabled: false). Cuando la actives, cada petición necesitará un token bearer; consulta Autenticación con Keycloak.
5. Habla con tu agente por REST
Los agentes son instancias de una implementación, que se crean y configuran mediante la API. Crea una:
curl -s -X POST http://localhost:18000/agents/create \
-H "Content-Type: application/json" \
-d '{"agent_name": "my-first-agent", "agent_type": "my_agent_app_echo"}' | jqCopia el id de la respuesta y envíale un mensaje:
curl -s -X POST http://localhost:18000/messages/post \
-H "Content-Type: application/json" \
-d '{
"agent_id": "<agent_id>",
"message_role": "human",
"message_content": "Hello, framework!"
}' | jqLa respuesta llega de forma síncrona:
{
"message_role": "assistant",
"message_content": "Echo: Hello, framework!",
"agent_id": "<agent_id>",
"id": "…"
}Ese viaje de ida y vuelta ha recorrido todo el stack: petición REST → búsqueda en el registro → contenedor
de DI → tu agente → persistencia del mensaje (la respuesta también se guarda; compruébalo con
POST /messages/list). El catálogo completo está en la Referencia de la API REST.
6. Observa la traza
La observabilidad de Agent-Lab es simplemente OpenTelemetry. Cuando la variable de entorno
OTEL_EXPORTER_OTLP_ENDPOINT está definida, la aplicación exporta trazas, métricas y logs OTLP; cuando
no lo está, la trazabilidad simplemente se desactiva, sin cambios en el código en ningún caso.
Ejecuta el stack de Grafana incluido en el framework (desde el repositorio del framework) y apunta tu aplicación a su colector:
# In the agent-lab framework repo — collector on :4318, Grafana UI on :3000
docker compose -f compose-grafana.yml up --build
# Back in your project — restart the app with the endpoint set
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 docker compose up --build -dEnvía otro mensaje, abre Grafana en
http://localhost:3000 (admin/admin) y explora el
panel Agent-Lab: el span HTTP, las consultas SQL y, en los agentes basados en LLM,
cada llamada al modelo con el recuento de tokens. ¿Prefieres una plataforma alojada de observabilidad de LLM? Define
LANGFUSE_HOST/LANGFUSE_PUBLIC_KEY/LANGFUSE_SECRET_KEY (o LANGWATCH_ENDPOINT/
LANGWATCH_API_KEY) en su lugar; encontrarás los detalles en la Guía de observabilidad.
7. Conócelo desde un cliente MCP
El scaffold ya incluye una herramienta MCP (my_agent_app/mcp/tools.py) expuesta en
/mcp, junto con las herramientas del framework para descubrir agentes, consultar el historial y enviar mensajes. Pruébala
con MCP Inspector:
npx @modelcontextprotocol/inspectorConéctate a http://localhost:18000/mcp (Streamable HTTP), lista las herramientas y llama a
my_agent_app_hello_tool. El mismo servidor funciona con Claude Desktop y con cualquier cliente
MCP; consulta la Guía del servidor MCP.
¿Y ahora qué?
| Página | |
|---|---|
| 🏗️ Crear un agente real (basado en LLM) | Guía para desarrolladores — Crear flujos de trabajo agénticos |
| ⚙️ Configurar bases de datos, autenticación y secretos | Referencia de configuración |
| 🌐 Catálogo completo de endpoints | Referencia de la API REST |
| 🧪 Evaluar el comportamiento del agente con un LLM como juez | Pruebas y simulaciones |
| 🚀 Ponerlo en producción | Guía de despliegue |