#Backend Engineering

Articles about Backend Engineering — exploring patterns, best practices, and real-world implementations in production systems.

220 posts tagged with backend engineering. ← All posts

#A2A (5)#ADK (8)#AG-UI (6)#AI (9)#AI Agents (212)#AI Engineering (39)#AI Governance (16)#AI Red Teaming (8)#AI Safety (6)#AI Security (16)#AML (3)#API Design (9)#API Security (8)#APIs (37)#AWS (9)#Accounting (9)#Agent Skills (3)#Agentic AI (24)#Agentic Commerce (12)#Agents (4)#Amazon Bedrock (8)#Architecture (36)#Audit (3)#Automation (6)#Azure (11)#Azure AI Foundry (9)#Backend Engineering (220)#BigQuery (6)#CI/CD (7)#Capital Markets (14)#Card Payments (12)#Cards (13)#Career (7)#Checkpointing (4)#Claude Code (8)#Cloud Architecture (3)#Code Review (8)#Collaboration (4)#Communication (4)#Compliance (42)#Concurrency (23)#Consulting (3)#Cost Optimisation (5)#Credit (14)#Credit Risk (14)#Crypto (12)#Cryptocurrency (12)#Custody (9)#Data (4)#Data Structures (3)#Databases (14)#Deployment (3)#DevSecOps (10)#Developer Experience (3)#Distributed Systems (64)#Documentation (3)#Embeddings (11)#Engineering (7)#Engineering Culture (3)#Engineering Practices (16)#Evaluation (31)#FREE-AI (8)#FX (5)#FinOps (5)#FinTech (6)#Financial AI (14)#Financial Systems (122)#Fintech (116)#Foreign Exchange (5)#Forward Deployed Engineer (8)#Forward Deployed Engineering (8)#Fraud (10)#Function Tools (5)#GCP (5)#Go (220)#Google ADK (36)#Governance (46)#Granite (6)#GraphQL (3)#Guardrails (21)#HIPAA (3)#HTTP (3)#Harness Engineering (8)#Human-in-the-Loop (8)#IBM watsonx (8)#Integration (3)#Interfaces (3)#KYC (11)#KYC and AML (12)#Kubernetes (8)#LLM (5)#LLMs (45)#LangGraph (11)#Ledger (12)#Lending (14)#MCP (10)#MLOps (3)#Machine Learning (12)#Markets (4)#Memory (8)#Microservices (3)#Microsoft Agent Framework (150)#Middleware (6)#Migration (9)#Monitoring (3)#Multi-Agent (10)#Multi-Agent AI (14)#Multi-Agent Systems (49)#Multimodal (3)#NIM (5)#NVIDIA (8)#OWASP (7)#Observability (25)#Open Source (6)#OpenTelemetry (4)#Opinion (6)#Orchestration (10)#Payment Rails (16)#Payments (51)#Performance (6)#Privacy Engineering (3)#Product (4)#Production (6)#Programming (10)#Prompt Engineering (26)#Prompt Injection (7)#Providers (4)#Python (89)#Quality (3)#RAG (23)#RBI (3)#REST (5)#Rails (16)#Reconciliation (3)#Regulation (9)#Reliability (27)#Resilience (3)#Responsible AI (4)#Retrieval (3)#Risk (13)#SRE (4)#Scalability (3)#Security (63)#Sessions (3)#Settlement (9)#Software Architecture (9)#Software Engineering (94)#Spanner (4)#Streaming (21)#Structured Output (4)#System Design (8)#Testing (30)#Tool Use (9)#Tools (3)#Trading (8)#Treasury (6)#Type System (3)#Type Systems (3)#Vector Databases (8)#Vector Search (3)#Workflows (14)#gRPC (4)
Pratik Dhanave · ·13 min read

Bedrock in Production: IAM, Cost, and Observability

Taking an Amazon Bedrock Go service from a working prototype to something you can run on-call — least-privilege IAM, credentials without static keys, tuning the SDK's built-in retryer, tracking token cost, and wiring up logging and metrics with aws-sdk-go-v2.

Taking a Bedrock Go service to production: least-privilege IAM and role-based credentials, tuning the SDK's built-in retryer for throttling, token-based cost tracking, and observability via model-invocation logging, structured metrics, and request IDs.

Pratik Dhanave · ·12 min read

Guardrails and Safety

How to put Amazon Bedrock Guardrails in front of a model from Go — attaching one to a Converse call, screening raw text with ApplyGuardrail, and reading whether the guardrail actually intervened.

Guardrails for Amazon Bedrock in Go: content filters, denied topics, PII/sensitive-information filters, and contextual grounding — attaching a guardrail to a Converse call and screening arbitrary text with ApplyGuardrail, checking for intervention.

Pratik Dhanave · ·15 min read

Production AI

The last post in the series: what changes when the LLM system you built across posts 1-14 has to run for real — reliability, security, cost, observability, evaluation gates, and versioning, from a Go engineer's seat, with code where it earns its place.

