<?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: PRASAD TILLOO</title>
    <description>The latest articles on DEV Community by PRASAD TILLOO (@prasadt1).</description>
    <link>https://dev.to/prasadt1</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%2F1429469%2Fea03ca68-cc0c-4768-b6f0-d9f14a5b9e94.jpeg</url>
      <title>DEV Community: PRASAD TILLOO</title>
      <link>https://dev.to/prasadt1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/prasadt1"/>
    <language>en</language>
    <item>
      <title>I built a closed-loop WhatsApp advisor for 100M+ Indian farmers — fully serverless on AWS</title>
      <dc:creator>PRASAD TILLOO</dc:creator>
      <pubDate>Sun, 19 Apr 2026 12:49:39 +0000</pubDate>
      <link>https://dev.to/prasadt1/i-built-a-closed-loop-whatsapp-advisor-for-100m-indian-farmers-fully-serverless-on-aws-20n9</link>
      <guid>https://dev.to/prasadt1/i-built-a-closed-loop-whatsapp-advisor-for-100m-indian-farmers-fully-serverless-on-aws-20n9</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Indian smallholder farmers don't lose crops because advice doesn't exist. They lose them because advice arrives after the spray window closes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;AgriNexus AI — a WhatsApp advisor that follows up until the farmer confirms "हो गया" (done).&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Hr9EcblzkwI"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;

&lt;p&gt;Three decisions worth sharing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. EventBridge Scheduler &amp;gt; Step Functions Wait States&lt;/strong&gt;&lt;br&gt;
Keeping a state machine open for 48h is expensive at scale. &lt;br&gt;
Step Functions completes in seconds; EventBridge Scheduler &lt;br&gt;
creates one-shot targets at T+24h / T+48h. DynamoDB Streams &lt;br&gt;
→ ResponseDetector Lambda cancels schedules on "done." &lt;br&gt;
Linear cost scaling instead of exponential state transitions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. S3 Vectors &amp;gt; OpenSearch Serverless&lt;/strong&gt;&lt;br&gt;
OpenSearch's always-on OCU costs dominated early bills &lt;br&gt;
regardless of query volume. S3 Vectors eliminated that.&lt;br&gt;
Modeled cost: ~$0.54/farmer/year at 10K scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Bedrock RAG with visible citations&lt;/strong&gt;&lt;br&gt;
Retrieve-and-Generate API + Claude. Knowledge base: ICAR, &lt;br&gt;
FAO, NFSM PDFs. Every response has a source link visible to the farmer. Trust needs traceability.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;p&gt;API Gateway + WAF → Lambda → SQS FIFO → Bedrock (Claude + &lt;br&gt;
S3 Vectors KB) → Transcribe → Polly → EventBridge Scheduler &lt;br&gt;
→ DynamoDB Streams&lt;/p&gt;

&lt;p&gt;Full article with architecture diagrams and ADRs: [article link]&lt;br&gt;
Repo: &lt;a href="https://github.com/prasadt1/agrinexus-ai" rel="noopener noreferrer"&gt;https://github.com/prasadt1/agrinexus-ai&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One ask
&lt;/h2&gt;

