Ga naar hoofdinhoud

Qwen-Agent: Een gids met demoproject

Leer hoe je Qwen-Agent en Qwen3 gebruikt om een realtime extensie te bouwen die webpagina’s samenvat.
· 12 min lezen

Verken met AI

In deze blogpost laat ik je stap voor stap zien hoe je een browserextensie bouwt op basis van Qwen-Agent die de inhoud van elke webpagina realtime samenvat. We behandelen hoe je:

  • Alibaba’s Qwen3-model lokaal gebruikt via Ollama
  • Qwen-Agent inzet voor gestructureerde prompts en toolgebruik
  • Een Chrome-extensie bouwt met streaming UI-updates
  • Een FastAPI-backend toevoegt voor realtime samenvattingen

Aan het einde heb je een offline-capabele samenvattingsagent, aangedreven door Qwen3, die met één klik webpagina’s in je browser leest en samenvat.

We houden onze lezers op de hoogte van het laatste AI-nieuws met The Median, onze gratis vrijdagse nieuwsbrief die de belangrijkste verhalen van de week uitlegt. Abonneer je en blijf scherp in een paar minuten per week:

Wat is Qwen-Agent?

Qwen-Agent is een lichtgewicht Python-framework van Alibaba voor het ontwikkelen van krachtige LLM-toepassingen met de Qwen3-modelreeks. Het richt zich op ondersteuning van:

  • Agents die instructies opvolgen
  • Toolgebruik en functieaanroepen
  • Geheugen en meerstapsplanning
  • Flexibel prompten via gestructureerde berichten

In de kern vereenvoudigt Qwen-Agent de ontwikkeling van modulaire AI-agents met robuuste redeneer- en code-uitvoeringsmogelijkheden. Het bevat elementaire componenten zoals LLM-wrappers en tools, en hoog-niveau Agent-klassen voor het orkestreren van workflows.

Qwen-Agent werkt met zowel cloud-API’s (zoals Alibaba DashScope) als lokale OpenAI-compatibele runtimes zoals vLLM en Ollama. Het maakt het eenvoudig om krachtige LLM-apps te bouwen met:

  • Snelle integratie via FastAPI
  • Ingebouwde streaming voor frontend-UI’s
  • Aanpasbare function-toolchains
  • Volledige offline privacy en performance

Projectoverzicht: Realtime web-samenvattingsextensie

In dit deel bouwen we een realtime samenvattingsextensie op basis van Qwen-Agent. Dit omvat:

  • Een FastAPI-backend die webpaginatekst accepteert en een samenvatting terugstuurt
  • Een Chrome-extensiepop-up om zichtbare paginainhoud vast te leggen
  • Een streaming-UI terwijl de samenvatting wordt gegenereerd
  • Backend aangedreven door Qwen3:1.7B die lokaal draait via Ollama

Laten we elk onderdeel van dit project doorlopen.

Stap 1: De Qwen3-backend instellen

In deze stap behandelen we alle codebestanden die we moeten opzetten zodat onze backend synchroon werkt met onze extensie.

Stap 1.1: Afhankelijkheden en libraries 

Begin met het installeren van ollama op je systeem. Noteer vervolgens alle Python-afhankelijkheden die voor de backend nodig zijn in requirements.txt. Dit helpt om een consistente omgeving op verschillende machines en containers te waarborgen.

fastapi
uvicorn
python-dateutil
python-dotenv
qwen-agent[code_interpreter]
matplotlib

Hier is een overzicht waar elke library voor wordt gebruikt:

  • qwen-agent[code_interpreter]: Dit is een kernframework voor agents met ondersteuning voor toolgebruik, waarmee je code kunt uitvoeren en gestructureerd kunt redeneren.
  • fastapi en uvicorn: Deze libraries verzorgen samen de async API-backend en dienen je samenvattingslogica.
  • python-dotenv en python-dateutil: Deze hulplibraries behandelen omgevingsvariabelen en datum-/tijdverwerking (handig voor toekomstige opschaling).
  • matplotlib: Wordt gebruikt voor plotten of het tonen van visuele outputs (optioneel) 

Als je dit project lokaal wilt draaien, voer dan de volgende opdracht uit om alle afhankelijkheden te installeren:

pip install -r requirements.txt

Stap 1.2: DockerFile-setup (optioneel)

Laten we nu een Dockerfile opzetten die een minimale Python-omgeving met onze app creëert en poort 7864 openstelt, zodat de Chrome-extensie verzoeken kan sturen naar de FastAPI-backend.

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"]

Deze setup is optioneel als je ervoor kiest om het project lokaal met Uvicorn te draaien in plaats van met Docker.