The capstone: running an LLM system in production from a Go engineer's seat — reliability (timeouts, retries, fallbacks), security (injection, least-privilege tools, secrets), cost and observability, CI eval gates, and versioning models and prompts.

Pratik Dhanave · ·13 min read

Bedrock Agents

How to invoke a managed Agent for Amazon Bedrock from Go — where the server owns the reason-act loop, and your job is to call InvokeAgent, range the event stream, accumulate the answer chunks, and read the trace for observability.

Agents for Amazon Bedrock from Go: the managed reason-act loop that runs server-side (vs the DIY Converse loop), invoking an agent alias with InvokeAgent, streaming the response and trace events, and keeping multi-turn state with a SessionId.

Pratik Dhanave · ·14 min read

Inference Optimization

Making an LLM system faster and cheaper without touching the weights — the levers an application engineer actually controls, from streaming and caching to token trimming, model routing, and Go's real superpower: concurrency with a rate limiter.

Make LLM systems faster and cheaper without retraining: TTFT vs throughput, exact and semantic response caching, prompt caching, token reduction, model routing and cascades, and Go concurrency with a worker pool and rate limiter.

Pratik Dhanave · ·11 min read

Evaluating Multi-Turn and Multi-Agent Systems

The capstone of the Evaluating Agents in Go series: how to score a conversation instead of a single reply, how to attribute errors across a coordinator and its sub-agents, and how to build rubric, safety, and hallucination judges in Go when the framework hands you no eval package.

The capstone of the Evaluating Agents in Go series: how to score a conversation instead of a single reply, how to attribute errors across a coordinator and its sub-agents, and how to build rubric, safety,...

Pratik Dhanave · ·10 min read

Retrieval-Augmented Generation with Knowledge Bases

How to query a Knowledge Base for Amazon Bedrock from Go — the managed retrieve-then-read layer — using both the low-level Retrieve call and the one-shot RetrieveAndGenerate, with citations wired through.

RAG on Bedrock in Go with Knowledge Bases: the retrieve-then-read pattern via Retrieve, the one-shot managed path via RetrieveAndGenerate with citations, and when to reach for each — plus reading grounding so you keep RAG's trust benefit.

Pratik Dhanave · ·13 min read

Evaluating AI Systems

How to know whether an LLM system actually works — building an eval dataset, the four metric families (deterministic checks, text overlap, embedding similarity, LLM-as-judge) in Go, task-specific eval for RAG and classification, and wiring a scored regression gate into CI so you measure instead of vibe.

How to know whether an LLM system works when outputs are non-deterministic: build an eval dataset, score with deterministic checks, embedding similarity, and LLM-as-judge (with its biases), evaluate RAG and classification, and gate regressions in CI.

Pratik Dhanave · ·13 min read

Agent Evaluation in CI: Regression Gating

How to wire agent evaluations into continuous integration in Go — running a slow, model-calling eval harness under `go test`, setting per-metric thresholds that fail the build on a regression, and living honestly with the fact that these gates are softer than unit tests.

How to wire agent evaluations into continuous integration in Go — running a slow, model-calling eval harness under `go test`, setting per-metric thresholds that fail the build on a regression, and living...

Pratik Dhanave · ·12 min read

Tool Use with the Converse API

How to give an Amazon Bedrock model real Go functions — declaring tools, catching the tool-use stop reason, executing your code, and returning results — using the full round-trip loop in aws-sdk-go-v2.

Giving a Bedrock model tools in Go via the Converse API: declaring a ToolConfiguration, the ToolUse round-trip loop, echoing ToolUseId, returning tool results as a user message, and handling parallel tool calls.

Pratik Dhanave · ·15 min read

Agent Memory and Planning

Give the hand-rolled Go agent from post 11 a memory it can carry between turns and a plan it can follow across many steps — a compacting conversation buffer, retrieval over the post-8 vector store, and a plan-then-execute-then-reflect loop, all built from scratch.

Give the agent memory and planning in Go: a compacting short-term conversation buffer, long-term memory as timestamped embeddings in the vector store, and planning — plan-then-execute, reflection and re-planning when observations contradict the plan, and task decomposition.

Pratik Dhanave · ·11 min read

Building Eval Datasets from Real Traces

Where good eval cases actually come from — seeding by hand, harvesting from production telemetry, and curating a golden dataset in Go that doesn't rot the moment your prompt changes.

Where good eval cases actually come from — seeding by hand, harvesting from production telemetry, and curating a golden dataset in Go that doesn't rot the moment your prompt changes.

Pratik Dhanave · ·9 min read

Streaming and Token Usage

How to stream Amazon Bedrock responses token-by-token with the aws-sdk-go-v2 Converse API, decode the event stream with a double type-switch, and account for tokens and cost from the metadata event — accurately, in Go.

