智能簡歷篩選案例拆解:基于LlamaIndex+LangChain的框架開發(fā)

上一篇文章介紹了使用基礎(chǔ)組件,實現(xiàn)企業(yè)規(guī)章制度 RAG 問答的案例。這種原生開發(fā)方式雖然有助于更直觀的理解 RAG 原理,但在面對更復(fù)雜的業(yè)務(wù)場景時,開發(fā)效率和功能擴展性方面的局限就會很明顯。尤其是包含異構(gòu)文件整合、結(jié)構(gòu)化信息提取和多輪對話交互的綜合性應(yīng)用,引入成熟的開發(fā)框架成為合理選擇。
正本清源:原生RAG入門案例拆解(企業(yè)規(guī)章制度問答)+ 技術(shù)棧全景
這篇基于兩個月前,我給一家獵頭公司做項目咨詢中的簡歷篩選場景,來演示下如何利用 LlamaIndex 和 LangChain 兩大主流框架,構(gòu)建一個智能簡歷篩選系統(tǒng)。
這篇試圖說清楚:
簡歷篩選場景的三大核心痛點、包含數(shù)據(jù)處理流水線、雙層知識存儲引擎,以及基于 LCEL 對話式 RAG 應(yīng)用鏈的核心架構(gòu),最后完整的演示下框架化的開發(fā)流程并進(jìn)行效果驗證。
1、業(yè)務(wù)背景
傳統(tǒng)的簡歷處理方式,無論是人工審閱還是基于關(guān)鍵詞的初步篩選,都存在固有的局限性。這篇以當(dāng)下比較火熱的 AI 產(chǎn)品經(jīng)理崗位招聘為例,從異構(gòu)文件的統(tǒng)一接入、精準(zhǔn)篩選與模糊檢索的平衡,以及信息檢索到?jīng)Q策輔助三個維度,拆解下該場景面臨的三個潛在痛點。
1.1異構(gòu)文件的統(tǒng)一問題
企業(yè)在招聘過程中,收到的簡歷文件格式通常橫跨 PDF、DOCX 等多種類型。這兩種主流格式在內(nèi)部結(jié)構(gòu)上差別很大。PDF 文件注重版式的精確固定,文本內(nèi)容的提取往往伴隨著換行、分頁等格式噪聲;而 DOCX 文件則以內(nèi)容流為核心,結(jié)構(gòu)相對清晰但同樣存在樣式多變的問題。
在不使用框架的情況下,需要給每一種文件格式編寫?yīng)毩⒌慕馕鲞壿?,例如使?PyMuPDF 庫處理 PDF 文件,使用 python-docx 庫處理 DOCX 文件。這將導(dǎo)致數(shù)據(jù)加載模塊的代碼維護起來有些費勁。每次需要支持新的文件格式時,都必須對核心代碼進(jìn)行修改和擴展。
1.2精準(zhǔn)篩選與模糊檢索的平衡
招聘需求(JD)中通常包含必須滿足的硬性指標(biāo),如”工作經(jīng)驗超過 5 年且具備 RAG 項目實戰(zhàn)經(jīng)驗“。智能簡歷篩選系統(tǒng)需要能夠像數(shù)據(jù)庫一樣,對這類條件進(jìn)行精準(zhǔn)識別和邏輯判斷。但是,傳統(tǒng)的關(guān)鍵詞匹配方式嚴(yán)重依賴精確的字符串匹配,無法處理表述方式的差異。當(dāng)候選人簡歷中使用“檢索增強生成技術(shù)”而不是“RAG”的時候,關(guān)鍵詞檢索就會漏掉這部分信息。
同時,許多候選人的能力描述可能與招聘需求的字面表述不完全一致,但語義上高度相關(guān)。例如,招聘需求中要求“LangChain 框架實踐項目經(jīng)驗”,但是候選人簡歷中可能表述為“負(fù)責(zé) RAG 流水線技術(shù)實現(xiàn)”或“主導(dǎo)智能問答系統(tǒng)構(gòu)建”。這些表述在語義上高度關(guān)聯(lián),基于向量的語義檢索能夠有效識別這種潛在匹配。
1.3從信息檢索到?jīng)Q策輔助
招聘決策的關(guān)鍵在于對多個候選人進(jìn)行標(biāo)準(zhǔn)化的橫向?qū)Ρ?。這也就要求智能簡歷篩選系統(tǒng)不僅能找到信息,更能以結(jié)構(gòu)化且一目了然的方式,展示每個候選人的評估檔案。例如,自動生成所有候選人的核心能力對比列表。以及進(jìn)一步支持招聘人員通過連續(xù)的追問,這要求系統(tǒng)具備上下文記憶和深度推理的能力。
2、核心架構(gòu)
整個系統(tǒng)采用分層架構(gòu)設(shè)計,由三個核心模塊構(gòu)成:位于底層的數(shù)據(jù)處理流水線、雙層知識存儲引擎,以及面向用戶的對話式 RAG 應(yīng)用鏈。

