All Products
Search
Document Center

Vector Retrieval Service for Milvus:Buat aplikasi Tanya Jawab kebijakan perusahaan dengan basis pengetahuan Alibaba Cloud Milvus

Last Updated:Aug 28, 2026

Basis pengetahuan Alibaba Cloud Milvus mengintegrasikan kebijakan, proses, dan SOP yang tersebar di berbagai departemen menjadi satu titik masuk internal untuk Tanya Jawab. Karyawan dapat mengajukan pertanyaan dalam bahasa alami dan menerima langkah-langkah proses beserta kutipan aslinya, sementara tag departemen membatasi pengambilan hanya pada cakupan tertentu.

Ikhtisar solusi

Pipeline end-to-end identik dengan Buat aplikasi Tanya Jawab layanan pelanggan cerdas dengan basis pengetahuan Alibaba Cloud Milvus: definisikan tag di Konsol → impor dokumen secara batch berdasarkan tag → publikasikan versi → lakukan pengambilan melalui SDK dengan filter tag opsional → LLM menghasilkan jawaban dengan kutipan sumber → Flask menyajikan halaman Tanya Jawab. Gunakan kembali kode rekayasa dari dokumen tersebut secara langsung (kb_client.py, upload.py, app.py, templates/index.html, dan start.sh). Topik ini hanya mencakup bagian-bagian yang harus diubah untuk skenario kebijakan: skema tag departemen, parameter pengambilan, prompt asisten kebijakan, dan manajemen versi kebijakan.

Untuk versi pertama, pilih hanya 5 hingga 20 dokumen dari satu departemen saja, lalu perluas setelah Anda memverifikasi kualitas pengambilan dan prompt. Seluruh proses membutuhkan waktu sekitar 20 hingga 30 menit.

Prasyarat

  • Buat basis pengetahuan dan catat Knowledge Base ID (misalnya, kd-803ae9b10cc31).

  • Buat RAM user dengan Akun Alibaba Cloud Anda, pilih Use a permanent AccessKey pair, dan sambungkan kebijakan sistem AliyunMilvusFullAccess.

  • Titik akhir LLM yang mendukung protokol OpenAI chat/completions beserta Kunci API-nya.

  • Python 3.9 atau versi lebih baru telah terinstal secara lokal, dan direktori proyek telah disiapkan mengikuti tutorial yang dirujuk dalam Ikhtisar solusi.

Langkah 1: Definisikan tag departemen dan kebijakan

Pada halaman detail basis pengetahuan, di bawah Basic Information, pilih Tags > Manage dan tambahkan tiga tag berikut, semuanya bertipe string:

Nama tagDeskripsiContoh nilai
departmentDepartemen yang memiliki kebijakanFinance, Administration, IT
docTypeJenis dokumenPolicy, Process
effectiveDateTanggal berlaku2026-01-01

Nilai tag menerima teks apa pun, sehingga Anda dapat langsung menggunakan nama departemen dan jenis dokumen.

Penting

Kotak dialog manajemen tag disimpan secara keseluruhan. Setelah Anda membuka kotak dialog, daftar tag dimuat secara asinkron. Tunggu hingga semua tag yang ada ditampilkan sebelum menambahkan tag baru dan mengklik Done. Jika tidak, kotak dialog tersebut dapat menimpa seluruh daftar dengan daftar kosong ditambah tag baru, yang menghapus definisi tag yang sudah ada.

Nilai tag yang telah ditulis ke data tidak hilang. Setelah Anda menambahkan kembali tag, verifikasi jumlah tag pada halaman detail.

Definisi tag terutama menstandarkan nilai yang diperbolehkan. Nama tag yang tidak didefinisikan tetap dapat ditulis bersama data dan digunakan untuk pemfilteran, tetapi sebaiknya didefinisikan terlebih dahulu sebelum impor agar kolaborasi tim dan pemeliharaan lebih mudah.