Streaming responses and accounting for tokens and cost on Bedrock in Go: ranging the ConverseStream event stream, the nested delta unions, checking stream.Err(), and computing cost from the metadata usage event with a formula you fill in.

Pratik Dhanave · ·14 min read

Agents from Scratch

Building a real agent loop in Go by hand — an LLM in a loop that picks tools, runs them, reads the results, and repeats until the task is done — so you can see there is no magic behind LangGraph, MAF, or ADK.

Build a minimal but real agent loop in Go by hand: an Agent with a tool registry and a reason-act Run loop, an iteration budget, validation against hallucinated tools, feeding tool errors back as observations, and parallel tool calls — the loop frameworks formalize, demystified.

Pratik Dhanave · ·13 min read

Response Evaluation: Match, ROUGE, and LLM-as-Judge

How to score an agent's final answer against a reference — from exact string match, through ROUGE-1 unigram overlap, to an LLM judge — with original Go you can drop into a test suite. Part 5 of Evaluating Agents in Go.

How to score an agent's final answer against a reference — from exact string match, through ROUGE-1 unigram overlap, to an LLM judge — with original Go you can drop into a test suite. Part 5 of Evaluating...

Pratik Dhanave · ·11 min read

Calling a Model with the Converse API

Your first real inference call in Go against Amazon Bedrock — using the unified, model-agnostic Converse API and the AWS SDK for Go v2, from client construction to reading tokens back off the response.

Your first real inference call on Bedrock in Go via the unified Converse API: building the client, the ConverseInput message/content-block union, extracting the assistant text, and reading stop reason and token usage — with the content-block union explained.

Pratik Dhanave · ·17 min read

Making RAG Good

Why the naive RAG pipeline from post 9 underperforms in production, and the concrete, evaluation-driven fixes — structure-aware chunking, hybrid search, reranking, query transformation, and deliberate context construction — each explained with the reasoning and a real Go sketch.

Why naive RAG underperforms and the techniques that fix it: measure recall@k first, then structure-aware chunking, hybrid dense+BM25 search fused with RRF, over-retrieve-then-rerank, query transformation (HyDE, multi-query), and deliberate context construction against lost-in-the-middle.

Pratik Dhanave · ·13 min read

Trajectory Evaluation in Go

How to score what an agent did, not just what it said — building trajectory metrics in Go from an exact-match baseline up to arg-aware, order-tolerant scoring, with a readable diff of expected vs. actual.

How to score what an agent *did*, not just what it *said* — building trajectory metrics in Go from an exact-match baseline up to arg-aware, order-tolerant scoring, with a human-readable diff of expected vs....

Pratik Dhanave · ·9 min read

What Amazon Bedrock Is

The opener for a Go series on building LLM and agent applications with Amazon Bedrock — what the service actually is, why it sits between your Go code and a dozen foundation models, and which aws-sdk-go-v2 packages you will lean on for the rest of the way.

The opener to a series on building LLM and agent applications on Amazon Bedrock in Go: what Bedrock actually is, what it adds over calling a provider API directly (one API across models, IAM auth, data residency), and the aws-sdk-go-v2 packages you'll use.

Pratik Dhanave · ·13 min read

Retrieval-Augmented Generation

Wire the embedding client, vector store, and chat client from the last five posts into one working RAG pipeline in Go — ingest and chunk documents, retrieve the top matches for a question, inject them as grounded context, and generate a cited answer, all from scratch.

Assemble embeddings and vector search into a working RAG pipeline in Go: chunk documents, embed and store them, retrieve the top-k for a query, augment the prompt with grounded context (and cite sources), then generate — a baseline end-to-end Answer() built from scratch.

Pratik Dhanave · ·13 min read

Building an Evaluation Harness in Go

The core of the series: a minimal, original evaluation harness in Go. Run an agent under test through adk-go's runner, capture the tool-call trajectory and the final response behind an adapter you own, and score them with `go test`.

The core of the series: a minimal, original evaluation harness in Go. Run an agent under test through adk-go's runner, capture the tool-call trajectory and the final response behind an adapter you own, and...

Pratik Dhanave · ·16 min read

Vector Search from Scratch

Build a working in-memory vector store and exact k-nearest-neighbor search in Go by hand — no vector database — then understand precisely what HNSW, FAISS, and pgvector optimize when brute force finally runs out of road.

Build an in-memory vector store and exact k-NN search in Go by hand: a VectorStore with Add and Search, top-k selection with container/heap, normalize-on-insert, an honest look at when brute force is right, and when ANN (HNSW, FAISS, pgvector) earns its keep.

Pratik Dhanave · ·11 min read

The ADK Evaluation Model

Before you can evaluate an agent in Go, you need a mental model of what "evaluating an agent" even means. This post unpacks the conceptual core of Google's Agent Development Kit eval framework — cases, trajectories, metrics, thresholds — the parts that are language-agnostic, so the rest of this series can implement them as plain Go types and functions.

