# prajwalachart/langgraph_job_search_agent architecture

> Architecture diagram of the GitHub repository prajwalachart/langgraph_job_search_agent, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-08-01). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/prajwalachart/langgraph_job_search_agent
- Repository: https://github.com/prajwalachart/langgraph_job_search_agent

## Overview

#### Purpose and Entry Points

This is an educational LangGraph-based job-search agent. It accepts a PDF CV, extracts a structured candidate profile, autonomously searches jobs, ranks listings against the CV, and produces a personalized result.

Primary entry points:
- Interactive learning workflow: `job_search_agent.ipynb`
- Streamlit upload-and-results UI: `streamlit_app.py`
- Reusable graph construction: `agent_core.py`

#### Orchestrated Agent Graph

`agent_core.py` defines the LangGraph state and five-stage workflow:

`START → parse_cv → agent ⇄ tools → score → format → END`

The `agent`/`tools` cycle implements ReAct control flow: the LLM determines search actions, invokes job-search tooling, observes results, and may issue additional searches before downstream ranking.

Grounding paths: `agent_core.py`, `job_search_agent.ipynb`.

#### CV Ingestion and Profile Boundary

`cv_parser.py` is the input-normalization boundary. It reads uploaded/local PDF content and uses an LLM to convert unstructured CV text into a typed Pydantic `CVProfile` containing candidate attributes such as skills and experience.

The structured profile becomes the durable candidate representation consumed by job-search planning, scoring, and result formatting.

Grounding paths: `cv_parser.py`, `streamlit_app.py`.

#### LLM Planning and Result Writing

The Groq-hosted LLM serves two distinct responsibilities:
- Parse CV text into the structured profile.
- Drive search decisions and write the final encouraging, personalized summary.

LLM calls are used for semantic interpretation and control decisions; deterministic/local components handle retrieval caching and ranking. The default documented model is Groq’s Llama 3.3 70B variant, with a smaller Groq model as a quota fallback.

Grounding paths: `agent_core.py`, `cv_parser.py`.

#### Job Retrieval Tool and Resilience

`job_tool.py` exposes the `search_jobs` tool used by the graph’s tools node. Its primary external dependency is RapidAPI’s JSearch API for live listings.

Retrieval has an availability and cost boundary:
- Successful searches are cached to avoid repeated JSearch requests.
- Cached listings and `sample_jobs.json` provide offline/demo fallback when the live API is disabled or returns no results.
- Job data crosses from external API responses into the agent state as listings for local scoring.

Grounding paths: `job_tool.py`, `sample_jobs.json`.

#### Local Ranking Stage

`scorer.py` ranks retrieved jobs against the CV with local semantic embeddings. It uses FastEmbed’s `BAAI/bge-small-en-v1.5` model and cosine similarity, executed through ONNX runtime rather than a hosted embedding API.

This stage is intentionally independent of LLM and JSearch quotas after the embedding model’s initial local download. Its output is the ordered set of matched jobs used by the final formatting node.

Grounding paths: `scorer.py`, `agent_core.py`.

#### UI, Observability, and Runtime Dependencies

`streamlit_app.py` provides the operational user flow: upload PDF, launch the graph, and render ranked jobs with application links. It additionally sends Streamlit-run LLM traces to Comet Opik and exposes a trace link; notebook execution intentionally omits tracing.

Material external services are Groq (LLM), RapidAPI/JSearch (job retrieval), and Opik (observability). Python package/runtime dependencies are declared in `requirements.txt`; environment configuration is represented by `config.toml`.

Grounding paths: `streamlit_app.py`, `requirements.txt`, `config.toml`.

Main entry points: [`agent_core.py`](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/agent_core.py) (LangGraph workflow), [`job_tool.py`](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/job_tool.py) (search_jobs), [`streamlit_app.py`](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/streamlit_app.py) (Streamlit UI), [`scorer.py`](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/scorer.py) (Local scorer)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_entry["Entry points"]
  node_notebook["Learning notebook"]
  node_streamlit["Streamlit UI<br/>web UI<br/>[streamlit_app.py]"]
end

subgraph group_workflow["Agent workflow"]
  node_cv_parser["CV parser<br/>ingestion boundary<br/>[cv_parser.py]"]
  node_cv_profile["CVProfile<br/>Pydantic profile<br/>[cv_parser.py]"]
  node_agent_graph["LangGraph workflow<br/>orchestrator<br/>[agent_core.py]"]
  node_agent["Search agent<br/>ReAct planner<br/>[agent_core.py]"]
  node_tools["Tools node<br/>tool executor<br/>[agent_core.py]"]
  node_scorer["Local scorer<br/>semantic ranker<br/>[scorer.py]"]
  node_formatter["Result formatter<br/>LLM writer<br/>[agent_core.py]"]
end

subgraph group_retrieval["Job retrieval"]
  node_job_tool["search_jobs<br/>retrieval tool<br/>[job_tool.py]"]
  node_job_cache[("Job cache<br/>listing cache<br/>[job_tool.py]")]
  node_sample_jobs["Sample listings<br/>offline fallback<br/>[sample_jobs.json]"]
end

subgraph group_services["External services"]
  node_groq{{"Groq LLM<br/>hosted model"}}
  node_jsearch{{"RapidAPI JSearch<br/>job listings API"}}
  node_fastembed{{"FastEmbed / ONNX<br/>local embedding model"}}
  node_opik{{"Comet Opik<br/>trace service"}}
