戰(zhàn):RAG 與 Tool Calling 構(gòu)建崗位分析系統(tǒng))
1. 為什么我要用 Spring AI 做一套崗位分析系統(tǒng)先把結(jié)論擺在前面這套系統(tǒng)的核心目標(biāo)是把一堆非結(jié)構(gòu)化的招聘 JD職位描述文本通過(guò)RAG檢索增強(qiáng)生成加Tool Calling工具調(diào)用兩條腿走路自動(dòng)產(chǎn)出結(jié)構(gòu)化的崗位畫像——包括技能棧分布、薪資區(qū)間、經(jīng)驗(yàn)要求、崗位間的技能關(guān)聯(lián)等等。聽(tīng)起來(lái)像是又一個(gè) RAG Demo但真正動(dòng)手之后你會(huì)發(fā)現(xiàn)純 RAG 在崗位分析這個(gè)場(chǎng)景里會(huì)撞墻必須靠 Tool Calling 補(bǔ)位。我為什么會(huì)選 Spring AI 而不是 LangChain4j 或者直接上 Python 那套原因很實(shí)際我的主業(yè)務(wù)系統(tǒng)是 Spring Boot 寫的JD 數(shù)據(jù)來(lái)自內(nèi)部招聘管理系統(tǒng)數(shù)據(jù)庫(kù)、緩存、定時(shí)任務(wù)全在 Java 生態(tài)里。如果為了做 RAG 單獨(dú)起一個(gè) Python 服務(wù)光是數(shù)據(jù)同步、鑒權(quán)打通、部署運(yùn)維就夠我喝一壺。Spring AI 的價(jià)值就在于它把向量庫(kù)、ChatClient、Embedding、Function Calling 這些能力做成了 Spring 風(fēng)格的 Bean直接注入就能用和現(xiàn)有 Spring Boot 項(xiàng)目是無(wú)縫的。這套系統(tǒng)適合誰(shuí)參考如果你是有 Spring Boot 基礎(chǔ)、想在自己的業(yè)務(wù)系統(tǒng)里嵌入 AI 能力的后端開(kāi)發(fā)或者你正在做招聘、HR SaaS、人才盤點(diǎn)這類產(chǎn)品想加一個(gè)智能崗位分析模塊那這篇內(nèi)容基本可以照著抄。如果你完全沒(méi)接觸過(guò) Spring Boot建議先把 Bean 注入、自動(dòng)配置這些基礎(chǔ)過(guò)一遍再回來(lái)不然中間很多為什么這么寫你會(huì)看得云里霧里。我踩過(guò)的最大一個(gè)坑是一開(kāi)始天真地以為把 JD 塞進(jìn)向量庫(kù)用戶問(wèn)什么就檢索什么就完事了。結(jié)果用戶問(wèn)幫我對(duì)比一下 Java 后端和 Go 后端這兩個(gè)崗位方向近半年的技能要求變化純 RAG 檢索出來(lái)的是一堆零散片段LLM 拼出來(lái)的答案驢唇不對(duì)馬嘴。這就是典型的RAG 瓶頸——它擅長(zhǎng)找相似不擅長(zhǎng)做聚合、做計(jì)算、做對(duì)比。而 Tool Calling 恰好能補(bǔ)上這塊讓模型自己決定我需要調(diào)用一個(gè)統(tǒng)計(jì)工具去算技能詞頻而不是硬靠檢索。下面我按真實(shí)搭建順序把整體設(shè)計(jì)、核心細(xì)節(jié)、實(shí)操過(guò)程、踩坑排查四塊拆開(kāi)講中間會(huì)穿插大量參數(shù)選擇和取舍邏輯。2. 系統(tǒng)整體設(shè)計(jì)與技術(shù)選型拆解2.1 為什么是 RAG Tool Calling 而不是純 RAG先講清楚這兩者的分工不然后面代碼你會(huì)看不懂為什么這么設(shè)計(jì)。RAG 負(fù)責(zé)知識(shí)召回把歷史 JD、崗位說(shuō)明書、技能詞典這些文本切片、向量化、存進(jìn)向量庫(kù)。用戶提問(wèn)時(shí)先做相似度檢索把最相關(guān)的片段喂給大模型作為上下文。它解決的是模型不知道我們公司內(nèi)部崗位數(shù)據(jù)這個(gè)問(wèn)題。Tool Calling 負(fù)責(zé)確定性計(jì)算與外部動(dòng)作比如統(tǒng)計(jì)某個(gè)技能在近 100 條 JD 里出現(xiàn)的頻次、計(jì)算薪資中位數(shù)、按經(jīng)驗(yàn)?zāi)晗薹纸M、查詢數(shù)據(jù)庫(kù)里某個(gè)崗位的在招數(shù)量。這些活兒如果交給 LLM 去心算它要么算錯(cuò)要么編造。Tool Calling 的本質(zhì)是讓模型輸出一個(gè)結(jié)構(gòu)化的調(diào)用意圖由我們的 Java 代碼去執(zhí)行真正的邏輯再把結(jié)果回傳給模型組織語(yǔ)言。我實(shí)測(cè)下來(lái)純 RAG 在崗位分析場(chǎng)景的hit rate命中率大概只有六成左右尤其是涉及對(duì)比趨勢(shì)排名這類問(wèn)題時(shí)幾乎必掛。加上 Tool Calling 之后這類問(wèn)題的可用率能拉到九成以上。所以這不是要不要加的問(wèn)題而是必須加。2.2 技術(shù)棧清單與選型理由組件選型選型理由應(yīng)用框架Spring Boot 3.x主業(yè)務(wù)生態(tài)一致自動(dòng)配置省心AI 框架Spring AIBean 化集成ChatClient/Embedding 開(kāi)箱即用大模型通義千問(wèn)qwen-plus / qwen-max中文崗位文本理解好Function Calling 支持穩(wěn)定向量庫(kù)開(kāi)發(fā)期用 SimpleVectorStore生產(chǎn)用 PGVector開(kāi)發(fā)零依賴生產(chǎn)復(fù)用現(xiàn)有 PostgreSQLEmbedding通義千問(wèn) text-embedding-v3中文語(yǔ)義向量質(zhì)量夠用維度 1024文本切片TokenTextSplitter按 token 切避免超長(zhǎng)截?cái)嗑彺鍯affeine高頻查詢結(jié)果緩存降低模型調(diào)用成本這里重點(diǎn)說(shuō)兩個(gè)選型決策。第一個(gè)是向量庫(kù)。很多人一上來(lái)就裝 Milvus 或者 Chroma我建議開(kāi)發(fā)階段先用 Spring AI 自帶的SimpleVectorStore它就是個(gè)內(nèi)存 Map重啟數(shù)據(jù)就沒(méi)了但勝在零配置、啟動(dòng)快調(diào) prompt 和切片策略的時(shí)候特別爽。等邏輯跑通了再切到 PGVector——因?yàn)槟愦蟾怕室呀?jīng)有 PostgreSQL 了加個(gè)擴(kuò)展就行不用額外維護(hù)一套向量數(shù)據(jù)庫(kù)集群。這個(gè)先內(nèi)存后持久化的路徑能幫你省掉至少兩天的環(huán)境折騰。第二個(gè)是模型。我選通義千問(wèn)不是因?yàn)樗顝?qiáng)而是因?yàn)樗谥形?JD 這種半結(jié)構(gòu)化、術(shù)語(yǔ)密集的文本上表現(xiàn)穩(wěn)定而且 Function Calling 的 JSON 輸出格式比較規(guī)矩不容易出現(xiàn)模型返回一堆廢話導(dǎo)致解析失敗的情況。qwen-plus 用于日常問(wèn)答qwen-max 留給復(fù)雜的對(duì)比分析任務(wù)按需切換能省不少 token 成本。2.3 整體數(shù)據(jù)流設(shè)計(jì)整個(gè)系統(tǒng)的數(shù)據(jù)流我畫成文字版方便你對(duì)照理解離線階段JD 原始文本 → 清洗去 HTML、去重復(fù)→ 切片 → Embedding → 存入向量庫(kù)。在線問(wèn)答階段用戶提問(wèn) → 檢索向量庫(kù)拿 Top-K 片段 → 組裝 prompt系統(tǒng)提示 檢索上下文 用戶問(wèn)題 可用工具列表→ 發(fā)給模型。工具調(diào)用階段模型判斷需要工具 → 返回工具名和參數(shù) → Java 側(cè)執(zhí)行工具 → 結(jié)果回傳模型 → 模型生成最終答案。緩存階段對(duì)高頻、結(jié)果穩(wěn)定的查詢做 Caffeine 緩存命中直接返回。這個(gè)流程里最容易出問(wèn)題的是第 2 步的 prompt 組裝和第 3 步的工具描述。工具描述寫得好不好直接決定模型會(huì)不會(huì)該調(diào)的時(shí)候不調(diào)不該調(diào)的時(shí)候亂調(diào)。這個(gè)后面會(huì)專門講。3. 核心細(xì)節(jié)解析與實(shí)操要點(diǎn)3.1 JD 文本切片切多長(zhǎng)、怎么切切片是 RAG 的地基切不好后面全白搭。我一開(kāi)始用固定 500 字符切結(jié)果一條 JD 里的崗位職責(zé)和任職要求被從中間劈開(kāi)檢索出來(lái)的片段語(yǔ)義不完整模型經(jīng)常答非所問(wèn)。后來(lái)我改成按語(yǔ)義段落優(yōu)先、token 兜底的策略先用正則按崗位職責(zé)任職要求加分項(xiàng)這類小標(biāo)題切大塊每個(gè)大塊再用TokenTextSplitter按 token 切chunkSize 設(shè) 400overlap 設(shè) 80。為什么是 400 和 80因?yàn)橥x千問(wèn)的 embedding 模型對(duì)單段文本有長(zhǎng)度限制400 token 大約對(duì)應(yīng) 600-800 個(gè)中文字符正好覆蓋一段完整的職責(zé)描述。overlap 設(shè) 80 是為了防止關(guān)鍵信息剛好卡在切片邊界被切斷——這個(gè) 20% 左右的重疊比例是我試了好幾組參數(shù)后比較穩(wěn)的。TokenTextSplitter splitter new TokenTextSplitter(400, 80, 5, 10000, true); ListDocument chunks splitter.apply(documents);注意TokenTextSplitter的構(gòu)造參數(shù)順序是 chunkSize、minChunkSizeChars、minChunkLengthToEmbed、maxNumChunks、keepSeparator不同版本可能有差異升級(jí) Spring AI 后一定要重新核對(duì)簽名我就因?yàn)榘姹旧?jí)參數(shù)錯(cuò)位導(dǎo)致切片全亂過(guò)一次。3.2 向量檢索的 Top-K 與相似度閾值檢索階段有兩個(gè)關(guān)鍵參數(shù)topK和similarityThreshold。topK我設(shè)的是 5。設(shè)太小比如 2召回不足模型沒(méi)素材設(shè)太大比如 10會(huì)引入大量噪聲片段反而干擾模型判斷還費(fèi) token。similarityThreshold設(shè) 0.7。低于這個(gè)相似度的片段直接丟棄寧可少給也不能給錯(cuò)。SearchRequest request SearchRequest.query(question) .withTopK(5) .withSimilarityThreshold(0.7);實(shí)測(cè)下來(lái)崗位分析這種問(wèn)題Top-5 基本能覆蓋到相關(guān) JD 的核心信息。如果你發(fā)現(xiàn)模型總是漏掉某些信息先別急著調(diào)大 topK先檢查切片是不是把關(guān)鍵信息切碎了——十有八九是切片的問(wèn)題不是檢索的問(wèn)題。3.3 Tool Calling 的工具設(shè)計(jì)原則這是整套系統(tǒng)里我最想強(qiáng)調(diào)的部分。工具設(shè)計(jì)有三個(gè)原則違反任何一個(gè)都會(huì)讓模型犯傻。原則一工具職責(zé)單一名字要自解釋。不要搞一個(gè)叫analyzeJob的萬(wàn)能工具模型根本不知道它內(nèi)部干了啥。要拆成countSkillFrequency、calculateSalaryMedian、groupByExperience這種一看名字就知道干嘛的。原則二參數(shù)描述要寫清楚單位和格式。比如薪資工具的參數(shù)要明確寫單位元/月整數(shù)。我一開(kāi)始沒(méi)寫單位模型傳了個(gè)15k進(jìn)來(lái)Java 側(cè)解析直接拋異常。原則三工具返回結(jié)果要結(jié)構(gòu)化且簡(jiǎn)短。返回一大坨 JSON 給模型它會(huì)抓不住重點(diǎn)。我一般返回精簡(jiǎn)后的字符串或小對(duì)象比如Java: 87次, Spring Boot: 65次, MySQL: 52次。Bean Description(統(tǒng)計(jì)指定技能關(guān)鍵詞在崗位庫(kù)中出現(xiàn)的頻次參數(shù) skill 為技能名稱如 Java) public FunctionSkillRequest, String countSkillFrequency() { return request - jobAnalysisService.countSkill(request.skill()); }Spring AI 里用Description注解描述工具這個(gè)描述就是模型判斷要不要調(diào)這個(gè)工具的唯一依據(jù)所以一定要寫得像給同事交代任務(wù)一樣清楚。3.4 系統(tǒng)提示詞System Prompt的寫法系統(tǒng)提示詞決定了模型的人設(shè)和行為邊界。我的寫法是這樣的你是一個(gè)崗位分析助手。你的職責(zé)是基于檢索到的崗位數(shù)據(jù)回答用戶問(wèn)題。 規(guī)則 1. 涉及統(tǒng)計(jì)、計(jì)算、排名的問(wèn)題必須調(diào)用工具不要自己估算。 2. 回答必須基于檢索到的數(shù)據(jù)數(shù)據(jù)中沒(méi)有的信息要明確說(shuō)數(shù)據(jù)中未提及。 3. 輸出用簡(jiǎn)潔的中文涉及數(shù)據(jù)時(shí)用表格呈現(xiàn)。這三條規(guī)則分別解決了三個(gè)高頻問(wèn)題模型亂算、模型編造、模型輸出啰嗦。尤其是第二條不加的話模型特別愛(ài)腦補(bǔ)崗位要求這在招聘場(chǎng)景里是致命的。4. 實(shí)操過(guò)程與核心環(huán)節(jié)實(shí)現(xiàn)4.1 項(xiàng)目初始化與依賴配置先建一個(gè)標(biāo)準(zhǔn)的 Spring Boot 3.x 項(xiàng)目然后在pom.xml里加 Spring AI 的依賴。這里要注意Spring AI 的版本迭代很快建議用 milestone 或正式發(fā)布版別用 snapshot不然今天能跑的代碼明天可能就編譯不過(guò)。dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-qwen/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-vector-store-pgvector/artifactId /dependency然后在application.yml里配置模型和向量庫(kù)spring: ai: dashscope: api-key: ${DASHSCOPE_API_KEY} chat: options: model: qwen-plus temperature: 0.3 vectorstore: pgvector: index-type: HNSW distance-type: COSINE_DISTANCE dimensions: 1024temperature設(shè) 0.3 是因?yàn)閸徫环治鲆氖欠€(wěn)定、可復(fù)現(xiàn)的結(jié)果不需要模型發(fā)揮創(chuàng)造力。設(shè)太高你會(huì)發(fā)現(xiàn)同一個(gè)問(wèn)題問(wèn)兩次答案不一樣這在業(yè)務(wù)系統(tǒng)里是大忌。4.2 數(shù)據(jù)入庫(kù)從 JD 文本到向量入庫(kù)流程分四步讀取原始 JD、清洗、切片、寫入向量庫(kù)。public void ingest(ListJobDescription jobs) { ListDocument documents jobs.stream() .map(job - new Document( job.getContent(), Map.of(jobId, job.getId(), title, job.getTitle()) )) .toList(); ListDocument chunks tokenTextSplitter.apply(documents); vectorStore.add(chunks); }這里有個(gè)細(xì)節(jié)我在Document的 metadata 里存了jobId和title。為什么因?yàn)闄z索出來(lái)的片段如果不知道來(lái)自哪個(gè)崗位后續(xù)做聚合分析時(shí)就沒(méi)法溯源。metadata 是 RAG 里最容易被忽視但極其重要的東西它讓你的檢索結(jié)果可追溯。實(shí)操心得入庫(kù)時(shí)一定要做去重。招聘系統(tǒng)的 JD 經(jīng)常有大量重復(fù)同一個(gè)崗位多渠道發(fā)布不去重的話向量庫(kù)里全是冗余檢索時(shí) Top-5 可能全是同一條 JD 的切片白白浪費(fèi)召回名額。我一般用 JD 內(nèi)容的 MD5 做去重鍵。4.3 檢索增強(qiáng)問(wèn)答的完整實(shí)現(xiàn)問(wèn)答的核心是ChatClient加QuestionAnswerAdvisor。Spring AI 提供了開(kāi)箱即用的 Advisor能自動(dòng)完成檢索 拼上下文這一步。Bean public ChatClient chatClient(ChatClient.Builder builder, VectorStore vectorStore) { return builder .defaultSystem(SYSTEM_PROMPT) .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore, SearchRequest.query().withTopK(5).withSimilarityThreshold(0.7))) .defaultFunctions(countSkillFrequency, calculateSalaryMedian, groupByExperience) .build(); }defaultFunctions這一步就是把工具注冊(cè)給模型。注意這里傳的是 Bean 的名字所以你的 Function Bean 命名要和這里一致否則模型根本看不到工具。調(diào)用的時(shí)候String answer chatClient.prompt() .user(幫我統(tǒng)計(jì)一下近半年 Java 崗位最需要的 5 個(gè)技能) .call() .content();模型收到問(wèn)題后會(huì)先判斷這需要統(tǒng)計(jì)然后調(diào)用countSkillFrequency拿到結(jié)果后再組織語(yǔ)言輸出。整個(gè)過(guò)程對(duì)調(diào)用方是透明的你只管問(wèn)工具調(diào)用是模型自己決定的。4.4 工具的具體實(shí)現(xiàn)以技能頻次統(tǒng)計(jì)為例工具的實(shí)現(xiàn)要薄——只做數(shù)據(jù)查詢和計(jì)算不做任何自然語(yǔ)言處理因?yàn)檎Z(yǔ)言處理是模型的活兒。Service public class JobAnalysisService { private final JdbcTemplate jdbcTemplate; public String countSkill(String skill) { String sql SELECT COUNT(*) FROM job_skill WHERE skill_name ? AND create_time NOW() - INTERVAL 6 months ; Integer count jdbcTemplate.queryForObject(sql, Integer.class, skill); return skill 在近半年出現(xiàn) count 次; } public String calculateSalaryMedian(String jobTitle) { String sql SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary_min) FROM job_description WHERE title ? ; Double median jdbcTemplate.queryForObject(sql, Double.class, jobTitle); return jobTitle 的薪資中位數(shù)為 median 元/月; } }用PERCENTILE_CONT(0.5)算中位數(shù)而不是平均值是因?yàn)樾劫Y數(shù)據(jù)分布偏斜嚴(yán)重平均值容易被極端值帶偏。這個(gè)細(xì)節(jié)很多教程不會(huì)講但在真實(shí)業(yè)務(wù)里很重要。4.5 緩存與性能優(yōu)化模型調(diào)用是這套系統(tǒng)里最貴、最慢的環(huán)節(jié)。我加了 Caffeine 緩存對(duì)技能頻次薪資中位數(shù)這類結(jié)果相對(duì)穩(wěn)定的查詢做緩存TTL 設(shè) 30 分鐘。Bean public CacheString, String analysisCache() { return Caffeine.newBuilder() .expireAfterWrite(30, TimeUnit.MINUTES) .maximumSize(1000) .build(); }為什么 TTL 是 30 分鐘而不是更長(zhǎng)因?yàn)閸徫粩?shù)據(jù)是動(dòng)態(tài)的新 JD 每天都在進(jìn)來(lái)緩存太久會(huì)導(dǎo)致分析結(jié)果滯后。30 分鐘是我權(quán)衡數(shù)據(jù)新鮮度和調(diào)用成本后的折中值。如果你的 JD 更新頻率低可以適當(dāng)延長(zhǎng)。5. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄5.1 模型不調(diào)用工具怎么辦這是最高頻的問(wèn)題。模型明明該調(diào)工具卻自己編了個(gè)答案。排查順序如下檢查工具是否真的注冊(cè)成功。在啟動(dòng)日志里搜工具名沒(méi)注冊(cè)上模型當(dāng)然看不到。檢查工具描述是否清晰。Description寫得太模糊模型判斷不了該不該調(diào)。檢查系統(tǒng)提示詞有沒(méi)有強(qiáng)制要求。加一句涉及統(tǒng)計(jì)必須調(diào)用工具能顯著提升調(diào)用率。檢查模型本身是否支持 Function Calling。不是所有模型都支持選型時(shí)要確認(rèn)。我遇到過(guò)一次工具描述寫的是處理技能相關(guān)模型完全不知道這工具能干嘛改成統(tǒng)計(jì)指定技能在崗位庫(kù)中的出現(xiàn)頻次之后立刻就正常調(diào)用了。5.2 檢索結(jié)果不相關(guān)如果檢索出來(lái)的片段和問(wèn)題八竿子打不著按這個(gè)順序查現(xiàn)象可能原因解決方向檢索結(jié)果全是無(wú)關(guān) JD切片太碎或太大調(diào)整 chunkSize 和 overlap相關(guān) JD 檢索不到相似度閾值太高降低 threshold 到 0.6 試試結(jié)果重復(fù)度高數(shù)據(jù)沒(méi)去重入庫(kù)前做 MD5 去重中文語(yǔ)義匹配差embedding 模型不適配換中文優(yōu)化過(guò)的 embedding 模型5.3 工具調(diào)用參數(shù)解析失敗模型傳參格式和你的 Java 對(duì)象對(duì)不上會(huì)拋反序列化異常。常見(jiàn)的是模型傳了帶單位的字符串15k而你的字段是 Integer。解決辦法有兩個(gè)一是參數(shù)描述里寫死格式要求二是 Java 側(cè)做容錯(cuò)解析把15k轉(zhuǎn)成 15000。我建議兩個(gè)都做雙保險(xiǎn)。5.4 響應(yīng)太慢一次完整的 RAG Tool Calling 鏈路涉及檢索 模型判斷 工具執(zhí)行 模型生成四步慢是正常的。優(yōu)化手段檢索和工具執(zhí)行并行化如果互不依賴高頻查詢走緩存簡(jiǎn)單問(wèn)題用 qwen-plus復(fù)雜問(wèn)題才用 qwen-max控制檢索片段數(shù)量別一股腦塞給模型。5.5 獨(dú)家避坑清單別在循環(huán)里調(diào)模型。我見(jiàn)過(guò)有人對(duì) 100 條 JD 逐條調(diào)模型做分類又慢又貴。批量處理要合并請(qǐng)求。metadata 一定要存業(yè)務(wù)主鍵。不然檢索結(jié)果沒(méi)法溯源做聚合分析時(shí)你會(huì)哭。工具返回結(jié)果別太長(zhǎng)。模型上下文有限返回一大坨數(shù)據(jù)會(huì)擠掉檢索上下文。prompt 里的規(guī)則要少而精。寫十幾條規(guī)則模型反而記不住三條核心規(guī)則足夠。上線前一定要做回歸測(cè)試。模型行為會(huì)隨版本更新變化今天好用的 prompt 明天可能就失效。6. 這套系統(tǒng)還能怎么擴(kuò)展跑通基礎(chǔ)版本之后我陸續(xù)加了幾個(gè)擴(kuò)展效果都不錯(cuò)這里分享給你。第一個(gè)是 GraphRAG 思路的引入。純向量檢索只能找到相似文本但崗位之間其實(shí)有技能關(guān)聯(lián)這種圖結(jié)構(gòu)關(guān)系。比如會(huì) Spring Boot 的人大概率也會(huì) MySQL。我把技能共現(xiàn)關(guān)系抽出來(lái)存成圖檢索時(shí)結(jié)合圖遍歷能回答從 Java 轉(zhuǎn) Go 需要補(bǔ)哪些技能這類關(guān)聯(lián)性問(wèn)題。這就是熱詞里說(shuō)的 ontology RAG 的落地場(chǎng)景。第二個(gè)是 NL2SQL 的補(bǔ)充。有些問(wèn)題本質(zhì)是數(shù)據(jù)庫(kù)查詢比如薪資大于 30k 的崗位有幾個(gè)。與其讓模型在向量庫(kù)里瞎找不如讓它生成 SQL 直接查庫(kù)。Spring AI Alibaba 的 NL2SQL 能力可以接進(jìn)來(lái)和 RAG 形成互補(bǔ)——結(jié)構(gòu)化問(wèn)題走 SQL非結(jié)構(gòu)化問(wèn)題走向量檢索。第三個(gè)是分析結(jié)果的可視化。把工具返回的統(tǒng)計(jì)數(shù)據(jù)直接喂給前端圖表庫(kù)用戶看到的不只是文字答案還有技能分布餅圖、薪資區(qū)間柱狀圖。這一步讓系統(tǒng)從問(wèn)答工具升級(jí)成分析平臺(tái)。我個(gè)人在實(shí)際操作中的體會(huì)是RAG 和 Tool Calling 的組合不是簡(jiǎn)單的11而是讓系統(tǒng)具備了既能查資料又能算數(shù)據(jù)的雙重能力。崗位分析只是其中一個(gè)應(yīng)用場(chǎng)景同樣的架構(gòu)套到客服知識(shí)庫(kù)、合同審查、競(jìng)品分析上邏輯是通的。真正花時(shí)間的從來(lái)不是寫代碼而是調(diào) prompt、調(diào)切片、調(diào)工具描述這些臟活——但這些臟活恰恰決定了系統(tǒng)到底能不能用。