In diesem Blogpost zeige ich dir, wie du mit Qwen-Agenteine Browsererweiterung baust , die den Inhalt einer beliebigen Webseite in Echtzeit zusammenfasst. Wir zeigen dir, wie du:
Nutze das Qwen3-Modell von Alibaba lokal über Ollama
Benutze den Qwen-Agent für strukturiertes Prompting und den Einsatz von Tools
Baue eine Chrome-Erweiterung mit Streaming UI Updates
FastAPI-Backend hinzufügen, um Echtzeit-Zusammenfassung zu unterstützen
Am Ende wirst du einen offline-fähigen Zusammenfassungs-Agenten haben, der von Qwen3 angetrieben wird und der Webseiten in deinem Browser mit einem einzigen Klick liest und zusammenfasst.
Wir halten unsere Leserinnen und Leser mit The Median auf dem Laufenden, unserem kostenlosen Freitags-Newsletter, der die wichtigsten Meldungen der Woche aufschlüsselt. Melde dich an und bleibe in nur ein paar Minuten pro Woche auf dem Laufenden:
Was ist Qwen-Agent?
Qwen-Agent ist ein leichtgewichtiges Python-Framework, das von Alibaba entwickelt wurde, um leistungsstarke LLM-Anwendungen mit der Qwen3 Familie von Modellen. Sie konzentriert sich auf die Unterstützung:
Agenten, die Anweisungen befolgen
Werkzeuggebrauch und Funktionsaufruf
Speicher und Multi-Turn-Planung
Flexible Eingabeaufforderung über strukturierte Nachrichten
Im Kern vereinfacht Qwen-Agent die Entwicklung von modularen KI-Agenten mit robusten Argumentations- und Codeausführungsfunktionen. Sie enthält atomare Komponenten wie LLM-Wrapper und Tools sowie High-Level-Klassen Agent für die Orchestrierung von Arbeitsabläufen.
Qwen-Agent funktioniert sowohl mit Cloud-basierten APIs (wie Alibaba DashScope) als auch mit lokalen OpenAI-kompatiblen Laufzeiten wie vLLM und Ollama. Es macht es einfach, leistungsstarke LLM-Apps zu erstellen:
Schnelle Integration über FastAPI
Eingebautes Streaming für Frontend UIs
Anpassbare Funktions-Toolchains
Volle Offline-Privatsphäre und Leistung
Projektübersicht: Real-Time Web Summarizer Erweiterung
In diesem Abschnitt bauen wir eine Echtzeit-Zusammenfassungserweiterung auf Basis von Qwen-Agent. Dazu gehören:
Ein FastAPI-Backend, das Webseitentext annimmt und eine Zusammenfassung zurückgibt
Ein Pop-up der Chrome-Erweiterung, um sichtbare Seiteninhalte zu erfassen
Eine Streaming-UI als Zusammenfassung wird erstellt
Das Backend wird von Qwen3:1.7B betrieben und läuft lokal über Ollama
Lass uns die einzelnen Teile dieses Projekts durchgehen.
Schritt 1: Einrichten des Qwen3 Backends
In diesem Schritt werden wir alle Codedateien behandeln, die wir einrichten müssen, damit unser Backend synchron mit unserer Erweiterung arbeitet.
Schritt 1.1: Abhängigkeiten und Bibliotheken
Beginne mit der Installation von ollama auf deinem System. Als Nächstes listest du alle Python-Abhängigkeiten auf, die für das Backend benötigt werden: requirements.txt.. So kannst du sicherstellen, dass die Umgebung auf allen Rechnern und Containern einheitlich eingerichtet ist.
fastapi
uvicorn
python-dateutil
python-dotenv
qwen-agent[code_interpreter]
matplotlibBereitgestellt von
Hier ist eine Aufschlüsselung, wofür jede Bibliothek verwendet wird:
qwen-agent[code_interpreter]: Dies ist ein Kernagenten-Framework mit Tool-Unterstützung, das die Ausführung von Code und strukturiertes Denken ermöglicht.
fastapi und uvicorn: Diese Bibliotheken bilden zusammen das asynchrone API-Backend und bedienen deine Zusammenfassungslogik.
python-dotenv und python-dateutil: Diese Utility-Bibliotheken behandeln Umgebungsvariablen und die Verarbeitung von Datum und Uhrzeit (nützlich für zukünftige Skalierungen).
matplotlib: Es wird zum Plotten oder Anzeigen von visuellen Ausgaben verwendet (optional).
Wenn du dieses Projekt lokal ausführen möchtest, führe den folgenden Befehl aus, um alle Abhängigkeiten zu installieren:
Jetzt richten wir ein Dockerfile ein, das eine minimale Python-Umgebung mit unserer App erstellt und Port 7864 freigibt, damit die Chrome-Erweiterung Anfragen an das FastAPI-Backend senden kann.
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"]Bereitgestellt von
Diese Einrichtung ist optional, wenn du dich dafür entscheidest, das Projekt lokal mit Uvicorn statt mit Docker auszuführen.
Schritt 1.3: Qwen mit Ollama dienen
Als Nächstes musst du das Qwen3-Modell mit Ollama lokal abrufen und bereitstellen. Dieser Schritt ermöglicht Offline-Inferenz, indem der LLM-Dienst auf deinem Rechner gehostet wird.
Schritt 1.4: Aufbau des FastAPI-Zusammenfassungsservers
Die Datei app.py definiert einen FastAPI-Server, der Zusammenfassungen von Webseiteninhalten in Echtzeit mit einem lokal laufenden Qwen3:1.7B-Modell über den Qwen-Agent streamt.
Schritt 1.4.1: Importe
Beginne mit dem Import von FastAPI, Streaming-Dienstprogrammen und Qwen-Agent-Komponenten wie Assistant, die das Modell und seine Werkzeugfähigkeiten umhüllen.
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 loggingBereitgestellt von
Schritt 1.4.2: FastAPI App Initialisierung
Als Nächstes definieren wir ein einfaches RequestData Schema, um Inhalte zu empfangen, und erstellen eine Bot-Instanz von 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.")Bereitgestellt von
Im obigen Code ist bot eine Instanz der Klasse Assistant von Qwen-Agent, die so konfiguriert ist, dass sie mit dem lokal bedienten Qwen3:1.7B-Modell über Ollama interagiert. Es nutzt das integrierte Tool code_interpreter, um den Inhalt zu durchsuchen und bei Bedarf Python-Code auszuführen. Eine benutzerdefinierte system_message steuert das Verhalten, um prägnante Webseiten-Zusammenfassungen zu erstellen.
Hinweis: Du kannst kleinere Modelle wie qwen3:0.6b oder qwen3:1.7b verwenden, um die Reaktionszeit und den Speicherverbrauch deutlich zu reduzieren. Dies ist besonders nützlich für schnellere Zusammenfassungsaufgaben ohne großen Denkaufwand.
Schritt 1.4.3: Zusammenfassende Route
Schließlich liest ein Endpunkt den eingehenden Inhalt und liefert eine Live-Zusammenfassung, die vom Modell erstellt wird. Sie verwendet eine Streaming-Ausgabe, damit der Nutzer nicht warten muss, bis die vollständige Antwort generiert wurde.
@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")Bereitgestellt von
So funktioniert unser Summarizer:
Die Funktion empfängt die Datenanweisung POST nach dem Schema RequestData und erwartet ein Feld mit dem Namen content, das den Rohtext der Webseite enthält.
Eine verschachtelte stream() Generatorfunktion wird definiert, um nach und nach Nachrichten zu erzeugen. So kann Echtzeit-Feedback an das Frontend gesendet werden, bevor die endgültige Zusammenfassung fertig ist.
Die Nachrichtenliste enthält explizit einen Tag-Wrapper in der Benutzernachricht, um interne Überlegungen zu unterdrücken, und eine detaillierte Systemaufforderung verstärkt dieses Verhalten.
Der Qwen-Agent-Bot wird über bot.run(messages) aufgerufen, wobei messages eine Liste ist, die eine einzelne Benutzereingabe enthält.
Die Antworten des Modells werden gestreamt und in result_list gesammelt. Der Code durchläuft dann die Liste in umgekehrter Reihenfolge, um den letzten vom LLM zurückgegebenen Inhaltsstring zu extrahieren.
Qwens interne Argumentationsmarker wie und werden mithilfe einer Regex aus der Ausgabe entfernt, um die endgültige Zusammenfassung zu bereinigen.
Wenn kein gültiger Inhalt gefunden wird, wird eine Fallback-Nachricht gesendet. Andernfalls wird die bereinigte Zusammenfassung an das Frontend gestreamt.
Schritt 2: Erstellung der Chrome-Erweiterung
In diesem Abschnitt werden alle Dateien beschrieben, die für die Einrichtung der Erweiterung benötigt werden, einschließlich der Frontend-Benutzeroberfläche, der Logik zum Extrahieren von Seiteninhalten, der Skripte für die Hintergrundkommunikation und der Konfigurationsmetadaten.
Bevor wir uns die einzelnen Skripte ansehen, hier eine einfache Aufschlüsselung, was jede Datei tut:
manifest.json: Dies ist eine Konfigurationsdatei, die Metadaten, Berechtigungen und Skripte für die Erweiterung definiert.
popup.html: Dieses Skript definiert die sichtbare Benutzeroberfläche für das Popup der Chrome-Erweiterung mit einer Schaltfläche und einem Ausgabefeld.
popup.js: Sie übernimmt die Frontend-Logik, erfasst den Text der aktuellen Registerkarte und streamt die zusammenfassende Antwort an die Benutzeroberfläche.
content.js: Es extrahiert sichtbare Webseiteninhalte, wenn sie angefordert werden, und fungiert als Inhaltsskript.
background.js: Dieses Skript koordiniert die Backend-Kommunikation und leitet die gestreamten Zusammenfassungen an das Popup weiter.
icon.png: Dies ist ein Erweiterungssymbol, das in der Symbolleiste und im Erweiterungsmanager von Chrome angezeigt wird.
Zusammen machen diese Dateien die Erweiterung interaktiv und reaktiv und ermöglichen die Kommunikation mit einem lokalen Modellserver.
Schritt 1: Metadaten der Erweiterung
Das Skript manifest.json enthält Metadaten für Chrome. Sie definiert das Verhalten der Erweiterung, die Berechtigungen, den Hintergrunddienst Worker und die Popup-Benutzeroberfläche.
{"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"}]}Bereitgestellt von
Diese Datei definiert die Konfiguration und die Fähigkeiten deiner Chrome-Erweiterung. Sie gewährt wichtige Berechtigungen wie scripting (zum Einfügen von JavaScript), activeTab (für den Zugriff auf den aktuellen Tab) und storage (zum Speichern von Benutzereinstellungen).
Das host_permissions Feld mit "<all_urls>" ermöglicht es, dass die Erweiterung auf jeder Webseite läuft. Außerdem wird die Benutzeroberfläche der Erweiterung über popup.html und icon.png eingerichtet und das Hintergrundverhalten über einen Service Worker (background.js) registriert. Schließlich wird ein Inhaltsskript (content.js) definiert, das auf allen geladenen Seiten ausgeführt wird und bei Bedarf eine Interaktion mit dem Inhalt der Webseite ermöglicht.
Schritt 2: Aufbau einer sichtbaren Schnittstelle
Die popup.html definiert die sichtbare Schnittstelle der Erweiterung. Sie verbindet sich mit der aktiven Registerkarte, die den sichtbaren Text erfasst und an deinen Backend-Server sendet.
Ich bin Google Developers Expertin für ML (Gen AI), dreifache Kaggle-Expertin und Women-Techmakers-Botschafterin mit über drei Jahren Erfahrung in der Tech-Branche. 2020 habe ich ein Health-Tech-Startup mitgegründet und absolviere derzeit einen Master in Informatik an der Georgia Tech mit Schwerpunkt Machine Learning.
Lerne die wichtigsten Arten von KI-Agenten kennen, wie sie mit ihrer Umgebung interagieren und wie sie in verschiedenen Branchen eingesetzt werden. Verstehe einfache reflexive, modellbasierte, zielbasierte, nutzenbasierte, lernende Agenten und mehr.
Lerne mehr über Python-Lambda-Funktionen, wozu sie gut sind und wann man sie benutzt. Enthält praktische Beispiele und bewährte Methoden für eine effektive Umsetzung.
In diesem Blogpost zeige ich dir, wie du mit Qwen-Agent eine Browsererweiterung baust , die den Inhalt einer beliebigen Webseite in Echtzeit zusammenfasst. Wir zeigen dir, wie du:
Am Ende wirst du einen offline-fähigen Zusammenfassungs-Agenten haben, der von Qwen3 angetrieben wird und der Webseiten in deinem Browser mit einem einzigen Klick liest und zusammenfasst.
Wir halten unsere Leserinnen und Leser mit The Median auf dem Laufenden, unserem kostenlosen Freitags-Newsletter, der die wichtigsten Meldungen der Woche aufschlüsselt. Melde dich an und bleibe in nur ein paar Minuten pro Woche auf dem Laufenden:
Was ist Qwen-Agent?
Qwen-Agent ist ein leichtgewichtiges Python-Framework, das von Alibaba entwickelt wurde, um leistungsstarke LLM-Anwendungen mit der Qwen3 Familie von Modellen. Sie konzentriert sich auf die Unterstützung:
Im Kern vereinfacht Qwen-Agent die Entwicklung von modularen KI-Agenten mit robusten Argumentations- und Codeausführungsfunktionen. Sie enthält atomare Komponenten wie LLM-Wrapper und Tools sowie High-Level-Klassen
Agentfür die Orchestrierung von Arbeitsabläufen.Qwen-Agent funktioniert sowohl mit Cloud-basierten APIs (wie Alibaba DashScope) als auch mit lokalen OpenAI-kompatiblen Laufzeiten wie vLLM und Ollama. Es macht es einfach, leistungsstarke LLM-Apps zu erstellen:
Projektübersicht: Real-Time Web Summarizer Erweiterung
In diesem Abschnitt bauen wir eine Echtzeit-Zusammenfassungserweiterung auf Basis von Qwen-Agent. Dazu gehören:
Lass uns die einzelnen Teile dieses Projekts durchgehen.
Schritt 1: Einrichten des Qwen3 Backends
In diesem Schritt werden wir alle Codedateien behandeln, die wir einrichten müssen, damit unser Backend synchron mit unserer Erweiterung arbeitet.
Schritt 1.1: Abhängigkeiten und Bibliotheken
Beginne mit der Installation von ollama auf deinem System. Als Nächstes listest du alle Python-Abhängigkeiten auf, die für das Backend benötigt werden:
requirements.txt.. So kannst du sicherstellen, dass die Umgebung auf allen Rechnern und Containern einheitlich eingerichtet ist.Hier ist eine Aufschlüsselung, wofür jede Bibliothek verwendet wird:
qwen-agent[code_interpreter]: Dies ist ein Kernagenten-Framework mit Tool-Unterstützung, das die Ausführung von Code und strukturiertes Denken ermöglicht.fastapiunduvicorn: Diese Bibliotheken bilden zusammen das asynchrone API-Backend und bedienen deine Zusammenfassungslogik.python-dotenvundpython-dateutil: Diese Utility-Bibliotheken behandeln Umgebungsvariablen und die Verarbeitung von Datum und Uhrzeit (nützlich für zukünftige Skalierungen).matplotlib: Es wird zum Plotten oder Anzeigen von visuellen Ausgaben verwendet (optional).Wenn du dieses Projekt lokal ausführen möchtest, führe den folgenden Befehl aus, um alle Abhängigkeiten zu installieren:
Schritt 1.2: DockerFile einrichten (optional)
Jetzt richten wir ein Dockerfile ein, das eine minimale Python-Umgebung mit unserer App erstellt und Port 7864 freigibt, damit die Chrome-Erweiterung Anfragen an das FastAPI-Backend senden kann.
Diese Einrichtung ist optional, wenn du dich dafür entscheidest, das Projekt lokal mit Uvicorn statt mit Docker auszuführen.
Schritt 1.3: Qwen mit Ollama dienen
Als Nächstes musst du das Qwen3-Modell mit Ollama lokal abrufen und bereitstellen. Dieser Schritt ermöglicht Offline-Inferenz, indem der LLM-Dienst auf deinem Rechner gehostet wird.
Schritt 1.4: Aufbau des FastAPI-Zusammenfassungsservers
Die Datei
app.pydefiniert einen FastAPI-Server, der Zusammenfassungen von Webseiteninhalten in Echtzeit mit einem lokal laufenden Qwen3:1.7B-Modell über den Qwen-Agent streamt.Schritt 1.4.1: Importe
Beginne mit dem Import von FastAPI, Streaming-Dienstprogrammen und Qwen-Agent-Komponenten wie
Assistant, die das Modell und seine Werkzeugfähigkeiten umhüllen.Schritt 1.4.2: FastAPI App Initialisierung
Als Nächstes definieren wir ein einfaches
RequestDataSchema, um Inhalte zu empfangen, und erstellen eine Bot-Instanz vonAssistant.Im obigen Code ist
boteine Instanz der KlasseAssistantvon Qwen-Agent, die so konfiguriert ist, dass sie mit dem lokal bedienten Qwen3:1.7B-Modell über Ollama interagiert. Es nutzt das integrierte Toolcode_interpreter, um den Inhalt zu durchsuchen und bei Bedarf Python-Code auszuführen. Eine benutzerdefiniertesystem_messagesteuert das Verhalten, um prägnante Webseiten-Zusammenfassungen zu erstellen.Hinweis: Du kannst kleinere Modelle wie
qwen3:0.6boderqwen3:1.7bverwenden, um die Reaktionszeit und den Speicherverbrauch deutlich zu reduzieren. Dies ist besonders nützlich für schnellere Zusammenfassungsaufgaben ohne großen Denkaufwand.Schritt 1.4.3: Zusammenfassende Route
Schließlich liest ein Endpunkt den eingehenden Inhalt und liefert eine Live-Zusammenfassung, die vom Modell erstellt wird. Sie verwendet eine Streaming-Ausgabe, damit der Nutzer nicht warten muss, bis die vollständige Antwort generiert wurde.
So funktioniert unser Summarizer:
POSTnach dem SchemaRequestDataund erwartet ein Feld mit dem Namencontent, das den Rohtext der Webseite enthält.stream()Generatorfunktion wird definiert, um nach und nach Nachrichten zu erzeugen. So kann Echtzeit-Feedback an das Frontend gesendet werden, bevor die endgültige Zusammenfassung fertig ist.Tag-Wrapper in der Benutzernachricht, um interne Überlegungen zu unterdrücken, und eine detaillierte Systemaufforderung verstärkt dieses Verhalten.bot.run(messages)aufgerufen, wobeimessageseine Liste ist, die eine einzelne Benutzereingabe enthält.result_listgesammelt. Der Code durchläuft dann die Liste in umgekehrter Reihenfolge, um den letzten vom LLM zurückgegebenen Inhaltsstring zu extrahieren.undwerden mithilfe einer Regex aus der Ausgabe entfernt, um die endgültige Zusammenfassung zu bereinigen.Schritt 2: Erstellung der Chrome-Erweiterung
In diesem Abschnitt werden alle Dateien beschrieben, die für die Einrichtung der Erweiterung benötigt werden, einschließlich der Frontend-Benutzeroberfläche, der Logik zum Extrahieren von Seiteninhalten, der Skripte für die Hintergrundkommunikation und der Konfigurationsmetadaten.
Bevor wir uns die einzelnen Skripte ansehen, hier eine einfache Aufschlüsselung, was jede Datei tut:
manifest.json: Dies ist eine Konfigurationsdatei, die Metadaten, Berechtigungen und Skripte für die Erweiterung definiert.popup.html: Dieses Skript definiert die sichtbare Benutzeroberfläche für das Popup der Chrome-Erweiterung mit einer Schaltfläche und einem Ausgabefeld.popup.js: Sie übernimmt die Frontend-Logik, erfasst den Text der aktuellen Registerkarte und streamt die zusammenfassende Antwort an die Benutzeroberfläche.content.js: Es extrahiert sichtbare Webseiteninhalte, wenn sie angefordert werden, und fungiert als Inhaltsskript.background.js: Dieses Skript koordiniert die Backend-Kommunikation und leitet die gestreamten Zusammenfassungen an das Popup weiter.icon.png: Dies ist ein Erweiterungssymbol, das in der Symbolleiste und im Erweiterungsmanager von Chrome angezeigt wird.Zusammen machen diese Dateien die Erweiterung interaktiv und reaktiv und ermöglichen die Kommunikation mit einem lokalen Modellserver.
Schritt 1: Metadaten der Erweiterung
Das Skript
manifest.jsonenthält Metadaten für Chrome. Sie definiert das Verhalten der Erweiterung, die Berechtigungen, den Hintergrunddienst Worker und die Popup-Benutzeroberfläche.Diese Datei definiert die Konfiguration und die Fähigkeiten deiner Chrome-Erweiterung. Sie gewährt wichtige Berechtigungen wie
scripting(zum Einfügen von JavaScript),activeTab(für den Zugriff auf den aktuellen Tab) undstorage(zum Speichern von Benutzereinstellungen).Das
host_permissionsFeld mit "<all_urls>" ermöglicht es, dass die Erweiterung auf jeder Webseite läuft. Außerdem wird die Benutzeroberfläche der Erweiterung überpopup.htmlundicon.pngeingerichtet und das Hintergrundverhalten über einen Service Worker (background.js) registriert. Schließlich wird ein Inhaltsskript (content.js) definiert, das auf allen geladenen Seiten ausgeführt wird und bei Bedarf eine Interaktion mit dem Inhalt der Webseite ermöglicht.Schritt 2: Aufbau einer sichtbaren Schnittstelle
Die
popup.htmldefiniert die sichtbare Schnittstelle der Erweiterung. Sie verbindet sich mit der aktiven Registerkarte, die den sichtbaren Text erfasst und an deinen Backend-Server sendet.Lass uns den obigen Code Schritt für Schritt verstehen:
-Tag ein, der Meta-Tags für die Zeichenkodierung, Viewport-Einstellungen und ein