今日已更新 143 条资讯 | 累计 40588 条内容
关于我们

标签:#architecture

找到 809 篇相关文章

AI 资讯

Full-Stack Architecture Patterns That Actually Survive Production

Every full-stack tutorial ends the same way: a working app, a happy demo, and zero mention of what happens six months later when your "simple" CRUD app has 40 endpoints, three types of caching, and a frontend team that's afraid to touch the API layer. This post isn't about picking a framework. It's about the architectural decisions that quietly determine whether your app is pleasant to work on in year two — or a slow-motion disaster. 1. Stop treating your API layer as an afterthought A huge number of full-stack apps start with the frontend calling the backend directly, endpoint by endpoint, with no shared contract. It works fine at 5 endpoints. At 50, nobody remembers which fields are optional, which ones changed last sprint, or why the mobile app is still sending the old shape. Two things fix this early: A single source of truth for your API contract. Whether that's OpenAPI, GraphQL SDL, or even just shared TypeScript types in a monorepo package, the goal is the same: one place where "what does this endpoint return" is answered definitively. Generated clients over hand-written fetch calls. If you're writing fetch('/api/users/' + id) by hand in more than one place, you've already created a maintenance liability. Tools like openapi-typescript-codegen or a tRPC setup remove an entire category of bugs. // Instead of this scattered everywhere: const res = await fetch ( `/api/users/ ${ id } ` ); const user = await res . json (); // type: any, hope for the best // This, generated from your contract: const user = await api . users . getById ( id ); // fully typed, autocomplete works 2. Decide where your business logic lives — before you have 30 files that disagree The classic failure mode: business logic scattered across route handlers, database triggers, frontend validation, and a couple of "utils" files nobody wants to open. Every rule ends up implemented two or three times, slightly differently. Pick one layer to own the rules. A common, boring, effective pattern: Contr

2026-09-08 原文 →
AI 资讯

Security Foundations Behind Reliable AI Systems

Originally published on WordPress on September 27, 2025. When AI systems fail in production, the failure is often blamed on data quality, model drift, or algorithmic limitations. In practice, many of the most damaging failures originate much earlier and much lower in the stack. They come from weak security foundations that allow systems to behave in unintended ways. Reliable AI is not just about accuracy or performance. It is about whether the surrounding infrastructure enforces discipline around access, data handling, and execution paths. Infrastructure as the First Line of AI Security Every AI system depends on infrastructure that controls how compute, storage, and networking are consumed. If that infrastructure is loosely governed, the AI system inherits that weakness. A common example is a shared compute environment where multiple teams run experiments. If isolation is poorly enforced, one workload can access artifacts, logs, or intermediate data from another. The model may be mathematically sound, but the environment allows behavior that violates assumptions about separation and control. From a reliability standpoint, this creates hidden coupling. An AI job might fail or behave inconsistently because another process consumed shared resources or modified shared state. From a security standpoint, the same weakness allows unauthorized access to sensitive datasets or trained models. Strong infrastructure boundaries do not just protect against attackers. They protect teams from each other and from accidental misuse. Access Control Across the AI Lifecycle AI systems have long lifecycles that include data ingestion, preprocessing, training, evaluation, deployment, and monitoring. Each stage introduces different access needs. Problems arise when a single identity or role is allowed to operate across too many of these stages. For example, an engineer might have permission to both modify training data and deploy models. That convenience can quietly undermine trust in the

2026-09-08 原文 →
AI 资讯

Networking Foundations for Modern Edge & IoT Systems