Before you can evaluate an agent in Go, you need a mental model of what "evaluating an agent" even means. This post unpacks the conceptual core of Google's Agent Development Kit eval framework — cases,...

Pratik Dhanave · ·13 min read

Embeddings

Turn text into a `[]float32` that places meaning in space — what an embedding is, cosine similarity implemented by hand in Go, calling an OpenAI-compatible /embeddings endpoint with net/http, and a worked pairwise-similarity example that scores related sentences higher.

Turn text into a []float32 that places meaning in space — what an embedding is, cosine similarity implemented by hand in Go, calling an OpenAI-compatible /embeddings endpoint with net/http, and a worked pairwise-similarity example that scores related sentences higher.

Pratik Dhanave · ·10 min read

Why Evaluating AI Agents Is Hard

The opener to a series on evaluating agents in Go: why an agent isn't a function you can unit-test, why "it worked in the demo" doesn't survive contact with production, and the two things actually worth measuring — the steps it took and the answer it gave.

The opener to a series on evaluating agents in Go: why an agent isn't a function you can unit-test, why "it worked in the demo" doesn't survive contact with production, and the two things actually worth...

Pratik Dhanave · ·15 min read

Prompt Engineering as Engineering

Treating the prompt as a real engineering artifact — grounded in how a next-token predictor actually works — with roles, specificity, few-shot examples, decomposition, chain-of-thought, grounding, temperature, injection defense, and versioned Go templates you can test.

Prompt engineering as a real engineering discipline: roles, specificity, few-shot, decomposition, chain-of-thought and its cost, grounding, and prompt injection — plus building prompts as versioned, testable Go text/template templates you treat like code.

Pratik Dhanave · ·13 min read

Structured Output and Tool Calling

From-scratch Go for the two mechanisms that turn an LLM from a text generator into a component you can wire into real software — schema-constrained JSON and function calling — both spoken over the same OpenAI-compatible chat JSON.

Getting reliable machine-readable output from an LLM in Go: structured output (json-schema mode, decode into a typed struct, validate with a bounded retry) and tool/function calling (the full round-trip loop, decoding tool arguments, returning results tied to the call id).

Pratik Dhanave · ·11 min read

Calling an LLM from Go

Make your first model call from scratch with net/http and encoding/json — the chat/messages API shape, a typed client with a Bearer key and context timeout, robust error handling, and server-sent-event streaming — no framework required.

Make your first model call from scratch with net/http and encoding/json — the chat/messages API shape, a typed client with a Bearer key and context timeout, robust error handling, and server-sent-event streaming.

Pratik Dhanave · ·12 min read

Tokens and Tokenization

The unit a language model actually reads is neither a word nor a character — it is a token, and once you see the world the way the model does, half of its strange behavior stops being strange.

The unit a language model actually reads is neither a word nor a character but a token. How byte-pair encoding builds a vocabulary, why tokenization explains half of an LLM's strange behavior, and how to count tokens exactly in Go.

Pratik Dhanave · ·12 min read

How LLMs Work, Enough to Build With Them

The working mental model an AI engineer needs — next-token prediction, attention, training, and sampling — without the transformer math, and with every fact tied back to a decision you make in code.

The working mental model an AI engineer needs — next-token prediction, attention at an intuition level, pretraining vs post-training, and sampling — with every fact tied back to a concrete decision you make in code.

Pratik Dhanave · ·12 min read

What AI Engineering Is

The opener to a from-scratch series on building applications on top of foundation models in Go — what AI engineering actually is, how it differs from traditional ML and from ordinary software, and why Go is a serious language for the systems around the model.

The opener to a from-scratch AI-engineering-in-Go series: what AI engineering actually is, how building on foundation models differs from traditional ML and from ordinary software, and why Go is a serious language for the systems around the model.

Pratik Dhanave · ·7 min read

Human-in-the-Loop: An Approval Gate on Durable State

Lesson 7 of Harness Engineering in Go — a sensitive action pauses for a human decision, and the whole suspension is nothing more than a Lesson 2 checkpoint marked awaiting_approval.

Series finale, Lesson 7: a sensitive action pauses for human approval, where suspension is just a Lesson 2 checkpoint marked awaiting_approval, the deadline is checked first so a late yes is void, and the action must be idempotent.

Pratik Dhanave · ·7 min read

Hierarchical Supervision: Bounded Fan-Out, Ordered Fan-In, Fault Isolation

Lesson 6 of Harness Engineering in Go — a supervisor splits a task, fans out to concurrent workers behind a semaphore, and fans the results back in decomposition order, with each worker's failure (or panic) isolated to one result.

Lesson 6: bounded fan-out behind a semaphore, ordered fan-in via a pre-sized results slice, and per-worker fault isolation so one sub-agent panicking becomes one failed result instead of crashing the whole run.

Pratik Dhanave · ·7 min read

Orchestration and Handoff: Routing Intent to a Specialist

Lesson 5 of Harness Engineering in Go — a triage step that first-matches a keyword and hands the request to a specialist, and the exact place a substring table stops being able to think.

