Tipos de mensajes de LangChain

En LangChain, todas las conversaciones se transmiten a través de objetos de mensaje (Message). Comprender el propósito de los distintos tipos de mensajes es la base para escribir un Agent.


Cuatro tipos de mensajes principales

LangChain define cuatro tipos de mensajes principales, que corresponden a los diferentes roles en la conversación:

TipoRolDescripciónContenido típico
HumanMessageUsuarioMensaje enviado por el usuario"¿Cómo está el clima hoy?"
AIMessageAsistente de IARespuesta del modelo, puede contener tool_calls"Hoy en Hangzhou hace sol, 25 °C"
SystemMessageSistemaInstrucciones del sistema, definen el rol y las reglas de comportamiento de la IA"Eres un asistente meteorológico profesional"
ToolMessageHerramientaResultado devuelto tras la ejecución de la herramienta"Despejado, 25 °C, humedad 60%"

HumanMessage: mensaje de usuario

HumanMessage representa el mensaje que el usuario envía a la IA. Es el tipo de mensaje más común y el punto de partida de la conversación.

Ejemplo

from langchain.messages import HumanMessage
from langchain.chat_models import init_chat_model

# Crear un mensaje de usuario
msg = HumanMessage(content="¿Qué es Python?")

print(f"Tipo: {msg.type}")        # human
print(f"Contenido: {msg.content}")      # ¿Qué es Python?
print(f"Rol: {msg.role}")         # user

# Crear una lista de mensajes (representa el historial de conversación de varias rondas)
messages = [
    HumanMessage(content="Hola"),
    HumanMessage(content="¿Qué cursos tiene EJEMPLO?"),
    HumanMessage(content="¿El curso de Python es adecuado para principiantes sin experiencia?"),
]

model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
response = model.invoke(messages)
print(f"\nRespuesta del modelo: {response.content}")

Resultado de la ejecución:

Tipo: human
Contenido: ¿Qué es Python?
Rol: user

Respuesta del modelo: Python es un lenguaje de programación de alto nivel e interpretado, conocido por su sintaxis clara y legible, ampliamente utilizado en muchos campos.
Su rico ecosistema y su diseño amigable para principiantes lo convierten en una excelente opción para quienes empiezan desde cero.

Formas rápidas de crear HumanMessage

Al construir listas de mensajes, se pueden usar tuplas o diccionarios como atajos:

Ejemplo

from langchain.messages import HumanMessage

# Método 1: construcción estándar
msg1 = HumanMessage(content="Hola")

# Método 2: atajo con tupla (role, content)
msg2 = ("user", "Hola")
msg3 = ("human", "Hola")

# Método 3: atajo con diccionario
msg4 = {"role": "user", "content": "Hola"}

# Las cuatro formas son equivalentes; todas se convierten en HumanMessage dentro del Agent
print(type(msg1))  # <class 'langchain_core.messages.human.HumanMessage'>

AIMessage: respuesta de IA

AIMessage representa la respuesta del modelo. A diferencia del texto normal, AIMessage puede contenertool_calls(solicitudes de llamada a herramientas).

Ejemplo

from langchain.messages import AIMessage

# Respuesta de IA normal (sin llamada a herramienta)
ai_msg = AIMessage(content="EJEMPLO es una plataforma de aprendizaje de programación")

# Respuesta de IA con llamada a herramienta
ai_with_tools = AIMessage(
    content="",  # En una llamada a herramienta, content normalmente está vacío
    tool_calls=[
        {
            "name": "get_weather",
            "args": {"city": "Hangzhou"},
            "id": "call_abc123",
            "type": "tool_call",
        }
    ]
)

print("=== Mensaje de IA normal ===")
print(f"content: {ai_msg.content}")
print(f"tool_calls: {ai_msg.tool_calls}")   # []

print("\n=== Mensaje de IA con llamada a herramienta ===")
print(f"content: {ai_with_tools.content}")
print(f"tool_calls: {ai_with_tools.tool_calls}")
# [{'name': 'get_weather', 'args': {'city': 'Hangzhou'}, ...}]

Información adicional de AIMessage

Ejemplo

from langchain.chat_models import init_chat_model

