Skip to content

Sr-Claude/pluma

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🐓 pluma

"Flask para agentes de IA. El micro-framework que no te dice cómo pensar."

pluma es un micro-framework Python para construir agentes de IA con personalidad, memoria y herramientas. Sin boilerplate. Sin magia negra. Solo código que vuela.

pip install pluma

¿Por qué pluma?

pluma LangChain LlamaIndex
Curva de aprendizaje 15 minutos días días
Líneas para un agente básico ~10 ~50 ~40
Dependencias 4 100+ 80+
Filosofía Flask Django Hibernate
Multi-proveedor
ReAct loop
Streaming

Instalación

# Solo el framework
pip install pluma

# Con soporte para Ollama (local)
pip install "pluma[ollama]"

# Con soporte para OpenAI
pip install "pluma[openai]"

# Con soporte para Anthropic
pip install "pluma[anthropic]"

# Todo
pip install "pluma[all]"

Requisitos: Python 3.10+


Quickstart — 5 minutos

Chat simple

import asyncio
from pluma import Plumifero, Manuscrito
from pluma import ProveedorOllama

async def main():
    agente = Plumifero(
        proveedor=ProveedorOllama(modelo="llama3.2"),
        manuscrito=Manuscrito(
            nombre="Cafecito",
            proposito="Ayudar a debuggear código antes del primer café.",
            personalidad="Paciente, preciso, con olor a café recién hecho.",
        ),
    )

    respuesta = await agente.dialogar("¿Qué es un decorador en Python?")
    print(respuesta)

asyncio.run(main())

Agente con herramientas (ReAct)

import asyncio
from pluma import Plumifero, Manuscrito, ProveedorOllama
from pluma import pluma_buscar_web, pluma_datetime

async def main():
    agente = Plumifero(
        proveedor=ProveedorOllama(modelo="llama3.2"),
        plumas=[pluma_buscar_web, pluma_datetime],
    )

    resultado = await agente.volar(
        "¿Qué día es hoy y qué noticias hay sobre Python?"
    )
    print(resultado.mensaje_final)
    print(f"Pasos: {len(resultado.pasos)} | Tokens: {resultado.tokens_usados}")

asyncio.run(main())

Agentes predefinidos (zero-config)

from pluma import crear_plumita, crear_don_pio, crear_madrugador, crear_poeta
from pluma import ProveedorAnthropic

proveedor = ProveedorAnthropic(modelo="claude-haiku-4-5-20251001")

# Chat conversacional
plumita = crear_plumita(proveedor)

# Revisor de código implacable
don_pio = crear_don_pio(proveedor)

# Automatización con shell + Python + archivos
madrugador = crear_madrugador(proveedor)

# Poeta que escribe sobre código
poeta = crear_poeta(proveedor)

Conceptos clave

🪶 Pluma — la herramienta

Una Pluma es una función que el agente puede invocar. Define su nombre, descripción y firma para que el LLM sepa cuándo y cómo usarla.

from pluma import Pluma

# Desde una función existente
def obtener_temperatura(ciudad: str, unidad: str = "celsius") -> str:
    """Obtiene la temperatura actual de una ciudad."""
    return f"La temperatura en {ciudad} es de 22°{unidad[0].upper()}"

pluma_clima = Pluma.crear(
    nombre="obtener_temperatura",
    descripcion="Obtiene la temperatura actual de una ciudad.",
    funcion=obtener_temperatura,
)

# Con decorador
@Pluma.desde_funcion
def fibonacci(n: int) -> str:
    """Calcula los primeros N números de la secuencia de Fibonacci."""
    a, b, seq = 0, 1, []
    for _ in range(n):
        seq.append(a); a, b = b, a + b
    return str(seq)

📜 Manuscrito — el alma

El Manuscrito define la identidad, propósito y personalidad del agente. Se convierte en el prompt de sistema enviado al LLM.

from pluma import Manuscrito

manuscrito = Manuscrito(
    nombre="DataBird",
    proposito="Analizar datasets y generar insights accionables.",
    personalidad="Riguroso con los números, pero accesible en las explicaciones.",
    tono="técnico pero claro, como un profesor que sabe de lo que habla",
    idioma="español",
    conocimiento_base=["pandas", "numpy", "estadística descriptiva"],
    restricciones=["No inventes datos. Si no puedes calcular algo, dilo."],
)

