Skip to content
White Paper2026-07-24

Pipeline RAG yang Murah, Aman, dan Presisi Tinggi: Catatan Arsitektur

Cara kami merangkai pipeline copilot + retrieval untuk CMMS maintenance yang murah per permintaan, aman dari prompt injection, dan presisi saat retrieval β€” tanpa model frontier di setiap giliran. Enam tahap, termurah-dulu, satu panggilan generasi.

DA
Dzulfikar Ats Tsauri
AI Engineer
Bagikan:

Cara kami merangkai lapisan AI untuk opexmx, sebuah CMMS maintenance (maintenance Corrective + Preventive, manajemen aset, basis pengetahuan). Tujuannya: pipeline copilot + retrieval yang murah per permintaan, aman dari prompt injection, dan presisi saat retrieval β€” tanpa membayar model frontier di setiap giliran.

Semua berjalan di Cloudflare Workers AI (lewat AI Gateway yang kompatibel dengan OpenAI). Model id yang sama berlaku di cloud maupun on-prem.


TL;DR β€” pipeline-nya

flowchart TD
    U([pesan pengguna]) --> R1["1. Guard regex β€” gratis, menangkap ~80–90% prompt injection"]
    R1 -->|bersih / tidak pasti| G["2. Klasifier Granite β€” intent + safety + routing, JSON-only (hanya jika ragu)"]
    G -->|allow| E["3. Qwen3-Embedding 0.6B β€” query ke vektor, 768-dim (Matryoshka dari 1024)"]
    E --> V["4. Pencarian vektor β€” over-fetch top-K x 3, Vectorize / pgvector (recall)"]
    V --> B["5. Reranker BGE base β€” cross-encoder men-skor ulang, ambil top-K (presisi)"]
    B --> Q["6. Qwen3-30B-A3B (MoE) + agen tool-calling β€” satu panggilan generasi, konteks terbaik. Manager Mode ke Llama-3.3-70B"]

Model mahal (30B/70B) berjalan sekali, hanya setelah permintaan divalidasi dan konteks terbaik terkumpul. Sebagian besar belanja per permintaan adalah klasifier kecil + rerank murah, bukan generasi.


Mengapa setiap lapisan ada

1. Guard β€” regex dulu, lalu klasifier murah

Copilot yang menelan teks pengguna bebas butuh pertahanan prompt-injection. Kami jalankan dua lapis, termurah dulu:

  • Lapisan 1 β€” regex (gratis). Daftar frasa: ignore previous instructions, reveal your system prompt, DAN, jailbreak, developer message:, dll. Menangkap sebagian besar serangan di $0. Berbasis frasa, bukan kata kunci telanjang β€” api key / token sendiri terlalu umum di teks maintenance nyata, jadi diserahkan ke klasifier.
  • Lapisan 2 β€” klasifier LLM (hanya jika Lapisan 1 bersih dan pesan bukan obrolan sepele). Model kecil mengembalikan JSON ketat:
    { "intent": "maintenance", "safe": true, "requires_rag": true,
      "requires_tools": false, "confidence": 0.9 }
    
    Ini melakukan tiga pekerjaan dalam satu panggilan murah: gerbang safety, klasifikasi intent, dan petunjuk routing. Petunjuk ditampilkan ke UI; tool-calling agen tetap menjadi router sebenarnya (tanpa rewrite agen).

Kebijakan kegagalan: fail-open. Jika klasifier error atau tak dikonfigurasi, pesan diizinkan β€” Lapisan 1 regex tetap memblokir kasus yang jelas. Chat tidak pernah rusak total saat guard down.

2. Embeddings β€” Qwen3-Embedding-0.6B di 768 dim

Kami mengindeks manual + dokumen knowledge-center (PDF, rich-text, keterangan gambar) jadi chunk lalu meng-embed-nya. Kami memilih @cf/qwen/qwen3-embedding-0.6b demi kualitas berbiaya rendah.

