ช่วยตัดสินใจสร้าง Resume โดยอิงจาก Job description ด้วย Resumize (My Rust & RAG side project)

Thanaphoom Babparn
6 min readMay 1, 2024

--

Introduction

สวัสดีครับทุกคน กลับมาพบกันอีกครั้งนะครับ สำหรับบทความนี้ จะเป็นการบันทึกการทำ Side project เกี่ยวกับ RAG และ LLM โดยที่รอบนี้ผมเลือกที่จะใช้ Rust ทั้งโปรเจคเลย ก็หวังว่าทุกคนจะสนุกไปกับการอ่าน หรือถ้าหากผู้อ่านสนใจจนได้ลองทำเอง ก็ขอให้สนุกกับการลงมือทำนะครับ 🙇‍♂️

ทั้งนี้ทั้งนั้น ผมได้แนบองค์ความรู้ต่าง ๆ ที่เกี่ยวข้องไว้ด้วย เอาไว้เหมาะสำหรับคนที่ Beginner ที่ Beginner กว่าผมไปอีก หวังว่าจะมีประโยชน์ไม่มากก็น้อยเช่นกันนะครับ 😁

Resumize or เรซูมั้ย?

Resumize หรือว่า เรซูมั้ย? เป็นโปรเจคที่ผมไม่ได้กะให้มันใหญ่ แค่ต้องการให้มันช่วยแนะนำแนวทางการเขียน Resume หรือแนวทางการปรับ Resume โดยที่ไม่ต้องไปเปิดตาม Internet แล้วเจอแต่ Resume Coach ที่เอาแต่เก็บตัง ก็เลยเอา LLM มาใช้ซะเลย แค่นี้แหละครับ Concept 5555555

อยากให้ช่วยหาแนวทางบน Resume โดยไม่ต้องเสียตัง

ป.ล. สำหรับคนที่มี creativity สูงกว่าผม หรือ computation power สูงกว่า เช่นไปที่ที่มี GPU, feel free to do so ครับ ผมไม่มีตัง 55555

Repository

ถ้าระแวงเรื่อง LICENSE ยังไง copy โค้ดแยกไปก็ได้ครับ ไม่หวง

Demo

บางช่วงบางตอนตอนมันรอ resule กดข้ามไปได้เลยครับ ไปรอดูผลลัพธ์เลยก็ได้

Tech Stack

How it’s designed

My simple diagram to explain what is happening on the background

Use-cases

  1. ใส่ Experiences ของตัวเองเข้าไป (ในที่นี้ใช้ JSON เพราะผมไปเอามาจาก Portfolio เว็บตัวเองได้)
  2. ใช้ Job description จากแหล่งต่าง ๆ as input of program
  3. สร้าง Resume และคำแนะนำต่าง ๆ ด้วย RAG technique

Prerequisite knowledge

ก่อนจะเริ่มต้นทำการสร้างนู่นนี่ ผมอยาก give jargon ไว้ให้กับทุกคนก่อนว่า คำที่จะพบเจอหลังจากนี้ มันจะมีอะไร ทำอะไร ๆ แบบคร่าว ๆ จะได้ลด knowledge gap กันก่อนที่จะ Explore ว่าผมทำอะไรไปนะครับ

LLM (Large Language Models)

เป็นคำที่ใช้เรียก AI Model ที่ถูกสร้างขึ้นมา เพื่อจุดประสงค์ในความเข้าใจ และการสร้างสิ่งใหม่ ๆ ได้ใกล้เคียงกับมนุษย์ โดยไอเจ้า LLM เนี้ย มันถูกสร้างขึ้นมาจากข้อมูลมหาศาล และตัว Model ก็จะมีจุดแข็งที่แตกต่าง ตามแต่ที่มันถูกสร้างขึ้นมา บางอันก็เป็น General บางอันก็เก่งเขียนโค้ดไปเลย เป็นต้น

ตัวอย่างเช่น

  • GPT-3/4 (OpenAI)
  • Llama 3 (Meta)

Llama 3

