阿里雲 Milvus 知識庫可以把公開法規、裁判文書與企業合規制度建成可檢索的法律資料助手:按案情檢索相似案例、歸納裁判觀點,並展示原文來源。
方案說明
整體鏈路與通過阿里雲Milvus知識庫搭建智能客服問答應用完全一致:控制台定義標籤 → 按標籤大量匯入資料 → 發布版本 → SDK 檢索(可按標籤過濾)→ 大模型產生帶來源標註的回答 → Flask 提供問答頁面。工程代碼(kb_client.py、upload.py、app.py、templates/index.html、start.sh)請直接複用該文,本文只說明法律情境需要改動的部分:案例標籤(含數實值型別標籤)、檢索參數、提示詞約束,以及必須補充的空結果處理。
建議第一版只選擇一個罪名或一個合規主題的 10~50 篇材料,驗證後再擴大範圍。整體耗時約 25~40 分鐘,其中文檔解析耗時取決於資料數量與大小。
本方案是資料檢索協助工具輔助,不產出法律意見。檢索結果與模型歸納都必須保留人工複核環節。
前提條件
已建立 Milvus 知識庫並記錄知識庫 ID(形如
kd-803ae9b10cc31)。已使用主帳號建立 RAM 使用者、勾選使用永久 AccessKey 訪問,並授予系統策略
AliyunMilvusFullAccess。已準備支援 OpenAI
chat/completions協議的大模型地址與 API Key。本地已安裝 Python 3.8 或以上版本,並已按上文教程建好工程目錄。
已完成資料的授權與脫敏檢查,詳見法律情境注意事項。
步驟一:定義案例標籤
在知識庫詳情頁的基本資料下方單擊標籤 > 管理,添加以下四個標籤。欄位類型在標籤名輸入框右側的下拉框中選擇,可選 string、int64、list、float32、bool。
把裁判年份定義為 int64 並不能用於範圍查詢。檢索介面目前不支援整型範圍運算式,定義為 int64 的作用是服務端會把字串數字轉換成整數,從而讓 =、in、not in 正常工作。因此「近三年的案例」這類需求只能由用戶端先算出年份列表,再用 in 傳入,例如 [2024, 2025, 2026];不要在樣本中使用 ≥ 或 ≤。年份跨度很大時沒有等價的高效寫法,需要拆成多次查詢。
標籤名 | 欄位類型 | 說明 | 樣本值 |
docType | string | 資料類型 | 裁判文書、法規、合規制度 |
court | string | 審理法院 | 某某市第一人民法院 |
caseType | string | 案由 | 合約詐騙、交通肇事 |
judgmentYear | int64 | 裁判年份 | 2025 |
標籤管理對話方塊是整體儲存的。對話方塊開啟後標籤列表為非同步載入,請等到已有標籤全部顯示出來,再添加新標籤並單擊完成;否則可能以"空列表 + 新標籤"整體覆蓋,導致已有標籤定義被清除。
關於標籤類型與取值,有兩點需要注意:
int64類型的標籤,在documents.jsonl中可直接寫 JSON 數字(如2025),過濾時value傳數字或字串均可命中。標籤值允許為空白字串。法規、合規制度沒有審理法院,可寫
"court": "",控制台會顯示為court=,且後續可用court = ""作為過濾條件精確命中這類資料。
步驟二:準備資料與匯入清單
把資料放進
documents/目錄,支援 PDF、DOCX、Markdown、TXT 等格式。案號、法院、裁判日期應保留在本文或檔案名稱中——實測把案號寫在本文首行後,可以用案號直接檢索到對應文書。建立
documents.jsonl,為每篇資料標註資料類型、法院、案由與裁判年份。{"path": "documents/criminal-case-001.md", "metadata": {"docType": "裁判文書", "court": "某某市第一人民法院", "caseType": "合約詐騙", "judgmentYear": 2025}} {"path": "documents/criminal-case-002.md", "metadata": {"docType": "裁判文書", "court": "某某市第二人民法院", "caseType": "合約詐騙", "judgmentYear": 2023}} {"path": "documents/law-excerpt.md", "metadata": {"docType": "法規", "court": "", "caseType": "刑事", "judgmentYear": 2024}} {"path": "documents/compliance-policy.md", "metadata": {"docType": "合規制度", "court": "", "caseType": "合規", "judgmentYear": 2024}}裁判文書需要保留案情、裁判理由與結論的上下文,可在知識庫詳情頁的處理策略中單擊建立策略調整切片粒度。最大分段長度的單位是字元(預設 512),建議設定為 770~1150 字元(約相當於 512~768 tokens),盡量讓"爭議焦點 + 裁判理由"落在同一個切片內。
建議同一案由下同時匯入結論不同的案例。法律檢索的價值恰在於呈現分歧:實測匯入兩份結論相反的合約詐騙判決後,模型會同時引用並明確指出"一案認定構成共同犯罪,另一案因缺乏通謀證據不認定",比只匯入單一結論的資料更有參考價值。
步驟三:配置檢索參數與提示詞
在 config.json 中按法律情境調整 aliyun.knowledge_base_version、retrieval 與 scenario。
{
"aliyun": {
"knowledge_base_version": "LATEST_PUBLISHED"
},
"retrieval": {
"page_size": 8,
"candidate_count": 80,
"min_score": 0.25,
"semantic_weight": 0.4,
"enable_query_expansion": true,
"rerank_model_name": "qwen3-rerank",
"tag_filter": {
"relation": "and",
"conditions": [
{"field": "docType", "op": "=", "value": "裁判文書"}
]
}
},
"scenario": {
"title": "法律與合規案例檢索",
"system_prompt": "你是法律資料檢索助手,不提供最終法律意見。只依據檢索資料歸納事實、爭議焦點、裁判觀點和依據,逐項標註[來源N];不同案例結論不一致時分別陳述;檢索資料為空白或與問題無關時,只回複“資料不足,建議人工複核”,禁止引用任何未出現在檢索資料中的法律法規、司法解釋或案例。",
"image_enabled": false,
"sample_questions": [
"虛構履約能力騙取貨款時,如何判斷合約詐騙共同犯罪?",
"交通肇事後自首對量刑有哪些影響?",
"哪些案例討論了主犯和從犯的區分?"
]
}
}參數說明:
semantic_weight=0.4:法律檢索大量使用案號、罪名與法律術語,語義權重調低、關鍵詞權重相應提高。實測用完整案號提問可精確命中對應文書。可通過檢索結果中的scoreDetails(含keywordScore與semanticScore兩項)校準該值。candidate_count=80並啟用qwen3-rerank:擴大候選集後由重排模型做類案相關性排序。需注意重排分數與向量分數不是同一量綱,與min_score疊加時可能過濾掉一部分結果,調參時建議先固定其中一項。knowledge_base_version建議保持LATEST_PUBLISHED,詳見下方說明。
版本號碼不要寫死
LATEST_PUBLISHED 表示自動使用最新的發行版本。也可以填寫明確的版本號碼(如 v2)來鎖定版本。合規情境通常需要追溯「哪一版資料支撐了哪次判斷」,建議在應用的調用日誌中記錄本次實際使用的版本號碼。刪除某個版本後,該版本會立即不可檢索(後台再非同步清理資料),因此刪除前必須先把仍鎖定它的應用程式切換到新版本。此外:
同時最多隻能存在 3 個發行版本。達到上限後發布版本按鈕會置灰,而頁面仍會顯示"當前有 N 條待發布變更",需要先在版本記錄中刪除不再需要的舊版本。一旦刪除了應用正在使用的版本,檢索會立即返回 404 Knowledge base version ... does not exist,頁面上表現為每次提問都失敗。因此若要鎖定版本,必須同時建立"刪除舊版本前先更新配置"的流程。
標籤過濾只能使用三個運算子
實測在目前的版本中,tag_filter.conditions 裡的 op 只有 =、in、not in 會真正生效:
運算子 | 行為 | 樣本 |
| 精確匹配, |
|
| 枚舉匹配 |
|
| 排除枚舉 |
|
| 條件被忽略,返回全部資料(不報錯) | — |
| 條件被忽略,返回全部資料 | — |
| 是 | — |
傳入上表中不生效的運算子時,介面不會報錯,而是返回未經過濾的全部資料。在法律情境下這意味著本應被排除的案例也會進入大模型上下文,且從頁面上看不出異常。因此:
不要用
>、≥做年份區間篩選,請改用in枚舉年份,例如{"field": "judgmentYear", "op": "in", "value": [2023, 2024, 2025]}。不要用
empty判斷標籤為空白,請改用{"field": "court", "op": "=", "value": ""}。配置好過濾條件後,務必與不加過濾的結果對比總條數,確認過濾確實生效;若兩者相同,說明該條件未被應用。
若
op寫成eq、==、like等別名,會返回400 Unsupported tag filter operator,導致每次提問都失敗。注意該報錯資訊中列出的 "Supported operators" 包含上表中不生效的運算子,不能作為可用清單。
必須處理"檢索結果為空白"的情況
複用的 app.py 中,llm_answer() 在檢索結果為空白時仍會調用大模型,此時上下文為空白字串,模型會完全依據自身知識作答。實測提問知識庫未覆蓋的問題(如"智慧財產權侵權的賠償數額如何計算"),模型輸出了大段賠償計算規則,並偽造了 [來源1:《…懲罰性賠償的解釋》第2條] 這樣的來源標註,而此時 sources 為空白。法律情境下這類輸出極具誤導性,必須在代碼層攔截:
def llm_answer(question: str, results: list[dict[str, Any]]) -> str:
if not LLM.get("enabled", True):
return "大模型未啟用;請查看下方檢索結果。"
if not results:
return "知識庫中沒有檢索到與該問題相關的資料,無法作答。建議補充相關材料後重試,或轉人工複核。"
...僅靠提示詞約束並不可靠——即使 system_prompt 已寫明"資料不足時明確說明",模型仍會作答。上述兜底加入後,未覆蓋的問題會穩定返回提示,且對有檢索結果的正常提問沒有影響。
步驟四:上傳、發布與驗證
上傳資料(
MetaFields對整批生效,指令碼會先按標籤分組再分批提交)。python upload.py --manifest documents.jsonl到控制台資料管理頁確認資料狀態為處理完成。上傳介面返回成功僅表示已提交非同步解析。
在版本管理頁單擊發布版本,完成嚮導後確認新版本狀態為發行。若按鈕置灰,請先刪除不再需要的舊版本(注意上文關於版本上限的說明)。
啟動服務並驗證。
python app.pycurl -sS http://127.0.0.1:7860/api/ask \ -H 'Content-Type: application/json' \ -d '{"question":"虛構履約能力騙取貨款時,如何判斷合約詐騙共同犯罪?"}'
按以下五條驗收:
頁面能正常開啟,提交問題後同時返回答案與檢索來源。
回答中的
[來源N]能在下方來源區找到對應的資料切片。用完整案號提問,能精確命中對應的裁判文書。
提問知識庫未覆蓋的內容時,返回"資料不足"提示,且不出現任何法條引用。這一條務必實測,是本情境最關鍵的驗收項。
補充資料並重新發布版本後,頁面能檢索到新內容。
法律情境注意事項
只使用有權公開和處理的資料,上傳前完成授權檢查。裁判文書如包含個人資訊,應先脫敏——資料切片會作為上下文發送給大模型,屬於資料出域。
頁面應有常駐免責聲明。樣本頁面唯寫了"回答由發行知識庫內容產生",建議改為明確提示"本結果僅為資料檢索輔助,不構成法律意見,請由專業人員複核"。
同案由下保留結論不同的案例,並在提示詞中要求分別陳述,避免模型把個案結論表述為通則。
按資料類型建立獨立入口。例如對外諮詢入口用
docType = 法規限定只檢索公開法規,內部研判入口再放開裁判文書。檢索結果中的
tags欄位不會回顯寫入的法院與裁判年份,它與AddDocuments的 MetaFields 是兩個不同的欄位,也沒有參數可以開啟返回,為空白不代表上傳失敗。需要在回答中標註這些資訊時,按檢索結果的documentId關聯documents.jsonl後再拼進上下文。線上部署不要繼續使用 Flask 程式開發伺服器,應改用生產 WSGI,並補充密鑰管理、鑒權、審計與限流。
常見問題
現象 | 原因與處理 |
每次提問都返回 | 配置中寫死的版本號碼已被刪除或從未發布。改用 |
提問返回 500,日誌顯示 |
|
加了標籤過濾但結果條數與不加過濾時完全一樣 | 使用了不生效的運算子(如 |
按年份區間篩選沒有效果 | 數值比較子當前不生效,請用 |
按標籤過濾後總是 0 條 | 標籤名拼字與寫入時不一致(介面不會報錯,只返回 0 條),在知識庫詳情頁 → 標籤 → 管理中核對;另外 |
問了知識庫裡沒有的問題,卻得到了看似規範的法條引用 |
|
檢索結果的 | 目前的版本不回填標籤,需自行用 manifest 反查。 |
上傳返回 | 整批檔案都因同名被去重。修改檔案名稱或先在控制台刪除舊資料。 |
檢索時報"失敗:None" | 複用代碼中 |
啟用重排後結果反而變少 | 重排分數與向量分數量綱不同,與 |