Notas prácticas: Ingeniería de arneses: El agente desnudo: Por qué tu framework entrega
Guía práctica paso a paso de Notas prácticas: Harness Engineering: The Naked Agent: Por qué su framework incluye contratos, verificaciones y espacios para código reutilizable para los equipos que implementan este patrón.
Úselo como una versión reestructurada dirigida a operadores de las ideas presentadas en “Harness Engineering: The Naked Agent: Why Your Framework Hands You a Loop, Not a Harness — I”: etapas claras, espacios ordenados para el código y notas de recuperación que sobreviven a la transferencia de responsabilidades.
Parte 1: Un bucle de agente sin complementos parece poderoso hasta que recibe tráfico real. Aquí está la razón por la cual los fallos en producción suelen provenir de la falta de un mecanismo de soporte alrededor del modelo, y no del propio modelo.
En la Parte 1, una etapa básica funciona mejor cuando se trata como una superficie medible. Capture una transcripción ejemplar, un caso de fallo y la nota de reversión antes de ampliar el alcance. Documente tanto el camino óptimo como el de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son detalles adicionales aplicados posteriormente. Asigne un presupuesto de tokens por turno y por sesión; las herramientas basadas en agentes amplían el contexto de manera agresiva; los límites estrictos evitan que las demostraciones se conviertan en facturas inesperadas.
La mayoría de los fallos de los agentes no se deben al modelo. Residen en la capa de disciplina que falta alrededor de él. Aquí se muestra cómo es un agente de IA sin mecanismos de control en Claude Agent SDK y LangChain Deep Agents, así como las tres formas específicas en que falla bajo tráfico real.
Los fallos de los agentes se resuelven mejor cuando se tratan como una superficie medible. Capture una transcripción ejemplar, un caso de fallo y la nota de reversión antes de ampliar el alcance. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando falla un paso, el problema debe referirse a una sola responsabilidad y no a un proceso complicado. Asigne un presupuesto de tokens por turno y por sesión; las herramientas de agentes amplían el contexto de forma excesiva; los límites estrictos evitan que las demostraciones se conviertan en facturas inesperadas.
El modelo no es la variable
El modelo funciona mejor cuando se trata como una superficie medible. Capture un caso exitoso, un caso de fallo y la nota de reversión antes de ampliar el alcance. Considere esta etapa como un contrato entre las entradas y las salidas validadas. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace completaciones parciales silenciosas. Asigne un presupuesto de tokens por turno y por sesión; las herramientas agentes amplían el contexto de forma excesiva; los límites máximos evitan que las demostraciones se conviertan en facturas inesperadas.
Qué significa realmente “desnudo”
El concepto de “What naked” funciona mejor cuando se trata como una superficie medible. Capture un registro exitoso, un caso de fallo y la nota de reversión antes de ampliar el alcance. Registre los tiempos y el costo de tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de la fase de demostración a entornos compartidos. Exponga herramientas con esquemas limitados y etiquetas claras sobre efectos secundarios. Los administradores necesitan saber qué llamadas modifican el estado antes de aprobarlas automáticamente.
import anthropic
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY
TOOLS = [
{"name": "search_flights",
"description": "Search flights between two cities for a date.",
"input_schema": {"type": "object", "properties": {
"origin": {"type": "string"}, "destination": {"type": "string"},
"date": {"type": "string", "description": "YYYY-MM-DD"}},
"required": ["origin", "destination", "date"]}},
{"name": "book_flight",
"description": "Book a specific flight.",
"input_schema": {"type": "object", "properties": {
"flight_id": {"type": "string"}, "passenger_name": {"type": "string"}},
"required": ["flight_id", "passenger_name"]}},
]
def run_naked(user_msg: str) -> str:
messages = [{"role": "user", "content": user_msg}]
while True: # ① no iteration cap
resp = client.messages.create(
model="claude-sonnet-4-6", max_tokens=1024,
tools=TOOLS, messages=messages,
)
if resp.stop_reason != "tool_use":
return resp.content[0].text
call = next(b for b in resp.content if b.type == "tool_use")
result = dispatch(call.name, call.input)
# ② direct side effect, no check
messages.extend([
# ③ whole history, every turn
{"role": "assistant", "content": resp.content},
{"role": "user", "content": [{"type": "tool_result",
"tool_use_id": call.id, "content": result}]},
])
El agente “naked” en el Claude Agent SDK
El agente “nudo” en la fase de pruebas funciona mejor cuando se trata como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Mantenga la configuración fuera del código de la aplicación; los archivos de entorno, los almacenes de datos confidenciales y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema. Exponga herramientas con esquemas limitados y etiquetas explícitas de efectos secundarios. Los administradores necesitan saber qué llamadas modifican el estado antes de aprobarlas automáticamente. El agente “nudo” en la fase de pruebas funciona mejor cuando se trata como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Prefiera unidades pequeñas y probables sobre scripts extensos; cuando un paso falla, el fallo debe referirse a una sola responsabilidad y no a un proceso complicado.
import asyncio
from claude_agent_sdk import (
query, ClaudeAgentOptions, tool,
create_sdk_mcp_server, AssistantMessage, ResultMessage,
)
@tool("search_flights", "Search flights between two cities for a date.",
{"origin": str, "destination": str, "date": str})
async def search_flights(args):
# ① no check that date exists
hits = flights_api.search(**args)
return {"content": [{"type": "text", "text": str(hits)}]}
@tool("book_flight", "Book a specific flight.",
{"flight_id": str, "passenger_name": str})
async def book_flight(args):
# ② destructive, ungated
confirmation = flights_api.book(**args)
return {"content": [{"type": "text", "text": confirmation}]}
server = create_sdk_mcp_server("travel", tools=[search_flights, book_flight])
async def main():
options = ClaudeAgentOptions(
mcp_servers={"travel": server},
allowed_tools=["mcp__travel__search_flights",
"mcp__travel__book_flight"],
)
async for msg in query(prompt="Rebook this customer for March 32nd.",
options=options):
if isinstance(msg, AssistantMessage):
for b in msg.content:
if hasattr(b, "text"):
print(b.text)
elif isinstance(msg, ResultMessage):
print("done:", msg.subtype)
# ③ no state survives this run
El agente “nudo” en LangChain Deep Agents
Para el agente desnudo en la etapa actual, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas. Autentíquese en la pasarela y vuelva a autorizarse en el plano de datos. Un token portador por sí solo no constituye un límite entre tenencias.
from langchain.tools import tool
from deepagents import create_deep_agent
@tool
def search_flights(origin: str, destination: str, date: str) -> str:
"""Search flights between two cities for a date (YYYY-MM-DD)."""
return str(flights_api.search(origin, destination, date))
# ① no date check
@tool
def book_flight(flight_id: str, passenger_name: str) -> str:
"""Book a specific flight."""
return flights_api.book(flight_id, passenger_name)
# ② ungated side effect
agent = create_deep_agent(
# ③ the loop, no controls
model="anthropic:claude-sonnet-4-6",
tools=[search_flights, book_flight],
)
result = agent.invoke({"messages": [{"role": "user",
"content": "Rebook this customer for March 32nd."}]})
print(result["messages"][-1].content)
# Ask a follow-up in a second invoke, and it starts from zero: no thread,
# no memory.
Vea cómo se rompe de tres maneras
Para monitorear su funcionamiento, divídalo en tres etapas: define las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Registra los tiempos de ejecución y el costo de los tokens o consultas junto con los resultados funcionales. Tener visibilidad temprana del costo evita facturas inesperadas cuando el proceso pasa de entornos de demostración a entornos compartidos. Autentica en la pasarela y vuelve a autorizar en el plano de datos; un token portador por sí solo no constituye un límite entre tenencias.
Fallo 1: un argumento mal formado llega a una llamada destructiva
Para el Falla 1 de etapa mal formada, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Guarde la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben encontrarse en un lugar que los operadores puedan auditar sin tener que leer todo el sistema. Autentique en la pasarela y vuelva a autorizar en el plano de datos. Un token portador por sí solo no constituye un límite entre tenencias. Para el Falla 1 de etapa mal formada, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando un paso falla, el error debe indicar una única responsabilidad y no un proceso complicado.
book_flight(flight_id=”AC-PHANTOM”, passenger_name=”J. Moffatt”)
# -> “Booked.” The action fired. Nothing in the loop asked whether it should.
Fallo 2: el contexto se descontrola y la calidad empeora silenciosamente
Al abordar la etapa en la que el contexto se descontrola debido al Fallo 2, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas. Registre el nombre de la herramienta, el hash de los argumentos, la latencia y el resultado de cada llamada. Depurar sin ese rastro desperdicia horas.
Fallo 3: una herramienta da error, pero el agente informa éxito
Al trabajar en la etapa de herramientas del Falla 3, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Registre los tiempos y el costo de tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de la versión de demostración a entornos compartidos. Registre el nombre de la herramienta, el hash de los argumentos, la latencia y el resultado de cada llamada. Depurar bucles sin ese historial desperdicia horas.
La estructura que seguirá cada parte
Al trabajar en la fase “La forma de cada parte”, anote primero el contrato: los datos de entrada requeridos, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Guarde la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema. Registre el nombre de la herramienta, el hash de los argumentos, la latencia y el resultado de cada llamada. Depurar sin ese rastro desperdicia horas. Al trabajar en la fase “La forma de cada parte”, anote primero el contrato: los datos de entrada requeridos, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Prefiera unidades pequeñas y probables sobre scripts extensos. Cuando falla un paso, el fallo debe apuntar a una única responsabilidad y no a un proceso complicado.
Haga esto hoy
La etapa “Haz esto hoy” funciona mejor cuando se trata como una superficie medible. Capture un registro exitoso, un caso de fallo y la nota de reversión antes de ampliar el alcance. Considere esta etapa como un contrato entre las entradas y las salidas validadas. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas. Exponga herramientas con esquemas limitados y etiquetas explícitas de efectos secundarios. Los administradores necesitan saber qué llamadas modifican el estado antes de aprobarlas automáticamente.
El modelo es la parte fácil
El modelo funciona mejor cuando se trata como una superficie medible. Capture un caso exitoso, un caso de fallo y la nota de reversión antes de ampliar el alcance. Registre los tiempos y el costo en tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de la versión de demostración a entornos compartidos. Asigne un presupuesto de tokens por turno y por sesión; las herramientas agenciales amplían el contexto de manera intensiva, por lo que los límites máximos evitan que las demostraciones se conviertan en facturas sorpresa.
Lista de verificación operativa
Al trabajar en la etapa de la lista de verificación operativa, anote primero los requisitos del contrato: entradas necesarias, señal de éxito y qué ocurre en caso de fallo parcial. Esa lista garantiza que los cambios posteriores en el código sean transparentes.
Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son ajustes realizados posteriormente.
Registra el nombre de la herramienta de registro, el hash de los argumentos, la latencia y el resultado de cada llamada. Depurar agentes en bucle sin esa información desperdicia horas.
Mantén el estado del gráfico simple y con tipos definidos. Los bloques anidados ocultan qué nodo escribió qué campo y dificultan reanudar el proceso tras interrupciones.
Añade una prueba de funcionamiento básica que ejecute la ruta crítica en CI con configuraciones fijas, y no con APIs pagadas en tiempo real, siempre que lo permitan los presupuestos.
Registra los tiempos de ejecución y el costo de tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando la ruta pasa de entornos de demostración a entornos compartidos.
Antes de promocionar la solución, congela las versiones, captura una transcripción de referencia para la ruta crítica y confirma los pasos para revertir cambios. Los entornos compartidos requieren límites de velocidad, verificaciones de asignación y un responsable claro para la rotación de credenciales. Prefiere una fiabilidad sencilla a demostraciones ingeniosas pero puntuales.
Nota por lotes para 765280e2df21: mantener las claves del proveedor fuera del repositorio, establecer un límite para los tokens por sesión y almacenar las transcripciones junto a los archivos de evaluación para que los cambios posteriores en el modelo sigan siendo comparables.