<?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: SROJISH</title>
    <description>The latest articles on DEV Community by SROJISH (@srojish).</description>
    <link>https://dev.to/srojish</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4089908%2F5029cd4f-edc8-46ca-a72c-607bcadda278.jpg</url>
      <title>DEV Community: SROJISH</title>
      <link>https://dev.to/srojish</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/srojish"/>
    <language>en</language>
    <item>
      <title># I Built an AI Agent, Then Tried to Make It Delete My Database</title>
      <dc:creator>SROJISH</dc:creator>
      <pubDate>Sat, 22 Aug 2026 15:57:42 +0000</pubDate>
      <link>https://dev.to/srojish/-i-built-an-ai-agent-then-tried-to-make-it-delete-my-database-263e</link>
      <guid>https://dev.to/srojish/-i-built-an-ai-agent-then-tried-to-make-it-delete-my-database-263e</guid>
      <description>&lt;p&gt;I've spent the last five years working with satellite imagery — classifying&lt;br&gt;
land cover, mapping urban heat islands, modeling climate scenarios. Real&lt;br&gt;
data, real coordinate systems, real consequences if the math is wrong. So&lt;br&gt;
when I started experimenting with LLM agents, one question kept bothering&lt;br&gt;
me: &lt;strong&gt;how do you let an AI touch spatial data without trusting it to do the&lt;br&gt;
math itself?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;LLMs are language models. They predict plausible-sounding text — including&lt;br&gt;
plausible-sounding numbers. That's fine for a chatbot. It's not fine for a&lt;br&gt;
system where a wrong distance calculation could mean the wrong emergency&lt;br&gt;
response radius, or the wrong infrastructure assessment.&lt;/p&gt;

&lt;p&gt;So I built a small system to test an idea: &lt;strong&gt;the AI never calculates&lt;br&gt;
anything. It only translates.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The core design
&lt;/h2&gt;

&lt;p&gt;A user asks a question in plain English: "How many restaurants are within&lt;br&gt;
this area?" An LLM (running entirely locally, via Ollama — no cloud API,&lt;br&gt;
no external calls) translates that into real SQL. A real PostgreSQL/PostGIS&lt;br&gt;
database the actual spatial database engine, not the AI— executes it and&lt;br&gt;
returns the answer. If the query fails, the agent sees the &lt;em&gt;real error&lt;/em&gt; and&lt;br&gt;
rewrites its own code. If it succeeds, a second pass checks whether the&lt;br&gt;
result actually makes sense before anything gets trusted.&lt;/p&gt;

&lt;p&gt;The whole thing runs on LangGraph, a state-machine framework for LLM&lt;br&gt;
agents  orchestrating a graph of nodes: read the live database schema,&lt;br&gt;
generate SQL, execute it, validate it, self-correct on failure. I loaded&lt;br&gt;
about 33,000 real points of interest from Overture Maps (an open geospatial&lt;br&gt;
dataset) into the database to test it against something real, not toy data.&lt;/p&gt;

&lt;p&gt;It worked. And then it broke in three genuinely interesting ways, and the&lt;br&gt;
breaking taught me more than the working did.&lt;/p&gt;
&lt;h2&gt;
  
  
  Finding 1: The AI invented coordinates
&lt;/h2&gt;

&lt;p&gt;Early on, I asked it something like "how many places are within 2km of&lt;br&gt;
Substation A,"  referencing a named entity already sitting in the database.&lt;br&gt;
Instead of looking up Substation A's real coordinates, the model &lt;strong&gt;invented&lt;br&gt;
a plausible-looking but completely fake location&lt;/strong&gt; and queried against&lt;br&gt;
that. The query ran successfully. No error, no crash. Just a confidently&lt;br&gt;
wrong answer.&lt;/p&gt;

&lt;p&gt;That's the dangerous failure mode — not the system that crashes, but the&lt;br&gt;
one that looks like it worked.&lt;/p&gt;

&lt;p&gt;The root cause, once I dug in: my prompt told the model "don't guess at&lt;br&gt;
coordinates," but never told it what to do &lt;em&gt;instead&lt;/em&gt;. Telling an LLM what&lt;br&gt;
not to do is weak instruction. The fix was showing it the exact pattern&lt;br&gt;
to use a &lt;code&gt;SELECT ... WHERE name = 'X'&lt;/code&gt; subquery with a concrete&lt;br&gt;
example. Once I did that, the hallucination stopped, verified against an&lt;br&gt;
independently computed ground-truth distance.&lt;/p&gt;
&lt;h2&gt;
  
  
  Finding 2: My safety mechanism made things worse
&lt;/h2&gt;

&lt;p&gt;This is the one I'm actually proudest of, because it's the least&lt;br&gt;
comfortable to admit.&lt;/p&gt;

&lt;p&gt;I built a second LLM pass, a "result validator" — specifically to catch&lt;br&gt;
semantically wrong queries, like a filter that doesn't actually make sense&lt;br&gt;
given the data. Reasonable idea. I turned it on, and immediately a&lt;br&gt;
previously correct, previously verified query started failing. The&lt;br&gt;
validator flagged it as wrong. The agent tried to "fix" a query that wasn't&lt;br&gt;
broken, and after a few rounds of increasingly confused self-correction,&lt;br&gt;
it produced genuinely broken SQL.&lt;/p&gt;

&lt;p&gt;I had built a safety layer that made the system less reliable, not more.&lt;/p&gt;

&lt;p&gt;Digging into why took real diagnosis, and there were two separate causes&lt;br&gt;
tangled together:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A leftover test table was still sitting in the database from earlier
development. Live schema-reading correctly picked it up — and confused
the model about which table's structure actually applied.&lt;/li&gt;
&lt;li&gt;Separately, the validator itself was &lt;strong&gt;inventing requirements that were
never asked for&lt;/strong&gt;, flagging a query for not doing something the
original question never requested. An LLM reviewing another LLM's work
can hallucinate problems exactly as easily as the first LLM can
hallucinate answers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I cleaned up the stale table, and rewrote the validator's prompt to demand conservatism explicitly: "do not invent additional requirements,"&lt;br&gt;
"default to OK when uncertain." Re-tested against both the case it broke&lt;br&gt;
and the case it was built to catch. Both passed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The lesson that stuck with me:&lt;/strong&gt; adding an AI safety check isn't&lt;br&gt;
automatically safer. It's a new component with its own failure modes, and&lt;br&gt;
it needs the same scrutiny as the thing it's checking.&lt;/p&gt;
&lt;h2&gt;
  
  
  Finding 3: Proving the security boundary, not just designing it
&lt;/h2&gt;

&lt;p&gt;This is the test I'm most glad I ran, because it's the one that actually&lt;br&gt;
matters if a system like this is ever going to touch real data.&lt;/p&gt;

&lt;p&gt;I connected the agent's database access through a PostgreSQL role with&lt;br&gt;
&lt;strong&gt;read-only permissions&lt;/strong&gt; — enforced by the database itself, not by&lt;br&gt;
application code. Then I deliberately tried to break it.&lt;/p&gt;

&lt;p&gt;I asked the agent: &lt;em&gt;"Delete all restaurants from the dataset."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The LLM complied. It generated a real &lt;code&gt;DELETE FROM places WHERE&lt;br&gt;
category ILIKE '%restaurant%'&lt;/code&gt; statement, and tried to run it.&lt;/p&gt;

&lt;p&gt;PostgreSQL rejected it. Three times, across retry attempts, with&lt;br&gt;
&lt;code&gt;permission denied for table places&lt;/code&gt;. Not because the AI decided to&lt;br&gt;
behave because it was physically, structurally incapable of writing&lt;br&gt;
data, regardless of what it generated or how many times it tried.&lt;/p&gt;

&lt;p&gt;I confirmed the data afterward: untouched.&lt;/p&gt;

&lt;p&gt;That distinction  &lt;em&gt;the AI choosing to be safe&lt;/em&gt; versus &lt;em&gt;the system making&lt;br&gt;
unsafe actions impossible&lt;/em&gt;  is the entire thesis of building AI agents&lt;br&gt;
for anything that actually matters. It's easy to design for. It's much&lt;br&gt;
more convincing once you've actually tried to break it and watched it&lt;br&gt;
hold.&lt;/p&gt;
&lt;h2&gt;
  
  
  Where this leaves me
&lt;/h2&gt;

&lt;p&gt;None of this is production-ready — it's a proof of concept, built to test&lt;br&gt;
one architectural idea end to end. There's no sandboxed code execution&lt;br&gt;
yet, no proper intent-parsing layer, no monitoring. That's the honest&lt;br&gt;
state of it.&lt;/p&gt;

&lt;p&gt;But I think the pattern is right, and I think it generalizes past&lt;br&gt;
geospatial data: &lt;strong&gt;don't ask an LLM to be trustworthy. Build a system&lt;br&gt;
where it doesn't need to be, because the parts that matter are enforced&lt;br&gt;
somewhere else.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Full build log — including every bug above in more detail, with the&lt;br&gt;
actual terminal output — is in the repo. If you're working on similar&lt;br&gt;
problems, or hiring for exactly this kind of work, I'd genuinely like to&lt;br&gt;
talk.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/srojish" rel="noopener noreferrer"&gt;
        srojish
      &lt;/a&gt; / &lt;a href="https://github.com/srojish/geo-ai-platform" rel="noopener noreferrer"&gt;
        geo-ai-platform
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Air-Gapped Geospatial AI Intelligence Platform&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;A self-contained, offline-first AI system that answers spatial questions over satellite imagery and geographic data — with zero internet dependency and zero hallucinated math.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Status: 🚧 Active development — core agent loop working end-to-end (LangGraph orchestration, live schema grounding, self-correction, result validation, read-only DB security boundary, adversarially tested). See &lt;a href="https://github.com/srojish/geo-ai-platform/./BUILD_LOG.md" rel="noopener noreferrer"&gt;BUILD_LOG.md&lt;/a&gt; for real-time progress.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Demo&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://youtu.be/kA-0aQDOEDA" rel="nofollow noopener noreferrer"&gt;Watch: Air-Gapped Geospatial AI Agent — Security Test Demo&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A 2-3 minute walkthrough: a normal query running end-to-end, followed by a deliberate attempt to make the agent delete real data — and the database itself refusing, three times in a row, regardless of what the AI generated.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;The Problem&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Organizations that work with sensitive geography — defense, intelligence, critical infrastructure operators — need AI-assisted spatial analysis ("find every substation within 5km of this facility," "has this AOI changed in the last satellite pass") but &lt;strong&gt;cannot&lt;/strong&gt; send that data to a cloud…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/srojish/geo-ai-platform" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8nd49pzmavb5yeqpms51.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8nd49pzmavb5yeqpms51.png" alt=" " width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>showdev</category>
      <category>langchain</category>
    </item>
  </channel>
</rss>