end

node_streamlit -->|"uploaded PDF"| node_cv_parser
node_notebook -->|"runs workflow"| node_agent_graph
node_streamlit -->|"launches graph"| node_agent_graph
node_cv_parser -->|"structured profile"| node_cv_profile
node_cv_parser -->|"extracts profile"| node_groq
node_cv_profile -->|"candidate state"| node_agent_graph
node_agent_graph -->|"plan search"| node_agent
node_agent -->|"tool calls"| node_tools
node_tools -->|"observations"| node_agent
node_agent -->|"search decisions"| node_groq
node_tools -->|"search_jobs"| node_job_tool
node_job_tool -->|"live search"| node_jsearch
node_job_tool -->|"read/write listings"| node_job_cache
node_job_tool -.->|"offline fallback"| node_sample_jobs
node_agent_graph -->|"retrieved listings"| node_scorer
node_cv_profile -->|"skills and experience"| node_scorer
node_scorer -->|"local embeddings"| node_fastembed
node_scorer -->|"ranked jobs"| node_formatter
node_formatter -->|"personalized summary"| node_groq
node_formatter -->|"results and links"| node_streamlit
node_streamlit -.->|"LLM traces"| node_opik

click node_notebook "https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/job_search_agent.ipynb"
click node_streamlit "https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/streamlit_app.py"
click node_cv_parser "https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/cv_parser.py"
click node_cv_profile "https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/cv_parser.py"
click node_agent_graph "https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/agent_core.py"
click node_agent "https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/agent_core.py"
click node_tools "https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/agent_core.py"
click node_scorer "https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/scorer.py"
click node_formatter "https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/agent_core.py"
click node_job_tool "https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/job_tool.py"
click node_job_cache "https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/job_tool.py"
click node_sample_jobs "https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/sample_jobs.json"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_notebook,node_streamlit toneBlue
class node_cv_parser,node_cv_profile,node_agent_graph,node_agent,node_tools,node_scorer,node_formatter toneAmber
class node_job_tool,node_job_cache,node_sample_jobs toneMint
class node_groq,node_jsearch,node_fastembed,node_opik toneRose
```

## Components

### Entry points

- [Learning notebook](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/job_search_agent.ipynb): notebook · Interactive workflow entry point. · `job_search_agent.ipynb`
- [Streamlit UI](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/streamlit_app.py): web UI · Uploads CVs and renders matched jobs. · `streamlit_app.py`

### Agent workflow

- [CV parser](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/cv_parser.py): ingestion boundary · Converts PDF CV text into a typed profile. · `cv_parser.py`
- [CVProfile](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/cv_parser.py): Pydantic profile · Durable structured candidate representation. · `cv_parser.py`
- [LangGraph workflow](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/agent_core.py): orchestrator · Coordinates parse, ReAct search, scoring, and formatting. · `agent_core.py`
- [Search agent](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/agent_core.py): ReAct planner · LLM decides searches and interprets tool observations. · `agent_core.py`
- [Tools node](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/agent_core.py): tool executor · `agent_core.py`
- [Local scorer](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/scorer.py): semantic ranker · Ranks listings with FastEmbed embeddings and cosine similarity. · `scorer.py`
- [Result formatter](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/agent_core.py): LLM writer · Produces a personalized encouraging summary. · `agent_core.py`

### Job retrieval

- [search_jobs](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/job_tool.py): retrieval tool · Retrieves and caches job listings. · `job_tool.py`
- [Job cache](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/job_tool.py): listing cache · Avoids repeated live retrieval requests. · `job_tool.py`
- [Sample listings](https://github.com/prajwalachart/langgraph_job_search_agent/blob/main/sample_jobs.json): offline fallback · Demo fallback when live search is unavailable. · `sample_jobs.json`

### External services

- **Groq LLM**: hosted model · Parses CVs, drives ReAct decisions, and writes results.
- **RapidAPI JSearch**: job listings API
- **FastEmbed / ONNX**: local embedding model · BAAI/bge-small-en-v1.5 semantic embeddings.
- **Comet Opik**: trace service · Receives Streamlit-run LLM traces.

## Connections

- Streamlit UI → CV parser: uploaded PDF
- Learning notebook → LangGraph workflow: runs workflow
- Streamlit UI → LangGraph workflow: launches graph
- CV parser → CVProfile: structured profile
- CV parser → Groq LLM: extracts profile
- CVProfile → LangGraph workflow: candidate state
- LangGraph workflow → Search agent: plan search
- Search agent → Tools node: tool calls
- Tools node → Search agent: observations · Repeats until search is complete.
- Search agent → Groq LLM: search decisions
- Tools node → search_jobs: search_jobs
- search_jobs → RapidAPI JSearch: live search
- search_jobs → Job cache: read/write listings
- search_jobs → Sample listings: offline fallback
- LangGraph workflow → Local scorer: retrieved listings
- CVProfile → Local scorer: skills and experience
- Local scorer → FastEmbed / ONNX: local embeddings
- Local scorer → Result formatter: ranked jobs
- Result formatter → Groq LLM: personalized summary
- Result formatter → Streamlit UI: results and links
- Streamlit UI → Comet Opik: LLM traces
