Lo que 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, sin nada conectado a mano. En 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 ejecución
No necesitas claves de API para este tutorial: el agente de eco no llama a un LLM. Los agentes basados en LLM vienen después (consulta ¿Qué sigue?).
1. Genera la estructura del proyecto
uvx cookiecutter gh:btech-software/agent-lab --directory cookiecutterResponde las preguntas; los valores predeterminados te dan un proyecto llamado My Agent App:
cd my-agent-appLa estructura generada es un consumidor ligero del framework, no un fork. btech-agent-lab
es una dependencia normal en pyproject.toml; tu código vive junto a ella y la extiende
a través de la API pública.
2. Entiende lo que obtuviste
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 agente en sí:
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 a tener en cuenta:
@discoverable_agent("my_agent_app_echo"): ese único decorador registra la clase bajo unagent_type. Sin modificar el registro ni cambiar el esquema: 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 agrega los proveedores correspondientes acore/container.py(consulta la Guía para desarrolladores).
3. Pruébalo antes de ejecutarlo
Las pruebas unitarias de la estructura generada inician 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 está formado por la aplicación (puerto 18000), PostgreSQL con pgvector (tres bases de datos: relacional, vectores y checkpoints de LangGraph), Redis para actualizaciones de estado mediante pub/sub, y Vault para los secretos. La documentación interactiva de OpenAPI está en http://localhost:18000/docs.
La autenticación está deshabilitada en la estructura generada (
auth.enabled: false). Cuando la habilites, cada solicitud 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 a través de 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 luego 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 recorrido de ida y vuelta puso a prueba todo el stack: solicitud REST → búsqueda en el registro → contenedor
de DI → tu agente → persistencia del mensaje (y la respuesta también se almacena; revisa
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á, el rastreo simplemente se desactiva, sin cambios de 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 collector:
# 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, luego abre Grafana en
http://localhost:3000 (admin/admin) y explora el
dashboard Agent-Lab: el span HTTP, las consultas SQL y, para los agentes basados en LLM,
cada llamada al modelo con el conteo 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 en un cliente MCP
La estructura generada ya incluye una herramienta MCP (my_agent_app/mcp/tools.py) expuesta en
/mcp, junto con las herramientas de descubrimiento de agentes, historial y mensajería del framework. Pruébala
con el 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.
¿Qué sigue?
| Página | |
|---|---|
| 🏗️ Crea un agente real (basado en LLM) | Guía para desarrolladores: creación de flujos de trabajo agénticos |
| ⚙️ Configura bases de datos, autenticación y secretos | Referencia de configuración |
| 🌐 Catálogo completo de endpoints | Referencia de la API REST |
| 🧪 Evalúa el comportamiento de los agentes con un LLM como juez | Pruebas y simulaciones |
| 🚀 Llévalo a producción | Guía de implementación |