# API fluida (inmutable — devuelve nuevo Manuscrito)
manuscrito_v2 = (
    manuscrito
    .con_conocimiento("matplotlib", "seaborn")
    .con_restriccion("No uses datos de usuarios sin anonimizar")
    .con_ejemplo(
        usuario="¿Qué es la media?",
        plumifero="La media es la suma de todos los valores dividida entre el número de elementos."
    )
)

# Serialización
manuscrito.guardar("mi_agente.json")
manuscrito_cargado = Manuscrito.cargar("mi_agente.json")

🫙 Tintero — la memoria

El Tintero gestiona el historial de conversación. Cada Plumifero tiene su propio Tintero.

from pluma import Tintero

tintero = Tintero(max_mensajes=50)  # mantiene los últimos 50 mensajes

# Escribir mensajes directamente
tintero.escribir_sistema("Eres un asistente útil.")
tintero.escribir_usuario("¿Hola?")
tintero.escribir_plumifero("¡Hola! ¿En qué puedo ayudarte?")

# Inspeccionar
mensajes = tintero.leer_todo()  # list[dict[str, str]]
sistema = tintero.leer_por_rol(RolMensaje.SISTEMA)

# Limpiar
tintero.vaciar()

🦜 Plumifero — el agente

El Plumifero orquesta todos los componentes: Proveedor + Manuscrito + Tintero + Plumas + Vuelo.

from pluma import Plumifero, ProveedorOllama

agente = Plumifero(
    proveedor=ProveedorOllama(modelo="llama3.2"),
    manuscrito=manuscrito,
    plumas=[pluma_clima, pluma_datetime],
    max_pasos=10,       # máximo de pasos ReAct
    nombre="Agente",    # sobrescribe el nombre del manuscrito
)

# Chat conversacional (una llamada al LLM)
respuesta = await agente.dialogar("¿Qué tiempo hace?")

# Con herramientas (ciclo ReAct completo)
resultado = await agente.volar("Dime la temperatura de Madrid ahora")

# Streaming
async for chunk in agente.dictar("Cuéntame algo interesante"):
    print(chunk, end="", flush=True)

# Gestión de herramientas
agente.emplumar(pluma_nueva)    # añadir (encadenable)
agente.desplumar("nombre")      # quitar (encadenable)

# Memoria
agente.historia()               # list[dict] con todos los mensajes
agente.reiniciar()              # borra la memoria (encadenable)

# Aliases poéticos
await agente.pensar(msg)        # = dialogar()
await agente.emprender_el_vuelo(msg)  # = volar()
agente.recordar()               # = historia()

Plumas predefinidas

Nombre LLM Tipo Descripción
obtener_datetime sync Fecha y hora actual con formato personalizable
leer_archivo sync Lee un archivo de texto en UTF-8
escribir_archivo sync Escribe/sobreescribe un archivo (crea directorios intermedios)
listar_directorio sync Lista el contenido de un directorio con emojis
ejecutar_shell async Ejecuta comandos de shell y captura la salida
ejecutar_python async Ejecuta código Python en un subproceso aislado
buscar_web async Busca en DuckDuckGo (sin API key)
from pluma import (
    pluma_datetime, pluma_leer_archivo, pluma_escribir_archivo,
    pluma_listar_directorio, pluma_shell, pluma_python, pluma_buscar_web,
)

Agentes predefinidos

Plumita — asistente conversacional

from pluma import crear_plumita, ProveedorOpenAI

plumita = crear_plumita(ProveedorOpenAI(modelo="gpt-4o-mini"))
respuesta = await plumita.dialogar("¿Cómo funciona async/await?")

Herramientas: buscar_web, datetime, leer_archivo

Don Pío — revisor de código

from pluma import crear_don_pio, ProveedorAnthropic

don_pio = crear_don_pio(ProveedorAnthropic())
resultado = await don_pio.volar(f"Revisa este código:\n\n{codigo}")

Herramientas: leer_archivo, listar_directorio

El Madrugador — automatización

from pluma import crear_madrugador, ProveedorOllama

madrugador = crear_madrugador(ProveedorOllama())
resultado = await madrugador.volar(
    "Lista todos los .py, cuenta las líneas de cada uno y escribe un informe."
)

Herramientas: shell, python, leer_archivo, escribir_archivo, listar_directorio, datetime

La Pluma Lírica — poeta

from pluma import crear_poeta, ProveedorOpenAI

poeta = crear_poeta(ProveedorOpenAI())
resultado = await poeta.volar("Escribe un poema sobre un bug de producción a las 3am.")