Lesson 5: a triage router first-matches a keyword to hand intent to a specialist, and the exact point a substring table stops being able to think.

Pratik Dhanave · ·6 min read

Advanced Memory: Threads, Keyword Retrieval, and Lossy Summarization

Lesson 4 of Harness Engineering in Go — three collaborating stores (a thread, a knowledge index, and a summarizer) behind interfaces, and an honest accounting of where each local stand-in leaks.

Lesson 4: memory is three stores, not one — an append-only thread, a keyword knowledge index, and a lossy first-and-last summarizer — and an honest account of where each local stand-in leaks against Azure.

Pratik Dhanave · ·7 min read

Secure Sandboxing: Running Agent-Written Code Behind a Timeout

Lesson 3 of Harness Engineering in Go — how a context deadline and `exec.CommandContext` reap a runaway snippet, why the two-shaped `Result` distinguishes a timeout from a failure, and the leak that makes a local subprocess a teaching tool, not a security boundary.

Lesson 3: run agent-written code behind a hard timeout with exec.CommandContext, distinguish OK from TimedOut, and face the leak — a subprocess is not a security boundary.

Pratik Dhanave · ·5 min read

Agent Config: Defining an ADK Agent in YAML, No Code Required

How ADK's config loader turns a declarative YAML file into a fully-built agent — and why treating an agent as data changes who gets to edit it.

Defining an agent declaratively in YAML and loading it via from_config — the loader reads, resolves, and validates the config into a built agent, so config-as-data works without writing code.

Pratik Dhanave · ·9 min read

Durable Execution: Checkpoint Every Step, Resume After a Crash

Lesson 2 of Harness Engineering in Go — a workflow that saves its progress after each step and picks up exactly where it died, proven by a test that kills a real subprocess mid-run.

Lesson 2: a workflow that checkpoints after every step and resumes from the last one after a crash, why at-least-once execution forces idempotent steps, and the atomic-rename store that survives a killed process.

Pratik Dhanave · ·5 min read

Context Caching in ADK: Stop Paying for the Same Tokens Every Turn

How caching a large, stable prompt prefix cuts latency and cost — and the ADK config that decides when it pays off.

Context caching cuts latency and cost by caching large, stable context — system prompt, reference docs, tool definitions — so repeated calls don't re-send and re-process the same tokens.

Pratik Dhanave · ·7 min read

The Agent Harness: guardrails as middleware around the model

Lesson 1 of Harness Engineering in Go — why the input guardrail is a hard block, not a warning, and how a plain `net/http` handler wraps the model call so it tests without a running server.

Lesson 1: why the input guardrail is a hard block rather than flag-and-pass, why it counts runes instead of bytes, and how a plain net/http handler wraps the (stubbed) model call so it tests with httptest.

Pratik Dhanave · ·5 min read

Planners & Thinking: Making an ADK Agent Reason Before It Acts

Post 23 of 26 in "Google ADK, Concept by Concept" — how a planner turns one-shot answers into inspectable plan-then-act reasoning.

Structuring an agent's reasoning: planners that make the model plan-then-act (ReAct-style), the built-in thinking feature, and how a planner improves multi-step tool use over naive prompting.

Pratik Dhanave · ·6 min read

Harness Engineering in Go: build the harness, then let Azure supply it

Seven patterns that turn a bare model call into production agent infrastructure — each written first as offline Go behind an interface, so the leap to Azure is a swap, not a rewrite.

Seven patterns that turn a bare model call into production agent infrastructure, each written first as offline Go behind an interface (the seam) so the leap to Azure is a swap, not a rewrite.

Pratik Dhanave · ·11 min read

context: Cancellation, Deadlines, and Values

How Go's `context` package carries a cancellation signal, a deadline, and a small bag of request-scoped values across every API and goroutine boundary in a request — and the handful of rules that keep it from leaking or lying to you.

How Go's `context` package carries a cancellation signal, a deadline, and a small bag of request-scoped values across every API and goroutine boundary in a request — and the handful of rules that keep it...

Pratik Dhanave · ·13 min read

Atomics and the Go Memory Model

What a data race actually is, why it is undefined behavior rather than "just a wrong number," the happens-before rules that make concurrent code correct, and when `sync/atomic` is the right tool — and when it quietly is not.

What a data race actually is, why it is undefined behavior rather than "just a wrong number," the happens-before rules that make concurrent code correct, and when `sync/atomic` is the right tool — and when...

Pratik Dhanave · ·3 min read

Advanced Workflows — Microsoft Agent Framework in Go

Durable workflows in Go: checkpoint and rehydrate, pause on a RequestPort for a human, nest sub-workflows, and coordinate through scoped shared state.

Durable Microsoft Agent Framework workflows in Go: checkpoint and rehydrate a fresh graph, pause on a RequestPort for a human, nest sub-workflows, and coordinate via scoped shared state.

