In this article
Cómo crear un resumen de noticias de seguridad con un agente de IA de CrewAI
Revisar numerosas fuentes de noticias de seguridad y bases de datos de vulnerabilidades requiere mucho trabajo, pero con el auge de los flujos de trabajo de IA agéntica, podemos delegarlo en un LLM. En este artículo, te mostramos cómo usar el framework de código abierto CrewAI para crear un agente de IA que seleccione noticias de seguridad.
Agentes de IA para seleccionar noticias de seguridad
En la aplicación que crearemos, nos enfocaremos específicamente en seleccionar nuevas vulnerabilidades de seguridad de Snyk Vulnerability Database para crear un feed de noticias de seguridad.
Nuestro agente de IA será una herramienta de línea de comandos que abrirá la página web de Snyk Vulnerability Database para un ecosistema determinado (usaremos el ecosistema de JavaScript de npm) y seleccionará los 3 informes de CVE más relevantes que considere importantes.
Primeros pasos con CrewAI
En la primera fase, crearemos un directorio para el nuevo proyecto en la ubicación que prefieras de tu entorno de desarrollo local e inicializaremos allí el framework CrewAI.
Estos son los requisitos:
El administrador de paquetes uv está instalado y disponible localmente
Un entorno de ejecución de Python >= 3.x (se puede instalar con
uv)
En el directorio que elegiste, comencemos por instalar la biblioteca y las herramientas de crewai:
uv tool install crewaiLuego, agrégalo al entorno de tu shell de trabajo para poder ejecutar el comando crewai como un ejecutable global:
uv tool update-shellAhora podemos comenzar a crear la estructura de un nuevo proyecto de crewai:
crewai create crew <your_project_name>Luego, instala las dependencias del proyecto con este comando:
crewai installAhora, el directorio del proyecto debería tener esta estructura:

