breadboard-ai / breadboard

A library for prototyping generative AI applications.
Apache License 2.0
181 stars 24 forks source link

Adding support for `include` and `slot` to graph safety #42

Closed seefeldb closed 1 year ago

seefeldb commented 1 year ago

This is a log of thoughts and issues I encounter trying to implement that (see google/breadboard-ai#38):

Currently the safety check is over the graph just after it is loaded. include and hence slot nodes are ignored.

Just evaluating the included graphs in isolation isn't going to work, as the safety constraints interact with the parent graph. For instance imagine a loop in the main graph (like in a React agent, see google/labs-prototypes#52), which means the graph's input node's constraint are in part tied to the output node's constraints.

(1) One version that could work: Just incrementally evaluating the graph at each step. Abort when a contradiction is encountered. This is tempting, but not a great long term solution:

(2) The next best option is re-evaluate the graph whenever an include or slot node is encountered, after adding the new graph to the prior full graph. This still means a runtime error, but it's a little more eager and consistently triggering. A complications we run into: ID namespaces are per graph, and so there could be name collisions. This requires changes to the current code, but shouldn't be difficult.

(3) We could then improve on that by trying to eagerly include all graphs before execution, basically recursively looking for all include and slot nodes and just loading these graphs. We have to be cautious about infinite loops, but otherwise this should work. Problems with this:

(4) The most elegant solution to address the second concern (dynamic graphs) would be to effectively implement parametric polymorphism for graphs: That is, infer from where graph sits in the graph, including what graphs are being slotted in, what constraints it must have, then ensure that any code producing graphs that should be included only outputs valid types. This would support any number of complex scenarios, including most recursion cases and where constraints come indirectly via the slotted graphs.

As part of ensuring that only valid graphs can be added, the system would either have to convince itself for static inputs or perform a runtime test at the right point. Examples:

My sense is to start with (2) and then go straight to (4), which subsumes the best of (3) as subsequent steps. Instead of implementing (1), I'm tempted to just implement fuse instead to get React agents working (see google/labs-prototypes#52).

seefeldb commented 1 year ago

This is now implemented and should even work for dynamic graphs. In the end I went with incremental checking on every include.

We could eventually