model = init_chat_model("deepseek:deepseek-v4-flash")
response = model.invoke("Presenta EJEMPLO")

# AIMessage contiene metadatos enriquecidos
print(f"Contenido: {response.content}")
print(f"ID del mensaje: {response.id}")
print(f"Nombre del modelo: {response.response_metadata.get('model_name')}")
print(f"Motivo de finalización: {response.response_metadata.get('finish_reason')}")

# usage_metadata contiene información del uso de tokens
if response.usage_metadata:
    print(f"Tokens de entrada: {response.usage_metadata.get('input_tokens')}")
    print(f"Tokens de salida: {response.usage_metadata.get('output_tokens')}")
    print(f"Tokens totales: {response.usage_metadata.get('total_tokens')}")

Resultado de la ejecución:

Contenido: Ejemplo es una plataforma gratuita de aprendizaje de programación para principiantes...
ID del mensaje: msg_abc123def456
Nombre del modelo: deepseek-v4-flash
Motivo de finalización: stop
Tokens de entrada: 19
Tokens de salida: 47
Tokens totales: 66

SystemMessage: instrucciones del sistema

SystemMessage se utiliza para establecer el comportamiento, el rol y las restricciones de la IA. Se coloca al principio de la lista de mensajes y guía al modelo sobre cómo responder.

Ejemplo

from langchain.messages import HumanMessage, SystemMessage
from langchain.chat_models import init_chat_model

model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0.7)

# Respuesta sin instrucciones del sistema
messages_no_system = [HumanMessage(content="Presenta EJEMPLO")]
response = model.invoke(messages_no_system)
print(f"Sin instrucciones del sistema: {response.content[:80]}...")

# Respuesta con instrucciones del sistema
messages_with_system = [
    SystemMessage(content="Eres un blogger de estilo Xiaohongshu, las respuestas deben ser animadas, usar emojis y llevar hashtags"),
    HumanMessage(content="Presenta EJEMPLO")
]
response = model.invoke(messages_with_system)
print(f"\nCon instrucciones del sistema: {response.content}")

Resultado de la ejecución:

Sin instrucción del sistema: Ejemplo es una plataforma en línea de aprendizaje de programación para principiantes, con tutoriales y ejemplos completos...

Con instrucción del sistema: ¡Sitio increíble! Recomiendo Ejemplo a todo principiante que quiera aprender a programar.
Tutoriales gratuitos y completos, ¡de HTML a Python, de todo!
Muchísimos ejemplos y muy rápido de empezar: ¡la herramienta perfecta para novatos en programación!
#AprenderProgramación #TutorialesGratis #DesdeCero #Ejemplo

ToolMessage: resultado devuelto por la herramienta

ToolMessage contiene el resultado devuelto tras la ejecución de la herramienta. Debe estar asociado con el tool_call correspondiente.

Ejemplo

from langchain.messages import HumanMessage, AIMessage, ToolMessage
from langchain.chat_models import init_chat_model

# Simular una conversación completa de llamada a herramienta
messages = [
    HumanMessage(content="¿Cómo está el clima en Hangzhou?"),

    # El modelo solicita llamar a la herramienta
    AIMessage(
        content="",
        tool_calls=[
            {"name": "get_weather", "args": {"city": "Hangzhou"},
             "id": "call_abc", "type": "tool_call"}
        ]
    ),

    # Resultado devuelto por la herramienta (debe incluir tool_call_id que corresponda al id anterior)
    ToolMessage(
        content="Despejado, 25 °C, humedad 60%",
        tool_call_id="call_abc",   # Corresponde al id del tool_call
        name="get_weather",        # Nombre de la herramienta
    ),
]

model = init_chat_model("deepseek:deepseek-v4-flash")
response = model.invoke(messages)
print(f"Respuesta del modelo basada en el resultado de la herramienta: {response.content}")

Resultado de la ejecución:

Respuesta del modelo basada en el resultado de la herramienta: Hoy hace sol en Hangzhou, 25 °C, humedad 60 %, ideal para actividades al aire libre.

