🚀 RiMCP_hybrid
這個項目提供了一套面向 RimWorld 源代碼與 XML 定義的檢索與導航工具。其核心目標是結合詞法檢索、語義檢索和圖結構導航,構建一個可被 AI 助手調用的服務。該項目既可以作為命令行工具使用,也能以 MCP 服務器的形式集成到 Claude Desktop 或 VS Code Copilot 等助手中。當前源碼實現了索引構建、混合檢索策略、跨層圖關係以及完整源碼定位與返回等功能。
🚀 快速開始
要啟動這個系統用於交互或集成,可直接運行 MCP 服務器組件,服務進程以標準輸入輸出或 JSON - RPC 協議暴露接口,外部的 AI 助手能向其發送檢索與導航請求並接收結構化響應。也可在命令行模式下運行各個工具命令來進行索引構建、混合檢索或圖查詢,便於離線測試和腳本化使用。
構建或更新索引
生成倒排索引、向量嵌入和圖關係數據。
- 最小索引構建命令(在項目根或 RimWorldCodeRag 目錄下運行):
cd src\RimWorldCodeRag
dotnet run -- index --root "..\..\RimWorldData"
cd src\RimWorldCodeRag
dotnet run -- index --root "..\..\RimWorldData" --python-batch 128 --embedding-server "http://127.0.0.1:5000"
cd src\RimWorldCodeRag
dotnet run -- index --root "..\..\RimWorldData" --embedding-server "http://127.0.0.1:5000"
- 新增功能:使用遠程嵌入 API(例如 OpenAI):
cd src\RimWorldCodeRag
dotnet run -- index --root "..\..\RimWorldData" --embedding-server "https://api.openai.com/v1/embeddings" --api-key "sk-1234567890abcdefghijklmnopqrstuvwxyz" --model-name "text-embedding-3-small"
- 帶強制重建(忽略增量判斷,重新構建全部索引):
--force 參數現在支持更精細的控制,可以指定重建索引的特定部分,從而節省時間。
cd src\RimWorldCodeRag
dotnet run -- index --root "..\..\RimWorldData" --force all --embedding-server "http://127.0.0.1:5000" --python-batch 512
cd src\RimWorldCodeRag
dotnet run -- index --root "..\..\RimWorldData" --force lucene
cd src\RimWorldCodeRag
dotnet run -- index --root "..\..\RimWorldData" --force embed --embedding-server "http://127.0.0.1:5000" --python-batch 512
cd src\RimWorldCodeRag
dotnet run -- index --root "..\..\RimWorldData" --force graph
注意:--force 強制清空/刷新已有索引並從頭構建,適用於修復字段存儲或切分規則變更後的完全重建。常規更新可去掉 --force 以啟動增量構建,更快且保留未變更的數據。
提示:最佳 batch 大小和 vram 有關。在 Geforce rtx4060 laptop + 16gb vram 上,256 ~ 512 的 batch 大小比較合適。超過這個值會導致部分數據被動態遷移至 CPU,極大降低嵌入效率。可多試驗幾次,找到最佳 batch 大小。
提示:使用 --embedding-server 可以連接到已運行的嵌入服務器,避免每次批次重新加載模型的開銷。需要先運行嵌入服務器:.\scripts\start-embedding-server.ps1
CLI 查詢命令
cd src\RimWorldCodeRag
dotnet run -- rough-search --query "weapon gun" --kind def --lexical-k 2000 --max-results 10
- 查找某個符號使用(返回該符號引用的其他符號,用
--kind 限制層):
dotnet run -- get-uses --symbol "xml:Gun_Revolver" --kind csharp
dotnet run -- get-used-by --symbol "RimWorld.CompProperties_Power" --kind xml
- 獲取完整源碼(按符號返回原始文件片段,可附帶行數限制):
dotnet run -- get-item --symbol "RimWorld.Building_Door" --max-lines 200
dotnet run -- get-item --symbol "xml:Door"
常用參數說明
--kind 支持 csharp/cs 或 xml/def,用於只在某一層(C# 或 XML)查詢
--max-results 控制返回候選數,--max-lines 控制源碼返回行數上限
✨ 主要特性
- 提供面向 RimWorld 源代碼與 XML 定義的檢索與導航工具。
- 結合詞法檢索、語義檢索和圖結構導航,構建可被 AI 助手調用的服務。
- 既可以作為命令行工具使用,也能以 MCP 服務器的形式集成到其他助手中。
- 實現了索引構建、混合檢索策略、跨層圖關係以及完整源碼定位與返回等功能。
📦 安裝指南
MCP 服務器完整設置指南
前置要求
- .NET 8.0 SDK(從 microsoft.com/net 下載)
- Python 3.9+(從 python.org 下載)
- RimWorld 遊戲文件:從 RimWorld 安裝目錄複製 Def 數據:C:\Program Files (x86)\Steam\steamapps\common\RimWorld\Data;C# 源碼通過 ILSpy 或者 dnspy 導出,存進項目根目錄/RimWorldData
- 跨平臺支持:Windows (PowerShell)、Linux/macOS (Shell 腳本)
1. 設置項目結構
cd RiMCP_hybrid/
2. 設置嵌入環境(一次性,在構建前運行)
.\scripts\setup-embedding-env.ps1
./scripts/setup-embedding-env.sh
3. 構建項目
dotnet build
4. 構建索引(一次性,在實際服務前運行)
cd src/RimWorldCodeRag
dotnet run -- index --root "..\..\RimWorldData"
5. 啟動服務
.\scripts\start-embedding-server.ps1
./scripts/start-embedding-server.sh
cd src\RimWorldCodeRag.McpServer
dotnet run
MCP 服務器詳細配置
環境變量配置
在運行 MCP 服務器前設置這些變量:
$env:RIMWORLD_INDEX_ROOT = "c:\path\to\RiMCP_hybrid\index"
$env:EMBEDDING_SERVER_URL = "http://127.0.0.1:5000"
替代方案:appsettings.json 配置
編輯 src/RimWorldCodeRag.McpServer/appsettings.json:
{
"McpServer": {
"IndexRoot": "c:/path/to/RiMCP_hybrid/index",
"EmbeddingServerUrl": "http://127.0.0.1:5000"
}
}
💻 使用示例
第一次使用
先完整構建索引(無 --force 或用 --force 如果你想確保乾淨狀態),然後運行若干典型查詢確認結果。
代碼或解析規則更新後
如果只是少量文件改動,使用增量索引;若修改了切分或存儲字段,使用 --force 完整重建。
在將 MCP 服務交給 AI 助手前
在本地用 CLI 驗證常用查詢,確保 get-item 能返回正確源碼片段,並檢查圖查詢(get-uses/get-used-by)的結果合理性。
跨平臺支持
- Windows: 使用 PowerShell 腳本(
.ps1)
- Linux/macOS: 使用 shell 腳本(
.sh)
- 兩個平臺都支持相同的功能和參數
日常維護
把索引構建或增量更新放入 CI 流程中,關鍵分支變更後運行驗證腳本。
📚 詳細文檔
MCP 工具說明
- rough_search - 混合語義搜索:使用自然語言查詢搜索 RimWorld 代碼符號和 XML 定義。返回匹配項目名稱列表及元數據。隨後使用
get_item 工具獲取任何感興趣結果的完整源代碼。如果搜索沒有返回相關結果,請嘗試簡化查詢以聚焦基本關鍵詞。
- get_uses - 依賴分析(下游):查找符號依賴什麼 - 顯示調用關係和實現邏輯。非常適合通過追蹤使用了哪些其他代碼/符號來理解功能的工作原理。隨後使用
get_item 工具檢查任何感興趣依賴項的完整源代碼。
- get_used_by - 反向依賴分析(上游):查找什麼使用了符號 - 顯示反向依賴和調用關係。非常適合通過追蹤誰調用或引用了符號來理解影響範圍和使用模式。隨後使用
get_item 工具檢查任何感興趣調用者的完整源代碼。
- get_item - 精確源代碼檢索:檢索特定符號的完整源代碼和元數據。從
rough_search、get_uses 或 get_used_by 結果中找到感興趣的符號後使用此工具。返回完整的類定義、方法實現或 XML 定義及詳細元數據。
測試 MCP 服務器
基礎測試
cd src\RimWorldCodeRag.McpServer
.\test-mcp.ps1
./test-mcp.sh
手動 JSON - RPC 測試
dotnet run
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05"}}' | dotnet run
VS Code 集成
創建或編輯 %APPDATA%\Code\User\globalStorage\mcp-servers.json:
{
"mcpServers": {
"rimworld-code-rag": {
"command": "dotnet",
"args": [
"run",
"--project",
"c:/path/to/RiMCP_hybrid/src/RimWorldCodeRag.McpServer"
],
"env": {
"RIMWORLD_INDEX_ROOT": "c:/path/to/RiMCP_hybrid/index",
"EMBEDDING_SERVER_URL": "http://127.0.0.1:5000"
}
}
}
}
🔧 技術細節
思路介紹
項目主要分為三部分:索引構建管線,檢索工具,mcp 服務器相關。
索引構建管線
- 數據分類:索引過程從原始數據開始,原始數據主要包括 C# 源代碼文件和 XML 定義文件(Defs)。索引的目標是提取可檢索、可理解的最小單元,這些單元要保留足夠上下文以便閱讀,也應足夠小以便精確匹配和生成語義向量。第一步是掃描文件系統,逐文件讀取並分類,記錄文件路徑、編碼、時間戳等基礎元數據作為索引項的輸入標識。元素有類,函數,變量定義和 xmldef。
- 文本切分:讀取文件後,需把長文本切分成若干塊。對 C# 代碼,按語法符號切分,分片基於類、方法、屬性或註釋塊,同時記錄每個片段在源文件中的起止偏移,以便後續精確回溯。對 XML Def,通常保留整個定義節點的字符串表示為一個塊,因為 Def 本身語義相對獨立且自包含。切分時會生成每個塊的標題、摘要性片段和用於檢索的正文文本。切分策略會影響召回質量,塊過大可能導致上下文腐化,塊過小又可能丟失相關信息。
- 存儲層寫入:文本塊生成後,索引流程並行地把每個塊送入兩個不同的存儲層:用於傳統詞法檢索的倒排索引(用 Lucene 實現)和用於語義檢索的向量索引。寫入倒排索引時,會把塊的標題、類型、路徑、源偏移、標籤等結構化字段一起存儲,這些字段既支持過濾,也支持把結果定位回源文件。向量部分要求先把文本塊轉換成向量表示,這通常由外部的嵌入服務完成。項目對嵌入生成支持批量參數配置,以便在不同顯存或 CPU 條件下調整批處理大小。生成向量後,這些向量會被寫入向量索引,並與對應的塊 ID 建立映射。由於 C# 的 huggingface 支持不佳,專門起了一個 Python 服務器在後臺 127.0.0.1:5000 進行嵌入服務,這樣也能節省每次查詢時冷啟動的時間。項目用上了 .NET 的 SIMD 加速特性,通過
System.Numerics.Tensors 庫讓向量點積運算跑得飛快,在現代 CPU 上能發揮硬件並行計算的全部潛力。
- 圖關係構建:索引的另一個關鍵部分是圖關係構建。靜態分析器會在解析源碼與 XML 時尋找有意義的引用關係,如繼承、方法調用、字段引用、XML 到 C# 的綁定等。每發現一條關係,都會把它作為圖的有向邊寫入圖存儲。圖的節點和邊屬性存儲在 tsv 中,而額外使用了兩份(行和列)壓縮稀疏矩陣表示來存儲,這樣可以在 O(1) 時間寫入,讀取向下關係,讀取向上關係。同時,由於使用二進制 bit 存儲而不是完整的邊信息文本,把原先 b 樹數據庫的 6.2gb 大小壓縮到了 400mb。這些邊補充了文本相似度的不足,使得跨層查詢(如"哪些 Def 使用了這個 C# 組件")可以高效地回答。
檢索召回部分
- 檢索工具:檢索召回一共有四個工具:粗搜
rough_search,兩個方向的依賴樹搜索 uses,used_by,和整段代碼召回 get_item。核心思路是儘量減少無用源代碼塊的直接返回,以減少大模型上下文中的噪聲。大模型 agent 的典型搜索路徑是:先對一個問題粗搜,得到一個候選元素列表,然後大模型選擇最感興趣的元素名字,召回整塊代碼;或者通過 get_uses 和 get_used_by 找依賴關係,得到元素列表,選擇最感興趣的元素名字召回整塊代碼。
- 粗搜策略:粗搜分成兩步:先使用 Lucene 模糊搜索和 BM25 字面相似度排序對所有大約八萬個元素進行快速索引,選取最相似的 1000 個。然後對這 1000 個實施基於向量相似度的語義相似度打分,選出候選的五個內容。這種方式能保證快,並且並沒有想象中的那麼容易漏掉正確答案。一開始打算將字面相似度分數和向量語義相似度分數相加,但並沒有得到兩者各自的優點,反而使得噪聲淹沒了信息。
- 圖檢索設計:圖檢索沒什麼特別的設計,三個圖數據庫合在一起足夠快,同時每條邊屬性的註冊也能便利根據種類的結果預先篩選,減少噪音。測試時,曾因大模型搜索
Verse.Thing 的被引用關係,MCP 直接返回兩萬六千條數據,導致上下文溢出。後來重寫了返回內容的排序,確保排序穩定性,以此基礎做了一個簡單的分頁機制,用實際運行的請求次數和 token 量為代價確保了一些安全。
- 部署與性能:項目對嵌入生成與向量索引的批量大小提供了調整參數,用以在不同顯存與硬件配置下平衡速度與資源佔用。實際運行時,Lucene 的檢索延遲通常很小,而語義重排序和向量搜索會隨著候選集和向量模型大小有所變化,因此在資源受限的環境裡可以選擇關閉嵌入或調小批次來保證穩定運行。
後續迭代方向
- 檢索架構調整:雖然粗搜階段的 Lucene -> embedding 聽起來不錯,但實際測試發現,Lucene 篩掉的正確選項比預想中的更多。因此,決定放棄混合雙階段檢索的架構,直接採用全量向量檢索,相信 Faiss 可以提供足夠的算法加速。當然,Lucene 和 BM25 的重排並不是完全沒用,在剩餘三個工具中,由於輸入都需要是準確的元素名稱,很多時候會導致召回失敗,可以使用這一套高效快速的檢索和字面相似度評分替代原先的直接匹配,提供更多的魯棒性,提升 Agent 工作流中的流暢度。
- 權重算法設計:在測試
get_uses 和 get_used_by 工具時,發現由於關係提取太過細緻,Rimworld 的源碼又足夠複雜,提取上下游關係時有可能返回超大量數據,為大模型的判斷帶來了不少噪聲。因此,計劃設計一套權重算法,為圖的邊附上優先級權重,查詢依賴關係的結果按照倒序排序,就能更高概率將重要的鏈接排到前面,變相降低大模型獲得的信息中的噪聲。邊的權重也許會和邊的種類,節點的重要性指數(計劃使用經典的谷歌 Pagerank 算法),甚至可能有加權因子是由兩者名字的字面相似程度計算而來。但擔心這套權重算法由於是人工直觀設計,並不能反映理論上的重要性,甚至會對檢索效率產生負面優化。若尋求非人工設計的最優解加權方式,卻甚至無法定義問題所在,從算法角度更是無可下手。所以未來大量的實驗應該是避免不了的。
- 功能更新:
- v1.1.0 更新:遠程嵌入 API 的功能已經實現了。現在可以通過
--api-key 和 --model-name 參數來連接到像 OpenAI 這樣的外部嵌入服務了。感謝 asvc_33 大佬的貢獻!
- v1.1.2 更新:稍微改變了 bm25 的運行方式,現在 bm25 會在各元素代碼全文(而不是原先的元素名稱)中匹配字面相似度,這是更合理並且普遍的一種做法。經過試驗,其實大約是發揮了應有的效果,同時召回並不算慢。這樣看來,faiss 的必要性減弱了。
- v1.2.0 更新:給圖生成設計了一套邊的權重生成公式:
$$(Pr\cdot 10^7)\sqrt{d}\cdot w$$
其中 Pr 代表目標節點的 Pagerank 原始分數,d 代表同一個連接在這個元素中的出現次數,w 代表節點的屬性所自帶的權重(這個權重是自己編的,比如繼承為 2.0,函數調用為 0.7,並沒有什麼特別的依據)。$10^7$ 的目的是防止浮點數誤差,因為 Pr 值一般數量級都較小。
- **1.2.1 更新**:在不斷的實驗中發現圖生成目前有非常大的問題,比如會對父類的關係也全盤繼承導致返回大量結果,噪聲很大,同時會漏捕捉靜態成員和反射調用的情況(實際上 xml 和 c# 的連接大多數都是這種方式,然而此前全部漏分析了)。這需要對解析代碼的方式做出一些深度的重構,目前先修復了重複抓取邊的問題,將原先將近五千萬條邊降到了只有 23 萬條,是一個對可用性比較大的提升。
📄 許可證
這個項目遵循 MIT 協議,意味著代碼可以任意為太陽系內的所有生物自由使用。
相關文檔
- 實現詳情:
docs/ 目錄
- MCP 協議:https://modelcontextprotocol.io/
故障排查
MCP 服務器故障排查
- "Index not found" 錯誤:確保運行了索引構建步驟:
dotnet run -- index --root "..\..\RimWorldData";檢查 RIMWORLD_INDEX_ROOT 環境變量是否指向 index/ 文件夾。
- "Embedding server connection failed" 錯誤:先啟動嵌入服務器,Windows PowerShell 用
.\scripts\start-embedding-server.ps1,Linux/macOS 用 ./scripts/start-embedding-server.sh;等待"Model loaded successfully"消息;檢查是否在端口 5000 運行。
- 構建失敗:確保安裝了 .NET 8.0 SDK;從項目根目錄運行
dotnet build。
- 無搜索結果:驗證 RimWorldData 文件夾包含遊戲文件;嘗試更簡單的搜索查詢(例如 "pawn" 而不是 "pawn hunger system")。
故障排查速查
- 無法找到符號:檢查符號格式,XML 用
xml:DefName,C# 用 Namespace.ClassName;必要時重新構建索引並驗證。
- 嵌入生成失敗或 OOM:減小
--python-batch,或在無 GPU 的環境下使用較小模型或僅使用倒排索引。
- MCP 無響應:檢查啟動目錄與命令是否正確,確認
dotnet run 能在命令行單獨啟動服務器,並查看控制檯日誌以定位錯誤。
- 遠程 API 錯誤:當使用
--api-key 時,請確保同時提供了 --embedding-server (API 的 URL) 和 --model-name。
性能說明
- 冷啟動:~2 - 5 秒(加載索引)
- 熱查詢:0.5 - 1 秒
- 內存使用:向量索引約 300MB
- 推薦 GPU 用於嵌入服務器(顯著加速)
更新說明
RimWorld 更新時:
- 使用新遊戲文件更新
RimWorldData/ 文件夾。
- 重新構建索引:
dotnet run -- index --root "..\..\RimWorldData" --force。