Kursus
Dalam tulisan blog ini, saya akan memandu Anda membangun ekstensi peramban bertenaga Qwen-Agent yang meringkas konten halaman web apa pun secara waktu nyata. Kita akan membahas cara:
- Menggunakan model Qwen3 dari Alibaba secara lokal melalui Ollama
- Menggunakan Qwen-Agent untuk pemicu terstruktur dan penggunaan alat
- Membangun ekstensi Chrome dengan pembaruan UI streaming
- Menambahkan backend FastAPI untuk mendukung peringkasan waktu nyata
Pada akhirnya, Anda akan memiliki agen peringkas yang bisa offline, didukung oleh Qwen3, yang membaca dan meringkas halaman web di peramban Anda hanya dengan satu klik.
Kami menjaga pembaca tetap terbarui tentang hal terbaru di AI melalui The Median, buletin gratis setiap Jumat yang merangkum kisah-kisah kunci pekan ini. Berlangganan dan tetap tajam hanya dalam beberapa menit setiap minggu:
Apa itu Qwen-Agent?
Qwen-Agent adalah kerangka kerja Python ringan yang dibuat oleh Alibaba untuk mengembangkan aplikasi LLM yang andal menggunakan keluarga model Qwen3. Fokusnya adalah mendukung:
- Agen yang mengikuti instruksi
- Penggunaan alat dan pemanggilan fungsi
- Memori dan perencanaan multi-putaran
- Pemicu fleksibel melalui pesan terstruktur
Pada intinya, Qwen-Agent menyederhanakan pengembangan agen AI modular dengan kemampuan penalaran dan eksekusi kode yang kuat. Ini mencakup komponen atomik seperti pembungkus LLM dan alat, serta kelas tingkat tinggi Agent untuk mengorkestrasi alur kerja.
Qwen-Agent bekerja dengan API berbasis cloud (seperti Alibaba DashScope) dan runtime lokal yang kompatibel dengan OpenAI seperti vLLM dan Ollama. Ini memudahkan pembangunan aplikasi LLM yang andal dengan:
- Integrasi cepat melalui FastAPI
- Streaming bawaan untuk UI frontend
- Rantai alat fungsi yang dapat disesuaikan
- Privasi dan performa sepenuhnya offline
Gambaran Proyek: Ekstensi Peringkas Web Waktu Nyata
Di bagian ini, kita akan membangun ekstensi peringkas waktu nyata yang didukung oleh Qwen-Agent. Ini mencakup:
- Backend FastAPI yang menerima teks halaman web dan mengembalikan ringkasan
- Pop-up ekstensi Chrome untuk menangkap konten halaman yang terlihat
- UI streaming saat ringkasan dihasilkan
- Backend didukung oleh Qwen3:1.7B yang berjalan secara lokal melalui Ollama
Mari kita telusuri setiap bagian proyek ini.
Langkah 1: Menyiapkan Backend Qwen3
Pada langkah ini, kita akan membahas semua berkas kode yang perlu kita siapkan agar backend dapat bekerja sinkron dengan ekstensi kita.
Langkah 1.1: Dependensi dan pustaka
Mulailah dengan memasang ollama di sistem Anda. Selanjutnya, daftar semua dependensi Python yang diperlukan untuk backend dalam requirements.txt. Ini membantu memastikan penyiapan lingkungan yang konsisten di berbagai mesin dan kontainer.
fastapi
uvicorn
python-dateutil
python-dotenv
qwen-agent[code_interpreter]
matplotlib
Berikut penjelasan singkat penggunaan masing-masing pustaka:
qwen-agent[code_interpreter]: Kerangka kerja agen inti dengan dukungan penggunaan alat, memungkinkan eksekusi kode dan penalaran terstruktur.fastapidanuvicorn: Keduanya menggerakkan backend API asinkron dan menyajikan logika peringkas Anda.python-dotenvdanpython-dateutil: Pustaka utilitas untuk menangani variabel lingkungan dan pemrosesan tanggal/waktu (berguna untuk skala di masa mendatang).matplotlib: Digunakan untuk membuat plot atau menampilkan keluaran visual (opsional)
Jika Anda ingin menjalankan proyek ini secara lokal, jalankan perintah berikut untuk memasang semua dependensi:
pip install -r requirements.txt
Langkah 1.2: Penyiapan DockerFile (opsional)
Sekarang, mari siapkan Dockerfile yang membuat lingkungan Python minimal dengan aplikasi kita dan membuka port 7864, sehingga ekstensi Chrome dapat mengirim permintaan ke 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"]
Penyiapan ini bersifat opsional jika Anda memilih menjalankan proyek secara lokal menggunakan Uvicorn alih-alih Docker.
Langkah 1.3: Menyajikan Qwen dengan Ollama
Selanjutnya, Anda perlu menarik dan menyajikan model Qwen3 secara lokal menggunakan Ollama. Langkah ini memungkinkan inferensi offline dengan menjadi host layanan LLM di mesin Anda.
ollama pull qwen3:1.7b
ollama serve
Langkah 1.4: Membangun server peringkasan FastAPI
Berkas app.py mendefinisikan server FastAPI yang melakukan streaming ringkasan konten halaman web secara waktu nyata menggunakan model Qwen3:1.7B yang berjalan lokal melalui Qwen-Agent.
Langkah 1.4.1: Impor
Mulailah dengan mengimpor FastAPI, utilitas streaming, dan komponen Qwen-Agent seperti Assistant, yang membungkus model dan kemampuan alatnya.
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
Langkah 1.4.2: Inisialisasi Aplikasi FastAPI
Selanjutnya, kita mendefinisikan skema RequestData sederhana untuk menerima konten, dan membuat instance bot dari 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."
)
Pada kode di atas, bot adalah instance kelas Assistant dari Qwen-Agent, dikonfigurasi untuk berinteraksi dengan model Qwen3:1.7B yang dilayani secara lokal melalui Ollama. Bot menggunakan alat bawaan code_interpreter untuk menalar konten dan mengeksekusi kode Python bila diperlukan. Sebuah system_message kustom membimbing perilakunya untuk menghasilkan ringkasan halaman web yang ringkas.
Catatan: Anda dapat menggunakan model yang lebih kecil seperti qwen3:0.6b atau qwen3:1.7b untuk secara signifikan mengurangi waktu respons dan penggunaan memori. Ini sangat berguna untuk tugas peringkasan yang lebih cepat tanpa banyak beban penalaran.
Langkah 1.4.3: Rute peringkas
Terakhir, sebuah endpoint membaca konten yang masuk dan mengirimkan teks ringkasan secara langsung saat dihasilkan oleh model. Ini menggunakan keluaran streaming sehingga pengguna tidak perlu menunggu hingga seluruh respons selesai dibuat.
@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")
Begini cara kerja peringkas kita:
- Fungsi menerima instruksi data
POSTmenggunakan skemaRequestData, yang mengharapkan field bernamacontentyang menampung teks mentah halaman web. - Sebuah fungsi generator bersarang
stream()didefinisikan untuk mengirim pesan secara progresif. Ini memungkinkan umpan balik waktu nyata dikirim kembali ke frontend sebelum ringkasan akhir selesai. - Daftar pesan secara eksplisit menyertakan pembungkus tag
</nothink>dalam pesan pengguna untuk menekan penalaran internal, dan prompt sistem terperinci memperkuat perilaku ini. - Bot Qwen-Agent dipanggil menggunakan
bot.run(messages)di manamessagesadalah daftar yang berisi satu pesan masukan pengguna. - Respons model di-stream dan dikumpulkan ke dalam
result_list. Kode kemudian melakukan loop melalui daftar secara terbalik untuk mengekstrak string konten terbaru yang dikembalikan oleh LLM. - Penanda penalaran internal Qwen seperti
<think>dan</think>dihapus dari output menggunakan regex untuk membersihkan ringkasan akhir. - Jika tidak ada konten yang valid ditemukan, pesan fallback dikirim. Jika ada, ringkasan yang telah dibersihkan di-stream ke frontend.
Langkah 2: Membangun Ekstensi Chrome
Bagian ini menjabarkan semua berkas yang diperlukan untuk menyiapkan ekstensi, termasuk UI frontend, logika untuk mengekstrak konten halaman, skrip komunikasi latar belakang, dan metadata konfigurasi.
Sebelum melihat skrip-skripnya satu per satu, berikut ringkasan sederhana fungsi tiap berkas:
manifest.json: Berkas konfigurasi yang mendefinisikan metadata, izin, dan skrip ekstensi.popup.html: Skrip yang mendefinisikan UI yang terlihat untuk pop-up ekstensi Chrome dengan tombol dan panel keluaran.popup.js: Menangani logika frontend dan menangkap teks tab saat ini serta men-stream respons ringkasan ke UI.content.js: Menarik konten halaman web yang terlihat saat diminta, bertindak sebagai skrip konten.background.js: Mengoordinasikan komunikasi backend dan meneruskan ringkasan yang di-stream ke pop-up.icon.png: Ikon ekstensi yang ditampilkan di bilah alat Chrome dan pengelola ekstensi.
Bersama-sama, berkas-berkas ini membuat ekstensi menjadi interaktif, reaktif, dan mampu berkomunikasi dengan server model lokal.
Langkah 1: Metadata ekstensi
Skrip manifest.json berisi metadata untuk Chrome. Ini mendefinisikan perilaku ekstensi, izin, service worker latar belakang, dan UI pop-up.
{
"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"
}
]
}
Berkas ini mendefinisikan konfigurasi dan kapabilitas ekstensi Chrome Anda. Ini memberikan izin penting seperti scripting (untuk menyuntikkan JavaScript), activeTab (untuk mengakses tab saat ini), dan storage (untuk menyimpan preferensi pengguna).
Field host_permissions dengan "<all_urls>" memungkinkan ekstensi berjalan di halaman web mana pun. Ini juga menyiapkan UI ekstensi melalui popup.html dan icon.png, serta mendaftarkan perilaku latar belakang menggunakan service worker (background.js). Terakhir, ini mendefinisikan skrip konten (content.js) untuk dijalankan pada semua halaman yang dimuat, memungkinkan interaksi dengan konten halaman web saat diperlukan.
Langkah 2: Membangun antarmuka yang terlihat
Berkas popup.html mendefinisikan antarmuka yang terlihat dari ekstensi. Ini terhubung ke tab aktif yang menangkap teks yang terlihat dan mengirimkannya ke server backend Anda.
<!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>
Mari pahami kode di atas selangkah demi selangkah:
- Pertama, kita menyiapkan struktur HTML dasar dengan tag
<head>yang mencakup meta tag untuk pengodean karakter, pengaturan viewport, dan tag<title>. - Lalu, di dalam tag
<body>, sebuah container menampung semua elemen UI, termasuk:
- Heading
<h2>yang meminta pengguna untuk meringkas halaman saat ini. - Tombol
Summarize(“#summarizeBtn”) yang diklik pengguna untuk memicu ekstraksi konten dan peringkasan. - Elemen
<pre>(“#output”) yang berfungsi sebagai panel gulir untuk menampilkan ringkasan saat di-stream.
- Gaya ditentukan menggunakan CSS tersemat untuk membuat pop-up bersih dan mudah dibaca. Blok
predigunakan agar keluaran dapat digulir dan tampak jelas. - Skrip
popup.jsmendengarkan klik tombol, mengekstrak konten halaman, mengirimkannya ke backend FastAPI, dan memperbarui panel output dengan teks ringkasan yang di-stream.
Langkah 3: Membangun UI frontend
Berkas popup.js bertindak sebagai pengendali logika frontend yang merespons klik tombol, mengekstrak teks dari tab saat ini, mengirimkannya ke backend, dan men-stream ringkasan kembali ke area output secara waktu nyata.
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;
}
}
);
});
});
Berkas JavaScript ini menggerakkan logika UI frontend dari ekstensi Chrome, memungkinkan pengguna mengekstrak dan meringkas konten halaman web dengan sekali klik.
Begini cara kerjanya:
- Saat pop-up dimuat (
DOMContentLoaded), pendengar peristiwa dipasang pada tombol "Summarize". - Saat tombol diklik, ekstensi menanyakan tab yang saat ini aktif menggunakan
chrome.tabs.query. - Kemudian menjalankan skrip konten di dalam tab tersebut menggunakan
chrome.scripting.executeScript, yang mencoba mengekstrakinnerTextdari body halaman. - Jika skrip gagal atau mengembalikan konten kosong, pesan fallback yang sesuai ditampilkan di UI.
- Jika teks berhasil diekstrak, teks tersebut dikirim sebagai permintaan POST ke backend FastAPI lokal di
http://127.0.0.1:7864/summarize_stream_status. - Respons di-stream menggunakan
res.body.getReader(), yang memungkinkan potongan ringkasan muncul secara waktu nyata di panel output. - Sebuah
TextDecodermendekode setiap potongan teks yang di-stream, menambahkannya secara langsung ke tampilan. - Kesalahan jaringan atau backend akan ditangkap dan ditampilkan di antarmuka pop-up untuk debugging atau umpan balik pengguna.
Langkah 4: Mengekstrak konten halaman web
Sebelum kita dapat mengirim konten halaman web ke backend, kita memerlukan cara untuk mengekstraknya dari tab saat ini. Skrip content.js mendengarkan pesan dari skrip latar belakang atau pop-up dan mengembalikan teks konten yang terlihat dari halaman web.
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.type === "GET_PAGE_TEXT") {
const bodyText = document.body.innerText.trim();
sendResponse({ text: bodyText || null });
}
});
Skrip ini mendengarkan pesan bertipe "GET_PAGE_TEXT" dan merespons dengan mengekstrak serta mengembalikan teks body yang terlihat (document.body.innerText). Ini memungkinkan worker latar belakang dengan mudah meminta konten halaman web tanpa menyuntikkan kode setiap kali, menjaga komunikasi tetap bersih dan asinkron.
Langkah 5: Koordinasi backend
Skrip latar belakang (background.js) menjembatani UI pop-up dan skrip konten. Ini memastikan pengiriman pesan dan koordinasi peringkasan berlangsung dengan benar di belakang layar.
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;
}
});
Kode di atas memastikan alur ekstraksi konten, peringkasan, dan pembaruan waktu nyata berjalan mulus. Berikut penjelasan langkah demi langkah cara kerjanya:
- Mendengarkan pesan bertipe "SUMMARIZE_PAGE" yang dipicu oleh klik tombol di pop-up.
- Setelah dipicu, ini mengidentifikasi tab aktif menggunakan
sender.tab.iddan menjalankan skrip yang disuntikkan melaluichrome.scripting.executeScriptuntuk mengekstrak teks yang terlihat dari halaman web. - Jika konten tidak dapat diakses atau kosong, pesan fallback dikirim kembali.
- Jika tidak, ia mengambil
database_host(biasanya127.0.0.1) dari penyimpanan lokal Chrome dan menggunakannya untuk mengirim permintaanPOSTke backend FastAPI dengan konten yang diekstrak. - Lalu, membuka koneksi streaming dan membaca respons sedikit demi sedikit menggunakan
ReadableStreamDefaultReader. - Saat setiap potongan didekode, ia mengirim pembaruan sementara ke pop-up menggunakan
chrome.runtime.sendMessagedengan tipe 'SUMMARY_PROGRESS'. - Setelah stream berakhir, ia mengirim pesan akhir dengan ringkasan lengkap. Jika terjadi kesalahan selama proses, pesan fallback dikirim sebagai gantinya.
Skrip latar belakang ini penting untuk memungkinkan ringkasan streaming secara waktu nyata di ekstensi Chrome tanpa menghambat UI atau memuat ulang halaman.
Langkah 6: Menambahkan ikon ekstensi
Pilih atau gambar ikon untuk ekstensi dan simpan sebagai icon.png di dalam folder ekstensi. Ini yang akan kita gunakan:

Gambar dibuat dengan FireFly
Struktur folder keseluruhan Anda seharusnya terlihat seperti ini:
QWEN-WEB-SUMMARIZER/
├── backend/
│ ├── app.py
│ ├── Dockerfile
│ └── requirements.txt
├── extension/
│ ├── background.js
│ ├── content.js
│ ├── icon.png
│ ├── manifest.json
│ ├── popup.html
│ └── popup.js
Langkah 3: Menjalankan Aplikasi
Untuk menjalankan semuanya secara lokal, jalankan perintah berikut di terminal:
uvicorn backend.app:app --host 0.0.0.0 --port 7864
Ini ideal untuk pengembangan atau debugging lokal tanpa Docker. Untuk menjalankan di Docker, jalankan perintah berikut satu per satu di terminal Anda:
docker build -t qwen-agent-backend .
docker run -p 7864:7864 qwen-agent-backend
Ekstensi Chrome berkomunikasi melalui port 7864. Sekarang, ikuti langkah-langkah berikut untuk menjalankan ekstensi Anda di Chrome:
- Buka Chrome dan klik “Extensions” (di sisi kanan bilah pencarian).
- Aktifkan “Developer mode” dan klik “Load unpacked” (pojok kiri atas).

- Selanjutnya, muat folder ekstensi kita yang berisi semua berkas dan tunggu konfirmasi.
- Setelah pop-up mengonfirmasi penyiapan ekstensi, klik ikon ekstensi di halaman web mana pun dan dapatkan ringkasan streaming menggunakan model Qwen3 lokal Anda.
Mari kita lihat hasilnya:

Kesimpulan
Dalam proyek ini, kita membangun asisten peringkas halaman web waktu nyata menggunakan kerangka kerja Qwen-Agent dan model Qwen3:1.7B yang berjalan secara lokal melalui Ollama. Kita mengembangkan backend FastAPI untuk menangani inferensi LLM dan mengintegrasikannya dengan ekstensi Chrome yang menangkap konten halaman yang terlihat dan menampilkan ringkasan yang di-stream langsung.
Demo ini menunjukkan bagaimana Qwen-Agent dapat memungkinkan alur kerja penalaran yang ditambah alat sepenuhnya offline di peramban. Ini menjadi landasan untuk membangun agen lokal yang lebih canggih seperti alat otomatisasi peramban, copilot riset, atau chatbot berbasis dokumen.
Untuk mempelajari lebih lanjut tentang agen AI, lihat blog berikut:
Saya adalah Google Developers Expert di ML (Gen AI), Kaggle 3x Expert, dan Women Techmakers Ambassador dengan pengalaman lebih dari 3 tahun di bidang teknologi. Saya ikut mendirikan startup health-tech pada 2020 dan sedang menempuh studi magister ilmu komputer di Georgia Tech dengan spesialisasi machine learning.

