面試結束後,我反問:「就面個實習至於上這麼大強度嗎?」面試官:「你對 RAG、Agent、MCP、Skill 理解得很到位,所以要求高一點。」

老王今天穿了件黑 T 恤,胸口印著一行白字「My code does compile」,鬍子有點拉碴,應該是連續好幾天沒刮了。

桌上擺著一杯冰美式,估摸著是剛沖的,但一直沒顧得上喝。

「我對你要求比較高。」老王開門見山地說,「你,可不要緊張啊。」

(內心 OS:哥們也是見過大風大浪的,根本不怕好吧,你儘管來。)

但講老實話,這次面試確實頂,頂到肺了快。😄

兄弟姐妹們可以先看看這些題目,真的,不是一般人,扛不住啊。

繫好安全帶,咱們粗粗粗粗發~~

content

01、RAG 項目,你裡邊的分片是怎麼設計的?然後還有就是內容的解析以及向量化又是怎麼做的,然後在檢索召回的時候又是怎麼做的?

我說:「我分四塊兒來講,分片、解析、向量化、召回。」

老王點點頭,往椅子上一靠,看樣子是準備聽我的長篇大論了。

分片這一塊,派聰明用的是多層級語義分片,按段落 → 句子 → 詞 → 字元這種遞進的方式來切。分片大小預設設的是 512 位元組,沒有用 overlap。

老王這時候插了一句:「不用 overlap 不怕語義割裂嗎?」

我說:「這個問題我們也想過。後來發現 overlap 在中文場景下效果一般,反而會讓相同內容在 ES 裡出現兩次,召回的時候排在前面的幾條都是同一段落的不同切片,相當於浪費 topK 名額。我們的做法是,分片之外維護一個 1MB 的父塊,流式讀進來防止 OOM,分片只承擔向量召回,命中之後回溯到父塊給大模型作為上下文。」

老王眼睛亮了一下,沒說話,示意我繼續。

解析這一塊,用的是 Apache Tika 2.9.1,自動識別格式,支援 PDF、Word、Excel、PPT、Markdown、HTML 這幾大類。PDF 我們是用 PDFBox 單獨處理的,按頁碼切片,同時把頁眉頁腳這些重複出現的字元給剔除掉。中文長句切詞用的 HanLP 的 StandardTokenizer。

向量化走的是阿里千問的 text-embedding-v4,維度 2048,通過相容 OpenAI 協議的 API 調,單次最多 batch 10 條。

召回這一塊是重頭戲。我們使用 Elasticsearch 來完成的,索引名為 knowledge_base,向量欄位用的 dense_vector,相似度 cosine。我們做了一個 KNN + BM25 的混合召回,KNN 先粗召回 topK × 30 條,然後 BM25 在這個窗口裡 rescore,最終返回 topK。

老王聽完說:「行,整體講清楚了,不錯。」

這句話雖然簡單,卻給了我很大鼓勵,說實話。

02、為什麼選擇千問,然後為什麼選擇 2048 維的向量呢?

我說:「這個問題我還真研究過。」

千問 v4 這個 embedding 模型,中文場景下的表現非常不錯,尤其是技術文件這種帶著程式碼、英文、中文解釋的混合內容。

我們之前對比過,同樣一份 Spring Boot 教程,千問的召回準確率能比另外一家向量模型高出十幾個百分點。

老王追問:「那 2048 維呢?千問 v4 不是支援 1024、1536、2048 三檔嗎?為什麼選最大的?

主要是兩個原因。

一是精度,維度越高,向量空間表達能力越強,對長文本和專業術語的區分度越好。

二是 ES 這邊的儲存和計算成本我們做過測算,2048 維相比 1024 維,單條向量大概多了 8KB,knowledge_base 索引裡目前有幾十萬條資料,多出來的儲存壓力可以接受。

檢索這塊兒因為有 BM25 兜底重排,KNN 的耗時增加在能接受的範圍內。

老王手指在桌面上輕輕敲了一下:「成本算過這點不錯。繼續。」

內心 OS:嘿嘿,這個問題之前被卡脖子過一次,回去補了一波功課。

03、這個 KNN 向量召回以及那個 BM25 重排序是怎麼做的呢?

KNN 用的是 ES 8.x 原生的 _knn_search 介面。