Stap 1.3: Qwen serveren met Ollama

Vervolgens moet je het Qwen3-model lokaal ophalen en serveren met Ollama. Deze stap maakt offline-inferentie mogelijk door de LLM-service op je machine te hosten.

ollama pull qwen3:1.7b
ollama serve 

Stap 1.4: De FastAPI-samenvattingsserver bouwen

Het bestand app.py definieert een FastAPI-server die realtime samenvattingen van webpaginas inhoud streamt met een lokaal draaiend Qwen3:1.7B-model via Qwen-Agent.

Stap 1.4.1: Imports

Begin met het importeren van FastAPI, streamingutilities en Qwen-Agent-componenten zoals Assistant, die het model en zijn toolmogelijkheden verpakt.

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 logging

Stap 1.4.2: Initialisatie van de FastAPI-app

Vervolgens definiëren we een eenvoudig RequestData-schema om content te ontvangen, en maken we een botinstantie van Assistant. 

app = FastAPI()
class RequestData(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."
)

In de bovenstaande code is bot een instantie van de Assistant-klasse uit Qwen-Agent, geconfigureerd om te communiceren met het lokaal geserveerde Qwen3:1.7B-model via Ollama. Het gebruikt de ingebouwde code_interpreter-tool om door content te redeneren en indien nodig Python-code uit te voeren. Een aangepaste system_message stuurt zijn gedrag om beknopte webpaginasamenvattingen te genereren.

Opmerking: je kunt kleinere modellen zoals qwen3:0.6b of qwen3:1.7b gebruiken om de responstijd en het geheugengebruik aanzienlijk te verlagen. Dit is vooral handig voor snellere samenvattingstaken zonder veel redeneerwerk.

Stap 1.4.3: Samenvattingsroute

Tot slot leest een endpoint de binnenkomende content en levert live samenvattingstekst terwijl die door het model wordt gegenereerd. Het gebruikt streamingoutput zodat de gebruiker niet hoeft te wachten tot de volledige respons is gegenereerd.

@app.post("/summarize_stream_status")
async def summarize_stream_status(data: RequestData):
    user_input = data.content
    def stream():
        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 = None
            for item in reversed(result_list):
                if isinstance(item, list):
                    for subitem in reversed(item):
                        if isinstance(subitem, dict) and "content" in subitem:
                            last_content = subitem["content"]
                            break
                if last_content:
                    break
            if not 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)
            yield f"\n Error: {str(e)}\n"
    return StreamingResponse(stream(), media_type="text/plain")

Zo werkt onze samenvatter:

  • De functie ontvangt POST-data-instructie met het RequestData-schema en verwacht een veld content met de ruwe webpaginatekst.
  • Er is een geneste stream()-generatorfunctie gedefinieerd die stapsgewijs berichten oplevert. Hierdoor kan er realtime feedback naar de frontend worden gestuurd voordat de uiteindelijke samenvatting klaar is.
  • De berichtenlijst bevat expliciet een </nothink>-tagwrapper in het gebruikersbericht om interne redeneringen te onderdrukken, en een gedetailleerde systeemprompt versterkt dit gedrag.
  • De Qwen-Agent-bot wordt aangeroepen met bot.run(messages) waarbij messages een lijst is met één gebruikersbericht. 
  • Modelantwoorden worden gestreamd en verzameld in result_list. De code loopt vervolgens omgekeerd door de lijst om de meest recente contentstring die door de LLM is geretourneerd te extraheren.
  • Qwen’s interne redeneermarkeringen zoals <think> en </think> worden met een regex uit de output verwijderd om de uiteindelijke samenvatting op te schonen.
  • Als er geen geldige content wordt gevonden, wordt een terugvalbericht verzonden. Anders wordt de opgeschoonde samenvatting naar de frontend gestreamd.

Stap 2: De Chrome-extensie bouwen

Dit deel loopt door alle bestanden die nodig zijn om de extensie op te zetten, waaronder de frontend-UI, logica om paginacontent te extraheren, achtergrondcommunicatiescripts en configuratiemetagegevens.

Voordat we de afzonderlijke scripts bekijken, volgt hier een eenvoudige uitleg van wat elk bestand doet:

  • manifest.json: Dit is een configuratiebestand dat extensiemetagegevens, machtigingen en scripts definieert.
  • popup.html: Dit script definieert de zichtbare UI voor de Chrome-extensiepop-up met een knop en een uitvoerpaneel.
  • popup.js: Dit handelt de frontendlogica af, legt de tekst van het huidige tabblad vast en streamt de samenvattingsrespons naar de UI.
  • content.js: Extraheert zichtbare webpaginas inhoud op aanvraag en fungeert als content script.
  • background.js: Coördineert backendcommunicatie en geeft gestreamde samenvattingen door aan de pop-up.
  • icon.png: Het extensiepictogram dat wordt weergegeven in de Chrome-werkbalk en extensiebeheer.