El tool_call_id de ToolMessage debe coincidir exactamente con el id del tool_call en AIMessage. Si no coincide, el modelo puede ignorar este resultado de herramienta o producir un comportamiento confuso.


AIMessageChunk: fragmentos de mensaje en salida de streaming

Cuando utilizas la salida en streaming con stream(), cada fragmento que llega es un AIMessageChunk, no un AIMessage completo:

Ejemplo

from langchain.chat_models import init_chat_model

model = init_chat_model("deepseek:deepseek-v4-flash")

print("Proceso de salida en streaming:")
# stream() devuelve un iterador de AIMessageChunk
for chunk in model.stream("Presenta EJEMPLO en una frase"):
    # Cada chunk es un pequeño fragmento de texto
    print(chunk.content, end="", flush=True)
print()  # Salto de línea

Resultado de la ejecución:

Salida en streaming:
Ejemplo es una plataforma gratuita de aprendizaje en línea para principiantes de programación, con tutoriales y ejemplos completos.

Tabla de referencia rápida de tipos de mensajes

Tipos de mensajesAtributo typeAtributo roleCampos claveCuándo usar
HumanMessagehumanusercontentEntrada del usuario
AIMessageaiassistantcontent, tool_calls, usage_metadataRespuesta del modelo
AIMessageChunkaiassistantcontent (delta)Fragmento de salida en streaming
SystemMessagesystemsystemcontentEstablecer el rol de la IA
ToolMessagetooltoolcontent, tool_call_id, nameResultado de la ejecución de la herramienta

ContentBlock: contenido de mensaje estructurado

Hasta ahora, el contenido de los mensajes que hemos usado son cadenas simples. Pero en realidad, el contenido de cada mensaje puede ser una lista de múltiplesContentBlock(bloques de contenido) que componen la lista.

Los tres tipos de bloques de contenido más comunes:

TipoDescripciónUso
PlainTextContentBlockContenido de texto sin formatoMensaje de texto normal
ImageContentBlockContenido de imagen (base64 o URL)Entrada de imagen para modelos multimodales
ToolCallSolicitud de llamada a herramientaLa IA solicita llamar a una herramienta

Ejemplo

from langchain.messages import HumanMessage
from langchain.messages import PlainTextContentBlock, ImageContentBlock

# Construyendo un mensaje con bloques de contenido
# content puede ser una cadena simple (caso simple)
simple_msg = HumanMessage(content="Hola")

# content también puede ser una lista de ContentBlock (caso complejo)
complex_msg = HumanMessage(content=[
    PlainTextContentBlock(text=¿Qué hay en esta imagen?),
    # La imagen puede ser una URL o codificación base64
    ImageContentBlock(
        url="https://example.com/photo.jpg"
    ),
])

print(fTipo de contenido del mensaje simple: {type(simple_msg.content)})
# Salida: <class 'str'>

print(fTipo de contenido del mensaje complejo: {type(complex_msg.content)})
# Salida: <class 'list'>

print(fNúmero de bloques de contenido: {len(complex_msg.content)})
# Salida: 2

Cuando solo necesitas enviar texto sin formato, pasa directamente una cadena; LangChain lo manejará automáticamente. Solo necesitas construir manualmente una lista de ContentBlock cuando debas mezclar texto e imágenes en un mismo mensaje.


Mensajes multimodales: permitir que el modelo "vea" imágenes

Si tu modelo admite entrada multimodal (como GPT-4o, Claude 3+), puedes hacer que analice el contenido de la imagen:

Ejemplo

import base64
from pathlib import Path
from langchain.messages import HumanMessage
from langchain.chat_models import init_chat_model

# Codificar la imagen local en base64
def encode_image(image_path: str) -> str:
    """Lee el archivo de imagen y conviértelo a codificación base64"""
    with open(image_path, "rb") as f:
        return base64.b64encode(f.read()).decode("utf-8")

# Crear un modelo multimodal (debe admitir entrada de imágenes)
model = init_chat_model("deepseek:deepseek-v4-flash")