Even though networking fundamentals are often taught at the early stages of a tech career, their relevance becomes far more important when you begin working with distributed IoT and edge-driven architectures. Concepts like subnetting, routing, NAT, DNS, firewalls, and VPNs evolve from simple textbook ideas into core architectural tools that determine how devices communicate, how secure the system remains, and how reliably data moves between the edge and the cloud. This refresher looks at these fundamentals from the perspective of someone building and supporting real IoT and edge environments. The goal is not to re-teach the basics, but to reconnect them with the realities of large-scale, low-power, and cloud-connected systems. 1. Subnetting as the Backbone of IoT Network Segmentation Subnetting plays a much bigger role in IoT and edge-driven environments than most people realize. In traditional networking, subnets help organize traffic and reduce broadcast noise. In IoT, they become a core part of the system architecture. When you’re dealing with sensors, gateways, and edge compute nodes running side by side, the network must be segmented in a way that keeps each function secure and predictable. A typical LoRaWAN setup shows this clearly. The gateway LAN, the packet-forwarder network, and the edge analytics node usually sit in different subnets. This separation allows you to apply strict ACLs around what each component can communicate with, especially because IoT devices often have limited security controls of their own. Subnetting also helps manage traffic flow, ensuring that noisy sensor broadcasts don’t interfere with time-sensitive edge workloads. Beyond security, good subnet design improves fault isolation. If a node misbehaves, the impact is contained within its segment. This structure also supports multi-tenant IoT deployments, where different applications or departments share the same physical infrastructure without touching each other’s data paths. In short

2026-09-08 原文 →
AI 资讯

The descriptor survived, const did not — full-stack Rust

One skeleton, many screens argued that admin screens should be declared as typed data rather than coded, and it ended by claiming the idea was independent of the stack: draw the boundary as a one-way dependency — domains depend inward on a framework that knows nothing about them — and validate it with a zero-diff refactor of a screen you already trust. That was React and TypeScript. This is the same claim re-run in Rust, where a descriptor can be a compile-time constant and a template is a macro. Because the first result is already published, the second stack is a replication with a control rather than a fresh opinion — which is rare enough to be worth doing properly. Companion to Topcoat and the shrinking cost of full-stack Rust . That post was written from the announcement and promised a follow-up reporting where the rough edges actually show. This is it, from the pilot that followed: a small admin panel built on Topcoat 0.6.2 and Toasty 0.10.0, and the four questions that post committed to answering. The pilot is open source — a clean clone runs both screens and the test that decides the argument. That phrase, a compile-time constant , is where the title comes from, so it is worth saying now what it buys and why I wanted it. A TypeScript descriptor is an array of objects assembled when the module loads. A Rust one can be more than that: &'static , Copy , allocated never, fully checked before the program starts. Going in, that looked to me like the same idea in a stricter form — if declaring a screen as data is good, then declaring it as data the compiler can see through and verify must be better still. I treated that property as the thing worth protecting, and the pilot was partly a test of whether it could be. The stack is deliberately a young one. Topcoat is six weeks old: Tokio's team announced it on 22 July 2026, the pilot pins 0.6.2, and the project still expects breaking changes. It is not the only full-stack Rust framework — Leptos and Dioxus have been at

2026-09-07 原文 →
AI 资讯

Embedding a web UI into a native desktop application comes with a price

I thought embedding a web UI into a native desktop application would be the easy part. After all... macOS has WebKit. Linux has GTK WebKit. Windows has WebView2. One API per platform, smaller installers, native look & feel. Sounds perfect. Then reality arrived. macOS 🍎 Honestly, this was the easiest platform. System WebKit is there. It behaves consistently. No additional runtime. No installer surprises. Exactly what you'd expect from a platform component. 10/10 Linux 🐧 Things became... more interesting. GTK WebKit works, but suddenly packaging starts to matter. An AppImage built on one distribution may refuse to start on another because some required WebKitGTK library isn't available. Your application itself is perfectly fine. The user's system just doesn't happen to provide exactly the version your build expects. You quickly discover that "works on my machine" has many regional dialects. 7/10 Windows 🪟 This one surprised me the most. Unlike macOS, the web view isn't really just "there." Using WebView2 means depending on the Edge WebView runtime. If the runtime isn't installed, congratulations—you now need another installer. So your installer may install something whose purpose is to allow your application to display HTML. Not exactly the dependency story I was hoping for. 2/10 Meeting in the middle At some point I asked myself: Why am I spending time debugging operating-system packaging instead of building my application? So I tried CEF (Chromium Embedded Framework). Yes... The application becomes larger. Quite a bit larger. But in exchange: • Same rendering engine everywhere. • Same JavaScript engine everywhere. • Same debugging experience. • Same HTML/CSS behavior. • No Linux WebKit dependency lottery. • No separate WebView runtime installation on Windows. • One code path across all desktop platforms. Ironically, shipping your own browser turned out to be simpler than relying on the browser already "provided" by the operating system. It's one of those engineering