Samen maken deze bestanden de extensie interactief, reactief en in staat om met een lokale modelserver te communiceren.

Stap 1: Extensiemetagegevens

Het script manifest.json bevat metagegevens voor Chrome. Het definieert het gedrag van de extensie, machtigingen, de achtergrondserviceworker en de pop-up-UI.

{
    "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"
      }
    ]
}  

Dit bestand definieert de configuratie en mogelijkheden van je Chrome-extensie. Het verleent essentiële machtigingen zoals scripting (om JavaScript te injecteren), activeTab (om toegang te krijgen tot het huidige tabblad) en storage (voor het opslaan van gebruikersvoorkeuren).

Het veld host_permissions met "<all_urls>" laat de extensie op elke webpagina draaien. Het stelt ook de UI van de extensie in via popup.html en icon.png, en registreert achtergrondgedrag met een serviceworker (background.js). Tot slot definieert het een content script (content.js) dat op alle geladen pagina’s draait, zodat wanneer nodig met webpaginas inhoud kan worden gecommuniceerd.

Stap 2: Een zichtbare interface bouwen 

De popup.html definieert de zichtbare interface van de extensie. Hij maakt verbinding met het actieve tabblad, legt de zichtbare tekst vast en stuurt die naar je backendserver. 

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Web Summarizer Assistant</title>
  <style>
    body {
      width: 500px;
      height: 600px;
      background-color: aliceblue;
      
      
      
    }
    .container {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 15px;
    }
    button {
      border: none;
      border-radius: 5px;
      background-
      color: white;
      
      
      cursor: pointer;
    }
    button:hover {
      background-
    }
    pre {
      background-
      border: 1px solid #ccc;
      border-radius: 5px;
      
      width: 90%;
      height: 350px;
      overflow: auto;
    }
    input[type="text"] {
      
      width: 90%;
      border-radius: 5px;
      border: 1px solid #ccc;
    }
  </style>
</head>
<body>
  <div class="container">
    <h2>Summarize Current Page</h2>
    <button id="summarizeBtn">Summarize</button>
    <pre id="output">Summary will appear here...</pre>
  </div>
  <script src="popup.js"></script>
</body>
</html>

