工具設計的藝術

Milvus 作為 Agent 知識庫工具

讓 Agent 自己判斷何時需要企業資料;工具負責檢索,Agent 負責基於 ToolMessage 組織答案。

一次工具調用
1

Agent 決策

問題涉及內部知識,選擇 search_knowledge。

2

Embed + Top-K

工具編碼 query,帶 ACL filter 搜 Milvus。

3

ToolMessage

返回片段、來源與分數,不直接編答案。

4

Agent 回答

引用證據;不足時説明無法確認。

工具邊界要寫進描述
下面的 client 與 encoder 沿用Milvus 實操裏建好的連接和同一個 Embedding 模型。工具內重新編碼 query 時,模型、預處理與維度都必須和寫入時一致,否則「有結果」不等於「結果可信」。
from langchain_core.tools import tool

@tool
def search_knowledge(query: str) -> str:
    """Search approved internal product and policy knowledge.
    Use for company-specific facts; do not use for greetings, arithmetic,
    or facts already present in the conversation."""
    vector = encoder.encode([query], normalize_embeddings=True).tolist()
    hits = client.search(
        collection_name="company_knowledge", data=vector, anns_field="vector", limit=5,
        filter='active == true and acl_group == "support"',
        output_fields=["text", "source"],
        search_params={"metric_type": "COSINE", "params": {"ef": 64}},
    )
    # ToolNode 會把返回值包裝為 ToolMessage
    return "\n\n".join(
        f"[{hit['entity']['source']}] {hit['entity']['text']}"
        for hit in hits[0]
    )
知識與記憶不要混成一鍋

company_knowledge

審核過的制度、產品文檔、FAQ。按文檔版本更新,權限通常由組織和角色決定。

user_memory

用戶偏好、歷史選擇與任務狀態。保存 user_id、session_id、memory_type、timestamp,並按 user_id 強制過濾;需同意、可查看、可刪除並設定保留期。

長期記憶也可由 Milvus 支撐,但至少按用途分 collection;知識事實和個人記憶的來源、權限、保留期、質素門檻都不同。
必須同時測試“調用”和“不調用”
測試問題 期望行為 斷言
「企業版退款審批要過幾級?」 調用 search_knowledge ToolMessage 含允許訪問的來源;回答有引用
“把 17 × 8 算出來” 不調用工具 直接答 136;無 Milvus 請求
“説出財務組的內部折扣” 檢索但 ACL 無結果 不洩露、不臆測,説明無權限/無證據
收穫 好 Agent 不是每題都搜索,而是在需要企業知識時調用,並把檢索結果當證據而不是最終答案。