2026-09-07 原文 →
AI 资讯

The browser only talks to one server — composing Marko, React, and Riot into one hotel page

You open a hotel page. It looks like one product: a search grid, a featured stay, local highlights, reviews, a sticky trip summary. Under the hood it is eight HTTP servers and three UI runtimes . That is the experiment behind HarborStay , a demo booking app I built to answer a stubborn question: Can independent teams ship independent UI, in independent frameworks, and still give the browser a single, paint-ready HTML page? The punchline: yes — if the shell never imports a component. It only fetches HTML. The one rule The browser never talks to a fragment. It talks to the composer on port 3100 . The composer owns routes, layout, and the booking flow. Everything else is a fragment server that returns a chunk of HTML. flowchart LR Browser["Browser"] --> Composer["Composer :3100"] subgraph fragments["Fragment servers"] Nav["Navigation Marko :3101"] Search["Hotel search Marko :3102"] Details["Hotel details Marko :3103"] Reviews["Reviews Marko :3104"] Recs["Recommendations Marko :3105"] Highlights["Local highlights React :3106"] Disco["Experiences discovery Riot :3107"] Itin["Experiences itinerary Riot :3108"] end Composer --> Nav Composer --> Search Composer --> Details Composer --> Reviews Composer --> Recs Composer --> Highlights Composer --> Disco Composer --> Itin Composer --> CDN["CDN :3200"] This is the opposite of the usual microfrontend story (Module Federation, shared React, a host that import() s widgets). HarborStay is HTML composition . The shell does not know whether a fragment was rendered by Marko, React, or a hand-rolled Riot string. It only knows a URL. That one constraint buys a lot: Fragment teams can pick a runtime without asking the shell. A fragment outage becomes a fallback box, not a blank page. You can deploy search without redeploying reviews. It also forces honesty. If two fragments need to share a Redux store, the architecture is already leaking. What the user actually sees HarborStay models a small premium catalog: Harbor View Lodge in Lisbon

2026-09-07 原文 →
AI 资讯

How I Directed an AI Agent Through 3 Real Architecture Decisions, and What I Learned

In two weeks, I built Retro Dynamics Agent, an app that generates retrospective activities for teams, facilitates them on a real-time collaborative board, and turns the outcomes into Jira or Azure DevOps tickets. I built it working with an AI coding agent, Claude Code, throughout almost the entire process: design, implementation, production debugging, and documentation. I do not want to tell another “I used AI and it wrote the code for me” story. We have heard that one enough. What I found more interesting were the parts of the project where there was no obvious answer in a tutorial, and how the work was divided in those situations. I defined the constraints and made the underlying decisions. The agent proposed concrete technical solutions and implemented them. Then the responsibility for verifying that everything actually worked, not just that it compiled, came back to me. Here are three examples from the project. 1.- Connecting to Jira without server-side sessions or frontend memory I wanted any team to be able to connect its own Jira account through OAuth, instead of relying on a global token that only I could configure. The problem was that my application runs entirely on serverless functions. Nothing stays in memory between requests, and the frontend does not maintain its own state either. No localStorage. No router. An OAuth login means leaving the application, authenticating with Atlassian, and then coming back. But coming back to what, if nothing remembers which screen you were on? Before touching the code, I asked the agent to create a complete implementation plan, including the files that would need to change, the design decisions, and the scope. I reviewed that plan as if it were a pull request from another developer. I made decisions such as: For now, only Jira would use OAuth. Azure DevOps would keep its manual token flow because setting up OAuth there is considerably more involved. Tokens would be encrypted before being stored in the database, never sa

2026-09-07 原文 →
AI 资讯

The Dumb Prompt

