CH 09 · Subsistemas centrales y el flujo de un mensaje
Objetivo del capítulo
CH 08 explicó que dsh es "un árbol de plugins"; este capítulo hace zoom: qué maneja cada plugin clave (subsistema) del árbol, cómo se coordinan, y luego sigue un mensaje de principio a fin — desde cuando pulsas Enter hasta cuando responde, qué pasa entre medias. Cuando veas estas dos cosas, sabrás cómo funciona dsh internamente.
Subsistemas centrales: el equipo de la cocina trasera del restaurante
Continuando con el pequeño restaurante de CH 08: la cocina no es una persona, sino un equipo con divisiones claras de trabajo, cada uno manejando lo suyo, pasándoselo entre sí. Los subsistemas centrales de dsh son este equipo:
| Subsistema | Contraparte en el personal | Qué maneja |
|---|---|---|
agent-loop | Chef principal | El driver por defecto: decide "qué hacer a continuación" — pedir al modelo, llamar herramientas, recoger resultados; todo el bucle lo conduce él |
llm | Operador de la línea de pedidos para llevar | Conecta con modelos externos vía adaptadores, envía mensajes, recibe respuestas |
tools | Armario de herramientas + portero | Registro de herramientas + pipeline de ejecución controlada; cada agent usa el suyo (aislamiento por scope) |
system-prompt | Bandeja de preparación | Une los fragmentos de prompt y los schemas de herramientas registrados por varios plugins en "lo que este plato muestra al modelo" |
session | Libro de cuentas | Log de sesión append-only: lo que enviaste, lo que respondió el modelo, qué herramientas corrieron — todo registrado |
scope | Aislamiento de puesto | Hace que el registro de cada agent solo sea efectivo en su propia celda, sin cruces |
Cómo se coordinan, mira este diagrama:
Una regla nemotécnica: el chef principal (agent-loop) da las órdenes, la bandeja (system-prompt) prepara, el operador de la línea (llm) pide para llevar, el armario de herramientas (tools) entrega las herramientas, y todos los resultados se apuntan en el libro de cuentas (session). El libro de cuentas es la estrella del siguiente capítulo.
Una unidad clave: step y turn
Antes de mirar el flujo, distingue primero dos términos; son la base para entender toda la cadena:
- step = una petición al modelo + las herramientas que llama. El modelo "piensa + actúa" una vez es un step.
- turn = cero o más steps. Desde recoger tu primera entrada hasta que ya no quede trabajo pendiente.
¿Por qué una sola respuesta puede tener varios steps? Porque el modelo a menudo hace "piensa un poco → llama una herramienta → ve el resultado y piensa otra vez → llama otra..." hasta que siente que es suficiente y entonces da la respuesta final. Toda esta cadena es un turn, y cada "piensa + actúa" dentro es un step. Las palabras oficiales: un turn se abre antes de recoger la primera entrada, y se cierra cuando ya no queda trabajo pendiente.
Una analogía de la vida real: pides una comida (turn), el camarero puede ir y venir varias veces (step) — primero confirma si el plato está disponible, luego lo sirve, luego pregunta si quieres algo extra — hasta que el pedido está completamente servido.
El flujo de un mensaje: desde tu tecla Enter hasta su respuesta
Ahora recorre un mensaje de principio a fin. Sigue este diagrama de arriba hacia abajo:
① turn/start: el turn se abre. Antes de pulsar Enter, este turn no ha empezado; después de pulsar, el turn primero se abre, entrando en "recoger entrada".
② Recoger entrada (inbox). Todas las entradas van primero a un buzón llamado inbox. El mensaje que enviaste despertará inmediatamente al chef principal para que empiece a trabajar; mientras que el "contexto inyectado" (el tipo que viste en CH 04) se queda primero en el buzón, esperando a que otro mensaje real lo despierte — así que "inyectar datos" por sí solo no interrumpirá el flujo.
③ Ensamblar: prompt + schema de herramientas. system-prompt une los fragmentos registrados por varios plugins en un plato, diciéndole al modelo "quién eres, qué herramientas hay disponibles, cómo son las herramientas".
④ agent/pre-step: decidir qué ve el modelo. Este es el primer "punto de extensión en vivo" — los plugins pueden reescribir el contenido que se va a enviar aquí, o directamente rechazarlo. Si se rechaza o se reescribe a vacío, el turn se cierra igualmente y se registra como siempre; el log muestra "lo intentó una vez pero no corrió".
⑤ step/start: ledger + tomar el historial. El mensaje que enviaste se escribe en el log de sesión como user/message; al mismo tiempo, el historial del modelo para este turn se proyecta desde el log (deriveMessages()). Todo lo que ve el modelo viene del log — esta es una línea a la que volveremos una y otra vez.
⑥ Pedir al modelo → recibir la respuesta. agent/request envía la petición (interceptable), llm/stream transmite en streaming, y la respuesta del modelo se escribe en el log como assistant/message.
⑦ ¿Necesita llamar a una herramienta? Si el modelo decide "necesito actuar", es tool/call → ejecutar → el resultado tool/result se escribe de vuelta en el log. Hay puntos de interceptación antes y después de la ejecución (pre/post-execute). Si no se necesita ninguna herramienta, salta al siguiente step.
⑧ step/end: ¿más trabajo? Si el resultado de la herramienta necesita que el modelo lo procese otra vez (o llega una nueva entrada), abre otro step, vuelve a "recoger entrada"; hasta que ya no quede trabajo pendiente, va a agent/turn-stopping → turn/end, este turn termina, y ves la respuesta final.
Una distinción clave que debes tener en mente: el lado derecho del diagrama marca dos tipos de eventos —
- Eventos persistentes (
turn/*,step/*,user/message,assistant/*,tool/*): escritos en el log de sesión, siguen ahí después del reinicio; - Puntos de extensión en vivo (
agent/pre-step,agent/request,llm/stream,tools/*): solo efectivos mientras se ejecuta; los plugins los usan para interceptar y cambiar el comportamiento, pero ellos mismos no quedan en el libro de cuentas.
Esto hace eco al "los eventos son puntos de extensión" de CH 08: para observar o interceptar el trabajo en ejecución, vigila los eventos en vivo; para dejar hechos persistentes, usa los eventos persistentes.
De dónde viene la memoria del modelo
Una línea: el log de sesión es el contexto que ve el modelo. Lo que el modelo "recuerda" en este turn no es algo que recuerde él mismo; es el historial que el sistema proyecta desde el log — así que "lo que ve el modelo es lo que está registrado" es una regla dura en dsh: cualquier cosa que llegue a una petición al modelo debe ser reconstruible desde el log, y el runtime lo comprueba con un invariante. Esta regla es el eje de todo el diseño; la cubriremos en CH 10.
Una referencia rápida con lo anterior: la "vista de Trajectory" que viste en CH 04 — esa fila de timeline ASSISTANT / TOOL — por debajo no es más que una visualización de este log de sesión. Lo que dijo el modelo, qué herramientas llamó, cuáles fueron los resultados — todo se renderiza desde el log. Así que cuando preguntas "¿por qué recuerda lo que dije antes?", la respuesta es sencilla: no es el modelo el que recuerda, es el log el que recuerda — cada vez antes de una consulta, el sistema proyecta el historial desde el log y se lo pasa al modelo.
Lo que aprendiste en este capítulo
- [ ] Enunciar la división de trabajo de los subsistemas centrales (agent-loop / llm / tools / system-prompt / session), y explicar cómo se coordinan
- [ ] Explicar la diferencia entre step y turn (step = una petición al modelo + herramientas; turn = cero o más steps)
- [ ] Recorrer el flujo completo de un mensaje siguiendo el diagrama: turn/start → recoger entrada → ensamblar → pre-step → step/start → pedir al modelo → tool call → step/end → turn/end
- [ ] Distinguir eventos persistentes de puntos de extensión en vivo, y enunciar el propósito de cada uno (dejar evidencia vs interceptar)
- [ ] Enunciar el significado de la regla "lo que ve el modelo es lo que está registrado"