具體參數上,我們設的是 recallK = topK × 30,比如最終要返回 10 條,KNN 會先粗召回 300 條出來。

BM25 這一段走的是 ES 的 rescore 機制,在 KNN 召回出來的 300 條窗口裡再排一次序。

權重設的是 KNN 占 0.2、BM25 占 1.0,BM25 是主導

老王挑了挑眉:「為什麼 BM25 占主導而不是 KNN?現在主流做法不是向量召回為主嗎?」

我們做過 A/B 測試,純 KNN 在長文件場景下會出現『語義相近但答案錯位』的情況,比如使用者問『派聰明的分片大小是多少』,純 KNN 會召回一堆講分片策略的段落,但具體的 512 這個數字反而排不到前面。

BM25 對關鍵字的命中很敏感,能把含『512』『chunk-size』這種精確的段落頂上來。所以我們讓 BM25 來做最終判定,KNN 提供候選池。

老王面露悅色,看起來對這個回答很認可。

04、BM25 是什麼呢?

BM25 是一個經典的文本相關性評分演算法,全名 Best Matching 25,跟 TF-IDF 是一脈相承的。

它的核心思想就三點:詞頻(TF)、逆文件頻率(IDF)、文件長度正規化。

詞在當前文件裡出現次數越多,這個詞對這個文件越重要;這個詞在所有文件裡出現得越普遍(比如「的」「是」),它的權重就越低;文件越長,單個詞的權重要適當低一些,因為長文件天然占優勢。

ES 預設的 similarity 就是 BM25,參數有兩個,k1 控制詞頻飽和速度,預設 1.2;b 控制長度正規化強度,預設 0.75。我們沒改過這兩個參數,用的就是預設值。

老王追問:「那 BM25 相比 TF-IDF 強在哪?」

最關鍵的是 k1 這個參數引入了詞頻飽和。

TF-IDF 裡詞頻是線性成長的,一個詞出現 100 次的文件得分是出現 10 次的 10 倍,這個明顯不合理。

BM25 用一個 (k1+1)*tf / (k1+tf) 的公式讓詞頻成長有上限,更符合人類直覺。

05、在實際完成這個專案的時候,你有哪些感悟或者說感受,這個專案是多少個人完成的?

這個專案核心開發就 3 個人,我和另外兩個宿友,加上我們的導師二哥。

要說感悟,最深的一條是:RAG 這個東西,效果好不好,七成在資料,兩成在召回,一成在模型

我們一開始死磕模型、調 prompt,效果就是上不去。後來回頭去看分片,發現把分片大小從 1024 調到 512、再加上語義邊界切分,召回準確率直接漲了一大截。

老王點點頭:「這個體感我也認同。還有別的嗎?」

還有一條,生產級 RAG 和 demo 級 RAG 完全是兩個東西

demo 跑通向量化 + 召回 + LLM 三步流程一週就能出來,但要加上權限隔離、多租戶、檔案去重、串流上傳、增量更新這些,工作量直接翻 10 倍。

我們光權限這一塊就做了 userId、orgTag、isPublic 三層過濾。

06、在整個這個專案當中,你覺得 AI 承擔了一個什麼樣的角色呢?

程式碼生成這塊兒,大概有 60% 的程式碼是 Codex 寫的,包括 mapper、service 的 CRUD、ES 的 mapping 配置、千問 API 的封裝等。

老王追問:「那剩下 40% 是什麼?」

剩下 40% 是核心業務邏輯,比如分片策略、混合召回的權重調優、prompt 工程、效能優化。

這些 AI 寫出來的第一版基本不能直接用,需要我們結合實際資料反覆調。

07、ElasticSearch KNN 向量召回的一個響應耗時大概有多少?

我們沒專門做過 SLA 測試,但從日誌埋點上看,單次 KNN + BM25 rescore 的整體耗時大概在 50ms 到 120ms 之間,平均 80ms 左右。

老王追問:「這個耗時受什麼影響最大?」

主要看三個因素。

一是資料量,knowledge_base 索引裡資料從 10 萬條漲到 50 萬條,單次查詢就會變慢。

二是 recallK 的設定,我們試過 topK × 50,召回品質沒明顯提升,但耗時卻更多了,所以後來定在了 × 30。