A grandes rasgos, CrewAI tiene un archivo crew.py que define los agentes y las tareas:
@agent
def researcher(self) -> Agent:
return Agent(
config=self.agents_config['researcher'], # type: ignore[index]
verbose=True
)
@agent
def reporting_analyst(self) -> Agent:
return Agent(
config=self.agents_config['reporting_analyst'], # type: ignore[index]
verbose=True
)
El mismo archivo también incluye las tareas que queremos llevar a cabo con esos agentes:
@task
def research_task(self) -> Task:
return Task(
config=self.tasks_config['research_task'], # type: ignore[index]
)
@task
def reporting_task(self) -> Task:
return Task(
config=self.tasks_config['reporting_task'], # type: ignore[index]
output_file='report.md'
)El archivo main.py incluye varias funciones exportadas, como run(), train() y otras, que invocan a los agentes y les proporcionan la información que necesitan para realizar su trabajo.
Así se ve el flujo de inicio de los agentes en el archivo principal de Python:
def run():
"""
Run the crew.
"""
inputs = {
'topic': 'AI LLMs',
'current_year': str(datetime.now().year)
}
try:
SecurityNewsSummary().crew().kickoff(inputs=inputs)
except Exception as e:
raise Exception(f"An error occurred while running the crew: {e}")Lo anterior describe la estructura de directorios del ejemplo predeterminado que CrewAI crea para el proyecto. Sin embargo, vamos a hacer cambios, definir nuestros propios agentes y tareas, y crear una herramienta personalizada para que la usen los agentes.
Cómo crear flujos de trabajo agénticos personalizados con CrewAI
Haremos cambios en tres partes principales del directorio del proyecto CrewAI:
Cambios en los agentes de
config/agents.yamlCambios en las tareas de
config/tasks.yamlCambios en el programa principal de CrewAI en crew.py
Además, crearemos una herramienta personalizada en el directorio tools/ que extrae el HTML de una página web con BeautifulSoup, una popular biblioteca de Python.
Agentes de IA
Una buena regla general para los agentes de IA es dividir sus tareas en pasos lo más pequeños posible. Al igual que en el enfoque de la ingeniería y el diseño de software, descomponer los problemas grandes en otros más pequeños resulta útil.
Siguiendo este consejo, definiremos dos agentes:
Un curador de CVE, cuya función es encontrar en la página web los enlaces a los CVE que considere más importantes.
Un investigador de CVE, cuya función es visitar los enlaces individuales a los CVE (páginas web) y extraer datos de ellos.
Abre config/agents.yaml y reemplaza la definición de los agentes que creó CrewAI por lo siguiente:
1cve_curator:
2 role: >
3 Senior Security Analyst
4 goal: >
5 Find the links to the top most interesting CVEs reported in {security_vulnerabilities_url}.
6 backstory: >
7 You're a seasoned web scraper with a knack for parsing HTML pages and extracting the most relevant information.
8
9cve_researcher:
10 role: >
11 Senior Security Researcher
12 goal: >
13 Summarize and format the CVE information found by the CVE curator.
14 backstory: >
15 You're a meticulous security researcher with a keen eye for detail. You're known for
16 your ability to turn complex data into clear and concise reports, making
17 it easy for others to understand and act on the information you provide.Tareas
A continuación, tendremos que definir las tareas correspondientes:
La tarea inicial consiste en extraer los enlaces a los CVE del directorio de la base de datos de vulnerabilidades (la página web principal con los resultados de búsqueda y el listado de vulnerabilidades).
La tarea de seguimiento del agente investigador de CVE consiste en extraer los datos de vulnerabilidad de cada CVE de su página de información.
Abre el archivo config/tasks.yaml y reemplaza el contenido que creó la biblioteca CrewAI por lo siguiente:
cve_curation_task:
description: >
Parse the HTML page to find the top most interesting CVEs reported in {security_vulnerabilities_url}.
You need to select 3 CVEs from the page and extract the link to their vulnerability page.
For example, the link to the vulnerability for the package @trpc/server is: https://security.snyk.io/vuln/SNYK-JS-TRPCSERVER-10060256
You should de-prioritize choosing CVEs for malicious packages. Instead, you should prioritize CVEs for popular packages and those that are likely
to have a high impact on the open-source ecosystem.
expected_output: >
A total of 3 CVEs, each formatted as a bullet point in the following markdown format
```
- https://security.snyk.io/vuln/SNYK-JS-TRPCSERVER-10060256
```
agent: cve_curator
cve_research_task:
description: >
For each of the CVE you should extract information by visiting the link to the vulnerability and extracting the information from the page.
For example, the link to the vulnerability for the package @trpc/server is: https://security.snyk.io/vuln/SNYK-JS-TRPCSERVER-10060256
Once you have the link, visit the page and extract the following information:
1) CVE ID (example: CVE-2025-12345)
2) Type of Vulnerability (example: RCE, SQL Injection, etc.)
3) CVE Publication Date (example: 2025-01-01)
4) Link to the CVE vulnerability page (example: https://security.snyk.io/vuln/SNYK-JS-KIBANA-10339388). The link exists as the href attribute of the anchor tag in the HTML page, set on the name of the vulnerability.
5) Package name that was found vulnerable (example: kibana)
expected_output: >
A total of 3 CVEs, each formatted as a bullet point in the following markdown format (strict markdown formatting for example links should not have space between the [] and () chars):
```
**@trpc/server** found vulnerable to CVE-2025-43855 [Uncaught Exception](https://security.snyk.io/vuln/SNYK-JS-TRPCSERVER-10060256), 24 Apr 2025
```
agent: cve_researcherVerás que las tareas están redactadas cuidadosamente para que nuestros agentes de IA las interpreten y cumplan. También incluyen un ejemplo del resultado esperado y las reglas que deben seguir.
Herramientas personalizadas
Para la primera tarea y nuestro primer agente, el curador de CVE, necesitamos crear una herramienta personalizada con código Python. Debemos hacerlo porque la herramienta integrada de CrewAI, ScrapeWebsiteTool, solo extrae texto de una página web y no puede analizar el código fuente HTML para extraer los elementos de anclaje (<a href>) que contienen los enlaces a los datos de cada CVE en la página.
Para empezar a crear una herramienta personalizada que puedan usar nuestros agentes, primero abre el archivo tools/__init__.py y actualízalo para exportar una nueva herramienta TableScraperTool de la siguiente manera:
from .custom_tool import MyCustomTool
from .table_scraper import TableScraperTool
__all__ = ['MyCustomTool', 'TableScraperTool']Ten en cuenta que MyCustomTool ya estaba incluido en la estructura del proyecto de ejemplo de CrewAI.
A continuación, tenemos que crear TableScraperTool. Para ello, crea un archivo nuevo en tools/table_scraper.py y agrega el siguiente código de Python:
from typing import List, Dict, Any
from bs4 import BeautifulSoup
import requests
from crewai.tools import BaseTool
class TableScraperTool(BaseTool):
name: str = "table_scraper"
description: str = "Scrapes table data from a webpage, extracting rows, links, and other relevant information"
def _run(self, url: str) -> List[Dict[str, Any]]:
"""
Scrapes table data from the given URL.
Args:
url: The URL to scrape
Returns:
List of dictionaries containing table row data
"""
try:
response = requests.get(url)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
# Find all table rows
rows = soup.find_all('tr', class_='table__row')
table_data = []
for row in rows:
row_data = {}
# Extract severity
severity_elem = row.find('li', class_='severity__item')
if severity_elem:
row_data['severity'] = severity_elem.get('class', [''])[0].replace('severity__item--', '')
# Extract vulnerability title and link
title_link = row.find('a', class_='anchor--underline')
if title_link:
row_data['title'] = title_link.text.strip()
row_data['vuln_link'] = title_link.get('href', '')
# Extract package name and link
package_link = row.find('a', attrs={'data-snyk-test-package-manager': True})
if package_link:
row_data['package_name'] = package_link.text.strip()
row_data['package_link'] = package_link.get('href', '')
# Extract version ranges
version_spans = row.find_all('span', class_='vulns-table__semver')
if version_spans:
row_data['version_ranges'] = [span.text.strip() for span in version_spans]
# Extract package manager and date
package_manager = row.find('span', attrs={'type': True})
if package_manager:
row_data['package_manager'] = package_manager.get('type', '')
row_data['published_date'] = package_manager.get('published', '')
if row_data: # Only add if we found some data
table_data.append(row_data)
return table_data
except Exception as e:
return [{"error": f"Failed to scrape table data: {str(e)}"}]
async def _arun(self, url: str) -> List[Dict[str, Any]]:
"""Async implementation of the tool"""
return self._run(url)Por último, también debemos incluir y actualizar la biblioteca de Python BeautifulSoup como parte del proyecto. Para ello, actualiza la lista de dependencies de myproject.toml de la siguiente manera:
dependencies = [
...
"beautifulsoup4>=4.12.0"Luego, aplícala con este comando:
uv pip install -e .Archivo principal de ejecución de CrewAI
Ahora enfoquémonos en el archivo principal crew.py, que encontrarás en src/security_news_summary o en el directorio donde hayas creado la estructura del proyecto CrewAI.
Edita el archivo y, primero, actualiza la importación de la siguiente manera (incluiremos nuestra herramienta personalizada TableScraperTool):
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai_tools import ScrapeWebsiteTool
from typing import List
from .tools import TableScraperToolLuego, desplázate hacia abajo y busca las funciones con anotaciones para agentes (identificadas con la anotación @agent) y tareas (identificadas con la anotación @task). Actualízalas para que reflejen los agentes y las tareas que acabamos de definir:
@agent
def cve_curator(self) -> Agent:
return Agent(
config=self.agents_config['cve_curator'], # type: ignore[index]
verbose=True,
tools=[ScrapeWebsiteTool(), TableScraperTool()]
)
@agent
def cve_researcher(self) -> Agent:
return Agent(
config=self.agents_config['cve_researcher'], # type: ignore[index]
verbose=True,
tools=[ScrapeWebsiteTool()]
)
# To learn more about structured task outputs,
# task dependencies, and task callbacks, check out the documentation:
# https://docs.crewai.com/concepts/tasks#overview-of-a-task
@task
def cve_curation_task(self) -> Task:
return Task(
config=self.tasks_config['cve_curation_task'], # type: ignore[index]
output_file='cves.md'
)
@task
def cve_research_task(self) -> Task:
return Task(
config=self.tasks_config['cve_research_task'], # type: ignore[index]
output_file='cves.md'
)Ejecutar agentes de IA con CrewAI
Eso es todo. Ya estamos listos para ejecutar nuestros agentes de IA y que seleccionen nuevas vulnerabilidades de seguridad usando Snyk Vulnerability Database como fuente de datos.
Solo tenemos que iniciar los agentes de CrewAI desde la terminal con este comando:
crewai runY los agentes de IA comienzan a trabajar:

A medida que avanzan, se informa el estado de las tareas:

Acerca de la seguridad de la IA y los flujos de trabajo agénticos
Crear agentes de IA parece mágico. Cuando funciona, su ejecución es sorprendentemente buena, y la biblioteca CrewAI para la orquestación de agentes es muy fácil de usar.
Dado el rápido avance de la IA y los flujos de trabajo de programación agéntica, debes prestar mucha atención a la confianza en la IA y establecer barreras de seguridad para evitar introducir riesgos y vulnerabilidades, como implementaciones inseguras de servidores MCP, ataques de inyección de prompts y otras superficies vulnerables relacionadas con la seguridad de la IA.
Te recomiendo estos recursos:
Revisa las barreras de seguridad para el código de IA de Snyk
Programación segura con IA con Snyk (y servidores MCP)
Entender la inyección de prompts: técnicas, desafíos y riesgos.
Desarrolla con IA de forma segura desde el inicio
Aprende a integrar la seguridad en cada etapa de tu flujo de trabajo de programación con IA, con consejos prácticos de implementación de expertos.