How to Fit More Web Search Data into a Local LLM SerpApi's new Markdown output lets a local LLM fit more web search data into its context window, because the same results take fewer tokens in Markdown than in JSON, according to the company's benchmark of seven searches. The benchmark compared four outputs — raw JSON, JSON with the JSON Restrictor, Markdown with the restrictor, and raw Markdown — using OpenAI's tiktoken cl100k_base encoding, and found that for most searches the full response now fits with no restrictor at all. The accompanying open-source app, built with TanStack Start 1.0 and running models in LM Studio with a 32K context window, defaults to Markdown with the restrictor. A local model can only use the web search results that fit in its context window https://www.ibm.com/think/topics/context-window . When we built the app for How to Connect Your Local LLM with Web Search Data https://serpapi.com/blog/how-to-connect-your-local-llm-with-web-search-data/ , a single SerpApi response was often bigger than the whole context window available. So we trimmed every response with the JSON Restrictor https://serpapi.com/json-restrictor , which keeps only the fields the model needs and drops the rest on SerpApi’s servers before it reaches the LLM. SerpApi's new Markdown output https://serpapi.com/markdown-output changes that budget. The same data takes fewer tokens in Markdown than in JSON, so the restrictor can keep more of it. For most searches, the full response now fits with no restrictor at all. This blog will show you how to apply the JSON Restrictor to Markdown output, and when the full response is worth the wait. We'll use the same open-source app https://github.com/serpapi/local-llm-web-search that gives a local model running in LM Studio https://lmstudio.ai internet access. The app is built with TanStack Start https://tanstack.com/start , and we upgraded it to Start 1.0 along the way. What’s New Since the First Blog SerpApi's Markdown output returns curated results as a Markdown document instead of JSON. You add output=md to a request, and the results come back as headings, lists and tables without the JSON keys, quotes and braces. It works across SerpApi's 100+ APIs https://serpapi.com/search-engine-apis , and a Markdown search costs the same as a JSON search. The launch blog Introducing SerpApi’s New Markdown Output https://serpapi.com/blog/introducing-serpapi-markdown-output/ covers the format and its token savings across our engines. The app now lets you choose what the model reads after each search. The benchmark compares four outputs, and a model only ever reads three of them. | Output | What the model reads | Parameters | |---|---|---| | JSON Raw | The full JSON response. The benchmark measures it, but no model reads it | No restrictor | | JSON Restrictor | JSON trimmed to the fields the model needs, as in the first blog | json restrictor | | Markdown Restrictor | Markdown with more results and more fields, at about the same size. This is the app's default | json restrictor and output=md | | Markdown Raw | The full Markdown document | output=md | The setup changed too. The first blog ran Qwen3.5-9B on a MacBook Pro M4 Max with 36 GB of memory. This time I ran four of LM Studio's staff picks on a MacBook Pro M5 Pro with 48 GB, using LM Link https://lmstudio.ai/link to connect both MacBooks. They are: How We Tested Every model ran with a 32K context window, the same size as in the first blog. LM Studio loads a model with an 8K window by default, which is too small once a chat carries search results. A 32K window is enough for a long conversation, and it fits a 27B model in memory on a 36 GB Mac. What the Benchmark Measures The app's Benchmark page measures two things, and this blog uses both. Payload size: The same seven searches run once for each of the four outputs, with no model involved. There's one search per tool, covering Search https://serpapi.com/search-api , Finance https://serpapi.com/google-finance-api , News https://serpapi.com/google-news-api , Maps https://serpapi.com/google-maps-api , Flights https://serpapi.com/google-flights-api , Hotels https://serpapi.com/google-hotels-api and Shopping https://serpapi.com/google-shopping-api . This shows what each output costs before a model reads anything. These sizes come from OpenAI's tiktoken https://github.com/openai/tiktoken library with its cl100k base encoding, which splits text into tokens. Each local model splits text its own way, so treat these sizes as estimates for comparing formats. End to end: Thirteen questions run through the whole app on each model, once for each of the three outputs a model can read. Seven need live data from SerpApi, one search per tool. Two need two searches at once, such as comparing AAPL with TSLA. The other four need no search, such as " What is 15% of 240? ", so they show how the model behaves on its own. We used it to compare how each model handles each output, how long it takes, and what it answers. How Much Does Markdown Save? To see what the format alone saves, we kept the restrictor strings from the first blog and sent the same seven searches as JSON and as Markdown. The seven results took 4,668 tokens in JSON and 3,412 in Markdown, 27% fewer. Here's how each tool changed: | Tool | JSON | Markdown | Change | |---|---|---|---| | Flights | 823 | 439 | −47% | | Finance | 521 | 324 | −38% | | News | 678 | 422 | −38% | | Search | 785 | 586 | −25% | | Hotels | 567 | 433 | −24% | | Maps | 497 | 449 | −10% | | Shopping | 797 | 759 | −5% | | Total | 4,668 | 3,412 | −27% | The saving depends on how deeply the data is nested. A flight option holds legs, and each leg holds airports and times, so JSON repeats keys, quotes and braces at every level. Markdown turns lists of results into tables and writes each column name once. Shopping results are flat, with a title, a price and a store per product, so there is little to remove. So instead of keeping that saving, we spend it. In Markdown, the same token budget can carry more fields and more results, so the Markdown output gets a looser restrictor. Apply the JSON Restrictor to Markdown Output There's no separate restrictor for Markdown. You send the same json restrictor parameter together with output=md , and SerpApi filters the sections first, then renders what's left as Markdown. In the app, each tool has two restrictor strings. JSON sends the original one, and Markdown sends a looser one with more results and more fields. The Markdown request is the same search with output=md added: // Pick the restrictor for the output mode. Markdown Raw sends none. function restrictorFor name: RestrictorTool, output: ToolOutput : string | null { if output === "markdown-full" return null return output === "markdown" ? MARKDOWN RESTRICTORS name : RESTRICTORS name } // Same parameters as the JSON request, plus output=md. async function serpApiMarkdown params: Record