&lt;p&gt;This is an AWS Builder &lt;strong&gt;AIdeas 2025 finalist&lt;/strong&gt;. Community voting runs &lt;strong&gt;April 18–23 PT&lt;/strong&gt;. If the architecture or the mission resonates:&lt;br&gt;
click the 👍 like button at the top of this AWS Builder article here 👉 &lt;a href="https://builder.aws.com/content/3C8hBRTcsRuQrHzE3Pq243yhXTF/aideas-finalist-agrinexus-ai" rel="noopener noreferrer"&gt;https://builder.aws.com/content/3C8hBRTcsRuQrHzE3Pq243yhXTF/aideas-finalist-agrinexus-ai&lt;/a&gt;&lt;br&gt;
&lt;em&gt;(One-time ~30-sec sign-up with Amazon Builder.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Happy to answer technical questions in the comments.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>aws</category>
      <category>serverless</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How I Built a Behavioral Nudge Engine for Farmers on Serverless AWS</title>
      <dc:creator>PRASAD TILLOO</dc:creator>
      <pubDate>Sat, 14 Mar 2026 09:45:46 +0000</pubDate>
      <link>https://dev.to/prasadt1/how-i-built-a-behavioral-nudge-engine-for-farmers-on-serverless-aws-3jh9</link>
      <guid>https://dev.to/prasadt1/how-i-built-a-behavioral-nudge-engine-for-farmers-on-serverless-aws-3jh9</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;a href="https://builder.aws.com/content/39qTnLaOki9b8RyT8MXOrg7Fns6/aideas-agrinexus-ai-how-i-built-an-ai-agronomist-for-indias-100m-smallholder-farmers-voice-vision-and-behavioral-nudges-on-whatsapp" rel="noopener noreferrer"&gt;Read the full article on AWS Builder Center&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every agricultural AI chatbot I found had the same blind spot: they stop at information delivery.&lt;/p&gt;

&lt;p&gt;They tell the farmer what to do. None of them know whether the farmer actually did it.&lt;/p&gt;

&lt;p&gt;That gap — between knowing and doing — is where crop loss happens. A cotton farmer in Maharashtra (India) who misses a 3-day insecticide / pesticide spray window can lose 30-50% of his crop. Not because the advice doesn't exist in &lt;a href="https://www.fao.org/home/en" rel="noopener noreferrer"&gt;FAO&lt;/a&gt; and &lt;a href="https://icar.org.in/" rel="noopener noreferrer"&gt;ICAR&lt;/a&gt; research manuals — but because it never reaches him in time, in his language, in a format he can act on.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;AgriNexus AI&lt;/strong&gt; — a WhatsApp-based agricultural advisor that goes beyond Q&amp;amp;A. It proactively sends weather-timed nudges and follows up until the farmer confirms: &lt;em&gt;"ho gaya"&lt;/em&gt; (done).&lt;/p&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.amazonaws.com%2Fuploads%2Farticles%2Fsv91plvbo3w2ud7d406k.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fsv91plvbo3w2ud7d406k.jpg" alt="The Problem vs The Solution — AgriNexus bridges the last mile" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built for the &lt;a href="https://builder.aws.com/content/39qTnLaOki9b8RyT8MXOrg7Fns6/aideas-agrinexus-ai-how-i-built-an-ai-agronomist-for-indias-100m-smallholder-farmers-voice-vision-and-behavioral-nudges-on-whatsapp" rel="noopener noreferrer"&gt;AWS 10,000 AIdeas competition&lt;/a&gt;. Full article with demo videos on AWS Builder Center.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Architecture: Four Flows, One WhatsApp Number
&lt;/h2&gt;

&lt;p&gt;AgriNexus supports four interaction modes — all through the WhatsApp number the farmer already has:&lt;/p&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.amazonaws.com%2Fuploads%2Farticles%2Fupbiax9nvd73tj0mtyrw.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.amazonaws.com%2Fuploads%2Farticles%2Fupbiax9nvd73tj0mtyrw.png" alt="AgriNexus AI — Four capabilities on one platform" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Text Chat&lt;/strong&gt; — Farmer types in Hindi, Marathi, Telugu, or English. Amazon Bedrock RAG searches FAO and ICAR manuals, Claude 3 Sonnet generates a response in the farmer's language with source citations. 3-5 seconds end-to-end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Voice Pipeline&lt;/strong&gt; — Farmer sends a voice note describing crop symptoms. The pipeline: OGG audio from WhatsApp → S3 → Amazon Transcribe (dialect-matched: hi-IN, mr-IN, te-IN, en-IN) → transcript re-queued to the same RAG pipeline → Claude 3 Sonnet response → Amazon Polly neural TTS → audio + text reply back. The farmer hears the answer while walking the field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Crop Vision&lt;/strong&gt; — Farmer photographs a diseased leaf. Claude 3 Sonnet Vision identifies the pest/disease, returns a structured diagnosis: pest name, confidence score, recommended pesticide, dosage, application timing, and safety warnings. All in the farmer's language.&lt;/p&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.amazonaws.com%2Fuploads%2Farticles%2F0n9zusuyfnj9ftsyelp2.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F0n9zusuyfnj9ftsyelp2.jpg" alt="Crop photo in → pest ID, dosage, safety warning out" width="800" height="993"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. The Nudge Loop&lt;/strong&gt; — This is what makes AgriNexus different from a chatbot. More on this below.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Behavioral Nudge Engine: From Knowledge to Action
&lt;/h2&gt;

&lt;p&gt;This is the core innovation. Every other agricultural AI tool I studied — Farmer.Chat, iSDA, AgriChat.AI — stops at information delivery. AgriNexus closes the loop.&lt;/p&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.amazonaws.com%2Fuploads%2Farticles%2F074dyg9ix9ahmzm641vi.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F074dyg9ix9ahmzm641vi.jpg" alt="Closing the behavior gap — from knowledge to action" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The nudge engine doesn't wait for the farmer to ask. When weather conditions are right for spraying, it initiates contact:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;EventBridge Scheduler&lt;/strong&gt; triggers WeatherPoller Lambda daily at 7 AM&lt;/li&gt;
&lt;li&gt;WeatherPoller checks conditions: wind &amp;lt; 15 km/h, no rain forecast&lt;/li&gt;
&lt;li&gt;If conditions pass → &lt;strong&gt;Step Functions&lt;/strong&gt; nudge workflow starts&lt;/li&gt;
&lt;li&gt;Workflow queries DynamoDB for eligible farmers by region + crop + consent (with duplicate prevention — no farmer gets two nudges for the same activity on the same day)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NudgeSender Lambda&lt;/strong&gt; fires a crop-specific WhatsApp message with interactive buttons&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The farmer sees (in Hindi):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Today is good weather for fungicide spray on wheat. Wind: 8 km/h."&lt;br&gt;
[Done] [Not now]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If they tap "ho gaya" (done) — DynamoDB Streams triggers ResponseDetector Lambda, which detects the DONE keyword across all supported languages (Hindi/Marathi/Telugu/English), cancels all pending reminders, and marks the nudge as COMPLETED.&lt;/p&gt;

&lt;p&gt;If they don't respond — reminders fire at T+24h and T+48h.&lt;/p&gt;

&lt;h2&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.amazonaws.com%2Fuploads%2Farticles%2Fw3wfbz7da32s1donz49r.jpg" alt="Farmer confirms vs farmer delays — the closed loop in action" width="800" height="446"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Architecture Decision That Saved Us: EventBridge Scheduler vs Step Functions Wait States
&lt;/h2&gt;

&lt;p&gt;This was the most interesting trade-off in the build.&lt;/p&gt;

&lt;p&gt;The naive approach: keep a Step Functions execution alive for 72 hours to handle T+24h and T+48h reminders. At scale, that's expensive — state transition costs accumulate, and you're paying for executions that idle for days.&lt;/p&gt;

&lt;p&gt;The AgriNexus approach: Step Functions workflow completes in under 5 seconds. It sends the nudge and registers EventBridge Scheduler targets for each reminder. When the farmer responds, ResponseDetector deletes those schedules instantly. Short execution + scheduled targets = clean, cheap, scalable.&lt;/p&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.amazonaws.com%2Fuploads%2Farticles%2Fvf8n89p9rooohd9b9t4r.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fvf8n89p9rooohd9b9t4r.jpg" alt="EventBridge Scheduler vs Step Functions Wait States" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This pattern is reusable for any system that needs delayed follow-ups with early cancellation — appointment reminders, SLA escalations, onboarding sequences.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Nudge Loop Architecture
&lt;/h2&gt;

&lt;p&gt;Here's the full flow diagram — 12 steps from weather check to loop closure:&lt;/p&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.amazonaws.com%2Fuploads%2Farticles%2Fywbegvyw1rp9r5n77enj.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fywbegvyw1rp9r5n77enj.jpg" alt="Nudge Loop Architecture — from weather check to farmer confirmation" width="800" height="446"&gt;&lt;/a&gt;&lt;br&gt;
Key components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EventBridge Scheduler&lt;/strong&gt; — 7 AM daily trigger + T+24h/T+48h reminder targets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step Functions&lt;/strong&gt; — orchestrates the nudge workflow (completes in seconds, not days)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DynamoDB Streams&lt;/strong&gt; — real-time DONE keyword detection without polling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ResponseDetector Lambda&lt;/strong&gt; — multi-language keyword matching + schedule cleanup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single-Table DynamoDB&lt;/strong&gt; — user profiles, message idempotency, and nudge tracking in one table with composite keys&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Five Architecture Decisions in 30 Seconds
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Single-Table DynamoDB&lt;/strong&gt; — composite keys (&lt;code&gt;PK=USER#&amp;lt;phone&amp;gt;&lt;/code&gt;, &lt;code&gt;SK=PROFILE|MSG#&amp;lt;ts&amp;gt;|NUDGE#&amp;lt;id&amp;gt;&lt;/code&gt;) with GSI for region-based targeting. Access patterns defined before schema.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;EventBridge Scheduler over Step Functions Wait States&lt;/strong&gt; — short-lived executions + scheduled targets. Event-driven cleanup on DONE detection.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DynamoDB Streams for real-time response detection&lt;/strong&gt; — no polling. Stream triggers Lambda on every write, checks for DONE keywords across 4 languages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Claude 3 Sonnet for code-switching&lt;/strong&gt; — farmers mix Hindi and English ("Mere cotton mein pests hain"). Don't over-engineer language detection. Let the model handle what it's trained for.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Batch transcription over streaming (MVP)&lt;/strong&gt; — 20-34 second latency is acceptable for async WhatsApp. Ship first, optimize with real user feedback. Transcribe Streaming (&amp;lt;2s) is the post-MVP path.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Messaging&lt;/td&gt;
&lt;td&gt;WhatsApp Business API + API Gateway&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intelligence&lt;/td&gt;
&lt;td&gt;Amazon Bedrock (Claude 3 Sonnet) + RAG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Knowledge Base&lt;/td&gt;
&lt;td&gt;Bedrock Knowledge Bases + OpenSearch Serverless&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Voice In&lt;/td&gt;
&lt;td&gt;Amazon Transcribe (hi-IN, mr-IN, te-IN, en-IN)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Voice Out&lt;/td&gt;
&lt;td&gt;Amazon Polly (Aditi/Kajal neural voices)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vision&lt;/td&gt;
&lt;td&gt;Claude 3 Sonnet multimodal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nudge Engine&lt;/td&gt;
&lt;td&gt;EventBridge Scheduler + Step Functions + DynamoDB Streams&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;DynamoDB single-table + S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Orchestration&lt;/td&gt;
&lt;td&gt;AWS SAM, Lambda (Python 3.11)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Fully serverless. Zero instances. Scales from 10 to 10,000 farmers without re-architecture. Under $0.70/farmer/year at 10,000 users.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Voice is the interface, not a feature.&lt;/strong&gt; Typing in Devanagari on a basic Android is slow and error-prone. Voice notes are what farmers already use to communicate with family. AgriNexus works the same way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Behavioral nudges need closed loops.&lt;/strong&gt; Sending a reminder is easy. Knowing whether it worked is hard — and it matters. The T+24h/T+48h chain with DONE/NOT YET buttons came from thinking about what actually changes behavior, not just what delivers information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt engineering is iterative.&lt;/strong&gt; Initial RAG prompts gave 60% accuracy. Structured prompts with explicit format instructions and language-specific system messages reached 95%. Treat the AI as a collaborator that needs clear instructions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event-driven beats polling.&lt;/strong&gt; DynamoDB Streams for DONE detection, EventBridge Scheduler for delayed reminders, SQS for async processing — events scale better than polling loops at every level.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It / Read More
&lt;/h2&gt;

&lt;p&gt;I built AgriNexus for the &lt;strong&gt;AWS 10,000 AIdeas competition&lt;/strong&gt; (Agriculture &amp;amp; Food Security category) using Kiro for spec-driven development and 100+ EARS requirements with full traceability to code.&lt;/p&gt;

&lt;p&gt;The full technical deep-dive with demo videos, all four architecture flow diagrams, cost analysis, and the complete build journey is here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://builder.aws.com/content/39qTnLaOki9b8RyT8MXOrg7Fns6/aideas-agrinexus-ai-how-i-built-an-ai-agronomist-for-indias-100m-smallholder-farmers-voice-vision-and-behavioral-nudges-on-whatsapp" rel="noopener noreferrer"&gt;Read the full article on AWS Builder Center&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/prasadt1/agrinexus-ai" rel="noopener noreferrer"&gt;GitHub: AgriNexus AI&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If this resonated — a like on the article puts an AI agronomist in one more farmer's pocket 🙏 &lt;strong&gt;Voting closes March 20&lt;/strong&gt;.  &lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;em&gt;Built with Amazon Bedrock, Kiro, AWS Lambda, DynamoDB, EventBridge Scheduler, Step Functions, SQS FIFO, and WhatsApp Business API.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Schema-First Prompt Engineering: The Gemini Lesson That Will Save Your Production App</title>
      <dc:creator>PRASAD TILLOO</dc:creator>
      <pubDate>Fri, 13 Mar 2026 22:45:46 +0000</pubDate>
      <link>https://dev.to/prasadt1/schema-first-prompt-engineering-the-gemini-lesson-that-will-save-your-production-app-5976</link>
      <guid>https://dev.to/prasadt1/schema-first-prompt-engineering-the-gemini-lesson-that-will-save-your-production-app-5976</guid>
      <description>&lt;h2&gt;
  
  
  How enforcing JSON schema at the API level — not just in your prompt text — makes Gemini outputs reliable enough for production.
&lt;/h2&gt;

&lt;p&gt;I built an AI Photography Coach using Google Gemini 3 Pro — it analyzes photos across five dimensions, exposes the AI's reasoning chain, and lets you chat with a mentor that remembers your analysis context. The full project is open-source and the writeup is on Medium.&lt;br&gt;
But the single most transferable lesson from building it wasn't about photography or multimodal AI. It was about how to ask Gemini for structured data without it breaking on you in production.&lt;br&gt;
Here's what I learned.&lt;/p&gt;

&lt;p&gt;Quick Project Highlights&lt;/p&gt;

&lt;p&gt;📸 Live app: Search "Photography Coach AI" on Google AI Studio&lt;br&gt;
🐙 GitHub: &lt;a href="https://github.com/prasadt1/photography-coach-ai-gemini3" rel="noopener noreferrer"&gt;https://github.com/prasadt1/photography-coach-ai-gemini3&lt;/a&gt;&lt;br&gt;
📖 Full writeup: &lt;a href="https://medium.com/@prasad.sgsits/i-built-an-ai-photography-coach-with-google-gemini-3-pro-heres-everything-i-learned-45411abef25c" rel="noopener noreferrer"&gt;https://medium.com/@prasad.sgsits/i-built-an-ai-photography-coach-with-google-gemini-3-pro-heres-everything-i-learned-45411abef25c&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Problem&lt;br&gt;
Early in development I asked Gemini for structured data the way most developers do the first time — in plain English inside the prompt:&lt;br&gt;
"Analyze this photo and return a JSON object with five dimension scores..."&lt;br&gt;
It worked perfectly in testing. It broke constantly in production — markdown fences, preamble text, explanation paragraphs, inconsistent field names. Every variation that JSON.parse() couldn't handle.&lt;br&gt;
The fix is simple once you know it, but it's not obvious from the docs.&lt;/p&gt;

&lt;p&gt;The Wrong Way&lt;br&gt;
typescript// Asking nicely in prompt text — unreliable in production&lt;br&gt;
const prompt = &lt;code&gt;Analyze this photo and return JSON with &lt;br&gt;
composition_score, lighting_score, technique_score, &lt;br&gt;
creative_score, subject_score, and a reasoning object...&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;const response = await geminiClient.generateContent({&lt;br&gt;
  contents: [{ parts: [{ text: prompt }] }]&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;const text = response.candidates[0].content.parts[0].text;&lt;br&gt;
const parsed = JSON.parse(text);&lt;br&gt;
// 💥 Fails when Gemini adds markdown fences, preamble, or explanation&lt;/p&gt;

&lt;p&gt;The Right Way&lt;br&gt;
typescriptconst response = await geminiClient.generateContent({&lt;br&gt;
  contents: [{&lt;br&gt;
    parts: [&lt;br&gt;
      { inlineData: { mimeType: "image/jpeg", data: base64Image } },&lt;br&gt;
      { text: ANALYSIS_PROMPT }&lt;br&gt;
    ]&lt;br&gt;
  }],&lt;br&gt;
  generationConfig: {&lt;br&gt;
    responseMimeType: "application/json",   // enforce at API level&lt;br&gt;
    responseSchema: {                        // define exact contract&lt;br&gt;
      type: "object",&lt;br&gt;
      properties: {&lt;br&gt;
        composition_score:  { type: "number" },&lt;br&gt;
        lighting_score:     { type: "number" },&lt;br&gt;
        technique_score:    { type: "number" },&lt;br&gt;
        creative_score:     { type: "number" },&lt;br&gt;
        subject_score:      { type: "number" },&lt;br&gt;
        reasoning: {&lt;br&gt;
          type: "object",&lt;br&gt;
          properties: {&lt;br&gt;
            observations:   { type: "array", items: { type: "string" } },&lt;br&gt;
            reasoning_steps:{ type: "array", items: { type: "string" } },&lt;br&gt;
            priority_fixes: { type: "array", items: { type: "string" } }&lt;br&gt;
          },&lt;br&gt;
          required: ["observations", "reasoning_steps", "priority_fixes"]&lt;br&gt;
        }&lt;br&gt;
      },&lt;br&gt;
      required: [&lt;br&gt;
        "composition_score", "lighting_score", "technique_score",&lt;br&gt;
        "creative_score", "subject_score", "reasoning"&lt;br&gt;
      ]&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;// Now deterministic — safe to parse without defensive gymnastics&lt;br&gt;
const result = JSON.parse(response.candidates[0].content.parts[0].text);&lt;/p&gt;

&lt;p&gt;Why This Works&lt;br&gt;
responseMimeType: "application/json" tells Gemini at the API level to return pure JSON — no markdown fences, no preamble, no trailing explanation. This alone eliminates most production failures.&lt;br&gt;
responseSchema defines the exact contract. Gemini will not return fields outside it or omit required ones. Your frontend parsing becomes deterministic.&lt;br&gt;
Together they shift the reliability burden from your parsing code to the API itself — which is exactly where it belongs.&lt;/p&gt;

&lt;p&gt;The Deeper Lesson&lt;br&gt;
Schema enforcement changes how you design prompts. When you define the schema first, you're forced to think clearly about what you actually need from the model. That clarity produces better prompts, better outputs, and fewer surprises at 2am.&lt;br&gt;
Define your schema before you write your first prompt. Not after.&lt;br&gt;
In Photography Coach AI, this schema-first approach is what made it possible to drive five separate UI tabs — Overview, Detailed Analysis, Mentor Chat, AI Enhancement, Economics — all from a single structured Gemini response. No ambiguity, no defensive parsing, no fallback logic for malformed outputs.&lt;/p&gt;

&lt;p&gt;Troubleshooting Tips&lt;/p&gt;

&lt;p&gt;Empty responses after adding responseSchema: Check that your schema property names exactly match what you're asking for in the prompt. Mismatches between prompt language and schema field names are the most common cause of silent failures&lt;br&gt;
Nested objects failing: Define required arrays at every level of nesting, not just the top level&lt;br&gt;
Numbers returning as strings: Explicitly set type: "number" for all numeric fields — Gemini will default to string if the type is ambiguous&lt;br&gt;
Schema too complex: If your schema has more than ~15 fields, consider splitting into two sequential API calls rather than one monolithic schema&lt;br&gt;
Testing tip: Validate your schema against Gemini's output in AI Studio's playground before wiring it into your frontend — iterate the schema there, not in code&lt;/p&gt;

&lt;p&gt;CTAs&lt;/p&gt;

&lt;p&gt;⭐ Star the repo: &lt;a href="https://github.com/prasadt1/photography-coach-ai-gemini3" rel="noopener noreferrer"&gt;https://github.com/prasadt1/photography-coach-ai-gemini3&lt;/a&gt;&lt;br&gt;
📖 Full project writeup on Medium: &lt;a href="https://medium.com/@prasad.sgsits/i-built-an-ai-photography-coach-with-google-gemini-3-pro-heres-everything-i-learned-45411abef25c" rel="noopener noreferrer"&gt;https://medium.com/@prasad.sgsits/i-built-an-ai-photography-coach-with-google-gemini-3-pro-heres-everything-i-learned-45411abef25c&lt;/a&gt;&lt;br&gt;
🚀 Try the live app: Search "Photography Coach AI" on Google AI Studio&lt;br&gt;
🐛 Open an issue with questions or schema edge cases you've hit&lt;/p&gt;

&lt;p&gt;Header image prompt:&lt;/p&gt;

&lt;p&gt;"Dark background technical diagram showing two code blocks side by side labeled 'Wrong Way' in red and 'Right Way' in green. Center arrow between them. Bottom label: 'Schema-First Prompt Engineering with Gemini'. Monospace font, minimal design, teal and red accent colors. Dev.to header format, wide aspect ratio. Filename: devto-schema-first-header.png"&lt;/p&gt;

&lt;h1&gt;
  
  
  gemini #googleai #promptengineering #typescript #webdev #llm #javascript #opensource
&lt;/h1&gt;

</description>
    </item>
    <item>
      <title>Schema-First Prompt Engineering: The Gemini Lesson That Will Save Your Production App</title>
      <dc:creator>PRASAD TILLOO</dc:creator>
      <pubDate>Wed, 18 Feb 2026 09:18:41 +0000</pubDate>
      <link>https://dev.to/prasadt1/schema-first-prompt-engineering-the-gemini-lesson-that-will-save-your-production-app-1pea</link>
      <guid>https://dev.to/prasadt1/schema-first-prompt-engineering-the-gemini-lesson-that-will-save-your-production-app-1pea</guid>
      <description>&lt;p&gt;I built an AI Photography Coach using Google Gemini 3 Pro — it analyzes photos across five dimensions, exposes the AI's reasoning chain, and lets you chat with a mentor that remembers your analysis context. The full project is open-source and the writeup is on Medium.&lt;br&gt;
But the single most transferable lesson from building it wasn't about photography or multimodal AI. It was about how to ask Gemini for structured data without it breaking on you in production.&lt;br&gt;
Here's what I learned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Project Highlights&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;📸 Live app: &lt;a href="https://ai.studio/apps/drive/1v2uJziWHPOHRES4EmmWXavydKZAe8ary?fullscreenApplet=true" rel="noopener noreferrer"&gt;https://ai.studio/apps/drive/1v2uJziWHPOHRES4EmmWXavydKZAe8ary?fullscreenApplet=true&lt;/a&gt;&lt;br&gt;
🐙 GitHub: &lt;a href="https://github.com/prasadt1/photography-coach-ai-gemini3" rel="noopener noreferrer"&gt;https://github.com/prasadt1/photography-coach-ai-gemini3&lt;/a&gt;&lt;br&gt;
📖 Full writeup: &lt;a href="https://medium.com/@prasad.sgsits/i-built-an-ai-photography-coach-with-google-gemini-3-pro-heres-everything-i-learned-45411abef25c" rel="noopener noreferrer"&gt;https://medium.com/@prasad.sgsits/i-built-an-ai-photography-coach-with-google-gemini-3-pro-heres-everything-i-learned-45411abef25c&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem&lt;/strong&gt;&lt;br&gt;
Early in development I asked Gemini for structured data the way most developers do the first time — in plain English inside the prompt:&lt;br&gt;
"Analyze this photo and return a JSON object with five dimension scores..."&lt;br&gt;
It worked perfectly in testing. It broke constantly in production — markdown fences, preamble text, explanation paragraphs, inconsistent field names. Every variation that JSON.parse() couldn't handle.&lt;br&gt;
The fix is simple once you know it, but it's not obvious from the docs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrong Way&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Wrong Way: Unstructured Prompt
const ai = await getGenAIClient();

const prompt = `Analyze this image and tell me if it's good or bad.
  Give me some feedback.`;

const result = await ai.models.generateContent(prompt);
console.log(result.response.text());

// Output: "It's okay. The lighting is bit dark..."
// 💥 Unpredictable format, breaks JSON.parse() in production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Right Way&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Right Way: Schema-First
const ai = await getGenAIClient();

const schema = {
  type: Type.OBJECT,
  properties: {
    score:        { type: Type.NUMBER },
    feedback:     { type: Type.STRING },
    improvements: { type: Type.ARRAY, items: { type: Type.STRING } }
  },
  required: ['score', 'feedback', 'improvements']
};

const result = await ai.models.generateContent({
  model: 'gemini-3-pro-preview',
  contents: { role: 'user', parts: [{ text: prompt }] },
  config: {
    responseMimeType: 'application/json',
    responseSchema: schema
  }
});

console.log(JSON.parse(result.text));
// Output: { score: 7, feedback: "Good composition...",
//           improvements: ["Increase exposure"] }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Bonus Pattern&lt;/strong&gt;: Dynamic Client for AI Studio Compatibility&lt;br&gt;
If you're publishing to Google AI Studio, use a dynamic client helper that checks for the shared API key first before falling back to your environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const getGenAIClient = async (): Promise&amp;lt;GoogleGenAI&amp;gt; =&amp;gt; {
  // 1. Check for shared API key (AI Studio Published App Mode)
  if (typeof window !== 'undefined' &amp;amp;&amp;amp; (window as any).aistudio?.getSharedApiKey) {
    try {
      const apiKey = await (window as any).aistudio.getSharedApiKey();
      if (apiKey) return new GoogleGenAI({ apiKey });
    } catch (e) {
      console.debug("Shared key failed, falling back to env var:", e);
    }
  }
  // 2. Fallback to local env var (Standard Dev Mode)
  return new GoogleGenAI({ apiKey: process.env.API_KEY || '' });
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lets the same codebase work in both local development and AI Studio's published app mode without any changes — no environment-specific builds, no conditional deploys.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why This Works&lt;/strong&gt;&lt;br&gt;
responseMimeType: "application/json" tells Gemini at the API level to return pure JSON — no markdown fences, no preamble, no trailing explanation. This alone eliminates most production failures.&lt;br&gt;
responseSchema defines the exact contract. Gemini will not return fields outside it or omit required ones. Your frontend parsing becomes deterministic.&lt;br&gt;
Together they shift the reliability burden from your parsing code to the API itself — which is exactly where it belongs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Deeper Lesson&lt;/strong&gt;&lt;br&gt;
Schema enforcement changes how you design prompts. When you define the schema first, you're forced to think clearly about what you actually need from the model. That clarity produces better prompts, better outputs, and fewer surprises at 2am.&lt;br&gt;
Define your schema before you write your first prompt. Not after.&lt;br&gt;
In Photography Coach AI, this &lt;em&gt;schema-first approach&lt;/em&gt; is what made it possible to drive five separate UI tabs — Overview, Detailed Analysis, Mentor Chat, AI Enhancement, Economics — all from a single structured Gemini response. No ambiguity, no defensive parsing, no fallback logic for malformed outputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Troubleshooting Tips&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Empty responses after adding responseSchema&lt;/strong&gt;: Check that your schema property names exactly match what you're asking for in the prompt. Mismatches between prompt language and schema field names are the most common cause of silent failures&lt;br&gt;
&lt;strong&gt;Nested objects failing&lt;/strong&gt;: Define required arrays at every level of nesting, not just the top level&lt;br&gt;
&lt;strong&gt;Numbers returning as strings&lt;/strong&gt;: Explicitly set type: "number" for all numeric fields — Gemini will default to string if the type is ambiguous&lt;br&gt;
&lt;strong&gt;Schema too complex&lt;/strong&gt;: If your schema has more than ~15 fields, consider splitting into two sequential API calls rather than one monolithic schema&lt;br&gt;
&lt;strong&gt;Testing tip&lt;/strong&gt;: Validate your schema against Gemini's output in AI Studio's playground before wiring it into your frontend — iterate the schema there, not in code&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CTAs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;⭐ Star the repo: &lt;a href="https://github.com/prasadt1/photography-coach-ai-gemini3" rel="noopener noreferrer"&gt;https://github.com/prasadt1/photography-coach-ai-gemini3&lt;/a&gt;&lt;br&gt;
📖 Full project writeup on Medium: &lt;a href="https://medium.com/@prasad.sgsits/i-built-an-ai-photography-coach-with-google-gemini-3-pro-heres-everything-i-learned-45411abef25c" rel="noopener noreferrer"&gt;https://medium.com/@prasad.sgsits/i-built-an-ai-photography-coach-with-google-gemini-3-pro-heres-everything-i-learned-45411abef25c&lt;/a&gt;&lt;br&gt;
🚀 Try the live app: &lt;a href="https://ai.studio/apps/drive/1v2uJziWHPOHRES4EmmWXavydKZAe8ary?fullscreenApplet=true" rel="noopener noreferrer"&gt;https://ai.studio/apps/drive/1v2uJziWHPOHRES4EmmWXavydKZAe8ary?fullscreenApplet=true&lt;/a&gt;&lt;br&gt;
🐛 Open an issue with questions or schema edge cases you've hit&lt;/p&gt;

&lt;h1&gt;
  
  
  gemini #googleai #promptengineering #typescript #webdev #llm #javascript #opensource
&lt;/h1&gt;

</description>
    </item>
    <item>
      <title>Schema-First Prompt Engineering: The Gemini Lesson That Will Save Your Production App</title>
      <dc:creator>PRASAD TILLOO</dc:creator>
      <pubDate>Wed, 18 Feb 2026 09:18:41 +0000</pubDate>
      <link>https://dev.to/prasadt1/schema-first-prompt-engineering-the-gemini-lesson-that-will-save-your-production-app-30np</link>
      <guid>https://dev.to/prasadt1/schema-first-prompt-engineering-the-gemini-lesson-that-will-save-your-production-app-30np</guid>
      <description>&lt;p&gt;I built an AI Photography Coach using Google Gemini 3 Pro — it analyzes photos across five dimensions, exposes the AI's reasoning chain, and lets you chat with a mentor that remembers your analysis context. The full project is open-source and the writeup is on Medium.&lt;br&gt;
But the single most transferable lesson from building it wasn't about photography or multimodal AI. It was about how to ask Gemini for structured data without it breaking on you in production.&lt;br&gt;
Here's what I learned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick Project Highlights&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;📸 Live app: Search "Photography Coach AI" on Google AI Studio&lt;br&gt;
🐙 GitHub: &lt;a href="https://github.com/prasadt1/photography-coach-ai-gemini3" rel="noopener noreferrer"&gt;https://github.com/prasadt1/photography-coach-ai-gemini3&lt;/a&gt;&lt;br&gt;
📖 Full writeup: &lt;a href="https://medium.com/@prasad.sgsits/i-built-an-ai-photography-coach-with-google-gemini-3-pro-heres-everything-i-learned-45411abef25c" rel="noopener noreferrer"&gt;https://medium.com/@prasad.sgsits/i-built-an-ai-photography-coach-with-google-gemini-3-pro-heres-everything-i-learned-45411abef25c&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem&lt;/strong&gt;&lt;br&gt;
Early in development I asked Gemini for structured data the way most developers do the first time — in plain English inside the prompt:&lt;br&gt;
"Analyze this photo and return a JSON object with five dimension scores..."&lt;br&gt;
It worked perfectly in testing. It broke constantly in production — markdown fences, preamble text, explanation paragraphs, inconsistent field names. Every variation that JSON.parse() couldn't handle.&lt;br&gt;
The fix is simple once you know it, but it's not obvious from the docs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrong Way&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Wrong Way: Unstructured Prompt
const ai = await getGenAIClient();

const prompt = `Analyze this image and tell me if it's good or bad.
  Give me some feedback.`;

const result = await ai.models.generateContent(prompt);
console.log(result.response.text());

// Output: "It's okay. The lighting is bit dark..."
// 💥 Unpredictable format, breaks JSON.parse() in production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Right Way&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Right Way: Schema-First
const ai = await getGenAIClient();

const schema = {
  type: Type.OBJECT,
  properties: {
    score:        { type: Type.NUMBER },
    feedback:     { type: Type.STRING },
    improvements: { type: Type.ARRAY, items: { type: Type.STRING } }
  },
  required: ['score', 'feedback', 'improvements']
};

const result = await ai.models.generateContent({
  model: 'gemini-3-pro-preview',
  contents: { role: 'user', parts: [{ text: prompt }] },
  config: {
    responseMimeType: 'application/json',
    responseSchema: schema
  }
});

console.log(JSON.parse(result.text));
// Output: { score: 7, feedback: "Good composition...",
//           improvements: ["Increase exposure"] }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why This Works&lt;/strong&gt;&lt;br&gt;
responseMimeType: "application/json" tells Gemini at the API level to return pure JSON — no markdown fences, no preamble, no trailing explanation. This alone eliminates most production failures.&lt;br&gt;
responseSchema defines the exact contract. Gemini will not return fields outside it or omit required ones. Your frontend parsing becomes deterministic.&lt;br&gt;
Together they shift the reliability burden from your parsing code to the API itself — which is exactly where it belongs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Deeper Lesson&lt;/strong&gt;&lt;br&gt;
Schema enforcement changes how you design prompts. When you define the schema first, you're forced to think clearly about what you actually need from the model. That clarity produces better prompts, better outputs, and fewer surprises at 2am.&lt;br&gt;
Define your schema before you write your first prompt. Not after.&lt;br&gt;
In Photography Coach AI, this &lt;em&gt;schema-first approach&lt;/em&gt; is what made it possible to drive five separate UI tabs — Overview, Detailed Analysis, Mentor Chat, AI Enhancement, Economics — all from a single structured Gemini response. No ambiguity, no defensive parsing, no fallback logic for malformed outputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Troubleshooting Tips&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Empty responses after adding responseSchema&lt;/strong&gt;: Check that your schema property names exactly match what you're asking for in the prompt. Mismatches between prompt language and schema field names are the most common cause of silent failures&lt;br&gt;
&lt;strong&gt;Nested objects failing&lt;/strong&gt;: Define required arrays at every level of nesting, not just the top level&lt;br&gt;
&lt;strong&gt;Numbers returning as strings&lt;/strong&gt;: Explicitly set type: "number" for all numeric fields — Gemini will default to string if the type is ambiguous&lt;br&gt;
&lt;strong&gt;Schema too complex&lt;/strong&gt;: If your schema has more than ~15 fields, consider splitting into two sequential API calls rather than one monolithic schema&lt;br&gt;
&lt;strong&gt;Testing tip&lt;/strong&gt;: Validate your schema against Gemini's output in AI Studio's playground before wiring it into your frontend — iterate the schema there, not in code&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CTAs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;⭐ Star the repo: &lt;a href="https://github.com/prasadt1/photography-coach-ai-gemini3" rel="noopener noreferrer"&gt;https://github.com/prasadt1/photography-coach-ai-gemini3&lt;/a&gt;&lt;br&gt;
📖 Full project writeup on Medium: &lt;a href="https://medium.com/@prasad.sgsits/i-built-an-ai-photography-coach-with-google-gemini-3-pro-heres-everything-i-learned-45411abef25c" rel="noopener noreferrer"&gt;https://medium.com/@prasad.sgsits/i-built-an-ai-photography-coach-with-google-gemini-3-pro-heres-everything-i-learned-45411abef25c&lt;/a&gt;&lt;br&gt;
🚀 Try the live app: &lt;a href="https://ai.studio/apps/drive/1v2uJziWHPOHRES4EmmWXavydKZAe8ary?fullscreenApplet=true" rel="noopener noreferrer"&gt;https://ai.studio/apps/drive/1v2uJziWHPOHRES4EmmWXavydKZAe8ary?fullscreenApplet=true&lt;/a&gt;&lt;br&gt;
🐛 Open an issue with questions or schema edge cases you've hit&lt;/p&gt;

&lt;h1&gt;
  
  
  gemini #googleai #promptengineering #typescript #webdev #llm #javascript #opensource
&lt;/h1&gt;

</description>
    </item>
    <item>
      <title>I Built a Portfolio That Thinks Like an Architect (Using Google Gemini + Cloud Run)</title>
      <dc:creator>PRASAD TILLOO</dc:creator>
      <pubDate>Mon, 02 Feb 2026 07:54:12 +0000</pubDate>
      <link>https://dev.to/prasadt1/i-built-a-portfolio-that-thinks-like-an-architect-using-google-gemini-cloud-run-5f3e</link>
      <guid>https://dev.to/prasadt1/i-built-a-portfolio-that-thinks-like-an-architect-using-google-gemini-cloud-run-5f3e</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/new-year-new-you-google-ai-2025-12-31"&gt;New Year, New You Portfolio Challenge Presented by Google AI&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  An experience-driven AI portfolio that matches client challenges against 15+ years of real delivery patterns — not generic ChatGPT responses.
&lt;/h2&gt;




&lt;h2&gt;
  
  
  👋 About Me
&lt;/h2&gt;

&lt;p&gt;I’m Prasad Tilloo — an independent Enterprise Architect and Transformation Consultant based in Germany who's spent 15+ years helping enterprises navigate cloud migrations, AI adoption, and compliance-heavy transformations. I've worked with everyone from healthcare giants to climate tech startups.&lt;/p&gt;

&lt;p&gt;But here's the thing: &lt;strong&gt;every client asks the same question&lt;/strong&gt; - &lt;em&gt;"Have you done something like this before?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That question inspired me to build something different. Not another generic AI chatbot, but a portfolio that actually &lt;strong&gt;thinks like an architect&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Portfolio
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;🌐 Cloud Run App link&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__cloud-run"&gt;
  &lt;iframe height="600px" src="https://portfolio-service-405207878826.europe-west1.run.app"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;🎥 Quick Demo Video&lt;/strong&gt; (2 minutes):&lt;br&gt;
&lt;/p&gt;
&lt;div&gt;
  &lt;iframe src="https://loom.com/embed/0e248d766f9446d38964643431a7479c"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;


&lt;p&gt;👉 Try it yourself at &lt;a href="https://prasadtilloo.com/tools/project-similarity" rel="noopener noreferrer"&gt;https://prasadtilloo.com/tools/project-similarity&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Screens
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Homepage&lt;/strong&gt;&lt;br&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.amazonaws.com%2Fuploads%2Farticles%2Ffbr11btro3xtqd0f9re4.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.amazonaws.com%2Fuploads%2Farticles%2Ffbr11btro3xtqd0f9re4.png" alt="Homepage" width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Similarity Matcher&lt;/strong&gt;&lt;br&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.amazonaws.com%2Fuploads%2Farticles%2Fs6jrc1gjuo5tf4olzyg0.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.amazonaws.com%2Fuploads%2Farticles%2Fs6jrc1gjuo5tf4olzyg0.png" alt="Similarity Matcher" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Core Idea: Experience-Driven AI
&lt;/h3&gt;

&lt;p&gt;Most AI portfolios just slap ChatGPT onto a website. I wanted something smarter.&lt;/p&gt;

&lt;p&gt;My system analyzes your project description against &lt;strong&gt;structured signals&lt;/strong&gt; from real projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Industry patterns&lt;/li&gt;
&lt;li&gt;Technical constraints
&lt;/li&gt;
&lt;li&gt;Anti-patterns I've observed&lt;/li&gt;
&lt;li&gt;Decision frameworks that worked&lt;/li&gt;
&lt;li&gt;Retrospective lessons&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Google Gemini 1.5 Pro&lt;/strong&gt; handles the reasoning, but it's constrained by real project metadata - no hallucinated architectures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tech Stack &amp;amp; Google AI Integration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: React + TypeScript + Tailwind&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: Node.js on Google Cloud Run&lt;br&gt;&lt;br&gt;
&lt;strong&gt;AI&lt;/strong&gt;: Google Gemini 1.5 Pro&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Data&lt;/strong&gt;: Google Sheets (lightweight CRM)&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Email&lt;/strong&gt;: SendGrid for lead capture  &lt;/p&gt;

&lt;h3&gt;
  
  
  AI-Assisted Development Workflow
&lt;/h3&gt;

&lt;p&gt;I used &lt;strong&gt;Google Gemini + Antigravity&lt;/strong&gt; in a "vibe coding" approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemini&lt;/strong&gt; for architectural reasoning and refactoring suggestions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Antigravity&lt;/strong&gt; for rapid UI iteration
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human decisions&lt;/strong&gt; for UX structure, domain modeling, and production hardening&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example prompt I used:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Build experience-driven matching using project metadata, not embeddings. Score industry, constraints, anti-patterns, and decision frameworks. Return top 3 with confidence."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This accelerated development while keeping architectural decisions manual.&lt;/p&gt;

&lt;h3&gt;
  
  
  Production Architecture
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;🏗️ System Overview&lt;/strong&gt;:&lt;/p&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.amazonaws.com%2Fuploads%2Farticles%2F8qef4jpvyf4x30thtjka.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.amazonaws.com%2Fuploads%2Farticles%2F8qef4jpvyf4x30thtjka.png" alt="Architecture" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Container-level architecture showing Cloud Run hosting both frontend and API, Gemini-powered similarity engine, Google Sheets CRM, SendGrid email delivery, and Namecheap DNS with managed SSL.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Components:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: React + TypeScript + Vite SPA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: Node.js API on Google Cloud Run
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Engine&lt;/strong&gt;: Google Gemini 1.5 Pro for similarity matching&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Storage&lt;/strong&gt;: Google Sheets for CRM + Static JSON for projects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email&lt;/strong&gt;: SendGrid for transactional delivery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure&lt;/strong&gt;: Custom domain + SSL via Cloud Run&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Data Flow:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;User&lt;/strong&gt; describes project challenge via React interface&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Run API&lt;/strong&gt; processes request and queries project database
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemini AI&lt;/strong&gt; analyzes similarity patterns against 15+ years of experience&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System&lt;/strong&gt; generates personalized insights and recommendations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SendGrid&lt;/strong&gt; delivers results via email after lead capture&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Sheets&lt;/strong&gt; stores lead information for follow-up
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser (React + Vite)
↓
Cloud Run (Node API)  
↓
Gemini 1.5 Pro
↓
Project Similarity Engine
↓
Google Sheets (Leads + Tool Requests)
↓
SendGrid (Email Delivery)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why Cloud Run?&lt;/strong&gt; Zero infrastructure ops, automatic HTTPS, simple CI/CD. Perfect for a consulting business.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custom Domain Setup&lt;/strong&gt;: Namecheap DNS → Google Cloud Run with automatic SSL certificates.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm Most Proud Of
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;It's Actually Useful&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This isn't a demo. It's my real business system. Clients use it to understand if their project matches my experience before booking calls.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Experience-Driven AI Differentiation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Instead of generic responses, visitors get:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Here's the closest project I've done like yours — what worked, what failed, and what I'd do differently today."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Production-Grade Implementation&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;GDPR-safe lead capture&lt;/li&gt;
&lt;li&gt;Rate limiting on AI endpoints
&lt;/li&gt;
&lt;li&gt;Feature flags for staged rollout&lt;/li&gt;
&lt;li&gt;Email gating before AI results&lt;/li&gt;
&lt;li&gt;Proper error handling and fallbacks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Strategic Focus&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I intentionally enabled only &lt;strong&gt;one AI feature&lt;/strong&gt; for this submission. Why? To showcase architectural thinking over feature dumping. The Project Similarity Matcher demonstrates real business value, not AI novelty.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Real Business Impact&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Live deployment serving actual clients at &lt;a href="https://prasadtilloo.com" rel="noopener noreferrer"&gt;prasadtilloo.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Lead qualification through AI matching&lt;/li&gt;
&lt;li&gt;Case studies with NDA-protected artifacts&lt;/li&gt;
&lt;li&gt;Evidence-based trust building&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;The Result?&lt;/strong&gt; A portfolio that doesn't just show my work - it &lt;strong&gt;thinks like I do&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of telling clients "I'm experienced," it shows them exactly how my experience applies to their specific challenge.&lt;/p&gt;

&lt;p&gt;That's the difference between a portfolio and a &lt;strong&gt;business system&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;🔗 Links&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live Site&lt;/strong&gt;: &lt;a href="https://prasadtilloo.com" rel="noopener noreferrer"&gt;prasadtilloo.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Demo Video&lt;/strong&gt;: &lt;a href="https://www.loom.com/share/0e248d766f9446d38964643431a7479c" rel="noopener noreferrer"&gt;2-minute Loom walkthrough&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source Code&lt;/strong&gt;: &lt;a href="https://github.com/prasadt1/my-portfolio" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Competition Page&lt;/strong&gt;: &lt;a href="https://prasadtilloo.com/competition" rel="noopener noreferrer"&gt;Technical Deep Dive&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Built for the Google AI "New Year, New You" Portfolio Challenge 🏆&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>portfolio</category>
      <category>gemini</category>
    </item>
    <item>
      <title>From Student to AI Architect: How Multi-Agent Systems Rewired My Understanding of Intelligent Applications</title>
      <dc:creator>PRASAD TILLOO</dc:creator>
      <pubDate>Sat, 13 Dec 2025 11:29:01 +0000</pubDate>
      <link>https://dev.to/prasadt1/from-student-to-ai-architect-how-multi-agent-systems-rewired-my-understanding-of-intelligent-5ehj</link>
      <guid>https://dev.to/prasadt1/from-student-to-ai-architect-how-multi-agent-systems-rewired-my-understanding-of-intelligent-5ehj</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/devteam/join-the-ai-agents-intensive-course-writing-challenge-with-google-and-kaggle-1i46?"&gt;Google AI Agents Writing Challenge&lt;/a&gt;: Learning Reflections &amp;amp; Capstone Showcase&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Learning Journey
&lt;/h2&gt;

&lt;p&gt;Five days ago, I submitted an AI Photography Coach—a multi-agent system capstone project for the &lt;a href="https://www.kaggle.com/learn-guide/5-day-agents" rel="noopener noreferrer"&gt;5-Day AI Agents Intensive Course with Google&lt;/a&gt;  that fundamentally changed how I think about building intelligent applications. This wasn't just another capstone project. It forced me to confront a question I'd been wrestling with for months: &lt;strong&gt;What separates a system that appears intelligent from one that genuinely solves problems?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Coming into the Google AI Agents Intensive, I understood agents conceptually. I'd read the papers. I'd tinkered with LLMs. But there was a critical gap between &lt;em&gt;understanding&lt;/em&gt; and &lt;em&gt;architecting&lt;/em&gt;—and this course obliterated that gap.&lt;/p&gt;

&lt;p&gt;The breakthrough came on Day 2 when we deconstructed the difference between &lt;strong&gt;monolithic LLM calls&lt;/strong&gt; and &lt;strong&gt;specialized agent systems&lt;/strong&gt;. Most people use LLMs like Swiss Army knives—one model trying to do everything. The course showed me something radical: &lt;strong&gt;the power isn't in having one smart model; it's in having many focused ones working together.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Concepts &amp;amp; Technical Deep Dive
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The ADK Native Orchestrator Pattern: Architecture That Actually Works
&lt;/h3&gt;

&lt;p&gt;The game-changer for my photography coach was understanding the &lt;strong&gt;ADK-native orchestrator pattern&lt;/strong&gt;. Instead of building a custom routing system, I leveraged Google's Agent Development Kit's built-in orchestration capabilities.&lt;/p&gt;

&lt;p&gt;Here's the architecture that makes this work:&lt;/p&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.amazonaws.com%2Fuploads%2Farticles%2F026yk6euplsz3074f91p.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.amazonaws.com%2Fuploads%2Farticles%2F026yk6euplsz3074f91p.png" alt="System Architecture - Agent Interaction" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core Agents (Shared):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vision Agent&lt;/strong&gt; (Sub-Agent 1): Uses Gemini 2.5 Flash Vision for image analysis—EXIF extraction, composition analysis, defect detection with severity scoring, and strength identification&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestrator Agent&lt;/strong&gt; (Parent): The intelligent coordinator that manages session state, routes requests to specialized sub-agents, implements context compaction, and persists memory using SQLite + ADK Cloud Memory adapters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge Agent&lt;/strong&gt; (Sub-Agent 2): Powered by Gemini 2.5 Flash with hybrid CASCADE RAG for query understanding, knowledge retrieval, response generation, citation grounding, and skill-level adaptation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Pattern: Orchestrator Mediates All Communication&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is critical: the orchestrator mediates &lt;em&gt;all&lt;/em&gt; agent communication. The Vision Agent doesn't talk directly to the Knowledge Agent. Instead:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Vision Agent outputs structured analysis (exif dict, composition_summary, detected_issues, strengths)&lt;/li&gt;
&lt;li&gt;Orchestrator aggregates this with session context&lt;/li&gt;
&lt;li&gt;Knowledge Agent receives unified input context and generates the coaching response&lt;/li&gt;
&lt;li&gt;Orchestrator updates conversation history and persists session state&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This eliminates cascading errors and makes the entire system debuggable in ways direct agent-to-agent communication could never achieve. It's a pattern, not just a feature—and it's built into ADK natively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three Infrastructure Approaches: One System, Multiple Deployments
&lt;/h3&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.amazonaws.com%2Fuploads%2Farticles%2Fwv3ueleaf41vpbhbzfk9.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.amazonaws.com%2Fuploads%2Farticles%2Fwv3ueleaf41vpbhbzfk9.png" alt="Multi-Platform Deployment" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What fascinated me was how the same core agents can run through &lt;em&gt;three different interfaces&lt;/em&gt;. This distinction between agent architecture and deployment architecture was the second major revelation:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. ADK Runner (Cloud)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Components: LlmAgent, Runner, Sessions&lt;/li&gt;
&lt;li&gt;Interface: Vertex AI / Cloud Run&lt;/li&gt;
&lt;li&gt;When to use: Production-grade photo coaching with cloud scalability and managed infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. MCP Server (Desktop)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Components: JSON-RPC 2.0 over stdio transport&lt;/li&gt;
&lt;li&gt;Capabilities: 3 tools exposed per agent&lt;/li&gt;
&lt;li&gt;Deploy: Claude Desktop, local machine&lt;/li&gt;
&lt;li&gt;When to use: Local development, integration with Claude, running alongside other MCP-compatible tools&lt;/li&gt;
&lt;li&gt;This was the breakthrough for me—MCP protocol meant I could integrate my agents with &lt;em&gt;any&lt;/em&gt; compatible application without rewriting core logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Python API (Custom)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Components: Direct imports, function calls&lt;/li&gt;
&lt;li&gt;Deploy: Notebooks, custom apps, Streamlit dashboards&lt;/li&gt;
&lt;li&gt;When to use: Research, experimentation, embedded systems, educational contexts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The realization: &lt;strong&gt;agent architecture is orthogonal to deployment architecture&lt;/strong&gt;. Design the agent system once (orchestrator + specialized agents), then expose it through whichever interface makes sense for your use case. This separation of concerns is elegant and powerful.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Critical Insight: Negative Space Design
&lt;/h3&gt;

&lt;p&gt;During debugging, I discovered something counterintuitive: &lt;strong&gt;the best agent isn't the one with the smartest prompts; it's the one with the clearest responsibilities.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I spent as much time defining what each agent should &lt;em&gt;not&lt;/em&gt; do as defining what it should do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vision Agent&lt;/strong&gt;: Analyzes only what's in the image. Never generates teaching advice or pedagogical content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge Agent&lt;/strong&gt;: Teaches based on provided analysis. Never re-analyzes images or duplicates vision work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestrator&lt;/strong&gt;: Routes and aggregates. Never generates original analysis or coaching—only synthesis.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This negative space design—drawing boundaries tighter than seemed necessary—eliminated entire categories of bugs. It forced each agent's responsibility to be so crystalline that context compaction became natural, error handling became obvious, and delegation logic became transparent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Context Engineering and Memory as Foundation
&lt;/h3&gt;

&lt;p&gt;The course's emphasis on context compaction changed how I architect systems. In a multi-agent ecosystem, context is a &lt;em&gt;resource&lt;/em&gt;, not a convenience.&lt;/p&gt;

&lt;p&gt;The photography coach uses a two-tier memory system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Session memory&lt;/strong&gt;: Short-term context about current analysis and conversation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User model&lt;/strong&gt;: Long-term history of preferences, skill progression, learning patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The orchestrator implements context compaction before passing context between agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Summarizing vision analysis into structured fields (rather than raw model output)&lt;/li&gt;
&lt;li&gt;Truncating conversation history intelligently&lt;/li&gt;
&lt;li&gt;Maintaining only relevant user profile context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't optimization; it's &lt;em&gt;architectural necessity&lt;/em&gt;. With three agents and multiple turns, uncompressed context balloons quickly. Compaction forces rigor in what information actually matters for decision-making.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools: The Backbone of Agent Capability
&lt;/h3&gt;

&lt;p&gt;The course reframed my entire thinking: agents aren't intelligent because of their prompts; they're intelligent because of their tools.&lt;/p&gt;

&lt;p&gt;For the photography coach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vision APIs&lt;/strong&gt;: Constrain analysis to structured outputs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vector Database&lt;/strong&gt; (CASCADE hybrid RAG): Guarantee knowledge comes from grounded sources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Tools&lt;/strong&gt;: Photography-specific calculations (depth of field relationships, shutter speed ratios, focal length conversions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory Tools&lt;/strong&gt;: SQLite adapters for persistence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each tool is a &lt;em&gt;constraint&lt;/em&gt; that prevents hallucination. When a Vision Agent can only output structured EXIF data and composition summaries, it can't invent. When the Knowledge Agent can only pull from photography principles via RAG, its advice has traceable citations. Tools aren't features you add; they're guardrails you build into the system's fabric.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflections &amp;amp; Takeaways
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What the Course Got Right
&lt;/h3&gt;

&lt;p&gt;The hands-on codelabs genuinely built intuition. I didn't just read about multi-agent systems; I implemented them, broke them, debugged them, rebuilt them. The guest speakers—engineers shipping agentic AI at scale—grounded theory in production reality. Learning about the ADK's orchestrator pattern in isolation, then building it into a real system, created understanding that no lecture could achieve.&lt;/p&gt;

&lt;p&gt;The emphasis on &lt;em&gt;architecture as design constraint&lt;/em&gt; was transformative. Before this course, I thought about features and interfaces. Now I think about specialization, coordination, failure modes, and the boundaries between components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Honest Critique
&lt;/h3&gt;

&lt;p&gt;The course could dive deeper into &lt;strong&gt;failure modes in multi-agent systems&lt;/strong&gt;. They fail in new ways: cascading errors compounding across agents, subtle bugs in delegation logic, context compaction artifacts that only emerge in production. A dedicated deep-dive would be invaluable.&lt;/p&gt;

&lt;p&gt;More explicit guidance on &lt;strong&gt;choosing deployment interfaces&lt;/strong&gt; would help practitioners. The fact that one agent system can work through ADK Runner, MCP Server, or custom Python API is powerful—but knowing when to use each requires hands-on experience or mentorship.&lt;/p&gt;

&lt;h3&gt;
  
  
  How This Changes What I Build Next
&lt;/h3&gt;

&lt;p&gt;I'm now architecting systems fundamentally differently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define agent specialization and boundaries first, &lt;em&gt;before&lt;/em&gt; any code&lt;/li&gt;
&lt;li&gt;Treat the orchestrator pattern as primitive, not optional&lt;/li&gt;
&lt;li&gt;Make context compaction a first-class design concern&lt;/li&gt;
&lt;li&gt;Use tools to constrain behavior, not enhance capability&lt;/li&gt;
&lt;li&gt;Choose deployment interface &lt;em&gt;after&lt;/em&gt; agent architecture is finalized, not before&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The photography coach is just the beginning. The real power is understanding that &lt;strong&gt;intelligent systems are built through specialization and clear boundaries&lt;/strong&gt;, not through smarter prompts or larger models. Architecture beats parameters every time.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Bigger Picture
&lt;/h3&gt;

&lt;p&gt;If you're considering the AI Agents Intensive: do it. But go in expecting it to change your architecture mindset, not just teach you new libraries.&lt;/p&gt;

&lt;p&gt;The future of AI isn't smarter models—it's smarter systems. Systems that know their limitations, delegate to specialists, maintain clear boundaries, and communicate through structured protocols. Systems where architecture is a design tool, not an afterthought. That's what this course teaches. That's what matters now.&lt;/p&gt;




&lt;h2&gt;
  
  
  Technical Stack &amp;amp; Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Core Agents (ADK Native):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vision Agent: Gemini 2.5 Flash Vision (image analysis, EXIF extraction, composition scoring, defect detection)&lt;/li&gt;
&lt;li&gt;Orchestrator Agent: Session management, context compaction, routing, memory persistence&lt;/li&gt;
&lt;li&gt;Knowledge Agent: Gemini 2.5 Flash + Hybrid CASCADE RAG (knowledge retrieval, citations, skill adaptation)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Memory &amp;amp; Persistence:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQLite for session state&lt;/li&gt;
&lt;li&gt;ADK Cloud Memory adapters&lt;/li&gt;
&lt;li&gt;Conversation history management&lt;/li&gt;
&lt;li&gt;User model tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Deployment Options:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ADK Runner&lt;/strong&gt;: Cloud/Vertex AI production deployment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Server&lt;/strong&gt;: Desktop deployment with JSON-RPC 2.0 (Claude Desktop, local tools)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python API&lt;/strong&gt;: Notebooks, Streamlit, custom applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Integration Patterns:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Orchestrator-mediated agent communication (no direct agent-to-agent)&lt;/li&gt;
&lt;li&gt;Structured context passing between agents&lt;/li&gt;
&lt;li&gt;RAG-grounded knowledge retrieval with citations&lt;/li&gt;
&lt;li&gt;Context compaction before inter-agent communication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Project Links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/prasadt1/ai-photography-coach-agents" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kaggle.com/competitions/agents-intensive-capstone-project/writeups/ai-photography-coach-multiagent-concierge-for-l" rel="noopener noreferrer"&gt;Kaggle Capstone Writeup&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>googlekagglechallenge</category>
      <category>ai</category>
      <category>aiagents</category>
    </item>
  </channel>
</rss>
