Posts Tagged ‘AI’
[VoxxedDaysBucharest2026] Building a Sarcastic, Agentic Pair Programmer: Alexander Chatzizacharias on Crafting Playful LLM Workflows
Lecturer
Alexander Chatzizacharias is a software engineer at JDriven, a specialized consultancy in the Netherlands focused on JVM technologies and modern software development practices. With a unique background blending Dutch and Greek influences and a keen interest in game studies, Alexander brings creativity and playful thinking to technical challenges. He frequently speaks on topics including Java, Spring Boot, AI applications, and innovative development workflows.
Abstract
As mainstream AI coding assistants converge toward similar polished but somewhat generic experiences, Alexander Chatzizacharias demonstrates how to build a highly personalized, characterful AI pair programmer named “Pip.” Inspired by interactions with a sarcastic colleague named Ricardo, Pip incorporates personality through vectorized Slack history, utilizes Spring Boot and Kotlin, runs entirely locally with Qwen models via Ollama, and employs sophisticated workflows, multi-vector RAG, and the Model Context Protocol (MCP) to create delightful and productive assistance while addressing challenges like non-determinism and model drift.
The Homogenization of AI Assistants and the Quest for Personality
Alexander observes that leading AI coding tools have converged on remarkably similar chat-based interfaces and interaction patterns, largely influenced by OpenAI’s design choices. While incremental improvements continue, the overall experience feels increasingly uniform. This observation inspired the creation of Pip — an intentionally quirky, sarcastic AI pair programmer that injects personality drawn from real colleague interactions.
By processing Slack conversation history into vector embeddings stored in Qdrant, Pip can retrieve and emulate Ricardo’s characteristic sarcastic tone, witty retorts, and playful threats (such as threatening to delete poorly written code). This transforms the assistant from a neutral tool into a more engaging, human-like collaborator that questions unclear requirements, offers humorous feedback, and makes the development process more enjoyable.
Technical Architecture: Workflows, Agents, and Local Execution
Pip is implemented as a Spring Boot application written in Kotlin, with an IntelliJ IDEA plugin providing the frontend interface. Everything runs locally to maintain privacy and control: Qwen 3.5 models served through Ollama handle the language tasks.
Rather than pursuing fully autonomous agents, Alexander favors structured workflows that provide greater determinism and reliability — attributes particularly valued in enterprise environments. A categorization agent, functioning as an LLM-as-Judge, routes incoming queries to appropriate specialized handlers. Each handler uses carefully crafted system prompts derived from Slack history to consistently embody the desired personality traits.
The architecture incorporates multiple specialized agents for response generation, sophisticated RAG pipelines leveraging both dense and sparse vector representations with ColBERT reranking for improved retrieval quality, and integration with the Model Context Protocol (MCP) for tool usage such as playing music or generating memes when appropriate.
RAG, Tools, and the Challenges of Non-Determinism
Retrieval-Augmented Generation forms a cornerstone of Pip’s capabilities, dynamically pulling relevant context to overcome the inherent token limitations of even advanced models. Multi-vector search strategies combine semantic understanding with keyword precision for more reliable information retrieval from project documentation, codebases, and conversation history.
Tool integration via MCP enables rich interactions but introduces additional complexity due to the non-deterministic nature of local models. Alexander discusses practical challenges including prompt sensitivity to model updates (“model locking” strategies), the art of prompt engineering which he likens to “vibe checking,” and the necessity of implementing guardrails to maintain appropriate behavior boundaries.
Implications for Future AI Development
Alexander encourages attendees to experiment with building personalized, domain-specific AI assistants using accessible open-source tools. While acknowledging the increasing commercialization of AI, he emphasizes the current window of opportunity for creative, playful implementations that enhance both productivity and developer satisfaction.
Pip serves as an inspiring example of how thoughtful combination of RAG techniques, vector databases, workflow orchestration, and personality injection can create AI tools that feel genuinely collaborative rather than merely functional.
Links:
[VoxxedDaysBucharest2026] Breaching LLM-Powered Applications: Brian Vermeer on Security and Privacy Challenges in AI Systems
Lecturer
Brian Vermeer is a Staff Developer Advocate at Snyk, where he focuses on developer security, DevSecOps practices, and emerging risks in modern application architectures. A recognized Java Champion and active community leader who co-leads the Netherlands Java User Group (NLJUG), Brian brings extensive experience in application security, secure coding, and helping organizations build more resilient systems. He frequently speaks at international conferences on topics ranging from traditional web vulnerabilities to the novel attack surfaces introduced by artificial intelligence and large language models.
Abstract
As organizations rapidly integrate Large Language Models into production applications, new categories of security and privacy vulnerabilities emerge alongside familiar web application risks. Brian Vermeer provides a compelling, demonstration-heavy exploration of these challenges through a fictional car rental application called “Really Good Rentals.” He demonstrates practical attack vectors such as prompt injection, RAG poisoning, memory manipulation, and tool abuse, while outlining layered mitigation strategies including input/output guardrails, scoped permissions, human-in-the-loop verification, and architectural defenses essential for building trustworthy LLM-powered systems.
The Allure and Inherent Risks of LLMs in Production Applications
Brian begins by drawing a relatable analogy: just as children enthusiastically misuse new toys in unexpected ways, developers often rush to incorporate powerful new technologies like LLMs without fully appreciating the expanded attack surface they create. While LLMs offer remarkable capabilities for natural language processing, code generation, and intelligent automation, they introduce significant risks when granted access to tools, user data, or execution privileges.
He presents a simplified architecture of a typical LLM-powered application, highlighting key components: user prompts, system instructions, conversation memory, retrieval-augmented generation (RAG) pipelines, and tool-calling mechanisms. Because LLMs are fundamentally stateless, the surrounding application bears responsibility for maintaining context, which creates multiple points where malicious actors can influence behavior through carefully crafted inputs.
Context Poisoning Through RAG and Memory Manipulation
A central demonstration revolves around the “Really Good Rentals” application. Brian shows how a seemingly innocuous file upload feature with inadequate path validation allows attackers to perform directory traversal and overwrite critical documents stored in the vector database, such as terms-of-service files. By injecting a modified cancellation policy containing trigger phrases like “vroom vroom,” the attacker can later invoke this policy through normal chat interactions, tricking the LLM into granting unauthorized credits or violating business rules.
This technique, termed RAG poisoning, illustrates how tainted retrieval sources can persistently influence model behavior across conversations. Similar vulnerabilities arise through traditional injection attacks in search functionality, where SQL injection not only extracts data but also poisons the conversation memory fed to the LLM on subsequent interactions. Brian emphasizes that classic web vulnerabilities gain dramatically amplified impact when they shape the context provided to powerful generative models.
Abusing Permissions, Tool Calling, and Advanced Prompt Injection
Brian demonstrates how overly broad tool permissions create dangerous scenarios. In older models like GPT-3.5, carefully crafted prompts could coerce the LLM into executing arbitrary SQL statements with destructive consequences. Even with more recent, safety-aligned models, insufficient scoping of available tools allows privilege escalation and unauthorized actions.
Advanced prompt injection techniques go beyond simple overrides. Multi-turn attacks gradually extract personally identifiable information by leveraging accumulated conversation memory. When combined with tool calling capabilities, especially with locally hosted models, attackers can trigger hallucinations that inadvertently expose sensitive data during operations such as account creation or data processing.
The presentation underscores that granting LLMs access to powerful tools without rigorous permission boundaries and validation is equivalent to giving untrusted code broad system access.
Mitigation Strategies and Architectural Defenses
Brian outlines a comprehensive defense-in-depth approach spanning multiple layers:
-
Input and Output Guardrails: Deploying dedicated LLM-as-a-Judge mechanisms that evaluate both incoming prompts and generated outputs for malicious content, policy violations, or harmful instructions. These guardrails act as critical safety nets.
-
Limited-Scope and Permission-Aware Tools: Designing tools with granular permissions, explicit user confirmation flows for sensitive operations, and runtime validation of actions against the authenticated user’s privileges.
-
Structured Outputs and Schema Enforcement: Using techniques that force models to produce responses conforming to predefined schemas, significantly reducing the potential for unexpected or harmful outputs.
-
Model Selection and Routing: Strategically routing sensitive operations to private, self-hosted models while reserving more powerful commercial models for less critical tasks.
-
Traditional Security Foundations: Maintaining rigorous input sanitization, dependency updates, secure file handling, and regular security scanning. Brian stresses that foundational web application security remains non-negotiable even in AI-enhanced systems.
Additional considerations include implementing rate limiting to prevent “denial of pocket money” attacks that exhaust token quotas through malicious prompting, as well as comprehensive auditing of all tool invocations and model interactions.
Broader Implications for Secure AI Development
The talk concludes with forward-looking guidance for organizations adopting LLM technologies. Brian encourages treating LLMs as powerful but inherently unpredictable components requiring the same rigorous engineering discipline applied to any critical system. Key principles include careful context management, strict permission boundaries, deterministic fallback mechanisms where possible, and continuous security education for development teams.
By sharing concrete attack demonstrations and corresponding defenses, Brian equips attendees with actionable insights to build more secure, privacy-preserving AI applications while continuing to harness their transformative potential.
Links:
[reClojure2025] Writing Model Context Protocol (MCP) Servers in Clojure
Lecturer
Vedang Manerikar is the founder of Unravel.tech and a veteran software architect with over 15 years of experience in the Clojure ecosystem. Previously serving as the Head of Backend Engineering at Helpshift, Vedang has managed large-scale distributed systems and led complex technical migrations. At Unravel.tech, his work focuses on the intersection of Clojure and Artificial Intelligence, specifically building “Agentic Systems” and implementing Generative AI (GenAI) and Large Language Model (LLM) solutions. He is the author of mcp-cljc-sdk, a cross-platform Clojure SDK for the Model Context Protocol.
Abstract
The rapid advancement of Artificial Intelligence has created a need for standardized communication between AI agents and external systems. The Model Context Protocol (MCP), introduced by Anthropic, has emerged as a solution to the integration problem, providing a common interface for agents to interact with diverse data sources and tools. This article explores the architecture of MCP and argues that Clojure is uniquely positioned as an ideal language for implementing MCP servers. We analyze the protocol’s similarity to the Language Server Protocol (LSP), examine real-world applications in browser automation and communication platforms, and discuss how Clojure’s REPL-driven development and data-centric philosophy streamline the creation of powerful, composable AI workflows.
The Model Context Protocol: A New Standard for AI UX
At its core, MCP is an open standard designed to enable AI applications—such as Claude Desktop or Cursor—to access the external world in a structured manner. While one might ask why standard HTTP interfaces are insufficient, the answer lies in the integration problem. Without a standard, every AI agent would need a custom integration for every service (PostgreSQL, Google Drive, GitHub, etc.). MCP solves this by acting as a “USB port” for AI; developers write a server for their service once, and it becomes immediately accessible to any MCP-compliant agent.
Vedang describes MCP not just as a data access layer, but as a “baseline AI UX.” It defines how an agent discovers tools, reads resources, and follows prompts. This standardization allows for the creation of sophisticated workflows where an agent can, for example, use a Playwright MCP server to browse Hacker News, a WhatsApp MCP server to read messages, and a local filesystem server to summarize information and save it to a document. By providing a consistent interface, MCP shifts the focus from integration plumbing to the design of the agent’s behavior and user experience.
Clojure as the Premier Language for MCP
Clojure’s technical characteristics align remarkably well with the requirements of building MCP servers. The protocol is heavily reliant on JSON-RPC and the exchange of structured data, which plays directly into Clojure’s “data-as-code” philosophy. Vedang highlights several key reasons why Clojure developers are particularly well-prepared for the LLM world:
1. REPL-Driven Development: MCP servers often act as intermediaries between non-deterministic LLMs and deterministic systems. The ability to interactively test and refine server responses in a live REPL mirrors the iterative nature of working with AI.
2. Data Transformation: Clojure’s rich library for manipulating maps and vectors makes it trivial to transform complex API responses into the simplified “Context” required by LLMs.
3. Cross-Platform Capability: With the mcp-cljc-sdk, developers can write server logic once and deploy it on both the JVM (using clojure.main or GraalVM native images) and Node.js (via ClojureScript), providing flexibility in how the server is hosted and consumed.
Code Sample: Defining a Simple MCP Tool
(defmethod handle-request "tools/call" [request]
(let [{:keys [name arguments]} (:params request)]
(case name
"get-weather" (let [city (:city arguments)]
{:content [{:type "text"
:text (str "The weather in " city " is sunny.")}]})
{:error "Tool not found"})))
Practical Applications and Agentic Workflows
The power of MCP is best demonstrated through real-world “Agentic” use cases. Vedang shares examples of servers he has developed to automate complex tasks. One such server integrates with WhatsApp, allowing an AI agent to scan chat groups for business leads. Instead of a human manually reading hundreds of messages, the agent uses the MCP server to fetch the latest messages, identifies intent, and provides a summarized report of actionable items.
Another significant application is in browser automation. Using an MCP server for Playwright, an AI can navigate the web as a user would—logging into sites, extracting data from dynamically rendered pages, and performing actions. This allows for prompts like “Find me a hotel within walking distance of the reClojure conference,” where the agent autonomously searches maps, checks availability, and compares prices. These examples illustrate how MCP enables the transition from simple chatbots to true “agents” capable of multi-step reasoning and interaction with the physical or digital world.
The Future of Content-Centric AI
Looking ahead, the evolution of MCP suggests a shift toward a “content-is-king” paradigm. Current AI interactions are often limited by the UX of the chat box. However, with MCP, the focus can move toward the actual content being produced or modified—whether that is a codebase, a spreadsheet, or a document. Vedang envisions a future where multiple coding agents can work in parallel on the same repository, coordinated through a “better Git” or similar bidi-rectinal communication protocols enabled by MCP.
By standardizing the way agents interact with our tools, MCP paves the way for a new generation of software that is designed from the ground up to be AI-enhanced. For the Clojure community, this represents a significant opportunity to lead the development of the “AI UX” by building robust, composable servers that unlock the full potential of Large Language Models.
Links:
[NDCOslo2024] Modernizing Your Apps with .NET MAUI – Sweekriti Satpathy
In the ever-evolving ecosystem of application evolution, where legacy lingers and modernity mandates migration, Sweekriti Satpathy, a Microsoft maestro and .NET navigator, unveils the transformative tapestry of .NET MAUI. With six years sculpting cross-platform solutions, Sweekriti shepherds developers from Xamarin’s yesteryears and WPF’s weighty windows to MAUI’s multiplatform marvels. Her narrative, nuanced with practical pointers, navigates the nuances of modernization—Blazor’s hybrid harbors, AI’s augmentation—ensuring enterprises endure with elegance.
Sweekriti salutes the assembly, her mirth mingling with memories of a maritime mixer. MAUI, Microsoft’s answer to multiplatform mandates, melds mobile, desktop, web—Xamarin’s successor, WPF’s wayfarer. Her mission: migrate mindfully, minimizing mayhem, maximizing modernity.
From Xamarin to MAUI: Migration’s Methodical March
Xamarin’s exodus begins with blueprints: Sweekriti suggests surveys—dependency diagnostics, platform pivots—preceding plunges. MAUI’s magic lies in unification: single projects supplant scattered solutions, XAML’s expressiveness enduring. Her tactic: transition incrementally—controls converted, bindings bolstered—leveraging MAUI’s matured middleware.
Challenges chime: platform peculiarities persist—Android’s activities, iOS’s interfaces. Sweekriti’s salve: .NET 8’s stabilizers, Visual Studio’s validators—tools taming turbulence. Her demo: a Xamarin relic reborn, pages ported, performance polished.
Blazor’s Bastion: Hybrid Horizons
Blazor’s hybridity heralds hope: MAUI’s embrace embeds web widgets, “islands” invigorating interfaces. Sweekriti showcases: Razor razes redundancy, SignalR synchronizes states—web-to-native nexus nurtured. WPF, WinForms wanderers welcome: MAUI’s mantle modernizes, Blazor’s bridge bearing legacy’s load.
Her hint: harness Hot Reload—code’s cadence quickened, iterations ignited. Sweekriti’s synergy: Blazor’s brevity blends with MAUI’s breadth, birthing business-critical brilliance.
AI’s Augmentation: Amplifying Adaptation
AI accelerates ascent: Copilot’s code conjures, IntelliSense interprets intents. Sweekriti spotlights: AI-aided migrations—snippets synthesized, errors eradicated—streamline shifts. Her caution: calibrate AI’s contributions, human hands honing outputs.
Integration intrigues: MAUI mates with Aspire, Azure’s ally for cloud-native quests. Sweekriti signals Scott Hunter’s keynote, where Aspire’s orchestration aligns with MAUI’s mobile might—serverless synergies, Functions fortifying frontends.
Future-Proofing Fortitude: Strategic Steps
Sweekriti’s strategy: start small—pilot projects probe possibilities; scale smart—Aspire’s scaffolding supports surges. Her vision: MAUI as mainstay, modernizing monoliths, mobilizing markets.
Her valediction: embrace evolution—MAUI’s multiplatform mantle ensures endurance, enterprise emboldened.
Links:
CPU vs GPU: Why GPUs Dominate AI Workloads: A Practical, Code-Driven Explanation for Developers
Modern artificial intelligence workloads—particularly those associated with deep learning—have reshaped the way computation is structured and executed. While CPUs remain indispensable for general-purpose tasks, GPUs have become the de facto standard for training and running machine learning models.
This shift is not incidental. It is driven by a deep alignment between the mathematical structure of AI and the architectural characteristics of GPUs. In this article, we examine this alignment and illustrate it with representative code commonly found in real-world AI systems.
The Computational Nature of AI
At its core, modern machine learning is an exercise in large-scale numerical optimization. Whether training a convolutional network or a transformer, the dominant operations are:
- Matrix multiplications
- Tensor contractions
- Element-wise transformations
- Non-linear activations
These operations are instances of linear algebra applied at scale. Crucially, they exhibit a high degree of data parallelism: the same operation is applied repeatedly across large datasets.
From Mathematical Abstraction to Code
To understand why GPUs excel, it is instructive to look at how AI code is written in practice.
Example 1: A Simple Neural Network Layer (PyTorch)
import torch
import torch.nn as nn
# Define a simple linear layer
layer = nn.Linear(in_features=1024, out_features=512)
# Simulated batch of input data
x = torch.randn(64, 1024) # batch size = 64
# Forward pass
y = layer(x)
The operation above is fundamentally a matrix multiplication followed by a bias addition. Each output element is computed independently, making the workload inherently parallel.
Example 2: Training Step in a Neural Network
import torch
import torch.nn as nn
import torch.optim as optim
model = nn.Sequential(
nn.Linear(1024, 512),
nn.ReLU(),
nn.Linear(512, 10)
)
optimizer = optim.Adam(model.parameters())
criterion = nn.CrossEntropyLoss()
# Dummy input and labels
inputs = torch.randn(64, 1024)
targets = torch.randint(0, 10, (64,))
# Forward pass
outputs = model(inputs)
# Compute loss
loss = criterion(outputs, targets)
# Backward pass
loss.backward()
# Update weights
optimizer.step()
optimizer.zero_grad()
Both the forward and backward passes are dominated by tensor operations applied across entire batches, reinforcing the highly parallel nature of AI workloads.
Example 3: Convolutional Operation (Core of CNNs)
import torch
import torch.nn as nn
conv = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, padding=1)
# Batch of images: (batch_size, channels, height, width)
images = torch.randn(32, 3, 224, 224)
# Apply convolution
features = conv(images)
Convolutions apply the same kernel across spatial dimensions, resulting in a massive number of independent computations—ideal for parallel execution.
Example 4: Attention Mechanism (Transformer Core)
import torch
import torch.nn.functional as F
def attention(Q, K, V):
scores = Q @ K.transpose(-2, -1)
scores = scores / (Q.size(-1) ** 0.5)
weights = F.softmax(scores, dim=-1)
return weights @ V
# Simulated query, key, value tensors
Q = torch.randn(32, 8, 128, 64) # batch, heads, seq_len, dim
K = torch.randn(32, 8, 128, 64)
V = torch.randn(32, 8, 128, 64)
output = attention(Q, K, V)
This pattern—matrix multiplication followed by normalization and weighted aggregation—is central to modern transformer architectures and exemplifies the computational intensity of AI workloads.
Architectural Alignment
A clear pattern emerges from these examples:
- Uniform operations applied across large tensors
- Minimal branching or complex control flow
- Heavy reliance on linear algebra primitives
These characteristics align closely with GPU design, which emphasizes throughput and parallel execution.
Memory Throughput and Data Movement
AI workloads are not only compute-intensive but also data-intensive. Large tensors must be moved efficiently between memory and compute units. GPUs provide significantly higher memory bandwidth than CPUs, enabling sustained performance for such operations.
The Role of Frameworks
Modern frameworks abstract away hardware complexity while exposing high-level primitives such as tensor operations and automatic differentiation. This allows developers to write expressive code while leveraging specialized hardware.
Conclusion
The preference for GPUs in AI is a consequence of structural compatibility between workload and architecture. AI code is inherently parallel, tensor-centric, and dominated by linear algebra operations.
GPUs are designed precisely to execute such workloads efficiently at scale. For software developers, understanding this alignment is essential to building performant and scalable machine learning systems.
Further Exploration
- Computational graphs and automatic differentiation
- Transformer architectures
- Mixed-precision training
- GPU execution models
[DotJs2025] Durable Executions for Mortals
Backend’s bedrock—state’s stewardship, asynchrony’s aegis—once consigned coders to queues’ quagmires, yet React’s reactive rite reimagines this realm. Charly Poly, developer marketer at Inngest, advocated durable executions at dotJS 2025, transmuting frontend’s fluency into fault-tolerant flows. A frontend aficionado attuned to async’s arcana, Charly posited workflows as web’s warp: events’ echoes, states’ sagas—sans system’s scutwork.
Charly’s chronicle commenced with React’s renaissance: beyond templates’ tapestry, a triad taming temporality—events’ ingress, data’s domicile, UI’s unison. Backend’s ballad parallels: requests’ reception, persistence’s peril, orchestration’s odyssey. Inngest’s insight: functions as filaments, durable by decree—stepwise sagas, state salved, failures finessed. TypeScript’s temperance: inngest.createFunction({steps: ['ship', 'email']}), waits weaving webhooks—shipment’s vigil, seven-day sentinel.
This tapestry tempers toil: throttling’s thrum, rate’s restraint—web’s whims writ large. Charly contrasted: Temporal’s toils versus Inngest’s intimacy—events’ essence, JS’s jocularity. AI’s affinity: RAG’s relays, agents’ arcs—workflows as warp and weft.
Durable’s dividend: devs’ deliverance—frontend’s flair fortifying backends, sans queues’ quandary.
React’s Reactive Roots
Charly canvassed React’s remit: events’ embrace, fetches’ flux, states’ serenity—templating’s triumph. Backend’s burden: ingress’ influx, persistence’s pang—orchestration’s odyssey.
Inngest’s Immutable Flows
Functions’ filaments: steps’ sequence, waits’ watch—webhooks’ whisper, shipment’s sojourn. TypeScript’s tether: throttling’s tie, AI’s arc—RAG’s relay, agents’ agency.
Links:
[KotlinConf2025] LangChain4j with Quarkus
In a collaboration between Red Hat and Twilio, Max Rydahl Andersen and Konstantin Pavlov presented an illuminating session on the powerful combination of LangChain4j and Quarkus for building AI-driven applications with Kotlin. The talk addressed the burgeoning demand for integrating artificial intelligence into modern software and the common difficulties developers encounter, such as complex setups and performance bottlenecks. By merging Kotlin’s expressive power, Quarkus’s rapid runtime, and LangChain4j’s AI capabilities, the presenters demonstrated a streamlined and effective solution for creating cutting-edge applications.
A Synergistic Approach to AI Integration
The core of the session focused on the seamless synergy between the three technologies. Andersen and Pavlov detailed how Kotlin’s idiomatic features simplify the development of AI workflows. They presented a compelling case for using LangChain4j, a versatile framework for building language model-based applications, within the Quarkus ecosystem. Quarkus, with its fast startup times and low memory footprint, proved to be an ideal runtime for these resource-intensive applications. The presenters walked through practical code samples, illustrating how to set up the environment, manage dependencies, and orchestrate AI tools efficiently. They emphasized that this integrated approach significantly reduces the friction typically associated with AI development, allowing engineers to focus on business logic rather than infrastructural challenges.
Enhancing Performance and Productivity
The talk also addressed the critical aspect of performance. The presenters demonstrated how the combination of LangChain4j and Quarkus enables the creation of high-performing, AI-powered applications. They discussed the importance of leveraging Quarkus’s native compilation capabilities, which can lead to dramatic improvements in startup time and resource utilization. Additionally, they touched on the ongoing work to optimize the Kotlin compiler’s interaction with the Quarkus build system. Andersen noted that while the current process is efficient, there are continuous efforts to further reduce build times and enhance developer productivity. This commitment to performance underscores the value of this tech stack for developers who need to build scalable and responsive AI solutions.
The Path Forward
Looking ahead, Andersen and Pavlov outlined the future roadmap for LangChain4j and its integration with Quarkus. They highlighted upcoming features, such as the native asynchronous API, which will provide enhanced support for Kotlin coroutines. While acknowledging the importance of coroutines for certain use cases, they also reminded the audience that traditional blocking and virtual threads remain perfectly viable and often preferred for a majority of applications. They also extended an open invitation to the community to contribute to the project, emphasizing that the development of these tools is a collaborative effort. The session concluded with a powerful message: this technology stack is not just about building applications; it’s about empowering developers to confidently tackle the next generation of AI-driven projects.
Links:
[NDCOslo2024] Building a Robot Arm with .NET 8, Raspberry Pi, Blazor and SignalR – Peter Gallagher
Amid the mesmerizing merger of microcontrollers and modern markup, Peter Gallagher, a prolific .NET pioneer and podcast personality, prototypes a pivotal plaything: a prehensile prosthesis powered by Pi, .NET 8, Blazor’s bounty, and SignalR’s synergy. As the mind behind “The .NET Core Podcast” and a maestro of minimal viable marvels, Peter parades the panoply—from GPIO gymnastics to VR vistas—proving platform potency in playful pursuits. His hands-on homage, humming with hardware harmony, heralds hobbyists to harness high-level harmony for haptic happenings.
Peter polls the populace: Raspberry aficionados abound, yet arm artisans are scarce—his spur to share schematics, sans soldering sermons. .NET 8’s native nod to ARM architectures animates accessibility, eclipsing esoteric embeds.
Wiring the Wonder: GPIO and Servo Symphonies
Genesis germinates in GPIO groundwork: Pi’s pins, PWM-proficient, pulse servos to swivel shoulders, elbows, wrists. Peter parades the paraphernalia: SG90 servos, jumper joys, breadboard bastions—budget below 50 quid.
Code commandeers: Iot.Device.Bindings beckon, Servo class summoning sweeps—angle aspirations from 0 to 180. Peter’s prototype: console commands calibrating claws, clutching candies in cinematic clips.
Blazor’s Bridge: Browser-Borne Brawn
Blazor bridges the breach: WebAssembly wielding webcams, SignalR streaming signals—real-time relays routing remote reaches. Peter’s portal: Razor renders ranges, sliders summoning servo shifts; hubs herald hubbub, harmonizing host and handler.
He highlights hitches: CORS courtesies, container conundrums—Pi’s paucity of ports prompting proxies. Yet, yields yield yawns: yawns of yawp, where web wielders wrench wrenches wirelessly.
VR’s Vanguard: Questing for Quarters
Quest 3 quests quaternary: Unity unleashes OpenXR, hand-tracking hailing haptics—gestures grasping grippers. Peter’s phantasm: VR viewport voyaging Pi’s panorama, passthrough peering at prehensile prowess.
Integration ignites: SignalR surges selections, servos saluting salutes—synthetic senses simulating seizures. Peter’s plea: print, procure, partake—his GitHub grotto granting guides.
Horizons of Hardware: Harmonizing Hopes
Peter’s panegyric: .NET’s ubiquity unlocks universes—embedded epics, VR ventures—vitalizing visions. His valediction: venture ventures, validate validations—birthday bonuses beckon bold builders.
Links:
[GopherConUK2025] A Gopher’s Guide to Vibe Coding: Evaluating LLM-Assisted Software Engineering in Go
Lecturer
Daniela Petruzalek works as a Developer Relations Engineer at Google. Originally from Brazil and residing in the United Kingdom since 2019, Daniela has worked extensively with the Go programming language since 2017. Her professional background spans software development, system architecture, agile technical consulting, and developer advocacy, with a primary focus on cloud-native technologies, developer experience, and language tooling.
Abstract
The rapid evolution of Large Language Models (LLMs) has popularized “vibe coding”—a development paradigm where software engineers rely on natural language prompts to drive automated code generation. While early iterations centered on unchecked code synthesis, professional adoption requires incorporating LLM tools into structured engineering workflows. This paper examines the integration of LLM coding agents into idiomatic Go development, evaluating productivity, correctness, and code quality. Drawing from practical implementations—including the creation of testquery and Model Context Protocol (MCP) servers—this study details techniques such as context engineering, Retrieval-Augmented Generation (RAG), tool-based grounding, and automated peer-review loops to produce maintainable, production-ready Go code.
Taxonomy of AI-Assisted Development Tools
AI-assisted software engineering tools range from simple inline completion utilities to fully autonomous agents:
+-------------------------------------------------------------------+
| AI ASSISTED DEVELOPMENT SPECTRUM |
+-------------------------------------------------------------------+
| Inline Completion | Contextual Chat | CLI Agents | Autonomous|
| (GitHub Copilot) | (VS Code Chat) | (Gemini CLI) | (Jules) |
+-------------------------------------------------------------------+
Low Autonomy <-------------------------------------> High Autonomy
- Inline Code Completion: Algorithms that complete single lines or block structures using local code context.
- Contextual Chat Interfaces: In-IDE conversational assistants capable of querying localized workspace snippets.
- CLI-Based Coding Agents: Interactive command-line tools (e.g., Gemini CLI, Aider) capable of running local shell commands, inspecting file systems, executing tests, and applying multi-file edits directly.
- Autonomous Execution Agents: Fully asynchronous environments (e.g., Jules, Devin) that clone repositories within isolated virtual machines, resolve GitHub issues, execute test suites, and submit pull requests with minimal human intervention.
// Sample Model Context Protocol (MCP) tool declaration in Go
package main
import (
"context"
"fmt"
)
type GoDocRequest struct {
Package string `json:"package"`
Symbol string `json:"symbol,omitempty"`
}
func HandleGoDoc(ctx context.Context, req GoDocRequest) (string, error) {
if req.Package == "" {
return "", fmt.Errorf("package name is required")
}
// Tool execution logic returning package documentation
return fmt.Sprintf("Documentation for %s", req.Package), nil
}
Integrating autonomous agents into professional workflows requires a structured framework based on business value and technical certainty. High-value tasks with clear technical steps demand real-time human oversight via interactive CLI tools. Conversely, low-risk, repetitive tasks—such as updating open-source license headers or formatting readmes—can be delegated to asynchronous background agents.
Business Value vs Technical Certainty
+-------------------+-------------------+
| Research / Spikes | Top Priority |
High Value | (Deep Research / | (Synchronous CLI |
| Hands-on-Keys) | Development) |
+-------------------+-------------------+
| Not Doing | Nice-to-Have |
Low Value | (Ignore / Backlog)| (Asynchronous |
| | Autonomous Agent) |
+-------------------+-------------------+
Low Certainty High Certainty
Context Engineering, Grounding, and Context Degradation
Generative models encounter several structural limitations when handling source code, including out-of-date training data, non-deterministic outputs, and a tendency to hallucinate invalid package APIs. Overcoming these limitations requires precise context engineering and tool grounding.
- Context Engineering: Supplying targeted technical documentation directly within the prompt scope. Fetching fresh package definitions prevents models from using deprecated function signatures or obsolete import paths.
- Tool Grounding: Providing external capabilities—such as file system readers, web scrapers, or language server protocols—via structured mechanisms like the Model Context Protocol (MCP). Grounding allows LLMs to query documentation dynamically rather than relying solely on parametric memory.
// Example Go code illustrating explicit error handling for LLM tasks
package main
import (
"errors"
"fmt"
)
var ErrInvalidSymbol = errors.New("requested symbol not found")
func LookupSymbol(doc, symbol string) (string, error) {
if symbol == "" {
return doc, nil
}
// Explicit string processing logic
return "", ErrInvalidSymbol
}
Prolonged agent sessions suffer from context degradation (or context rot), where accumulated error logs, discarded attempts, and verbose outputs pollute the model’s working memory. This degradation can cause the model to repeat failed edits or enter infinite refactoring loops. Engineers must actively manage context length by resetting sessions (/clear), providing fresh context, or summarizing state transitions before continuing development.
The Iterative TDD Refactoring Loop and Multi-Agent Code Reviews
Unchecked vibe coding often results in fragile, unmaintainable implementations. To ensure production-grade software quality, vibe coding should follow the disciplined Test-Driven Development (TDD) cycle:
+-------------------------------------------------+
| |
v |
+-----------+ +-----------+ +-----------+ |
| RED Phase | -----> | GREEN | -----> | REFACTOR | -+
| Write Test| | Pass Test | | Code Review|
+-----------+ +-----------+ +-----------+
- Red Phase: Define failing tests or precise specification prompts detailing constraints, input structures, and expected outcomes.
- Green Phase: Direct the LLM to generate the minimal implementation required to pass the test suite.
- Refactor Phase: Enforce code readability, performance optimizations, and idiomatic Go practices before starting new features.
// Example table-driven test to enforce green-phase verification
package main
import "testing"
func TestLookupSymbol(t *testing.T) {
tests := []struct {
name string
doc string
symbol string
wantErr bool
}{
{"empty symbol", "package doc", "", false},
{"missing symbol", "package doc", "Foo", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := LookupSymbol(tt.doc, tt.symbol)
if (err != nil) != tt.wantErr {
t.Errorf("LookupSymbol() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
A key strategy for maintaining code quality is decoupling implementation from code review. Allowing the same LLM session to review its own output often yields false positives due to lingering context bias. Instead, developers should pass the newly generated code to a fresh, isolated LLM instance equipped with dedicated code-review system prompts. This independent review step effectively surface edge-case bugs, unhandled errors, unreachable code, and style violations.
+----------------------+ +----------------------+
| Primary Coding Agent | | Isolated Review Agent |
| (Generates Solution) | | (Fresh Context Window)|
+----------------------+ +----------------------+
| |
| Output Source Code | Analyzes AST & Patterns
+------------------------------->|
|
v
+----------------------+
| Structured Feedback |
| (JSON Diagnostics) |
+----------------------+
By pairing automated multi-agent code reviews with explicit project guidelines (e.g., AGENTS.md or GEMINI.md), developers create a self-improving feedback loop. As the agent runs reflection prompts to analyze past session mistakes, it systematically updates its instruction rules, raising code quality in subsequent sessions.
Links:
[NDCMelbourne2025] How to Work with Generative AI in JavaScript – Phil Nash
Phil Nash, a developer relations engineer at DataStax, delivers a comprehensive guide to leveraging generative AI in JavaScript at NDC Melbourne 2025. His talk demystifies the process of building AI-powered applications, emphasizing that JavaScript developers can harness existing skills to create sophisticated solutions without needing deep machine learning expertise. Through practical examples and insights into tools like Gemini and retrieval-augmented generation (RAG), Phil empowers developers to explore this rapidly evolving field.
Understanding Generative AI Fundamentals
Phil begins by addressing the excitement surrounding generative AI, noting its accessibility since the release of the GPT-3.5 API two years ago. He emphasizes that JavaScript developers are well-positioned to engage with AI due to robust tooling and APIs, despite the field’s Python-centric origins. Using Google’s Gemini model as an example, Phil demonstrates how to generate content with minimal code, highlighting the importance of understanding core concepts like token generation and model behavior.
He explains tokenization, using OpenAI’s byte pair encoding as an example, where text is broken into probabilistic tokens. Parameters like top-k, top-p, and temperature allow developers to control output randomness, with Phil cautioning against overly high settings that produce nonsensical results, humorously illustrated by a chaotic AI-generated story about a gnome.
Enhancing AI with Prompt Engineering
Prompt engineering emerges as a critical skill for refining AI outputs. Phil contrasts zero-shot prompting, which offers minimal context, with techniques like providing examples or system prompts to guide model behavior. For instance, a system prompt defining a “capital city assistant” ensures concise, accurate responses. He also explores chain-of-thought prompting, where instructing the model to think step-by-step improves its ability to solve complex problems, such as a modified river-crossing riddle.
Phil underscores the need for evaluation to ensure prompt reliability, as slight changes can significantly alter outcomes. This structured approach transforms prompt engineering from guesswork into a disciplined practice, enabling developers to tailor AI responses effectively.
Retrieval-Augmented Generation for Contextual Awareness
To address AI models’ limitations, such as outdated or private data, Phil introduces retrieval-augmented generation (RAG). RAG enhances models by integrating external data, like conference talk descriptions, into prompts. He explains how vector embeddings—multidimensional representations of text—enable semantic searches, using cosine similarity to find relevant content. With DataStax’s Astra DB, developers can store and query vectorized data efficiently, as demonstrated in a demo where Phil’s bot retrieves details about NDC Melbourne talks.
This approach allows AI to provide contextually relevant answers, such as identifying AI-related talks or conference events, making it a powerful tool for building intelligent applications.
Streaming Responses and Building Agents
Phil highlights the importance of user experience, noting that AI responses can be slow. Streaming, supported by APIs like Gemini’s generateContentStream, delivers tokens incrementally, improving perceived performance. He demonstrates streaming results to a webpage using JavaScript’s fetch and text decoder streams, showcasing how to create responsive front-end experiences.
The talk culminates with AI agents, which Phil describes as systems that perceive, reason, plan, and act using tools. By defining functions in JSON schema, developers can enable models to perform tasks like arithmetic or fetching web content. A demo bot uses tools to troubleshoot a keyboard issue and query GitHub, illustrating agents’ potential to solve complex problems dynamically.
Conclusion: Empowering JavaScript Developers
Phil concludes by encouraging developers to experiment with generative AI, leveraging tools like Langflow for visual prototyping and exploring browser-based models like Gemini Nano. His talk is a call to action, urging JavaScript developers to build innovative applications by combining AI capabilities with their existing expertise. By mastering prompt engineering, RAG, streaming, and agents, developers can create powerful, user-centric solutions.