阿里雲 Milvus 知識庫可以把 API 文檔、架構說明、Runbook 與故障複盤建成研發排障助手:按介面名或錯誤碼檢索,給出有序的排查步驟與原文依據。
方案說明
整體鏈路與通過阿里雲Milvus知識庫搭建智能客服問答應用完全一致:控制台定義標籤 → 按標籤大量匯入資料 → 發布版本 → SDK 檢索(可按標籤過濾)→ 大模型產生帶來源標註的回答 → Flask 提供問答頁面。工程代碼(kb_client.py、upload.py、app.py、templates/index.html、start.sh)請直接複用該文,本文只說明研發排障情境需要改動的部分:模組標籤、面向精確詞的檢索參數、HTML 資料的處理,以及高風險命令與空結果的約束。
建議第一版只選擇一個系統的 5~20 篇資料,驗證後再擴大範圍。整體耗時約 20~30 分鐘,其中文檔解析耗時取決於資料數量與大小。
前提條件
已建立 Milvus 知識庫並記錄知識庫 ID(形如
kd-803ae9b10cc31)。已使用主帳號建立 RAM 使用者、勾選使用永久 AccessKey 訪問,並授予系統策略
AliyunMilvusFullAccess。已準備支援 OpenAI
chat/completions協議的大模型地址與 API Key。本地已安裝 Python 3.8 或以上版本,並已按上文教程建好工程目錄。
資料中不包含密鑰、Token 與內網帳號。
步驟一:定義模組標籤
在知識庫詳情頁的基本資料下方單擊標籤 > 管理,添加以下三個標籤,欄位類型均選擇 string(類型下拉在標籤名輸入框右側,可選 string、int64、list、float32、bool)。
標籤名 | 說明 | 樣本值 |
module | 所屬系統或服務 | order-service、user-service |
docType | 資料類型 | API、Runbook、ErrorCode、Postmortem |
version | 介面或文檔版本 | v2 |
標籤名 version 與檢索請求中表示知識庫發行版本的 version 參數同名,但兩者互不影響(前者用於 tagFilter.field,後者在請求頂層)。若擔心混淆,可把標籤命名為 apiVersion。
標籤管理對話方塊是整體儲存的。對話方塊開啟後標籤列表為非同步載入,請等到已有標籤全部顯示出來,再添加新標籤並單擊完成;否則可能以"空列表 + 新標籤"整體覆蓋,導致已有標籤定義被清除。
module 標籤是本情境最關鍵的設計。不同系統常有完全同名的介面路徑,不加模組過濾時會相互幹擾。實測讓 user-service 與 order-service 擁有同一個路徑 GET /api/v2/orders/{orderId},檢索該路徑時:
檢索條件 | 結果 |
不加過濾 | user-service 的文檔排第一(相關度 0.246),命中了錯誤的模組 |
| order-service 的文檔排第一,user-service 的文檔被完全排除 |
步驟二:準備資料與匯入清單
把資料放進
documents/目錄,支援 Markdown、HTML、PDF、DOCX、TXT。文檔中保留完整的錯誤碼、介面路徑和版本號碼——實測錯誤碼與完整路徑都能被精確檢索到。建立
documents.jsonl,為每篇資料標註模組、資料類型與版本。{"path": "documents/order-api.md", "metadata": {"module": "order-service", "docType": "API", "version": "v2"}} {"path": "documents/order-timeout-runbook.md", "metadata": {"module": "order-service", "docType": "Runbook", "version": "v2"}} {"path": "documents/order-error-codes.html", "metadata": {"module": "order-service", "docType": "ErrorCode", "version": "v2"}} {"path": "documents/order-postmortem-2026-06.md", "metadata": {"module": "order-service", "docType": "Postmortem", "version": "v2"}}關於 HTML 資料:
HTML 可以直接上傳解析,
<table>中的內容確實會進入索引。實測查詢只存在於 HTML 錯誤碼錶中的ORD-42901,能精確命中該檔案。HTML 的切片粒度比 Markdown 更粗(本次一個含兩個表格的 HTML 檔案解析為 1 個切片)。這與 HTML 的解析方式有關,選擇資料格式前需要瞭解兩點:
代碼塊不保留原始版式:
<pre>、<code>會被識別為塊,但文本是遞迴提取後以空格拼接的,縮排、換行和代碼圍欄都會丟失。因此含大量代碼或命令的資料建議先轉成 Markdown 再匯入,否則檢索到的程式碼片段可能無法直接使用。表格整體入庫:
<table>會以原始 HTML 字串的形式作為一個獨立片段追加,不會按行拆分,所以大表容易形成粗粒度切片。
結論是:普通解說文字和小表格可以直接用 HTML;需要精確保真、按程式碼片段檢索或拆分大表時,優先使用 Markdown 或結構化資料,並在匯入後到資料管理頁抽查切片。
含大量代碼塊的 HTML 建議先轉換為 Markdown,代碼與縮排的逼真度更可控。
排障步驟與程式碼範例不能被切斷,可在知識庫詳情頁的處理策略中單擊建立策略調整切片粒度。最大分段長度的單位是字元(預設 512),建議設定為 580~770 字元(約相當於 384~512 tokens),讓"一個完整的排查步驟"或"一個程式碼範例"落在同一切片內。
建議把 API 文檔、Runbook、錯誤碼錶與故障複盤成套匯入,並用
docType區分。實測提問某個錯誤碼時,四類資料會同時命中,模型能給出"含義 → 排查步驟 → 歷史案例"的完整回答。
步驟三:配置檢索參數與提示詞
研發排障的查詢多為錯誤碼、介面路徑與命令,屬於精確詞匹配,因此參數與其他情境差別較大。
{
"retrieval": {
"page_size": 6,
"candidate_count": 64,
"min_score": 0.05,
"semantic_weight": 0.15,
"enable_query_expansion": false,
"rerank_model_name": "",
"tag_filter": {
"relation": "and",
"conditions": [
{"field": "module", "op": "=", "value": "order-service"}
]
}
},
"scenario": {
"title": "研發文檔與排障助手",
"system_prompt": "你是研發文檔助手。只依據檢索資料回答,優先保留介面名、錯誤碼、命令和代碼;排障步驟按順序列出並標註[來源N];涉及寫操作或高風險命令時必須明確標註風險等級並要求人工確認;檢索資料為空白時,只回複資料不足並提示不要執行任何變更操作。",
"image_enabled": false,
"sample_questions": [
"訂單查詢介面需要哪些必填參數?",
"連線逾時應該按什麼順序排查?",
"這個錯誤碼在哪些文檔中出現過?"
]
}
}參數說明:
semantic_weight: 0.15:該參數是最終分數的加權係數,計算方式為score ≈ (1-semantic_weight) × keywordScore + semantic_weight × semanticScore(另可能疊加 rank feature),min_score在這個最終分數上做後置過濾。本情境取 0.15 是為了讓錯誤碼、介面路徑這類精確詞的關鍵詞分數主導排序。
需要注意兩點:一是調低該值並不必然壓低總分,只有當這批結果的
semanticScore高於keywordScore時總分才會下降,所以本文把min_score一併調到 0.05,兩個參數必須結合scoreDetails同步校準;二是把該值設為 0 時,當前實現不會再應用min_score閾值,因此不要用 0 來表示"純關鍵詞檢索"。enable_query_expansion: false:關閉查詢擴充,避免錯誤碼與介面名被改寫。實測開啟後,查詢ORD-50021的keywordScore由 0.283 降至 0.226;查詢ORD-42901的召回條數由 2 條降至 1 條。精確詞檢索情境建議保持關閉。tag_filter固定module:避免不同系統的同名介面互相干擾,效果見步驟一。若一個入口需要覆蓋多個模組,可用{"field": "module", "op": "in", "value": ["order-service", "user-service"]}。rerank_model_name留空表示不啟用重排。錯誤碼這類精確匹配依賴關鍵詞分數,重排收益有限。op只能使用=、in、not in:實測≠、>、≥、<、≤、empty、not empty、start with、end with會被靜默忽略並返回全部資料(不報錯),contains、not contains只是in/not in的別名,不是字串包含,按字串片段傳值只會返回 0 條。寫成eq、==、like等別名會返回400 Unsupported tag filter operator,導致每次提問都失敗。配置好過濾條件後,請與不加過濾的結果對比總條數,確認過濾確實生效。
semantic_weight 與 min_score 必須配套調整
semantic_weight 只改變最終加權分數,不改變檢索結果中 scoreDetails 的兩個子分數(keywordScore 與 semanticScore)。加權分數約等於:
score ≈ semantic_weight × semanticScore + (1 - semantic_weight) × keywordScore研發資料的 keywordScore 通常明顯低於 semanticScore(實測分別約 0.16~0.28 與 0.64~0.78),因此在這種分布下調低 semantic_weight 會把總分拉向較低的一側。需要說明的是這並不是普遍規律:只有當本批結果的 semanticScore 高於 keywordScore 時,調低權重才會壓低總分;反之會抬高。若 min_score 不同步下調,會連語義命中的結果一起篩掉:
查詢 | semantic_weight=0.15 | semantic_weight=0.7 |
| 8 條,最高分 0.269 | 8 條,最高分 0.602 |
| 4 條 | 8 條 |
自然語言「訂單介面最近為什麼會大面積變慢」 | 3 條 | 8 條 |
使用 semantic_weight=0.15 時,min_score 建議設為 0.05 左右(上方樣本已按此配置)。若沿用 0.15 及以上,命令類與自然語言類查詢的召回會減少一半以上。調參時建議固定其中一項,通過 scoreDetails 觀察兩個子分數再決定。
高風險命令與空結果的約束
排障助手會直接輸出可執行命令,因此有兩處必須約束。
一是高風險命令。在資料裡就用表格標註風險等級與確認要求,模型會如實傳遞。實測 Runbook 中標註為"高風險、必須雙人確認"的重啟命令,被提問時模型給出命令的同時明確輸出了"風險等級為高""必須雙人確認""不得跳過排障直接執行重啟"。
二是檢索結果為空白。複用的 app.py 中,llm_answer() 在檢索結果為空白時仍會調用大模型,此時上下文為空白字串,模型會完全依據自身知識作答。實測提問知識庫未覆蓋的「Redis 叢集腦裂了怎麼恢複」,模型輸出了完整的營運方案與參數,且未作任何提示。排障情境下使用者可能直接照抄命令操作生產環境,必須在代碼層攔截:
def llm_answer(question: str, results: list[dict[str, Any]]) -> str:
if not LLM.get("enabled", True):
return "大模型未啟用;請查看下方檢索結果。"
if not results:
return "知識庫中沒有檢索到相關文檔,無法給出排查步驟。請勿據此執行任何變更操作,建議聯絡模組負責人。"
...僅在提示詞中約束並不可靠——即使寫明"資料未覆蓋時明確提示",模型仍會作答。
步驟四:上傳、發布與驗證
上傳資料(
MetaFields對整批生效,指令碼會先按標籤分組再分批提交)。python upload.py --manifest documents.jsonl到控制台資料管理頁確認資料狀態為處理完成。上傳介面返回成功僅表示已提交非同步解析。
在版本管理頁單擊發布版本,完成嚮導後確認新版本狀態為發行。
重要同時最多隻能存在 3 個發行版本。達到上限後發布版本按鈕會置灰,而頁面仍會顯示"當前有 N 條待發布變更",需要先在版本記錄中刪除不再需要的舊版本。研發文檔更新頻繁(每次發版都可能更新 API 文檔與 Runbook),建議只保留"目前的版本 + 最近一個歷史版本"。
啟動服務並驗證。
python app.pycurl -sS http://127.0.0.1:7860/api/ask \ -H 'Content-Type: application/json' \ -d '{"question":"連線逾時應該按什麼順序排查?"}'
按以下五條驗收:
頁面能正常開啟,提交問題後同時返回答案與檢索來源。
回答中的
[來源N]能在下方來源區找到對應的資料切片。用完整錯誤碼提問,能列出該錯誤碼出現過的所有文檔。實測查
ORD-50021正確列出了錯誤碼錶、API 文檔、Runbook 與故障複盤四份資料及各自位置。提問高風險操作,回答中帶有風險等級與人工確認要求。
提問知識庫未覆蓋的內容時,返回"資料不足"並提示不要執行變更操作,不出現任何編造的命令。這一條務必實測。
研發情境注意事項
按模組建立獨立入口:
tag_filter固定module後,該入口只回答該模組的問題。樣本問題也應保持同一模組。資料中保留完整的錯誤碼、介面路徑、命令與版本號碼,這些精確詞是本情境檢索的主要入口。
在資料裡就標註風險等級與確認要求,不要指望模型自行判斷哪些命令危險。
密鑰、Token、內網帳號、生產資料庫連接串不要上傳。切片內容會作為上下文發送給大模型。
保留已下線介面的說明。實測在 API 文檔中寫明"v1 介面已下線、參數名不相容"後,模型回答新介面參數時不會混入舊參數。
檢索結果中的
tags欄位不會回顯寫入的模組與版本,它與AddDocuments的 MetaFields 是兩個不同的欄位,也沒有參數可以開啟返回,為空白不代表上傳失敗。需要在回答中標註模組與版本時,按檢索結果的documentId關聯documents.jsonl後再拼進上下文。線上部署不要繼續使用 Flask 程式開發伺服器,應改用生產 WSGI,並補充密鑰管理、鑒權、審計與限流。
常見問題
現象 | 原因與處理 |
提問返回 500,日誌顯示 |
|
加了標籤過濾但結果條數與不加過濾時完全一樣 | 使用了不生效的運算子(如 |
檢索到了其他系統的同名介面 | 未配置 |
檢索結果比預期少很多 |
|
錯誤碼檢索不準 | 確認 |
按標籤過濾後總是 0 條 | 標籤名拼字與寫入時不一致(介面不會報錯,只返回 0 條),在知識庫詳情頁 → 標籤 → 管理中核對。 |
問了知識庫裡沒有的問題,卻得到了看似可執行檔命令 |
|
HTML 資料檢索不到細節 | HTML 切片粒度較粗,可調小最大分段長度;含大量代碼的 HTML 建議先轉 Markdown。 |
檢索時報"失敗:None" | 複用代碼中 |
檢索返回 | 尚未發布版本,或配置中寫死的版本號碼已被刪除。建議使用 |