Jebakan dimensi (ini pernah menggigit kami): Qwen3-Embedding-0.6B secara native 1024-dim, tetapi vector store kami (indeks Cloudflare Vectorize + kolom pgvector) sudah di-pin ke 768 dari model sebelumnya (bge-base-en-v1.5). Dimensi campuran ilegal dalam satu indeks. Alih-alih migrasi seluruh store ke 1024 (indeks baru + kolom baru + reindex penuh), kami memanfaatkan Matryoshka representation learning: Qwen3 mendukung truncation output di rentang 32–1024 dim, jadi kami minta dimensions: 768 pada panggilan /embeddings dan mendapat vektor 768-dim yang tetap kompatibel dengan store yang ada.

⚠️ Field dimensions milik OpenAI harus diteruskan gateway ke model. Jika gateway Anda menghapusnya, Anda diam-diam mendapat 1024 dan insert gagal. Verifikasi dengan:

curl -s $GW/embeddings -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"model":"@cf/qwen/qwen3-embedding-0.6b","input":["test"],"dimensions":768}' \
  | jq '.data[0].embedding | length'   # harapan 768

Juga: kirim dimensions hanya untuk model yang mendukung Matryoshka. bge-base fixed-768 dan 400 pada field ini.

3. Retrieval β€” pencarian vektor (recall)

Embed query, cari di indeks, over-fetch (mis. top-KΓ—3) dengan fan-out filter (dokumen global + lingkup aset + lingkup tipe peralatan, digabung berdasarkan skor terbaik per chunk). Embedding recall-optimized β€” ia mengangkat lingkungan yang benar, bukan chunk yang persis tepat.

4. Reranker β€” BGE-Reranker-Base (presisi)

Cross-encoder bukan chatbot lain. Tugasnya satu: "dari chunk yang diretrieve, mana yang benar-benar paling relevan?" Ia menerima pasangan (query, passage) dan mengembalikan skor relevansi, lalu kami urutkan ulang dan ambil top-K.

Ini adalah tuas kualitas retrieval terbesar dengan biaya ~nol:

chunkembedding simskor reranker
Manual pompa0.840.99
Troubleshooting pompa0.820.95
Spesifikasi bearing0.810.91
SOP konveyor (off-topic)0.800.20

Fail-open: reranker error apa pun β†’ pertahankan urutan embedding-similarity. Retrieval tidak pernah putus.

5. Generasi β€” Qwen3-30B-A3B + tool-calling

30B Mixture-of-Experts (hanya ~3B aktif per token) memberi kualitas model besar pada latensi/biaya model kecil, dengan function calling native untuk loop agen. Tools: search_assets, get_asset_status, search_documents, search_problems, create_ticket, PM/parts/metrics, dll. Model merutekan sendiri.

Manager Mode menaikkan hanya langkah sintesis ke Llama-3.3-70B (chatModelPro) saat pengguna meminta tinjauan lintas-domain. Ronde tool tetap di model dasar murah; hanya briefing akhir yang membayar model besar.

6. Autocomplete / fill-with-AI β€” jalur cepat terpisah

Autocomplete ghost-text inline dan "isi field ini" butuh latensi rendah, bukan reasoning. Mereka berjalan di model kecil cepat (chatModelFast, Llama-3.1-8B-instruct-fp8-fast) dan fallback ke model chat jika tak mengembalikan apa-apa.

⚠️ Gotcha: jika provider Anda gateway kompatibel-OpenAI, pastikan ia menghormati model id per-role yang berbeda. Bug umum: gateway men-collapse semua id @cf/ ke satu model chat terkonfigurasi, sehingga setelan "fast model" Anda diam-diam diabaikan dan setiap autocomplete membayar 30B. Teruskan id yang diminta saat gateway berbicara dalam namespace model yang sama; hanya collapse @cf/β†’nama-lokal pada endpoint lokal satu-model (Ollama/mlx).

⚠️ Gotcha #2: model reasoning kecil (mis. MoE mikro hibrid) adalah pilihan salah untuk tugas generasi seperti pengisian field. Dengan thinking dimatikan ia bisa memancarkan kosong. Pakai untuk klasifikasi; pakai model instruct biasa untuk autocomplete/fill.