# Construir un mensaje que contenga la imagen
# Nota: content usa formato de lista, incluye bloques de texto y bloques de imagen
image_data = encode_image("screenshot.png")
messages = [
    HumanMessage(content=[
        {"type": "text", "text": Por favor, describe el contenido de esta captura de pantalla del sitio web oficial de EJEMPLO.},
        {
            "type": "image_url",
            "image_url": {
                "url": f"data:image/png;base64,{image_data}",
                "detail": "auto"  # Opcional: low, high, auto
            }
        }
    ])
]

response = model.invoke(messages)
print(fResultado del análisis de la imagen: {response.content})

Si tu mensaje solo contiene una imagen y no texto, puedes usar directamente:

Ejemplo

from langchain.chat_models import init_chat_model

model = init_chat_model("deepseek:deepseek-v4-flash")

# Usar una URL para referenciar directamente una imagen en línea
messages = [
    {
        "role": "user",
        "content": [
            {"type": "text", "text": ¿Qué describe esta imagen?},
            {
                "type": "image_url",
                "image_url": {"url": "https://www.example.com/wp-content/uploads/2024/01/logo.png"}
            }
        ]
    }
]

response = model.invoke(messages)
print(response.content)

No todos los modelos admiten entrada multimodal. Lo hacen la serie GPT-4o de OpenAI, Claude 3+ de Anthropic y la serie Gemini de Google. Si envías una imagen a un modelo que no la admite, recibirás un error.


ToolCall: mensaje de llamada a herramienta

El campo tool_calls en AIMessage es una lista de ToolCall; cada ToolCall representa una solicitud del modelo para llamar a una herramienta:

Ejemplo

from langchain.messages import AIMessage
from langchain.messages.tool import ToolCall

# Construir manualmente un ToolCall
tool_call = ToolCall(
    name="get_weather",        # Nombre de la herramienta
    args={"city": "Hangzhou"},     # Parámetros de la llamada
    id="call_abc123",         # Identificador único
    type="tool_call",         # Valor fijo
)

# Crear un AIMessage con tool_calls
ai_message = AIMessage(
    content="",               # Cuando hay tool_calls, content suele estar vacío
    tool_calls=[tool_call],
)

print(fNombre de la herramienta: {ai_message.tool_calls)
print(fParámetros de la llamada: {ai_message.tool_calls)
print(fID de la llamada: {ai_message.tool_calls)

Verificar si AIMessage contiene una llamada a herramienta

Ejemplo

from langchain.chat_models import init_chat_model

model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)

# Después de vincular la herramienta, el modelo puede devolver tool_calls
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": Consultar el tiempo,
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": Nombre de la ciudad}
            },
            "required": ["city"]
        }
    }
}]

model_with_tools = model.bind_tools(tools)

# Pregunta que activa la llamada a herramienta
response = model_with_tools.invoke(¿Cómo está el clima en Hangzhou?)

# Dos formas de determinar si hay una llamada a herramienta
# Método 1: comprobar si la lista tool_calls no está vacía
if response.tool_calls:
    print(El modelo solicita llamar a la herramienta)

# Método 2: comprobar si content está vacío
# (La mayoría de los modelos tienen content vacío cuando hay tool_calls)
if not response.content:
    print(El content del modelo está vacío, lo que indica que quiere llamar a la herramienta en lugar de responder directamente.)

trim_messages(): recortar el historial de mensajes

Cuando la conversación se vuelve más larga, la lista de mensajes puede exceder la ventana de contexto del modelo.trim_messages()La función te ayuda a recortar el historial de mensajes de forma inteligente.

Ejemplo

from langchain.messages import (
    HumanMessage, AIMessage, SystemMessage, trim_messages
)
from langchain.chat_models import init_chat_model

# Simular un historial de conversación muy largo
messages = [
    SystemMessage(content=Eres el asistente de IA de EJEMPLO.),
    HumanMessage(content=¿Cómo empezar con Python?),
    AIMessage(content=La introducción a Python puede comenzar desde los conceptos básicos...),
    HumanMessage(content=¿Tienes algún IDE recomendado?),
    AIMessage(content=Recomiendo VS Code o PyCharm...),
    HumanMessage(content=¿Cómo instalar librerías de terceros?),
    AIMessage(content=Usa el comando pip install...),
    HumanMessage(content=¿Qué es NumPy?),
    AIMessage(content=NumPy es una librería de cálculo científico...),
    HumanMessage(content=¿Cuál es la diferencia entre pandas y NumPy?),
]

