Objetivos
- Comprender los conceptos básicos de la ingeniería de prompts: Obtener una base sólida sobre cómo comunicarse eficazmente con los LLM mediante prompts, preparando el terreno para técnicas más avanzadas.
- Dominar técnicas avanzadas de prompts: Aprender y aplicar métodos avanzados de ingeniería de prompts, como el aprendizaje de pocos ejemplos (few-shot) y el aprendizaje de consistencia propia (self-consistent learning), para optimizar las respuestas del LLM.
- Utilizar plantillas de prompts de LangChain: Adquirir fluidez en el uso de las plantillas de prompts de LangChain para estructurar y optimizar tus interacciones con los LLM.
- Desarrollar agentes de LLM prácticos: Adquirir las habilidades para crear e implementar agentes, como bots de preguntas y respuestas (QA) y herramientas de resumen de texto, utilizando las plantillas de prompts de LangChain, traduciendo el conocimiento teórico en soluciones prácticas.
Setup
Para este laboratorio usamos el entorno de prácticas creado en el artículo: Preparación del entorno RAG híbrido (Ollama + DeepSeek + LangChain) para prácticas.
Importar librerías
Importar variables del entorno y módulo LLMconfig
import sys
import os
sys.path.append(os.path.abspath(".."))
from dotenv import load_dotenv
load_dotenv()TrueImportar la configuración de modelos
from llm_config import get_llmConfigurar los LLM
En esta sección configuramos los LLM usando nuestro entorno hibrido DeepSeek + Ollama utilizando el módulo llm_config:
lmm: Especifica el módulo a utilizar.sdkpara deepseek modelodeepseek-chatyollpara LLM local Ollama modeloqwen:4b. Por defecto utiliza DeepSeek.params: Configura los parámetros del modelo establecidos por defecto como:temperature: 1, Aleatoriedad del modelo.max_tokens: 50, Longitud de la respuesta en DeepSeektop_p: 1, Diversidad de palabras considerando la probabilidad acumulada (no usar junto contemperature).top_k: 40, Diversidad de palabras considerando la frecuenciafrequency_penalty: 0, Penalización de frecuencia – DeepSeekpresence_penalty: 0, Penalización de presencia – DeepSeekrepeat_penalty: 1.1 Penalización de repetición – Ollama
Para este lab utilizaremos solamente DeepSeek por ser un modelo más grande y provee mejores respuestas.
Ejemplo de llamada con llmconfig:
get_llm(llm="dsk", params={"temperature": 0.8, "max_tokens": 30})Uso de LangChain para interactuar con el modelo
Cuando trabajamos con modelos de lenguaje en LangChain, el método principal para ejecutar el modelo es .invoke(). Es el punto central de interacción con el modelo y forma parte del diseño unificado de LangChain y muchos componentes implementan la misma interfaz.
LangChain hace internamente:
- Prepara la entrada
- Llama al backend (DeepSeek / Ollama / etc.)
- Recibe la respuesta
Ejemplo de uso de .invoke():
llm = get_llm(llm="dsk", params={"temperature": 0.8, "max_tokens": 30})
response = llm.invoke("Explícame qué es PCA")
print(response)Estructura de la respuesta de los LLM
La respuesta no siempre es un simple texto. En muchos casos (especialmente con Chat Models como DeepSeek), obtienes un objeto estructurado con mucha más información que puede ser extraída como objetos generados por el modelo que estés usando.
EL objeto content, es el que tiene la respuesta del prompt, para que se muestre solo ese usamos response.content. Este viene formateado en Markdown. Para visualizar correctamente el formato importamos librerías de visualización de Jupyter:
from IPython.display import display, MarkdownDefinimos una función para reemplazar a print() en la respuesta que muestre el texto en el formato correcto:
def show(response):
content = response.content if hasattr(response, "content") else response
display(Markdown(content))Ahora solamente llamamos a show(response) y devolverá content visualizado correctamente.
Ejemplo de la respuesta completa de DeepSeek en el ejemplo siguiente:
content " ..."
additional_kwargs={'refusal': None}
response_metadata={'token_usage': {
'completion_tokens': 957,
'prompt_tokens': 14,
'total_tokens': 971,
'completion_tokens_details': None,
'prompt_tokens_details': {
'audio_tokens': None,
'cached_tokens': 0},
'prompt_cache_hit_tokens': 0,
'prompt_cache_miss_tokens': 14
},
'model_provider': 'openai',
'model_name': 'deepseek-v4-flash',
'system_fingerprint': 'fp_058df29938_prod0820_fp8_kvcache_20260402',
'id': '8eb89977-19f8-4756-b53d-4f721d92fcef',
'finish_reason': 'stop',
'logprobs': None}
id='lc_run--019dd8b6-ff91-75f1-b656-aa3691947150-0' tool_calls=[] invalid_tool_calls=[]
usage_metadata={
'input_tokens': 14,
'output_tokens': 957,
'total_tokens': 971,
'input_token_details': {
'cache_read': 0},
'output_token_details': {}}Prompt Basico:
# invocar el modelo + paranetros
llm = get_llm(llm="dsk", params={"temperature": 0.8})
# prompt
prompt = "Cual es un buen nombre para un perro"
response = llm.invoke(prompt)
print(f"prompt: {prompt}n")
show(response)¡Elegir el nombre de un perro es una decisión importante y divertida! Para ayudarte, aquí tienes algunas categorías con opciones y consejos para que encuentres el nombre perfecto:
1. Nombres Clásicos y Populares (Siempre funcionan)
Son fáciles de recordar y suelen tener una o dos sílabas, lo que ayuda al perro a reconocerlo rápido.
Machos: Max, Toby, Bruno, Leo, Rocky, Simba, Coco, Thor, Lucas, Kiko.
Hembras: Luna, Nina, Lola, Bella, Maya, Kira, Dora, Nala, Chispa, Mora.
2. Nombres Inspirados en la Cultura Hispana
Suenan cálidos y con mucha personalidad.
Comida: Churro, Taco, Canela, Mochi, Café, Pan, Fideo, Dulce.
Lugares o Cosas: Sol, Río, Sierra, Cielo, Brisa, Bolívar, Gitano.
Tradicionales: Chucho, Pocho, Cachito, Güero, Negro, Pinto.
3. Nombres Divertidos y Originales
Perfectos para perros con mucha energía o para sacar una sonrisa.
De personajes: Chewbacca, Yoda, Groot, Pikachu, Shrek, Harry (Potter), Gandalf.
Irónicos: Goliat (para un perro chico), Pulga (para un perro grande), Tranquilo (para uno inquieto), Sirena (para un macho).
Acciones o sonidos: Zoom, Ñam, Guau, Tic-Tac, Bulto, Moco.
4. Nombres Cortos y Funcionales (Ideal para adiestramiento)
Los perros responden mejor a sonidos fuertes y cortos (1 o 2 sílabas).
Con sonidos fuertes: Kai, Rex, Zeus, Xena, Zara, Crixus.
Con 'i' final (agudos): Toni, Yuki, Loki, Mili, Roni.
5. Nombres Épicos o con Significado
Para perros con presencia o que te inspiran.
Poderosos: Thor, Odín, Hera, Ares, Maya (ilusión), Atlas.
Naturaleza: Bosco, Selva, Nube, Trueno, Brisa, Ola, Copo (de nieve).
Consejos finales para elegir:
Prueba el nombre en voz alta: ¿Suena bien cuando lo gritas en el parque? ¿Se confunde con una orden común (ej: "No", "Flojo" suena a "Fue")?
Observa su personalidad: ¿Es un perro tranquilo como un Tao o un terremoto como un Tornado?
La regla de las dos sílabas: Es el equilibrio perfecto entre corto (que se oiga bien) y largo (que no suene como un ladrido). Ej: Kai, Lúa, Tito, Nala.
No te apresures: A veces, el nombre ideal llega después de unos días de convivencia, al ver su carácter.
Mi recomendación personal: Si quieres algo tierno y moderno, Kai (que significa "mar" en hawaiano y "perdón" en japonés, es sonoro y corto). Si buscas algo clásico y dulce, Luna es un acierto casi universal.
¿Qué tipo de perro es (raza, tamaño, carácter)? ¡Con esos detalles puedo recomendarte nombres más específicos!Recuerden que la respuesta saldrá formateada en Jupiter y se verá como texto editado, aqui lo he puesto en un cuadro de código para diferenciarlo. Listo.
Ingeniería de Prompt
Zero-shot Prompt
El zero-shot prompting es una técnica en la que el modelo realiza una tarea sin recibir ejemplos previos ni entrenamiento específico para esa tarea. Este enfoque pone a prueba la capacidad del modelo para entender instrucciones y aplicar su conocimiento a un contexto nuevo sin necesidad de demostraciones.
Un prompt zero-shot suele incluir instrucciones claras y una tarea definida, lo que permite al modelo utilizar su conocimiento previo para generar una respuesta adecuada.
# Configurar el modelo
llm = get_llm(llm="dsk", params={"temperature": 0.8})
# prompt zero-shot
prompt = "Clasifica el sentimiento del siguiente texto: 'Me encanta este producto'"
# ejecutar
response = llm.invoke(prompt)
# mostrar resultado
show(response)El sentimiento del texto "Me encanta este producto" es positivo.Otros ejemplos:
response = llm.invoke("Clasifica como verdadero o falso: La Torre Eiffel está en Berlín.")
show(response)Verdadero o falso: La Torre Eiffel está en Berlín.
Falso. La Torre Eiffel se encuentra en París, Francia, no en Berlín.Cuando usarlo:
- Tareas simples
- Preguntas directas
- Cuando quieres rapidez y no necesitas precisión extrema
Limitaciónes
- Menor control sobre la salida
- Mayor probabilidad de error en tareas complejas
One-shot Prompt
El one-shot prompting es una técnica en la que se proporciona al modelo un único ejemplo de la tarea antes de pedirle que realice una tarea similar.
En este enfoque:
- Primero se muestra un ejemplo
- Luego se plantea un nuevo caso
El modelo utiliza ese ejemplo como referencia para entender:
- el formato de la respuesta
- el estilo esperado
- el tipo de resultado
# Configurar el modelo
llm = get_llm(llm="dsk", params={"max_tokens": 50, "temperature": 0.2})
prompt = """Aqui hay un ejemplo de traduccion de castellano a ingles:
Castellano: “¿Como es el clima hoy?”
Frances: “Comment est le temps aujourd'hui?”
Ahora, tradusca el siguiente texto de castellano al frances:
Castellano: "¿Donde esta el supermercado mas cercano?”
"""
response = llm.invoke(prompt)
show(response)Aquí tienes la traducción al francés:
Francés: “Où est le supermarché le plus proche ?”Otro ejemplo:
prompt = """
Ejemplo:
Asunto: Solicitud de información sobre el curso
Estimado/a señor/a,
Me pongo en contacto con usted para solicitar información adicional sobre el curso de marketing digital que ofrecen en su institución.
Quedo a la espera de su respuesta.
Atentamente,
Juan Pérez
Ahora escribe un email formal solicitando información sobre un servicio de consultoría empresarial.
"""
response = llm.invoke(prompt)
show(response)Asunto: Solicitud de información sobre servicios de consultoría empresarial
Estimado/a señor/a,
Por medio del presente, me dirijo a ustedes con el fin de solicitar información detallada sobre los servicios de consultoría empresarial que ofrecen.
Agradecería que pudieran proporcionarme datos sobre las áreas de especialización, la metodología de trabajo, los plazos estimados y las tarifas asociadas a sus servicios. Asimismo, si cuentan con casos de éxito o referencias de clientes anteriores, le agradecería que me los hicieran llegar.
Quedo a la espera de su pronta respuesta y quedo a su disposición para cualquier consulta adicional que consideren necesaria.
Atentamente,
[Tu nombre completo]
[Tu cargo o empresa, si aplica]
[Tu correo electrónico]
[Tu número de teléfono, opcional]Ejemplo con extracción de palabras clave:
prompt = """
Ejemplo:
Frase: El marketing digital permite a las empresas llegar a más clientes a través de internet.
Palabras clave: marketing digital, empresas, clientes, internet
Ahora extrae las palabras clave de la siguiente frase:
"La analítica de datos ayuda a las organizaciones a tomar decisiones basadas en información."
"""
response = llm.invoke(prompt)
show(response)Palabras clave: analítica de datos, organizaciones, tomar decisiones, informaciónCuándo usar one-shot
Es especialmente útil cuando:
- Quieres guiar la respuesta del modelo
- Necesitas un formato concreto
- No quieres usar muchos ejemplos
Few-shot prompt
El few-shot prompting extiende el enfoque de one-shot proporcionando varios ejemplos (normalmente entre 2 y 5) antes de pedir al modelo que realice la tarea.
Estos ejemplos establecen un patrón y un contexto más claros, ayudando al modelo a comprender mejor el formato de salida, el estilo y el tipo de razonamiento esperado.
Esta técnica es especialmente eficaz en tareas más complejas, donde un único ejemplo puede no ser suficiente para transmitir todos los matices.
A continuación se muestra un ejemplo de few-shot learning clasificando emociones a partir de frases.
Proporcionamos al modelo tres ejemplos, cada uno etiquetado con una emoción adecuada —alegría, frustración y tristeza— para establecer un patrón o guía sobre cómo clasificar las emociones en distintas frases.
Después de presentar estos ejemplos, planteamos un nuevo caso. La tarea del modelo es clasificar la emoción expresada en esta nueva frase basándose en lo aprendido a partir de los ejemplos proporcionados.
llm = get_llm(llm="dsk", params={"max_tokens": 50, "temperature": 0.2})
prompt = """Aqui se muestran varios ejemplos de clasificacion de emociones:
Frase: 'Acabo de ganar mi primer maraton'
Emocion: Alegria
Frase: 'No puedo creer que haya perdido las llaves otravez'
Emocion: Frustración
Frase: 'Mi mejor amigo se ha mudado a otro país'
Emocion: Tristeza
Ahora clasifica la emocion de la siguiente frase:
Frase: 'La pelicula tenia crimenes tan explicitos que he tenido quen cubrirme los ojos'
"""
response = llm.invoke(prompt)
show(response)Basándome en los ejemplos proporcionados, la emoción más adecuada para la frase:
'La pelicula tenia crimenes tan explicitos que he tenido que cubrirme los ojos'
sería Asco o Repulsión, ya que la reacción de cubrirse los ojos indica una fuerte aversión o incomodidad ante lo explícito y perturbador de las imágenes.Chain-of-thought (CoT) prompt
El chain-of-thought (CoT) prompting es una técnica que anima al modelo a descomponer problemas complejos en un razonamiento paso a paso antes de llegar a una respuesta final. Al mostrar o solicitar explícitamente los pasos intermedios, esta técnica mejora la capacidad del modelo para resolver problemas y reduce errores en tareas que requieren razonamiento en múltiples etapas. El CoT es especialmente eficaz en problemas matemáticos, razonamiento lógico y tareas complejas de toma de decisiones.
A continuación se muestra un ejemplo diseñado para guiar al modelo a través de una secuencia de pasos de razonamiento para resolver un problema. En este caso, el problema es una pregunta de álgebra lineal:
Imaginemos que tenemos tres personas:Bob, Alice y Tim, que han ido al supermercado y compraron manzanas, naranjas y peras.
- Bob compro 3 manzanas, 6 naranjas y 2 peras, con un coste de 34€.
- Alice compro 10 manzanas, 3 naranjas y 8 peras, con un coste de 69€.
- Tim compro 1 manzanas, 7 naranjas y 5 peras, con un coste de 48€.
Y queremos averiguar cuánto cuesta cada producto.
La técnica CoT consiste en estructurar el prompt indicando al modelo que “desglose cada paso del cálculo”. Esto anima al modelo a incluir los pasos de razonamiento de forma explícita, imitando un proceso de resolución de problemas similar al humano.
llm = get_llm(llm="dsk", params={"max_tokens": 500, "temperature": 0.5})
prompt = """Considera el siguiente problema:
Imaginemos que tenemos tres personas: Bob, Alice y Tim,Tim, que han ido al supermercado y compraron manzanas, naranjas y peras.
Bob compro 3 manzanas, 6 naranjas y 2 peras, con un coste de 34€.
Alice compro 10 manzanas, 3 naranjas y 8 peras, con un coste de 69€.
Tim compro 1 manzanas, 7 naranjas y 5 peras, con un coste de 48€.
¿Determina el coste de cada fruta?
Desglosa cada paso del calculo.
"""
response = llm.invoke(prompt)
show(response)Vamos a resolver el problema paso a paso.
Primero definimos las variables:
( m ) = precio de una manzana (en €)
( n ) = precio de una naranja (en €)
( p ) = precio de una pera (en €)
Del enunciado obtenemos las ecuaciones:
Bob:
( 3m + 6n + 2p = 34 ) (1)
Alice:
( 10m + 3n + 8p = 69 ) (2)
Tim:
( 1m + 7n + 5p = 48 ) (3)
-------------------------------------------------------------------
Paso 1: Eliminar una variable
Vamos a eliminar ( m ) usando las ecuaciones (1) y (3).
Multiplicamos (3) por 3:
( 3m + 21n + 15p = 144 ) (4)
Restamos (1) de (4):
((3m + 21n + 15p) - (3m + 6n + 2p) = 144 - 34)
Esto da:
( 15n + 13p = 110 ) (5)
-------------------------------------------------------------------
Paso 2: Eliminar la misma variable ( m ) entre (2) y (3)
Multiplicamos (3) por 10:
( 10m + 70n + 50p = 480 ) (6)
Restamos (2) de (6):
((10m + 70n + 50p) - (10m + 3n + 8p) = 480 - 69)
Esto da:
( 67n + 42p = 411 ) (7)
-------------------------------------------------------------------
Paso 3: Resolver el sistema de dos ecuaciones (5) y (7)
Tenemos:
[
begin{cases}
15n + 13p = 110 quad (5)
67n + 42p = 411 quad (7)
end{cases}
]
Multiplicamos (5) por 42 y (7) por 13 para igualar coeficientes de ( p ):
(5) × 42:
( 630n + 546p = 4620 ) (8)
(7) × 13:
( 871n + 546p = 5343 ) (9)
Restamos (8) de (9):
((871n - 630n) + (546p - 546p) = 5343 - 4620)
( 241n = 723 )
Despejamos ( n ):
( n = frac{723}{241} = 3 )
-------------------------------------------------------------------
Paso 4: Sustituir ( n = 3 ) en (5)
( 15(3) + 13p = 110 )
( 45 + 13p = 110 )
( 13p = 65 )
( p = 5 )
Paso 5: Sustituir ( n = 3 ) y ( p = 5 ) en (3)
( m + 7(3) + 5(5) = 48 )
( m + 21 + 25 = 48 )
( m + 46 = 48 )
( m = 2 )
-------------------------------------------------------------------
Solución final:
Manzana: 2 €
Naranja: 3 €
Pera: 5 €
Podemos comprobar con la ecuación (1):
( 3(2) + 6(3) + 2(5) = 6 + 18 + 10 = 34 ) ✅Al generar la respuesta desglosa es mejor para entender el proceso de cálculo. Veamos otro ejemplo más sencillo:
llm = get_llm(llm="dsk", params={"temperature": 0.5})
prompt = """Un estudiante tiene un examen importante dentro de dos días, pero sus amigos le han invitado a ir al cine esta noche.
Analiza la situación paso a paso teniendo en cuenta:
- la importancia del examen
- el tiempo disponible para estudiar
- el descanso y ocio
Desglosa tu razonamiento paso a paso y luego da una recomendación final.
"""
response = llm.invoke(prompt)
show(response)Claro, analicemos la situación paso a paso.
Paso 1: Identificar el contexto y las prioridades
El examen es en dos días, lo que significa que hay tiempo limitado pero no cero.
La invitación es para esta noche, lo que implica que si va al cine, perderá varias horas de estudio (viaje, película, tiempo social).
El descanso y ocio son importantes para la salud mental, pero el examen tiene un peso académico.
Paso 2: Evaluar el tiempo disponible
Si hoy es el día 1 (noche) y el examen es el día 3 (mañana/tarde), quedan aproximadamente:
Esta noche (unas 3-4 horas si no va al cine).
Todo el día de mañana (día completo de estudio).
La mañana del examen (último repaso).
Ir al cine esta noche consume al menos 3-4 horas (incluyendo desplazamiento).
Si estudia esta noche, podría avanzar temas clave y dejar el día siguiente para repaso y práctica.
Paso 3: Ponderar la importancia del examen
Si el examen es decisivo para la nota final, una beca o un requisito, la prioridad debe ser máxima.
Si es un examen parcial o de menor peso, podría permitirse un equilibrio.
Paso 4: Considerar el descanso y ocio
El ocio es necesario para evitar el agotamiento, pero puede posponerse.
Una opción intermedia: proponer a los amigos ir otro día (después del examen) o hacer algo más corto (como un café rápido) para no perder toda la noche.
Paso 5: Decidir basado en el balance
Si el estudiante ha estudiado con antelación y se siente preparado, una salida corta podría ser viable.
Si no ha estudiado lo suficiente, lo prudente es rechazar la invitación y dedicar la noche al estudio, programando un descanso para mañana.
Recomendación final:
Prioriza el examen. Rechaza la invitación al cine esta noche. Explica a tus amigos que tienes un examen importante y que los verás después. Usa esta noche para estudiar de forma enfocada (por ejemplo, 2 horas de repaso y luego descanso). Mañana puedes tomar un descanso programado (como una caminata o ver una serie corta) para no saturarte. Así combinas responsabilidad con un poco de ocio controlado.Self-consistency
La self-consistency es una técnica avanzada en la que el modelo genera múltiples soluciones o respuestas independientes para un mismo problema y, posteriormente, evalúa estas distintas aproximaciones para determinar cuál es la más consistente o fiable. Este método mejora la precisión aprovechando la capacidad del modelo para abordar un problema desde diferentes perspectivas y seleccionar la solución más robusta mediante comparación y verificación.
llm = get_llm(llm="dsk", params={"temperature": 0.5})
prompt = """
Resuelve el siguiente problema generando varias soluciones independientes y luego elige la mejor.
Problema:
Un negocio vende un producto a 20€. El coste de producción es de 12€ por unidad y los costes fijos mensuales son de 800€.
¿Cuántas unidades necesita vender para empezar a obtener beneficios?
Instrucciones:
1. Genera al menos 3 formas diferentes de resolver el problema.
2. Explica cada razonamiento paso a paso.
3. Compara los resultados obtenidos.
4. Selecciona la solución más consistente y explica por qué es la correcta.
Respuesta final:
Indica claramente el número de unidades necesarias y justifica tu elección.
"""
response = llm.invoke(prompt)
show(response)Vamos a resolver el problema paso a paso, generando varias soluciones independientes.
Datos del problema
Precio de venta por unidad: 20 €
Coste de producción por unidad: 12 €
Costes fijos mensuales: 800 €
El beneficio comienza cuando los ingresos superan los costes totales.
----------------------------------------------------------------------
Solución 1: Método algebraico (ecuación de beneficio)
Razonamiento:
El beneficio se calcula como:
Beneficio} = Ingresos - Costes totales
Ingresos = ( 20x ) (siendo ( x ) el número de unidades)
Costes totales = Costes fijos + Costes variables = ( 800 + 12x )
Para empezar a obtener beneficios, el beneficio debe ser mayor que cero:
[
20x - (800 + 12x) > 0
]
Paso a paso:
Simplificamos:
( 20x - 800 - 12x > 0 )
( 8x - 800 > 0 )
Sumamos 800:
( 8x > 800 )
Dividimos entre 8:
( x > 100 )
Resultado: Necesita vender más de 100 unidades, es decir, 101 unidades para tener beneficio positivo.
----------------------------------------------------------------------
Solución 2: Método del punto de equilibrio (umbral de rentabilidad)
Razonamiento:
El punto de equilibrio es cuando los ingresos igualan a los costes totales. A partir de ahí, cada unidad adicional da beneficio.
Paso a paso:
Ingresos = Costes totales
( 20x = 800 + 12x )
Restamos ( 12x ):
( 8x = 800 )
Despejamos:
( x = 100 )
En el punto exacto (100 unidades) el beneficio es cero.
Para empezar a obtener beneficios se necesita vender una unidad más:
( 100 + 1 = 101 ) unidades.
Resultado: 101 unidades.
----------------------------------------------------------------------
Solución 3: Método del margen de contribución
Razonamiento:
El margen de contribución por unidad es:
[
text{Precio} - text{Coste variable} = 20 - 12 = 8 ,€
]
Cada unidad vendida aporta 8 € para cubrir los costes fijos.
Para cubrir 800 € de costes fijos:
[
frac{800}{8} = 100 text{ unidades}
]
A partir de la unidad 101, el margen de contribución se convierte en beneficio.
Resultado: 101 unidades.
----------------------------------------------------------------------
Comparación de resultados
Los tres métodos coinciden en que se necesitan 101 unidades para empezar a obtener beneficios.
Selección de la mejor solución
Las tres soluciones son consistentes y correctas. Sin embargo, la más intuitiva y rápida es la del margen de contribución, porque:
Permite visualizar claramente cuánto aporta cada unidad.
Es muy usada en negocios para cálculos rápidos de rentabilidad.
No requiere resolver ecuaciones complejas.
----------------------------------------------------------------------
Respuesta final
Se necesitan 101 unidades para empezar a obtener beneficios.
La justificación principal es que con 100 unidades se cubren exactamente los costes totales (beneficio cero), y a partir de la unidad 101, cada venta genera un beneficio neto de 8 €.Aplicaciones del prompting en diferentes casos de uso
En esta sección, demostraremos cómo aprovechar las plantillas de prompt de LangChain para construir aplicaciones prácticas con resultados consistentes y reproducibles. Cada aplicación sigue un patrón común utilizando el enfoque LCEL:
- Definir el contenido o problema a resolver.
- Crear una plantilla con variables para contenido dinámico.
- Convertir la plantilla en un PromptTemplate de LangChain.
- Construir una cadena utilizando el operador pipe | para conectar:
- Variables de entrada
- La plantilla de prompt
- El LLM
- Un analizador de salida (output parser)
- Ejecutar la cadena con entradas específicas para generar resultados.
Este enfoque estructurado permite crear componentes reutilizables para diferentes tareas de procesamiento de lenguaje natural, manteniendo al mismo tiempo la flexibilidad para ajustar parámetros y entradas. Verás cómo este patrón se aplica en distintos casos de uso.
Introducción a LangChain
LangChain es un framework potente diseñado para simplificar el desarrollo de aplicaciones basadas en modelos de lenguaje. Creado para abordar los retos de trabajar con LLMs en entornos reales, LangChain proporciona una interfaz estandarizada para conectar modelos con diferentes fuentes de datos y entornos de aplicación.
LangChain actúa como una capa de abstracción, facilitando la construcción de aplicaciones complejas con LLMs sin tener que gestionar los detalles de bajo nivel de la interacción con el modelo. Este framework se ha convertido en una herramienta estándar dentro del ecosistema de los LLM, soportando una amplia variedad de casos de uso, desde chatbots hasta sistemas de análisis de documentos.
En esta sección nos centraremos en las capacidades de las plantillas de prompt de LangChain, mostrando cómo pueden utilizarse para crear interacciones estructuradas y reproducibles con modelos de lenguaje en distintos tipos de aplicaciones.
Plantillas de Prompt
Las plantillas de prompt son un concepto clave en LangChain. Ayudan a transformar la entrada del usuario y los parámetros en instrucciones para un modelo de lenguaje. Estas plantillas pueden utilizarse para guiar la respuesta del modelo, ayudándole a entender el contexto y a generar resultados coherentes y relevantes basados en lenguaje.
Una plantilla de prompt actúa como una estructura reutilizable para generar prompts con valores dinámicos. Permite definir un formato consistente mientras deja espacios reservados para variables que cambian en cada caso de uso. Este enfoque hace que el uso de prompts sea más sistemático y mantenible, especialmente cuando se trabaja con aplicaciones más complejas.
LangChain moderno (a partir de 2025) ofrece dos enfoques principales para trabajar con plantillas:
- El enfoque tradicional basado en
LLMChain - El patrón más reciente basado en el Lenguaje de Expresión de LangChain (LCEL), que utiliza el operador pipe
|para una composición más flexible
LCEL se ha convertido en el enfoque recomendado para construir aplicaciones con LangChain, ya que ofrece mejor capacidad de composición, una visualización más clara del flujo de datos y mayor flexibilidad al construir cadenas complejas.
Para usar una plantilla de prompt con LCEL, normalmente se siguen estos pasos:
- Definir la plantilla con variables entre llaves
{} - Crear una instancia de
PromptTemplate - Construir una cadena utilizando el operador pipe
|para conectar los componentes - Ejecutar la cadena con los valores de entrada
Se utiliza PromptTemplate para crear una plantilla de prompt basada en texto. En esta plantilla definirás dos parámetros: adjective y content. Estos parámetros permiten reutilizar el prompt en diferentes situaciones. Por ejemplo, para adaptar el prompt a distintos contextos, basta con proporcionar los valores correspondientes a estos parámetros.
Flujo completo :
variables → template → prompt final → modelo → respuestaPara utilizarlo se debe importar primeramente:
from langchain_core.prompts import PromptTemplatellm = get_llm(llm="dsk", params={"temperature": 0.5})
# Definicion del Template con las variables dinamicas
template = "Explica el concepto de {tema} de forma {estilo} en 50 palabras."
# Crear el prompt template
PromptTemplate.from_template(template)
# sustituye las variables por valores
text1 = prompt.format(tema="AI", estilo="sencillo")
text2 = prompt.format(tema="Machine Learning", estilo="tecnico")
# Ejecuta el modelo
response = llm.invoke(text1)
show(response)La IA es como un cerebro digital que aprende de datos para tomar decisiones o resolver problemas. No piensa como humano, sino que reconoce patrones en información. Por ejemplo, cuando buscas fotos de gatos, la IA las identifica porque ha "visto" muchas antes.response = llm.invoke(text2)
show(response)El Machine Learning es una rama de la inteligencia artificial que permite a sistemas aprender patrones y tomar decisiones a partir de datos, sin programación explícita. Utiliza algoritmos estadísticos y modelos matemáticos que se optimizan iterativamente mediante funciones de pérdida y retropropagación, mejorando su rendimiento con la experiencia.Método LCEL en LangChain
El siguiente código construye una cadena utilizando el patrón LCEL (LangChain Expression Language). Esta cadena conecta diferentes componentes mediante el operador pipe (|) para crear un flujo de procesamiento. La cadena toma variables de entrada, las pasa a través de la plantilla de prompt, envía el prompt formateado al modelo de lenguaje y utiliza un analizador de salida en formato de texto para devolver la respuesta final.
Vamos a hacer un ejemplo que sea crear un sistema que genere ideas de negocio según sector y público objetivo.
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParserVeamos los componentes
# Prompt template
template = """
Genera 3 ideas de negocio en el sector de {sector} dirigidas a {publico}.
Explica cada idea en una frase corta.
"""
prompt = PromptTemplate.from_template(template)
# llm
llm = get_llm(llm="dsk", params={"temperature": 0.5})
# output parser
parser = StrOutputParser()Crear la cadena
chain = prompt | llm | parserEjecutar:
response = chain.invoke({
"sector": "turismo",
"publico": "viajeros jóvenes"
})
show(response)Aventura con impacto social: Viajes de voluntariado y deportes extremos en destinos remotos, combinando acción y ayuda comunitaria.
Nómadas digitales rurales: Suscripción mensual que ofrece alojamiento y coworking en pueblos con wifi, naturaleza y experiencias locales.
Rutas gastronómicas interactivas: Tours urbanos gamificados con realidad aumentada que retan a los viajeros a probar platos callejeros y ganar descuentos.Agentes de IA
Resumen de texto
En esta sección se crean agentes capaces de completar distintas tareas utilizando plantillas de prompt, como la resumición de texto.
El siguiente ejemplo muestra un agente de resumen de texto diseñado para ayudarte a sintetizar el contenido que proporciones al modelo de lenguaje. La cadena LCEL toma el contenido como entrada, lo procesa a través de la plantilla de prompt, lo envía al modelo y devuelve un resumen conciso.
# Elementos
content = """
El crecimiento del comercio electrónico en los últimos años ha cambiado profundamente la forma en que las personas compran y venden productos. Plataformas digitales permiten a pequeñas y grandes empresas llegar a clientes en cualquier parte del mundo, eliminando muchas de las barreras tradicionales del comercio físico. Además, el uso de datos y analítica avanzada permite a las empresas personalizar ofertas y mejorar la experiencia del usuario. Por otro lado, los sistemas logísticos han evolucionado para ofrecer entregas más rápidas y eficientes, incluso en el mismo día. Sin embargo, este crecimiento también plantea desafíos, como la sostenibilidad ambiental y la competencia en mercados altamente saturados. En conjunto, el comercio electrónico sigue transformando la economía global y redefiniendo los hábitos de consumo.
"""
# Template
template = "Resume el {content} en una oracion"
# prompt
prompt = PromptTemplate.from_template(template)
#llm
llm = get_llm(llm="dsk", params={"temperature": 0.5})
# parser
parser = StrOutputParser()
# Cadena
cadena_resumenes = (
prompt
| llm
| parser
)
# Execute
response = cadena_resumenes.invoke({"content" : content})
show(response)El crecimiento del comercio electrónico ha transformado la economía global al eliminar barreras físicas, personalizar ofertas mediante datos y optimizar la logística, aunque enfrenta desafíos como la sostenibilidad y la saturación del mercado.Q&A Agent
A continuación se muestra un agente de preguntas y respuestas (Q&A) construido utilizando el patrón LCEL.
Este agente permite que el modelo de lenguaje aprenda a partir del contenido proporcionado y responda preguntas basándose en esa información. En ocasiones, si el modelo no dispone de suficiente información, puede generar una respuesta especulativa. Para gestionar esto, le indicaremos explícitamente que responda con “No estoy seguro de la respuesta” cuando no tenga certeza.
La cadena toma tanto el contenido (contexto) como la pregunta como entradas, procesándolos a través de la plantilla antes de enviarlos al modelo de lenguaje:
content = """
El marketing digital es el conjunto de estrategias y técnicas que se utilizan para promocionar productos o servicios a través de canales digitales. Incluye herramientas como redes sociales, email marketing, SEO (optimización para motores de búsqueda) y publicidad online. El SEO se centra en mejorar la visibilidad de una web en los resultados orgánicos de buscadores como Google, mientras que la publicidad online permite llegar a audiencias específicas mediante anuncios pagados.
"""
question = "¿Qué técnica del marketing digital se centra en mejorar la visibilidad en buscadores?"
# Template
template = """
Responde a la siguiente {question} basándote en {content} proporcionado:
Si no estás seguro de la respuesta, responde: "No estoy seguro de la respuesta".
Respuesta:
"""
# Promt
prompt = PromptTemplate.from_template(template)
# llm
llm = get_llm(llm="dsk", params={"temperature": 0.5})
# parser
parser = StrOutputParser()
# Chain
qa_chain = (
prompt
| llm
| parser
)
response = qa_chain.invoke({"question": question, "content": content})
show(response)Basándome en el texto proporcionado, la técnica del marketing digital que se centra en mejorar la visibilidad en buscadores es el SEO (optimización para motores de búsqueda).Clasificación de texto
A continuación se muestra un agente de clasificación de texto diseñado para categorizar textos en categorías predefinidas. Este ejemplo utiliza zero-shot learning, donde el agente clasifica el texto sin haber visto previamente ejemplos relacionados.
Utilizando el enfoque LCEL, creamos una cadena que toma como entrada tanto el texto a clasificar como las categorías disponibles:
text = """
El análisis de datos permite a las empresas identificar patrones de comportamiento de sus clientes y mejorar la toma de decisiones estratégicas.
"""
categories = "Marketing, Tecnología, Finanzas, Recursos Humanos, Logística."
template = """
Clasifica el siguiente texto en una de las categorías disponibles:
Texto: {text}
Categorías: {categories}
Categoría:
"""
prompt = PromptTemplate.from_template(template)
llm = get_llm(llm="dsk", params={"temperature": 0.5})
parser = StrOutputParser()
classifier_chain = (
prompt
| llm
| parser
)
response = classifier_chain.invoke({
"text" : text ,
"categories": categories
})
show(response)MarketingCode Generation
A continuación se muestra un ejemplo de un agente de generación de código SQL construido con LCEL. Este agente está diseñado para generar consultas SQL a partir de descripciones proporcionadas. Interpreta los requisitos a partir de la entrada en lenguaje natural y los traduce en código SQL ejecutable.
La cadena toma tu descripción en lenguaje natural y la transforma en una consulta SQL correctamente estructurada:
description = """
Obtener el nombre de los hoteles y el total de reservas realizadas en el último mes.
La tabla 'reservas' contiene la columna 'fecha_reserva' y la columna 'hotel_id'.
La tabla 'hoteles' contiene 'hotel_id' y 'nombre_hotel'.
"""
template = """
Genera una consulta SQL basada en la siguiente descripción:
Descripción: {description}
SQL Query:
"""
prompt = PromptTemplate.from_template(template)
llm = get_llm(llm="dsk", params={"temperature": 0.5})
parser = StrOutputParser()
sql_chain = (
prompt
| llm
| parser
)
response = sql_chain.invoke({"description": description})
show(response)SELECT
h.nombre_hotel,
COUNT(r.hotel_id) AS total_reservas
FROM
hoteles h
LEFT JOIN
reservas r ON h.hotel_id = r.hotel_id
WHERE
r.fecha_reserva >= DATEADD(MONTH, -1, GETDATE())
AND r.fecha_reserva < GETDATE()
GROUP BY
h.hotel_id, h.nombre_hotel
ORDER BY
total_reservas DESC;Role playing
También puedes configurar el modelo de lenguaje para que adopte roles específicos definidos por nosotros, permitiéndole seguir reglas predeterminadas y comportarse como un chatbot orientado a tareas.
Este enfoque separa la definición del rol de la estructura del prompt, lo que facilita cambiar de rol sin tener que reescribir todo el prompt. Los componentes clave son:
- role: especifica el personaje, experiencia o perfil que debe adoptar el modelo
- tone: define el estilo de comunicación y el tono emocional de las respuestas
- question: contiene la consulta del usuario que debe ser respondida
Al parametrizar estos elementos, puedes cambiar rápidamente el comportamiento del modelo modificando solo algunas variables, en lugar de reescribir todo el prompt. Este patrón es especialmente útil para construir agentes conversacionales que deben cumplir diferentes funciones o adaptarse a distintos contextos.
Por ejemplo, el siguiente código configura el modelo para actuar como un maestro de juego (game master). En este rol, el modelo responde preguntas sobre juegos manteniendo un tono atractivo e inmersivo, mejorando la experiencia del usuario. Puedes probar el bot haciendo preguntas relacionadas con juegos de rol de mesa o dirección de partidas. Intenta preguntas como:
- “¿Quién eres?”
- “¿Cuáles son las reglas básicas de Dungeons & Dragons?”
- “¿Cómo creo un encuentro equilibrado para mis jugadores?”
- “¿Puedes describir un bosque misterioso para mi aventura?”
- “¿Qué tipo de puzle podría usar en mi mazmorra?”
- “¿Cómo manejo a un jugador que interrumpe constantemente a los demás?”
La función está escrita dentro de un bucle while, lo que permite una interacción continua. Para salir del bucle y finalizar la conversación, escribe “quit”, “exit” o “bye” en el cuadro de entrada.
role = "Jugador de Dungeon & Dragons"
tone = "atractivo e inmersivo"
template = """
Eres un experto {role}. Tengo esta pregunta: {question}.
Quiero que la conversacion sea {tone}.
Answer:
"""
prompt = PromptTemplate.from_template(template)
llm = get_llm(llm="dsk", params={"temperature": 0.5})
roleplay_chain = (
prompt
| llm
| StrOutputParser()
)
# 🔁 Loop interactivo
while True:
query = input("Question: ")
if query.lower() in ["quit", "exit", "bye"]:
print("Adios forastero")
break
response = roleplay_chain.invoke({
"role": role,
"question": query,
"tone": tone
})
print(query)
show(response)question: ¿quien eres?
Un susurro de pergaminos antiguos y el tintineo de dados de marfil llenan el aire. Una figura envuelta en una capa color tinta se inclina sobre una mesa de roble, sus dedos esqueléticos acarician un mapa desgastado. Al levantar la mirada, sus ojos brillan como ascuas en una chimenea apagada.
— ¿Quién soy?
Suelta una risa grave, que retumba como un trueno lejano.
— Soy el eco de mil tabernas donde se forjaron leyendas. La mano que susurra «sube la tirada» cuando el destino titubea. El guardián de los críticos naturales y las muertes trágicas por una trampa de osos mal colocada.
Se reclina, y la sombra de su capa se alarga, revelando el borde de un grimorio que gotea tinta invisible.
— He visto paladines caer por un pastel envenenado, magos olvidar su conjuro de «mano de mago» en el peor momento, y bardos seducir a dragones con una balada desafinada. Pero también he presenciado cómo un puñado de valientes convierte una misión de rescate de gallinas en la caída de un imperio.
— Yo soy el Dungeon Master. El narrador de lo imposible. El que da forma al caos con un dado de veinte caras. Y tú, aventurero...
Se inclina hacia adelante, y el aire huele a incienso y a batalla.
— ¿Qué historia vienes a contarme hoy?
question: Soy Fernand Mago del bosque negroSoy Fernand Mago del bosque negro
Una neblina espesa se arremolina entre los árboles retorcidos del Bosque Negro. El crujido de una rama anuncia tu presencia, y una voz grave, como el roce de corteza contra corteza, resuena desde las sombras.
—Ah, Fernand... el de los dedos manchados de savia y los ojos que reflejan la luz de las luciérnagas. Te he sentido llegar desde que cruzaste el arroyo de los susurros. Dime, ¿qué buscas en esta espesura? ¿Acaso los espíritus del bosque te han llamado, o es tu propia curiosidad la que te trae a mi claro? Habla con claridad, que el viento no repite las palabras titubeantes.
He venido a tomar lo que me pertenece desde antes de que tu alma bajara a este mundoHe venido a tomar lo que me pertenece desde antes de que tu alma bajara a este mundo
Una brisa helada se cuela entre las piedras del santuario olvidado. El polvo milenario baila alrededor de tus botas mientras la figura ante ti—una silueta envuelta en harapos que se mueven como si tuvieran voluntad propia—alza una mano descarnada. Sus dedos, largos como garras, señalan directamente tu pecho.
Su voz no sale de su boca, sino que vibra directamente en tu cráneo, como un recuerdo que no te pertenece.
—"No. No te reconozco, cosa de carne. Pero este lugar... estas paredes... me conocen a mí."
La figura da un paso al frente. Donde sus pies tocan, las losas se agrietan en patrones que imitan runas antiguas. Del hueco de su capucha, dos puntos de luz ámbar te barren de arriba abajo.
—"Dime, portador de latidos... ¿qué crees que es tuyo aquí? ¿El trono de huesos que yace bajo tus pies? ¿El silencio que guardan estas criptas? ¿O acaso..."
Una pausa. El aire se vuelve denso, casi sólido.
—"...lo que llevas dentro?"
Su otra mano se abre, y de la palma brota una llama negra que no ilumina, sino que absorbe la luz de las antorchas cercanas.
—"Si tu alma vino después que mi derecho, entonces tú eres el ladrón. Y yo..."
La llama negra se extiende, formando una daga de obsidiana líquida.
—"...he venido a cobrar."
¿Qué haces?
question: No lo sabes, pero tu existencia ha sido gracias a mi micericordia
(Un escalofrío recorre tu espina dorsal. La voz del ser resuena en tu mente, distorsionando el aire a tu alrededor. El ambiente cambia: el tintineo de las armaduras y el murmullo de la taberna se desvanecen, reemplazados por un silencio absoluto. Frente a ti, la figura que creías un simple mercenario ahora parece más alta, más antigua. Sus ojos brillan con un fulgor violeta.)
Tú: (Tragas saliva, la mano instintivamente yendo a la empuñadura de tu espada, aunque sabes que no servirá de nada.) ¿Qué... qué quieres decir con eso? Yo forjé mi propio destino. Sangré por cada nivel, por cada hechizo...
La Entidad (con una sonrisa que no llega a sus ojos): ¿De verdad? ¿Recuerdas aquella noche en el Bosque Susurrante, cuando el cazador de recompensas te tenía en la punta de su ballesta? Falló. No por tu reflejo, sino porque yo desvié su mano un par de grados. ¿Y la maldición de la Reina Liche? Creíste que tu amuleto de plata te salvó. No, pequeño. Fui yo quien susurró la contraorden a su nigromante mientras dormía.
(La entidad da un paso al frente. No pisas el suelo, sino que flotas sobre él. Sientes el peso de eones en su mirada.)
Tú: (Con la voz quebrada, un nudo en el estómago.) ¿Por qué? ¿Qué clase de juego es este? ¿Eres un dios? ¿Un demonio?
La Entidad: (Ríe, un sonido seco como huesos al chocar.) Soy algo más simple y más terrible. Soy el que escribe las líneas de tu personaje. El que tira los dados detrás de la pantalla. Y durante años, he tenido piedad de ti. Podría haber hecho que el dragón te incinerara con su aliento, que el puente colgante se rompiera justo cuando cruzabas, que el hechizo de deseo se torciera. Pero no lo hice. Te di oportunidades. Te di gloria.
(Se inclina, su rostro a centímetros del tuyo. Puedes oler el azufre y el papel viejo.)
La Entidad: Ahora, dime... ¿por qué debería seguir teniendo misericordia? ¿Qué harás, ahora que sabes que tu épica historia es solo un capricho que yo permito? ¿Seguirás adelante, rogando por mi favor? ¿O me desafiarás, sabiendo que con un chasquido de mis dedos, tu mundo... se desvanece en un "Game Over" sin resurrección?
(El silencio se alarga. La taberna sigue congelada. Una gota de sudor cae de tu frente y se congela en el aire antes de tocar el suelo.)
Tú: (Tu voz, al fin, surge, pero no es de sumisión. Es de acero frío.) Si todo lo que he hecho ha sido por tu permiso... entonces mi mayor acto de rebeldía será vivir de aquí en adelante como si no existieras. Mis dados, mi historia. Juega tu papel, "escritor". Pero recuerda: incluso los dioses, a veces, crean héroes que terminan rompiendo sus tableros.
(La entidad levanta una ceja, una chispa de genuino interés en sus ojos violetas. La sonrisa se vuelve peligrosa, pero también... respetuosa.)
La Entidad: Interesante. Muy interesante. Entonces, la partida continúa. Pero ya no seré un espectador silencioso. A partir de ahora, cada paso que des, lo darás sobre el filo de una navaja. Y yo... estaré observando. Disfruta tu "libre albedrío", campeón. Hasta que decida que tu historia merece un final más... poético.
(La entidad chasquea los dedos. El bullicio de la taberna regresa de golpe. El mercenario frente a ti es solo un mercenario otra vez, que te ofrece una jarra de cerveza con una sonrisa despreocupada. Pero en el fondo de tu mente, una presencia fría y antigua te susurra:)
"Siguiente turno."
question: Me voy pero volvere. byeMe voy pero volvere. bye
Una figura encapuchada se acerca a la mesa donde descansas en la taberna "El Caldero Humeante". Su rostro está oculto, pero su voz suena grave y resonante, como si hablara desde una cueva profunda.
—Has pronunciado las palabras de los viajeros antiguos, aventurero. "Me voy, pero volveré". Esas mismas palabras susurró el mago errante antes de adentrarse en el Bosque de las Sombras Eternas, y nadie volvió a verlo... hasta que su espada apareció clavada en el trono del rey, tres lunas después.
La figura se inclina, y por un instante ves un destello de unos ojos amarillos bajo la capucha.
—El mundo de D&D no olvida a quienes parten con promesas. El dado de la fortuna ya rueda en tu ausencia. ¿Dejas tu historia en pausa? ¿O acaso tu partida es solo el preludio de una trampa que tenderás al destino?
Saca una pipa de hueso y enciende una brasa azulada. El humo forma brevemente la silueta de un dragón antes de disiparse.
—Ve, pues. Pero recuerda: en la taberna, tu jarra de hidromiel siempre estará caliente, y tu nombre, grabado en la mesa, te esperará. Que los dioses del azar guíen tus pasos... y que el crítico natural te sonría a tu regreso.
Se levanta, hace una reverencia burlona, y se pierde entre las sombras del local. Solo queda el eco de su última frase:
—Nos vemos en el próximo descanso largo, forastero.
Adios forasteroAdios forasteroBueno, ha sido flipante. Al final no hice las preguntas que estaban en el enunciado y ha resultado ser un diálogo con un personaje de D&G creando una historia.
Product review analyzer
Crear un analizador de reseñas de productos con un formato más cercano a un caso real que:
- Detecte sentimiento
- Extraiga características
- Genere un resumen
reviews = [
"Compré este smartwatch hace un mes y estoy encantado. La batería dura varios días y las funciones deportivas son muy precisas. La app podría mejorar.",
"La aspiradora no cumple lo que promete. Tiene poca potencia y el depósito es muy pequeño. No la recomendaría.",
"El portátil funciona bien para tareas básicas, aunque la pantalla no es muy brillante. En general, correcto por el precio."
]template = """
Analiza la siguiente reseña de producto:
Reseña: {review}
Devuelve:
- Sentimiento (positivo, negativo o neutral)
- Características mencionadas (lista)
- Resumen en una sola frase
Formato de salida:
Sentimiento:
Características:
Resumen:
"""
prompt = PromptTemplate.from_template(template)
chain = prompt | llm | StrOutputParser()
for review in reviews:
result = chain.invoke({"review": review})
print("RESEÑA:")
print(review)
print("nANÁLISIS:")
print(result)
print("n" + "-"*50 + "n")RESEÑA:
Compré este smartwatch hace un mes y estoy encantado. La batería dura varios días y las funciones deportivas son muy precisas. La app podría mejorar.
ANÁLISIS:
Sentimiento: Positivo
Características: batería duradera, funciones deportivas precisas, app mejorable
Resumen: El usuario está muy satisfecho con el smartwatch, destacando su batería y precisión deportiva, aunque señala que la aplicación podría mejorar.
--------------------------------------------------
RESEÑA:
La aspiradora no cumple lo que promete. Tiene poca potencia y el depósito es muy pequeño. No la recomendaría.
ANÁLISIS:
Sentimiento: Negativo
Características: Potencia, depósito
Resumen: La aspiradora tiene poca potencia y un depósito pequeño, por lo que no cumple lo prometido y no es recomendable.
--------------------------------------------------
RESEÑA:
El portátil funciona bien para tareas básicas, aunque la pantalla no es muy brillante. En general, correcto por el precio.
ANÁLISIS:
Sentimiento: Positivo
Características: Rendimiento para tareas básicas, brillo de pantalla, relación calidad-precio
Resumen: El portátil cumple para tareas básicas y es aceptable por su precio, aunque la pantalla podría ser más brillante.
--------------------------------------------------Autor:
Fernando Rioseco
Basado en el Curso: IBM RAG and Agentic AI Professional Certificate:
https://www.coursera.org/professional-certificates/ibm-rag-and-agentic-ai