Proveedores

Ollama (local, gratis)

from pluma import ProveedorOllama

# Requiere: pip install "pluma[ollama]" y Ollama corriendo en localhost
proveedor = ProveedorOllama(modelo="llama3.2")
proveedor = ProveedorOllama(modelo="llama3.2", base_url="http://mi-servidor:11434")

OpenAI

from pluma import ProveedorOpenAI

# Requiere: pip install "pluma[openai]" y OPENAI_API_KEY en el entorno
proveedor = ProveedorOpenAI(modelo="gpt-4o-mini")
proveedor = ProveedorOpenAI(modelo="gpt-4o", api_key="sk-...")

Anthropic

from pluma import ProveedorAnthropic

# Requiere: pip install "pluma[anthropic]" y ANTHROPIC_API_KEY en el entorno
proveedor = ProveedorAnthropic(modelo="claude-haiku-4-5-20251001")
proveedor = ProveedorAnthropic(modelo="claude-sonnet-4-6", api_key="sk-ant-...")

CLI

# Chat interactivo con Plumita
pluma conversar

# Chat con proveedor específico
pluma conversar --proveedor openai --modelo gpt-4o-mini

# Chat con herramientas de sistema (shell, Python, archivos)
pluma conversar --con-herramientas

# Don Pío revisa tu código
pluma revisar src/mi_modulo.py
pluma revisar mi_codigo.py --proveedor anthropic

# El Madrugador ejecuta una tarea con herramientas (ReAct)
pluma volar "lista los archivos .py del directorio y cuéntalos"
pluma volar "busca info sobre Python 3.13" --verbose

# Wizard para crear un Manuscrito
pluma crear
pluma crear --guardar mi_agente.json

# Ver todas las plumas predefinidas
pluma lista-plumas

Inspeccionar ResultadoVuelo

resultado = await agente.volar("tarea compleja")

resultado.exitoso          # bool
resultado.mensaje_final    # str — la respuesta del agente
resultado.estado           # EstadoVuelo.COMPLETADO | .LIMITE_PASOS | .ERROR
resultado.tokens_usados    # int — tokens consumidos en total
resultado.duracion_segundos  # float — tiempo del vuelo
resultado.error            # str | None — mensaje de error si falló

# Inspeccionar cada paso del ciclo ReAct
for paso in resultado.pasos:
    paso.pensamiento   # str | None — razonamiento interno del agente
    paso.accion        # str | None — nombre de la herramienta usada
    paso.argumentos    # dict — argumentos pasados a la herramienta
    paso.observacion   # str | None — resultado de la herramienta
    paso.respuesta_final  # str | None — respuesta si es el último paso

Estructura del proyecto

src/pluma/
├── __init__.py          ← API pública
├── tipos.py             ← Tipos base (Mensaje, Paso, ResultadoVuelo...)
├── pluma.py             ← Pluma (herramienta)
├── tintero.py           ← Tintero (memoria)
├── manuscrito.py        ← Manuscrito + manuscritos predefinidos
├── vuelo.py             ← Motor ReAct
├── plumifero.py         ← Plumifero (agente)
├── cli.py               ← CLI con Typer
└── proveedores/
    ├── base.py          ← Clase abstracta Proveedor
    ├── ollama.py
    ├── openai.py
    └── anthropic.py
    predefinidos/
    ├── plumas.py        ← 7 plumas listas para usar
    └── plumiferos.py    ← 4 fábricas de agentes

Desarrollo

git clone https://github.com/casromur/pluma
cd pluma
pip install -e ".[dev,all]"

# Tests
pytest

# Lint
ruff check src/

# Tipos
mypy src/pluma/

Ejemplos

Los ejemplos en examples/ están listos para ejecutar:

# Chat básico con Plumita
python examples/01_hola_plumita.py

# Don Pío revisa código (crea un archivo temporal y lo analiza)
python examples/02_don_pio_revisor.py

# El Madrugador en acción: ReAct, streaming y herramientas personalizadas
python examples/03_agente_madrugador.py

Licencia

MIT © 2024 Sr Claude


"Todo gran escritor necesita una gran pluma. El Plumífero es ambos." — Don Pío, amanecer de 2024

About

🐓 pluma "Flask para agentes de IA. El micro-framework que no te dice cómo pensar." pluma es un micro-framework Python para construir agentes de IA con personalidad, memoria y herramientas. Sin boilerplate. Sin magia negra. Solo código que vuela.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages