<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: API Tier</title>
    <description>The latest articles on DEV Community by API Tier (@apitier).</description>
    <link>https://dev.to/apitier</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F966637%2F795eef15-266f-4b7d-8931-95f9514c592f.png</url>
      <title>DEV Community: API Tier</title>
      <link>https://dev.to/apitier</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/apitier"/>
    <language>en</language>
    <item>
      <title>The Data Layer Problem in Agentic AI — Why Your Agent Knows Everything Except What It Needs</title>
      <dc:creator>API Tier</dc:creator>
      <pubDate>Mon, 27 Apr 2026 20:23:52 +0000</pubDate>
      <link>https://dev.to/apitier/the-data-layer-problem-in-agentic-ai-why-your-agent-knows-everything-except-what-it-needs-1dke</link>
      <guid>https://dev.to/apitier/the-data-layer-problem-in-agentic-ai-why-your-agent-knows-everything-except-what-it-needs-1dke</guid>
      <description>&lt;p&gt;Every AI agent demo looks impressive until it hits the real world.&lt;/p&gt;

&lt;p&gt;The reasoning works. The tool calls chain correctly. Then the agent tries to look up a UK postcode, validate a VAT number, or verify a company registration — and it either hallucinates the answer or stops dead.&lt;/p&gt;

&lt;p&gt;The missing piece is almost never the model. It's the &lt;strong&gt;data layer&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is the Data Layer in an Agentic System?
&lt;/h2&gt;

&lt;p&gt;In traditional software, the data layer is your database, ORM, and query logic. In an agentic system, it's broader: it's everything that lets an agent retrieve &lt;strong&gt;ground truth about the external world&lt;/strong&gt; at runtime.&lt;/p&gt;

&lt;p&gt;A well-designed agentic data layer has three tiers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────┐
│         Agent / LLM Core            │  ← reasoning, planning, tool selection
├─────────────────────────────────────┤
│         Tool / Function Layer        │  ← structured API calls, schema validation
├─────────────────────────────────────┤
│         Data Provider Layer          │  ← real-time data: APIs, DBs, indexes
└─────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most tutorials focus on the top two layers. The bottom layer — the actual data providers — is where production agents break.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Agents Hallucinate "Factual" Answers
&lt;/h2&gt;

&lt;p&gt;LLMs are trained on static snapshots of the world. For anything time-sensitive or domain-specific, they guess. And they guess confidently.&lt;/p&gt;

&lt;p&gt;Ask &lt;code&gt;gpt-4o&lt;/code&gt; for the current registered address of a UK company. It will give you one. It may be three years out of date, or entirely fabricated.&lt;/p&gt;

&lt;p&gt;This isn't a failure of reasoning. It's a failure of &lt;strong&gt;data architecture&lt;/strong&gt;. The agent has no reliable path to ground-truth data, so it fills the gap with pattern-matched text.&lt;/p&gt;

&lt;p&gt;The fix isn't a better prompt. It's a real data connection.&lt;/p&gt;




&lt;h2&gt;
  
  
  What a Reliable Agentic Data Layer Looks Like
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Structured, schema-validated API calls
&lt;/h3&gt;

&lt;p&gt;Agents work best when data sources return typed, predictable JSON — not free-text scraped HTML or inconsistent responses. Every data provider your agent calls should have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clear request schema (the agent knows what to send)&lt;/li&gt;
&lt;li&gt;A stable response schema (the agent knows what it gets back)&lt;/li&gt;
&lt;li&gt;Explicit error states (the agent knows when to stop or retry)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Bad: agent parses unstructured text
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;scrape_companies_house&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Acme Ltd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# returns HTML or markdown blob
&lt;/span&gt;
&lt;span class="c1"&gt;# Good: agent calls a structured API
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;company_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Acme Ltd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# returns: { "company_number": "12345678", "status": "active", "registered_address": {...} }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Real-time data, not cached training knowledge
&lt;/h3&gt;

&lt;p&gt;For anything that changes — addresses, VAT status, company registrations, exchange rates — the agent must call out at runtime. Cached or embedded knowledge is a liability for factual queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Separation of data concerns
&lt;/h3&gt;

&lt;p&gt;Don't build a single monolithic "search everything" tool. Give your agent narrow, composable tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;lookup_uk_postcode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;# → addresses for a given postcode
&lt;/span&gt;    &lt;span class="n"&gt;validate_vat_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# → VAT registration status
&lt;/span&gt;    &lt;span class="n"&gt;verify_company&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# → Companies House data
&lt;/span&gt;    &lt;span class="n"&gt;check_bank_sortcode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# → sort code / bank branch validity
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Narrow tools are easier for the LLM to select correctly, easier to test, and easier to replace.&lt;/p&gt;




&lt;h2&gt;
  
  
  MCP: A Standard Data Interface for Agents
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; is an open standard (introduced by Anthropic) that defines how AI agents connect to external data and tools. Think of it as a USB-C port for agent data sources — one standard interface, many compatible providers.&lt;/p&gt;

&lt;p&gt;An MCP server exposes tools that any MCP-compatible agent can call — Claude Desktop, Cursor, Windsurf, or a custom agent built with the Anthropic SDK.&lt;/p&gt;

&lt;p&gt;A minimal MCP tool for address lookup looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lookup_postcode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Look up UK addresses for a given postcode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;postcode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UK postcode, e.g. SW1A 1AA&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;postcode&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;addressApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postcode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent decides when to call this tool. The MCP server handles the actual data retrieval. The data provider (an API) returns ground truth.&lt;/p&gt;

&lt;p&gt;This three-way separation is clean and testable at every layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Practical Example: KYC Agent Data Layer
&lt;/h2&gt;

&lt;p&gt;Consider a KYC (Know Your Customer) agent for a UK fintech. It needs to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verify a company is registered and active&lt;/li&gt;
&lt;li&gt;Look up the registered address and cross-check it&lt;/li&gt;
&lt;li&gt;Validate the VAT number if provided&lt;/li&gt;
&lt;li&gt;Flag inconsistencies for human review&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Without a proper data layer, the agent reasons from training data — which is wrong for dissolved companies, relocated addresses, and newly registered entities.&lt;/p&gt;

&lt;p&gt;With a proper data layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User: "Verify Acme Trading Ltd, VAT GB123456789"

Agent calls:
  → verify_company("Acme Trading Ltd")        # Companies House: active ✓
  → lookup_address("EC2A 4NE")               # Royal Mail PAF: registered address ✓
  → validate_vat("GB123456789")              # HMRC: VAT registered, matches name ✓

Agent returns:
  "Company verified. Registered and active. Address confirmed. VAT number valid and matches registered entity."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every answer is sourced. None of it is hallucinated.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Mistakes When Building the Data Layer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Giving the agent a web search tool and calling it done&lt;/strong&gt;&lt;br&gt;
Web search is useful for open-ended research. It's unreliable for structured factual queries. A search result saying a company is active is not the same as a live Companies House API response.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Returning too much data per tool call&lt;/strong&gt;&lt;br&gt;
If your address lookup returns a 4KB JSON blob with 40 fields, the agent will include irrelevant fields in its reasoning. Return the minimum needed. Let the agent ask follow-up questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No error handling contract&lt;/strong&gt;&lt;br&gt;
If your API returns a 404 with an HTML error page, the agent will try to parse it as data. Define what "not found" looks like in your schema and return it consistently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mixing real-time and cached data without labelling it&lt;/strong&gt;&lt;br&gt;
If some tools return live data and others return cached snapshots, label the difference. An agent treating a 6-month-old cache as current fact is worse than no data at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to Start
&lt;/h2&gt;

&lt;p&gt;If you're building a production agentic system that needs to interact with real-world structured data:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;List every factual query your agent needs to answer&lt;/strong&gt; — addresses, company data, financial identifiers, identity checks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Map each to a reliable API source&lt;/strong&gt; — not a search engine, not training knowledge&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wrap each in a narrow, typed tool&lt;/strong&gt; — one concern per tool&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expose via MCP if you want agent portability&lt;/strong&gt; — Claude, Cursor, and others will be able to use it without additional integration work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test the failure cases&lt;/strong&gt; — what happens when the API returns a 429, a 404, or an empty result set?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The reasoning layer of your agent will improve automatically as the models improve. The data layer only improves if you build it deliberately.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;APITier&lt;/strong&gt; provides a set of UK-focused data APIs (address lookup, VAT validation, company verification, KYC checks) designed to work as agent tools via an MCP server. If you're building agents that work with UK data, you can find the MCP server setup in the &lt;a href="https://docs.apitier.com/docs/mcp-server/introduction" rel="noopener noreferrer"&gt;APITier developer docs&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What data layer challenges have you hit building production agents? Drop a comment below.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>api</category>
      <category>mcp</category>
    </item>
    <item>
      <title>How to Convert Web to PDF Using PYTHON?</title>
      <dc:creator>API Tier</dc:creator>
      <pubDate>Sun, 06 Nov 2022 10:10:30 +0000</pubDate>
      <link>https://dev.to/apitier/how-to-convert-web-to-pdf-using-python-17n9</link>
      <guid>https://dev.to/apitier/how-to-convert-web-to-pdf-using-python-17n9</guid>
      <description>&lt;h3&gt;
  
  
  WEB TO PDF Conversion
&lt;/h3&gt;

&lt;p&gt;APITier extract web content as PDF from web url or html content. The APITier is converting web url or html content to PDF file. It is very Simple, easy to integrate, self-explanatory API will get you up and running in under 10 minutes. Web to PDF Conversion API is easy to use and fast API. &lt;/p&gt;

&lt;p&gt;You can easily call this API using python code. We’ve provided below in python code. Below are two steps for how to convert web to pdf using python.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1
&lt;/h3&gt;

&lt;p&gt;Users can need to create account and register without providing Card Details. Users can register Free with a user name (email) and password. &lt;strong&gt;&lt;a href="https://www.apitier.com/signup"&gt;Get free access API KEY&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The registered user gets the Unique API KEY, to access the API. API KEY can be used to access endpoints of the WEB Conversion API. &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2
&lt;/h3&gt;

&lt;p&gt;Create your PYTHON Project and install their all dependencies. After that add this code.&lt;br&gt;&lt;br&gt;
In this code need to add &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Your Web URL or HTML content. &lt;strong&gt;For Example -&lt;/strong&gt; &lt;a href="https://www.apitier.com"&gt;https://www.apitier.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; Your APITier API KEY.  &lt;strong&gt;For Example -&lt;/strong&gt; hv90CBlVBN9R6Tbfx4wsg3CxRTXyk9CA6bvx2f11
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import requests
import json

url = "https://web.apitier.com/convert/url/to/pdf?x-api-key={x-api-key}"

payload = json.dumps({
  "url": "https://www.apitier.com"
})
headers = {
  'Content-Type': 'application/json'
}

response = requests.request("POST", url, headers=headers, data=payload)

print(response.text)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>api</category>
      <category>python</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
