Building a Library Research Agent: Book Search, Citation Help, and Resource Recommendations
Create an AI-powered library research agent that searches catalogs, formats citations in multiple styles, handles inter-library loan requests, and recommends related academic resources.
The Modern Library Challenge
Academic libraries hold vast collections across physical stacks, digital databases, and inter-library loan networks. Students often struggle to find the right resources, format citations correctly, or even know which databases to search. A library research agent transforms this experience by providing intelligent catalog search, automatic citation generation, and personalized resource recommendations.
Modeling the Library Catalog
A library catalog entry needs to represent books, journals, digital resources, and their availability.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
flowchart LR
INPUT(["User intent"])
PARSE["Parse plus<br/>classify"]
PLAN["Plan and tool<br/>selection"]
AGENT["Agent loop<br/>LLM plus tools"]
GUARD{"Guardrails<br/>and policy"}
EXEC["Execute and<br/>verify result"]
OBS[("Trace and metrics")]
OUT(["Outcome plus<br/>next action"])
INPUT --> PARSE --> PLAN --> AGENT --> GUARD
GUARD -->|Pass| EXEC --> OUT
GUARD -->|Fail| AGENT
AGENT --> OBS
style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style OUT fill:#059669,stroke:#047857,color:#fff
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional
from datetime import date
class ResourceType(Enum):
BOOK = "book"
JOURNAL = "journal"
ARTICLE = "article"
EBOOK = "ebook"
THESIS = "thesis"
CONFERENCE_PAPER = "conference_paper"
class AvailabilityStatus(Enum):
AVAILABLE = "available"
CHECKED_OUT = "checked_out"
ON_HOLD = "on_hold"
DIGITAL = "digital"
ILL_AVAILABLE = "inter_library_loan"
class CitationStyle(Enum):
APA = "apa"
MLA = "mla"
CHICAGO = "chicago"
IEEE = "ieee"
@dataclass
class LibraryResource:
resource_id: str
title: str
authors: list[str]
resource_type: ResourceType
year: int
isbn: Optional[str] = None
doi: Optional[str] = None
publisher: str = ""
journal_name: str = ""
volume: str = ""
issue: str = ""
pages: str = ""
subjects: list[str] = field(default_factory=list)
availability: AvailabilityStatus = AvailabilityStatus.AVAILABLE
location: str = ""
call_number: str = ""
abstract: str = ""
Citation Formatter
One of the most common library requests is help formatting citations. The agent needs a reliable formatter.
def format_citation(
resource: LibraryResource, style: CitationStyle
) -> str:
authors_str = _format_authors(resource.authors, style)
if style == CitationStyle.APA:
if resource.resource_type == ResourceType.BOOK:
return (
f"{authors_str} ({resource.year}). "
f"*{resource.title}*. {resource.publisher}."
)
elif resource.resource_type in (
ResourceType.ARTICLE, ResourceType.JOURNAL
):
return (
f"{authors_str} ({resource.year}). "
f"{resource.title}. *{resource.journal_name}*, "
f"*{resource.volume}*({resource.issue}), "
f"{resource.pages}."
)
elif style == CitationStyle.MLA:
if resource.resource_type == ResourceType.BOOK:
return (
f"{authors_str}. *{resource.title}*. "
f"{resource.publisher}, {resource.year}."
)
elif style == CitationStyle.IEEE:
if resource.resource_type == ResourceType.ARTICLE:
return (
f"{authors_str}, \"{resource.title},\" "
f"*{resource.journal_name}*, vol. {resource.volume}, "
f"no. {resource.issue}, pp. {resource.pages}, "
f"{resource.year}."
)
return f"{authors_str}. {resource.title}. {resource.year}."
def _format_authors(
authors: list[str], style: CitationStyle
) -> str:
if not authors:
return "Unknown"
if style == CitationStyle.APA:
if len(authors) == 1:
parts = authors[0].split()
return f"{parts[-1]}, {parts[0][0]}."
formatted = []
for author in authors[:6]:
parts = author.split()
formatted.append(f"{parts[-1]}, {parts[0][0]}.")
if len(authors) > 6:
return ", ".join(formatted) + ", ... et al."
return ", ".join(formatted[:-1]) + ", & " + formatted[-1]
return " and ".join(authors)
Agent Tools for Library Search and Recommendations
from agents import Agent, function_tool, Runner
import json
CATALOG: dict[str, LibraryResource] = {}
@function_tool
def search_catalog(
query: str,
resource_type: str = "",
subject: str = "",
) -> str:
"""Search the library catalog by keyword, type, and subject."""
results = []
query_lower = query.lower()
for res in CATALOG.values():
title_match = query_lower in res.title.lower()
author_match = any(
query_lower in a.lower() for a in res.authors
)
subject_match = any(
query_lower in s.lower() for s in res.subjects
)
if not (title_match or author_match or subject_match):
continue
if resource_type and res.resource_type.value != resource_type:
continue
if subject and not any(
subject.lower() in s.lower() for s in res.subjects
):
continue
results.append({
"id": res.resource_id,
"title": res.title,
"authors": res.authors,
"year": res.year,
"type": res.resource_type.value,
"availability": res.availability.value,
"location": res.location,
"call_number": res.call_number,
})
return json.dumps(results[:10]) if results else "No results found."
@function_tool
def generate_citation(
resource_id: str, style: str = "apa"
) -> str:
"""Generate a formatted citation for a resource."""
resource = CATALOG.get(resource_id)
if not resource:
return "Resource not found."
try:
citation_style = CitationStyle(style.lower())
except ValueError:
return f"Unsupported style. Use: apa, mla, chicago, ieee"
return format_citation(resource, citation_style)
@function_tool
def find_related_resources(resource_id: str) -> str:
"""Find resources related to a given resource by shared subjects."""
source = CATALOG.get(resource_id)
if not source:
return "Resource not found."
source_subjects = set(s.lower() for s in source.subjects)
related = []
for rid, res in CATALOG.items():
if rid == resource_id:
continue
res_subjects = set(s.lower() for s in res.subjects)
overlap = source_subjects & res_subjects
if overlap:
related.append({
"id": rid,
"title": res.title,
"authors": res.authors,
"shared_subjects": list(overlap),
"relevance_score": len(overlap) / len(source_subjects),
})
related.sort(key=lambda r: r["relevance_score"], reverse=True)
return json.dumps(related[:5])
library_agent = Agent(
name="Library Research Assistant",
instructions="""You are an academic library research assistant.
Help patrons search the catalog, generate properly formatted
citations, find related resources, and request inter-library
loans. When a resource is checked out, suggest alternatives
or offer to place a hold. Always ask which citation style the
patron needs before generating citations.""",
tools=[search_catalog, generate_citation, find_related_resources],
)
FAQ
How does the agent handle resources from external databases like JSTOR or PubMed?
Implement additional tool functions that call external APIs. JSTOR and PubMed provide REST APIs that return structured metadata. The agent can search these alongside the local catalog and clearly indicate which resources are available locally versus externally.
Can the agent detect plagiarism or verify citation accuracy?
The agent can verify that a citation matches the source metadata (correct authors, year, title) by comparing against catalog records. For plagiarism detection, integrate with services like Turnitin via their API. The agent should frame this as a verification service, not an accusation tool.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
How do you handle multi-branch library systems?
Add a branch field to each resource and a preferred_branch to the patron record. The search tool returns availability per branch, and the agent can suggest the nearest location with an available copy or offer to initiate a transfer between branches.
#AIAgents #EdTech #LibraryScience #Python #Research #AgenticAI #LearnAI #AIEngineering
Try CallSphere AI Voice Agents
See how AI voice agents work for your industry. Live demo available -- no signup required.