Laten we de bovenstaande code stap voor stap begrijpen:

  1. Eerst zetten we een basis-HTML-structuur op met een <head>-tag met metatags voor tekencodering, viewportinstellingen en een <title>-tag.
  2. Daarna bevat de container binnen de <body>-tag alle UI-elementen, waaronder:
  • Een <h2>-kop die de gebruiker vraagt de huidige pagina samen te vatten.
  • Een Summarize-knop (“#summarizeBtn”) die de gebruiker klikt om contentextractie en samenvatten te starten.
  • Een <pre>-element (“#output”) dat fungeert als scrollbaar paneel om de samenvatting te tonen terwijl deze binnenstroomt.
  1. De styling is gedefinieerd met ingesloten CSS om de pop-up visueel strak en leesbaar te maken. Het pre-blok maakt de output scrollbaar en visueel onderscheidend.
  2. Het script popup.js luistert naar klikken op de knop, extraheert de paginacontent, stuurt die naar de FastAPI-backend en werkt het uitvoerpaneel bij met gestreamde samenvattingstekst.

Stap 3: Een frontend-UI bouwen 

De popup.js fungeert als frontendlogica-controller die reageert op knopklikken, tekst uit het huidige tabblad extraheert, die naar de backend stuurt en de samenvatting realtime terugstreamt naar het uitvoergebied.

document.addEventListener('DOMContentLoaded', function () {
    let serverAddress = '127.0.0.1'; 
    document.getElementById('summarizeBtn').addEventListener('click', async () => {
      const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
      chrome.scripting.executeScript(
        {
          target: { tabId: tab.id },
          func: () => {
            try {
              return document.body?.innerText || 'EMPTY';
            } catch (e) {
              return 'SCRIPT_ERROR';
            }
          }
        },
        async (results) => {
          const pageText = results?.[0]?.result || '';
          console.log(' Extracted text:', pageText.slice(0, 500));
          if (pageText === 'SCRIPT_ERROR') {
            document.getElementById('output').innerText = 'Could not access page content (script error).';
            return;
          }
          if (!pageText || pageText.trim() === 'EMPTY') {
            document.getElementById('output').innerText = ' No page text found.';
            return;
          }
          try {
            console.log( Sending streaming POST to http://${serverAddress}:7864/summarize_stream_status);
            const res = await fetch(http://${serverAddress}:7864/summarize_stream_status, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ content: pageText }),
            });
            const reader = res.body.getReader();
            const decoder = new TextDecoder();
            let resultText = '';
            while (true) {
            const { done, value } = await reader.read();
            if (done) break;
            const chunk = decoder.decode(value, { stream: true });
            resultText += chunk;
            document.getElementById('output').innerText = resultText;
            }
          } catch (err) {
            console.error(' Fetch error:', err);
            document.getElementById('output').innerText = ' Failed to get summary.\n' + err.message;
          }
        }
      );
    });
  });

Dit JavaScript-bestand verzorgt de frontend-UI-logica van de Chrome-extensie, zodat gebruikers met één klik webpaginas inhoud kunnen extraheren en samenvatten.

Zo werkt het:

  • Wanneer de pop-up is geladen (DOMContentLoaded), wordt een eventlistener gekoppeld aan de "Summarize"-knop.
  • Bij een klik vraagt de extensie het huidige actieve tabblad op met chrome.tabs.query.
  • Vervolgens voert hij een content script uit in dat tabblad met chrome.scripting.executeScript, dat probeert de innerText van de pagina-body te extraheren.
  • Als het script faalt of lege content teruggeeft, worden passende fallbackberichten in de UI getoond.
  • Als er succesvol tekst is geëxtraheerd, wordt die als POST-verzoek verstuurd naar de lokale FastAPI-backend op http://127.0.0.1:7864/summarize_stream_status.
  • De respons wordt gestreamd met res.body.getReader(), zodat delen van de samenvatting realtime in het uitvoerpaneel verschijnen.
  • Een TextDecoder decodeert elk gestreamd tekstfragment en voegt het live toe aan de weergave.
  • Eventuele netwerk- of backendfouten worden opgevangen en getoond in de pop-up voor debugging of feedback.

Stap 4: Webpaginas inhoud extraheren

Voordat we webpaginas inhoud naar onze backend kunnen sturen, hebben we een manier nodig om deze uit het huidige tabblad te halen. Het script content.js luistert naar berichten van de achtergrond- of pop-up-scripts en retourneert de zichtbare tekstinhoud van de webpagina. 

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.type === "GET_PAGE_TEXT") {
      const bodyText = document.body.innerText.trim();
      sendResponse({ text: bodyText || null });
    }
});

Dit script luistert naar berichten van het type "GET_PAGE_TEXT" en reageert door de zichtbare bodytekst (document.body.innerText) te extraheren en terug te sturen. Zo kan de achtergrondworker eenvoudig om webpaginas inhoud vragen zonder telkens code te injecteren, waardoor de communicatie netjes en asynchroon blijft.

Stap 5: Backendcoördinatie

Het achtergrondscript (background.js) vormt de brug tussen de pop-up-UI en content scripts. Het zorgt ervoor dat berichtuitwisseling en samenvattingscoördinatie achter de schermen correct verlopen.

chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
    if (request.type === "SUMMARIZE_PAGE") {
      const tabId = sender.tab.id;
        chrome.scripting.executeScript(
        {
          target: { tabId },
          func: () => {
            try {
              return document.body?.innerText || 'EMPTY';
            } catch (e) {
              return 'SCRIPT_ERROR';
            }
          }
        },
        async (results) => {
          const pageText = results?.[0]?.result || '';
          if (!pageText || pageText === 'SCRIPT_ERROR') {
            chrome.runtime.sendMessage({
              type: 'SUMMARY_RESULT',
              summary: ' Failed to read page text.',
            });
            return;
          }
          chrome.storage.local.get(['database_host'], async function (result) {
            const host = result.database_host || '127.0.0.1';
            try {
              const response = await fetch(http://${host}:7864/summarize_stream_status, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ content: pageText }),
              });
              const reader = response.body.getReader();
              const decoder = new TextDecoder();
              let fullSummary = '';
              while (true) {
                const { done, value } = await reader.read();
                if (done) break;
                const chunk = decoder.decode(value, { stream: true });
                fullSummary += chunk;
                chrome.runtime.sendMessage({
                  type: 'SUMMARY_PROGRESS',
                  chunk
                });
              }
              chrome.runtime.sendMessage({
                type: 'SUMMARY_DONE',
                summary: fullSummary
              });
            } catch (err) {
              chrome.runtime.sendMessage({
                type: 'SUMMARY_RESULT',
                summary: ' Error during summarization: ' + err.message
              });
            }
          });
        }
      );
      return true; 
    }
  });
  

