Introduciendo bibliotecas de IA en tu base de código de manera saludable

16/12/20247 min read
EnglishEspañol

La inteligencia artificial ha llegado para quedarse. Los Modelos de Lenguaje de Gran Escala (LLM) como ChatGPT, Claude o Llama se están convirtiendo rápidamente en parte del conjunto de herramientas de muchos desarrolladores y empresas. El problema: demasiado a menudo, estas potentes herramientas se lanzan a productos existentes sin mucha reflexión sobre arquitectura o mantenibilidad.

¿Qué sucede cuando tomas la primera biblioteca de chatbot que encuentras y la desatas en tu base de código? Tu proyecto puede volverse rápidamente inmanejable, difícil de evolucionar y frágil cuando llegan los cambios. Si has utilizado productos que integran la IA generativa de manera descuidada, probablemente hayas experimentado esto de primera mano.

En este artículo, recorreremos un ejemplo simple para mostrarte cómo introducir la IA generativa de manera responsable y mantener una arquitectura saludable. Específicamente, usaremos un generador de frases motivacionales para desarrolladores de software (porque, seamos sinceros, todos necesitamos algo de motivación después de sumergirnos en código). En el camino, destacaremos los problemas que surgen cuando se acoplan estrechamente las bibliotecas de IA a la lógica de negocio y demostraremos cómo solucionarlos usando Inversión de Control (IoC).

Comencemos.

El Problema: IA Acoplada a la Lógica de Negocio

Imagina un simple programa en Python para generar frases motivacionales usando un modelo de IA generativa. El programa hace lo siguiente:

  1. Instancia un modelo de IA usando la biblioteca langchain (específicamente Llama, en este caso).
  2. Envía un prompt al modelo para generar una frase motivacional.
  3. Devuelve la frase generada.

Aquí está la implementación rápida y sucia:

from langchain.llms import Ollama

def main():
    llm = Ollama(model="llama3.2")
    prompt = "Generate a motivational phrase for software developers."
    result = llm.invoke(prompt)
    print(result)

if __name__ == "__main__":
    main()

En la superficie, este código funciona bien. Ejecútalo y obtendrás algo como esto:

"La creación de soluciones innovadoras y sostenibles para mejorar la vida de las personas es el verdadero propósito del desarrollo de software."

Suena motivacional, ¿verdad? Pero hay problemas serios ocultos bajo la superficie:

  1. Infraestructura y Lógica de Negocio Mezcladas: La intención del programa (generar una frase motivacional) está contaminada por detalles de implementación del modelo Ollama y la biblioteca langchain.
    • Si decides cambiar de Llama a ChatGPT o Claude, tendrás que modificar tu lógica de negocio.
  2. Difícil de Probar: Para probar la función, tendrías que lidiar con la biblioteca de IA real, requiriendo monkey-patching o mocking a bajo nivel.
  3. Pobre Separación de Responsabilidades: El código tiene múltiples responsabilidades — gestionar el LLM y definir la lógica de negocio para generar frases motivacionales.

Este enfoque puede parecer inofensivo en scripts pequeños, pero en proyectos complejos, este acoplamiento estrecho lleva a:

  • Código difícil de mantener o extender.
  • Cambios de infraestructura que rompen la funcionalidad central.
  • Pruebas frágiles y engorrosas.

La solución: Desacoplar la lógica de negocio de la infraestructura usando Inversión de Control.

La Solución: Inversión de Control (IoC)

La Inversión de Control es un principio de diseño donde las dependencias no se crean o gestionan directamente dentro de la lógica de negocio. En su lugar, se inyectan desde el exterior. Esto hace que el código sea más modular, comprobable y más fácil de cambiar.

Así es como refactorizaremos nuestro generador de frases motivacionales:

  1. Crear un Servicio Abstracto: Definir una interfaz (o clase abstracta) para generar texto.
  2. Inyectar la Implementación: Pasar la implementación de LLM a la lógica de negocio como una dependencia.
  3. Separar Responsabilidades: Permitir que el generador se preocupe solo por definir el prompt, mientras que el servicio de IA maneja la generación de texto.

Paso 1: Definir el Servicio Abstracto

Comenzaremos creando una clase abstracta para el servicio de generación de texto:

from abc import ABC, abstractmethod

class LLMService(ABC):
    @abstractmethod
    def generate_text(self, prompt: str) -> str:
        pass

Esta clase abstracta define un contrato: cualquier implementación de LLMService debe proporcionar un método generate_text.

Paso 2: Desacoplar el Generador

Luego, refactorizamos el generador de frases motivacionales para depender del servicio abstracto en lugar de un LLM específico:

class MotivationalPhraseGenerator:
    def __init__(self, llm_service: LLMService):
        self._llm_service = llm_service

    def generate_phrase(self) -> str:
        prompt = "Generate a motivational phrase for software developers."
        return self._llm_service.generate_text(prompt)

Ahora, el generador es limpio y está enfocado. Solo conoce la intención (generar una frase motivacional), no los detalles de implementación del modelo de IA.

Paso 3: Implementar el Servicio

Implementamos el servicio abstracto para el modelo Ollama:

from langchain.llms import Ollama

class OllamaService(LLMService):
    def __init__(self, model: str):
        self._model = Ollama(model=model)

    def generate_text(self, prompt: str) -> str:
        return self._model.invoke(prompt)

Paso 4: Juntar Todo

Finalmente, instanciamos el generador con el servicio de IA específico:

if __name__ == "__main__":
    service = OllamaService(model="llama3.2")
    generator = MotivationalPhraseGenerator(service)
    print(generator.generate_phrase())

Ejecuta esto, y aún obtendrás hermosas frases motivacionales:

"Desarrollar software no es solo crear código; es construir soluciones que mejoran vidas y cambian el mundo."

Beneficios de Esta Refactorización

Al aplicar la Inversión de Control, hemos:

  1. Separado Responsabilidades: El generador se enfoca únicamente en definir el prompt. El servicio de IA maneja la generación de texto.

  2. Mejorado la Mantenibilidad: Cambiar a otro LLM (por ejemplo, ChatGPT) solo requiere implementar un nuevo servicio. El generador permanece intacto.

  3. Habilitado la Capacidad de Prueba: Podemos simular fácilmente el servicio para pruebas unitarias:

    class MockLLMService(LLMService):
        def generate_text(self, prompt: str) -> str:
            return "Esta es una frase motivacional simulada."
    
    def test_generator():
        service = MockLLMService()
        generator = MotivationalPhraseGenerator(service)
        assert generator.generate_phrase() == "Esta es una frase motivacional simulada."
    
  4. Mejorada la Extensibilidad: Añadir nuevas características o LLMs no requiere modificar código existente.

Reflexiones Finales

Introducir la IA generativa en tus proyectos puede ser emocionante, pero debe hacerse con reflexión. El acoplamiento estrecho de infraestructura (como LLMs) con la lógica de negocio conduce a código desordenado, difícil de mantener y escalar.

Aplicando Inversión de Control y adhiriéndote a principios de arquitectura limpia, puedes:

  • Mantener tu lógica de negocio pura y enfocada.
  • Probar tu código fácilmente.
  • Adaptarte a tecnologías cambiantes sin dolores de cabeza.

Ya sea que estés construyendo generadores motivacionales o sistemas complejos impulsados por IA, este enfoque te ayudará a mantener tu base de código saludable y preparada para el futuro.

Feliz programación, y recuerda:

"Cada línea de código cuenta."

Mantente al día

Suscríbete a la newsletter para enterarte de las últimas noticias!

Comparte este artículo