LLM powered content extraction

Introduction#

Gemini through LangChain and LangGraph for placement emails. Four stages: classify, extract, validate/enhance, sanitize privacy. Pydantic schemas keep the graph honest.

Project structure#

The system is organized around services and clients that encapsulate responsibilities:

  • Services: PlacementService (extraction pipeline), EmailNoticeService (non-placement notices), PlacementNotificationFormatter (notification formatting)
  • Clients: GoogleGroupsClient (email fetching)
  • Core: Configuration and logging utilities
  • Orchestration: main.py coordinates fetching and processing

Core components#

  • PlacementService: Implements the four-stage LangGraph pipeline for placement offers, including classification, extraction, validation/enhancement, and privacy sanitization.
  • EmailNoticeService: Processes non-placement notices via a separate LangGraph pipeline with LLM-based classification and extraction.
  • PlacementNotificationFormatter: Formats extracted data into notices using Pydantic models.
  • GoogleGroupsClient: Fetches unread emails from Google Groups via IMAP and extracts forwarded metadata.
  • DatabaseService: Persists notices and placement offers to MongoDB and computes statistics.
  • Configuration: Centralized settings and logging utilities.

Key implementation highlights:

  • LangGraph StateGraph with typed state dictionaries
  • Strict JSON extraction prompts with privacy rules
  • Retry logic with bounded attempts for validation errors
  • Pydantic models for strong schema enforcement
  • Privacy sanitization removing headers and forwarded metadata

Architecture overview#

The system orchestrates email fetching, classification, extraction, validation, and persistence. The primary flow is driven by PlacementService’s LangGraph pipeline.

Detailed component analysis#

PlacementService: four-stage pipeline#

  • State management: GraphState defines the pipeline state (email, classification flags, extracted data, validation errors, retry count).
  • Classification: Keyword scoring over sender, subject, and body; confidence aggregation; threshold-based decision.
  • Extraction: LLM prompt enforces strict schema and JSON output; privacy rules disallow headers/forwarding metadata.
  • Validation and Enhancement: Pydantic validation, consistency checks, defaults assignment for roles/packages.
  • Privacy Sanitization: Removes headers/forwarded markers from extracted fields.
  • Conditional Edges: Decide whether to extract based on relevance/confidence; retry extraction on validation errors.

Classification algorithm: keyword scoring and confidence#

  • Placement keywords: presence increases score (bounded weight).
  • Company indicators: presence adds modest weight.
  • Negative keywords: reduce confidence (spam/security indicators).
  • Heuristics: presence of names, numbers, email formats.
  • Threshold: classification is relevant if confidence >= 0.6.

Extraction prompt engineering and JSON formatting#

  • Two-phase prompt:
  • Phase 1: Final placement offer classification with strict criteria.
  • Phase 2: Structured extraction with strict schema and privacy rules.
  • Output format: Raw JSON only, no markdown or explanations.
  • Privacy rules: Do not include headers, sender info, or forwarded markers in extracted fields.

Validation and enhancement#

  • Pydantic validation ensures schema compliance.
  • Consistency checks: company name length, presence of students/roles, number_of_offers alignment.
  • Enhancement: default role/package assignment when single role exists; normalize counts.

Privacy sanitization#

  • Removes email headers and forwarded markers from extracted fields (additional_info, roles.package_details, job_location).
  • Ensures no sender/forwarding metadata appears in user-facing content.

Pydantic models and state management#

  • Student: name, enrollment_number, email, role, package
  • RolePackage: role, package, package_details
  • PlacementOffer: company, roles, job_location, joining_date, students_selected, number_of_offers, additional_info, email_subject, email_sender, time_sent
  • GraphState: email, is_relevant, confidence_score, classification_reason, rejection_reason, extracted_offer, validation_errors, retry_count

Integration with LangChain and LangGraph#

  • ChatGoogleGenerativeAI configured with model and temperature.
  • StateGraph with nodes for classify, extract_info, validate_and_enhance, sanitize_privacy, display_results.
  • Conditional edges for decision-making and retries.

Email fetching and orchestration#

  • GoogleGroupsClient fetches unread emails, parses bodies, and extracts forwarded metadata/time.
  • main.py orchestrates email processing: fetch IDs, iterate emails, try PlacementService first, then EmailNoticeService, persist results, and mark read.

Dependency analysis#

External dependencies include LangChain, LangGraph, and Pydantic for LLM integration, state management, and schema enforcement. Internal dependencies stay separate:

  • PlacementService depends on GoogleGroupsClient, ChatGoogleGenerativeAI, and DatabaseService.
  • EmailNoticeService depends on GoogleGroupsClient, ChatGoogleGenerativeAI, and PlacementPolicyService.
  • PlacementNotificationFormatter depends on Pydantic models and DatabaseService.

Performance considerations#

  • Sequential processing of emails: safer and allows granular error handling and retry logic.
  • Retry limits: bounded attempts (e.g., 3) prevent infinite loops and reduce LLM cost.
  • JSON parsing and validation: early failure detection reduces downstream processing overhead.
  • Privacy sanitization: minimal overhead via regex-based cleaning; applied only when needed.
  • Logging and daemon mode: configurable logging minimizes I/O impact in production.

[No sources needed since this section provides general guidance]

Troubleshooting guide#

Common issues and resolutions:

  • Empty or malformed LLM response: treated as non-placement offer; pipeline proceeds to display results.
  • JSON parsing failures: retry up to configured limit; on exhaustion, record validation errors and rejection reason.
  • Validation errors (schema mismatch): retry with bounded attempts; otherwise mark as invalid.
  • Privacy leakage: ensure privacy sanitization runs after extraction; verify headers/forwarded markers are removed.
  • Email fetching failures: check credentials and network connectivity; re-run with verbose logging.

Operational tips:

  • Use verbose logging to inspect confidence scores and classification reasons.
  • Monitor retry counts and validation errors to identify prompt/schema drift.
  • Verify forwarded metadata extraction and sanitization for accurate timestamps and sender attribution.

Conclusion#

Gemini via LangChain/LangGraph runs a four-stage placement pipeline: classify, extract, validate/enhance, sanitize privacy. Pydantic models and retries keep the output usable.

Appendices#

Example input/output transformations#

  • Input: Email subject/body with forwarded headers and metadata.
  • Transformation: Headers and forwarded markers removed; LLM extracts JSON aligned to PlacementOffer schema.
  • Output: PlacementOffer object persisted to database with derived metadata and sanitized fields.

[No sources needed since this section provides general guidance]