I'm interesting in hearing thoughts from people here who have checked out some of the more popular recent LLM frameworks. Here's the text from the linked post:

-------------

I've worked with more than a few streaming, distributed processing, and orchestration frameworks in the past, and am familiar with their designs and, more importantly, the reasoning behind their designs. It's common for frameworks like these to have you treat your functions as some flavor of an abstract computation node, assemble them into pipelines, use conditional/"routing" primitives that they provide, limit the library functions you can call from within a computation node to a set of functions their API provides, etc.

This is done so the frameworks can more easily accomplish their core purpose, i.e. distribute and parallelize computation while routing data/messages, control the input/output flow themselves for distributed execution, feed streaming events from an external source to a function by invoking it per msg or in batches, support streaming computation using stream processing functions the framework has built-in support for, etc. The reason for these frameworks to not use vanilla Python/etc is partly because applications using the framework can not be executed as a normal Python script, executed by the Python interpreter, because the framework is essentially providing a different execution model (i.e. streaming, distributed, event-based + distributed, whatever) and will need to itself perform certain functions that the interpreter normally would perform.

Handling all of these things is significantly easier for a framework if it provides a set of standard abstractions (in code) that define how applications must be structured, control how clients can define functions, inputs, execution and data flow, limit what methods can be called from within functions, limit how clients can define and access stateful variables, etc - think Flink & similar as examples. The design of these constructs/API enforces the restrictions inherent to the framework, and using them versus vanilla Python/etc removes the need for things like Python/etc AST parsing and validation. These abstractions are restrictive, as they limit how you can write your application, and they require the framework to reimplement and handle things the actual language runtime normally would - but it's all for the sake of enabling the frameworks' core functionality.

I'm seeing the same concepts used in frameworks like Haystack, Griptape, LangChain, but with none of the benefits and no similar underlying reasons. Can somebody explain why things like https://docs.haystack.deepset.ai/docs/nodes_overview#decisio... and Haystack/Griptape's various types of nodes, plus pipelines, workflows, agents, etc etc... are better than `if` statements (in the case of decision nodes) and normal Python function definitions and general execution?

Let's take this snippet from Langchain's docs as another example:

Why do we need chains?

Chains allow us to combine multiple components together to create a single,
coherent application. For example, we can create a chain that takes user input,
formats it with a PromptTemplate, and then passes the formatted response to an
LLM. We can build more complex chains by combining multiple chains together, or
by combining chains with other components.

Am I crazy, or are they are literally just describing the concept of abstracting code into function blocks and allowing function blocks to call other function blocks... you know, the most fundamental and basic of programming primitives. It would be one thing if Chains were then used as a building block by the framework to enable some type of functionality/processing, or provide some kind of guarantee, that normal Python function definitions and invocations do not already provide... but no, instead they're just invoked and executed like any other function/callable, with the "chain" becoming nothing more than the call stack at runtime. What is a single benefit of having to structure everything using a hierarchy of "Chains" versus normal Python/Typescript function calls?

One could argue that useless/contrived abstractions still have actual value for framework authors because they increase the coupling between your codebase and their framework, increasing the friction of moving to a different framework... but to paraphrase Hanlon, "prob not." Am I just missing something?