Módulo 3: LM Studio - Introducción
Mini-Proyecto: Chatbot 100% Local
Descripción del proyecto
Proyecto final del Módulo 3: Chatbot completamente local (costo $0, privacidad 100%) usando LM Studio.
Tomarás el chatbot del Módulo 2 y lo adaptarás para funcionar 100% offline con Mistral 7B local.
Tiempo: 30-45 minutos
Dificultad: Media
🎯 Objetivo
Crear chatbot CLI local con:
- ✅ Conversaciones con contexto
- ✅ Cost tracking (confirmar $0)
- ✅ Performance metrics (latency)
- ✅ Persistence (JSON)
- ✅ 100% offline (sin API calls cloud)
💻 Código Completo
#!/usr/bin/env python3
"""
Chatbot 100% Local con LM Studio
Módulo 3 - Proyecto Final
"""
import json
import time
from datetime import datetime
from pathlib import Path
from openai import OpenAI
# ============================================================================
# CONFIGURACIÓN
# ============================================================================
# Cliente LM Studio (local)
client = OpenAI(
base_url="http://localhost:1234/v1",
api_key="not-needed"
)
MODEL = "mistral-7b-instruct" # Ajusta según tu modelo
Path("conversations_local").mkdir(exist_ok=True)
# ============================================================================
# CLASE CHATBOT LOCAL
# ============================================================================
class LocalChatBot:
"""Chatbot 100% local con LM Studio."""
def __init__(self):
self.messages = [
{"role": "system", "content": "Eres un asistente útil y amigable."}
]
self.total_time = 0.0
self.query_count = 0
self.conversation_id = datetime.now().strftime("%Y%m%d_%H%M%S")
def chat(self, user_message: str) -> str:
"""Envía mensaje y retorna respuesta."""
self.messages.append({"role": "user", "content": user_message})
# Medir latency
start = time.time()
try:
response = client.chat.completions.create(
model=MODEL,
messages=self.messages,
temperature=0.7,
max_tokens=150
)
latency = time.time() - start
self.total_time += latency
self.query_count += 1
assistant_message = response.choices[0].message.content
self.messages.append({"role": "assistant", "content": assistant_message})
print(f"[Latency: {latency:.2f}s]")
return assistant_message
except Exception as e:
print(f"❌ Error: {e}")
return None
def show_stats(self):
"""Muestra estadísticas."""
if self.query_count == 0:
print("\n📊 Sin queries aún")
return
avg_latency = self.total_time / self.query_count
print("\n" + "="*50)
print("📊 ESTADÍSTICAS")
print("="*50)
print(f"Queries: {self.query_count}")
print(f"Tiempo total: {self.total_time:.2f}s")
print(f"Latency avg: {avg_latency:.2f}s")
print(f"💰 Costo: $0.00 (100% local!)")
print("="*50 + "\n")
def show_history(self):
"""Muestra historial."""
print("\n" + "="*50)
print("HISTORIAL")
print("="*50)
for i, msg in enumerate(self.messages[1:], 1):
role = "TÚ" if msg["role"] == "user" else "BOT"
print(f"\n[{i}] {role}: {msg['content']}")
print("\n" + "="*50 + "\n")
def save_conversation(self):
"""Guarda conversación."""
filename = f"conversations_local/conversation_{self.conversation_id}.json"
data = {
"conversation_id": self.conversation_id,
"timestamp": datetime.now().isoformat(),
"model": MODEL,
"messages": self.messages[1:],
"query_count": self.query_count,
"total_time": self.total_time,
"avg_latency": self.total_time / self.query_count if self.query_count > 0 else 0,
"cost": 0.0 # $0 local!
}
with open(filename, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f"💾 Conversación guardada: {filename}")
# ============================================================================
# MAIN
# ============================================================================
def main():
"""CLI principal."""
print("\n" + "="*50)
print("🤖 CHATBOT 100% LOCAL (LM Studio)")
print("="*50)
print(f"\nModelo: {MODEL}")
print("Costo: $0.00 (offline)")
print("\nComandos:")
print(" - 'salir' → Terminar")
print(" - 'historial' → Ver historial")
print(" - 'stats' → Ver estadísticas")
print("\n" + "="*50 + "\n")
# Verificar servidor LM Studio
print("Verificando servidor LM Studio...")
try:
models = client.models.list()
print(f"✅ Servidor activo ({len(models.data)} modelos disponibles)\n")
except Exception as e:
print(f"❌ Error: {e}")
print("\n⚠️ Asegúrate que LM Studio está corriendo con servidor activo")
print(" Settings → Local Server → Start Server\n")
return
bot = LocalChatBot()
# Loop principal
while True:
try:
user_input = input("Tú: ").strip()
if user_input.lower() in ["salir", "exit", "quit"]:
print("\n👋 ¡Hasta pronto!\n")
bot.show_stats()
bot.save_conversation()
break
if user_input.lower() == "historial":
bot.show_history()
continue
if user_input.lower() == "stats":
bot.show_stats()
continue
if not user_input:
print("⚠️ Escribe un mensaje.\n")
continue
response = bot.chat(user_input)
if response:
print(f"\nBot: {response}\n")
except KeyboardInterrupt:
print("\n\n👋 Interrumpido por usuario\n")
bot.show_stats()
bot.save_conversation()
break
except Exception as e:
print(f"\n❌ Error inesperado: {e}\n")
break
if __name__ == "__main__":
main()
🚀 Uso
1. Iniciar servidor LM Studio:
- LM Studio → Settings → Start Server
- Verifica 🟢 "Server running on port 1234"
2. Cargar modelo:
- Home → My Models → Load (Mistral 7B)
3. Ejecutar chatbot:
python chatbot_local.py
📊 Ejemplo de Conversación
==================================================
🤖 CHATBOT 100% LOCAL (LM Studio)
==================================================
Modelo: mistral-7b-instruct
Costo: $0.00 (offline)
Comandos:
- 'salir' → Terminar
- 'historial' → Ver historial
- 'stats' → Ver estadísticas
==================================================
Verificando servidor LM Studio...
✅ Servidor activo (1 modelos disponibles)
Tú: Hola, ¿qué modelo eres?
[Latency: 4.2s]
Bot: Soy Mistral 7B, un modelo de lenguaje local ejecutándose en tu máquina.
Tú: ¿Cuál es la capital de Francia?
[Latency: 3.8s]
Bot: La capital de Francia es París.
Tú: stats
==================================================
📊 ESTADÍSTICAS
==================================================
Queries: 2
Tiempo total: 8.00s
Latency avg: 4.00s
💰 Costo: $0.00 (100% local!)
==================================================
Tú: salir
👋 ¡Hasta pronto!
==================================================
📊 ESTADÍSTICAS
==================================================
Queries: 2
Tiempo total: 8.00s
Latency avg: 4.00s
💰 Costo: $0.00 (100% local!)
==================================================
💾 Conversación guardada: conversations_local/conversation_20240215_143022.json
✅ Rúbrica de Auto-Evaluación
Funcionalidad (40 pts):
- (10) Chatbot responde coherentemente
- (10) Mantiene contexto
- (10) Comandos funcionan (historial, stats, salir)
- (10) Conversaciones guardadas
Performance (30 pts):
- (10) Latency tracking funciona
- (10) Stats precisas
- (10) Costo confirmado $0
Local (30 pts):
- (15) Funciona sin OpenAI API
- (15) Funciona offline (desconecta WiFi y prueba)
Total: ___/100
🎯 Comparación con Módulo 2
| Métrica | Módulo 2 (OpenAI) | Módulo 3 (LM Studio) |
|---|---|---|
| Latency | 1.5s | 4.0s (2.6x más lento) |
| Costo (100 queries) | $0.10 | $0.00 |
| Privacidad | Cloud | 100% local ✅ |
| Offline | ❌ | ✅ |
| Setup | 5 min | 30 min |
🔗 Extensiones Opcionales
1. Comparador side-by-side:
# Envía query a ambos (OpenAI + LM Studio)
# Compara respuestas y latency
2. Auto-switch por latency:
# Si LM Studio >10s → fallback a OpenAI
3. Hybrid mode:
# Queries simples → LM Studio ($0)
# Queries complejas → GPT-4 ($$$)
✅ Resumen del Módulo 3
Lo que dominaste:
- ✅ LM Studio setup completo
- ✅ Model management (descarga, quantization)
- ✅ API local compatible OpenAI
- ✅ Migración trivial de código
- ✅ Chatbot 100% local funcionando
Trade-offs entendidos:
- Costo $0 vs Latency 3-5x más lenta
- Privacidad máxima vs Setup más complejo
- Offline vs Calidad 10% menor
➡️ Próximo paso
Siguiente módulo: Módulo 4 - Ollama (Local CLI)
Aprenderás Ollama, alternativa a LM Studio pero:
- CLI en vez de GUI (más pro)
- Docker support (producción)
- Multi-node clustering (escalabilidad)
Tiempo: 2-3 horas
¡Felicitaciones! Completaste el Módulo 3. 🎉
Tiempo total módulo: 2-3 horas
Siguiente: Módulo 4 - Ollama