- upload PDF file
- split PDF file using a text_splitter
- add embeddings (method to embed documents and queries)
- add vector_store
- add documents to vector_store
- query vector_store with a query
In [1]:
from dotenv import load_dotenv
load_dotenv()
Out[1]:
True
In [2]:
import os, asyncio, json
from langchain.chat_models import init_chat_model
from langchain.agents import create_agent, AgentState
from langchain.messages import HumanMessage, AIMessage, ToolMessage
from langchain.tools import tool, ToolRuntime
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_community.utilities import SQLDatabase
from langchain_community.document_loaders import PyPDFLoader
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import Command
from mcp.shared.exceptions import McpError
from mcp.types import CallToolResult, TextContent
from typing import Dict, Any
from tavily import TavilyClient
from pprint import pprint
from dataclasses import dataclass
from datetime import date
DEEPSEEK_MODEL = "deepseek-chat"
DEEPSEEK_BASE_URL = "https://api.deepseek.com"
def deepseek_model(model: str = DEEPSEEK_MODEL, max_tokens=1000, **kwargs):
return init_chat_model(
model=model,
# DeepSeek uses LangChain's OpenAI-compatible transport.
model_provider="openai",
api_key=os.environ["DEEPSEEK_API_KEY"],
base_url=DEEPSEEK_BASE_URL,
max_tokens=max_tokens,
**kwargs,
)
Semantic search¶
In [3]:
loader = PyPDFLoader("resources/acmecorp-employee-handbook.pdf")
data = loader.load()
print(data)
[Document(metadata={'producer': 'ReportLab PDF Library - www.reportlab.com', 'creator': '(unspecified)', 'creationdate': '2025-11-20T23:23:16+00:00', 'author': '(anonymous)', 'keywords': '', 'moddate': '2025-11-20T23:23:16+00:00', 'subject': '(unspecified)', 'title': '(anonymous)', 'trapped': '/False', 'source': 'resources/acmecorp-employee-handbook.pdf', 'total_pages': 1, 'page': 0, 'page_label': '1'}, page_content='Employee Handbook\nNon-Disclosure Agreement (NDA) Policy\nEmployees must protect confidential information belonging to the company, its clients, and partners.\nThis includes, but is not limited to, product roadmaps, customer data, internal communications,\nproprietary algorithms, financial information, and unreleased features. Confidential information may not\nbe shared with unauthorized individuals inside or outside the organization. These obligations continue\nafter employment ends.\nWorkplace Conduct Policy\nEmployees must maintain a respectful, professional environment free from harassment, discrimination,\nand intimidation. All employees are expected to follow organizational values, collaborate effectively,\nand communicate constructively. Disruptive behavior, verbal abuse, or misuse of company systems is\nprohibited. Violations may result in disciplinary action.\nPaid Time Off (PTO) Policy\nFull■time employees accrue PTO according to the following schedule: \x7f 0–1 years of service: 10 days\nper year (0.833 days per month) \x7f 1–3 years of service: 15 days per year (1.25 days per month) \x7f 3+\nyears of service: 20 days per year (1.67 days per month) PTO may be used for vacation, personal\nneeds, or illness. Requests should be submitted in advance through the HR system unless related to\nan emergency. Employees may carry over up to 5 unused PTO days per calendar year. Extended\nabsences exceeding 5 consecutive business days require manager approval.\nTravel & Expense Policy\nEmployees may be reimbursed for reasonable and necessary expenses incurred during approved\nbusiness travel. This includes transportation, lodging, meals, and incidental expenses within\nestablished limits. Receipts must be submitted within 14 days of travel. First-class travel, personal\nexpenses, and non-business activities are not reimbursable. Employees should exercise good\njudgment and cost-effective decision-making when traveling on behalf of the company.')]
In [4]:
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, chunk_overlap=200, add_start_index=True
)
all_splits = text_splitter.split_documents(data)
print(len(all_splits))
3
In [5]:
import hashlib
import math
import re
from langchain_core.embeddings import Embeddings
class HashingEmbeddings(Embeddings):
def __init__(self, size: int = 384):
self.size = size
def _embed(self, text: str) -> list[float]:
vector = [0.0] * self.size
for token in re.findall(r"[a-z0-9]+", text.lower()):
digest = hashlib.md5(token.encode("utf-8")).digest()
index = int.from_bytes(digest[:4], "big") % self.size
sign = 1.0 if digest[4] % 2 == 0 else -1.0
vector[index] += sign
norm = math.sqrt(sum(value * value for value in vector)) or 1.0
return [value / norm for value in vector]
def embed_documents(self, texts: list[str]) -> list[list[float]]:
return [self._embed(text) for text in texts]
def embed_query(self, text: str) -> list[float]:
return self._embed(text)
embeddings = HashingEmbeddings()
In [6]:
from langchain_core.vectorstores import InMemoryVectorStore
vector_store = InMemoryVectorStore(embeddings)
In [7]:
ids = vector_store.add_documents(documents=all_splits)
In [8]:
results = vector_store.similarity_search(
"How many days of vacation does an employee get in their first year?"
)
print(results[0])
page_content='prohibited. Violations may result in disciplinary action.
Paid Time Off (PTO) Policy
Full■time employees accrue PTO according to the following schedule: 0–1 years of service: 10 days
per year (0.833 days per month) 1–3 years of service: 15 days per year (1.25 days per month) 3+
years of service: 20 days per year (1.67 days per month) PTO may be used for vacation, personal
needs, or illness. Requests should be submitted in advance through the HR system unless related to
an emergency. Employees may carry over up to 5 unused PTO days per calendar year. Extended
absences exceeding 5 consecutive business days require manager approval.
Travel & Expense Policy
Employees may be reimbursed for reasonable and necessary expenses incurred during approved
business travel. This includes transportation, lodging, meals, and incidental expenses within
established limits. Receipts must be submitted within 14 days of travel. First-class travel, personal' metadata={'producer': 'ReportLab PDF Library - www.reportlab.com', 'creator': '(unspecified)', 'creationdate': '2025-11-20T23:23:16+00:00', 'author': '(anonymous)', 'keywords': '', 'moddate': '2025-11-20T23:23:16+00:00', 'subject': '(unspecified)', 'title': '(anonymous)', 'trapped': '/False', 'source': 'resources/acmecorp-employee-handbook.pdf', 'total_pages': 1, 'page': 0, 'page_label': '1', 'start_index': 812}
RAG Agent¶
In [9]:
@tool
def search_handbook(query: str) -> str:
"""Search the employee handbook for information"""
results = vector_store.similarity_search(query)
return results[0].page_content
In [10]:
agent = create_agent(
model=deepseek_model(),
tools=[search_handbook],
system_prompt="You are a helpful agent that can search the employee handbook for information."
)
In [13]:
response = agent.invoke(
{"messages": [HumanMessage(content="How many days of vacation does an employee get in their first year?")]}
)
In [16]:
for token, metadata in agent.stream(
{"messages": [HumanMessage(content="How many days of vacation does an employee get in their first year?")]},
stream_mode = "messages"
):
if token.content:
print(token.content, end = '', flush = True)
Let me search the employee handbook for information about vacation days.prohibited. Violations may result in disciplinary action. Paid Time Off (PTO) Policy Full■time employees accrue PTO according to the following schedule: 0–1 years of service: 10 days per year (0.833 days per month) 1–3 years of service: 15 days per year (1.25 days per month) 3+ years of service: 20 days per year (1.67 days per month) PTO may be used for vacation, personal needs, or illness. Requests should be submitted in advance through the HR system unless related to an emergency. Employees may carry over up to 5 unused PTO days per calendar year. Extended absences exceeding 5 consecutive business days require manager approval. Travel & Expense Policy Employees may be reimbursed for reasonable and necessary expenses incurred during approved business travel. This includes transportation, lodging, meals, and incidental expenses within established limits. Receipts must be submitted within 14 days of travel. First-class travel, personalAccording to the employee handbook, here are the vacation/PTO details for an employee in their **first year (0–1 years of service)**: - **10 days per year** (0.833 days per month) - This PTO can be used for vacation, personal needs, or illness - Requests should be submitted in advance through the HR system - Up to 5 unused PTO days can be carried over per calendar year
In [17]:
print(response['messages'][-1].content)
According to the employee handbook, an employee in their first year (0–1 years of service) gets **10 days** of Paid Time Off (PTO) per year. This accrues at a rate of 0.833 days per month. These PTO days can be used for vacation, personal needs, or illness. Also, employees may carry over up to 5 unused PTO days per calendar year.