Langkah 2: Mengatur dokumen kebijakan dan manifes impor

  1. Atur dokumen berdasarkan departemen dan tempatkan di direktori documents/. Sertakan nama kebijakan serta versi atau tanggal berlaku dalam setiap nama file, sehingga setiap entri mudah diidentifikasi di bagian sumber jawaban.

  2. Buat documents.jsonl dan anotasi setiap dokumen dengan departemen, jenis, dan tanggal berlaku:

    {"path": "documents/finance-travel.md", "metadata": {"department": "Finance", "docType": "Policy", "effectiveDate": "2026-01-01"}}
    {"path": "documents/finance-reimbursement.md", "metadata": {"department": "Finance", "docType": "Process", "effectiveDate": "2026-02-01"}}
    {"path": "documents/hr-leave.md", "metadata": {"department": "Administration", "docType": "Policy", "effectiveDate": "2026-01-01"}}
    {"path": "documents/it-troubleshoot.md", "metadata": {"department": "IT", "docType": "Process", "effectiveDate": "2026-03-01"}}

  3. Tulis setiap dokumen kebijakan dengan tanggal berlaku dan pemilik kebijakan di awal isi, dan tandai versi lama dengan "Superseded by version X". Secara default, LLM hanya melihat isi chunk yang diambil. Tag effectiveDate tidak ditambahkan ke prompt secara otomatis dan hanya disertakan setelah Anda menerapkan perubahan di Langkah 4.

  4. Sesuaikan granularitas chunking. Dokumen kebijakan biasanya berupa entri pendek. Pada halaman detail basis pengetahuan, di Processing Policy (pengaturan pemrosesan dan chunking dokumen basis pengetahuan), klik Create Policy. Satuan panjang maksimum chunk adalah karakter (default 512). Atur menjadi 580 hingga 770 karakter (sekitar 384 hingga 512 token) agar setiap langkah proses tetap utuh.

Langkah 3: Konfigurasikan parameter pengambilan dan prompt

Dalam config.json, sesuaikan retrieval dan scenario untuk skenario kebijakan. Ubah hanya dua bagian ini dan biarkan sisa file tetap tidak berubah.

{
  "retrieval": {
    "page_size": 6,
    "candidate_count": 48,
    "min_score": 0.35,
    "semantic_weight": 0.6,
    "enable_query_expansion": true,
    "rerank_model_name": "",
    "tag_filter": {
      "relation": "and",
      "conditions": []
    }
  },
  "scenario": {
    "title": "Enterprise policy and process Q&A",
    "system_prompt": "You are an internal policy assistant. Answer only based on the retrieved published policies. Organize processes into steps, state the applicable conditions and required materials, and cite sources as [Source N]. When the materials conflict or are insufficient, clearly tell the user to contact the policy owner.",
    "image_enabled": false,
    "sample_questions": [
      "What materials are required for travel expense reimbursement?",
      "Who approves leave requests longer than three days?",
      "What is the process for reporting an issue when my computer cannot connect to the network?"
    ]
  }
}

Parameter lain dalam contoh (page_size, candidate_count, enable_query_expansion, dan rerank_model_name) mempertahankan nilai dari tutorial yang dirujuk. Parameter min_score, semantic_weight, dan tag_filter memerlukan penyesuaian spesifik skenario:

  • min_score — Tidak ada nilai rekomendasi universal yang berlaku untuk semua korpus. Kalibrasi ambang batas terhadap korpus Anda sendiri menggunakan pertanyaan nyata:

    1. Atur min_score ke 0 dan ambil sejumlah hasil.

    2. Beri label relevansi hasil secara manual.

    3. Pilih ambang batas berdasarkan distribusi recall dan false-positive.

      Hingga Anda memiliki data kalibrasi tersebut, mulailah dari 0,35, nilai yang diukur pada korpus dalam topik ini. Pada korpus tersebut, pada skor 0,2, kebijakan yang sama sekali tidak relevan (skor 0,36 hingga 0,43) masih masuk ke konteks LLM, yang meningkatkan biaya dan risiko jawaban salah. Pada 0,35, hasil tersebut difilter. Lakukan kalibrasi ulang setiap kali Anda mengubah korpus, mengganti model rerank, atau menyesuaikan semantic_weight.
  • semantic_weight=0.6 — Pertanyaan kebijakan sering mencampurkan proper noun dengan ekspresi percakapan, sehingga perlu menyeimbangkan pencocokan semantik dan kata kunci.

    Parameter ini merupakan faktor pembobotan skor akhir, dihitung sebagai score ≈ (1-semantic_weight) × keywordScore + semantic_weight × semanticScore (fitur peringkat juga dapat ditambahkan). min_score melakukan filter berdasarkan skor akhir ini setelah dihitung.

    Tanpa reranking, semanticScore adalah kemiripan vektor; dengan reranking diaktifkan, nilainya adalah skor model rerank. Keduanya memiliki skala berbeda, sehingga setelah Anda mengubah bobot atau mengaktifkan/menonaktifkan reranking, lakukan kalibrasi ulang ambang batas bersama dengan scoreDetails. Menurunkan bobot tidak selalu menurunkan skor total; skor hanya turun jika semanticScore lebih tinggi daripada keywordScore untuk batch tersebut.

  • tag_filter — Biarkan conditions kosong secara default untuk mengambil dari semua departemen. Konfigurasikan kondisi filter hanya jika Anda ingin membatasi titik masuk ke satu departemen saja. Langkah 5: Batasi pengambilan ke satu departemen menjelaskan konfigurasi dan mencantumkan perilaku operator yang harus Anda ketahui.