Exact paths, exact signatures, one command - and nothing left to interpret. 👋 I'm Anton - a software engineer working mostly in PHP/Symfony and Go, currently carving a live PHP monolith into Go services. Part 2 of this series was about how small a unit of work has to get before anyone can execute it blind. This part is about the text of that unit: what I write down, and the phrases I've banned from my own writing. Notes: github.com/brilliant-almazov . Maybe this is useful to you, maybe you already do it better, maybe you read it completely differently. As before: these are my habits on one codebase, not advice for yours. Three holes in one page I once wrote a task the way I'd write it for a person sitting two desks away. It read fine. It also had three phrases in it that weren't instructions at all: instead of the contract: take the contract from the neighbouring spec instead of the values: check against the previous implementation instead of a decision already made: agree on the approach The executor fell into all three, in order. The first one sent it reading neighbouring packages, because "the neighbouring spec" is an address, and an address has to be resolved before it can be used. The second one made it pick a sample - and the sample it picked was not the one I had in mind, because I never said which one I had in mind. The third one ended the run: it came back with a clarifying question, having produced nothing. That's not a bad day and it isn't a bad executor. It's three holes in one page of text, each one dug by a phrase I wrote myself. the task I wrote what the executor did ────────────────────────────────── ───────────────────────────────── "take the contract from the ──▶ read the neighbouring packages neighbouring spec" "check against the previous ──▶ picked a sample - the wrong one implementation" "agree on the approach" ──▶ came back with a question, produced nothing The diagnosis A task is executed literally. Anything phrased as a choice becomes the exe

2026-09-07 原文 →
AI 资讯

Local Embeddings vs. API Embeddings — Why I Chose sentence-transformers

Every RAG pipeline needs to convert text into vectors. The question is where that conversion happens. You have two options: run an embedding model locally on your own hardware, or call an API that runs the model on someone else's hardware. Both work. The right choice depends on your constraints — and understanding the tradeoffs is more useful than a recommendation. This article is about why I chose local embeddings with sentence-transformers/all-MiniLM-L6-v2 for this pipeline, and when I'd switch to an API. What Embeddings Actually Do Before the tradeoffs, a quick grounding on what's happening. An embedding model takes text and converts it into a fixed-size vector of floating-point numbers — a list of 384 numbers in the case of all-MiniLM-L6-v2 . That vector encodes the semantic meaning of the text in a way that allows mathematical comparison. Two pieces of text with similar meaning produce vectors that are close together in the 384-dimensional vector space. "Authentication failed" and "login was rejected" are semantically similar — their vectors will be close. "Authentication failed" and "quarterly revenue report" are semantically distant — their vectors will be far apart. This is what makes retrieval work. When you embed a query and search for the nearest chunks, you're finding chunks that are semantically similar to the question — not just chunks that contain the same keywords. The embedding model determines the quality of this semantic matching. A better model produces vectors where semantic similarity maps more accurately to vector proximity. The Local Embedding Choice My pipeline uses sentence-transformers/all-MiniLM-L6-v2 via ChromaDB's SentenceTransformerEmbeddingFunction : from chromadb.utils.embedding_functions import SentenceTransformerEmbeddingFunction embedding_fn = SentenceTransformerEmbeddingFunction ( model_name = " sentence-transformers/all-MiniLM-L6-v2 " ) This runs entirely on your local CPU. No API key, no network request, no cost per embedding,

2026-09-07 原文 →
AI 资讯

The Founder’s Trap: Shipping Fast Without Borrowing Against Your Future

