By Arjav Jain · Co-founder, OpenOfficeAI
How to Give an AI Agent the Ability to Create Documents
LLM agents are great at reasoning, but when they need to hand back a spreadsheet or a report they usually dump a Markdown table into the chat. Here is the pattern that turns that into a real, shareable document — and the runnable code to add it to your agent today.
The fastest way to give an agent document output is a single tool that calls a document API and returns a URL. The agent decides when to use it, supplies the data, and your code runs the request. The result is a link the user can open and edit — not 2,000 tokens of pipe-delimited text the model had to generate character by character.
Why a table-in-chat is the wrong output
Generating a large table token-by-token is slow, expensive, error-prone, and produces something the user still has to copy, clean, and paste into a real spreadsheet. Worse, the model often truncates or mis-aligns columns. A document API removes all of that: the agent sends structured rows, and a hosted file comes back with a shareable link. For the full reasoning, see why AI agents need a document API.
The pattern: one tool, one POST, one link
Every framework below uses the same three-step shape: (1) define a tool with a title androws input, (2) inside it, POST to a document API, (3) return the URL. Here is the bare API call the tool wraps:
POST https://openofficeai.com/api/v1/sheets
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
{ "title": "Q3 Revenue", "sheets": [{ "rows": [
["Month", "Revenue"], ["July", 48200], ["August", 61900]
] }] }
# → { "url": "https://openofficeai.com/s/..." }OpenAI function calling
Declare a function tool; when the model calls it, run the request and feed the URL back.
tools = [{
"type": "function",
"function": {
"name": "create_spreadsheet",
"description": "Create a shareable spreadsheet; returns a URL.",
"parameters": {"type": "object", "properties": {
"title": {"type": "string"},
"rows": {"type": "array", "items": {"type": "array"}}},
"required": ["title", "rows"]}
}
}]
def create_spreadsheet(title, rows):
r = requests.post("https://openofficeai.com/api/v1/sheets",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"title": title, "sheets": [{"rows": rows}]})
return r.json()["url"]Full walkthrough: OpenAI function calling integration.
Claude tool use
Claude proposes a tool_use block; you execute it and return a tool_result with the link.
tools = [{
"name": "create_spreadsheet",
"description": "Create a shareable spreadsheet and return its URL.",
"input_schema": {"type": "object", "properties": {
"title": {"type": "string"},
"rows": {"type": "array", "items": {"type": "array"}}},
"required": ["title", "rows"]}
}]
# On tool_use, POST to /api/v1/sheets and return the url as tool_result.Full walkthrough: Claude tool use / MCP integration.
LangChain & CrewAI
Framework agents wrap the same call in their tool decorator.
from langchain_core.tools import tool
@tool
def create_spreadsheet(title: str, rows: list) -> str:
"""Create a shareable spreadsheet; first row is the header. Returns a URL."""
r = requests.post("https://openofficeai.com/api/v1/sheets",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"title": title, "sheets": [{"rows": rows}]})
return r.json()["url"]Same idea in LangChain, CrewAI, LlamaIndex, PydanticAI, and the Vercel AI SDK — see the full integrations directory for copy-paste code per framework.
Four practices that make agent tool calls reliable
- Keep the signature flat. A
title+rows(array of arrays) shape calls reliably; deeply nested schemas cause malformed calls. - Write the description for the model. State that the first row is the header and the tool returns a URL — the model uses this to format data correctly.
- Keep the API key server-side. The tool executes in your code, never inside the model, so the key stays in an environment variable.
- Return just the URL. One short string is easy for the model to hand back; avoid returning large payloads it then re-summarizes.
Documents, not just spreadsheets
The same pattern produces formatted documents: add a second tool that posts to /api/v1/docs with a content array of headings and paragraphs, and your agent can return reports, memos, and proposals as shareable links — downloadable as PDF or DOCX. See the API docs for the full schema.
FAQ
Why not just have the agent write a CSV?
A CSV string still has to be saved, opened, and shared by the user, and large tables burn tokens and risk truncation. A document API returns a finished, hosted, editable artifact in one call.
Does this work with local models?
Yes — any tool-capable model works, including local ones via Ollama. The document call is the only thing that leaves your machine.
How do I start?
Grab a free API key (500 calls/month), pick your framework in the integrations directory, and paste in the tool.
Give your agent document output
Free tier: 500 API calls/month, no card required.