Langkah 4: Sertakan departemen dan tanggal berlaku dalam jawaban

Tanya Jawab kebijakan harus menentukan versi mana yang berlaku dan departemen mana yang berlaku, sehingga sertakan nilai tag dalam konteks LLM. Field tags dalam hasil pengambilan tidak mengembalikan nilai tag yang Anda tulis. Field ini berasal dari fitur peningkatan tag chunk internal layanan dan merupakan field berbeda dari MetaFields yang ditulis oleh AddDocuments. Tidak ada parameter permintaan yang dapat mengaktifkan pengembaliannya, sehingga nilai kosong tidak berarti unggahan gagal atau tag hilang.

Pertahankan pemetaan di sisi client: indeks manifes impor lokal berdasarkan nama file, cari setiap hasil pengambilan berdasarkan documentName-nya, dan tambahkan nilai tag ke konteks LLM.

Penting

Pencarian bergantung pada pencocokan nama eksak. Verifikasi bahwa documentName yang dikembalikan oleh pengambilan sesuai dengan nama file di documents.jsonl. Jika tidak, entri sumber diam-diam tidak membawa label tag.

Dalam app.py, setelah app = Flask(__name__), tambahkan pemetaan:

META_BY_NAME: dict[str, dict[str, Any]] = {}
_manifest = Path("documents.jsonl")
if _manifest.is_file():
    for _line in _manifest.read_text(encoding="utf-8").splitlines():
        if _line.strip():
            _entry = json.loads(_line)
            META_BY_NAME[Path(str(_entry["path"])).name] = _entry.get("metadata") or {}

Lalu modifikasi llm_answer() untuk menyertakan nilai tag saat membangun konteks dan memberikan tanggal saat ini dalam pertanyaan:

def llm_answer(question: str, results: list[dict[str, Any]]) -> str:
    if not LLM.get("enabled", True):
        return "The LLM is disabled. Review the retrieval results below."
    if not results:
        return "The current policy materials contain no relevant provisions. Contact the corresponding policy owner for confirmation."
    blocks = []
    for index, item in enumerate(results, 1):
        title = field(item, "documentName", "DocumentName")
        meta = META_BY_NAME.get(title) or {}
        label = ", ".join(f"{key}={value}" for key, value in meta.items())
        header = f"[Source {index}] {title}" + (f" ({label})" if label else "")
        blocks.append(f"{header}\n{field(item, 'content', 'Content')}")
    context = "\n\n".join(blocks)
    today = datetime.date.today().isoformat()
    url = str(LLM["base_url"]).rstrip("/") + "/chat/completions"
    response = requests.post(
        url,
        headers={"Authorization": f"Bearer {LLM['api_key']}"},
        json={
            "model": LLM["model"],
            "temperature": 0.1,
            "messages": [
                {"role": "system", "content": SCENARIO.get("system_prompt", "Answer only based on the provided materials.")},
                {"role": "user", "content": f"Current date: {today}\nQuestion: {question}\n\nRetrieved materials:\n{context}"},
            ],
        },
        timeout=90,
    )
    response.raise_for_status()
    return response.json()["choices"][0]["message"]["content"].strip()

Tambahkan import datetime ke header file.

Penting

Jangan pernah melewatkan langkah memberikan tanggal saat ini. LLM tidak mengetahui tanggal hari ini. Jika Anda hanya memberikan effectiveDate, model akan mengasumsikan tanggal saat ini sendiri dan mungkin mencapai kesimpulan yang berlawanan. Misalnya, model dapat menilai versi baru yang sudah berlaku sebagai "belum berlaku" dan mengutip standar lama yang sudah digantikan. Hanya ketika nilai tag dan tanggal saat ini disediakan, model dapat memilih versi saat ini dengan benar dan menjelaskan bahwa versi lama telah digantikan.

Langkah 5: Batasi pengambilan ke satu departemen

Untuk menyediakan titik masuk khusus bagi satu departemen, konfigurasikan kondisi filter yang sesuai:

"tag_filter": {
  "relation": "and",
  "conditions": [
    {"field": "department", "op": "=", "value": "Finance"}
  ]
}