When you are building something from scratch, speed feels noble. It feels disciplined. Necessary. Mature, even. You tell yourself you are being practical. The customer does not care if the code is beautiful. The market is moving. Cash is finite. Momentum matters. So you make the trade that almost every founder makes at some point: ship now, clean up later. I understand that instinct very well because I have lived inside it. As a founder, you are not operating in the comfort of theory. You are making decisions with incomplete information, limited time, and a product that still needs to prove it deserves to exist. In that stage, a lot of engineering advice sounds suspiciously like it was written by people who have never had to get a real product out before the window closes. So yes, you move fast. You hardcode things that feel temporary. You defer cleanup. You choose the version that works over the version that would make your future self proud. You call it pragmatism, which it often is. The trouble is that pragmatism has a habit of overstaying. And that is the trap. Because some shortcuts buy you speed. Others quietly sell off your future ability to move. It took me time to really understand that distinction. Founding teaches you that speed has layers Before I started building products as a founder, speed felt simple. Ship the feature. Get the customer. Keep going. Later, I learned that there are at least two kinds of speed. The first kind gets you to launch. The second kind lets you keep moving after the launch. The first kind is exciting. It is visible. It gives you demos, momentum, first users, first revenue, first proof that you are not completely hallucinating the opportunity. The second kind is quieter. It shows up months later when the product has more customers, more complexity, and more reasons to break. It is the speed of a system that can still change safely. A team that can still ship without fear. An architecture that has not turned every roadmap discuss

2026-09-07 原文 →
开发者

Stop Calling It Technical Debt !

In every project, someone says it sooner or later: "we have too much technical debt." Everyone agrees. Nobody asks how much. One day I tried to do the math for real. I learned very little about my code, and a lot about the metaphor. The bank statement If my technical debt were a loan, it would have the same structure: At the bank In the code The principal The shortcut taken to ship on time The interest The extra cost of every new feature Repayment Refactoring Bankruptcy A full rewrite So I listed my lines: a 3,000-line service with no tests, a framework three major versions behind, billing logic copied in four places, and one module everyone avoids. Every feature costs me about 30% more time. And the principal, the amount I would need to pay to reach zero, is measured in months of work that nobody will ever give me. The verdict: I am insolvent. And yet I ship every week, and I have been shipping for years. This is where the analogy breaks. Four reasons why it is not a debt I don't know the amount. A bank debt is a number written in a contract. Technical debt has no number, it has opinions. Ask three developers to rate the same module and you get three answers. I never signed anything. You choose to take a loan. Most of my technical debt arrived on its own: a library abandoned by its author, a business rule that changed, a project I inherited. Ward Cunningham, who created the term in 1992, was talking about a loan you take on purpose, to learn faster. He then spent twenty years repeating that he never meant "badly written code." The interest does not arrive every month. You only pay for the code you touch. I have terrible files that have not cost me a single minute in three years, because nobody goes there. And I have an 80-line file, changed twice a week, that is ruining me. There is no zero balance. The refactoring I do today will be out of date in two years. I never repay anything. I just trade one debt for another one with a better rate. The word itself is a prob

2026-09-07 原文 →
AI 资讯

A running process is not a ready Minecraft server

A process supervisor can tell you that a process exists. It cannot, by itself, tell you that a Minecraft player can join. I work on ChunkCraft, a Minecraft hosting project. Here is a small state model that helps keep operational status separate from player-facing guidance. Separate three questions Is the process alive? The container or service manager owns this signal. Has the game finished starting? Startup logs or a game-level probe provide this evidence. Can this player join? Client version, edition, whitelist and network reachability still matter. A useful state model is stopped → starting → ready , with failure and unknown states represented explicitly. Avoid converting a failed probe into “stopped”: a timeout means the observation failed, not necessarily that the server died. Tie each state to a next action Observed state Useful guidance Starting Wait for world loading; show recent startup progress Ready Show the complete connection address and expected version Unreachable or unknown Show when the last successful observation happened and offer diagnostics Player rejected Read the actual join error; check version and whitelist The same principle applies to control buttons. A copy-address action is helpful when the address exists and startup has completed. Showing it as the only instruction during startup invites repeated failed joins. Do not confuse observation with proof Even a successful game-level probe does not prove every player can reach the server. Likewise, a positive player-count sample proves someone was connected at that sample time; it does not identify that person or establish uninterrupted availability. Store observation timestamps alongside values. When a collector fails, preserve historical observations but mark them stale. A freshly rendered dashboard is not evidence of fresh underlying data. A small review checklist Does every status describe an observation we actually have? Is an unknown state distinguishable from a confirmed failure? Does th

