En esta entrada del blog, te explicaré cómo crear una extensión del navegador basada en Qwen-Agent que resuma el contenido de cualquier página web en tiempo real. Veremos cómo hacerlo:
Utiliza el modelo Qwen3 de Alibaba localmente a través de Ollama
Utiliza Qwen-Agent para la orientación estructurada y el uso de herramientas
Crea una extensión de Chrome con actualizaciones de interfaz de usuario en tiempo real
Añade el backend FastAPI para soportar el resumen en tiempo real
Al final, dispondrás de un agente resumidor con capacidad offline, impulsado por Qwen3, que lee y resume páginas web en tu navegador con un solo clic.
Mantenemos a nuestros lectores al día de lo último en IA enviándoles The Median, nuestro boletín gratuito de los viernes que desglosa las noticias clave de la semana. Suscríbete y mantente alerta en sólo unos minutos a la semana:
¿Qué es Qwen-Agent?
Qwen-Agente es un marco de trabajo ligero en Python creado por Alibaba para desarrollar potentes aplicaciones LLM utilizando la plataforma Qwen3 de modelos. Se centra en apoyar:
Agentes seguidores de instrucciones
Uso de herramientas y llamada a funciones
Memoria y planificación multivuelta
Aviso flexible mediante mensajes estructurados
En esencia, Qwen-Agent simplifica el desarrollo de agentes modulares de IA con sólidas capacidades de razonamiento y ejecución de código. Incluye componentes atómicos como envoltorios LLM y herramientas, así como clases de alto nivel Agent para orquestar flujos de trabajo.
Qwen-Agent funciona tanto con API basadas en la nube (como Alibaba DashScope) como con tiempos de ejecución locales compatibles con OpenAI, como vLLM y Ollama. Facilita la creación de potentes aplicaciones LLM:
Integración rápida mediante FastAPI
Streaming integrado para interfaces de usuario frontales
Cadenas de herramientas de funciones personalizables
Total privacidad y rendimiento offline
Resumen del proyecto: Extensión del Resumidor Web en Tiempo Real
En esta sección, construiremos una extensión de resumidor en tiempo real con Qwen-Agent. Esto incluye
Un backend FastAPI que acepta el texto de una página web y devuelve un resumen
Una extensión de Chrome emergente para capturar el contenido visible de la página
Se genera una interfaz de usuario de streaming como resumen
Backend alimentado por Qwen3:1.7B ejecutándose localmente a través de Ollama
Recorramos cada parte de este proyecto.
Paso 1: Configurar el backend Qwen3
En este paso, cubriremos todos los archivos de código que necesitamos configurar para que nuestro backend funcione de forma sincronizada con nuestra extensión.
Paso 1.1: Dependencias y bibliotecas
Empieza instalando ollama en tu sistema. A continuación, enumera todas las dependencias de Python necesarias para el backend en requirements.txt.. Esto ayuda a garantizar una configuración coherente del entorno en todas las máquinas y contenedores.
fastapi
uvicorn
python-dateutil
python-dotenv
qwen-agent[code_interpreter]
matplotlibCon la tecnología de
Aquí tienes un desglose de para qué se utiliza cada biblioteca:
qwen-agent[code_interpreter]: Se trata de un marco central de agentes con soporte para el uso de herramientas, que permite la ejecución de código y el razonamiento estructurado.
fastapi y uvicorn: Estas bibliotecas juntas alimentan el backend asíncrono de la API y sirven a tu lógica de resumen.
python-dotenv y python-dateutil: Estas bibliotecas de utilidades gestionan las variables de entorno y el procesamiento de fecha/hora (útil para futuros escalados).
matplotlib: Se utiliza para gráficar o mostrar resultados visuales (opcional)
Si quieres ejecutar este proyecto localmente, ejecuta el siguiente comando para instalar todas las dependencias:
Ahora, vamos a configurar un archivo Dockerfile que cree un entorno Python mínimo con nuestra aplicación y exponga el puerto 7864, permitiendo que la extensión de Chrome envíe peticiones al backend FastAPI.
FROM python:3.10
WORKDIR /app
COPY . .
RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 7864
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7864"]Con la tecnología de
Esta configuración es opcional si decides ejecutar el proyecto localmente utilizando Uvicorn en lugar de Docker.
Paso 1.3: Servir a Qwen con Ollama
A continuación, tendrás que extraer y servir el modelo Qwen3 localmente utilizando Ollama. Este paso permite la inferencia fuera de línea alojando el servicio LLM en tu máquina.
Paso 1.4: Construir el servidor de integración FastAPI
El archivo app.py define un servidor FastAPI que transmite resúmenes en tiempo real del contenido de una página web utilizando un modelo Qwen3:1.7B de ejecución local a través de Qwen-Agent.
Paso 1.4.1: Importaciones
Empieza importando FastAPI, utilidades de streaming y componentes de Qwen-Agent como Assistant, que envuelve el modelo y sus capacidades de herramienta.
import re
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from typing import List, Dict, Any
from qwen_agent.agents import Assistant
import loggingCon la tecnología de
Paso 1.4.2: Inicialización de la aplicación FastAPI
A continuación, definimos un esquema sencillo de RequestData para recibir contenidos, y creamos una instancia de bot de Assistant.
app = FastAPI()classRequestData(BaseModel):
content:str
bot = Assistant(
llm={"model":"qwen3:1.7b","model_server":"http://localhost:11434/v1","api_key":"EMPTY"},
function_list=["code_interpreter"],
system_message="You are a summarization assistant. Directly output the cleaned summary of the given text without any reasoning, self-talk, thoughts, or internal planning steps. Do not include phrases like 'I think', 'maybe', 'let's', 'the user wants', or anything not part of the final summary. Your output must look like it was written by an editor, not a model.")Con la tecnología de
En el código anterior, el bot es una instancia de la clase Assistant de Qwen-Agent, configurada para interactuar con el modelo Qwen3:1.7B servido localmente a través de Ollama. Utiliza la herramienta integrada code_interpreter para razonar sobre el contenido y ejecutar código Python si es necesario. Un system_message personalizado guía su comportamiento para generar resúmenes concisos de páginas web.
Nota: Puedes utilizar modelos más pequeños como qwen3:0.6b o qwen3:1.7b para reducir significativamente el tiempo de respuesta y el uso de memoria. Esto es especialmente útil para tareas de resumen más rápidas sin mucha sobrecarga de razonamiento.
Paso 1.4.3: Ruta del resumidor
Por último, un punto final lee el contenido entrante y proporciona texto resumido en directo a medida que lo genera el modelo. Utiliza salida en streaming para que el usuario no tenga que esperar a que se genere la respuesta completa.
@app.post("/summarize_stream_status")asyncdefsummarize_stream_status(data: RequestData):
user_input = data.content
defstream():try:yield"🔍 Reading content on website...\n"print(" Received text:", user_input[:200])
messages =[{"role":"system","content":"You are a summarization assistant. Directly output the cleaned summary of the given text without any reasoning, self-talk, thoughts, or internal planning steps. Do not include phrases like 'I think', 'maybe', 'let's', 'the user wants', or anything not part of the final summary. Your output must look like it was written by an editor, not a model."},{"role":"user","content":"<nothink>\nSummarize the following text clearly and concisely. Do not include any internal thoughts, planning, or reasoning. Just return the final summary:\n\n"+ user_input +"\n</nothink>"}]yield"🧠 Generating summary...\n"
result = bot.run(messages)
result_list =list(result)print(" Raw result:", result_list)# Extract summary
last_content =Nonefor item inreversed(result_list):ifisinstance(item,list):for subitem inreversed(item):ifisinstance(subitem,dict)and"content"in subitem:
last_content = subitem["content"]breakif last_content:breakifnot last_content:yield" No valid summary found.\n"return
summary = re.sub(r"</?think>","", last_content)
summary = re.sub(r"(?s)^.*?(Summary:|Here's a summary|The key points are|Your tutorial|This tutorial|To summarize|Final summary:)","",
summary,
flags=re.IGNORECASE
)
summary = re.sub(r"\n{3,}","\n\n", summary)
summary = summary.strip()yield"\n📄 Summary:\n"+ summary +"\n"except Exception as e:print(" Error:", e)yieldf"\n Error: {str(e)}\n"return StreamingResponse(stream(), media_type="text/plain")Con la tecnología de
Así funciona nuestro resumidor:
La función recibe la instrucción de datos POST utilizando el esquema RequestData, esperando un campo llamado content que contiene el texto en bruto de la página web.
Se define una función generadora anidada stream() para producir mensajes progresivamente. Esto permite enviar información en tiempo real al frontend antes de completar el resumen final.
La lista de mensajes incluye explícitamente una envoltura de la etiqueta en el mensaje de usuario para suprimir el razonamiento interno, y una indicación detallada del sistema refuerza este comportamiento.
El bot Qwen-Agent se invoca utilizando bot.run(messages), donde messages es una lista que contiene un único mensaje de entrada del usuario.
Las respuestas del modelo se transmiten y recogen en result_list. A continuación, el código recorre la lista en sentido inverso para extraer la cadena de contenido más reciente devuelta por el LLM.
Los marcadores de razonamiento interno de Qwen, como y , se eliminan de la salida mediante una regex para limpiar el resumen final.
Si no se encuentra ningún contenido válido, se envía un mensaje alternativo. De lo contrario, el resumen limpio se transmite al frontend.
Paso 2: Crear la extensión de Chrome
Esta sección recorre todos los archivos necesarios para configurar la extensión, incluida la interfaz de usuario del frontend, la lógica para extraer el contenido de la página, los scripts de comunicación en segundo plano y los metadatos de configuración.
Antes de ver los guiones individuales, aquí tienes un desglose sencillo de lo que hace cada archivo:
manifest.json: Es un archivo de configuración que define los metadatos, permisos y scripts de la extensión.
popup.html: Este script define la interfaz de usuario visible para la ventana emergente de la extensión de Chrome con un botón y un panel de salida.
popup.js: Se encarga de la lógica del frontend y captura el texto de la pestaña actual y transmite la respuesta del resumen a la interfaz de usuario.
content.js: Extrae el contenido visible de la página web cuando se le solicita, actuando como script de contenido.
background.js: Este script coordina la comunicación del backend y transmite los resúmenes en streaming a la ventana emergente.
icon.png: Se trata de un icono de extensión que aparece en la barra de herramientas y en el gestor de extensiones de Chrome.
Juntos, estos archivos hacen que la extensión sea interactiva, reactiva y capaz de hablar con un servidor de modelos local.
Paso 1: Metadatos de la extensión
El script manifest.json contiene metadatos para Chrome. Define el comportamiento de la extensión, los permisos, el trabajador de servicios en segundo plano y la interfaz de usuario emergente.
{"manifest_version":3,"name":"Web Summarizer","version":"1.0","description":"Summarize the content of the current page using a local LLM agent.","permissions":["scripting","activeTab","storage"],"host_permissions":["<all_urls>"],"action":{"default_popup":"popup.html","default_icon":"icon.png"},"background":{"service_worker":"background.js"},"content_scripts":[{"matches":["<all_urls>"],"js":["content.js"],"run_at":"document_idle"}]}Con la tecnología de
Este archivo define la configuración y las capacidades de tu extensión de Chrome. Concede permisos esenciales como scripting (para inyectar JavaScript), activeTab (para acceder a la pestaña actual) y storage (para guardar las preferencias del usuario).
El campo host_permissions con "<all_urls>" permite que la extensión se ejecute en cualquier página web. También configura la interfaz de usuario de la extensión a través de popup.html y icon.png, y registra el comportamiento en segundo plano utilizando un trabajador de servicios (background.js). Por último, define un script de contenido (content.js) para que se ejecute en todas las páginas cargadas, permitiendo la interacción con el contenido de la página web cuando sea necesario.
Paso 2: Construir una interfaz visible
La página popup.html define la interfaz visible de la extensión. Se conecta a la pestaña activa que captura el texto visible y lo envía a tu servidor backend.
En primer lugar, creamos una estructura HTML básica con una etiqueta que incluye metaetiquetas para la codificación de caracteres, la configuración de la ventana gráfica y una etiqueta
Soy experta Google Developers en ML (Gen AI), triple experta en Kaggle y embajadora de Women Techmakers, con más de tres años de experiencia en el sector tecnológico. Cofundé una startup de salud en 2020 y actualmente curso un máster en informática en Georgia Tech, con especialización en aprendizaje automático.
Aprende a utilizar modelos de IA generativa para crear un editor de imágenes, un chatbot similar a ChatGPT con pocos recursos y una aplicación clasificadora de aprobación de préstamos y a automatizar interacciones PDF y un asistente de voz con GPT.
Un tutorial completo sobre la construcción de agentes LangChain multiherramienta para automatizar tareas en Python utilizando LLMs y modelos de chat utilizando OpenAI.
Una visión completa de la API Assistants con nuestro artículo, que ofrece una mirada en profundidad a sus características, usos en la industria, guía de configuración y las mejores prácticas para maximizar su potencial en diversas aplicaciones empresariales.
Explore el potencial sin explotar de los grandes modelos lingüísticos con LangChain, un marco Python de código abierto para crear aplicaciones avanzadas de IA.
Una guía completa para afinar un modelo FLAN-T5 para una tarea de respuesta a preguntas utilizando la biblioteca de transformadores, y ejecutando la inferencia optmizada en un escenario del mundo real.
En esta entrada del blog, te explicaré cómo crear una extensión del navegador basada en Qwen-Agent que resuma el contenido de cualquier página web en tiempo real. Veremos cómo hacerlo:
Al final, dispondrás de un agente resumidor con capacidad offline, impulsado por Qwen3, que lee y resume páginas web en tu navegador con un solo clic.
Mantenemos a nuestros lectores al día de lo último en IA enviándoles The Median, nuestro boletín gratuito de los viernes que desglosa las noticias clave de la semana. Suscríbete y mantente alerta en sólo unos minutos a la semana:
¿Qué es Qwen-Agent?
Qwen-Agente es un marco de trabajo ligero en Python creado por Alibaba para desarrollar potentes aplicaciones LLM utilizando la plataforma Qwen3 de modelos. Se centra en apoyar:
En esencia, Qwen-Agent simplifica el desarrollo de agentes modulares de IA con sólidas capacidades de razonamiento y ejecución de código. Incluye componentes atómicos como envoltorios LLM y herramientas, así como clases de alto nivel
Agentpara orquestar flujos de trabajo.Qwen-Agent funciona tanto con API basadas en la nube (como Alibaba DashScope) como con tiempos de ejecución locales compatibles con OpenAI, como vLLM y Ollama. Facilita la creación de potentes aplicaciones LLM:
Resumen del proyecto: Extensión del Resumidor Web en Tiempo Real
En esta sección, construiremos una extensión de resumidor en tiempo real con Qwen-Agent. Esto incluye
Recorramos cada parte de este proyecto.
Paso 1: Configurar el backend Qwen3
En este paso, cubriremos todos los archivos de código que necesitamos configurar para que nuestro backend funcione de forma sincronizada con nuestra extensión.
Paso 1.1: Dependencias y bibliotecas
Empieza instalando ollama en tu sistema. A continuación, enumera todas las dependencias de Python necesarias para el backend en
requirements.txt.. Esto ayuda a garantizar una configuración coherente del entorno en todas las máquinas y contenedores.Aquí tienes un desglose de para qué se utiliza cada biblioteca:
qwen-agent[code_interpreter]: Se trata de un marco central de agentes con soporte para el uso de herramientas, que permite la ejecución de código y el razonamiento estructurado.fastapiyuvicorn: Estas bibliotecas juntas alimentan el backend asíncrono de la API y sirven a tu lógica de resumen.python-dotenvypython-dateutil: Estas bibliotecas de utilidades gestionan las variables de entorno y el procesamiento de fecha/hora (útil para futuros escalados).matplotlib: Se utiliza para gráficar o mostrar resultados visuales (opcional)Si quieres ejecutar este proyecto localmente, ejecuta el siguiente comando para instalar todas las dependencias:
Paso 1.2: Configuración de DockerFile (opcional)
Ahora, vamos a configurar un archivo Dockerfile que cree un entorno Python mínimo con nuestra aplicación y exponga el puerto 7864, permitiendo que la extensión de Chrome envíe peticiones al backend FastAPI.
Esta configuración es opcional si decides ejecutar el proyecto localmente utilizando Uvicorn en lugar de Docker.
Paso 1.3: Servir a Qwen con Ollama
A continuación, tendrás que extraer y servir el modelo Qwen3 localmente utilizando Ollama. Este paso permite la inferencia fuera de línea alojando el servicio LLM en tu máquina.
Paso 1.4: Construir el servidor de integración FastAPI
El archivo
app.pydefine un servidor FastAPI que transmite resúmenes en tiempo real del contenido de una página web utilizando un modelo Qwen3:1.7B de ejecución local a través de Qwen-Agent.Paso 1.4.1: Importaciones
Empieza importando FastAPI, utilidades de streaming y componentes de Qwen-Agent como
Assistant, que envuelve el modelo y sus capacidades de herramienta.Paso 1.4.2: Inicialización de la aplicación FastAPI
A continuación, definimos un esquema sencillo de
RequestDatapara recibir contenidos, y creamos una instancia de bot deAssistant.En el código anterior, el
botes una instancia de la claseAssistantde Qwen-Agent, configurada para interactuar con el modelo Qwen3:1.7B servido localmente a través de Ollama. Utiliza la herramienta integradacode_interpreterpara razonar sobre el contenido y ejecutar código Python si es necesario. Unsystem_messagepersonalizado guía su comportamiento para generar resúmenes concisos de páginas web.Nota: Puedes utilizar modelos más pequeños como
qwen3:0.6boqwen3:1.7bpara reducir significativamente el tiempo de respuesta y el uso de memoria. Esto es especialmente útil para tareas de resumen más rápidas sin mucha sobrecarga de razonamiento.Paso 1.4.3: Ruta del resumidor
Por último, un punto final lee el contenido entrante y proporciona texto resumido en directo a medida que lo genera el modelo. Utiliza salida en streaming para que el usuario no tenga que esperar a que se genere la respuesta completa.
Así funciona nuestro resumidor:
POSTutilizando el esquemaRequestData, esperando un campo llamadocontentque contiene el texto en bruto de la página web.stream()para producir mensajes progresivamente. Esto permite enviar información en tiempo real al frontend antes de completar el resumen final.en el mensaje de usuario para suprimir el razonamiento interno, y una indicación detallada del sistema refuerza este comportamiento.bot.run(messages), dondemessageses una lista que contiene un único mensaje de entrada del usuario.result_list. A continuación, el código recorre la lista en sentido inverso para extraer la cadena de contenido más reciente devuelta por el LLM.y, se eliminan de la salida mediante una regex para limpiar el resumen final.Paso 2: Crear la extensión de Chrome
Esta sección recorre todos los archivos necesarios para configurar la extensión, incluida la interfaz de usuario del frontend, la lógica para extraer el contenido de la página, los scripts de comunicación en segundo plano y los metadatos de configuración.
Antes de ver los guiones individuales, aquí tienes un desglose sencillo de lo que hace cada archivo:
manifest.json: Es un archivo de configuración que define los metadatos, permisos y scripts de la extensión.popup.html: Este script define la interfaz de usuario visible para la ventana emergente de la extensión de Chrome con un botón y un panel de salida.popup.js: Se encarga de la lógica del frontend y captura el texto de la pestaña actual y transmite la respuesta del resumen a la interfaz de usuario.content.js: Extrae el contenido visible de la página web cuando se le solicita, actuando como script de contenido.background.js: Este script coordina la comunicación del backend y transmite los resúmenes en streaming a la ventana emergente.icon.png: Se trata de un icono de extensión que aparece en la barra de herramientas y en el gestor de extensiones de Chrome.Juntos, estos archivos hacen que la extensión sea interactiva, reactiva y capaz de hablar con un servidor de modelos local.
Paso 1: Metadatos de la extensión
El script
manifest.jsoncontiene metadatos para Chrome. Define el comportamiento de la extensión, los permisos, el trabajador de servicios en segundo plano y la interfaz de usuario emergente.Este archivo define la configuración y las capacidades de tu extensión de Chrome. Concede permisos esenciales como
scripting(para inyectar JavaScript),activeTab(para acceder a la pestaña actual) ystorage(para guardar las preferencias del usuario).El campo
host_permissionscon "<all_urls>" permite que la extensión se ejecute en cualquier página web. También configura la interfaz de usuario de la extensión a través depopup.htmlyicon.png, y registra el comportamiento en segundo plano utilizando un trabajador de servicios (background.js). Por último, define un script de contenido (content.js) para que se ejecute en todas las páginas cargadas, permitiendo la interacción con el contenido de la página web cuando sea necesario.Paso 2: Construir una interfaz visible
La página
popup.htmldefine la interfaz visible de la extensión. Se conecta a la pestaña activa que captura el texto visible y lo envía a tu servidor backend.Vamos a entender el código anterior paso a paso:
que incluye metaetiquetas para la codificación de caracteres, la configuración de la ventana gráfica y una etiqueta