Google Workspace CLI: Bangun Asisten RAG di Atas File Drive Anda
Pelajari cara memasang CLI AI-optimized baru dari Google, melakukan autentikasi, dan menghubungkannya ke pipeline RAG bertenaga Gemini yang menjawab pertanyaan tentang file Drive Anda sendiri.
Google baru saja merilis sesuatu yang benar-benar menarik bagi developer. Sebuah antarmuka baris perintah Google Workspace yang memberi Anda akses terstruktur dan dapat diskrip ke seluruh Google Workspace Anda termasuk Drive, Gmail, Kalender, Sheets, Docs, Chat, dan lainnya dalam satu alat.
Codebase-nya hampir seluruhnya Rust (99,3%), tetapi didistribusikan melalui npm sebagai binary native pra-bangun, jadi Anda tidak perlu memasang toolchain Rust.
Dalam tutorial ini, Anda akan menyiapkan Google Workspace CLI dari nol, melakukan autentikasi, dan membangun asisten RAG bertenaga Gemini yang memungkinkan Anda menanyakan file Drive dalam bahasa alami. Di akhir, Anda akan memiliki:
gws terpasang dan diautentikasi terhadap Drive Anda
Lingkungan virtual Python dengan ChromaDB, Sentence Transformers, dan Gemini SDK
Pipeline RAG lokal yang berfungsi yang mengambil file melalui gws, melakukan embedding dengan model lokal, dan melakukan streaming jawaban dengan Gemini 2.5 Flash
Catatan: Ini bukan produk Google yang didukung secara resmi.
Apa Itu Google Workspace CLI?
Google Workspace CLI (gws) adalah alat baris perintah yang dioptimalkan untuk AI bagi seluruh ekosistem Google Workspace Anda. Berikut yang membuatnya menonjol:
Penemuan perintah dinamis: Alih-alih mengirimkan pohon perintah yang di-hardcode, gws membaca Discovery Service Google saat runtime. Saat Google menambahkan endpoint API baru, CLI akan menangkapnya secara otomatis tanpa peningkatan versi.
Desain agent-native: CLI dilengkapi 100+ skill agent bawaan dan 50 resep terkurasi untuk alur kerja umum yang meringkas email, memindahkan file Drive, membuat event kalender, dan banyak lagi. Setiap output berupa JSON terstruktur, sehingga LLM dapat mengonsumsinya langsung.
Dukungan server MCP native: Jalankan gws sebagai server MCP lokal dan berikan agen AI Anda akses penuh ke alat Workspace tanpa menulis satu pun klien API.
Integrasi Model Armor: Untuk agen produksi yang membaca konten yang dikendalikan pengguna, Anda dapat menyalurkan respons API melalui Google Cloud Model Armor untuk mensterilkan dari prompt injection sebelum dilihat LLM Anda.
Berikan nama dan catat Project ID yang dibuat otomatis yang akan kita gunakan di langkah berikutnya
Siapkan kredensial OAuth:
Masuk ke APIs & Services dan pilih Credentials
Klik Create Credentials dan masuk ke OAuth 2.0 Client ID
Pilih Desktop app sebagai jenis aplikasi
Catat Client ID dan Client Secret yang akan kita gunakan untuk gws auth setup.
CLI menyelesaikan OAuth dengan menyalakan server localhost sementara. Klien Desktop app menangani port localhost apa pun secara otomatis. Klien Web application mengharuskan Anda menambahkan setiap http://localhost:PORT secara manual ke daftar authorized redirect URIs.
Jika Anda menggunakan klien Web application dan menemui "Access blocked: This app's request is invalid", buka Credentials lalu klik OAuth client diikuti Authorized redirect URIs dan tambahkan URL http://localhost:PORT persis seperti yang ditampilkan pada error.
Langkah 3: Lakukan autentikasi
Untuk menghubungkan gws ke proyek GCP Anda, pertama ekspor kredensial OAuth Anda sebagai variabel lingkungan agar wizard penyiapan dapat mengambilnya secara otomatis:
exportGOOGLE_WORKSPACE_CLI_CLIENT_ID="CLIENT_ID"exportGOOGLE_WORKSPACE_CLI_CLIENT_SECRET="CLIENT_SECRET"Didukung oleh
Lalu jalankan:
gws auth setup --project YOUR_PROJECT_ID --loginDidukung oleh
Wizard penyiapan akan:
Menanyakan akun Google mana yang ingin Anda gunakan
Membuka browser untuk alur persetujuan OAuth Google standar
Menanyakan scope mana (seperti Drive, Gmail, Kalender, dll.) yang akan diotorisasi
Setelah selesai, Anda akan melihat: Setup complete!
Kredensial disimpan di ~/.config/gws/. Untuk mengonfirmasi semuanya terhubung dengan benar, jalankan:
Perintah ini mencetak akun yang diautentikasi, proyek GCP yang ditautkan, dan scope aktif. Jika ada yang terlihat salah, jalankan kembali gws auth setup dengan flag yang benar alih-alih mencoba mengedit file konfigurasi secara manual.
Langkah 4: Uji akses Drive
Sebelum menulis Python, ada baiknya melakukan pemeriksaan cepat langsung dari terminal untuk mengonfirmasi CLI telah diautentikasi dan dapat berkomunikasi dengan Drive Anda. Mari jalankan perintah berikut untuk mencantumkan lima file Drive terbaru Anda:
gws drive files list --params'{"pageSize": 5}'Didukung oleh
Flag --params menerima string JSON yang dipetakan langsung ke parameter kueri API Drive. Di sini, pageSize: 5 membatasi respons menjadi lima hasil yang cukup untuk mengonfirmasi konektivitas tanpa menampilkan seluruh Drive Anda.
Jika autentikasi berfungsi dengan benar, Anda akan menerima respons JSON terstruktur seperti ini:
{"files":[{"id":"1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms","name":"Q3 Strategy Doc","mimeType":"application/vnd.google-apps.document"},
...
]}Didukung oleh
Setiap respons dari gws adalah JSON terstruktur tanpa parsing, tanpa scraping, tanpa keluaran teks rapuh.
Jika Anda malah melihat “403 error” yang menyebut serviceusage.services.use, itu berarti kredensial OAuth Anda diarahkan ke proyek GCP yang berbeda dari yang memiliki penagihan diaktifkan. Jalankan kembali penyiapan dengan project ID yang benar untuk menautkan semuanya kembali:
gws auth setup --project YOUR_PROJECT_ID --loginDidukung oleh
Dengan akses Drive terkonfirmasi, kita siap mengaktifkan API dan mulai membangun sisi Python dari pipeline.
Langkah 5: Aktifkan Google Drive API
Pada titik ini, gws dapat melakukan autentikasi terhadap proyek GCP Anda, tetapi belum bisa membaca konten file Drive. GCP memisahkan autentikasi (membuktikan siapa Anda) dari aktivasi API (menyatakan layanan mana yang digunakan proyek Anda). Bahkan dengan kredensial OAuth yang valid, upaya mengambil konten file akan mengembalikan error 403 accessNotConfigured sampai Drive API diaktifkan secara eksplisit pada proyek.
Untuk mengaktifkannya, buka URL ini di browser dan ganti [PROJECT_ID] dengan project ID Anda yang sebenarnya lalu klik Enable:
Sebagai alternatif, jika Anda memasang CLI gcloud, Anda dapat mengaktifkannya langsung dari terminal:
gcloud services enable drive.googleapis.com --project YOUR_PROJECT_IDDidukung oleh
Kedua metode melakukan hal yang sama. Menjalankan salah satunya pada API yang sudah diaktifkan aman karena operasinya idempoten dan tidak akan mengatur ulang konfigurasi yang ada.
Setelah diaktifkan, GCP mungkin memerlukan beberapa detik untuk mempropagasi perubahan. Jika Anda langsung menjalankan gws drive files list dan masih melihat 403, tunggu 30 detik dan coba lagi.
Langkah 6: Pasang dependensi
Dengan sisi CLI sepenuhnya dikonfigurasi, kini kita dapat menyiapkan lingkungan Python yang menangani logika embedding dan retrieval. Pipeline RAG sengaja dibuat ringan dengan empat paket, tanpa memerlukan GPU, dan seluruh embedding terjadi secara lokal di mesin Anda.
Mulailah dengan membuat lingkungan virtual dengan menjalankan perintah berikut satu per satu:
cd /path/to/your/project
python3 -m venv .venv
source .venv/bin/activate
python -m pip install--upgrade pip
pip install-r requirements.txtDidukung oleh
Lalu pasang dependensi dari requirements.txt:
.txt
chromadb==1.5.5
google-genai==1.70.0
langchain-text-splitters==1.1.1
sentence-transformers==5.3.0Didukung oleh
Berikut kontribusi tiap paket pada pipeline:
chromadb: Basis data vektor lokal yang menyimpan embedding dokumen ke ./chroma_db di disk dan memuatnya pada run berikutnya, sehingga aplikasi tidak perlu melakukan embedding ulang file yang sudah diproses.
google-genai: SDK Python resmi untuk Gemini. Aplikasi menggunakannya untuk mengirim konteks yang diambil dan pertanyaan pengguna ke Gemini 2.5 Flash, dengan streaming respons kembali token demi token.
langchain-text-splitters: Paket ini menyediakan RecursiveCharacterTextSplitter, yang memecah dokumen besar menjadi potongan tumpang-tindih sebelum embedding. Overlap memastikan kalimat di batas potongan tidak terputus dari konteksnya.
sentence-transformers: Sentence Transformers menjalankan model embedding secara lokal melalui DefaultEmbeddingFunction milik ChromaDB. Jadi, setiap potongan dokumen di-embed di mesin tanpa panggilan API eksternal.
Catatan: Model embedding (~90MB) diunduh otomatis saat pertama kali digunakan dan di-cache secara lokal.
Dengan lingkungan Python siap, bagian terakhir sebelum menulis kode adalah mendapatkan kunci API Gemini.
Langkah 7: Siapkan Kunci API Gemini
Pipeline RAG menggunakan Gemini sebagai lapisan pembangkitan jawaban karena mengambil potongan dokumen yang diambil dan pertanyaan pengguna, lalu melakukan streaming respons yang terlandas. Untuk terhubung ke Gemini, Anda memerlukan kunci API dari Google AI Studio.
Masuk dengan akun Google Anda, klik Get API Key, lalu pilih Create API Key. Pilih proyek GCP Anda saat diminta agar kuota dan penagihan tercatat. Tautkan akun penagihan di dasbor GCP di bawah Billing lalu pilih Link a billing account.
Setelah Anda memiliki kunci, ekspor sebagai variabel lingkungan:
Ekspor kunci di terminal Anda:
exportGEMINI_API_KEY="YOUR_GEMINI_API_KEY"Didukung oleh
Untuk mempertahankannya antar sesi terminal, jalankan:
echo'export GEMINI_API_KEY="YOUR_GEMINI_API_KEY"'>> ~/.zshrc
source ~/.zshrcDidukung oleh
Aplikasi membaca kunci ini melalui os.getenv("GEMINI_API_KEY") saat startup. Jika variabel tidak disetel, aplikasi akan meminta Anda menempelkan kunci secara interaktif.
Catatan model: Aplikasi menggunakan default gemini-2.5-flash. Anda dapat menimpanya dengan mengekspor GEMINI_MODEL="gemini-2.5-pro" jika menginginkan penalaran yang lebih kuat pada dokumen kompleks. Perlu dicatat bahwa gemini-2.0-flash telah dihentikan untuk kunci API baru, jadi jangan gunakan di sini.
Dengan autentikasi, Drive API, dependensi, dan kunci Gemini siap, kita memiliki semua yang diperlukan. Mari bangun pipeline-nya.
Langkah 8: Bangun Pipeline RAG
Sekarang mari hubungkan semuanya. Kita akan bekerja dengan empat file, termasuk fetcher.py, vector_store.py, main.py, dan requirements.txt. Setiap file punya satu tanggung jawab, seperti fetcher.py menangani semua interaksi CLI, vector_store.py mengelola embedding dan retrieval, dan main.py mengorkestrasi loop penuh dari ingestion hingga streaming chat.
Pada run pertama, gws mengambil file Drive Anda, konten dipecah dan di-embed secara lokal, dan indeks vektor ditulis ke ./chroma_db di disk. Pada run berikutnya, ChromaDB memuat dari disk, hanya file baru yang diambil dan di-embed, dan loop chat segera dimulai tanpa memproses ulang apa pun.
Mari kita ulas setiap file.
Langkah 8.1: fetcher.py — Akses Drive via gws
Modul ini adalah jembatan antara CLI gws dan Python. Semua interaksi Drive seperti mencantumkan file, mengekspor konten, dan memeriksa autentikasi dilakukan melalui pemanggilan subprocess ke gws, dan output JSON terstruktur diurai menjadi dict Python. Hasilnya, kode Python tidak pernah perlu berurusan langsung dengan token OAuth, klien HTTP, atau skema respons API; gws menangani semua itu dan mengembalikan JSON yang bersih.
def_gws_json_stdout(stdout:str)->str:ifnot stdout or"{"notin stdout:return stdout or""return stdout[stdout.find("{"):]Didukung oleh
Helper _gws_json_stdout menangani masalah halus saat gws kadang memunculkan baris keyring atau logging sebelum payload JSON. Di sini, memanggil json.loads(result.stdout) secara langsung akan gagal sehingga fungsi ini memotong semuanya sebelum { pertama.
defcheck_auth()->bool:
cmd =["gws","drive","about","get","--params",'{"fields": "user"}']
result = subprocess.run(cmd, capture_output=True, text=True)
payload = _gws_json_stdout(result.stdout)try:
data = json.loads(payload)if payload.strip()else{}except json.JSONDecodeError:print("Error checking authentication status (could not parse gws output).")returnFalseif"error"in data or result.returncode !=0:
handle_error_output(result.stdout, result.stderr)returnFalsereturnTrueDidukung oleh
Fungsi check_auth() dipanggil saat startup di main.py yang membuat panggilan API Drive ringan dan memeriksa respons. Jika autentikasi bermasalah atau scope kurang, aplikasi keluar dengan rapi sebelum mencoba ingestion.
Handler error juga menangkap mode kegagalan spesifik dan mencetak pesan yang dapat ditindaklanjuti:
Pengambil daftar dokumen menargetkan hanya tipe MIME yang dapat diekspor sebagai teks:
deffetch_document_list(limit=10)->list[dict]:
q =("(mimeType='text/plain' or mimeType='application/vnd.google-apps.document' ""or mimeType='application/vnd.google-apps.spreadsheet') and trashed=false")
cmd =["gws","drive","files","list","--params",
json.dumps({"q": q,"pageSize": limit,"orderBy":"modifiedTime desc"}),]Didukung oleh
Kueri memfilter ke teks biasa, Google Docs, dan Google Sheets, masing-masing diurutkan berdasarkan yang terakhir dimodifikasi. File biner (PDF, gambar) dikecualikan karena tidak dapat diekspor sebagai teks dengan pendekatan ini.
Namun, pengunduhan ditangani berbeda per tipe MIME:
gws menulis byte file yang diekspor ke disk melalui -o, bukan ke stdout. Stdout membawa metadata JSON. Kode menggunakan file sementara untuk menangkap output biner, membacanya, dan membersihkan di blok finally, sehingga file sementara selalu dihapus bahkan saat error.
Langkah 8.2: vector_store.py — Embedding lokal dengan ChromaDB
Modul ini memecah teks yang masuk, menghasilkan embedding secara lokal menggunakan Sentence Transformers, menyimpannya ke disk melalui ChromaDB, dan mengekspos metode query() sederhana yang dipanggil loop chat untuk setiap pertanyaan pengguna.
PersistentClient menulis indeks vektor ke ./chroma_db dan memuatnya pada run berikutnya tanpa perlu ingestion ulang kecuali Anda menghapus direktori tersebut. DefaultEmbeddingFunction menggunakan Sentence Transformers secara lokal, sementara embedding dihitung di mesin Anda dengan biaya marginal nol.
Splitter menggunakan chunk_size=1000 dengan chunk_overlap=200, sehingga overlap memastikan konteks di batas potongan tidak hilang saat kalimat terbelah di dua potongan.
defadd_document(self, file_id:str, filename:str, text:str):
chunks = self.text_splitter.split_text(text)
ids =[f"{file_id}_{i}"for i inrange(len(chunks))]
metadatas =[{"source": filename,"file_id": file_id}for _ in chunks]
self.collection.upsert(documents=chunks, metadatas=metadatas, ids=ids)print(f"-> Added {len(chunks)} chunks for {filename}")Didukung oleh
upsert pada cuplikan kode di atas berarti menjalankan pipeline lagi pada file yang sudah diingest akan memperbarui potongan alih-alih memunculkan error ID duplikat.
defdocument_exists(self, file_id:str)->bool:try:
results = self.collection.get(where={"file_id": file_id}, limit=1)returnlen(results["ids"])>0except Exception:returnFalseDidukung oleh
Pemeriksaan cepat ini di loop ingestion main.py menghindari pengunduhan ulang file yang sudah Anda embed, membuat run berikutnya menjadi instan.
Langkah 8.3: main.py — Ingestion, retrieval, dan streaming chat
File main.py menjalankan pemeriksaan autentikasi, menggerakkan loop ingestion, menginisialisasi klien Gemini, dan menjalankan loop chat interaktif. File ini sengaja dibuat tipis karena pekerjaan berat didelegasikan ke fetcher.py dan vector_store.py.
defsetup_gemini():
api_key = os.getenv("GEMINI_API_KEY")ifnot api_key:print("Please enter your GEMINI_API_KEY (get one from Google AI Studio).")
api_key =input("Key: ").strip()return genai.Client(api_key=api_key)Didukung oleh
Jika GEMINI_API_KEY tidak disetel, aplikasi meminta secara interaktif alih-alih crash. Anda dapat menyetel GEMINI_API_KEY seperti yang kita lakukan pada langkah sebelumnya.
Pemeriksaan document_exists adalah mekanisme ingestion inkremental dengan hanya file baru yang diunduh dan di-embed pada setiap run. Loop chat mengambil 3 potongan yang paling mirip secara semantik dan memberi anotasi masing-masing dengan nama file sumbernya:
defchat_loop(model, store):whileTrue:
query =input("\nYou: ")
results = store.query(query, n_results=3)
documents = results.get("documents",[[]])[0]
metadatas = results.get("metadatas",[[]])[0]
context_parts =[]for doc, meta inzip(documents, metadatas):
source = meta.get("source","Unknown")
context_parts.append(f"Source: {source}\nText:\n{doc}\n")
full_context ="\n---\n".join(context_parts)
prompt =f"""You are a helpful assistant. Answer the user's question based ONLY on the following context from their Google Drive. If you cannot answer from the context, say "I don't know based on your documents."
Context:
{full_context}
Question: {query}
"""
model_name = os.getenv("GEMINI_MODEL","gemini-2.5-flash")
response = model.models.generate_content_stream(model=model_name, contents=prompt)for chunk in response:if chunk.text:print(chunk.text, end="", flush=True)print()Didukung oleh
Prompt di atas sepenuhnya terlandas sehingga LLM diinstruksikan untuk menjawab hanya dari konteks yang disediakan dan mengatakan "I don't know" jika jawabannya tidak ada. Ini mencegah halusinasi informasi yang tidak ada di Drive Anda. Respons distream token demi token melalui generate_content_stream, sehingga keluaran muncul seketika.
Pada run pertama, aplikasi memeriksa autentikasi, menginisialisasi ChromaDB, mengunduh model embedding jika belum di-cache, mengambil hingga 10 file Drive, melakukan embedding dan menyimpannya, lalu membawa pengguna ke loop chat. Anda akan melihat progres bertahap dicetak untuk setiap file saat diingest:
Pada run berikutnya, ChromaDB memuat indeks yang dipertahankan dari disk, file yang sudah diingest dilewati, dan Anda mencapai prompt chat hampir seketika.
Namun, untuk meng-ingest ulang semuanya dari nol, misalnya setelah menambahkan file Drive baru yang ingin Anda sertakan, Anda perlu menghapus direktori ChromaDB dan menjalankan ulang:
Ini mengeksekusi check_auth() dan mencetak daftar file Drive Anda untuk mengonfirmasi bahwa CLI, OAuth, dan Drive API semuanya berfungsi sebelum Anda menjalankan ingestion penuh.
Kesimpulan
Asisten RAG yang kita bangun dengan Google Workspace CLI sengaja dibuat minimal di mana gws mengambil, Sentence Transformers melakukan embedding secara lokal, ChromaDB menyimpan, Gemini melakukan streaming jawaban. Empat file, nol biaya embedding cloud, ingestion inkremental pada setiap run. Arsitektur ini diskalakan dengan bersih jika Anda ingin menambahkan Gmail dan Kalender sebagai sumber ingestion tambahan, mengganti dengan model Gemini yang lebih besar, atau mengganti loop chat dengan agen LangGraph. Fondasinya tetap sama.
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.
Google Workspace CLI FAQs
Apakah saya perlu toolchain Rust untuk memasang gws?⌄
Tidak. CLI dikirimkan sebagai paket npm dengan binary pra-bangun untuk tiap OS dan arsitektur. npm install -g @googleworkspace/cli adalah seluruh prosesnya.
Mengapa saya membutuhkan proyek GCP?⌄
OAuth untuk akses developer ke Google API memerlukan proyek GCP untuk menampung kredensial klien OAuth dan melacak kuota API. Jalankan gws auth setup untuk menangani konfigurasi, tetapi proyek harus ada terlebih dahulu di GCP Console.
Saya mendapat error 403 serviceusage.services.use.⌄
Kredensial OAuth Anda diarahkan ke proyek GCP yang berbeda dari yang memiliki penagihan dan akses API aktif. Jalankan ulang gws auth setup --project YOUR_PROJECT_ID.
Bagaimana cara menambahkan Gmail atau Kalender sebagai sumber dokumen?⌄
Jalankan gws gmail messages list dan gws calendar events list untuk mengembalikan JSON terstruktur. Tambahkan fungsi fetch baru di fetcher.py untuk tiap layanan dan panggil dari ingest_documents().
Dapatkah saya menggunakan ini dengan akun organisasi Google Workspace?⌄
Bisa, tetapi admin Workspace Anda mungkin perlu menyetujui aplikasi OAuth. Jika alur autentikasi mengembalikan "Access blocked by your organization", periksa ke admin Anda tentang allowlisting klien OAuth.
Kuasai pertanyaan wawancara basis data, dari konsep SQL dasar hingga skenario desain sistem tingkat lanjut. Panduan mendalam ini mencakup semua yang Anda perlukan untuk sukses di wawancara DBMS dan meraih peran berikutnya.
Temukan alasan mengapa Anda sebaiknya (tidak) menggunakan spaghetti plot untuk menyampaikan ketidakpastian jalur prediksi badai serta dampaknya terhadap interpretasi.
Google baru saja merilis sesuatu yang benar-benar menarik bagi developer. Sebuah antarmuka baris perintah Google Workspace yang memberi Anda akses terstruktur dan dapat diskrip ke seluruh Google Workspace Anda termasuk Drive, Gmail, Kalender, Sheets, Docs, Chat, dan lainnya dalam satu alat.
Codebase-nya hampir seluruhnya Rust (99,3%), tetapi didistribusikan melalui npm sebagai binary native pra-bangun, jadi Anda tidak perlu memasang toolchain Rust.
Dalam tutorial ini, Anda akan menyiapkan Google Workspace CLI dari nol, melakukan autentikasi, dan membangun asisten RAG bertenaga Gemini yang memungkinkan Anda menanyakan file Drive dalam bahasa alami. Di akhir, Anda akan memiliki:
gwsterpasang dan diautentikasi terhadap Drive AndaLingkungan virtual Python dengan ChromaDB, Sentence Transformers, dan Gemini SDK
Pipeline RAG lokal yang berfungsi yang mengambil file melalui
gws, melakukan embedding dengan model lokal, dan melakukan streaming jawaban dengan Gemini 2.5 FlashCatatan: Ini bukan produk Google yang didukung secara resmi.
Apa Itu Google Workspace CLI?
Google Workspace CLI (
gws) adalah alat baris perintah yang dioptimalkan untuk AI bagi seluruh ekosistem Google Workspace Anda. Berikut yang membuatnya menonjol:Penemuan perintah dinamis: Alih-alih mengirimkan pohon perintah yang di-hardcode,
gwsmembaca Discovery Service Google saat runtime. Saat Google menambahkan endpoint API baru, CLI akan menangkapnya secara otomatis tanpa peningkatan versi.Desain agent-native: CLI dilengkapi 100+ skill agent bawaan dan 50 resep terkurasi untuk alur kerja umum yang meringkas email, memindahkan file Drive, membuat event kalender, dan banyak lagi. Setiap output berupa JSON terstruktur, sehingga LLM dapat mengonsumsinya langsung.
Dukungan server MCP native: Jalankan
gwssebagai server MCP lokal dan berikan agen AI Anda akses penuh ke alat Workspace tanpa menulis satu pun klien API.Integrasi Model Armor: Untuk agen produksi yang membaca konten yang dikendalikan pengguna, Anda dapat menyalurkan respons API melalui Google Cloud Model Armor untuk mensterilkan dari prompt injection sebelum dilihat LLM Anda.
Anda dapat menelusuri pustaka skill lengkap di sini: github.com/googleworkspace/cli/blob/main/docs/skills.md.
Tutorial: Bangun Asisten RAG dengan Google Workspace CLI dan Gemini
Dalam tutorial ini, kita akan membangun asisten RAG selangkah demi selangkah. Secara garis besar, inilah yang dilakukan aplikasi:
Melakukan autentikasi terhadap Google Drive Anda menggunakan CLI
gwsdan mengambil file Docs, Sheets, dan teks yang terakhir dimodifikasiMemecah setiap dokumen dan melakukan embedding secara lokal menggunakan Sentence Transformers melalui ChromaDB
Menyimpan indeks vektor ke disk sehingga run berikutnya melewati file yang sudah diingest dan langsung ke percakapan
Menerima pertanyaan berbahasa alami, mengambil 3 potongan paling relevan dari ChromaDB, dan membangun prompt konteks yang terlandas
Melakukan streaming jawaban ber-sitasi berbasis konteks saja dari Gemini 2.5 Flash token demi token langsung di terminal Anda
Mari kita bangun selangkah demi selangkah.
Kode tutorial lengkap: https://github.com/AashiDutt/Google-Workspace-CLI-Demo
Langkah 1: Pasang CLI
CLI didistribusikan sebagai paket
npmyang membungkus binary Rust pra-bangun. Tidak perlu toolchain Rust.Verifikasi pemasangan dengan menjalankan perintah berikut satu per satu:
Jika
gwstidak ditemukan setelah pemasangan, pastikan direktori binnpm globalada padaPATHAnda.Langkah 2: Buat proyek di Google Cloud
CLI melakukan autentikasi melalui klien OAuth proyek GCP, jadi Anda memerlukan satu sebelum masuk. Untuk membuat atau memilih proyek dari GCP:
Siapkan kredensial OAuth:
Masuk ke APIs & Services dan pilih Credentials
Klik Create Credentials dan masuk ke OAuth 2.0 Client ID
Pilih Desktop app sebagai jenis aplikasi
Catat Client ID dan Client Secret yang akan kita gunakan untuk
gws auth setup.CLI menyelesaikan OAuth dengan menyalakan server localhost sementara. Klien Desktop app menangani port localhost apa pun secara otomatis. Klien Web application mengharuskan Anda menambahkan setiap
http://localhost:PORTsecara manual ke daftar authorized redirect URIs.Jika Anda menggunakan klien Web application dan menemui "Access blocked: This app's request is invalid", buka Credentials lalu klik OAuth client diikuti Authorized redirect URIs dan tambahkan URL
http://localhost:PORTpersis seperti yang ditampilkan pada error.Langkah 3: Lakukan autentikasi
Untuk menghubungkan
gwske proyek GCP Anda, pertama ekspor kredensial OAuth Anda sebagai variabel lingkungan agar wizard penyiapan dapat mengambilnya secara otomatis:Lalu jalankan:
Wizard penyiapan akan:
Setelah selesai, Anda akan melihat: Setup complete!
Kredensial disimpan di
~/.config/gws/. Untuk mengonfirmasi semuanya terhubung dengan benar, jalankan:Perintah ini mencetak akun yang diautentikasi, proyek GCP yang ditautkan, dan scope aktif. Jika ada yang terlihat salah, jalankan kembali
gws auth setupdengan flag yang benar alih-alih mencoba mengedit file konfigurasi secara manual.Langkah 4: Uji akses Drive
Sebelum menulis Python, ada baiknya melakukan pemeriksaan cepat langsung dari terminal untuk mengonfirmasi CLI telah diautentikasi dan dapat berkomunikasi dengan Drive Anda. Mari jalankan perintah berikut untuk mencantumkan lima file Drive terbaru Anda:
Flag
--paramsmenerima string JSON yang dipetakan langsung ke parameter kueri API Drive. Di sini,pageSize: 5membatasi respons menjadi lima hasil yang cukup untuk mengonfirmasi konektivitas tanpa menampilkan seluruh Drive Anda.Jika autentikasi berfungsi dengan benar, Anda akan menerima respons JSON terstruktur seperti ini:
Setiap respons dari
gwsadalah JSON terstruktur tanpa parsing, tanpa scraping, tanpa keluaran teks rapuh.Jika Anda malah melihat “403 error” yang menyebut
serviceusage.services.use, itu berarti kredensial OAuth Anda diarahkan ke proyek GCP yang berbeda dari yang memiliki penagihan diaktifkan. Jalankan kembali penyiapan dengan project ID yang benar untuk menautkan semuanya kembali:Dengan akses Drive terkonfirmasi, kita siap mengaktifkan API dan mulai membangun sisi Python dari pipeline.
Langkah 5: Aktifkan Google Drive API
Pada titik ini,
gwsdapat melakukan autentikasi terhadap proyek GCP Anda, tetapi belum bisa membaca konten file Drive. GCP memisahkan autentikasi (membuktikan siapa Anda) dari aktivasi API (menyatakan layanan mana yang digunakan proyek Anda). Bahkan dengan kredensial OAuth yang valid, upaya mengambil konten file akan mengembalikan error403 accessNotConfiguredsampai Drive API diaktifkan secara eksplisit pada proyek.Untuk mengaktifkannya, buka URL ini di browser dan ganti
[PROJECT_ID]dengan project ID Anda yang sebenarnya lalu klik Enable:https://console.developers.google.com/apis/api/drive.googleapis.com/overview?project=[PROJECT_ID]Sebagai alternatif, jika Anda memasang CLI
gcloud, Anda dapat mengaktifkannya langsung dari terminal:Kedua metode melakukan hal yang sama. Menjalankan salah satunya pada API yang sudah diaktifkan aman karena operasinya idempoten dan tidak akan mengatur ulang konfigurasi yang ada.
Setelah diaktifkan, GCP mungkin memerlukan beberapa detik untuk mempropagasi perubahan. Jika Anda langsung menjalankan
gws drive files listdan masih melihat 403, tunggu 30 detik dan coba lagi.Langkah 6: Pasang dependensi
Dengan sisi CLI sepenuhnya dikonfigurasi, kini kita dapat menyiapkan lingkungan Python yang menangani logika embedding dan retrieval. Pipeline RAG sengaja dibuat ringan dengan empat paket, tanpa memerlukan GPU, dan seluruh embedding terjadi secara lokal di mesin Anda.
Mulailah dengan membuat lingkungan virtual dengan menjalankan perintah berikut satu per satu:
Lalu pasang dependensi dari
requirements.txt:Berikut kontribusi tiap paket pada pipeline:
chromadb: Basis data vektor lokal yang menyimpan embedding dokumen ke./chroma_dbdi disk dan memuatnya pada run berikutnya, sehingga aplikasi tidak perlu melakukan embedding ulang file yang sudah diproses.google-genai: SDK Python resmi untuk Gemini. Aplikasi menggunakannya untuk mengirim konteks yang diambil dan pertanyaan pengguna keGemini 2.5 Flash, dengan streaming respons kembali token demi token.langchain-text-splitters: Paket ini menyediakanRecursiveCharacterTextSplitter, yang memecah dokumen besar menjadi potongan tumpang-tindih sebelum embedding. Overlap memastikan kalimat di batas potongan tidak terputus dari konteksnya.sentence-transformers: Sentence Transformers menjalankan model embedding secara lokal melaluiDefaultEmbeddingFunctionmilik ChromaDB. Jadi, setiap potongan dokumen di-embed di mesin tanpa panggilan API eksternal.Catatan: Model embedding (~90MB) diunduh otomatis saat pertama kali digunakan dan di-cache secara lokal.
Dengan lingkungan Python siap, bagian terakhir sebelum menulis kode adalah mendapatkan kunci API Gemini.
Langkah 7: Siapkan Kunci API Gemini
Pipeline RAG menggunakan Gemini sebagai lapisan pembangkitan jawaban karena mengambil potongan dokumen yang diambil dan pertanyaan pengguna, lalu melakukan streaming respons yang terlandas. Untuk terhubung ke Gemini, Anda memerlukan kunci API dari Google AI Studio.
Masuk dengan akun Google Anda, klik Get API Key, lalu pilih Create API Key. Pilih proyek GCP Anda saat diminta agar kuota dan penagihan tercatat. Tautkan akun penagihan di dasbor GCP di bawah Billing lalu pilih
Link a billing account.Setelah Anda memiliki kunci, ekspor sebagai variabel lingkungan:
Ekspor kunci di terminal Anda:
Untuk mempertahankannya antar sesi terminal, jalankan:
Aplikasi membaca kunci ini melalui
os.getenv("GEMINI_API_KEY")saat startup. Jika variabel tidak disetel, aplikasi akan meminta Anda menempelkan kunci secara interaktif.Catatan model: Aplikasi menggunakan default
gemini-2.5-flash. Anda dapat menimpanya dengan mengeksporGEMINI_MODEL="gemini-2.5-pro"jika menginginkan penalaran yang lebih kuat pada dokumen kompleks. Perlu dicatat bahwagemini-2.0-flashtelah dihentikan untuk kunci API baru, jadi jangan gunakan di sini.Dengan autentikasi, Drive API, dependensi, dan kunci Gemini siap, kita memiliki semua yang diperlukan. Mari bangun pipeline-nya.
Langkah 8: Bangun Pipeline RAG
Sekarang mari hubungkan semuanya. Kita akan bekerja dengan empat file, termasuk
fetcher.py,vector_store.py,main.py, danrequirements.txt. Setiap file punya satu tanggung jawab, sepertifetcher.pymenangani semua interaksi CLI,vector_store.pymengelola embedding dan retrieval, danmain.pymengorkestrasi loop penuh dari ingestion hingga streaming chat.Pada run pertama,
gwsmengambil file Drive Anda, konten dipecah dan di-embed secara lokal, dan indeks vektor ditulis ke./chroma_dbdi disk. Pada run berikutnya, ChromaDB memuat dari disk, hanya file baru yang diambil dan di-embed, dan loop chat segera dimulai tanpa memproses ulang apa pun.Mari kita ulas setiap file.
Langkah 8.1:
fetcher.py— Akses Drive viagwsModul ini adalah jembatan antara CLI
gwsdan Python. Semua interaksi Drive seperti mencantumkan file, mengekspor konten, dan memeriksa autentikasi dilakukan melalui pemanggilan subprocess kegws, dan output JSON terstruktur diurai menjadi dict Python. Hasilnya, kode Python tidak pernah perlu berurusan langsung dengan token OAuth, klien HTTP, atau skema respons API;gwsmenangani semua itu dan mengembalikan JSON yang bersih.Helper
_gws_json_stdoutmenangani masalah halus saatgwskadang memunculkan baris keyring atau logging sebelum payload JSON. Di sini, memanggiljson.loads(result.stdout)secara langsung akan gagal sehingga fungsi ini memotong semuanya sebelum{pertama.Fungsi
check_auth()dipanggil saat startup dimain.pyyang membuat panggilan API Drive ringan dan memeriksa respons. Jika autentikasi bermasalah atau scope kurang, aplikasi keluar dengan rapi sebelum mencoba ingestion.Handler error juga menangkap mode kegagalan spesifik dan mencetak pesan yang dapat ditindaklanjuti:
Pengambil daftar dokumen menargetkan hanya tipe MIME yang dapat diekspor sebagai teks:
Kueri memfilter ke teks biasa, Google Docs, dan Google Sheets, masing-masing diurutkan berdasarkan yang terakhir dimodifikasi. File biner (PDF, gambar) dikecualikan karena tidak dapat diekspor sebagai teks dengan pendekatan ini.
Namun, pengunduhan ditangani berbeda per tipe MIME:
gwsmenulis byte file yang diekspor ke disk melalui-o, bukan ke stdout. Stdout membawa metadata JSON. Kode menggunakan file sementara untuk menangkap output biner, membacanya, dan membersihkan di blokfinally, sehingga file sementara selalu dihapus bahkan saat error.Langkah 8.2:
vector_store.py— Embedding lokal dengan ChromaDBModul ini memecah teks yang masuk, menghasilkan embedding secara lokal menggunakan Sentence Transformers, menyimpannya ke disk melalui ChromaDB, dan mengekspos metode
query()sederhana yang dipanggil loop chat untuk setiap pertanyaan pengguna.PersistentClientmenulis indeks vektor ke./chroma_dbdan memuatnya pada run berikutnya tanpa perlu ingestion ulang kecuali Anda menghapus direktori tersebut.DefaultEmbeddingFunctionmenggunakan Sentence Transformers secara lokal, sementara embedding dihitung di mesin Anda dengan biaya marginal nol.Splitter menggunakan
chunk_size=1000denganchunk_overlap=200, sehingga overlap memastikan konteks di batas potongan tidak hilang saat kalimat terbelah di dua potongan.upsertpada cuplikan kode di atas berarti menjalankan pipeline lagi pada file yang sudah diingest akan memperbarui potongan alih-alih memunculkan error ID duplikat.Pemeriksaan cepat ini di loop ingestion
main.pymenghindari pengunduhan ulang file yang sudah Anda embed, membuat run berikutnya menjadi instan.Langkah 8.3:
main.py— Ingestion, retrieval, dan streaming chatFile
main.pymenjalankan pemeriksaan autentikasi, menggerakkan loop ingestion, menginisialisasi klien Gemini, dan menjalankan loop chat interaktif. File ini sengaja dibuat tipis karena pekerjaan berat didelegasikan kefetcher.pydanvector_store.py.Jika
GEMINI_API_KEYtidak disetel, aplikasi meminta secara interaktif alih-alih crash. Anda dapat menyetelGEMINI_API_KEYseperti yang kita lakukan pada langkah sebelumnya.Pemeriksaan
document_existsadalah mekanisme ingestion inkremental dengan hanya file baru yang diunduh dan di-embed pada setiap run. Loop chat mengambil 3 potongan yang paling mirip secara semantik dan memberi anotasi masing-masing dengan nama file sumbernya:Prompt di atas sepenuhnya terlandas sehingga LLM diinstruksikan untuk menjawab hanya dari konteks yang disediakan dan mengatakan "I don't know" jika jawabannya tidak ada. Ini mencegah halusinasi informasi yang tidak ada di Drive Anda. Respons distream token demi token melalui
generate_content_stream, sehingga keluaran muncul seketika.Langkah 9: Menjalankan Aplikasi
Dengan keempat file siap, mulai aplikasi dengan:
Pada run pertama, aplikasi memeriksa autentikasi, menginisialisasi
ChromaDB, mengunduh model embedding jika belum di-cache, mengambil hingga 10 file Drive, melakukan embedding dan menyimpannya, lalu membawa pengguna ke loop chat. Anda akan melihat progres bertahap dicetak untuk setiap file saat diingest:Pada run berikutnya,
ChromaDBmemuat indeks yang dipertahankan dari disk, file yang sudah diingest dilewati, dan Anda mencapai prompt chat hampir seketika.Namun, untuk meng-ingest ulang semuanya dari nol, misalnya setelah menambahkan file Drive baru yang ingin Anda sertakan, Anda perlu menghapus direktori ChromaDB dan menjalankan ulang:
Untuk memverifikasi autentikasi secara terpisah tanpa menjalankan pipeline penuh, jalankan
fetcher.pylangsung:Ini mengeksekusi
check_auth()dan mencetak daftar file Drive Anda untuk mengonfirmasi bahwa CLI, OAuth, dan Drive API semuanya berfungsi sebelum Anda menjalankan ingestion penuh.Kesimpulan
Asisten RAG yang kita bangun dengan Google Workspace CLI sengaja dibuat minimal di mana
gwsmengambil, Sentence Transformers melakukan embedding secara lokal, ChromaDB menyimpan, Gemini melakukan streaming jawaban. Empat file, nol biaya embedding cloud, ingestion inkremental pada setiap run. Arsitektur ini diskalakan dengan bersih jika Anda ingin menambahkan Gmail dan Kalender sebagai sumber ingestion tambahan, mengganti dengan model Gemini yang lebih besar, atau mengganti loop chat dengan agen LangGraph. Fondasinya tetap sama.