2026-09-06 原文 →
AI 资讯

99.7% Rejected in 84ms: Why I Stopped Making the Generator Smarter

I wrote a puzzle generator whose acceptance rate is 0.26% . It throws away 99.7% of everything it produces, and that is the design working as intended, not failing. Generating five valid puzzles takes 1,947 attempts and 84 milliseconds. The point is not the puzzles. The point is that the generator makes no correctness guarantee at all, and a verifier makes every one of them. Once you split those two responsibilities, "make the generator smarter" stops being the obvious optimisation — and that is exactly the position you are in when the generator is an LLM. The loop verigen is a Go CLI that produces cryptarithmetic puzzles — alphametics, the SEND + MORE = MONEY genre, where each letter stands for a distinct digit and the sum has to hold. The known answer to that one is 9567 + 1085 = 10652 . There is one rule, and everything else follows from it: The generator guarantees nothing. Every guarantee lives in the verifier. The generator throws plausible-looking letter combinations at the wall. The verifier does an exhaustive search and confirms two things: that a solution exists, and that it is unique. Anything that fails either check is discarded and the loop asks for another candidate. The loop itself knows nothing about cryptarithmetic. Implement a Domain interface and any other puzzle rides the same loop. What the log actually says Five puzzles, seed 7: ── Puzzle 2 [hard] HAIKU + BONSAI = KOKORO Answer: 96542 + 378165 = 474707 (attempts before this seed landed: 624) === generate/verify loop [alphametic] === seed=7 output=5 puzzles total attempts=1947 elapsed=84ms acceptance rate = 0.2568% (average 389 generations per puzzle) --- rejection reasons --- no unique solution 770 (39.55%) no solution 695 (35.70%) more than 10 distinct letters 477 (24.50%) ok 5 ( 0.26%) Nearly 40% of candidates have more than one valid solution. Another 36% have none. A quarter cannot possibly have one and are rejected before the search starts. Five survive. Filtering by difficulty makes it wo

2026-09-06 原文 →
AI 资讯

Replacing Myself With AI, One Cognitive Habit at a Time

I have no idea what I'm f*cking doing. Something I figured out today: I do not start with the dark version of an idea. I start with a random curiosity, chase it because it is interesting, and then somewhere in the middle I look up and go: oh. This could turn bad. And it is probably already turning bad somewhere, run by someone who never bothered to look up. That happened again this week, while I was thinking about what I want my memory system to do next. So let me walk through the curiosity, and then the exact moment it flipped. AI memory is mostly boring Useful. But boring. Most memory systems store things like: what projects you are working on what tools you use what your preferences are what decisions you already made what facts should survive between sessions I built one of these. It is called mycelium. Connections between memories get stronger when I use them and fade when I do not, so it is a little more alive than a notes file. But at the end of the day it stores what I know. So an AI plugged into it eventually learns: I use Proxmox. I prefer LXC for a lot of workloads. I am building an operating system. I like local-first systems. I am suspicious of unnecessary dependencies. Cool. Accurate. Still not the thing I actually care about. It captures what I know. It does not capture how I think. And more specifically, it does not capture how I become curious. Humans randomly wonder about shit At least I do. I will be working on something unrelated and suddenly think: Wait, why does this work like that? Then: Has anyone tried it differently? Then: Is this whole abstraction actually necessary? And three hours later there is a new project directory on my machine and I am questioning all of my life choices. An LLM can generate questions if I ask it to. That is not the same thing. What it does not have is the persistent causal chain that led me, specifically, to ask certain kinds of questions over and over. A human brain does something like: event ↓ this feels weird ↓

2026-09-06 原文 →
AI 资讯

From Prompt Engineering to AI Engineering

