Google Workspace CLI: Xây dựng trợ lý RAG trên các tệp Drive của bạn
Tìm hiểu cách cài đặt CLI tối ưu cho AI mới của Google, xác thực và kết nối nó với pipeline RAG dùng Gemini để trả lời câu hỏi về chính các tệp Drive của bạn.
Google vừa ra mắt một thứ thực sự thú vị cho nhà phát triển: một giao diện dòng lệnh Google Workspace cung cấp cho bạn quyền truy cập có cấu trúc và có thể lập trình vào toàn bộ Google Workspace, bao gồm Drive, Gmail, Calendar, Sheets, Docs, Chat và nhiều hơn nữa trong một công cụ duy nhất.
Mã nguồn hầu như hoàn toàn viết bằng Rust (99,3%), nhưng được phân phối qua npm dưới dạng binary gốc dựng sẵn, vì vậy bạn không cần cài bộ công cụ Rust.
Trong hướng dẫn này, bạn sẽ thiết lập Google Workspace CLI từ đầu, xác thực và xây dựng một trợ lý RAG dùng Gemini cho phép bạn truy vấn tệp Drive bằng ngôn ngữ tự nhiên. Kết thúc, bạn sẽ có:
Đã cài và xác thực gws với Drive của bạn
Một môi trường ảo Python với ChromaDB, Sentence Transformers và Gemini SDK
Một pipeline RAG cục bộ hoạt động: lấy tệp qua gws, nhúng bằng mô hình cục bộ và stream câu trả lời với Gemini 2.5 Flash
Lưu ý: Đây không phải là sản phẩm chính thức được Google hỗ trợ.
Google Workspace CLI là gì?
Google Workspace CLI (gws) là công cụ dòng lệnh tối ưu cho AI dành cho toàn bộ hệ sinh thái Google Workspace của bạn. Những điểm nổi bật:
Khám phá lệnh động: Thay vì đóng gói một cây lệnh cố định, gws đọc Discovery Service của Google khi chạy. Khi Google thêm endpoint API mới, CLI sẽ tự động nhận mà không cần tăng phiên bản.
Thiết kế thân thiện với agent: CLI đi kèm 100+ kỹ năng agent dựng sẵn và 50 công thức đã tuyển chọn cho các quy trình thường gặp như tóm tắt email, di chuyển tệp Drive, tạo sự kiện lịch, v.v. Mọi đầu ra đều là JSON có cấu trúc để LLM có thể tiêu thụ trực tiếp.
Hỗ trợ máy chủ MCP gốc: Chạy gws như một máy chủ MCP cục bộ và cấp cho agent AI của bạn toàn quyền truy cập công cụ Workspace mà không cần viết bất kỳ client API nào.
Tích hợp Model Armor: Với agent sản xuất đọc nội dung do người dùng kiểm soát, bạn có thể dẫn dữ liệu API qua Google Cloud Model Armor để khử nhiễm tấn công prompt injection trước khi LLM nhìn thấy.
Đặt tên và ghi lại Project ID được tạo tự động để dùng ở bước tiếp theo
Thiết lập thông tin xác thực OAuth:
Đi tới APIs & Services và chọn Credentials
Nhấp Create Credentials và chọn OAuth 2.0 Client ID
Chọn Desktop app làm loại ứng dụng
Ghi lại Client ID và Client Secret mà chúng ta sẽ dùng cho gws auth setup.
CLI hoàn tất OAuth bằng cách khởi chạy máy chủ localhost tạm thời. Client Desktop app tự động xử lý các cổng localhost bất kỳ. Client Web application yêu cầu bạn thủ công thêm từng http://localhost:PORT vào danh sách Authorized redirect URIs.
Nếu bạn dùng Web application client và gặp lỗi "Access blocked: This app's request is invalid", hãy vào Credentials, nhấp OAuth client rồi Authorized redirect URIs và thêm URL http://localhost:PORT chính xác hiển thị trong lỗi.
Bước 3: Xác thực
Để nối gws với dự án GCP, trước tiên xuất thông tin xác thực OAuth thành biến môi trường để trình hướng dẫn thiết lập tự động nhận:
exportGOOGLE_WORKSPACE_CLI_CLIENT_ID="CLIENT_ID"exportGOOGLE_WORKSPACE_CLI_CLIENT_SECRET="CLIENT_SECRET"Được hỗ trợ bởi
Sau đó chạy:
gws auth setup --project YOUR_PROJECT_ID --loginĐược hỗ trợ bởi
Trình hướng dẫn sẽ:
Hỏi bạn muốn dùng tài khoản Google nào
Mở trình duyệt cho luồng đồng ý OAuth tiêu chuẩn của Google
Hỏi các scope (như Drive, Gmail, Calendar, v.v.) cần cấp quyền
Hoàn tất, bạn sẽ thấy: Setup complete!
Thông tin xác thực được lưu tại ~/.config/gws/. Để xác nhận mọi thứ đã nối đúng, chạy:
Lệnh này in ra tài khoản đã xác thực, dự án GCP được liên kết và các scope đang hoạt động. Nếu có gì đó sai, hãy chạy lại gws auth setup với cờ đúng thay vì chỉnh tay tệp cấu hình.
Bước 4: Kiểm tra truy cập Drive
Trước khi viết bất kỳ mã Python nào, nên làm một kiểm tra nhanh ngay từ terminal để xác nhận CLI đã xác thực và có thể giao tiếp với Drive của bạn. Hãy chạy nhanh lệnh sau để liệt kê năm tệp Drive gần đây nhất của bạn:
gws drive files list --params'{"pageSize": 5}'Được hỗ trợ bởi
Cờ --params nhận một chuỗi JSON ánh xạ trực tiếp tới tham số truy vấn của Drive API. Ở đây, pageSize: 5 giới hạn phản hồi ở năm kết quả, đủ để xác nhận kết nối mà không đổ toàn bộ Drive của bạn.
Nếu xác thực hoạt động đúng, bạn sẽ nhận về phản hồi JSON có cấu trúc như sau:
{"files":[{"id":"1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms","name":"Q3 Strategy Doc","mimeType":"application/vnd.google-apps.document"},
...
]}Được hỗ trợ bởi
Mọi phản hồi từ gws đều là JSON có cấu trúc, không cần parse phức tạp, không scraping, không đầu ra văn bản mong manh.
Nếu thay vào đó bạn thấy “403 error” đề cập serviceusage.services.use, nghĩa là thông tin xác thực OAuth của bạn đang trỏ tới một dự án GCP khác với dự án đã bật thanh toán. Chạy lại thiết lập với Project ID chính xác để liên kết lại mọi thứ:
gws auth setup --project YOUR_PROJECT_ID --loginĐược hỗ trợ bởi
Khi đã xác nhận truy cập Drive, chúng ta sẵn sàng bật API và bắt đầu xây dựng phần Python của pipeline.
Bước 5: Bật Google Drive API
Lúc này, gws có thể xác thực với dự án GCP của bạn, nhưng vẫn chưa thể đọc nội dung tệp Drive. GCP tách biệt xác thực (chứng minh bạn là ai) với việc kích hoạt API (khai báo dịch vụ dự án sử dụng). Dù có thông tin xác thực OAuth hợp lệ, mọi nỗ lực lấy nội dung tệp sẽ trả về lỗi 403 accessNotConfigured cho đến khi Drive API được bật rõ ràng trên dự án.
Để bật, mở URL này trên trình duyệt và thay [PROJECT_ID] bằng Project ID thực của bạn rồi nhấp Enable:
Ngoài ra, nếu bạn đã cài gcloud CLI, có thể bật trực tiếp từ terminal:
gcloud services enable drive.googleapis.com --project YOUR_PROJECT_IDĐược hỗ trợ bởi
Cả hai cách đều như nhau. Chạy trên một API đã bật cũng an toàn vì thao tác là idempotent và sẽ không đặt lại cấu hình hiện có.
Sau khi bật, GCP có thể mất vài giây để truyền thay đổi. Nếu bạn lập tức chạy gws drive files list và vẫn thấy 403, đợi 30 giây rồi thử lại.
Bước 6: Cài đặt phụ thuộc
Khi phía CLI đã cấu hình xong, chúng ta thiết lập môi trường Python xử lý logic nhúng và truy xuất. Pipeline RAG được thiết kế gọn nhẹ với bốn gói, không cần GPU và toàn bộ việc nhúng diễn ra cục bộ trên máy của bạn.
Bắt đầu bằng cách tạo môi trường ảo, chạy lần lượt các lệnh sau:
cd /path/to/your/project
python3 -m venv .venv
source .venv/bin/activate
python -m pip install--upgrade pip
pip install-r requirements.txtĐược hỗ trợ bởi
Sau đó cài các phụ thuộc từ requirements.txt:
.txt
chromadb==1.5.5
google-genai==1.70.0
langchain-text-splitters==1.1.1
sentence-transformers==5.3.0Được hỗ trợ bởi
Vai trò của từng gói trong pipeline:
chromadb: Cơ sở dữ liệu vector cục bộ lưu embedding tài liệu vào ./chroma_db trên đĩa và tải lại ở lần chạy sau, nên ứng dụng không cần nhúng lại các tệp đã xử lý.
google-genai: SDK Python chính thức cho Gemini. Ứng dụng dùng để gửi ngữ cảnh truy xuất và câu hỏi người dùng tới Gemini 2.5 Flash, stream phản hồi theo từng token.
langchain-text-splitters: Cung cấp RecursiveCharacterTextSplitter để chia tài liệu lớn thành các đoạn chồng lắp trước khi nhúng. Phần chồng lắp giúp câu ở ranh giới đoạn không bị tách khỏi ngữ cảnh.
sentence-transformers: Chạy mô hình nhúng cục bộ qua DefaultEmbeddingFunction của ChromaDB. Mỗi đoạn tài liệu được nhúng trên máy, không cần gọi API ngoài.
Lưu ý: Mô hình nhúng (~90MB) được tải tự động lần đầu và lưu đệm cục bộ.
Khi môi trường Python đã sẵn sàng, phần cuối cùng trước khi viết mã là lấy khóa API Gemini.
Bước 7: Thiết lập khóa API Gemini
Pipeline RAG dùng Gemini làm lớp sinh câu trả lời vì nó nhận các đoạn tài liệu truy xuất cùng câu hỏi của người dùng và stream về phản hồi có căn cứ. Để kết nối tới Gemini, bạn cần khóa API từ Google AI Studio.
Đăng nhập bằng tài khoản Google của bạn, nhấp Get API Key rồi chọn Create API Key. Chọn dự án GCP khi được hỏi để áp dụng hạn ngạch và thanh toán. Liên kết tài khoản thanh toán trong bảng điều khiển GCP mục Billing rồi chọn Link a billing account.
Khi đã có khóa, hãy xuất nó thành biến môi trường:
echo'export GEMINI_API_KEY="YOUR_GEMINI_API_KEY"'>> ~/.zshrc
source ~/.zshrcĐược hỗ trợ bởi
Ứng dụng đọc khóa này qua os.getenv("GEMINI_API_KEY") khi khởi động. Nếu biến chưa đặt, ứng dụng sẽ nhắc bạn dán khóa tương tác.
Ghi chú mô hình: Ứng dụng mặc định gemini-2.5-flash. Bạn có thể ghi đè bằng cách xuất GEMINI_MODEL="gemini-2.5-pro" nếu muốn năng lực suy luận mạnh hơn cho tài liệu phức tạp. Lưu ý gemini-2.0-flash đã ngừng cho khóa API mới, nên đừng dùng ở đây.
Với xác thực, Drive API, phụ thuộc và khóa Gemini đã sẵn sàng, ta có đủ mọi thứ. Hãy xây dựng pipeline.
Bước 8: Xây dựng Pipeline RAG
Giờ hãy nối mọi thứ lại. Chúng ta sẽ làm việc với bốn tệp gồm fetcher.py, vector_store.py, main.py và requirements.txt. Mỗi tệp đảm nhiệm một trách nhiệm: fetcher.py xử lý mọi tương tác CLI, vector_store.py phụ trách nhúng và truy xuất, còn main.py điều phối vòng lặp từ đưa vào đến chat streaming.
Ở lần chạy đầu, gws lấy tệp Drive của bạn, nội dung được chia nhỏ và nhúng cục bộ, và chỉ mục vector được ghi vào ./chroma_db trên đĩa. Ở các lần sau, ChromaDB tải từ đĩa, chỉ tệp mới được lấy và nhúng, và vòng chat bắt đầu ngay mà không xử lý lại.
Hãy đi qua từng tệp.
Bước 8.1: fetcher.py — Truy cập Drive qua gws
Module này là cầu nối giữa CLI gws và Python. Mọi tương tác Drive như liệt kê tệp, xuất nội dung và kiểm tra xác thực đều đi qua lời gọi subprocess tới gws, và đầu ra JSON có cấu trúc được parse thành dict Python. Nhờ vậy, mã Python không cần xử lý token OAuth, HTTP client hay schema phản hồi API trực tiếp; gws lo phần đó và trả về JSON sạch.
def_gws_json_stdout(stdout:str)->str:ifnot stdout or"{"notin stdout:return stdout or""return stdout[stdout.find("{"):]Được hỗ trợ bởi
Hàm trợ giúp _gws_json_stdout xử lý vấn đề tinh vi khi gws đôi lúc in dòng keyring hoặc logging trước payload JSON. Khi đó gọi json.loads(result.stdout) trực tiếp sẽ lỗi, nên hàm này cắt mọi thứ trước dấu {.
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)returnFalsereturnTrueĐược hỗ trợ bởi
Hàm check_auth() được gọi khi khởi động trong main.py, thực hiện một lời gọi Drive API nhẹ và kiểm tra phản hồi. Nếu xác thực hỏng hoặc thiếu scope, ứng dụng thoát gọn gàng trước khi cố gắng đưa dữ liệu vào.
Bộ xử lý lỗi cũng bắt các tình huống hỏng cụ thể và in thông điệp có thể hành động:
Trình lấy danh sách tài liệu chỉ nhắm tới các loại MIME có thể xuất văn bản:
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"}),]Được hỗ trợ bởi
Truy vấn lọc Plain text, Google Docs và Google Sheets, sắp xếp theo sửa đổi gần nhất. Tệp nhị phân (PDF, hình ảnh) bị loại vì không thể xuất văn bản sạch theo cách này.
Tuy nhiên, việc tải xuống xử lý khác nhau theo MIME type:
gws ghi byte tệp đã xuất ra đĩa qua -o, không ghi ra stdout. Stdout mang metadata JSON. Mã dùng tệp tạm để bắt đầu ra nhị phân, đọc nó và dọn dẹp trong khối finally, nên tệp tạm luôn được xóa kể cả khi lỗi.
Bước 8.2: vector_store.py — Nhúng cục bộ với ChromaDB
Module này chia nhỏ văn bản đầu vào, tạo embedding cục bộ bằng Sentence Transformers, lưu xuống đĩa qua ChromaDB và cung cấp phương thức query() đơn giản để vòng chat gọi cho mỗi câu hỏi.
PersistentClient ghi chỉ mục vector vào ./chroma_db và tải lại ở lần chạy sau mà không cần đưa vào lại trừ khi bạn xóa thư mục. DefaultEmbeddingFunction dùng Sentence Transformers cục bộ, các embedding được tính trên máy bạn với chi phí biên bằng 0.
Bộ chia dùng chunk_size=1000 với chunk_overlap=200, phần chồng lắp giúp ngữ cảnh ở ranh giới đoạn không bị mất khi câu bị chia đôi.
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}")Được hỗ trợ bởi
Trong đoạn trên, upsert có nghĩa là chạy lại pipeline trên tệp đã đưa vào sẽ cập nhật các đoạn thay vì báo lỗi ID trùng.
Bước kiểm tra nhanh này trong vòng đưa vào của main.py giúp tránh tải lại các tệp bạn đã nhúng, khiến lần chạy sau gần như tức thì.
Bước 8.3: main.py — Đưa vào, truy xuất và chat streaming
Tệp main.py chạy kiểm tra xác thực, điều khiển vòng đưa vào, khởi tạo client Gemini và chạy vòng chat tương tác. Tệp này cố ý mảnh vì phần nặng đã ủy quyền cho fetcher.py và 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)Được hỗ trợ bởi
Nếu GEMINI_API_KEY chưa đặt, ứng dụng sẽ nhắc tương tác thay vì sập. Bạn có thể đặt GEMINI_API_KEY như ở bước trước.
Kiểm tra document_exists là cơ chế đưa vào gia tăng: mỗi lần chạy chỉ tải và nhúng tệp mới. Vòng chat truy xuất top-3 đoạn tương đồng ngữ nghĩa và chú thích nguồn tệp:
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()Được hỗ trợ bởi
Prompt trên được neo chặt: LLM được hướng dẫn chỉ trả lời từ ngữ cảnh cung cấp và nói "I don't know" nếu câu trả lời không có trong tài liệu của bạn. Điều này tránh bịa đặt thông tin không có trong Drive. Phản hồi stream theo từng token qua generate_content_stream, nên đầu ra xuất hiện ngay lập tức.
Lần chạy đầu, ứng dụng kiểm tra xác thực, khởi tạo ChromaDB, tải mô hình nhúng nếu chưa được cache, lấy tối đa 10 tệp Drive, nhúng và lưu, sau đó đưa bạn vào vòng chat. Bạn sẽ thấy tiến độ từng tệp khi đưa vào:
Ở các lần sau, ChromaDB tải chỉ mục lưu sẵn từ đĩa, các tệp đã đưa vào được bỏ qua, và bạn đến prompt chat gần như ngay lập tức.
Tuy nhiên, để đưa vào lại mọi thứ từ đầu, ví dụ sau khi thêm tệp Drive mới muốn bao gồm, bạn cần xóa thư mục ChromaDB rồi chạy lại:
Lệnh này thực thi check_auth() và in danh sách tệp Drive của bạn để xác nhận CLI, OAuth và Drive API đều hoạt động trước khi bạn chạy đưa vào đầy đủ.
Kết luận
Trợ lý RAG chúng ta xây dựng với Google Workspace CLI được cố ý tối giản: gws lấy dữ liệu, Sentence Transformers nhúng cục bộ, ChromaDB lưu trữ, Gemini stream câu trả lời. Bốn tệp, chi phí nhúng đám mây bằng 0, đưa vào gia tăng mỗi lần chạy. Kiến trúc mở rộng gọn gàng nếu bạn muốn thêm Gmail và Calendar làm nguồn đưa vào, thay mô hình Gemini lớn hơn hoặc thay vòng chat bằng agent LangGraph. Nền tảng vẫn giữ nguyên.
Tôi là Chuyên gia Google Developers trong lĩnh vực ML (Gen AI), Chuyên gia Kaggle 3x và Đại sứ Women Techmakers với hơn 3 năm kinh nghiệm trong ngành công nghệ. Tôi đồng sáng lập một startup công nghệ y tế vào năm 2020 và hiện đang theo học thạc sĩ khoa học máy tính tại Georgia Tech, chuyên sâu về học máy.
Google Workspace CLI FAQs
Tôi có cần bộ công cụ Rust để cài gws không?⌄
Không. CLI được phát hành dưới dạng gói npm với binary dựng sẵn cho từng hệ điều hành và kiến trúc. npm install -g @googleworkspace/cli là toàn bộ quy trình.
Tại sao tôi cần một dự án GCP?⌄
OAuth để nhà phát triển truy cập Google APIs yêu cầu một dự án GCP để chứa thông tin xác thực OAuth client và theo dõi hạn ngạch API. Chạy gws auth setup để xử lý cấu hình, nhưng dự án cần tồn tại trước trong GCP Console.
Tôi gặp lỗi 403 serviceusage.services.use.⌄
Thông tin xác thực OAuth của bạn đang trỏ tới một dự án GCP khác với dự án đã bật thanh toán và quyền truy cập API. Chạy lại gws auth setup --project YOUR_PROJECT_ID.
Làm sao thêm Gmail hoặc Calendar làm nguồn tài liệu?⌄
Chạy gws gmail messages list và gws calendar events list để nhận JSON có cấu trúc. Thêm hàm fetch mới trong fetcher.py cho từng dịch vụ và gọi chúng từ ingest_documents().
Tôi có thể dùng cái này với tài khoản Google Workspace của tổ chức không?⌄
Có, nhưng quản trị viên Workspace của bạn có thể cần phê duyệt ứng dụng OAuth. Nếu luồng xác thực trả về "Access blocked by your organization", hãy liên hệ quản trị viên để allowlist OAuth client.
Google vừa ra mắt một thứ thực sự thú vị cho nhà phát triển: một giao diện dòng lệnh Google Workspace cung cấp cho bạn quyền truy cập có cấu trúc và có thể lập trình vào toàn bộ Google Workspace, bao gồm Drive, Gmail, Calendar, Sheets, Docs, Chat và nhiều hơn nữa trong một công cụ duy nhất.
Mã nguồn hầu như hoàn toàn viết bằng Rust (99,3%), nhưng được phân phối qua npm dưới dạng binary gốc dựng sẵn, vì vậy bạn không cần cài bộ công cụ Rust.
Trong hướng dẫn này, bạn sẽ thiết lập Google Workspace CLI từ đầu, xác thực và xây dựng một trợ lý RAG dùng Gemini cho phép bạn truy vấn tệp Drive bằng ngôn ngữ tự nhiên. Kết thúc, bạn sẽ có:
Đã cài và xác thực
gwsvới Drive của bạnMột môi trường ảo Python với ChromaDB, Sentence Transformers và Gemini SDK
Một pipeline RAG cục bộ hoạt động: lấy tệp qua
gws, nhúng bằng mô hình cục bộ và stream câu trả lời với Gemini 2.5 FlashLưu ý: Đây không phải là sản phẩm chính thức được Google hỗ trợ.
Google Workspace CLI là gì?
Google Workspace CLI (
gws) là công cụ dòng lệnh tối ưu cho AI dành cho toàn bộ hệ sinh thái Google Workspace của bạn. Những điểm nổi bật:Khám phá lệnh động: Thay vì đóng gói một cây lệnh cố định,
gwsđọc Discovery Service của Google khi chạy. Khi Google thêm endpoint API mới, CLI sẽ tự động nhận mà không cần tăng phiên bản.Thiết kế thân thiện với agent: CLI đi kèm 100+ kỹ năng agent dựng sẵn và 50 công thức đã tuyển chọn cho các quy trình thường gặp như tóm tắt email, di chuyển tệp Drive, tạo sự kiện lịch, v.v. Mọi đầu ra đều là JSON có cấu trúc để LLM có thể tiêu thụ trực tiếp.
Hỗ trợ máy chủ MCP gốc: Chạy
gwsnhư một máy chủ MCP cục bộ và cấp cho agent AI của bạn toàn quyền truy cập công cụ Workspace mà không cần viết bất kỳ client API nào.Tích hợp Model Armor: Với agent sản xuất đọc nội dung do người dùng kiểm soát, bạn có thể dẫn dữ liệu API qua Google Cloud Model Armor để khử nhiễm tấn công prompt injection trước khi LLM nhìn thấy.
Bạn có thể duyệt toàn bộ thư viện kỹ năng tại: github.com/googleworkspace/cli/blob/main/docs/skills.md.
Hướng dẫn: Xây dựng trợ lý RAG với Google Workspace CLI và Gemini
Trong hướng dẫn này, chúng ta sẽ xây dựng trợ lý RAG từng bước. Ở mức khái quát, ứng dụng sẽ:
Xác thực với Google Drive của bạn bằng CLI
gwsvà lấy các tệp Docs, Sheets, và văn bản được chỉnh sửa gần đây nhấtChia nhỏ mỗi tài liệu và nhúng cục bộ bằng Sentence Transformers qua ChromaDB
Lưu chỉ mục vector xuống đĩa để những lần chạy sau bỏ qua tệp đã đưa vào và đi thẳng vào trò chuyện
Nhận câu hỏi ngôn ngữ tự nhiên, truy xuất top-3 đoạn liên quan nhất từ ChromaDB và dựng prompt ngữ cảnh có căn cứ
Stream câu trả lời có trích dẫn, chỉ dựa trên ngữ cảnh từ Gemini 2.5 Flash theo từng token trực tiếp trong terminal của bạn
Hãy xây dựng từng bước.
Mã đầy đủ của hướng dẫn: https://github.com/AashiDutt/Google-Workspace-CLI-Demo
Bước 1: Cài đặt CLI
CLI được phân phối dưới dạng gói
npmbọc các binary Rust dựng sẵn. Không cần bộ công cụ Rust.Xác minh cài đặt bằng cách chạy lần lượt các lệnh sau:
Nếu không tìm thấy
gwssau khi cài, đảm bảo thư mục binnpm globalnằm trongPATHcủa bạn.Bước 2: Tạo dự án trên Google Cloud
CLI xác thực qua OAuth client của một dự án GCP, vì vậy bạn cần có một dự án trước khi đăng nhập. Để tạo hoặc chọn dự án từ GCP:
Thiết lập thông tin xác thực OAuth:
Đi tới APIs & Services và chọn Credentials
Nhấp Create Credentials và chọn OAuth 2.0 Client ID
Chọn Desktop app làm loại ứng dụng
Ghi lại Client ID và Client Secret mà chúng ta sẽ dùng cho
gws auth setup.CLI hoàn tất OAuth bằng cách khởi chạy máy chủ localhost tạm thời. Client Desktop app tự động xử lý các cổng localhost bất kỳ. Client Web application yêu cầu bạn thủ công thêm từng
http://localhost:PORTvào danh sách Authorized redirect URIs.Nếu bạn dùng Web application client và gặp lỗi "Access blocked: This app's request is invalid", hãy vào Credentials, nhấp OAuth client rồi Authorized redirect URIs và thêm URL
http://localhost:PORTchính xác hiển thị trong lỗi.Bước 3: Xác thực
Để nối
gwsvới dự án GCP, trước tiên xuất thông tin xác thực OAuth thành biến môi trường để trình hướng dẫn thiết lập tự động nhận:Sau đó chạy:
Trình hướng dẫn sẽ:
Hoàn tất, bạn sẽ thấy: Setup complete!
Thông tin xác thực được lưu tại
~/.config/gws/. Để xác nhận mọi thứ đã nối đúng, chạy:Lệnh này in ra tài khoản đã xác thực, dự án GCP được liên kết và các scope đang hoạt động. Nếu có gì đó sai, hãy chạy lại
gws auth setupvới cờ đúng thay vì chỉnh tay tệp cấu hình.Bước 4: Kiểm tra truy cập Drive
Trước khi viết bất kỳ mã Python nào, nên làm một kiểm tra nhanh ngay từ terminal để xác nhận CLI đã xác thực và có thể giao tiếp với Drive của bạn. Hãy chạy nhanh lệnh sau để liệt kê năm tệp Drive gần đây nhất của bạn:
Cờ
--paramsnhận một chuỗi JSON ánh xạ trực tiếp tới tham số truy vấn của Drive API. Ở đây,pageSize: 5giới hạn phản hồi ở năm kết quả, đủ để xác nhận kết nối mà không đổ toàn bộ Drive của bạn.Nếu xác thực hoạt động đúng, bạn sẽ nhận về phản hồi JSON có cấu trúc như sau:
Mọi phản hồi từ
gwsđều là JSON có cấu trúc, không cần parse phức tạp, không scraping, không đầu ra văn bản mong manh.Nếu thay vào đó bạn thấy “403 error” đề cập
serviceusage.services.use, nghĩa là thông tin xác thực OAuth của bạn đang trỏ tới một dự án GCP khác với dự án đã bật thanh toán. Chạy lại thiết lập với Project ID chính xác để liên kết lại mọi thứ:Khi đã xác nhận truy cập Drive, chúng ta sẵn sàng bật API và bắt đầu xây dựng phần Python của pipeline.
Bước 5: Bật Google Drive API
Lúc này,
gwscó thể xác thực với dự án GCP của bạn, nhưng vẫn chưa thể đọc nội dung tệp Drive. GCP tách biệt xác thực (chứng minh bạn là ai) với việc kích hoạt API (khai báo dịch vụ dự án sử dụng). Dù có thông tin xác thực OAuth hợp lệ, mọi nỗ lực lấy nội dung tệp sẽ trả về lỗi403 accessNotConfiguredcho đến khi Drive API được bật rõ ràng trên dự án.Để bật, mở URL này trên trình duyệt và thay
[PROJECT_ID]bằng Project ID thực của bạn rồi nhấp Enable:https://console.developers.google.com/apis/api/drive.googleapis.com/overview?project=[PROJECT_ID]Ngoài ra, nếu bạn đã cài
gcloudCLI, có thể bật trực tiếp từ terminal:Cả hai cách đều như nhau. Chạy trên một API đã bật cũng an toàn vì thao tác là idempotent và sẽ không đặt lại cấu hình hiện có.
Sau khi bật, GCP có thể mất vài giây để truyền thay đổi. Nếu bạn lập tức chạy
gws drive files listvà vẫn thấy 403, đợi 30 giây rồi thử lại.Bước 6: Cài đặt phụ thuộc
Khi phía CLI đã cấu hình xong, chúng ta thiết lập môi trường Python xử lý logic nhúng và truy xuất. Pipeline RAG được thiết kế gọn nhẹ với bốn gói, không cần GPU và toàn bộ việc nhúng diễn ra cục bộ trên máy của bạn.
Bắt đầu bằng cách tạo môi trường ảo, chạy lần lượt các lệnh sau:
Sau đó cài các phụ thuộc từ
requirements.txt:Vai trò của từng gói trong pipeline:
chromadb: Cơ sở dữ liệu vector cục bộ lưu embedding tài liệu vào./chroma_dbtrên đĩa và tải lại ở lần chạy sau, nên ứng dụng không cần nhúng lại các tệp đã xử lý.google-genai: SDK Python chính thức cho Gemini. Ứng dụng dùng để gửi ngữ cảnh truy xuất và câu hỏi người dùng tớiGemini 2.5 Flash, stream phản hồi theo từng token.langchain-text-splitters: Cung cấpRecursiveCharacterTextSplitterđể chia tài liệu lớn thành các đoạn chồng lắp trước khi nhúng. Phần chồng lắp giúp câu ở ranh giới đoạn không bị tách khỏi ngữ cảnh.sentence-transformers: Chạy mô hình nhúng cục bộ quaDefaultEmbeddingFunctioncủa ChromaDB. Mỗi đoạn tài liệu được nhúng trên máy, không cần gọi API ngoài.Lưu ý: Mô hình nhúng (~90MB) được tải tự động lần đầu và lưu đệm cục bộ.
Khi môi trường Python đã sẵn sàng, phần cuối cùng trước khi viết mã là lấy khóa API Gemini.
Bước 7: Thiết lập khóa API Gemini
Pipeline RAG dùng Gemini làm lớp sinh câu trả lời vì nó nhận các đoạn tài liệu truy xuất cùng câu hỏi của người dùng và stream về phản hồi có căn cứ. Để kết nối tới Gemini, bạn cần khóa API từ Google AI Studio.
Đăng nhập bằng tài khoản Google của bạn, nhấp Get API Key rồi chọn Create API Key. Chọn dự án GCP khi được hỏi để áp dụng hạn ngạch và thanh toán. Liên kết tài khoản thanh toán trong bảng điều khiển GCP mục Billing rồi chọn
Link a billing account.Khi đã có khóa, hãy xuất nó thành biến môi trường:
Xuất khóa trong terminal của bạn:
Để lưu qua các phiên terminal, chạy:
Ứng dụng đọc khóa này qua
os.getenv("GEMINI_API_KEY")khi khởi động. Nếu biến chưa đặt, ứng dụng sẽ nhắc bạn dán khóa tương tác.Ghi chú mô hình: Ứng dụng mặc định
gemini-2.5-flash. Bạn có thể ghi đè bằng cách xuấtGEMINI_MODEL="gemini-2.5-pro"nếu muốn năng lực suy luận mạnh hơn cho tài liệu phức tạp. Lưu ýgemini-2.0-flashđã ngừng cho khóa API mới, nên đừng dùng ở đây.Với xác thực, Drive API, phụ thuộc và khóa Gemini đã sẵn sàng, ta có đủ mọi thứ. Hãy xây dựng pipeline.
Bước 8: Xây dựng Pipeline RAG
Giờ hãy nối mọi thứ lại. Chúng ta sẽ làm việc với bốn tệp gồm
fetcher.py,vector_store.py,main.pyvàrequirements.txt. Mỗi tệp đảm nhiệm một trách nhiệm:fetcher.pyxử lý mọi tương tác CLI,vector_store.pyphụ trách nhúng và truy xuất, cònmain.pyđiều phối vòng lặp từ đưa vào đến chat streaming.Ở lần chạy đầu,
gwslấy tệp Drive của bạn, nội dung được chia nhỏ và nhúng cục bộ, và chỉ mục vector được ghi vào./chroma_dbtrên đĩa. Ở các lần sau, ChromaDB tải từ đĩa, chỉ tệp mới được lấy và nhúng, và vòng chat bắt đầu ngay mà không xử lý lại.Hãy đi qua từng tệp.
Bước 8.1:
fetcher.py— Truy cập Drive quagwsModule này là cầu nối giữa CLI
gwsvà Python. Mọi tương tác Drive như liệt kê tệp, xuất nội dung và kiểm tra xác thực đều đi qua lời gọi subprocess tớigws, và đầu ra JSON có cấu trúc được parse thành dict Python. Nhờ vậy, mã Python không cần xử lý token OAuth, HTTP client hay schema phản hồi API trực tiếp;gwslo phần đó và trả về JSON sạch.Hàm trợ giúp
_gws_json_stdoutxử lý vấn đề tinh vi khigwsđôi lúc in dòng keyring hoặc logging trước payload JSON. Khi đó gọijson.loads(result.stdout)trực tiếp sẽ lỗi, nên hàm này cắt mọi thứ trước dấu{.Hàm
check_auth()được gọi khi khởi động trongmain.py, thực hiện một lời gọi Drive API nhẹ và kiểm tra phản hồi. Nếu xác thực hỏng hoặc thiếu scope, ứng dụng thoát gọn gàng trước khi cố gắng đưa dữ liệu vào.Bộ xử lý lỗi cũng bắt các tình huống hỏng cụ thể và in thông điệp có thể hành động:
Trình lấy danh sách tài liệu chỉ nhắm tới các loại MIME có thể xuất văn bản:
Truy vấn lọc Plain text, Google Docs và Google Sheets, sắp xếp theo sửa đổi gần nhất. Tệp nhị phân (PDF, hình ảnh) bị loại vì không thể xuất văn bản sạch theo cách này.
Tuy nhiên, việc tải xuống xử lý khác nhau theo MIME type:
gwsghi byte tệp đã xuất ra đĩa qua-o, không ghi ra stdout. Stdout mang metadata JSON. Mã dùng tệp tạm để bắt đầu ra nhị phân, đọc nó và dọn dẹp trong khốifinally, nên tệp tạm luôn được xóa kể cả khi lỗi.Bước 8.2:
vector_store.py— Nhúng cục bộ với ChromaDBModule này chia nhỏ văn bản đầu vào, tạo embedding cục bộ bằng Sentence Transformers, lưu xuống đĩa qua ChromaDB và cung cấp phương thức
query()đơn giản để vòng chat gọi cho mỗi câu hỏi.PersistentClientghi chỉ mục vector vào./chroma_dbvà tải lại ở lần chạy sau mà không cần đưa vào lại trừ khi bạn xóa thư mục.DefaultEmbeddingFunctiondùng Sentence Transformers cục bộ, các embedding được tính trên máy bạn với chi phí biên bằng 0.Bộ chia dùng
chunk_size=1000vớichunk_overlap=200, phần chồng lắp giúp ngữ cảnh ở ranh giới đoạn không bị mất khi câu bị chia đôi.Trong đoạn trên,
upsertcó nghĩa là chạy lại pipeline trên tệp đã đưa vào sẽ cập nhật các đoạn thay vì báo lỗi ID trùng.Bước kiểm tra nhanh này trong vòng đưa vào của
main.pygiúp tránh tải lại các tệp bạn đã nhúng, khiến lần chạy sau gần như tức thì.Bước 8.3:
main.py— Đưa vào, truy xuất và chat streamingTệp
main.pychạy kiểm tra xác thực, điều khiển vòng đưa vào, khởi tạo client Gemini và chạy vòng chat tương tác. Tệp này cố ý mảnh vì phần nặng đã ủy quyền chofetcher.pyvàvector_store.py.Nếu
GEMINI_API_KEYchưa đặt, ứng dụng sẽ nhắc tương tác thay vì sập. Bạn có thể đặtGEMINI_API_KEYnhư ở bước trước.Kiểm tra
document_existslà cơ chế đưa vào gia tăng: mỗi lần chạy chỉ tải và nhúng tệp mới. Vòng chat truy xuất top-3 đoạn tương đồng ngữ nghĩa và chú thích nguồn tệp:Prompt trên được neo chặt: LLM được hướng dẫn chỉ trả lời từ ngữ cảnh cung cấp và nói "I don't know" nếu câu trả lời không có trong tài liệu của bạn. Điều này tránh bịa đặt thông tin không có trong Drive. Phản hồi stream theo từng token qua
generate_content_stream, nên đầu ra xuất hiện ngay lập tức.Bước 9: Chạy ứng dụng
Khi cả bốn tệp đã sẵn, khởi chạy ứng dụng bằng:
Lần chạy đầu, ứng dụng kiểm tra xác thực, khởi tạo
ChromaDB, tải mô hình nhúng nếu chưa được cache, lấy tối đa 10 tệp Drive, nhúng và lưu, sau đó đưa bạn vào vòng chat. Bạn sẽ thấy tiến độ từng tệp khi đưa vào:Ở các lần sau,
ChromaDBtải chỉ mục lưu sẵn từ đĩa, các tệp đã đưa vào được bỏ qua, và bạn đến prompt chat gần như ngay lập tức.Tuy nhiên, để đưa vào lại mọi thứ từ đầu, ví dụ sau khi thêm tệp Drive mới muốn bao gồm, bạn cần xóa thư mục ChromaDB rồi chạy lại:
Để xác minh xác thực độc lập mà không chạy toàn bộ pipeline, chạy trực tiếp
fetcher.py:Lệnh này thực thi
check_auth()và in danh sách tệp Drive của bạn để xác nhận CLI, OAuth và Drive API đều hoạt động trước khi bạn chạy đưa vào đầy đủ.Kết luận
Trợ lý RAG chúng ta xây dựng với Google Workspace CLI được cố ý tối giản:
gwslấy dữ liệu, Sentence Transformers nhúng cục bộ, ChromaDB lưu trữ, Gemini stream câu trả lời. Bốn tệp, chi phí nhúng đám mây bằng 0, đưa vào gia tăng mỗi lần chạy. Kiến trúc mở rộng gọn gàng nếu bạn muốn thêm Gmail và Calendar làm nguồn đưa vào, thay mô hình Gemini lớn hơn hoặc thay vòng chat bằng agent LangGraph. Nền tảng vẫn giữ nguyên.