Pratik Dhanave · ·12 min read

The sync Package

When channels are the wrong tool — a working guide to shared memory and locks in Go: Mutex, RWMutex, WaitGroup, Once, Cond, Map, Pool, and the race detector that keeps you honest.

When channels are the wrong tool — a working guide to shared memory and locks in Go: Mutex, RWMutex, WaitGroup, Once, Cond, Map, Pool, and the race detector that keeps you honest.

Pratik Dhanave · ·3 min read

Orchestration Patterns — Microsoft Agent Framework in Go

The prebuilt orchestration builders in agent-framework-go — Sequential, Concurrent, Group Chat — plus wrapping a whole workflow as one agent.

The Sequential, Concurrent, and Group Chat orchestration builders in agent-framework-go, plus wrapping a whole workflow as one nestable agent.

Pratik Dhanave · ·12 min read

Channels and select

A working guide to Go's channels — unbuffered rendezvous vs buffered capacity, send/receive/close semantics, directional types in APIs, and how `select` multiplexes, times out, and disables cases with a nil channel.

A working guide to Go's channels — unbuffered rendezvous vs buffered capacity, send/receive/close semantics, directional types in APIs, and how `select` multiplexes, times out, and disables cases with a nil...

Pratik Dhanave · ·6 min read

Grounding & RAG in ADK: Answers Anchored in Real Data

Post 18 of 26 in "Google ADK, Concept by Concept" — retrieval tools, grounding metadata, rendering citations, and the retrieve→augment→generate loop.

Grounding answers in real data: retrieval tools, grounding metadata returned with responses, rendering citations from that metadata, and the retrieve-augment-generate RAG pattern in ADK.

Pratik Dhanave · ·2 min read

Capstone · DocQA — answer questions about your own documents

The final lesson ties the whole Go tutorial into one small product: an assistant that answers questions about your docs — grounded, cited, and refusing to guess.

The capstone: a grounded DocQA agent that answers only from embedded docs via a search_docs tool, cites sources, and refuses to guess — with an optional reviewer.

Pratik Dhanave · ·11 min read

Goroutines

What a goroutine actually is, why it is cheaper than a thread, and the one rule that separates working concurrent code from a program that quietly leaks itself to death: every goroutine you start must have a way to stop.

What a goroutine actually is, why it is cheaper than a thread, and the one rule that separates working concurrent code from a program that quietly leaks itself to death: every goroutine you start must have...

Pratik Dhanave · ·3 min read

Workflow Mechanics — Microsoft Agent Framework in Go

The graph model underneath every multi-agent app: executors as nodes, edges as data flow, and typed events streaming out of `WatchStream` as it runs.

The Microsoft Agent Framework workflow model in Go: executors bound to IDs, AddEdge wiring, WithOutputFrom, and typed WatchStream events - plus an upstream route-builder fix.

Pratik Dhanave · ·11 min read

panic, recover, and defer's Role

Go handles ordinary failure with values, not exceptions — so what are panic and recover actually for? A working guide to how panic unwinds the stack through your defers, why recover only fires inside a deferred function, and the narrow set of places where catching a panic is the right call rather than a code smell.

Go handles ordinary failure with values, not exceptions — so what are panic and recover actually for? A working guide to how panic unwinds the stack through your defers, why recover only fires inside a...

Pratik Dhanave · ·3 min read

Observability, Safety, and Providers — Microsoft Agent Framework in Go

Wrap every run in an OpenTelemetry span, gate risky tool actions behind a permission handler, and swap model providers behind one agent.Agent.

Wrap every Microsoft Agent Framework run in an OpenTelemetry span, gate risky tool actions behind a permission handler, and swap Anthropic, OpenAI, Gemini, Copilot, and Azure behind one agent.

Pratik Dhanave · ·13 min read

Errors, Wrapping, and errors.Is / errors.As

Go treats errors as ordinary values, not exceptions — which means everything you know about passing, comparing, and inspecting values applies. This is a working guide to sentinel errors, wrapping with %w, and the two verbs that make error chains navigable: errors.Is and errors.As.

Go treats errors as ordinary values, not exceptions — which means everything you know about passing, comparing, and inspecting values applies. This is a working guide to sentinel errors, wrapping with %w,...

Pratik Dhanave · ·5 min read

Observability in ADK: Seeing Inside a Running Agent

How OpenTelemetry traces, structured logs, and token metrics turn an agent's event stream into something you can debug in production.

Seeing inside a running agent: OpenTelemetry tracing with spans for agent, model, and tool steps, structured logging, and exporting traces to debug latency and tool-call trajectories.

Pratik Dhanave · ·11 min read

Generics: Type Parameters and Constraints

How type parameters and constraints actually work in Go 1.18+ — writing functions and data structures that are type-safe across many types, when the compiler can infer type arguments for you, and the harder question of when a plain interface is still the better tool.