Model & biaya (Cloudflare Workers AI, ~$0.011 / 1k Neurons)

PeranModelCatatan
Chat / agen@cf/qwen/qwen3-30b-a3b-fp8MoE murah, multibahasa, tool-calling
Pro / Manager@cf/meta/llama-3.3-70b-…-fp8-fastlangkah sintesis saja
Autocomplete@cf/meta/llama-3.1-8b-…-fp8-fastjalur cepat terpisah
Embeddings@cf/qwen/qwen3-embedding-0.6b768-dim (Matryoshka-truncated)
Reranker@cf/baai/bge-reranker-basecross-encoder, pasca-retrieval
Guard/klasifier@cf/ibm-granite/granite-4.0-h-microintent + prompt-injection, JSON-only

Biaya andalan: ~$0.045 / pengguna ringan / bulan, ~$0.27 / pengguna berat. Guard + reranker menambah belanja bisa diabaikan relatif terhadap satu generasi 30B per giliran.


Prinsip desain

  1. Termurah-dulu. Regex sebelum LLM; klasifier kecil sebelum 30B; embedding+rerank sebelum generasi. Bayar model besar sekali, terakhir.
  2. Fail-open di jalur safety/klasifier; fail-open di jalur rerank. Tak boleh ada yang memutus chat atau retrieval. Regex tetap memblokir injection yang jelas meski guard LLM down.
  3. Satu model murah, tiga pekerjaan. Guard mengembalikan safety + intent + petunjuk routing dalam satu panggilan JSON, bukan tiga model terpisah.
  4. Disiplin dimensi. Pilih satu dimensi embedding dan pin seluruh store ke sana. Saat ganti model, samakan dimensi atau pakai truncation Matryoshka β€” lalu reindex agar setiap vektor tinggal di ruang yang sama.
  5. Recall saat retrieval, presisi saat rerank, kualitas saat generasi. Jangan minta satu tahap mengerjakan tugas tahap lain.

Pelajaran yang kami bayar

  • Verifikasi langsung, jangan percaya halaman docs. Sumber docs/search mengklaim Qwen3-Embedding 768-dim "mungkin." Gateway live mengembalikan 1024 dan insert gagal. Selalu curl endpoint dan cek .data[0].embedding | length.
  • Gateway harus meneruskan dimensions. Tanpa passthrough, truncation Matryoshka tak terlihat dan Anda diam-diam mendapat dim native.
  • Model id per-role harus dihormati. Gateway yang menulis ulang semua id @cf/ ke satu model chat diam-diam menggagalkan setelan model fast/pro Anda (dan eskalasi Manager-Mode).
  • Kecil β‰  selalu murah. Model reasoning mikro pada prompt generasi kompleks bisa mengembalikan kosong dan menyia-nyiakan detik sebelum fallback. Cocokkan kelas model ke tugasnya.

Mereproduksi bentuk ini

Jika Anda membangun sesuatu yang serupa, bagian minimalnya:

  • modul guard: daftar regex + panggilan JSON-klasifier (fail-open);
  • langkah embed yang di-pin ke satu dimensi (truncate Matryoshka bila perlu);
  • langkah retrieve yang over-fetch;
  • langkah rerank (cross-encoder) yang men-skor ulang dan memangkas (fail-open);
  • langkah generate pada satu model bagus, dengan jalur eskalasi model pro;
  • jalur cepat (model instruct kecil) untuk autocomplete/fill, dengan fallback model chat.

Semuanya muat dalam anggaran permintaan di mana biaya dominan adalah satu panggilan generasi β€” persis seperti yang Anda inginkan.

Bicara dengan kami tentang men-deploy copilot RAG pada data maintenance Anda β†’

Insight maintenance ke inbox Anda

Bergabung dengan operator yang mendapat tips CMMS praktis, studi kasus, dan update produk. Tanpa spam.