三是文件命中範圍,如果使用者的查詢關鍵字太寬泛,BM25 那一段 rescore 的窗口就會變大,耗時會漲。

08、為什麼你們做這個東西要用 ES 呢?

主要是因為它一份索引同時支援文本檢索和向量檢索

如果用專門的向量資料庫比如 Milvus、Qdrant,再單獨搭一套關鍵字檢索,運維和資料同步的成本就上去了。ES 8.x 之後的 dense_vector 已經夠用,沒必要再引入新元件。

老王追問:「ES 底層資料結構了解嗎?」

文本檢索是經典的 Lucene 倒排索引,文件分詞後建立詞到文件的對映,查詢的時候直接查詞。

向量檢索,ES 8.x 用的是 HNSW(Hierarchical Navigable Small World)演算法,簡單說就是一個多層圖結構,從頂層稀疏圖入口往下逐層精搜,能在 O(log n) 的複雜度內找到近似最近鄰。

老王明顯對這方面有深入的研究,聽到 HNSW 的時候點了點頭。

常規查詢方式上,ES 主要有幾種:

term 精確匹配、match 分詞匹配、bool 組合查詢、range 範圍查詢、aggregation 彙總。

然後我們專案裡最常用的是 bool + match + filter 的組合,bool 包括 must/should/filter 三種用法,should 做權限過濾,filter 做硬性過濾不參與評分。

老王面露悅色:「這個理解到位了。」

09、AI 用的模型是啥什麼?

我們專案裡用了兩個 AI 模型,一個是 embedding,一個是 LLM。

embedding 用的是阿里千問 text-embedding-v4,2048 維。

LLM 用的是 DeepSeek-chat,走官方 API(api.deepseek.com/v1)。

老王追問:「為什麼 LLM 選 DeepSeek 而不是千問或者 GLM?」

主要是性價比。

DeepSeek 的輸出品質在 Top 梯隊,但 API 價格只有 GPT 的幾十分之一,對我們特別友好。

10、你平時在用那個 AI 程式設計的時候,是怎麼去使用的?

Claude Code 主要用來處理文本,Codex 主要用來編碼。

為了方便使用,我在 IntelliJ IDEA 中也接入了 Codex,閱讀程式碼的時候非常好用;Claude Code 也做一個 PaiSwitch 控制台,可以切換底層的模型,Kimi 和 GLM 都在用。

老王追問:「Claude Code 你用過哪些 Skill?」

Frontend-design(前端設計)、Skill-creator、web-access 等,最後一個最好用,可以讓 Agent 的聯網能力拉滿,如果有些內容需要登入才能存取,這個 Skill 可以通過 cdp 直連 Chrome 已登入的分頁。

11、那怎麼知道 AI 做的對不對呢?

我現在的做法分三層。

第一層,讓 AI 自己給出驗證方案。比如它寫完一個介面,我會讓它再跑一遍單元測試,或者寫一段 curl 命令驗證。

第二層,**關鍵路徑必須多個 Agent review。**比如說 Codex 寫完程式碼,我會開 Qoder 的專家團進行測試。

第三層,親自動手測試。雖然說 Codex 可以用 computer use 控制瀏覽器進行測試,但有些難產的問題 Agent 現在還是沒辦法觸及到,還是需要親自動手去測。

12、平時會關注一些就是技術前沿的動態嗎?怎麼關注的呢?以什麼方式呢?

主要是 X、GitHub trending、Hacker News 這三個管道。

X 上我關注了一批活躍的開發者和官方帳號,包括 Anthropic、OpenAI、DeepMind 這些大廠,還有一些獨立開發者比如 swyx、karpathy。

Hacker News 我用 OpenClaw 跑了一個定時任務,每天早上推送一封郵件給我,把前一天 top 30 的帖子和評論摘要發給我,能了解到不少。

13、那如果說我們要把這個 rag 升級成一個智能體需要怎麼做?

核心改造有三塊。

  • 一是把檢索從『一次性查詢』改成『循環查詢』,讓模型能根據中間結果決定要不要再查、查什麼。
  • 二是引入工具調用,除了知識庫檢索,再加上聯網搜尋、SQL 查詢、檔案讀寫這些原子能力。
  • 三是加一個規劃器(Planner),讓模型先把使用者問題拆成子任務,然後逐個執行。