How type parameters and constraints actually work in Go 1.18+ — writing functions and data structures that are type-safe across many types, when the compiler can infer type arguments for you, and the harder...

Pratik Dhanave · ·6 min read

Deploying an ADK Agent: One Command to Cloud Run and Agent Engine

How `adk deploy` builds, pushes, and ships an agent in a single step — and the ack-after-invocation rule that keeps event-driven agents reliable.

Deploying an agent: adk deploy with its cloud_run and agent_engine subcommands, containerizing the app, and reliability rules like ack-after-invocation so failures are redelivered, not dropped.

Pratik Dhanave · ·11 min read

Type Assertions, Type Switches, and Interface Internals

How Go recovers a concrete type from an interface value, why the comma-ok form exists, and the two-word memory layout that explains the single most surprising bug in the language — the non-nil interface holding a nil pointer.

How Go recovers a concrete type from an interface value, why the comma-ok form exists, and the two-word memory layout that explains the single most surprising bug in the language — the non-nil interface...

Pratik Dhanave · ·3 min read

Conversation and Memory — Microsoft Agent Framework in Go

A Session threads history into each run; a ContextProvider carries memory across sessions — and because a Session is JSON, both survive a process restart.

A Session threads history into each run and a ContextProvider carries memory across sessions. Because a Session is JSON, both survive a process restart.

Pratik Dhanave · ·13 min read

Interfaces

How Go turns "what a value can do" into a first-class type — with implicit satisfaction, small contracts, the consumer-defined-interface rule, and the typed-nil trap that catches everyone once.

How Go turns "what a value can do" into a first-class type — with implicit satisfaction, small contracts, the consumer-defined-interface rule, and the typed-nil trap that catches everyone once.

Pratik Dhanave · ·12 min read

Methods and Receivers

How Go attaches behavior to types without classes — the receiver, the value-versus-pointer decision, method sets and what they mean for interfaces, and the addressability rules that trip people up when a value lives in a map.

How Go attaches behavior to types without classes — the receiver, the value-versus-pointer decision, method sets and what they mean for interfaces, and the addressability rules that trip people up when a...

Pratik Dhanave · ·5 min read

Runtime & Events in ADK: The Runner, the Invocation, and the Event Stream

How an agent actually runs — a Runner drives an invocation and hands you back a stream of events, not a single answer.

How ADK runs an agent: the Runner drives an invocation that yields a stream of Event objects — content, tool calls, state deltas, control signals. The event loop explains streaming, callbacks, and state.

Pratik Dhanave · ·13 min read

Structs, Embedding, and Tags