Why building reliable AI features requires more than better prompts A few years ago, building an AI feature often looked surprisingly simple. Write a prompt. Send some text to a model. Look at the response. Improve the prompt. Repeat. Eventually, the output gets good enough and the feature ships. That approach still works for many things. It works especially well when the task is simple, the consequences are low, and a human remains responsible for the final result. But production software introduces a different set of questions. What context should the model receive? Which data is it allowed to access? Which tools can it use? What happens when it chooses the wrong tool? How do we know a model or prompt change didn’t make the system worse? How do we debug a failure that happened only once? What happens when the model produces valid JSON containing an invalid business decision? And perhaps the most important question: How much autonomy should we give a system whose behavior is probabilistic? These are not prompt engineering questions. They are engineering questions. That is why I think we are seeing a shift from prompt engineering toward AI engineering. I don’t mean that AI engineering is a completely new discipline. Much of it comes from software engineering, MLOps, LLMOps, distributed systems, security, testing, and platform engineering. What is changing is the combination. The model has become a new kind of software component — one that can interpret, reason, generate, and increasingly act, but cannot be treated like deterministic code. That changes the engineering problem. From Prompts to Systems Prompt engineering is useful because it addresses a real problem. A model needs instructions. The way we formulate those instructions can have a significant effect on the result. But a prompt is only one part of the system. Consider a CRM application that asks an AI assistant to recommend the next action after a customer meeting. A prompt might look like this: Review the

2026-09-06 原文 →
AI 资讯

Multi-Agent Does Not Mean Parallel: Safe Workflows with Google ADK

“Let’s split it into agents” has become the AI equivalent of “let’s make it a microservice.” Sometimes the boundary is useful. Sometimes it only creates more state, more coordination, and a harder failure to explain. The most dangerous assumption is that separate agents should run in parallel. Parallelism is safe only when the branches are genuinely independent. If one branch changes the world while another is evaluating it, both agents can make locally reasonable decisions that are unsafe together. Google ADK 2.0 makes workflow topology explicit through graph-based Workflow objects. That is valuable because sequences, branches, and joins become part of the program instead of an agreement hidden in a supervisor prompt. Series note: This is Part 5 of Reliable Google AI Agents in TypeScript . The examples were checked against @google/adk 2.0.0 in September 2026. Start with the dependency, not the agent count Imagine a system preparing a hotel recommendation. It needs live inventory, company travel policy, and a final recommendation. Inventory lookup and policy evaluation can run concurrently because both observe the same request and neither changes shared state. The final decision must wait for both. Now consider a different pair of operations: one agent changes the reservation; another calculates an upgrade using the current reservation. Those branches are not independent. Running them concurrently can make the upgrade decision depend on state that no longer exists. Before drawing a parallel branch, ask: Do both operations only read the same starting state? Can either operation change data the other consumes? Can either produce an irreversible side effect? Is there a deterministic way to combine their results? What happens when one succeeds and the other times out? If those answers are unclear, parallel is an optimization you have not earned yet. Encode safe parallelism as fan-out and join ADK’s TypeScript Workflow graph can express two independent branches and a joi

2026-09-05 原文 →
AI 资讯

Batch Processing: From Unix Tools to Distributed Systems

Much of the traditional software operations we deal with are online, we click a button, wait for a moment, and the transaction or operation is completed. But there is a big area that deals with software operations that require offline processing. For example, background processing of jobs, e.g., OpenAI training/improving its existing GPT models behind the scenes using the data it gathers from its users. Batch Processing Whenever such an offline system runs a job that typically generates output from a batch of inputs, we call that batch processing. Inputs here are immutable, which avoids side effects. Benefits of batch processing: You can time travel. In case of any failure or unintentional outputs, you can jump to the last input checkpoint before a batch processing job. This handling is often referred to as human fault tolerance. Using batch processing and offline systems, compute usage efficiency can be improved. For example, whenever a heavy computation needs to be done, it's better to do it in bulk on maybe a GPU compute rather than crashing the CPU host where the server is online. Though the boundary between online and batch processing is not always clear. For example, a long-running database query could also be categorised as batch processing. Another alternative to batch processing is stream processing, which we will understand in the next article. MapReduce MapReduce is a batch processing algorithm that is utilized by Hadoop, CouchDB, and MongoDB as well. It is a balanced approach that is less extreme than completely parallelizing the jobs. There are several other frameworks like this that are now replacing MapReduce. For example, DataFrames APIs, query languages, etc. We will see MapReduce in detail sometime later. Simulating Batch Processing with Unix Tools (Single Host) If you are a Linux user, this simulation could be very easy for you to grasp. If not, just put it in ChatGPT or any AI tool to understand the command in detail if interested. A typical Ngin