model = init_chat_model("deepseek:deepseek-v4-flash")

# Recortar mensajes para ajustarse a la ventana de contexto del modelo (máximo 1000 tokens)
# strategy="last" conserva el último mensaje del sistema y la conversación reciente
trimmed = trim_messages(
    messages,
    max_tokens=1000,           # Conservar como máximo 1000 tokens
    strategy="last",           # Conservar el último mensaje del sistema + la conversación reciente
    token_counter=model,       # Usar el método de conteo de tokens del modelo
    include_system=True,       # Conservar siempre SystemMessage
    start_on="human",          # Después del recorte, comienza con un mensaje human
)

print(fAntes de recortar: {len(messages)} mensajes)
print(fDespués de recortar: {len(trimmed)} mensajes)
for msg in trimmed:
    snippet = msg.content[:50] if isinstance(msg.content, str) else str(msg.content)[:50]
    print(f"  [{msg.type}] {snippet}...")

Resultado de la ejecución:

Antes de recortar: 10 mensajes
Después de recortar: 5 mensajes
  [system] Eres el asistente de IA de Ejemplo...
  [human] ¿Cómo instalo bibliotecas de terceros?...
  [ai] Usa el comando pip install...
  [human] ¿Qué es NumPy?...
  [ai] NumPy es una biblioteca de computación científica...
EstrategiaDescripciónEscenario de aplicación
strategy="last"Conservar mensaje system + conversación recienteEn conversaciones largas, solo importa el contexto más reciente
strategy="first"Conservar mensaje system + primeras conversacionesAsegurar que el contexto clave no se recorte

start_on="human" asegura que la lista de mensajes recortada comience con un mensaje del usuario (en lugar de un mensaje de IA), evitando que el modelo reciba una respuesta de IA aislada al inicio.


RemoveMessage: eliminar mensajes específicos

En algunos escenarios avanzados, es posible que necesites eliminar mensajes específicos del historial (como limpieza de contenido sensible, regeneración de respuestas, etc.):

Ejemplo

from langchain.messages import HumanMessage, AIMessage, RemoveMessage

# Supongamos que hay una conversación
messages = [
    HumanMessage(content="Hola", id="msg_1"),
    AIMessage(content=¡Hola! ¿En qué puedo ayudarte?, id="msg_2"),
    HumanMessage(content=Ayúdame a consultar el tiempo, id="msg_3"),
]

# Usar RemoveMessage para eliminar mensajes específicos (mediante ID)
# RemoveMessage se usa junto con el reducer add_messages
# Al actualizar el estado del agente, RemoveMessage elimina de la lista los mensajes con el ID correspondiente
removal = RemoveMessage(id="msg_3")

print(fID del mensaje a eliminar: {removal.id})
print(fTipo: {removal.type})  # remove

RemoveMessage normalmente se usa con el reducer add_messages de AgentState. Devolver RemoveMessage en middleware o en el hook after_model permite limpiar dinámicamente el historial de mensajes.


Métodos comunes para las propiedades de mensajes

Todos los tipos de mensajes heredan de BaseMessage y comparten algunos métodos comunes:

Ejemplo

from langchain.messages import HumanMessage, AIMessage

msg = HumanMessage(content=Hola, Tutorial para Novatos)

# Atributos básicos
print(f"content: {msg.content}")      # Contenido del mensaje
print(f"type: {msg.type}")            # Tipo de mensaje (human/ai/system/tool)
print(f"id: {msg.id}")                # ID único generado automáticamente

# Propiedad text: si es contenido de texto, devuelve el texto; de lo contrario, devuelve ""
print(f"text: {msg.text}")

# pretty_repr(): impresión formateada, adecuada para depuración
print(f"Salida embellecida:\n{msg.pretty_repr()}")

Resultado de la ejecución:

content: Hola, mundo
type: human
id: 00000000-0000-4000-8000-000000000000
text: Hola, mundo
Salida formateada:
================================ Human Message =================================
Hola, mundo
Otras extensiones