How Go builds aggregate types from value semantics up — why a struct is a copy, when it stops being comparable, what embedding actually promotes (and what it deliberately doesn't), and how a backtick string in a field definition ends up steering `encoding/json`.

How Go builds aggregate types from value semantics up — why a struct is a copy, when it stops being comparable, what embedding actually promotes (and what it deliberately doesn't), and how a backtick string...

Pratik Dhanave · ·13 min read

Maps

How Go's built-in hash table really behaves — reference semantics, the nil-write panic, comma-ok, randomized iteration, why `&m[k]` is illegal, and the presizing and concurrency rules that separate correct map code from the code that bites you at 2 a.m.

How Go's built-in hash table really behaves — reference semantics, the nil-write panic, comma-ok, randomized iteration, why `&m[k]` is illegal, and the presizing and concurrency rules that separate correct...

Pratik Dhanave · ·5 min read

Context in ADK: The Objects Passed Into Your Tools and Callbacks

ReadonlyContext, CallbackContext, ToolContext, InvocationContext — and why the read-only vs mutable distinction is a feature, not a limitation.

The context objects ADK passes into tools and callbacks — InvocationContext, ToolContext, CallbackContext, ReadonlyContext — what each exposes and why the read-only vs mutable split matters.

Pratik Dhanave · ·12 min read

Arrays and Slices

Why an array is a value and a slice is a view — the three-word header, how `append` really grows, the aliasing trap that silently corrupts data, and the small habits (three-index slices, `copy`, pre-sizing) that keep it from biting you.

Why an array is a value and a slice is a view — the three-word header, how `append` really grows, the aliasing trap that silently corrupts data, and the small habits (three-index slices, `copy`, pre-sizing)...

Pratik Dhanave · ·5 min read

Artifacts: Where ADK Agents Put Their Files

Session state is for small text and JSON. When your agent produces a PNG, a PDF, or a WAV, it belongs in the artifact store — binary-native, versioned, and out of the session record.

Artifacts are binary/file data agents produce or consume: ArtifactService saves and versions named artifacts, loaded and saved via context, keeping large blobs out of session state.

Pratik Dhanave · ·12 min read

Strings, Runes, Bytes, and UTF-8

What a Go string actually is under the hood — an immutable read-only slice of bytes, not a sequence of characters — and how bytes, runes, and code points relate, so you stop shipping the classic multibyte bugs.

What a Go string actually is under the hood — an immutable read-only slice of bytes, not a sequence of characters — and how bytes, runes, and code points relate, so you stop shipping the classic multibyte bugs.

Pratik Dhanave · ·11 min read

Pointers and Addressability

What a Go pointer actually is, why there's no pointer arithmetic, `new(T)` versus `&T{}`, the addressability rules that decide what `&` will even compile against, and when reaching for a pointer helps versus when it just adds indirection and GC pressure.

What a Go pointer actually is, why there's no pointer arithmetic, `new(T)` versus `&T{}`, the addressability rules that decide what `&` will even compile against, and when reaching for a pointer helps...

Pratik Dhanave · ·5 min read

Sessions & State in ADK: The Memory Inside a Conversation

A `Session` is the conversation; `state` is the key-value bag agents and tools read and write — and the prefix on a key decides how long it lives.

A Session holds a conversation; state is a scoped key-value store (session/user/app/temp) read and written by tools, injected into instructions via {state} templating, and persisted by SessionService.

Pratik Dhanave · ·12 min read

Functions, Closures, and Variadics

How Go treats functions as ordinary values — and what that buys you: the (result, error) idiom, variadic APIs, closures over shared state, and the decorator/middleware/option patterns that fall out of passing functions around.

How Go treats functions as ordinary values — and what that buys you: the (result, error) idiom, variadic APIs, closures over shared state, and the decorator/middleware/option patterns that fall out of...

Pratik Dhanave · ·5 min read

Tools in ADK: Turning Functions into Agent Capabilities

How a plain function becomes a callable tool, how ToolContext reaches session state, and how long-running tools pause a run for a human.

Tools give agents capabilities: a plain function becomes a tool with its signature as the schema, plus ToolContext, built-in tools, and long-running/human-in-the-loop tools across Python and Go.

Pratik Dhanave · ·12 min read

Control Flow and defer

Go's control flow is deliberately small — one loop keyword, a switch that doesn't fall through, an `if` that can scope its own variable — and then there's `defer`, the one construct that repays close reading. A tour of the whole surface, with the sharp edges labelled.

Go's control flow is deliberately small — one loop keyword, a switch that doesn't fall through, an `if` that can scope its own variable — and then there's `defer`, the one construct that repays close...

Pratik Dhanave · ·5 min read

Multi-Agent Systems in ADK: Coordinators, sub_agents, and LLM-Driven Delegation

How one agent routes work to specialists — and why the description field is the most important string you write.

Agent hierarchies and LLM-driven delegation: sub_agents, how the description field drives auto-transfer, and coordinator/dispatcher patterns — contrasted with deterministic workflow agents.

Pratik Dhanave · ·12 min read

Variables, Constants, and iota

How Go's declaration forms, scope rules, and its unusual constant system fit together — including the untyped-constant model that makes numeric literals feel effortless, and the `iota` patterns that turn enums and bit-flags into a few tidy lines.

How Go's declaration forms, scope rules, and its unusual constant system fit together — including the untyped-constant model that makes numeric literals feel effortless, and the `iota` patterns that turn...

Pratik Dhanave · ·10 min read

Types, Values, and Zero Values

How Go's type system actually behaves — predeclared types, the zero-value guarantee that removes a whole class of null bugs, the "no implicit conversions" rule and why it exists, and the difference between a named type and a mere alias.

How Go's type system actually behaves — predeclared types, the zero-value guarantee that removes a whole class of null bugs, the "no implicit conversions" rule and why it exists, and the difference between...

Pratik Dhanave · ·2 min read

06 · Mixed Workflow — Agents *and* Executors in One Graph

This lesson teaches how deterministic function executors and agent-backed executors compose in one graph with the same `AddEdge` wiring.

One workflow that mixes deterministic executors with two Foundry agent nodes for jailbreak detection and response, joined by the same AddEdge wiring and TurnToken triggering.

Pratik Dhanave · ·2 min read

04 · Multi-Model Service (a sequential agent workflow)

This lesson teaches how to chain three role-specialised agents — researcher → fact_checker → reporter — into one sequential workflow and stream each stage.

A sequential workflow of three role-specialised Foundry agents — researcher, fact_checker, reporter — built with NewSequentialWorkflowBuilder and streamed stage by stage.

Pratik Dhanave · ·2 min read

03 · Agent Workflow Patterns (sequential · concurrent · group chat)

This lesson teaches that orchestration is a property of the workflow, not the agents — the same three agents drop into three different built-in graph shapes.

The same three agents dropped into three built-in agentworkflow builders — sequential, concurrent, and round-robin group chat — showing orchestration is a property of the graph, not the agents.

All posts on this site are written by Pratik Dhanave, an Agentic AI Architect with 7+ years building production distributed systems, multi-agent AI platforms, and cloud-native infrastructure. About the author → Each article includes working code, architecture diagrams, and references to the specific frameworks and standards discussed. Browse all posts or explore related topics using the tag cloud above.