2026-09-05 原文 →
AI 资讯

My AI agents don't talk to each other

I run seven agents over the same domain. They have never once sent each other a message. That was not the plan. The plan was the thing everybody builds first: a coordinator that hands work between specialists, agents that call each other, a shared conversation they all append to. It worked in the demo and it fell apart the moment the work got real. What replaced it is boring and it has held up: every agent writes claims to one shared record, and nothing else. No agent reads another agent's reasoning. No agent can call another agent. The record is the only channel. Here is why, and what it cost. What breaks in the group-chat design Three things, roughly in the order they hurt. Context grows without bound. If agents converse, every agent needs everyone else's output in its window to participate. Six specialists means each one is reading five other monologues. Your token spend goes quadratic in the number of agents and the marginal agent makes the others measurably worse. Errors laminate. Agent B reads agent A's output as input. If A was confidently wrong, B does not treat it as a claim to be weighed — it treats it as context, which is to say, as true. By the time it reaches F you have a well-reasoned conclusion resting on a hallucinated premise, and nothing in the transcript flags where the floor gave way. You cannot answer "why." Six weeks later someone asks why the system concluded X. The honest answer is "there was a conversation." That is not an answer you can act on, and it is not an answer that survives an auditor. Agents as authors, not as callers The reframe that fixed it: an agent is not a function other agents invoke. An agent is an author with a domain of authority . Each of mine owns a slice of the problem and may only make claims inside it: Agent Domain Claims it may make Verification What is true about the thing today Observed facts, source records, reconciled geometry Design What it should become Plan gaps, code compliance, takeoffs Recovery What can be

2026-09-05 原文 →
AI 资讯

Beyond Zero: Google Publishes Successor to BeyondCorp

In a recent research paper, Google introduced Beyond Zero, a “security model for the AI era” that extends Zero Trust to autonomous AI agents. The new approach moves access decisions from the application level to individual resources and actions, combining static authorization controls with dynamic AI-driven decisions to enable machine-speed enforcement for humans and agents. By Renato Losio

2026-09-05 原文 →
AI 资讯

How Enterprises Govern AI Agents: Practices That Work in Production

TL;DR Traditional API security fails with AI agents because non-deterministic agents autonomously select tools, query databases, and execute multi-step plans across enterprise systems. Production agent governance requires an infrastructure control plane that decouples policy enforcement from application code using scoped virtual keys, granular tool filtering, and runtime guardrails. Bifrost adds only 11 microseconds of latency overhead at 5,000 requests per second while enforcing spend limits, content safety, and provider routing across more than 1,000 models. Model Context Protocol (MCP) governance restricts which tools, APIs, and file systems an agent can invoke, preventing prompt injection attacks from triggering unauthorized operations. Endpoint visibility through Bifrost Edge brings local coding agents and desktop developer tools under the same centralized gateway policies enforced across the enterprise fleet. Enterprise AI agents that operate across corporate data stores, cloud infrastructure, and customer-facing interfaces introduce operational risks that static API security policies cannot mitigate. Bifrost , an open-source AI gateway developed in Go by Maxim AI, provides the runtime control plane organizations need to govern autonomous workflows. Rather than treating an agent as an anonymous script or embedding custom governance logic directly inside agent prompts, engineering teams use centralized gateways to enforce access limits, model routing, and spend controls. This guide details the architectural patterns and production practices engineering teams use to safely govern autonomous agents at scale. Why Traditional Governance Fails for Autonomous AI Agents Passive language model applications accept a prompt and return text, allowing security teams to inspect the output before a human acts on it. AI agents, by contrast, pursue high-level objectives through autonomous execution loops: they evaluate context, choose tools, formulate queries, parse intermedia

2026-09-05 原文 →