老王追問:「具體到 PaiCLI Agent,你會怎麼改?」

最簡單的方案是引入一個 ReAct 循環。

讓模型思考完再執行,然後觀察結果後再思考,不斷重複。

呼叫 ES 檢索,觀察 Elasticsearch 的返回。直到模型輸出 Final Answer 結束循環。這套機制 LangChain、LangGraph 都有現成的實作,搬過來就能用。

不過要做到生產可用,還得加上幾個東西:

超時和最大輪次限制(避免死循環)、中間狀態持久化(避免一次失敗全部重來)、人工介入介面(關鍵決策需要確認)。

14、你是怎麼理解 skills, mcp 還有 tool 的?

這三個東西在 Claude Code 裡經常一起出現,但定位不同。

Tool 是最底層的原子能力,比如讀檔案、跑命令列、查資料庫,每個 Tool 就是一個函式簽名 + 一段執行邏輯。模型通過 Function Calling 呼叫 Tool,參數和回傳值都是結構化的 JSON。

MCP 是 Tool 的標準化協議。MCP 規定了一套統一的協議,讓 Tool 可以打包成獨立的 Server,被任何支援 MCP 的客戶端呼叫。Claude Code、Codex 這些工具都支援 MCP。

Skill 是工作流程的封裝。是一套「做某件事的完整方法論」,包含了 prompt 模板、呼叫順序、判斷邏輯、甚至子 Skill 的呼叫。Anthropic 把 Skill 放在 .claude/skills/ 目錄下,每個 Skill 是一個資料夾,包含 SKILL.md(說明)、references(參考資料)、scripts(輔助腳本)。

老王追問:「那這三者是包含關係嗎?」

不完全是。

Tool 是原子能力,MCP 是 Tool 的傳輸協議,Skill 是基於 Tool 和 prompt 編排出來的高階能力。

可以這麼類比:Tool 像是 Linux 裡的 cat、grep、awk 這些命令;MCP 像是 shell 這個統一介面;Skill 像是寫好的 shell 腳本。

老王聽完這個類比,忍不住樂了:「這個類比挺貼切。」

15、那麼在實際的使用當中,就是說你在 AI 程式設計的過程當中,你覺得哪種會用得比較多?

Skill 用得最多,MCP 排第二,原生 Tool 用得最少

Tool 屬於底層的東西,Agent 直接就封裝好了。

MCP 的話,我目前用得最多的是 Chrome Devtools MCP 和 IntelliJ IDEA,可以接入到 Agent 中使用。

Skills 的話,目前用得比較多,如果 GitHub 上有開源的現成的、比較好用的,我會直接拿來用。沒有合適的話,我會自己讓 Agent 根據我的工作流去生成。

老王追問:「那 Skill 有什麼坑嗎?」

最大的坑是 Skill 的描述寫不好,模型就不會主動觸發。

Skill 的 description 欄位相當於一個分類器,模型看到使用者請求之後會判斷要不要載入這個 Skill。description 寫得太寬泛,會被誤觸發。

16、自己寫過 skills 嗎?沒有,那有看過 skills 的具體實作嗎?

寫過不少。

比如說我之前蒸餾過王小波.skill,出來的效果還是挺有趣的。

老王眼睛一下亮了:「能講講怎麼寫的嗎?」

Skill 的核心就是三個檔案。

第一個是 SKILL.md,frontmatter 裡寫 name 和 description,正文寫工作流程。第二個是 references 目錄,放參考資料,比如風格指南、歷史文章樣本。第三個是 scripts 目錄,放輔助腳本,比如檢查字數的 Python 腳本。

老王聽完,長長地舒了一口氣:「行,我們差不多就到這。」

我反問了一句:「就面個實習至於上這麼大強度嗎?」

老王笑了笑:「你對 RAG、Agent、MCP、Skill 理解得很到位,所以要求高一點。一會兒 HR 會和你聊。」

走出會議室的時候,我看了一眼手機,整整一個半小時。

內心 OS:老王這體力是真好,還特麼能問,勞資快頂不住了。


原文出處:https://juejin.cn/post/7653108100300242987


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝16   💬1   ❤️1
508
🥈
我愛JS
📝1   ❤️1
30
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登