Claude Skills: Cómo Construir Custom Agents que Realmente Funcionan en Producción
Learn to build Claude Skills custom agents in production: atomic skill architecture, tool use patterns, orchestration, and error handling in Python.
El 80% de los Claude Agents en Producción Son Chatbots Glorificados
Le das acceso a Claude a tu codebase. Le conectas tres tools. Y esperas que "funcione como un agente".
No funciona. Te devuelve respuestas genéricas, se pierde en contexto irrelevante, y falla justo cuando más lo necesitas.
*El problema real no es Claude. Es que no has definido sus Skills.*
Un Claude Skill no es un prompt bonito. Es una capacidad acotada, con inputs/outputs definidos, herramientas específicas y lógica de error explícita. La diferencia entre un chatbot y un custom agent real.
Este artículo te enseña a construir claude skills custom agents que van de prototipo a producción sin romperse.
---
Qué es un Claude Skill y Por Qué Importa
La mayoría de developers piensa que un agent es Claude + muchas tools.
Error. Eso es un modelo confundido con demasiado contexto.
Un Skill es una unidad de comportamiento autónomo:
→ Tiene una responsabilidad única
→ Sabe cuándo usarse y cuándo no
→ Tiene herramientas propias, no compartidas con todo el sistema
→ Falla de forma predecible
El concepto real de claude skills custom agents es: cada Skill es un microservicio cognitivo. Claude orquesta Skills. Los Skills ejecutan trabajo.
*La arquitectura real no es Claude haciendo todo. Es Claude delegando en Skills especializados.*
---
Arquitectura Base: Skill como Unidad Atómica
Antes de escribir código, define estos tres elementos para cada Skill:
1. Trigger claro: ¿Cuándo se activa este Skill y cuándo no?
2. Herramientas acotadas: Exactamente las tools que necesita, ni una más.
3. Output contractado: Formato de salida predecible que el sistema pueda consumir.
❌ Enfoque común (agent genérico):
```python
client.messages.create(
model="claude-opus-4-5",
tools=[
search_web, read_file, write_file,
send_email, query_db, call_api,
generate_image, analyze_data # 8 tools mezcladas
],
messages=[{"role": "user", "content": user_input}]
)
```
✅ Enfoque correcto (Claude Skill acotado):
```python
Skill específico: solo analiza PRs de GitHub
class CodeReviewSkill:
TOOLS = ["get_pr_diff", "get_file_context", "post_review_comment"]
SYSTEM_PROMPT = """
Eres un reviewer de código especializado.
SOLO analizas pull requests de GitHub.
NUNCA ejecutas código ni modificas archivos directamente.
Output siempre en formato JSON con: issues[], suggestions[], severity.
"""
def run(self, pr_url: str) -> ReviewResult:
response = client.messages.create(
model="claude-opus-4-5",
system=self.SYSTEM_PROMPT,
tools=self._get_tools(), # Solo 3 tools, no 8
messages=[{"role": "user", "content": f"Review este PR: {pr_url}"}]
)
return self._parse_structured_output(response)
```
El Skill de code review no sabe nada de emails. No sabe nada de bases de datos. *Eso es precisamente lo que lo hace fiable.*
---
Step by Step: Construir tu Primer Claude Skill
Paso 1: Define el Contrato del Skill
Antes de una línea de código, escribe esto:
```python
from dataclasses import dataclass
from typing import List, Optional
@dataclass
class SkillContract:
name: str
trigger_condition: str # Cuándo se activa
input_schema: dict # Qué recibe
output_schema: dict # Qué devuelve SIEMPRE
tools_allowed: List[str] # Herramientas permitidas
fallback_behavior: str # Qué hace si falla
Ejemplo concreto
code_review_contract = SkillContract(
name="CodeReviewSkill",
trigger_condition="Cuando hay una PR URL y se pide análisis de código",
input_schema={"pr_url": "string", "focus_areas": "list[string]"},
output_schema={
"issues": "list",
"severity": "low|medium|high|critical",
"approved": "boolean"
},
tools_allowed=["get_pr_diff", "get_file_context", "post_review_comment"],
fallback_behavior="Devolver issues=[], severity='unknown', approved=False"
)
```
Este contrato es el documento de diseño y la validación en runtime. Dos en uno.
Paso 2: Implementa el Tool Use con Manejo de Errores Real
```python
import anthropic
import json
from typing import Any
client = anthropic.Anthropic()
def run_skill_with_tools(skill_contract: SkillContract, user_input: str) -> dict:
messages = [{"role": "user", "content": user_input}]
Agentic loop con límite de iteraciones
max_iterations = 10
iteration = 0
while iteration < max_iterations:
iteration += 1
response = client.messages.create(
model="claude-opus-4-5",
system=build_system_prompt(skill_contract),
tools=get_tools_for_skill(skill_contract.tools_allowed),
messages=messages,
max_tokens=4096
)
Si Claude termina sin tool use
if response.stop_reason == "end_turn":
return extract_structured_output(response, skill_contract.output_schema)
Si Claude quiere usar una tool
if response.stop_reason == "tool_use":
tool_results = []
for block in response.content:
if block.type == "tool_use":
Validar que la tool está permitida
if block.name not in skill_contract.tools_allowed:
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": "ERROR: Tool no permitida en este Skill",
"is_error": True
})
continue
result = execute_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result)
})
Continuar el loop con los resultados
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
Fallback si se exceden iteraciones
return json.loads(skill_contract.fallback_behavior)
```
El límite de iteraciones no es opcional. Es la diferencia entre un agent que controlas y uno que te factura tokens infinitos.
Paso 3: Compón Skills en un Orquestador
Aquí está el verdadero poder de los claude skills custom agents: la composición.
```python
class AgentOrchestrator:
def __init__(self):
self.skills = {
"code_review": CodeReviewSkill(),
"dependency_audit": DependencyAuditSkill(),
"documentation": DocGenerationSkill(),
"test_generation": TestGenSkill()
}
def route_to_skill(self, user_request: str) -> dict:
Claude como router, no como executor
routing_response = client.messages.create(
model="claude-haiku-4-5", # Modelo rápido para routing
system="""Eres un router. Clasifica la request en exactamente
uno de estos skills: code_review, dependency_audit,
documentation, test_generation.
Responde SOLO con el nombre del skill en JSON: {"skill": "..."}.""",
messages=[{"role": "user", "content": user_request}],
max_tokens=50
)
skill_name = json.loads(routing_response.content[0].text)["skill"]
skill = self.skills[skill_name]
return skill.run(user_request)
```
Usa claude-haiku para routing y claude-opus para ejecución. El routing es simple clasificación — no necesitas el modelo más potente para eso.
---
Los 3 Errores que Arruinan los Custom Agents
❌ Error 1: System prompts genéricos
Un system prompt de 2.000 palabras que intenta cubrir todos los casos posibles. Claude se pierde. El Skill falla silenciosamente.
✅ Corrección: Cada Skill tiene su propio system prompt de máximo 300 palabras. Específico, acotado, sin ambigüedad.
❌ Error 2: Output no estructurado
Claude devuelve texto libre y el sistema intenta parsearlo con regex. Falla en producción el tercer día.
✅ Corrección: Define el schema de output en el system prompt y valídalo con Pydantic antes de que llegue al resto del sistema.
```python
from pydantic import BaseModel, ValidationError
class ReviewOutput(BaseModel):
issues: list[str]
severity: str
approved: bool
def parse_skill_output(raw_response: str) -> ReviewOutput:
try:
data = json.loads(raw_response)
return ReviewOutput(**data)
except (json.JSONDecodeError, ValidationError):
Fallback predecible, nunca crash
return ReviewOutput(issues=[], severity="unknown", approved=False)
```
❌ Error 3: Sin aislamiento entre Skills
Un Skill modifica estado global que otro Skill consume. Condición de carrera en producción. Imposible de debuggear.
✅ Corrección: Cada Skill es stateless. El estado vive en la capa de orquestación, nunca dentro del Skill.
---
Cuándo Usar Claude Skills vs. Un Agent Monolítico
No todo necesita una arquitectura de Skills. Esta es la regla:
→ Task de menos de 3 pasos: Un agent simple con el modelo directamente.
→ Task con pasos > 3 o herramientas > 4: Arquitectura de Skills.
→ Task que se repite con variaciones: Skill reutilizable obligatorio.
→ Task que necesita auditabilidad: Skill con logging estructurado en cada paso.
*La complejidad de la arquitectura debe ser proporcional a la complejidad del problema.*
Equipos como los de Anthropic construyendo claude code agent teams usan exactamente este patrón: agentes especializados que se coordinan, no un superagente que lo hace todo.
---
Conclusión: Skills como Unidad de Arquitectura
Los claude skills custom agents no son una feature de Anthropic. Son una decisión de arquitectura que tú tomas.
Lo que más developers necesitan recordar:
→ Un Skill = una responsabilidad. Sin excepciones.
→ Define el contrato primero, el código después.
→ Output estructurado con validación Pydantic en producción siempre.
→ Usa Haiku para routing, Opus para ejecución compleja.
→ Límite de iteraciones en cada agentic loop. Sin negociación.
→ Estado en la capa de orquestación, nunca dentro del Skill.
Los agents que se rompen en producción no fallan por Claude. Fallan porque nadie definió los límites de lo que cada parte del sistema debe hacer.
*Define los Skills. El resto se sostiene solo.*
Lee el artículo completo en brianmenagomez.com