Anda juga dapat menggabungkan beberapa kondisi. Misalnya, untuk mencari hanya dokumen proses dari departemen Finance:

"conditions": [
  {"field": "department", "op": "=", "value": "Finance"},
  {"field": "docType", "op": "=", "value": "Process"}
]

Perangkap operator filter tag

Hanya =, in, dan not in yang benar-benar berlaku dalam filter tag. Tinjau perilaku berikut sebelum mengonfigurasi filter:

KonfigurasiPerilaku aktual
op adalah operator lain, termasuk operator dalam daftar "Supported operators" dari error 400 Unsupported tag filter operatorPengujian menunjukkan bahwa kondisi tersebut diabaikan diam-diam dan data lengkap tanpa filter dikembalikan.
op adalah contains atau not containsIni hanyalah alias dari operasi himpunan in dan not in, bukan pencarian substring. Memberikan fragmen string menghasilkan 0 hasil.
field adalah nama tag yang tidak didefinisikanAPI tidak mengembalikan error dan hanya menghasilkan 0 hasil.
op adalah alias seperti eq, ==, equal, atau likeAPI mengembalikan 400 Unsupported tag filter operator.

Praktik yang benar:

  • Untuk memfilter berdasarkan rentang numerik atau tanggal, enumerasi nilai-nilainya dengan in.

  • Untuk memeriksa apakah tag kosong, gunakan = "".

  • Setelah mengonfigurasi kondisi filter, bandingkan jumlah total hasil dengan dan tanpa filter untuk memastikan filter berlaku.

    Setelah filter departemen dikonfigurasi, titik masuk ini hanya dapat menjawab pertanyaan dari departemen tersebut. Sesuaikan sample_questions dengan tepat; jika tidak, pertanyaan tentang departemen lain hanya akan menghasilkan "tidak ada ketentuan relevan".

Untuk mengganti titik masuk ke departemen lain, ubah tiga tempat sekaligus:

  • Metadata di documents.jsonl, yang merupakan sumber tag yang ditulis saat unggah dan label jawaban yang ditambahkan di Langkah 4.

  • tag_filter di config.json, yang menentukan cakupan pengambilan titik masuk.

  • Pertanyaan contoh, agar sesuai dengan cakupan baru.

Langkah 6: Unggah, publikasikan, dan verifikasi

Unggah dokumen

MetaFields berlaku untuk seluruh batch. Skrip mengelompokkan dokumen berdasarkan tag terlebih dahulu lalu mengirimkannya dalam batch.

python upload.py --manifest documents.jsonl
Penting

Unggahan duplikat file dengan nama yang sama gagal. Saat doc_name_dedup=True, jika setiap file dalam batch dideduplikasi berdasarkan nama, API mengembalikan 400 No OSS document can be registered. Saat memperbarui kebijakan, sertakan nomor versi dalam nama file, atau hapus data lama di Konsol terlebih dahulu.

Periksa hasil pemrosesan

Pada halaman Data Management di Konsol, pastikan status dokumen adalah Processing Completed dan kolom tag menampilkan tag yang ditulis (misalnya, docType=Process, department=IT +1).

Publikasikan versi

Pada halaman Version Management, klik Publish Version. Setelah menyelesaikan wizard tiga langkah, pastikan status versi baru adalah Published.

Setelah memperbarui kebijakan, Anda harus mempublikasikan ulang versinya. Aplikasi hanya mengambil konten baru saat menggunakan LATEST_PUBLISHED.

Kuota versi. Secara default, paling banyak 3 versi yang dipublikasikan dapat ada secara bersamaan. Batas ini dihitung per penyewa dan tidak bertambah seiring spesifikasi CU instans. Saat batas tercapai, tombol Publish Version menjadi abu-abu, meskipun halaman tetap menunjukkan bahwa ada N perubahan tertunda untuk dipublikasikan. Basis pengetahuan kebijakan sering diperbarui. Simpan hanya versi efektif saat ini ditambah versi historis terbaru, dan bersihkan versi lama sebelum mempublikasikan yang baru. Batas ini dapat disesuaikan di sisi server, tetapi saat ini tidak tersedia entri permintaan kuota self-service untuk pengguna. Kirim tiket untuk evaluasi.

Peringatan

Penghapusan versi tidak dapat dikembalikan, dan versi yang dihapus langsung tidak dapat diambil. Backend membersihkan data secara asinkron. Sebelum menghapus, pastikan tidak ada aplikasi yang terkunci pada nomor versi tersebut, dan alihkan aplikasi yang masih menggunakannya ke versi baru.

