Show HN: Fructose – LLM calls as strongly typed functions (github.com)
Fructose
Fructose is a python package to call LLMs as strongly typed functions. It uses function type signatures to guide the generation and guarantee a correctly typed output, in whatever basic/complex python datatype requested.
By guaranteeing output structure, we believe this will enable more complex applications to be built, interweaving code with LLMs with code. For now, we’ve shipped Fructose as a client-only library simply calling gpt-4 (by default) with json mode, pretty simple and not unlike other packages such as marvin and instructor, but we’re also working on our own lightweight formatting model that we’ll host and/or distribute to the client, to help reduce token burn and increase accuracy.
We figure, no time like the present to show y’all what we’re working on! Questions, compliments, and roasts welcomed.
104 comments
[ 3.9 ms ] story [ 83.9 ms ] threadOpenAI (& peer) API pricing is honestly quite cheap - I spend way less than 20$ a month for my needs. On the other hand, ChatGPT offers a different experience, so I pay for that too.
https://help.openai.com/en/articles/7127956-how-much-does-gp...
I've been impressed at how well gpt-4 does with the default prompt template we use. Even better if you enable the chain_of_thought flavor.
Looking at the prompt templates (https://github.com/bananaml/fructose/tree/main/src/fructose/... ), they use LangChain-esque "just try to make the output to be valid JSON" when APIs such as GPT-4 Turbo which this model uses by default now support function calling/structured data natively and do a very good job of it (https://news.ycombinator.com/item?id=38782678), and libraries such as outlines (https://github.com/outlines-dev/outlines) which is more complex but can better ensure a dictionary output for local LLMs.
What are the benefits of using Fructose over LMQL, Guidance or OpenAI's function calling?
What we're mostly going for is composability vs abstraction. What's the smallest nugget of lift we can do for you, to make it feel natural to implement what you want? In this case it's treating the calls as functions and leaning on native python features like functions, docstrings, and types, so you can still use the python language like closures to do the weird things you need.
This is all handwavy, put on my wizard language design hat, so take it with a grain of salt. We're just trying things out.
https://github.com/eth-sri/lmql
https://github.com/outlines-dev/outlines
https://github.com/guidance-ai/guidance
I'd like to see an injectable mitm like proxy that can rewrite payloads. Many of these frameworks are useful, but when they go off the rails, they hard to modify and introspect.
It would be nice if LLMs had a way to speak an annotated format, like XML that was able to encode higher level information in a coherent manner over "well formed" addhoc text.
LLM libraries are in a crazy state right now. It is like JS frameworks 2015, a new one that demos well every other day.
Langchain & Llamaindex plus Fructose really need to skip the structure adherence work & move to chunking/KG generation since that's the next pain point to tackle.
https://github.com/guidance-ai/guidance
or ...
https://huggingface.co/docs/text-generation-inference/concep...
or ... ?
A quick glance through these, they don't seem yet to leverage json_object on OpenAI with the word JSON in the prompt, which works wonders with the 0125 models.
We're trying to make it more of a language feature with the decorated functions. Plus exploring the hosted formatting model direction.
How do you feel this compares? Do you think there's any gaps in current tools worth working on?
I just want `create(response_model=T) -> T` lol
Feels very similiar to DSPy except you dont have optimizations yet. But I like your API and the programming model your are enforcing through this.
This strikes a happy medium, where machines are assisting programmers, making them much more productive. Yet the resulting code is understandable as a human has decomposed everything into functions, and also robust as it is formally verified.
I am working on a F# proof-of-concept system like this, there are other alternatives around implemented in Haskell and other languages with varying levels of automation. It is potentially an interesting niche for a startup.
(also, +1 for OS link request)
In fact, synthesis has a relatively rich history using SAT/SMT solvers.
Being able to sometimes answer a given question is perhaps a first step to writing code that can answer that question reliably, but it's a long way from an LLM that does the former to one that does the latter.
https://www.microsoft.com/en-us/research/publication/program...
I’ve wanted to see the traditional techniques combined with modern ML to sort of drive the search and generation process. Then, we’d still have the advantages of both formal specifications and classic AI (esp traceability). While looking for a synthesis link, I stumbled onto one paper trying to mix the two approaches:
https://ojs.aaai.org/index.php/AAAI/article/download/5048/49...
"Type-Driven Program Synthesis" by Nadia Polikarpova https://www.youtube.com/watch?v=HnOix9TFy1A
Links to more projects and papers by Prof. Polikarpova: https://cseweb.ucsd.edu/~npolikarpova/
I think this is one of the main projects she discusses in the talk: https://github.com/nadia-polikarpova/synquid
EDIT: meant to mention this too, which I think has been around a bit longer, not that I've ever used it in production: https://ucsd-progsys.github.io/liquidhaskell/
This is how I use copilot currently, so I might not be following on what part of this is 'future' facing or relevant to this Fructose project?
Not being contrarian, I thought this was an interesting point but as I thought about it more I realized, "wait, they're describing what I already do".
https://jxnl.github.io/instructor/
This feels pretty much identical to Marvin? Like the entire API?
From a genuine place of curiosity: I get that your prompts are different, but like why in the name of open source would you just not contribute to these libraries instead of starting your own from scratch?
If you run your own models as a part of it, surely you could hook up your models as a backend to whatever abstractions you’re copying here.
If you have your own thoughts, surely you could just think them to yourself while upvoting.
I was responding to them sidestepping the first commenter’s question.
So as long as this library can be directed to localhost or configured, it can use any LLM
I'm about to write something that generates typescript code from pydantic models. If this just works out of box, it would make me very happy.
I'll take a look through the repo tomorrow, sorry if my response is a little lazy, I just got off work.
Another project I'm excited about in this area is GPTScript, which launched last week: http://github.com/gptscript-ai/gptscript.
Instead of this:
@ai() def describe(animals: list[str]) -> str: """ Given a list of animals, use one word that'd describe them all. """
it would seem a lot more intuitive to do this:
def describe(animals: list[str]) -> str: return ai("""Given a list of animals, use one word that'd describe them all.""", animals)
For your suggestion, the decorator would still be required to overload the function execution with the remote call, otherwise you'd just be calling the function body, but we have considered special wrapper return types to help play better with pyright (and also give programmatic access to debug details of the call), but that'd add bloat to the package and subtract from the more native python feel we're aiming for.
Python has an existing convention for this (so its not a "trick"), the use of the special value Ellipsis (literal: ...)
https://mypy.readthedocs.io/en/stable/stubs.html
Of course, this doesn't really matter at all, and I get that it feels strange. I've just been thinking about grammars and syntax lately, and it's been interesting to now have the vocabulary and mental model to understand these unintuitive things :)
During my senior year, I worked on a research project very similar to this and I’m glad to see this out there for everyone. I’d love to connect with the team if possible!
The future here really lies in compiling down context free grammars. They let you model json, yml, csv, and other programming languages as finite state machines that can force LLM transitions. They end up being pretty magical: you can force value typing, enums, and syntax validation of multivariate payloads. For use in data pipelines they can't be beat.
I did some experiments a few weeks ago on training models to generate these formats explicitly with jsonformers/outlines. Finetuning in the right format is still important to maximize output. You can end up seeing a 7% lift if you finetune explicitly for your desired format. [^1] At inference time the CFGs will constrain your model to do what it's actually intended to.
[^1]: https://freeman.vc/notes/constraining-llm-outputs
https://platform.openai.com/docs/guides/text-generation/json...