เป็น Open source LLM จากทาง Meta ถูกออกแบบมาให้ใช้ใน use case ของ generative AI ideas ให้กับชาว developers, researchers หรือ general purpose อื่น ๆ

อ่านเพิ่มเติมได้ที่นี่

Prompt Engineering

Prompt Engineering เป็นกระบวนการในการ craft input เพื่อที่จะ guide ให้ generative AI สามารถ product output ให้ตรงกับปัญหาใดปัญหานึงโดยเฉพาะเจาะจง และได้ผลลัพธ์ตามที่คาดหวังไว้

Prompt

เป็นชื่อเรียกของ Input ที่เราจะใช้ในโลกของ generative AI เพื่อที่จะทำให้มันสร้าง response ให้กับเรา อาจจะเป็นคำสั้น ๆ ประโยคยาว ๆ โดยตัว model จะใช้ส่วนนี้แหละ เอาไปสร้าง response ที่เกี่ยวข้อง

System Message, User Message

System Message — เป็นคำเรียกที่ใช้วาง Role ให้กับ LLM เพื่อควบคุมให้ผลลัพธ์อยู่ใน scope ที่เราต้องการมากขึ้น

User Message — เป็น Input ที่เรากรอกเนี่ยแหละ เช่นตัวที่เราพิมพ์เข้าไปใน ChatGPT เป็นต้น

ถ้าเกิดว่าผสมรวมกัน ผลลัพธ์ก็จะกลายเป็นแบบนี้

RAG (Retrieval-Augmented Generation)

Retrieval-Augmented Generation (RAG) เป็นกระบวนการ optimizing output ของ LLM โดยการเพิ่ม knowledge base เข้าไปจากเดิม จาก data ที่มันเคยถูกเทรนมา ก่อนที่จะเริ่มสร้าง response

  • แค่คำว่า Generation แปลว่า เป็นการสร้างข้อมูลขึ้นมาจาก User query ที่ได้รับ แล้วสร้างออกมาเป็นผลลัพธ์
  • แต่ถ้าข้อมูลที่มีมัน general หรือ out of date หรือเราต้องการให้มันมีข้อมูลของเราล่ะ
  • Retrieval-Augmented แปลตรงตัวว่า การดึงข้อมูลจาก Augmented หรือศัพท์โปรแกรมมิ่ง arguments ก็คือมันรับ Source อื่น ๆ เข้าไปพิจารณาได้นั่นเอง
  • คราวนี้ตัว LLM ก็จะมีแหล่งอ้างอิงเพิ่มเติม เพื่อทำให้ผลลัพธ์ของเราอยู่ใน scope ที่ตั้งใจมากขึ้นนั่นเอง

คำอธิบายเพิ่มเติมเกี่ยวกับ RAG ที่ผมว่าอธิบายไว้ดีมาก ๆ

Vector Database

Vector Database เรียกได้ว่าอาจจะเป็น database ที่ดีไซน์มาใหม่โดยใช้งานสำหรับ Vector data ในการทำการ indexing, querying, retrieving ตัว vector data.

ตัว Vector data ก็จะเป็นข้อมูลที่ถูกแปลงให้เป็นในรูปแบบของ Numerical จะมี dimension และ context ของข้อมูลและเก็บออกมาให้เป็นในรูปแบบของ Vectors (สามารถเรียนเกี่ยวกับ Vector เพิ่มเติมได้จากวิชา Theory of Computation หรือ Discrete Math หรือ Physics เลยละกัน ตัว concept vector database ก็มีที่มาจากตรงนั้นน่ะแหละ)

คราวนี้เวลา Vector Database จะเอา Data เราไปหา ก็จะหาจากสิ่งที่มีความคล้ายคลึง (เอาทิศทางของข้อมูลไปหา) แล้วเราก็จะได้ข้อมูลที่มี context หรือ concept ที่คล้ายกับ Input และ expect output ของเรา ขึ้นอยู่กับความคล้ายคลึงของข้อมูล หรือเรียกว่า similarity search

Source: What is a Vector Database?

Qdrant