Jalankan layanan dan verifikasi

python app.py

Kirim pertanyaan uji:

curl -sS http://127.0.0.1:7860/api/ask \
  -H 'Content-Type: application/json' \
  -d '{"question":"What materials are required for travel expense reimbursement?"}'

Akseptasi berdasarkan kriteria berikut:

  • Halaman terbuka normal, dan pertanyaan yang dikirim mengembalikan jawaban beserta sumber pengambilannya.

  • Setiap [Source N] dalam jawaban memiliki chunk kebijakan yang sesuai di bagian sumber di bawahnya.

  • Header [Source N] membawa label tag, seperti department=, docType=, dan effectiveDate=. Jika label hilang, verifikasi bahwa documentName yang dikembalikan oleh pengambilan sesuai dengan nama file di documents.jsonl.

  • Saat Anda menanyakan hal yang tidak dicakup kebijakan, jawaban secara jelas menyatakan tidak ada ketentuan relevan dan meminta Anda menghubungi pemilik kebijakan.

  • Setelah kebijakan diperbarui dan versi dipublikasikan ulang, halaman mengambil konten dari versi baru. Ini memerlukan aplikasi untuk menggunakan LATEST_PUBLISHED.

Pertimbangan untuk skenario kebijakan

  • Versi kebijakan lama — Jika Anda menyimpan versi historis untuk jejak audit, tandai isi dengan "Superseded by version X" dan bedakan versi dengan effectiveDate. Jika jejak audit tidak diperlukan, hapus versi lama di halaman Data Management dan publikasikan ulang, agar model tidak ragu-ragu antar versi.

  • Fallback manual — Untuk Tanya Jawab kebijakan kritis, pertahankan titik masuk fallback manual dan beri tahu karyawan untuk mengikuti dokumen kebijakan resmi yang dipublikasikan.

FAQ

Tabel berikut mencantumkan gejala umum beserta penyebab dan resolusinya.

GejalaPenyebab dan resolusi
Pertanyaan mengembalikan 500, dan log menunjukkan 400 Unsupported tag filter operatorop menggunakan alias seperti eq, ==, atau like. Gunakan =, in, atau not in sebagai gantinya.
Setelah menambahkan filter tag, jumlah hasil persis sama seperti tanpa filterAnda menggunakan operator yang tidak berlaku, seperti >, , , atau empty. Hanya =, in, dan not in yang berlaku.
Setelah mengonfigurasi filter departemen, sebagian besar pertanyaan dijawab dengan "tidak ada ketentuan relevan"Titik masuk dibatasi hanya untuk satu departemen. Pastikan cakupan pertanyaan sesuai dengan tag_filter, atau biarkan conditions kosong.
Pemfilteran berdasarkan tag selalu mengembalikan 0 hasilEjaan nama tag tidak sesuai dengan yang ditulis. API tidak mengembalikan error, hanya 0 hasil. Verifikasi nama tag di bawah Tags > Manage pada halaman detail basis pengetahuan.
Jawaban mencampur versi kebijakan lama dan baruChunk yang diambil tidak memiliki informasi versi. Ikuti Langkah 4 untuk menyertakan nilai tag dalam konteks, dan tandai versi lama sebagai superseded dalam isi.
Unggah mengembalikan 400 No OSS document can be registered.Setiap file dalam batch dideduplikasi berdasarkan nama. Ubah nama file atau hapus data lama terlebih dahulu.
Pengambilan mengembalikan 404 Knowledge base version ... does not existBelum ada versi yang dipublikasikan, atau knowledge_base_version tidak sesuai dengan nomor versi aktual.
Tombol Publish Version berwarna abu-abu, tetapi halaman menunjukkan perubahan tertundaJumlah versi yang dipublikasikan telah mencapai batas 3. Arahkan kursor ke tombol untuk melihat petunjuk. Hapus versi lama di catatan versi, lalu publikasikan.
Anda ingin menampilkan tag dalam jawaban, tetapi field tags dari hasil pengambilan kosongHasil pengambilan tidak mengisi kembali nilai tag. Ikuti Langkah 4 untuk mencarinya dari documents.jsonl.
Setelah menambahkan tag, definisi tag asli menghilangKotak dialog manajemen tag disimpan secara keseluruhan. Buka kembali kotak dialog, tunggu hingga daftar selesai dimuat, lalu tambahkan kembali definisi tag yang hilang. Nilai tag yang telah ditulis ke data tidak terpengaruh.