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/completionsbeserta 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 tag | Deskripsi | Contoh nilai |
| department | Departemen yang memiliki kebijakan | Finance, Administration, IT |
| docType | Jenis dokumen | Policy, Process |
| effectiveDate | Tanggal berlaku | 2026-01-01 |
Nilai tag menerima teks apa pun, sehingga Anda dapat langsung menggunakan nama departemen dan jenis dokumen.
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
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.Buat
documents.jsonldan 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"}}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
effectiveDatetidak ditambahkan ke prompt secara otomatis dan hanya disertakan setelah Anda menerapkan perubahan di Langkah 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:Atur
min_scoreke 0 dan ambil sejumlah hasil.Beri label relevansi hasil secara manual.
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 menyesuaikansemantic_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_scoremelakukan filter berdasarkan skor akhir ini setelah dihitung.Tanpa reranking,
semanticScoreadalah 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 denganscoreDetails. Menurunkan bobot tidak selalu menurunkan skor total; skor hanya turun jika semanticScore lebih tinggi daripada keywordScore untuk batch tersebut.tag_filter— Biarkanconditionskosong 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.
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.
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:
| Konfigurasi | Perilaku aktual |
op adalah operator lain, termasuk operator dalam daftar "Supported operators" dari error 400 Unsupported tag filter operator | Pengujian menunjukkan bahwa kondisi tersebut diabaikan diam-diam dan data lengkap tanpa filter dikembalikan. |
op adalah contains atau not contains | Ini hanyalah alias dari operasi himpunan in dan not in, bukan pencarian substring. Memberikan fragmen string menghasilkan 0 hasil. |
field adalah nama tag yang tidak didefinisikan | API tidak mengembalikan error dan hanya menghasilkan 0 hasil. |
op adalah alias seperti eq, ==, equal, atau like | API 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. Sesuaikansample_questionsdengan 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_filterdiconfig.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.jsonlUnggahan 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.
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.pyKirim 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, sepertidepartment=,docType=, daneffectiveDate=. Jika label hilang, verifikasi bahwadocumentNameyang dikembalikan oleh pengambilan sesuai dengan nama file didocuments.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.
| Gejala | Penyebab dan resolusi |
Pertanyaan mengembalikan 500, dan log menunjukkan 400 Unsupported tag filter operator | op menggunakan alias seperti eq, ==, atau like. Gunakan =, in, atau not in sebagai gantinya. |
| Setelah menambahkan filter tag, jumlah hasil persis sama seperti tanpa filter | Anda 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 hasil | Ejaan 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 baru | Chunk 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 exist | Belum ada versi yang dipublikasikan, atau knowledge_base_version tidak sesuai dengan nomor versi aktual. |
| Tombol Publish Version berwarna abu-abu, tetapi halaman menunjukkan perubahan tertunda | Jumlah 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 kosong | Hasil pengambilan tidak mengisi kembali nilai tag. Ikuti Langkah 4 untuk mencarinya dari documents.jsonl. |
| Setelah menambahkan tag, definisi tag asli menghilang | Kotak 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. |