Sebastian Gomez
Muchos de los modelos de lenguaje de razonamiento más potentes hoy en día son propietarios y de código cerrado. Esto limita el acceso para los desarrolladores 👩💻 y frena la investigación 🔬 en estas capacidades cruciales. ¡Pero no te preocupes! En este artículo, construiremos nuestro propio agente de razonamiento usando Gemini 1.5 Flash de Google, ajustándolo (haciendo fine-tuning) con un conjunto de datos disponible públicamente. Nuestro objetivo es replicar el razonamiento de “cadena de pensamiento” (chain-of-thought) que a menudo se encuentra en los modelos cerrados. Este método consiste en que el modelo explica su proceso de pensamiento paso a paso antes de proporcionar la respuesta final 🤔➡️💡, haciendo esta poderosa técnica mucho más accesible para todos.
¿Por qué es importante el razonamiento explícito? 🤔
Que un modelo “piense en voz alta” no es solo un truco interesante. Tiene beneficios concretos:
Lograremos esto usando Vertex AI de Google Cloud Platform (GCP) ☁️, demostrando el flujo de trabajo completo desde la preparación de los datos hasta el despliegue del modelo ajustado.
Creando un Bucket de Almacenamiento 🪣Antes de poder entrenar nuestro modelo, necesitamos un lugar seguro y accesible para guardar nuestros datos de entrenamiento. Usaremos Google Cloud Storage (GCS) para esto. Piensa en GCS como un disco duro gigante y seguro en la nube ☁️💾 donde puedes almacenar archivos de cualquier tipo.
Un “bucket” en GCS es esencialmente un contenedor principal para tus datos. Es similar a una carpeta en tu computadora, pero a una escala mucho mayor y optimizado para la nube. ¿Por qué lo necesitamos? Porque Vertex AI (la plataforma donde entrenaremos el modelo) necesita poder acceder a los datos de entrenamiento desde una ubicación centralizada y eficiente. Un bucket de GCS proporciona una forma confiable, escalable y perfectamente integrada con otros servicios de GCP para poner nuestro conjunto de datos a disposición del proceso de entrenamiento de Vertex AI.
Pasos para crear un bucket:
Para permitir que nuestro código (que correrá, por ejemplo, en un cuaderno de Colab o en una instancia de Vertex AI) interactúe de forma segura con Vertex AI y Cloud Storage, necesitamos configurar una cuenta de servicio y sus permisos usando Identity and Access Management (IAM).
Una cuenta de servicio es como una identidad especial de Google que usan las aplicaciones o servicios (como nuestro script de entrenamiento) 🤖, en lugar de usuarios individuales 👤. Esto es crucial por seguridad: en lugar de usar tus credenciales personales en el código (¡nunca hagas eso!), le damos a nuestro código su propia identidad con permisos específicos y limitados.
Pasos para configurar la cuenta de servicio en GCP:
Antes de empezar a trabajar con el dataset y Vertex AI, necesitamos instalar e importar las librerías de Python necesarias. Esta sección cubre los paquetes requeridos. ¡Manos a la obra!
```python
# Instalar las librerías necesarias
!pip install datasets --quiet
!pip install google-cloud-storage Pillow --quiet
!pip install --upgrade google-cloud-aiplatform --quiet
# Autenticar gcloud (esto puede abrir una ventana de login en Colab/notebooks)
!gcloud auth application-default login
```python
# Importar las librerías
import datasets
import json
from copy import deepcopy # Para copiar estructuras de datos complejas
from google.cloud import storage
from google.oauth2 import service_account # Para usar la clave JSON
import time # Para pausas y monitoreo
import vertexai
import os # Para interactuar con el sistema operativo (variables de entorno)
from vertexai.tuning import sft # Specificamente para Supervised Fine-Tuning
from vertexai.generative_models import GenerativeModel, SafetySetting, Part # Para usar los modelos Gemini
Ahora, sube el archivo de clave JSON que descargaste (ej: finetune-gemini-razonamiento-xxxxxxxx.json) al entorno donde estés ejecutando este código (por ejemplo, a la sesión de Colab). Luego, definiremos algunas variables constantes que usaremos a lo largo del cuaderno.
Asegúrate de ajustar los valores con el nombre de tu bucket y el nombre exacto de tu archivo de clave.
```python
# --- CONFIGURACIÓN ---
# ¡¡¡CAMBIA ESTOS VALORES POR LOS TUYOS!!!
BUCKET_NAME = "reasoning_dataset_bucket" # ⚠️ Reemplaza con el nombre de TU bucket
SERVICE_ACCOUNT_KEY_PATH = "/content/finetune-gemini-razonamiento-xxxxxxxx.json" # ⚠️ Reemplaza con la ruta a TU archivo de clave en el entorno
PROJECT_ID = "tu-proyecto-gcp-id" # ⚠️ Reemplaza con el ID de tu proyecto GCP
LOCATION = "us-central1" # Puedes elegir otra región compatible con Vertex AI y Gemini
# Modelo base de Gemini a ajustar
# Puedes probar 'gemini-1.5-pro-002' si necesitas más potencia (y presupuesto)
MODEL_BASE = "gemini-1.5-flash-001" # Usamos la version flash por eficiencia
# Nombre que le daremos a nuestro modelo ajustado en Vertex AI
FINETUNED_MODEL_NAME = "gemini_1_5_flash_razonador_ajustado_v1"
# --- FIN CONFIGURACIÓN ---
# Configurar variable de entorno para autenticación con la clave
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = SERVICE_ACCOUNT_KEY_PATH
# Inicializar Vertex AI SDK
vertexai.init(project=PROJECT_ID, location=LOCATION)
print("✅ Configuración lista y Vertex AI inicializado.")
Descargar el Conjunto de Datos y Convertir el Formato 📊➡️📄Ahora descargaremos el conjunto de datos de razonamiento y lo transformaremos al formato específico JSON Lines (JSONL) requerido por Vertex AI para el fine-tuning. JSONL es simplemente un archivo de texto donde cada línea es un objeto JSON válido. Este formato es eficiente para procesar grandes cantidades de datos línea por línea.
Aquí usaremos un dataset de Hugging Face 🤗 llamado KingNish/reasoning-base-20k.
```python
# Descargar el dataset desde Hugging Face
dataset_hf = datasets.load_dataset("KingNish/reasoning-base-20k")
print("Dataset descargado:")
print(dataset_hf)
Este dataset está diseñado específicamente para entrenar modelos a razonar paso a paso sobre problemas, de forma similar a como lo haría un humano 🧑🔬. Contiene una diversidad de problemas (ciencia, código, matemáticas, lógica general) junto con una detallada cadena de pensamiento (COT) que lleva a la respuesta correcta. Crucialmente para nuestro objetivo, el dataset ya separa explícitamente la etapa de "pensamiento" (reasoning) de la "respuesta" final (assistant). ¡Perfecto para lo que queremos!
Para ajustar Gemini en Vertex AI, necesitamos que nuestros datos sigan una estructura JSON específica por cada ejemplo de entrenamiento. La estructura esperada es la siguiente:
// Estructura de ejemplo para UNA línea en el archivo JSONL
{
"system_instruction": { // Opcional: Instrucción general para el modelo
"role": "system",
"parts": [{"text": "Eres un modelo experto en razonamiento..."}]
},
"messages": [ // Lista de turnos de conversación
{
"role": "user", // Lo que el usuario pregunta
"parts": [{"text": "{pregunta_del_dataset}"}]
},
{
"role": "model", // Lo que el modelo debe responder
"parts": [{"text": "<think>{razonamiento_del_dataset}</think>\n<answer>{respuesta_del_dataset}</answer>"}]
}
]
}
system_instruction (opcional): Contiene una instrucción general que guía el comportamiento del modelo en toda la conversación.
messages: Una lista de turnos de conversación. Cada turno tiene:
role: Indica quién habla ("user" para la entrada, "model" para la salida esperada).
parts: Una lista que contiene el texto. Para la parte del "model", incluiremos nuestro formato especial con las etiquetas <think>...</think> para el razonamiento y <answer>...</answer> para la respuesta final.
Vamos a definir una instrucción de sistema estándar y una plantilla para formatear nuestros datos:
# Instrucción de sistema que guiará a nuestro modelo ajustado
instruction = """
Eres un modelo de lenguaje excepcional especializado en razonamiento lógico.
Siempre debes pensar paso a paso antes de proporcionar una respuesta final.
Encierra tu proceso de pensamiento dentro de etiquetas <think> </think>.
Después de pensar, resume tu razonamiento y presenta la respuesta final clara y concisa dentro de etiquetas <answer> </answer>.
"""
# Plantilla base para cada ejemplo JSONL
template_format = {
"messages": [
{
"role": "user",
"parts": [{"text": "{question}"}] # Marcador para la pregunta
},
{
"role": "model",
"parts": [{"text": "{answer}"}] # Marcador para la respuesta formateada (pensamiento + respuesta)
},
]
}
# Añadimos la instrucción del sistema (opcional pero recomendado)
# template_format["system_instruction"] = {"role": "system", "parts": [{"text": instruction}]}
# Nota: Para Gemini 1.5 Flash SFT, la instrucción de sistema se pasa de otra forma durante el entrenamiento,
# así que nos enfocaremos en el formato 'messages' por ahora, pero la incluiremos en la inferencia.
# Función para preprocesar cada ejemplo del dataset de Hugging Face
def preproc_train_data(example):
# Extraer pregunta, razonamiento y respuesta del ejemplo original
now_input = example['user']
now_reasoning = example['reasoning']
now_assistant_answer = example['assistant']
# Construir la salida formateada para el modelo
now_output = f"<think>\n{now_reasoning}\n</think>\n<answer>\n{now_assistant_answer}\n</answer>"
# Crear una copia profunda de la plantilla para no modificar la original
template_now = deepcopy(template_format)
# Rellenar la plantilla con los datos del ejemplo actual
template_now['messages'][0]['parts'][0]['text'] = now_input
template_now['messages'][1]['parts'][0]['text'] = now_output
# Convertir el diccionario JSON a una cadena de texto JSON
# Esto es necesario porque cada línea del archivo JSONL debe ser una cadena JSON
return {
"data_jsonl": json.dumps(template_now)
}
# Aplicar la función de preprocesamiento a todo el dataset
# Usamos 'map' que es muy eficiente. 'num_proc' usa múltiples procesadores si están disponibles.
dataset_processed = dataset_hf.map(preproc_train_data, num_proc=os.cpu_count())
# Extraer solo la columna 'data_jsonl' que contiene las cadenas JSON formateadas
# Nos enfocaremos en el split 'train' para este ejemplo
training_data_jsonl_strings = dataset_processed['train']['data_jsonl']
print(f"📄 Preprocesados {len(training_data_jsonl_strings)} ejemplos de entrenamiento.")
print("Ejemplo de una línea JSONL formateada:")
print(training_data_jsonl_strings[0])
Subir el Dataset al Bucket 📤☁️Ahora que hemos preparado nuestro dataset de entrenamiento en el formato JSONL correcto (como una lista de strings, donde cada string es un JSON), necesitamos subirlo al bucket de Google Cloud Storage que creamos antes. Esto hace que los datos sean accesibles para Vertex AI durante el proceso de fine-tuning.
Usaremos la librería google-cloud-storage para manejar la subida. Aquí hay una función útil para hacerlo:
def upload_list_of_json_strings_to_gcs(bucket_name, destination_blob_name, json_string_list, service_account_key_path):
"""Sube una lista de cadenas JSON a GCS como un archivo JSON Lines (.jsonl).
Args:
bucket_name (str): El nombre del bucket de GCS.
destination_blob_name (str): El nombre del archivo de destino en el bucket (debe terminar en .jsonl).
json_string_list (list): Una lista donde cada elemento es una cadena de texto JSON válida.
service_account_key_path (str): Ruta al archivo de clave de la cuenta de servicio JSON.
"""
try:
# 1. Inicializar el cliente de GCS usando la clave de servicio
storage_client = storage.Client.from_service_account_json(service_account_key_path)
# 2. Obtener el bucket
bucket = storage_client.bucket(bucket_name)
# 3. Crear el blob (archivo) en el bucket
blob = bucket.blob(destination_blob_name)
# 4. Unir la lista de cadenas JSON con saltos de línea para formar el contenido JSONL
jsonl_content = '\n'.join(json_string_list)
# 5. Subir el contenido como una cadena de texto, especificando el tipo de contenido
blob.upload_from_string(jsonl_content, content_type="application/jsonl")
print(f"✅ Archivo JSON Lines '{destination_blob_name}' subido exitosamente a 'gs://{bucket_name}/{destination_blob_name}'")
return f"gs://{bucket_name}/{destination_blob_name}" # Retornar la ruta GCS
except Exception as e:
print(f"❌ Error al subir el archivo JSON Lines: {e}")
return None
# Nombre que le daremos a nuestro archivo en GCS
TRAINING_DATA_GCS_FILENAME = "training_dataset_reasoning_gemini.jsonl"
# Subir los datos de entrenamiento preprocesados
training_data_gcs_uri = upload_list_of_json_strings_to_gcs(
BUCKET_NAME,
TRAINING_DATA_GCS_FILENAME,
training_data_jsonl_strings,
SERVICE_ACCOUNT_KEY_PATH
)
# Guardamos la URI de GCS para usarla en el trabajo de ajuste
if training_data_gcs_uri:
print(f"URI del dataset de entrenamiento en GCS: {training_data_gcs_uri}")
else:
print("⚠️ Hubo un problema al subir el dataset. Revisa los mensajes de error.")
# Puedes verificar la carga yendo a la sección de Cloud Storage en la Consola de GCP,
# navegando a tu bucket. ¡Deberías ver tu archivo .jsonl allí!
Ajuste Fino (Fine-tuning) de Gemini ✨🚀¡Ahora viene el núcleo del proceso! Ajustar el modelo base de Gemini (nuestro MODEL_BASE) con nuestro dataset preparado. Usaremos el SDK de Vertex AI, específicamente la funcionalidad de Supervised Fine-Tuning (SFT), para enviar un trabajo de ajuste (tuning job).
Ya inicializamos Vertex AI antes, así que podemos proceder a definir y lanzar el trabajo.
# Usaremos la función sft.train() del módulo vertexai.tuning
# Documentación: https://cloud.google.com/vertex-ai/docs/generative-ai/models/tune-models
print(f"🚀 Iniciando el trabajo de ajuste fino para el modelo base: {MODEL_BASE}")
print(f"Usando dataset de entrenamiento en: {training_data_gcs_uri}")
# Verificar que la URI del dataset existe antes de lanzar el trabajo
if not training_data_gcs_uri:
raise ValueError("La URI del dataset de GCS no está definida. No se puede iniciar el entrenamiento.")
try:
sft_tuning_job = sft.train(
source_model=MODEL_BASE,
train_dataset=training_data_gcs_uri,
# --- Parámetros Opcionales pero Importantes ---
# validation_dataset="gs://ruta/a/tu/validation_data.jsonl", # ¡Recomendado tener un set de validación!
epochs=2, # Número de veces que el modelo verá el dataset completo. 2-4 es un buen punto de partida.
adapter_size=4, # Tamaño del adaptador LoRA. Valores comunes: 1, 4, 8, 16. Más grande = más capacidad (y coste).
learning_rate_multiplier=1.0, # Multiplicador de la tasa de aprendizaje base. 1.0 suele estar bien.
# upload_pipeline_root=f"gs://{BUCKET_NAME}/pipeline_roots", # Opcional: para guardar artefactos del pipeline
# --- Nombre para el Modelo Ajustado ---
tuned_model_display_name=FINETUNED_MODEL_NAME, # El nombre que definimos antes
)
print("✅ Trabajo de ajuste enviado exitosamente a Vertex AI.")
print(f"ID del trabajo: {sft_tuning_job._gca_resource.name}")
print("Puedes monitorear el progreso en la sección 'Pipelines' o 'Modelos' de Vertex AI en la consola de GCP.")
except Exception as e:
print(f"❌ Error al enviar el trabajo de ajuste: {e}")
La función sft.train() devuelve un objeto sft.TuningJob (lo guardamos en sft_tuning_job). Este objeto representa el trabajo de ajuste que ahora se está ejecutando en la infraestructura de Vertex AI.
Monitoreo del Trabajo:
El ajuste fino puede llevar tiempo ⏳ (desde menos de una hora hasta varias horas o incluso días, dependiendo del tamaño del dataset, el modelo base y los parámetros como epochs y adapter_size). Necesitamos monitorear el progreso del trabajo y esperar a que se complete.
El siguiente código revisa el estado del trabajo cada 60 segundos hasta que termina (ya sea con éxito o con error).
# Solo si el trabajo se envió correctamente
if 'sft_tuning_job' in locals() and sft_tuning_job:
print("🕒 Esperando a que el trabajo de ajuste fino finalice... (Esto puede tardar)")
while not sft_tuning_job.has_ended:
time.sleep(60) # Esperar 60 segundos
try:
sft_tuning_job.refresh() # Actualizar el estado del objeto job
print(f"Estado actual del trabajo ({time.strftime('%H:%M:%S')}): {sft_tuning_job.state}")
except Exception as e:
print(f"⚠️ Error al refrescar el estado del job: {e}. Reintentando...")
time.sleep(60) # Espera extra si hay error de API
# Una vez que el bucle termina, el trabajo ha finalizado
print("\n🎉 ¡El trabajo de ajuste ha finalizado!")
# Verificar el estado final
if sft_tuning_job.state == vertexai.JobState.JOB_STATE_SUCCEEDED:
print("✅ El trabajo se completó exitosamente.")
# Obtener información sobre el modelo ajustado y su endpoint (si se creó automáticamente)
tuned_model = sft_tuning_job.get_tuned_model()
print(f"Nombre del modelo ajustado registrado en Vertex AI: {tuned_model.name}")
# Importante: El ajuste SFT en Vertex AI ahora crea un *Modelo* pero no despliega automáticamente un *Endpoint*.
# Necesitarás ir a la consola de Vertex AI > Model Registry, encontrar tu modelo
# (por el display_name: FINETUNED_MODEL_NAME) y desplegarlo manualmente a un Endpoint.
print("\n➡️ Acción Requerida: Ve a la consola de Vertex AI > Model Registry, busca tu modelo")
print(f" '{FINETUNED_MODEL_NAME}' y despliégalo a un nuevo Endpoint para poder usarlo.")
# Guarda el nombre del recurso del modelo para referencia
TUNED_MODEL_RESOURCE_NAME = tuned_model.name
print(f" Nombre del recurso del modelo: {TUNED_MODEL_RESOURCE_NAME}")
else:
print(f"❌ El trabajo falló o fue cancelado. Estado final: {sft_tuning_job.state}")
print(f"Error (si está disponible): {sft_tuning_job.error}")
else:
print("⚠️ No se pudo iniciar el monitoreo porque el trabajo de ajuste no se envió correctamente.")
Una vez que el trabajo se completa con éxito (JOB_STATE_SUCCEEDED), tendrás un nuevo modelo registrado en el Model Registry de Vertex AI. El paso crucial siguiente es desplegar este modelo a un Endpoint. Un Endpoint es básicamente una URL de servicio web 🌐 que expone tu modelo ajustado para que puedas enviarle solicitudes de inferencia (hacerle preguntas). Puedes hacer esto fácilmente desde la interfaz de usuario de la consola de Google Cloud.
Inferencia (Usando el Modelo Ajustado) 🤖💡¡Felicidades! Si llegaste hasta aquí, has ajustado tu propio modelo Gemini. Ahora que tu modelo ajustado está desplegado en un Endpoint de Vertex AI, podemos enviarle prompts (preguntas o instrucciones) y recibir respuestas que demuestren sus nuevas capacidades de razonamiento, siguiendo el formato <think>...</think><answer>...</answer> que le enseñamos.
Primero, necesitas obtener el nombre completo del Endpoint al que desplegaste tu modelo. Lo encontrarás en la consola de Vertex AI, en la sección "Endpoints". Se verá algo como: projects/TU_PROJECT_ID/locations/TU_REGION/endpoints/TU_ENDPOINT_ID.
# --- CONFIGURACIÓN DE INFERENCIA ---
# ⚠️ ¡¡¡ REEMPLAZA CON EL NOMBRE DE TU ENDPOINT DESPLEGADO !!! ⚠️
ENDPOINT_NAME = "projects/tu-proyecto-gcp-id/locations/us-central1/endpoints/1234567890123456789" # Ejemplo, usa el tuyo
if "TU_PROJECT_ID" in ENDPOINT_NAME or "123456789" in ENDPOINT_NAME:
print("🚨 ¡ALERTA! Parece que no has reemplazado el ENDPOINT_NAME de ejemplo. Por favor, actualízalo con el nombre real de tu endpoint de Vertex AI.")
# Puedes detener la ejecución si no quieres continuar con un endpoint incorrecto
# raise ValueError("Endpoint no configurado.")
else:
print(f"Usando el endpoint: {ENDPOINT_NAME}")
# Re-inicializar Vertex AI si es necesario (por si estás en una sesión nueva)
# os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = SERVICE_ACCOUNT_KEY_PATH
# vertexai.init(project=PROJECT_ID, location=LOCATION)
# Cargar el modelo Generativo apuntando al Endpoint del modelo ajustado
# Ya no usamos el MODEL_BASE, sino el Endpoint que sirve nuestro modelo tuneado
try:
tuned_model_endpoint = GenerativeModel(model_name=ENDPOINT_NAME)
print("✅ Modelo ajustado cargado desde el endpoint.")
except Exception as e:
print(f"❌ Error al cargar el modelo desde el endpoint '{ENDPOINT_NAME}': {e}")
print(" Asegúrate de que el nombre del endpoint es correcto y que el modelo está desplegado y activo.")
tuned_model_endpoint = None # Marcar como no cargado
Ahora, definamos una función para enviar un prompt al modelo y obtener la respuesta. Incluiremos la
instrucción de sistema
que definimos antes para reforzar el comportamiento deseado (pensar antes de responder). También configuraremos algunos parámetros de generación y seguridad.
# Instrucción de sistema (la misma que usamos para pensar en el formato)
system_instruction_inference = """
Eres un modelo de lenguaje excepcional especializado en razonamiento lógico.
Siempre debes pensar paso a paso antes de proporcionar una respuesta final.
Encierra tu proceso de pensamiento dentro de etiquetas <think> </think>.
Después de pensar, resume tu razonamiento y presenta la respuesta final clara y concisa dentro de etiquetas <answer> </answer>.
"""
# Configuración de generación (controla cómo el modelo genera el texto)
generation_config = {
"max_output_tokens": 2048, # Máximo de tokens en la respuesta
"temperature": 0.3, # Creatividad (0 = determinista, >1 = más creativo/aleatorio) - Usamos bajo para razonamiento
"top_p": 0.95, # Muestreo por núcleo (nucleus sampling)
# "top_k": 40, # Muestreo por top-k (opcional)
}
# Configuración de seguridad (puedes ajustarla según tus necesidades)
# Aquí las desactivamos para este ejemplo, pero en producción considera habilitarlas.
# ¡CUIDADO! Desactivar filtros puede permitir contenido potencialmente dañino.
safety_settings = {
vertexai.generative_models.HarmCategory.HARM_CATEGORY_HATE_SPEECH: vertexai.generative_models.HarmBlockThreshold.BLOCK_NONE,
vertexai.generative_models.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: vertexai.generative_models.HarmBlockThreshold.BLOCK_NONE,
vertexai.generative_models.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: vertexai.generative_models.HarmBlockThreshold.BLOCK_NONE,
vertexai.generative_models.HarmCategory.HARM_CATEGORY_HARASSMENT: vertexai.generative_models.HarmBlockThreshold.BLOCK_NONE,
}
# Función para generar contenido con el modelo ajustado
def generate_with_tuned_model(prompt_text):
if not tuned_model_endpoint:
print("Modelo no cargado, no se puede generar contenido.")
return None
print(f"\n🤔 Enviando prompt al modelo ajustado: '{prompt_text}'")
try:
# Iniciar una 'conversación' (aunque sea de un solo turno) aplicando la instrucción de sistema
# Nota: Para endpoints, pasamos la instrucción de sistema directamente al crear el objeto GenerativeModel
# o en cada llamada a generate_content si no se hizo al inicio. Recreamos el objeto aquí
# para asegurarnos de incluirla.
model_with_system_instruction = GenerativeModel(
ENDPOINT_NAME,
system_instruction=[system_instruction_inference] # Pasamos la instrucción aquí
)
response = model_with_system_instruction.generate_content(
[prompt_text], # El prompt del usuario como una lista
generation_config=generation_config,
safety_settings=safety_settings,
# stream=False # Poner True si quieres respuesta en streaming
)
print("✅ Respuesta recibida.")
return response
except Exception as e:
print(f"❌ Error durante la inferencia: {e}")
return None
# --- ¡Probemos el modelo! ---
question = "¿Qué pasa si no tengo suficiente dinero para pagar GCP y no he vinculado mi tarjeta de crédito?"
# Generar la respuesta completa
full_response = generate_with_tuned_model(question)
# Procesar la respuesta para extraer las partes de pensamiento y respuesta
if full_response and full_response.candidates:
try:
full_text = full_response.candidates[0].content.parts[0].text
# Extraer la parte del pensamiento
thinking_part = ""
if "<think>" in full_text and "</think>" in full_text:
start_think = full_text.find("<think>") + len("<think>")
end_think = full_text.find("</think>")
thinking_part = full_text[start_think:end_think].strip()
# Extraer la parte de la respuesta
answer_part = ""
if "<answer>" in full_text and "</answer>" in full_text:
start_answer = full_text.find("<answer>") + len("<answer>")
end_answer = full_text.find("</answer>")
answer_part = full_text[start_answer:end_answer].strip()
elif "</think>" in full_text: # Si no hay <answer> pero sí </think>, tomar lo que sigue
answer_part = full_text.split("</think>", 1)[1].strip()
else: # Si no hay ninguna etiqueta, tomar todo como respuesta (fallback)
answer_part = full_text.strip()
print("\n--- Proceso de Pensamiento del Modelo --- 🤔")
print(thinking_part if thinking_part else "(No se encontró la etiqueta <think>)")
print("\n--- Respuesta Final del Modelo --- 💡")
print(answer_part if answer_part else "(No se encontró la etiqueta <answer> o texto después de </think>)")
except (AttributeError, IndexError, ValueError) as e:
print(f"⚠️ No se pudo parsear la respuesta del modelo: {e}")
print("Respuesta completa recibida:")
print(full_response)
else:
print("No se recibió una respuesta válida del modelo.")
Conclusión ✅🎉En este artículo, hemos recorrido el camino completo para ajustar con éxito el modelo Gemini 1.5 Flash de Google y convertirlo en un agente de razonamiento capaz de demostrar su proceso de "cadena de pensamiento".
Comenzamos con un problema común: la opacidad de muchos modelos potentes. Nuestra solución fue tomar un modelo accesible (Gemini Flash), un dataset público diseñado para razonar (KingNish/reasoning-base-20k), y usar las herramientas de Google Cloud Platform, específicamente Vertex AI y Google Cloud Storage, para:
Lo que podría parecer una tarea desalentadora — construir un modelo que no solo responde, sino que explica cómo llegó a la respuesta — es sorprendentemente accesible gracias a las plataformas y herramientas modernas como las que ofrece Google Cloud 🛠️. El proceso, aunque involucra varios pasos (preparación de datos, configuración de permisos, entrenamiento, despliegue, inferencia), es bastante directo cuando se desglosa.
El SDK de Vertex AI, en particular, simplifica enormemente muchas de las complejidades subyacentes de la gestión de infraestructura y el entrenamiento de modelos grandes, permitiéndote concentrarte en la tarea central: enseñarle a tu modelo a pensar y razonar mejor para tus necesidades específicas. ¡Ahora tienes el poder de crear modelos más transparentes y confiables!
Creador de contenido principalmente acerca de tecnología.