2.1數(shù)據(jù)處理流水線
數(shù)據(jù)處理流水線的入口是多格式的簡歷文件(PDF、DOCX 等)。系統(tǒng)利用 LlamaIndex 提供的 SimpleDirectoryReader 組件,實現(xiàn)對指定目錄下不同格式文件的自動加載。這個組件統(tǒng)一了底層不同文件類型的解析接口,為上層處理提供了標(biāo)準(zhǔn)化的 Document 對象輸入。
為了更加精準(zhǔn)的實現(xiàn)分塊,這里設(shè)計了一個上下文感知解析器(ResumeNodeParser)。這個解析器專門針對簡歷的結(jié)構(gòu)特點,通過正則表達(dá)式識別“工作經(jīng)歷”、“項目經(jīng)歷”等章節(jié)標(biāo)題,進(jìn)行語義導(dǎo)向的切分。這種方式可以保證切分出的文本塊在語義上的完整性,還能在解析階段就為文本塊賦予類型元數(shù)據(jù)。
2.2雙層知識存儲引擎
這個雙層設(shè)計是這個系統(tǒng)架構(gòu)的重要特點,通過不同的存儲方式,分別支撐 RAG 問答和結(jié)構(gòu)化概覽兩種不同的應(yīng)用需求。
ChromaDB 向量數(shù)據(jù)庫
數(shù)據(jù)處理流水線輸出的語義文本塊,會經(jīng)過向量化處理,即通過嵌入模型將其轉(zhuǎn)換為高維數(shù)學(xué)向量。這些向量與原始文本塊一同存入 ChromaDB 向量數(shù)據(jù)庫。ChromaDB 作為專門的向量數(shù)據(jù)庫,相比上篇文章使用的 FAISS 索引庫,在集成便利性和數(shù)據(jù)管理方面具有優(yōu)勢。
SQLite 結(jié)構(gòu)化數(shù)據(jù)庫
與此同時,數(shù)據(jù)處理流水線輸出的完整簡歷文本,會經(jīng)歷一個結(jié)構(gòu)化提取過程。這個過程調(diào)用大模型,根據(jù)預(yù)定義的 Pydantic 模型(Python 數(shù)據(jù)驗證庫,用于定義結(jié)構(gòu)化數(shù)據(jù)格式),從純文本中抽取出候選人的姓名、工作年限、項目經(jīng)驗、優(yōu)劣勢分析等關(guān)鍵信息,形成一份標(biāo)準(zhǔn)化的結(jié)構(gòu)化檔案。這份檔案最終被存入 SQLite 結(jié)構(gòu)化數(shù)據(jù)庫(一個輕量級的關(guān)系型數(shù)據(jù)庫)。這個數(shù)據(jù)庫的作用是為最后的用戶界面提供即時候選人信息查詢服務(wù),支撐系統(tǒng)的候選人概覽和詳情展示功能。
2.3對話式 RAG 應(yīng)用鏈
這個模塊采用 Streamlit UI 作為前端界面(一個 Python Web 應(yīng)用框架),關(guān)鍵邏輯由基于 LCEL 構(gòu)建的對話鏈驅(qū)動。當(dāng)用戶輸入問題后,系統(tǒng)啟動以下 RAG 流程:
1.檢索上下文:LCEL 對話鏈?zhǔn)紫葘⒂脩魡栴}向量化,并向 ChromaDB 向量數(shù)據(jù)庫發(fā)起檢索請求,獲取與問題語義最相關(guān)的簡歷文本塊作為上下文。
2.整合聊天歷史:為了支持多輪對話,對話鏈會從內(nèi)存歷史記錄中讀取之前的交互內(nèi)容,理解當(dāng)前問題的完整語境。
3.調(diào)用大模型:對話鏈將用戶問題、檢索到的上下文以及聊天歷史,一同組裝成一個結(jié)構(gòu)化的提示,并發(fā)送給大模型進(jìn)行處理。
4.生成回答:大模型在充分理解所有輸入信息的基礎(chǔ)上,生成一個精準(zhǔn)、連貫的回答,并將結(jié)果返回給對話鏈。最終,該回答通過 Streamlit UI 呈現(xiàn)給用戶,完成一次交互。
3、技術(shù)實現(xiàn)
這部分來演示下上述三個模塊背后的一些核心代碼邏輯。整個過程依賴 LlamaIndex 進(jìn)行數(shù)據(jù)處理與索引構(gòu)建,借助 Pydantic 模型實現(xiàn)結(jié)構(gòu)化信息提取,并利用 LCEL 靈活編排帶記憶功能的對話鏈。最終,通過 Streamlit 把所有后端能力封裝成一個直觀的 Web 應(yīng)用界面,并進(jìn)行實戰(zhàn)效果驗證。
3.1數(shù)據(jù)處理引擎
全局模型配置
在進(jìn)行任何數(shù)據(jù)處理之前,首先需要為 LlamaIndex 進(jìn)行全局模型配置,指定后續(xù)流程中使用的大模型(用于結(jié)構(gòu)化信息提?。┖颓度肽P停ㄓ糜谙蛄炕?。系統(tǒng)通過 config.py 配置文件統(tǒng)一管理模型參數(shù)和環(huán)境設(shè)置
# config.py 配置示例
def get_config():
"""
提供應(yīng)用程序的配置。
"""
return {
"model": {
"llm_model": "qwen3:30b", # 大模型
"ollama_embedding_model": "bge-m3", # 嵌入模型
"collection_name": "resume_collection"
},
"env": {
"ollama_host": "http://localhost:11434", # Ollama服務(wù)地址
"ollama_timeout": 120.0 # 請求超時時間
}
}配置字典隨后在 RAGEngine 的初始化過程中被加載,并通過 _setup_llamaindex_settings 方法應(yīng)用到 LlamaIndex 的全局配置中。
# core/rag_engine.py ->_setup_llamaindex_settings 方法
from llama_index.core import Settings
from llama_index.llms.ollama import Ollama
from llama_index.embeddings.ollama import
OllamaEmbedding
# ...
Settings.llm = Ollama(
model=self.config['model']['llm_model'],
base_url=self.config['env']['ollama_host'],
request_timeout=float(self.config['env']['ollama_timeout'])
)
Settings.embed_model = OllamaEmbedding(
model_name=self.config['model']['ollama_embedding_model'],
base_url=self.config['env']['ollama_host']
)通過這種配置與代碼分離的策略,后續(xù)所有 LlamaIndex 組件都會自動調(diào)用此處指定的 Ollama 本地化部署模型,確保了模型調(diào)用的一致性。
數(shù)據(jù)處理流水線
RAGEngine 類的 build_index 方法負(fù)責(zé)編排完整的數(shù)據(jù)處理流水線。這個方法首先使用 SimpleDirectoryReader 統(tǒng)一加載 documents 目錄下的 PDF 和 DOCX 文件,然后調(diào)用自定義解析器 ResumeNodeParser,把原始 Document 對象轉(zhuǎn)換為結(jié)構(gòu)化的 TextNode 對象列表(LlamaIndex 中表示文本塊的標(biāo)準(zhǔn)化數(shù)據(jù)結(jié)構(gòu))。
# core/rag_engine.py -> build_index 方法核心邏輯
from llama_index.core import SimpleDirectoryReader
# ...
# 1. 統(tǒng)一加載異構(gòu)文件
reader =
SimpleDirectoryReader(input_files=files_to_process)
documents = reader.load_data()
# 2. 調(diào)用自定義解析器生成節(jié)點
parser = ResumeNodeParser()
all_nodes =
parser.get_nodes_from_documents(documents)
#
... 后續(xù)的索引構(gòu)建與結(jié)構(gòu)化提取將基于 all_nodes 和 documents 進(jìn)行3.2簡歷節(jié)點解析器
通用文本分塊策略對于簡歷這類具有明確章節(jié)結(jié)構(gòu)的文檔,往往效果不好。這個系統(tǒng)實現(xiàn)了一個自定義的 ResumeNodeParser,能夠識別簡歷的上下文結(jié)構(gòu),實現(xiàn)更精準(zhǔn)的語義分割。這個組件的實現(xiàn)位于 core/rag_engine.py中,設(shè)計思想包含以下三點。
1.基于章節(jié)標(biāo)題分割:解析器通過正則表達(dá)式識別“核心技能”、“工作經(jīng)歷”等章節(jié)標(biāo)題,把這些標(biāo)題出現(xiàn)的位置作為文本塊的分割點。
2.注入語義元數(shù)據(jù):在創(chuàng)建 TextNode 時,解析器會把識別出的章節(jié)類型(如 work_experience)作為元數(shù)據(jù)附加到節(jié)點上。
3.二次精細(xì)分割:對于內(nèi)容較長的章節(jié)(如“工作經(jīng)歷”),解析器會進(jìn)行二次分割,確保每個文本塊的長度適中。
# core/rag_engine.py ->ResumeNodeParser._parse_nodes 方法
import re
from llama_index.core.node_parser import
NodeParser
from llama_index.core.schema import TextNode
# ...
class ResumeNodeParser(NodeParser):
def
_parse_nodes(self, documents: List[Document], **kwargs: Any) ->
List[BaseNode]:
all_nodes: List[BaseNode] = []
# ...
# 1. 定義章節(jié)標(biāo)題與類型的映射
section_map = {
"核心技能":
"skills", "工作經(jīng)歷": "work_experience",
"項目經(jīng)歷":
"projects", "教育背景": "education",
}
# 2. 使用正則表達(dá)式在文本中找到所有章節(jié)標(biāo)題
pattern = r"^\s*(?i)(" +
"|".join(section_map.keys()) + r")[\s\n:]*"
matches = list(re.finditer(pattern, full_text, re.MULTILINE))
# 3. 遍歷匹配結(jié)果,根據(jù)標(biāo)題邊界創(chuàng)建塊
for i, match in enumerate(matches):
# ... 省略邊界計算代碼 ...
chunk_text = full_text[chunk_start:chunk_end].strip()
# 4. 獲取標(biāo)題并分配元數(shù)據(jù)
title = match.group(1)
chunk_type = section_map.get(title, "others")
# 5. 創(chuàng)建并添加帶有元數(shù)據(jù)的TextNode
node = TextNode(text=chunk_text, metadata=doc_parts[0].metadata.copy())
node.metadata["chunk_type"] = chunk_type
all_nodes.append(node)
# ...
return all_nodes3.3結(jié)構(gòu)化信息存儲
系統(tǒng)選用輕量級的 SQLite 數(shù)據(jù)庫,實現(xiàn)持久化地存儲從簡歷中提取出的結(jié)構(gòu)化信息,并通過一個專門的數(shù)據(jù)訪問類 StructuredStore 來封裝所有數(shù)據(jù)庫操作,實現(xiàn)業(yè)務(wù)邏輯與數(shù)據(jù)存儲的解耦。這個實現(xiàn)過程可以分為以下兩個主要步驟。
設(shè)計數(shù)據(jù)存儲表
在 core/structured_store.py 的 _create_table 方法中,定義了名為 candidates 的數(shù)據(jù)表結(jié)構(gòu)。這個表將最常用于候選人概覽和排序的字段設(shè)為獨立列,而把完整的候選人檔案序列化為 JSON 字符串后存儲在 profile_json 列中,兼顧了查詢效率與信息完整性。
# core/structured_store.py ->_create_table 方法
import sqlite3
class StructuredStore:
def
_create_table(self):
with sqlite3.connect(self.db_path) as conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS
candidates (
name TEXT PRIMARY KEY,
file_name TEXT,
overall_score INTEGER,
recommendation TEXT,
summary TEXT, profile_json
TEXT
)
""")數(shù)據(jù)的寫入和查詢接口
數(shù)據(jù)表的寫入操作由 save_profile 方法實現(xiàn),接收一個 CandidateProfile Pydantic 對象,序列化后存入數(shù)據(jù)庫。這個方法使用 INSERT OR REPLACE 語句,保證了數(shù)據(jù)攝取流程的冪等性(多次執(zhí)行相同操作產(chǎn)生相同結(jié)果的特性)。
# core/structured_store.py -> save_profile方法
from .schemas import CandidateProfile
class StructuredStore:
def
save_profile(self, profile: CandidateProfile, file_name: str):
with sqlite3.connect(self.db_path) as conn:
conn.execute("""
INSERT OR REPLACE INTO
candidates (...) VALUES (?, ?, ?, ?, ?, ?)
""", (
profile.name, file_name,
profile.overall_match_score,
profile.recommendation,
profile.summary, profile.json()
))3.4基于 Pydantic 的結(jié)構(gòu)化信息提取鏈
結(jié)構(gòu)化提取的實際效果,在很大程度上取決于提示詞的設(shè)計質(zhì)量。智能簡歷篩選系統(tǒng)在 core/application.py 中構(gòu)建了一個高指令性的提示詞模板,其中包括了角色扮演、動態(tài)注入招聘需求、明確評估規(guī)則以及集成格式指令等關(guān)鍵要素。提示詞模板的示例內(nèi)容如下。
# core/application.py -> _initialize_extraction_chain 提示詞模板
prompt_template_str = """
你是一位極其嚴(yán)格和挑剔的AI招聘專家。你的唯一目標(biāo)是根據(jù)下面提供的"職位描述(JD)",對"簡歷原文"進(jìn)行無情的、差異化的評估。
**職位描述 (JD):**
---
{jd_content}
---
**核心評估指令:**
1. **嚴(yán)格對照**: 嚴(yán)格將簡歷內(nèi)容與JD中的"任職要求"進(jìn)行逐條比對。
2. **RAG經(jīng)驗是關(guān)鍵**: ...
**JSON輸出格式指令:**
{format_instructions}
**簡歷原文:**最后,系統(tǒng)利用 LCEL 把輸入、提示詞、大模型和輸出解析器優(yōu)雅地串聯(lián)起來,形成一條自動化的處理鏈。其中關(guān)鍵的 _initialize_extraction_chain 方法的代碼實現(xiàn)示例如下。
# core/application.py ->_initialize_extraction_chain
from langchain_core.prompts import
ChatPromptTemplate
from langchain_core.output_parsers import
PydanticOutputParser
from langchain_core.runnables import
RunnablePassthrough
# ...
parser =
PydanticOutputParser(pydantic_object=CandidateProfile)
prompt =
ChatPromptTemplate.from_template(template=prompt_template_str)
self.extraction_chain = (
{
"resume_content": RunnablePassthrough(),
"jd_content": lambda x: jd_processor.get_full_jd_text()
}
|
prompt.partial(format_instructinotallow=parser.get_format_instructions())
|
self.llm
|
parser
)3.5集成帶記憶的對話式 RAG 鏈
為了提供流暢的多輪對話體驗,智能簡歷篩選系統(tǒng)必須具備管理對話記憶的能力。LangChain 的 RunnableWithMessageHistory 類為此提供了標(biāo)準(zhǔn)化的解決方案。
支持歷史消息的提示詞
與單次提取任務(wù)不同,對話式任務(wù)的提示詞需要包含歷史交互信息。系統(tǒng)在 _initialize_rag_chain_with_history 方法中,使用了 LangChain 的 MessagesPlaceholder 來實現(xiàn)這一點。
# core/application.py ->_initialize_rag_chain_with_history 提示詞模板
from langchain_core.prompts import
ChatPromptTemplate, MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages([
("system", "你是一個專業(yè)的AI簡歷篩選助手...職位描述(JD):\n{jd_content}"),
MessagesPlaceholder(variable_name="chat_history"),
("human", "候選人簡歷上下文:\n{context}\n\n問題: {question}")
])MessagesPlaceholder(variable_name="chat_history")的作用是在提示詞中預(yù)留一個占位符,LangChain 的記憶機制會自動將歷史對話消息填充到這個位置,從而大模型能夠基于完整的對話上下文生成回答。
基于會話的內(nèi)存管理
為了隔離不同用戶的對話,系統(tǒng)需要為每個獨立的會話維護一份獨立的聊天歷史。ResumeApplication 類通過一個字典 self.chat_histories 和一個輔助方法 get_session_history 來實現(xiàn)此功能。
# core/application.py -> 內(nèi)存管理核心邏輯
from langchain_core.chat_history import
BaseChatMessageHistory
from langchain_community.chat_message_histories
import ChatMessageHistory
# ...
class ResumeApplication:
def
__init__(self, ...):
# ...
self.chat_histories: Dict[str, BaseChatMessageHistory] = {}
def
get_session_history(self, session_id: str) -> BaseChatMessageHistory:
"""根據(jù)session_id獲取或創(chuàng)建聊天歷史記錄。"""
if session_id not in self.chat_histories:
self.chat_histories[session_id] = ChatMessageHistory()
return self.chat_histories[session_id]當(dāng)處理請求的時候,系統(tǒng)會傳入一個唯一的 session_id。get_session_history 方法會根據(jù)此 ID 查找或創(chuàng)建一個 ChatMessageHistory 實例,確保每個用戶的對話歷史得到獨立管理。
封裝 RAG 鏈
最后一步是將基礎(chǔ)的 RAG 鏈與內(nèi)存管理機制進(jìn)行綁定。RunnableWithMessageHistory 承擔(dān)了封裝和連接的功能。它封裝了一個基礎(chǔ) RAG 鏈,并自動為其注入了狀態(tài)管理(記憶)能力。
# core/application.py ->_initialize_rag_chain_with_history 核心封裝邏輯
from langchain_core.runnables.history import
RunnableWithMessageHistory
# ...
# 1. 構(gòu)建一個基礎(chǔ)的RAG鏈
(base_rag_chain)
# 此鏈負(fù)責(zé)檢索、格式化文檔、填充提示詞等核心RAG邏輯
base_rag_chain = (
{"context": retriever | format_docs, "question":
...}
|
prompt
|
self.llm
|
StrOutputParser()
)
# 2. 使用 RunnableWithMessageHistory 對基礎(chǔ)鏈進(jìn)行封裝
self.conversational_rag_chain =
RunnableWithMessageHistory(
base_rag_chain,
self.get_session_history, # 指定獲取歷史記錄的方法
input_messages_key="question", # 指定輸入鍵
history_messages_key="chat_history", # 指定歷史消息在提示詞中的占位符
)3.6Streamlit 應(yīng)用與效果驗證
系統(tǒng)選用 Streamlit 框架,把所有后端能力封裝在 app.py 腳本中。前端的具體實現(xiàn)這部分不做贅述了,感興趣的可以后續(xù)在星球查看源碼,這部分直接介紹下測試文檔后進(jìn)行效果演示。
JD 要求
所有篩選和評估邏輯圍繞“AI 產(chǎn)品經(jīng)理”職位展開。該崗位主要負(fù)責(zé) RAG、AI 工作流等前沿技術(shù)在新能源汽車制造領(lǐng)域的產(chǎn)品化應(yīng)用。具體查看下面截圖

四份簡歷
測試使用四份背景各異的候選人簡歷(人名為虛構(gòu)),分別以 PDF 和 DOCX 格式存儲。這四位候選人在關(guān)鍵評估維度上形成了很好的對比樣本。
候選人 | 工作年限 | 產(chǎn)品經(jīng)驗 | RAG技術(shù)能力 | 制造業(yè)背景 |
張偉 | 8年 | 豐富 | 實戰(zhàn)經(jīng)驗 | 高度匹配 |
李靜 | 6年 | 轉(zhuǎn)型中(2年) | 技術(shù)專家 | 無 |
趙敏 | 6年 | 豐富 | 應(yīng)用經(jīng)驗 | 無 |
王磊 | 10年 | 非常豐富 | 無 | 高度匹配 |

候選人預(yù)覽
在后臺執(zhí)行 streamlit run app.py 命令啟動應(yīng)用后,在前端界面的側(cè)邊欄點擊“執(zhí)行數(shù)據(jù)攝取”按鈕,系統(tǒng)會自動完成對 documents 目錄下所有簡歷的解析、結(jié)構(gòu)化提取和索引構(gòu)建。候選人概覽標(biāo)簽頁展示了數(shù)據(jù)處理與分析的結(jié)果。

這個頁面直觀地呈現(xiàn)了四個候選人的 AI 評估摘要,包括匹配度評分、推薦等級(強烈推薦、可以考慮、不匹配)和一句話總結(jié)。這體現(xiàn)了結(jié)構(gòu)化信息提取鏈的處理效果,以及 SQLite 結(jié)構(gòu)化存儲引擎的支撐作用。系統(tǒng)通過 1-10 分的量化評分機制,結(jié)合“強烈推薦”、“可以考慮”、“不匹配”等直觀的推薦等級,以及大模型生成的核心能力摘要,實現(xiàn)了候選人的快速篩選和排序。
候選人詳情
在候選人概覽視圖的基礎(chǔ)上,招聘人員可以對感興趣的候選人進(jìn)行進(jìn)一步了解。比如在左側(cè)邊欄的“候選人”下拉列表中選擇“李靜”,并切換到“候選人詳情”標(biāo)簽頁后,系統(tǒng)會呈現(xiàn)一份由 AI 自動生成的完整評估報告。

智能問答頁面
系統(tǒng)側(cè)邊欄的“模型配置”下拉框,允許招聘人員根據(jù)本地 Ollama 服務(wù)中已下載的模型列表,隨時切換驅(qū)動問答的大模型。
單輪問答:“請找出所有具備 RAG 項目實戰(zhàn)經(jīng)驗的候選人,并以表格形式展示他們的姓名、相關(guān)項目名稱、使用的技術(shù)棧和量化成果?!?/span>

系統(tǒng)不僅返回了格式規(guī)整的 Markdown 表格,還在答案上方提供了一個可以折疊的思維鏈。
多輪問答 1:“張偉和李靜哪個更適合這個崗位?”

多輪問答 2:“這個 RAG 架構(gòu)設(shè)計的經(jīng)驗,在她的哪個項目得到了體現(xiàn)?”

系統(tǒng)成功地理解了代詞“她”(指代李靜)和上下文中提及的“RAG 架構(gòu)設(shè)計經(jīng)驗”,并精準(zhǔn)地將這項抽象技能與“智能投研報告分析系統(tǒng)”這一具體項目關(guān)聯(lián)起來。這有力地證明了 RunnableWithMessageHistory 組件的有效性,系統(tǒng)具備了真正連貫、有深度的對話能力。
4、寫在最后
框架的核心價值在于抽象化處理。LangChain 的 RunnableWithMessageHistory 把復(fù)雜的多輪對話狀態(tài)管理抽象成簡單的封裝調(diào)用,很大程度提升開發(fā)效率。但是,高層抽象也帶來調(diào)試挑戰(zhàn)。相比之下,原生開發(fā)雖然繁瑣,但問題定位相對直接。
4.1框架選型
LlamaIndex 在數(shù)據(jù)處理與索引構(gòu)建方面較為專業(yè),豐富的 NodeParser、Reader 等組件可以支持精細(xì)化數(shù)據(jù)處理。LangChain 在應(yīng)用鏈編排、Agent 構(gòu)建等方面更具優(yōu)勢,LCEL 的靈活性和強大組件生態(tài)使其成為構(gòu)建復(fù)雜應(yīng)用邏輯的首選。在復(fù)雜項目中,采用混合模式——使用 LlamaIndex 構(gòu)建高效的數(shù)據(jù)處理引擎,將其作為 LangChain 應(yīng)用鏈中的組件進(jìn)行調(diào)用往往能實現(xiàn)更好的效果。
4.2從問答到自主 Agent
這篇文章定位上還是個面向初學(xué)者的入門案例演示,本質(zhì)上仍是“被動式”系統(tǒng)。對于有基礎(chǔ)的盆友,可以在此基礎(chǔ)上把 LCEL 對話鏈升級為基于 ReAct 思想的 Agent。封裝一系列外部 API 作為 Agent 可調(diào)用的工具,例如 schedule_interview 調(diào)用公司日歷系統(tǒng)安排面試,send_assessment_test 調(diào)用在線測評系統(tǒng)發(fā)送技術(shù)筆試,request_portfolio 調(diào)用郵件系統(tǒng)索要候選人作品集,這樣可以實現(xiàn)更加實用的招聘助理的價值。






























