# cultiva_agents/agents.py # Sistema multi-agente para pipeline de contenido de marketing # CULTIVA IA β Agencia de IA marca blanca from semantic_kernel import Kernel from semantic_kernel.agents import ChatCompletionAgent from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion from semantic_kernel.functions import kernel_function import os # ββ Kernel compartido ββββββββββββββββββββββββββββββββββββββββββββ def create_kernel(model: str = "gpt-4o") -> Kernel: kernel = Kernel() kernel.add_service( AzureChatCompletion( deployment_name=model, endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], api_key=os.environ["AZURE_OPENAI_KEY"], ) ) return kernel # ββ Herramientas reutilizables βββββββββββββββββββββββββββββββββββ class MarketingTools: @kernel_function(description="Recupera datos de tendencias de busqueda para un sector") def get_trends(self, sector: str) -> str: # Integrar con SerpAPI / Google Trends en produccion return f"[Tendencias actuales para {sector}: IA generativa +340%, automatizacion +89%]" @kernel_function(description="Analiza competidores principales de un cliente") def analyze_competitors(self, company: str, sector: str) -> str: # Integrar con Semrush / Ahrefs API en produccion return f"[Competidores de {company} en {sector}: dominio_autoritad, backlinks, keywords clave]" # ββ Definicion de los 4 agentes ββββββββββββββββββββββββββββββββββ def build_agents() -> dict: kernel_full = create_kernel("gpt-4o") kernel_mini = create_kernel("gpt-4o-mini") # Anadir herramientas al kernel del investigador kernel_full.add_plugin(MarketingTools(), plugin_name="marketing_tools") investigador = ChatCompletionAgent( kernel=kernel_full, name="Investigador", instructions="""Eres un analista de mercado senior especializado en marketing digital B2B. Dado un cliente y sector, usa las herramientas disponibles para: - Identificar tendencias del sector (ultimos 6 meses) - Analizar 3 competidores principales - Detectar oportunidades de contenido poco exploradas Devuelve un informe estructurado con bullets. Maximo 400 palabras.""", ) estratega = ChatCompletionAgent( kernel=kernel_full, name="Estratega", instructions="""Eres un estratega de contenido con enfoque en conversion B2B. Con el informe de investigacion, define: - 3 angulos narrativos diferenciadores - Mensaje clave para cada pieza de contenido - Tono y voz recomendados para la marca - Llamadas a la accion prioritarias SΓ© especifico y accionable.""", ) redactor = ChatCompletionAgent( kernel=kernel_full, name="Redactor", instructions="""Eres un redactor creativo especializado en contenido de marketing para tecnologia. Con la estrategia definida, produce: - 1 post de LinkedIn (150-200 palabras, con hook potente) - 1 email de nurturing (asunto + cuerpo, 120 palabras) - 3 titulares alternativos para blog Usa el tono y angulos definidos por el Estratega. No uses emojis en exceso.""", ) editor = ChatCompletionAgent( kernel=kernel_mini, # gpt-4o-mini basta para revision name="Editor", instructions="""Eres un editor senior. Revisa el contenido del Redactor y verifica: 1. Coherencia con la estrategia definida 2. Claridad y fluidez de lectura 3. Ausencia de clichΓ©s o lenguaje corporativo vacio 4. Llamada a la accion clara y convincente Si todo esta correcto, responde EXACTAMENTE: "APROBADO" Si necesita cambios, responde: "REVISION: [lista de mejoras concretas]" Maximo 2 rondas de revision antes de aprobar.""", ) return { "investigador": investigador, "estratega": estratega, "redactor": redactor, "editor": editor, }
# orchestration.py from semantic_kernel.agents import AgentGroupChat from semantic_kernel.agents.strategies import ( SequentialSelectionStrategy, KernelFunctionTerminationStrategy, ) from semantic_kernel.functions import KernelFunction async def run_sequential_pipeline( agents: dict, client_brief: str, kernel: Kernel, ) -> str: # Funcion de terminacion: el Editor dice "APROBADO" termination_fn = KernelFunction.from_prompt( """Revisa el ultimo mensaje. Si contiene exactamente "APROBADO", responde: si De lo contrario, responde: no Ultimo mensaje: {{$last_message}}""", kernel=kernel, ) chat = AgentGroupChat( agents=[ agents["investigador"], agents["estratega"], agents["redactor"], agents["editor"], ], selection_strategy=SequentialSelectionStrategy( agents=[ agents["investigador"], agents["estratega"], agents["redactor"], agents["editor"], ] ), termination_strategy=KernelFunctionTerminationStrategy( agents=[agents["editor"]], function=termination_fn, result_parser=lambda r: r.value[0].content.strip() == "si", max_iterations=8, ), ) await chat.add_chat_message(message=client_brief) outputs = [] async for response in chat.invoke(): outputs.append( f"\n[{response.name}]\n{response.content}" ) return "\n".join(outputs)
# Investigacion en paralelo: sector + competidores + tendencias import asyncio from semantic_kernel.agents import ChatCompletionAgent async def parallel_research( kernel: Kernel, client: str, sector: str, ) -> str: # 3 agentes especializados se lanzan simultaneamente sector_agent = ChatCompletionAgent( kernel=kernel, name="AnalistaSector", instructions="Analiza el estado actual del sector. 200 palabras max.", ) competitor_agent = ChatCompletionAgent( kernel=kernel, name="AnalistaCompetencia", instructions="Compara estrategia de contenido de 3 competidores. 200 palabras max.", ) trend_agent = ChatCompletionAgent( kernel=kernel, name="AnalistaTendencias", instructions="Identifica 5 tendencias emergentes del sector. 200 palabras max.", ) prompt = f"Cliente: {client} | Sector: {sector}" # Fan-out: los 3 corren en paralelo sector_res, comp_res, trend_res = await asyncio.gather( sector_agent.invoke(prompt), competitor_agent.invoke(prompt), trend_agent.invoke(prompt), ) # Fan-in: sintetizador agrega los 3 resultados synthesizer = ChatCompletionAgent( kernel=kernel, name="Sintetizador", instructions="Sintetiza los tres analisis en un informe unificado. Resalta las oportunidades.", ) synthesis = await synthesizer.invoke( f"SECTOR:\n{sector_res.content}\n\n" f"COMPETIDORES:\n{comp_res.content}\n\n" f"TENDENCIAS:\n{trend_res.content}" ) return synthesis.content
# api.py β endpoint listo para conectar con n8n, Make o webhook de Slack from fastapi import FastAPI, HTTPException from pydantic import BaseModel from contextlib import asynccontextmanager from .agents import build_agents, create_kernel from .orchestration import run_sequential_pipeline, parallel_research # ββ Modelos de entrada / salida ββββββββββββββββββββββββββββββββββ class ContentRequest(BaseModel): cliente: str # ej. "Legalia Tech β plataforma LegalTech B2B" sector: str # ej. "legaltech" tipo_contenido: str # ej. "post LinkedIn + email nurturing" objetivo: str # ej. "generar leads de despachos medianos" tono: str = "profesional-cercano" class ContentResponse(BaseModel): status: str # "ok" | "error" pipeline: str # transcripcion completa de todos los agentes resumen: str # extraccion del contenido final aprobado # ββ App lifecycle ββββββββββββββββββββββββββββββββββββββββββββββββ _agents = {} _kernel = None @asynccontextmanager async def lifespan(app: FastAPI): global _agents, _kernel _agents = build_agents() # Crea agentes una vez al arrancar _kernel = create_kernel("gpt-4o") # Kernel compartido para orquestacion yield # Cleanup si fuera necesario app = FastAPI( title="CULTIVA IA β Content Pipeline API", description="Sistema multi-agente para produccion automatica de contenido de marketing", version="1.0.0", lifespan=lifespan, ) # ββ Endpoint principal βββββββββββββββββββββββββββββββββββββββββββ @app.post("/pipeline/content", response_model=ContentResponse) async def content_pipeline(req: ContentRequest): """ Ejecuta el pipeline completo: 1. Investigacion paralela (sector + competidores + tendencias) 2. Pipeline secuencial (estrategia -> redaccion -> edicion) Retorna el contenido final aprobado por el Editor. """ try: # Paso 1: investigacion paralela (fan-out) research = await parallel_research( _kernel, req.cliente, req.sector ) # Paso 2: pipeline secuencial con hallazgos de investigacion brief = ( f"CLIENTE: {req.cliente}\n" f"SECTOR: {req.sector}\n" f"OBJETIVO: {req.objetivo}\n" f"TIPO CONTENIDO: {req.tipo_contenido}\n" f"TONO: {req.tono}\n\n" f"INVESTIGACION PREVIA:\n{research}" ) pipeline_output = await run_sequential_pipeline( _agents, brief, _kernel ) # Extraer bloque final aprobado (ultimo mensaje del Redactor antes de APROBADO) lines = pipeline_output.split("\n") final_content = "\n".join( l for l in lines if not l.startswith("[Editor]") and "APROBADO" not in l ).strip() return ContentResponse( status="ok", pipeline=pipeline_output, resumen=final_content, ) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) # Iniciar: uvicorn cultiva_agents.api:app --reload --port 8000
{ "cliente": "Legalia Tech", "sector": "legaltech B2B EspaΓ±a", "tipo_contenido": "post LinkedIn + email", "objetivo": "leads despachos medianos", "tono": "profesional-cercano" }
// [Investigador] β sector + competidores El mercado legaltech en EspaΓ±a crece al 23% anual. Solo el 18% de los despachos medianos ha adoptado IA para gestion documental. Oportunidad clave: ROI demostrable en due diligence (-40% tiempo). // [Estratega] β angulos y mensajes Angulo 1: "El despacho que no adopta IA pierde eficiencia frente a los grandes" Angulo 2: Caso de uso concreto: due diligence en 2h CTA principal: Demo gratuita de 30 min // [Redactor] β contenido final LinkedIn: "Los despachos que automatizan due diligence con IA cierran operaciones un 40% mas rapido..." Email subject: "ΒΏCuanto tiempo pierde tu equipo en revision de contratos?" // [Editor] β APROBADO