利用AI和大型語言模型從履歷到求職信,使用Python和Streamlit
這裡有一個方法,利用不到100行代碼,幫你構建一個大型語言模型(LLM)應用,將你的履歷轉換為針對特定工作的求職信。
Piero Paialunga
2025年2月5日
16分鐘閱讀
照片來源:João Ferrão於Unsplash
免責聲明:使用AI來撰寫求職信或履歷的想法並不是我首創的。很多人之前已經成功地做過這件事,並從這個想法建立了網站甚至公司。這只是一個教程,教你如何使用Python和幾行代碼構建自己的求職信AI生成應用。所有代碼都可以在我的公共Github文件夾中找到。享受吧。🙂
引言
佩普·瓜迪奧拉是一位(非常成功的)曼城足球教練。在巴薩的梅西年代,他發明了一種名為「Tiki-Taka」的足球風格。這意味著你一接到球,就立即傳球,甚至不需要控制球。你可以在進球前傳球30到40次。
十多年後,我們看到瓜迪奧拉和他的巴薩所創造的這種踢球方式已經不再流行。如果你看曼城的比賽,他們接到球後會立即尋找前鋒或邊鋒。只需要幾次垂直傳球,立刻尋找機會。這樣的方式雖然更可預測,但由於頻繁進行,最終你會找到攻擊的空間。
我認為求職市場在某種程度上也朝著這個方向發展。
過去,你有機會親自到公司遞交履歷,和他們交談,參加面試,與人互動。你會花幾周的時間準備這次出行,潤飾你的履歷,檢討問題和答案。
對許多人來說,這種老派的策略依然有效,我相信這一點。如果你有良好的社交機會,或正確的時機和地點,親自遞交履歷非常有效。人們喜愛人際互動,而認識某人確實能帶來很大的幫助。
但同時也需要考慮到另一種方法。像LinkedIn、Indeed等公司,以及整個互聯網完全改變了遊戲規則。你可以向許多公司發送大量履歷,依靠統計數據找到工作。AI更進一步改變了這個遊戲。現在有許多AI工具可以幫你針對特定公司調整履歷,提升履歷的吸引力,或者製作針對工作的求職信。的確,有很多公司向求職者提供這類服務。
我想說的是,我對這些公司的運作方式並無意見,但他們使用的AI其實並不完全是「他們的AI」。我的意思是,如果你使用ChatGPT、Gemini或全新的DeepSeek來完成相同的任務,結果很可能不會比你在他們網站上使用的(付費)工具差。你實際上是在為一個後端API支付「商品費用」,這個API完成的工作本來就可以通過ChatGPT實現。這是公平的。
不過,我想向你展示,使用大型語言模型創建自己的「履歷助手」其實非常簡單且便宜。特別是我想專注於求職信。你給我你的履歷和工作描述,我就能給你一封可以複製到LinkedIn、Indeed或電郵的求職信。
這樣看起來會是這樣:
(圖片由作者製作,圖片來源於作者)
現在,大型語言模型(LLMs)是專門生成文本的AI模型。更具體地說,它們是巨型機器學習模型(即使是小型的也很大)。
這意味著構建自己的LLM或從頭訓練一個是非常昂貴的。我們不會這樣做。我們將使用一個運行良好的LLM,並明智地指導它執行我們的任務。更具體地說,我們將用Python和一些API來實現這一點。正式來說,這是一個付費API。不過,自從我開始這個項目(經歷了所有的試錯過程)以來,我花費的還不到30美分。你可能只需花4或5美分。
此外,我們將製作一個工作應用,讓你在幾次點擊中就能擁有你的求職信。這是一個幾百行代碼的努力。
為了激勵你,這裡是最終應用的截圖:
(圖片由作者製作)
挺酷的吧?我花了不到5小時從零開始建造整個東西。相信我,這真的很簡單。在這篇博客文章中,我們將按順序描述:
1. LLM API策略。這一部分將幫助讀者了解我們使用了哪些LLM代理以及我們如何連接它們。
2. LLM對象。這是使用Python實現上述LLM API策略的部分。
3. Web應用和結果。LLM對象然後通過Streamlit轉換為Web應用。我會告訴你如何訪問它以及一些結果。
4. 我會儘量具體,讓你擁有一切需要自己動手的材料,但如果這些內容過於技術性,隨時可以跳到第三部分,享受日落吧🙃。
開始吧!
1. LLM API策略
這是這個項目的機器學習系統設計部分,我保持得非常簡單,因為我希望最大限度地提高整體可讀性(而且老實說,這並不需要更複雜)。
我們將使用兩個API:
1. 文檔解析LLM API:將讀取履歷並提取所有有意義的信息。這些信息將放入一個.json文件中,以便在生產中,我們可以將已處理的履歷存儲在內存中。
2. 求職信LLM API:這個API將讀取解析後的履歷(來自前一個API的輸出)和工作描述,並輸出求職信。
(圖片由作者製作,圖片來源於作者)
兩個主要點:
1. 這項任務的最佳LLM是什麼?對於文本提取和摘要,LLama或Gemma被認為是相對便宜且有效的LLM。由於我們將使用LLama進行摘要任務,為了保持一致性,我們也可以將其應用於另一個API。如果你想使用其他模型,隨意。
2. 我們如何連接這些API?有多種方法可以做到這一點。我決定試用Llama API。文檔並不是特別豐富,但運作良好,並且允許你玩轉多種模型。你需要登錄、購買一些信用(1美元就足夠了),並保存你的API密鑰。如果你想換成其他解決方案(如Hugging Face或Langchain),也可以。
好了,現在我們知道該怎麼做,我們只需要在Python中實現它。
2. LLM對象
我們首先需要的是實際的LLM提示。在API中,提示通常用字典傳遞。由於它們可能相當長,且結構總是相似,因此將它們存儲在.json文件中是有意義的。我們將讀取這些JSON文件並將其用作API調用的輸入。
2.1 LLM提示
在這個.json文件中,你將有模型(你可以隨意命名)和內容,即LLM的指令。當然,內容鍵有一個靜態部分,即「指令」,還有一個動態部分,即API調用的具體輸入。例如:這是我為第一個API創建的.json文件,命名為resume_parser_api.json:
“`json
{
“model”: “llama3.3-70b”,
“messages”: [
{
“role”: “user”,
“content”: “You are a resume parser. You will extract information from this resume and put them in a .json file. The keys of your dictionary will be first_name, last_name, location, work_experience, school_experience, skills. In selecting the information, keep track of the most insightful.”
}
]
}
“`
從「content」中可以看到靜態調用:
「你是一個履歷解析器。你將從這份履歷中提取信息並將其放入一個.json文件中。你的字典鍵將是first_name, last_name, location, work_experience, school_experience, skills。在選擇信息時,請保持對最有見地信息的追蹤。」
我想從「.json」文件中提取的鍵是:
[first_name, last_name, location, work_experience, school_experience, skills]
隨意添加你想從履歷中「提取」的更多信息,但記住,這些內容應該只對你的求職信有意義。具體的履歷將在這段文本之後添加,以形成完整的調用/指令。稍後會詳細說明。
接下來是cover_letter_api.json的指令:
“`json
{
“model”: “llama3.3-70b”,
“messages”: [
{
“role”: “user”,
“content”: “You are an expert in job hunting and a cover letter writer. Given a resume json file, the job description, and the date, write a cover letter for this candidate. Be persuasive and professional. Resume JSON: {resume_json} ; Job Description: {job_description}, Date: {date}”
}
]
}
“`
現在的指令是:
「你是一位求職專家和求職信撰寫者。給定一個履歷json文件、工作描述和日期,為這位候選人撰寫一封求職信。要求有說服力和專業性。履歷JSON: {resume_json} ; 工作描述: {job_description}, 日期: {date}」
如你所見,這裡有三個佔位符:「Resume_json」、「job_description」和「date」。與之前一樣,這些佔位符將被相應的信息替換,以形成完整的提示。
2.2 constants.py
我創建了一個非常小的constants.py文件,裡面包含兩個.json提示文件的路徑和你需要從LLamaApi生成的API。修改此文件,如果你想在本地運行該文件。
“`python
LLM_API_KEY = “your_api_key”
RESUME_PARSER_JSON_FILE = “your_resume_parser_instruction_file_path.json”
COVER_LETTER_JSON_FILE = “your_cover_letter_instruction_file_path.json”
“`
2.3 file_loader.py
這個文件是一組用於加載履歷的「加載器」。雖然有點無聊,但卻很重要。
“`python
import os
from docx import Document
import PyPDF2
def read_docx(file_path):
“””讀取.docx文件並返回文本內容。”””
try:
doc = Document(file_path)
text = []
for paragraph in doc.paragraphs:
text.append(paragraph.text)
return ‘n’.join(text)
except Exception as e:
return f”Error reading .docx file: {e}”
def read_pdf(file_path):
“””讀取.pdf文件並返回文本內容。”””
try:
with open(file_path, ‘rb’) as pdf_file:
reader = PyPDF2.PdfReader(pdf_file)
text = []
for page in reader.pages:
text.append(page.extract_text())
return ‘n’.join(text)
except Exception as e:
return f”Error reading .pdf file: {e}”
def read_document(file_path):
“””判斷文件類型並相應地讀取文檔。”””
if not os.path.exists(file_path):
return “File not found. Please check the file path.”
_, file_extension = os.path.splitext(file_path)
if file_extension.lower() == ‘.docx’:
return read_docx(file_path)
elif file_extension.lower() == ‘.pdf’:
return read_pdf(file_path)
else:
return “Unsupported file format. Please use .docx or .pdf.”
“`
2.4 cover_letter.py
LLM策略的完整實現可以在我命名為CoverLetterAI的對象中找到。代碼如下:
“`python
from file_loader import *
import json
from constants import *
from llamaapi import LlamaAPI
from datetime import datetime
class CoverLetterAI():
def __init__(self, resume_parser_api_json_file = RESUME_PARSER_JSON_FILE, llm_api_key = LLM_API_KEY,
cover_letter_api_json_file = COVER_LETTER_JSON_FILE):
self.load_config(resume_parser_api_json_file, cover_letter_api_json_file, llm_api_key)
def load_api_file(self, api_json_file):
“””
該函數讀取api json文件並將其加載為Python變量。
—-
input:
api_json_file: json文件路徑
output:
api_content: json文件內容
—
“””
with open(api_json_file, ‘r’) as file:
api_content = json.load(file)
return api_content
def load_config(self, resume_parser_api_json_file, cover_letter_api_json_file, llm_api_key):
“””
該函數加載將使用的配置。
特別是,它讀取apis,載入LlamaAPI環境並提取今天的日期。
—
input:
resume_parser_api_json_file: 履歷解析指令json的文件路徑
cover_letter_api_json_file: 求職信指令json的文件路徑
llm_api_key: 來自llamaapi.com的api密鑰
output:
None.
—
“””
self.llm_api_key = llm_api_key
self.llama = LlamaAPI(self.llm_api_key)
self.resume_api_content = self.load_api_file(resume_parser_api_json_file)
self.cover_letter_api_content = self.load_api_file(cover_letter_api_json_file)
today = datetime.today()
formatted_date = today.strftime(“%d – %b – %Y”)
self.date_today = formatted_date
def connect_resume(self):
“””該函數讀取履歷解析的api_content並添加具體的履歷信息
—
input:
None
output:
None
—
“””
self.resume_api_content[‘messages’][0][‘content’] = self.resume_api_content[‘messages’][0][‘content’] + ‘n Resume:’ + self.resume
def profile_candidate(self):
“””
該函數處理履歷並將候選人信息存儲在json文件和字符串中。
—
input:
None
output:
json_content: 解析後的履歷的json版本
—
“””
response = self.llama.run(self.resume_api_content)
success = False
while not success:
try:
profiled_person = response.json()[‘choices’][0][‘message’][‘content’]
success = True
except:
continue
start = profiled_person.find(““`json”) + len(““`json”)
end = profiled_person.find(““`”, start)
json_content = profiled_person[start:end].strip()
self.profile_dict = json.loads(json_content)
self.profile_str = json_content
return json_content
def add_job_description(self, job_description_str = None):
“””通過將其粘貼到輸入提示中來添加工作描述的函數。
—
input:
job_description_str: 輸入的工作描述。
output:
job_description: 輸入的工作描述已添加到系統中
“””
print(“Paste the job description below (press Enter twice when done):”)
self.job_description = job_description_str
return job_description_str
def read_candidate_data(self, resume_file_path):
“””
該函數從文件路徑讀取履歷並將其連接到履歷解析api
—
input:
resume_file_path: 履歷存儲的路徑
output:
None
—
“””
self.resume_file_path = resume_file_path
self.resume = read_document(self.resume_file_path)
self.connect_resume()
def prepare_cover_letter_api(self):
“””
該函數通過添加具體的個人資料信息、工作描述和今天的日期來準備求職信指令
—
input:
None
output:
None
—
“””
instruction = self.cover_letter_api_content[‘messages’][0][‘content’]
instruction = instruction.replace(‘{resume_json}’, self.profile_str)
instruction = instruction.replace(‘{job_description}’, self.job_description)
instruction = instruction.replace(‘{date}’, self.date_today)
self.cover_letter_api_content[‘messages’][0][‘content’] = instruction
def write_cover_letter(self):
“””
該函數撰寫求職信。
—
input:
None
output:
cover_letter_response: LLM的’字符串’響應
—
“””
self.prepare_cover_letter_api()
response = self.llama.run(self.cover_letter_api_content)
cover_letter_response = response.json()[‘choices’][0][‘message’][‘content’]
return cover_letter_response
“`
我花了相當多的時間來使一切模塊化且易於閱讀。我也為所有函數添加了很多註釋,以便你能清楚地看到每個部分的功能。那麼,我們如何使用這個強大的工具?
整個代碼只需5行簡單的運行。如下:
“`python
from cover_letter import CoverLetterAI
cover_letter_AI = CoverLetterAI()
cover_letter_AI.read_candidate_data(‘path_to_your_resume_file’)
cover_letter_AI.profile_candidate()
cover_letter_AI.add_job_description(‘Insert job description’)
cover_letter_AI.write_cover_letter()
“`
依次來說:
1. 你調用CoverLetterAI對象。它將成為整個過程的明星。
2. 你給我履歷的路徑。可以是PDF或Word,我會讀取你的信息並存儲在變數中。
3. 你調用profile_candidate(),我運行我的第一個LLM。這個過程將候選人的文字信息處理並創建我們將用於第二個LLM的.json文件。
4. 你給我工作描述,並將其添加到系統中。已存儲。
5. 你調用write_cover_letter(),我運行我的第二個LLM,根據工作描述和履歷.json文件生成求職信。
3. Web應用和結果
這就是全部內容。你在前面的段落中看到了這篇博客文章的所有技術細節。
為了讓你更加驚艷並展示其功能,我還將其製作成一個Web應用,你只需上傳履歷,添加工作描述,然後點擊生成求職信。這是鏈接和代碼。
生成的求職信非常出色。
以下是一封隨機生成的求職信:
2025年2月1日
招聘經理,
[公司名我故意模糊]
我很高興申請[公司名我故意模糊]的傑出AI工程師職位,在這裡我可以利用我對構建負責任且可擴展的AI系統的熱情,徹底改變銀行業。作為一名經驗豐富的機器學習工程師和研究員,擁有堅實的物理學和工程背景,我相信我的技能和經驗與該角色的要求相符。
我在辛辛那提大學獲得航空航天工程及工程力學的博士學位,並在羅馬托爾維加大學獲得複雜系統和大數據的物理碩士學位,擁有理論和實踐知識的獨特結合。我在開發和部署AI模型、設計和實施機器學習算法以及處理大型數據集方面的經驗,使我具備推動AI工程創新的能力。
作為辛辛那提大學的研究和教學助理,我應用代理模型檢測和分類管道中的裂紋,在損傷檢測實驗中提高了14%的準確率。我還利用深度學習算法開發代理模型,加速有限元方法(FEM)模擬,從而實現了1M倍的計算時間減少。我在為對AI感興趣的青少年教授信號處理和圖像處理課程方面的經驗,鍛煉了我有效傳達複雜概念的能力。
在我之前作為Gen Nine, Inc.、Apex Microdevices和Accenture的機器學習工程師的角色中,我成功設計、開發並部署了多項AI驅動的解決方案,包括配置毫米波雷達和Jetson設備進行數據收集、實施尖端點雲算法以及領導FastMRI項目以加速MRI掃描時間。我精通Python、TensorFlow、PyTorch和MATLAB等編程語言,以及在AWS、Docker和Kubernetes等雲平台上的經驗,使我能夠開發和部署可擴展的AI解決方案。
我特別被[公司名我故意模糊]對創建負責任和可靠的AI系統的承諾所吸引,這些系統優先考慮客戶體驗和簡便性。我對跟蹤最新AI研究的熱情,以及在生產中明智應用新技術的能力,與公司的願景相符。我對能夠與跨職能的工程師、研究科學家和產品經理團隊合作,交付AI驅動的產品,徹底改變[公司名我故意模糊]服務客戶的方式感到興奮。
除了我的技術技能和經驗,我還擁有優秀的溝通和演示能力,這在我於Towards Data Science的技術寫作經驗中得到了證明,我撰寫了關於機器學習和數據科學的全面文章,每月吸引了超過50,000名觀眾。
感謝您考慮我的申請。我期待與您討論我的技能和經驗如何為[公司名我故意模糊]的成功作出貢獻,以及[公司名我故意模糊]的使命,即通過AI為銀行業帶來人性化和簡便性。我相信,我對AI的熱情、技術專業知識以及協作工作的能力,將使我成為您團隊的寶貴資產。
誠摯地,
Piero Paialunga
這些求職信看起來就像我為特定工作描述所寫的那樣。不過,到了2025年,你需要小心,因為招聘經理確實知道你在使用AI來撰寫求職信,而「計算機語氣」非常容易被識別(例如,「eager」這個詞就非常「ChatGPT風格」)。因此,我想說明,使用這些工具時要謹慎。當然,你可以利用它們建立「模板」,但一定要添加你的個人風格,否則你的求職信將與其他數千份申請者的求職信完全相同。
這是構建Web應用的代碼。
4. 結論
在這篇博客文章中,我們探討了如何使用LLM將你的履歷和工作描述轉換為特定的求職信。我們觸及了以下幾點:
1. AI在求職中的應用。在第一章中,我們討論了AI如何徹底改變求職過程。
2. 大型語言模型的概念。設計LLM API非常重要,我們在第二段中做到了這一點。
3. LLM API實現。我們用Python有機而高效地實現了LLM APIs。
4. Web應用。我們使用Streamlit構建了一個Web應用API,展示了這種方法的強大。
5. 這種方法的局限性。我認為AI生成的求職信確實非常好,內容切合、專業且精心製作。然而,如果每個人都開始使用AI來撰寫求職信,它們看起來會非常相似,或至少都有相同的語氣,這並不好,值得深思。
5. 參考文獻及其他精彩實現
我認為提到許多在我之前已經提出這個想法並公開分享的人是公平的。這裡列舉幾位我在網上找到的。
Cover Letter Craft由Balaji Kesavan創建,是一個實現類似於使用AI撰寫求職信的Streamlit應用。我們與他的應用的不同之處在於,我們直接從Word或PDF中提取履歷,而他的應用則要求複製和粘貼。不過,我認為這位創作者非常有才華且富有創意,值得一看他的作品。
Randy Pettus也有類似的想法。他的方法與本教程所提及的不同之處在於,他非常具體地詢問信息,例如「當前招聘經理」和模型的溫度。這非常有趣(且聰明),因為你可以清楚地看到他如何引導AI生成他所喜歡的求職信。非常推薦。
Juan Esteban Cepeda的應用也做得很好。你也可以看出,他在努力將其打造成一個不僅僅是簡單的streamlit應用,因為他添加了公司鏈接和用戶評價。幹得好,努力非凡。🙂
6. 關於我!
再次感謝你的時間,這對我來說意義重大❤
我叫Piero Paialunga,這是我的照片:
(圖片由作者製作)
我是在辛辛那提大學航空航天工程系的博士生,並且是Gen Nine的機器學習工程師。我在我的博客文章和LinkedIn上討論AI和機器學習。如果你喜歡這篇文章並想了解更多有關機器學習的內容,並跟隨我的研究,你可以:
A. 在LinkedIn上關注我,我會發布所有故事。
B. 訂閱我的通訊。這將使你隨時了解新故事,並給你機會發短信給我,詢問所有的修正或疑問。
C. 成為推薦會員,這樣你就不會有「每月最大故事數量」的限制,可以閱讀我(以及其他數千名機器學習和數據科學頂尖作家)有關最新技術的文章。
D. 想和我合作?查看我在Upwork上的費率和項目!
如果你想問我問題或開始合作,請在這裡或在LinkedIn上留言:
piero.paialunga@hotmail.com
以上文章由特價GPT API KEY所翻譯及撰寫。而圖片則由FLUX根據內容自動生成。
🎬 YouTube Premium 家庭 Plan成員一位 只需 HK$148/年!
不用提供密碼、不用VPN、無需轉區
直接升級你的香港帳號 ➜ 即享 YouTube + YouTube Music 無廣告播放