Qdrant เป็น vector database ที่ใช้ในการทำ similarity search โดยถูกเขียนขึ้น Rust 🦀

Actix Web

Actix Web เป็น web framework ของภาษา Rust หรือเราจะเรียกมันว่าเขียน Backend ด้วยภาษา Rust ก็ได้ ก็สามารถให้ developer สามารถสร้าง Backend ให้กับ Web/Mobile/Desktop Frontend ได้

Dioxus

Dioxus เป็น library ที่ช่วยให้เราสามารถสร้าง Application บน desktop, web, mobile ได้ (เขาบอกมาแบบนี้) โดยที่มีแรงบันดาลใจจาก React

LlamaEdge

เขาบอกว่ามันเป็น The easiest, smallest and fastest local LLM runtime and API server. ก็คือเราเอามาใช้ run local LLM นั่นเอง รวมถึง LlamaEdge มี API Server ที่ใช้ในการ interact กับ model ได้ในรูปแบบของ OpenAI-compatible REST APIs

Let’s begin!

คราวนี้ก็จะมาไล่ไปทีละ Step ในการรันมันขึ้นมา

Run LlamaEdge on locally

ถ้าเกิดอยากได้แบบ Original version สามารถตามไปที่นี่ได้เลยครับ

ส่วนถ้าจะเอาแค่ใช้ในโปรเจคนี้ ให้เป็น Step ดังนี้

  1. ลง WasmEdge
curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s - - plugin wasi_nn-ggml

2. โหลด Llama-3–8B model

curl -LO https://huggingface.co/second-state/Llama-3-8B-Instruct-GGUF/resolve/main/Meta-Llama-3-8B-Instruct-Q5_K_M.gguf

3. ลง API server app ที่ใช้งานกับ model โดยที่ตัว API จะเป็น OpenAI-compatible

curl -LO https://github.com/LlamaEdge/LlamaEdge/releases/latest/download/llama-api-server.wasm

4. ลง Chatbot UI

curl -LO https://github.com/LlamaEdge/chatbot-ui/releases/latest/download/chatbot-ui.tar.gz
tar xzf chatbot-ui.tar.gz
rm chatbot-ui.tar.gz

5. Start API server ให้ model

wasmedge - dir .:. - nn-preload default:GGML:AUTO:Meta-Llama-3–8B-Instruct-Q5_K_M.gguf \
llama-api-server.wasm \
- prompt-template llama-3-chat \
- ctx-size 4096 \
- model-name Llama-3–8B

Run Qdrant by container approach

ใช้ command docker compose หรือ podman compose ที่ลงที่เครื่องได้เลยครับ

podman compose up -d

โดย compose.yml ที่ผมมี จะเป็นดังนี้ really simple for locally

Note — แต่ถ้าไม่อยากใช้ compose ใช้แบบนี้ก็ได้ครับ

docker run -p 6333:6333 -p 6334:6334 \
-v $(pwd)/qdrant_storage:/qdrant/storage:z \
qdrant/qdrant

Run Actix Web

ตัว Backend ก็ใช้ command ให้มัน run on locally

cargo watch -x "run --bin server"

Code

ตัวโค้ด ผมจะอธิบายแบบคร่าว ๆ นะครับ

  1. ตอน start backend application จะทำการโหลด configuration ลง AppState แล้ว create collection for storing document
  2. Expose port ขึ้นอยู่กับ value ใน Setting.toml
  3. API upload document จะรับเป็น Multipart แล้วแปลงผ่าน langchain-rust ทำให้เป็น vector แล้วเอาใส่ใน database
  4. API resume suggestion รับ Path เป็น Job title และ Body เป็น Job description โดยที่ตัว Content-Type ใช้เป็น text/plain ค้นหาประสบการ์ที่เกี่ยวข้องด้วย Job Title และใช้ Job Description เอาไปถาม Llama 3

Example of backend response — resume suggestion

Example of backend response

Run Dioxus desktop application

