Agent tools
Give your LLM agent tools over your documents: it lists your collections and documents, finds the ones that answer, and searches or reads their pages, then cites them. For an agent you write; for an MCP client, see MCP.
Set up an agent
Make the tools with client.tools() and give them to your agent. They see all your documents: name a collection or document in the question, or keep the agent to some of them (see Choose the documents).
# pip install "pageindex-search[agents]"
from agents import Agent, Runner
from pageindex_search import PageSearch
tools = PageSearch().tools() # all your documents; collection= or filter= keeps the agent to some
agent = Agent(
name="Filings",
model="gpt-6.1-terra",
instructions="Answer from the documents and cite the file and page numbers.",
tools=tools.openai_agents(),
)
result = Runner.run_sync(agent, "What was NVIDIA's revenue in fiscal 2025?", max_turns=30)
print(result.final_output)What the agent does, in a collection of 40 annual reports:
list_documents {"filter": {"$and": [{"ticker": "NVDA"}, {"year": 2025}]}}
→ NVDA_2025_10K.pdf, 130 pages
search_pages {"questions": ["…"], "document_id": "doc_458c6d87306949ac8184cbdd", "top_k": "auto"}
→ pages 38, 52, 78, …, each with its text
NVIDIA's fiscal 2025 revenue was $130.497 billion. (NVDA_2025_10K.pdf, pp. 38, 52)Show where the answer is
Add CITATIONS to the agent's instructions, and it cites as it answers: a tag after each sentence, with the page. Add CITATIONS_WITH_BOXES instead for the part of the page too: the agent then looks at each page it cites, for a few seconds more.
Revenue was $215.9 billion. <cite doc="NVDA_2026_10K.pdf" page="51"/>
Data Center made most of it. <cite doc="NVDA_2026_10K.pdf" page="77" box="0.08,0.31,0.92,0.52"/>client.citations(answer) finds the tags, each with its document's id. Open the page at the answer, outline its box on it, or show only that part with page_image. Each citation also says where its tag is in the answer, to put a link in its place.
from pageindex_search import CITATIONS_WITH_BOXES, PageSearch
client = PageSearch()
instructions = "Answer only from the documents. " + CITATIONS_WITH_BOXES # give these to your agent
# ... run the agent with client.tools(), as above; answer is what it wrote ...
for c in client.citations(answer):
print(c.document, c.page, c.box) # box: (x0, y0, x1, y1), fractions of the page, or None
png = client.documents.page_image(c.document_id, c.page, box=c.box) # the page, or that part of itThe examples and the console's Agent work so: an answer's citations open its pages, with the part outlined.
Tips
- Scope the tools only to limit them. Made for all your documents, the tools let the agent find the collection or documents a question names. Give them a collection, or a filter, to keep the agent to those documents, whatever it asks for.
- Leave
top_kon auto. The tools ask for the documents and pages likely to help; a number brings back many pages of text, and many more tokens. When those pages do not answer, the agent reads the next most relevant, which come with them, for free, instead of searching again. - Ask several questions at once. Both searches take up to 10 questions; each after the first costs less than a search of its own, so the tools ask the agent to put together the questions it has of the same documents.
- Let it call tools in parallel. For a question across several companies, an agent that searches each at once answers in a few turns.
- Make the tools again when documents change. The metadata in their descriptions is read when they are made.
- Give documents metadata. With metadata, the agent finds the documents a question names by listing them, for free, and searches documents only when it cannot.
- Listing and reading cost nothing. Searches are priced as in Pricing; listing documents, the text and pictures of pages, and zooming in on them, are free.
Tools
client.tools() gives seven tools:
| Tool | What it does |
|---|---|
list_collections | Lists your collections, each with its id, name and how many documents it holds. Free. The agent uses it when the question names a collection, then passes its id to list_documents or search_documents. |
list_documents | Lists the documents whose metadata meets a filter, a page at a time. Free. Its description lists your metadata's keys, types and values, so the agent can write the filter. The agent uses it when the question says which documents it is about. |
search_documents | Finds which documents likely answer a question, if any, with the next most relevant. The agent uses it when a filter cannot pick the documents out, and narrows it with a filter where it can. |
search_pages | Finds the pages of one document that help answer a question, each with its relevance, its text, and how it is best read, and the next most relevant pages, to read if those do not answer. The agent calls it for each document it picked, at the same time. |
read_pages | Reads pages: their text, with a picture of any page whose read is "image", such as a scan or a chart. Up to 20 pages, 5 of them pictures, at a time. |
view_pages | Shows pages as pictures, with their text, where how a page looks matters, such as a table's layout. Up to 5 at a time. |
zoom_page | Shows part of a page, sharper, where small print or a dense table's figures are hard to read in its picture. The agent looks at the whole page first, then zooms on the part it needs. |
tools.definitions are the tools for Claude, tools.openai for OpenAI, and, in Python, tools.openai_agents() for the OpenAI Agents SDK, and tools.mcp() an MCP server. tools.run(name, input) calls one: its .text is JSON for the model and its .images the pictures of pages, and .anthropic() makes both into Claude's tool result. An error, such as a filter written wrong, comes back as {"error": …} for the agent to correct.
The metadata lines the agent sees in list_documents, for a collection of 40 annual reports:
Metadata keys of the 40 documents:
- ticker: string, on 40 documents; values: "AAPL" (5), "BA" (5), "BRK" (5), "JPM" (5), "NVDA" (5), …
- year: number, on 40 documents; 2021 to 2026The tools call the API, documented in the API reference. To search yourself, see Search pages. Try the tools in the console's Agent playground, which shows each step and what it cost.