Mirascope / mirascope

LLM abstractions that aren't obstructions
https://docs.mirascope.io/
MIT License
680 stars 37 forks source link

Directed Acyclic Graph support? #342

Closed joekendal closed 3 days ago

joekendal commented 3 months ago

Question

Apologies if this has been asked in the community somewhere. I'm currently using LangChain with LangGraph but Mirascope looks like a simpler/better alternative to LangChain - is that correct?

and if so, how do you approach LangGraph primitives to have more control over agentic workflows?

willbakst commented 3 months ago

LangGraph reminds me of TensorFlow v1.

Our current focus is to make the primitives for working with LLMs as good as they can be so that writing even more complex agent workflows doesn't require giving up control like using LangGraph seems to require (for example, where are the tools being called? how are they being called? what if I want to do something more custom?).

If we do decide to implement an additional level of abstraction on top of these primitives for building agentic workflows, I would strive to implement a system more like PyTorch 2.0 and less like TensorFlow v1. If there's a graph, it should be run eagerly and not compiled. Creating it should be the same as chaining functions together -- not manually constructing the graph yourself.

There is a reason that PyTorch is currently the clear winner

joekendal commented 3 months ago

LangGraph would be great but they require too much boilerplate code to do it. I don't think their concept is wrong, just their implementation is verbose/ugly. Just like LangChain is a good concept but a bad implementation.

I've stumbled on a comment in the slack channel that mentions creating a DAG with the cached_property decorator, but it is less clear how this can achieve the same thing as LangGraph. Perhaps some examples for how to implement these (multi-agent systems) would help with understanding: https://langchain-ai.github.io/langgraph/tutorials/

willbakst commented 3 months ago

I agree with you.

In the new v1 interface you can use computed fields to create chains/graphs easily. For example:

from mirascope.core import openai

@openai.call("gpt-4o")
def recommend_author(genre: str):
    """Recommend an author who writes {genre} book."""

def format_book(title: str, author: str):
    return f"{title} by {author}"

@openai.call("gpt-4o", tools=[format_book])
def recommend_book(genre: str):
    """Recommend a {genre} book written by {author}."""
    return {"computed_fields": {"author": recommend_author(genre)}}

response = recommend_book("fantasy")
if tools := response.tools:
    for tool in tools:
        output = tool.call()
        print(output)
else:
    print(response.content)

You can see here that writing arbitrarily complex chains/DAGs is as simple as just writing functions and calling them. For example, you could wrap the tool-use part of the script in another function and use that as a computed field in another call. The DAG is implicit in how you're calling the functions. The main thing is that you're fully in control.

I think re-implementing the examples you shared using Mirascope would be a great thing to include in the cookbook we're working on, so thank you for sharing! We'll push to have those examples ready for the release :)

willbakst commented 1 month ago

@joekendal we implemented the LangGraph quickstart tutorial the Mirascope way.

Would love to know if this is in line with what you're looking for wrt. DAG support?

willbakst commented 3 days ago

I've added a new issue (#522) to track showing how Mirascope supports the same things as LangGraph without the graph abstraction.

If there is a desire for specific features around DAG support, we can open a new issue that defines what features we should add and why.

joekendal commented 3 days ago

@willbakst looks awesome, thanks. do you have any best practices for deployment to production?

willbakst commented 3 days ago

We don't have any formally written documentation here. I've added another issue for including documentation specifically around production deployment best practices that we hope to get to soon.

Generally since everything is written using Pydantic, catching API errors and validation errors leads to a fairly robust system, and using our tenacity integration makes including retries easy to make your systems even more robust.