ก็คือเราจะให้มี Frontend ให้ interact ด้วย จะได้เห็นครบ Flow การทำงาน สามารถรันมันขึ้นมาด้วย command นี้

dx serve --hot-reload --platform desktop

Note — เคสนี้ไม่จำเป็นต้องรัน Tailwind เพราะผม commit CSS ขึ้นไปหมดแล้ว แต่ถ้าอยากจะแก้ Tailwind เพิ่ม ให้ทำตาม instructions นี้แทนนะครับ

Simple desktop application with 2 pages

Code

The way to make an enhancement

ในที่นี่ ผมขอแบ่งออกเป็นแต่ละ Flow ละกันครับ

General

  • ตัวโปรเจคใช้ langchain-rust คิดว่าลองหาความเป็นไปได้ใน crate อื่น ๆ ก็น่าจะทำได้เช่น llm-chain

Upload experience enhancement suggestion

  • คิดว่าถ้าใช้เป็น PDF คง cover ได้หลาย use-case ฝั่ง Backend ก็เปลี่ยนไปใช้ PDFLoader ได้
  • จากการออกแบบแบบนี้ คิดว่าถ้าทำเป็น asynchronous แบบว่า user upload file มาแล้ว => ส่งต่อ file ไปที่อื่น แล้ว response ไปได้เลย => อีก workload ก็ไป upsert document บน vector database
Enhancement upload flow to asynchronous approach by message queue
  • สามารถใช้ user identity ในการแยก document ที่เกี่ยวข้องได้ โดยเราสามารถค้นหาได้ผ่านทาง metadata ใช่มะ แต่ถ้าเราทำ consent ให้ข้อมูลของ experience แชร์ไปมาได้ ก็จะทำให้เราสามารถ suggest resume ได้ดีขึ้นใน part ของ tips

Generate new resume content enhancement

  • ผลลัพธ์ปัจจุบันเป็น Markdown แต่ว่า Dioxus ตอนนี้ยังไม่ support markdown on desktop ดังนั้นถ้าใครทำ Web frontend น่าจะมีตัวที่ให้แสดง markdown ได้ง่าย ๆ อยู่นะ มันน่าจะสวยกว่าด้วย
  • ทำเป็น asynchronous approach ได้เหมือนกัน อาจจะเป็นแบบว่า เรายื่น request แล้วให้แจ้งผลลัพธ์มาเมื่อเสร็จแล้ว เช่นอาจจะส่ง Email หรือส่ง Push notification แล้วให้ตัว result ไปอยู่ใน Inbox ในแอปของเรา
  • คิดว่าน่าจะ promp template ที่ทำให้ผลลัพธ์มันดีขึ้นได้อยู่นะ

Conclusions

เป็นไงกันบ้างครับสำหรับโปรเจคนี้ จริง ๆ ก็สร้างขึ้นมาด้วย mindset RAG เป็นหลัก แต่ไหน ๆ ก็ทำแล้ว จะทำ Backend อย่างเดียวก็ยังไงอยู่ เลยทำมันทั้งหมดเลย

ผลสรุปคือ

  • ผมได้หัดเขียน Rust มากขึ้น
  • ผมได้ทบทวน Actix Web
  • ได้ลองเล่น Qdrant
  • ได้ลองใช้ Dioxus
  • ได้คิดว่า น่าจะถึงเวลาซื้อเครื่องใหม่ หยอก! 😜

ทั้งนี้ทั้งนั้น ถ้าผู้อ่านได้ประโยชน์จากบทความนี้ก็ขอบคุณมากครับ แต่ถ้าตัวโปรเจคไม่เป็นที่น่าสนใจเท่าไหร่ ก็ขออภัยด้วยครับ

ขอบคุณที่อ่านจนจบ ไว้เจอกันใหม่บทความหน้าครับ ขอให้ทุกคนมีความสุข 🙇‍♂️

Facebook: Thanaphoom Babparn
FB Page: TP Coder
LinkedIn: Thanaphoom Babparn
Website: TP Coder — Portfolio

--

--

Thanaphoom Babparn

Software engineer who wanna improve himself and make an impact on the world.