Complete tutorial for integrating HireSquire with LangChain. Covers Python SDK usage, @tool decorator patterns, async workflows, and LangGraph hiring pipelines.
LangChain + HireSquire Python SDK Tutorial: Build AI Hiring Agents
Learn how to integrate HireSquire's resume screening capabilities directly into your LangChain agent workflows. This tutorial covers the Python SDK, @tool decorator usage, async patterns, and LangGraph integration for autonomous hiring pipelines.
pip install hiresquire langchain langchain-openai python-dotenv
Why HireSquire + LangChain?
Integrating HireSquire with LangChain gives your AI agents native resume screening capabilities:
- Native Python tools - First-class @tool decorator support
- Async workflow - Non-blocking screening for agent systems
- Structured outputs - Pydantic models for perfect agent parsing
- LangGraph compatibility - Build stateful hiring pipelines
- Memory integration - Track candidates across conversations
Basic SDK Usage
First, import and initialize the HireSquire client:
from hiresquire import HireSquire
import os
from dotenv import load_dotenv
load_dotenv()
# Initialize client (pass token as first positional arg)
client = HireSquire(os.getenv("HIRESQUIRE_API_TOKEN"))
# Submit a screening job
job = client.jobs.create(
title="Senior Python Developer",
description="Looking for Python developer with 5+ years experience, Django, and API design skills.",
resumes=["./resumes/john_doe.txt", "./resumes/jane_smith.pdf"]
)
# Wait for completion
results = client.jobs.wait(job["job_id"])
# Print qualified candidates
for candidate in results["candidates"]:
if candidate["score"] >= 80:
print(f"✅ {candidate['name']}: {candidate['score']}/100")
print(f" {candidate['summary']}")
LangChain Tool Integration
Create LangChain tools using the @tool decorator for your agents:
from langchain.tools import tool
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_tools_agent
from langchain_core.prompts import ChatPromptTemplate
@tool
def screen_candidates(job_title: str, job_description: str, resume_files: list[str]) -> dict:
"""
Screen candidates against a job description using HireSquire AI.
Args:
job_title: Title of the position
job_description: Detailed job requirements
resume_files: List of paths to resume files
Returns:
Screening results with scores and analysis
"""
client = HireSquire(os.getenv("HIRESQUIRE_API_TOKEN"))
job = client.jobs.create(job_title, job_description, resume_files)
return client.jobs.wait(job["job_id"])
@tool
def generate_interview_email(job_id: int, candidate_id: int) -> str:
"""
Generate a personalized interview invitation email.
Args:
job_id: The ID of the screening job
candidate_id: The ID of the candidate
Returns:
Formatted email content
"""
client = HireSquire(os.getenv("HIRESQUIRE_API_TOKEN"))
result = client.candidates.generate_email(
job_id=job_id,
candidate_id=candidate_id,
email_type="invite",
tone="professional"
)
return result["email"]["body"]
# Initialize agent
tools = [screen_candidates, generate_interview_email]
llm = ChatOpenAI(model="gpt-4-turbo", temperature=0)
prompt = ChatPromptTemplate.from_messages([
("system", "You are an AI recruiting assistant. Use the screen_candidates tool to evaluate resumes, then generate interview emails for qualified candidates (score >= 80)."),
("human", "{input}"),
("agent_scratchpad", "{agent_scratchpad}"),
])
agent = create_openai_tools_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# Run the agent
result = executor.invoke({
"input": "Screen these resumes for the Senior Python Developer role: ./resumes/john_doe.txt, ./resumes/jane_smith.pdf. The job requires 5+ years Python experience with Django. Send interview invites to anyone scoring 80 or higher."
})
Non-Blocking Batch Patterns
For processing multiple jobs concurrently without blocking, submit all jobs first then poll each - or use webhooks for fully event-driven workflows:
import time
from hiresquire import HireSquire
client = HireSquire(os.getenv("HIRESQUIRE_API_TOKEN"))
# Submit multiple jobs upfront (non-blocking)
job_python = client.jobs.create("Python Dev", python_description, python_resumes)
job_react = client.jobs.create("React Dev", react_description, react_resumes)
job_devops = client.jobs.create("DevOps", devops_description, devops_resumes)
all_job_ids = [job_python["job_id"], job_react["job_id"], job_devops["job_id"]]
# Poll all jobs until each completes
all_results = []
for job_id in all_job_ids:
result = client.jobs.wait(job_id, poll_interval=5, timeout=300)
all_results.append(result)
# Or configure a webhook_url when submitting to get async push notifications:
# client.screen(..., webhook_url="https://your-app.com/webhook/hiresquire")
Agent Tip: For large batches, set a webhook_url when submitting each job. HireSquire will POST results to your endpoint when complete - no polling needed, and no risk of timeout in long-running agent sessions.
LangGraph Hiring Pipeline
Build a complete stateful hiring workflow with LangGraph:
from langgraph.graph import StateGraph, END
from typing import TypedDict, List
class HiringState(TypedDict):
job_title: str
job_description: str
resume_files: List[str]
screening_results: dict
qualified_candidates: List[dict]
emails_sent: List[str]
def screen_resumes(state: HiringState) -> HiringState:
client = HireSquire(os.getenv("HIRESQUIRE_API_TOKEN"))
job = client.jobs.create(state["job_title"], state["job_description"], state["resume_files"])
state["screening_results"] = client.jobs.wait(job["job_id"])
return state
def filter_candidates(state: HiringState) -> HiringState:
state["qualified_candidates"] = [
c for c in state["screening_results"]["candidates"]
if c["score"] >= 80
]
return state
def send_interviews(state: HiringState) -> HiringState:
client = HireSquire(os.getenv("HIRESQUIRE_API_TOKEN"))
state["emails_sent"] = []
for candidate in state["qualified_candidates"]:
result = client.candidates.generate_email(
job_id=state["screening_results"]["job_id"],
candidate_id=candidate["id"],
email_type="invite",
tone="professional"
)
# Send email via your service
state["emails_sent"].append(candidate["name"])
return state
# Build the graph
workflow = StateGraph(HiringState)
workflow.add_node("screen", screen_resumes)
workflow.add_node("filter", filter_candidates)
workflow.add_node("interview", send_interviews)
workflow.set_entry_point("screen")
workflow.add_edge("screen", "filter")
workflow.add_edge("filter", "interview")
workflow.add_edge("interview", END)
app = workflow.compile()
# Execute the pipeline
result = app.invoke({
"job_title": "Senior Python Developer",
"job_description": "5+ years Python, Django, API design...",
"resume_files": ["./resumes/1.txt", "./resumes/2.txt", "./resumes/3.txt"]
})
Error Handling for Agents
Implement robust error handling for production agent systems:
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))
def reliable_screening(title: str, description: str, resumes: list):
try:
client = HireSquire(api_token=os.getenv("HIRESQUIRE_API_TOKEN"))
job = client.jobs.create(title, description, resumes)
return client.jobs.wait(job["job_id"], timeout=300)
except Exception as e:
if "rate_limit" in str(e):
raise # Let retry handle it
elif "invalid_token" in str(e):
# Alert system - token needs rotation
raise
else:
# Log and return partial results
return {"error": str(e), "status": "failed"}
Handling Bad Inputs
Before passing agent inputs to the SDK, validate them to avoid API 422 errors and handle timeouts gracefully:
def safe_screen_candidates(title: str, description: str, resumes: list) -> dict:
# 1. Validate inputs
if not title or len(title.strip()) < 5:
return {"error": "Validation failed: Title is too short or empty."}
if not description or len(description.strip()) < 50:
return {"error": "Validation failed: Description must be at least 50 characters."}
valid_resumes = [r for r in resumes if os.path.exists(r) and os.path.getsize(r) > 0]
if not valid_resumes:
return {"error": "Validation failed: No valid resume files provided."}
# 2. Execute with safety net
try:
client = HireSquire(os.getenv("HIRESQUIRE_API_TOKEN"))
job = client.jobs.create(title, description, valid_resumes)
# 3. Handle asynchronous timeout gracefully
try:
return client.jobs.wait(job["job_id"], timeout=120)
except TimeoutError:
return {
"status": "processing",
"job_id": job["job_id"],
"message": "Job is taking longer than expected. Continue other tasks and poll later."
}
except Exception as e:
return {"error": f"API Error: {str(e)}", "status": "failed"}
Next Steps
Continue building your agent system with these resources:
- CLI Guide - Quick command-line testing
- MCP Server - Claude Desktop integration
- REST API - Advanced custom integrations
- Error Handling - Production-grade patterns
The HireSquire Python SDK is designed from the ground up for agent integration. With native LangChain support, async operations, and structured outputs, you can build production-ready hiring agents in minutes.