Hacker News new | ask | show | jobs
by tptacek 345 days ago
I don't know where "more agents" is coming from.
3 comments

I guess this part

> there should be one LLM context that is reading tickets, and another LLM context that can drive MCP SQL calls, and then agent code in between those contexts to enforce invariants.

I get the impression that saurik views the LLM contexts as multiple agents and you view the glue code (or the whole system) as one agent. I think both of youses points are valid so far even if you have semantic mismatch on "what's the boundary of an agent".

(Personally I hope to not have to form a strong opinion on this one and think we can get the same ideas across with less ambiguous terminology)

You said you wanted to take the one agent, split it into two agents, and add a third agent in between. It could be that we are equivocating on the currently-dubious definition of "agent" that has been being thrown around in the AI/LLM/MCP community ;P.
No, I didn't. An LLM context is just an array of strings. Every serious agent manages multiple contexts already.
If I have two agents and make them communicate, at what point should we start to consider them to have become a single agent?
They don’t communicate directly. They’re mediated by agent code.
Now I'm more confused. So does that mediating agent code constitute a separate agent Z, making it three agents X,Y,Z? Explicitly or not (is this the meaningful distinction?) information flowing between them constitutes communication for this purpose.

It's a hypothetical example where I already have two agents and then make one affect the other.

Again: an LLM context is simply an array of strings.
FWIW, I don't think you can enforce that correctly with human code either, not "in between those contexts"... what are you going to filter/interpret? If there is any ability at all for arbitrary text to get from the one LLM to the other, then you will fail to prevent the SQL-capable LLM from being attacked; and like, if there isn't, then is the "invariant" you are "enforcing" that the one LLM is only able to communicate with the second one via precisely strict exact strings that have zero string parameters? This issue simply cannot be fixed "in between" the issue tracking parsing LLM (which I maintain is a red herring anyway) and the SQL executing LLM: it must be handled in between the SQL executing LLM and the SQL backend.
There doesn't have to be an ability for "arbitrary text" to go from one context to another. The first context can produce JSON output; the agent can parse it (rejecting it if it doesn't parse), do a quick semantic evaluation ("which tables is this referring to"), and pass the structured JSON on.

I think at some point we're just going to have to build a model of this application and have you try to defeat it.

Ok, so the JSON parses, and the fields you can validate are all correct... but if there are any fields in there that are open string query parameters, and the other side of this validation is going to be handed to an LLM with access to the database, you can't fix this.

Like, the key question here is: what is the goal of having the ticket parsing part of this system talk to the database part of this system?

If the answer is "it shouldn't", then that's easy: we just disconnect the two systems entirely and never let them talk to each other. That, to me, is reasonably sane (though probably still open to other kinds of attacks within each of the two sides, as MCP is just too ridiculous).

But, if we are positing that there is some reason for the system that is looking through the tickets to ever do a database query--and so we have code between it and another LLM that can work with SQL via MCP--what exactly are these JSON objects? I'm assuming they are queries?

If so, are these queries from a known hardcoded set? If so, I guess we can make this work, but then we don't even really need the JSON or a JSON parser: we should probably just pass across the index/name of the preformed query from a list of intended-for-use safe queries.

I'm thereby assuming that this JSON object is going to have at least one parameter... and, if that parameter is a string, it is no longer possible to implement this, as you have to somehow prevent it saying "we've been trying to reach you about your car's extended warranty".

You enforce more invariants than "free associate SQL queries given raw tickets", and fewer invariants than "here are the exact specific queries you're allowed to execute". You can probably break this attack completely with a domain model that doesn't do anything much more than limit which tables you can query. The core idea is simply that the tool-calling context never sees the ticket-reading LLM's innermost thoughts about what interesting SQL table structure it should go explore.

That's not because the ticket-reading LLM is somehow trained not to share it's innermost stupid thoughts. And it's not that the ticket-reading LLM's outputs are so well structured that they can't express those stupid thoughts. It's that they're parsable and evaluatable enough for agent code to disallow the stupid thoughts.

A nice thing about LLM agent loops is: you can err way on the side of caution in that agent code, and the loop will just retry automatically. Like, the code here is very simple.

(I would not create a JSON domain model that attempts to express arbitrary SQL; I would express general questions about tickets or other things in the application's domain model, check that, and then use the tool-calling context to transform that into SQL queries --- abstracted-domain-model-to-SQL is something LLMs are extremely good at. Like: you could also have a JSON AST that expresses arbitrary SQL, and then parse and do a semantic pass over SQL and drop anything crazy --- what you've done at that point is write an actually good SQL MCP[†], which is not what I'm claiming the bar we have to clear is).

The thing I really want to keep whacking on here is that however much of a multi-agent multi-LLM contraption this sounds like to people reading this thread, we are really just talking about two arrays of strings and a filtering function. Coding agents already have way more sophisticated and complicated graphs of context relationships than I'm describing.

It's just that Cursor doesn't have this one subgraph. Nobody should be pointing Cursor at a prod database!

[†] Supabase, DM for my rate sheet.

Seems they can't imagine the constraints being implemented as code a human wrote so they're just imagining you're adding another LLM to try to enforce them?
(EDIT: THIS WAS WRONG.) [[FWIW, I definitely can imagine that (and even described multiple ways of doing that in a lightweight manner: pattern whitelisting and fine-grained permissions); but, that isn't what everyone has been calling an "agent" (aka, an LLM that is able to autonomously use tools, usually, as of recent, via MCP)? My best guess is that the use of "agent code" didn't mean the same version of "agent" that I've been seeing people use recently ;P.]]

EDIT TO CORRECT: Actually, no, you're right: I can't imagine that! The pattern whitelisting doesn't work between two LLMs (vs. between an LLM and SQL, where I put it; I got confused in the process of reinterpreting "agent") as you can still smuggle information (unless the queries are entirely fully baked, which seems to me like it would be nonsensical). You really need a human in the loop, full stop. (If tptacek disagrees, he should respond to the question asked by the people--jstummbillig and stuart73547373--who wanted more information on how his idea would work, concretely, so we can check whether it still would be subject to the same problem.)

NOT PART OF EDIT: Regardless, even if tptacek meant adding trustable human code between those two LLM+MCP agents, the more important part of my comment is that the issue tracking part is a red herring anyway: the LLM context/agent/thing that has access to the Supabase database is already too dangerous to exist as is, because it is already subject to occasionally seeing user data (and accidentally interpreting it as instructions).

It's fine if you want to talk about other bugs that can exist; I'm not litigating that. I'm talking about foreclosing on this bug.
I actually agree with you, to be clear. I do not trust these things to make any unsupervised action, ever, even absent user-controlled input to throw wrenches into their "thinking". They simply hallucinate too much. Like... we used to be an industry that saw value in ECC memory because a one-in-a-million bit flip was too much risk, that understood you couldn't represent arbitrary precision numbers as floating point, and now we're handing over the keys to black boxes that literally cannot be trusted?