Bovenstaande code zorgt voor een soepele stroom van contentextractie, samenvatten en realtime updates. Zo werkt het stap voor stap:

  • Hij luistert naar een bericht van het type "SUMMARIZE_PAGE" dat wordt geactiveerd door een knopklik in de pop-up.
  • Eenmaal geactiveerd identificeert hij het actieve tabblad met sender.tab.id en voert een geïnjecteerd script uit via chrome.scripting.executeScript om de zichtbare tekst van de webpagina te extraheren.
  • Als de content niet toegankelijk is of leeg blijkt, wordt een fallbackbericht teruggestuurd.
  • Anders haalt hij de database_host (meestal 127.0.0.1) op uit Chrome’s lokale opslag en gebruikt die om een POST-verzoek naar de FastAPI-backend te sturen met de geëxtraheerde content.
  • Vervolgens opent hij een streamingverbinding en leest hij de respons stukje bij beetje met een ReadableStreamDefaultReader.
  • Elk fragment wordt gedecodeerd en als tussentijdse update naar de pop-up gestuurd met chrome.runtime.sendMessage met type 'SUMMARY_PROGRESS'.
  • Zodra de stream eindigt, wordt een laatste bericht met de volledige samenvatting verzonden. Als er tijdens dit proces een fout optreedt, wordt in plaats daarvan een fallbackbericht verstuurd.

Dit achtergrondscript is cruciaal om realtime, gestreamde samenvattingen in de Chrome-extensie mogelijk te maken zonder de UI te blokkeren of de pagina te herladen.

Stap 6: Een extensiepictogram toevoegen

Kies of teken een pictogramafbeelding voor de extensie en sla die op als icon.png in de extensiemap. Dit is wat we gebruiken:

Extensiepictogram

Afbeelding gegenereerd met FireFly

Je totale mapstructuur zou er zo uit moeten zien:

QWEN-WEB-SUMMARIZER/
├── backend/
│   ├── app.py
│   ├── Dockerfile
│   └── requirements.txt
├── extension/
│   ├── background.js
│   ├── content.js
│   ├── icon.png
│   ├── manifest.json
│   ├── popup.html
│   └── popup.js

Stap 3: De app draaien

Om alles lokaal te draaien, voer je de volgende opdracht uit in de terminal:

uvicorn backend.app:app --host 0.0.0.0 --port 7864

Dit is ideaal voor lokale ontwikkeling of debugging zonder Docker. Om in Docker te draaien, voer je de volgende opdrachten één voor één uit in je terminal:

docker build -t qwen-agent-backend .
docker run -p 7864:7864 qwen-agent-backend

De Chrome-extensie communiceert met poort 7864.  Volg nu deze stappen om je extensie in Chrome te laten draaien:

  • Open Chrome en klik op “Extensions” (aan de rechterkant van de zoekbalk).
  • Zet “Developer mode” aan en klik op “Load unpacked” (linksboven). 

Chrome-extensietab voor het activeren van een extensie op basis van Qwen-Agent

  • Laad vervolgens onze extensiemap met alle bestanden en wacht op de bevestiging.
  • Zodra de pop-up de extensie bevestigt, klik je op het extensiepictogram op een willekeurige webpagina en krijg je een streamende samenvatting via je lokale Qwen3-model.

Laten we de resultaten bekijken:

Voorbeeld van Qwen-Agent-extensie

Conclusie

In dit project hebben we een realtime assistent voor webpaginasamenvatting gebouwd met het Qwen-Agent-framework en het Qwen3:1.7B-model dat lokaal draait via Ollama. We hebben een FastAPI-backend ontwikkeld voor LLM-inferentie en die geïntegreerd met een Chrome-extensie die zichtbare paginacontent vastlegt en een live gestreamde samenvatting toont.

Deze demo laat zien hoe Qwen-Agent volledig offline, tool-aangevulde redeneerworkflows in de browser mogelijk maakt. Het vormt de basis voor het bouwen van geavanceerdere lokale agents, zoals browserautomatiseringstools, researchcopilots of documentgebaseerde chatbots.

Wil je meer leren over AI-agents? Bekijk dan deze blogs:

Aashi Dutt

Auteur

Aashi Dutt

Ik ben een Google Developers Expert in ML (Gen AI), een Kaggle 3x Expert en een Women Techmakers Ambassador met meer dan 3 jaar ervaring in tech. In 2020 heb ik een healthtech-startup mee opgericht en ik volg een master computer science aan Georgia Tech, met als specialisatie machine learning.

Onderwerpen

Gerelateerd