sublayerapp / sublayer

A model-agnostic Ruby Generative AI DSL and framework. Provides base classes for building Generators, Actions, Tasks, and Agents that can be used to build AI powered applications in Ruby.
https://docs.sublayer.com
MIT License
112 stars 2 forks source link

Make defining output structure more natural and intuitive #92

Open swerner opened 2 months ago

swerner commented 2 months ago

The way to phrase and use the llm_output_adapter directive isn't super intuitive and we frequently run into cases where we confuse the LLM resulting in issues like #43 on top of that, as we add more types of output adapters it becomes a harder documentation problem where you need to remember the different names for the different adapters you want to use.

This problem is partially resolved with the generator generator in that it can usually get you the output structure you want, but it would be nice to be easier to write.

Came up with an idea the other night of changing it to something like:

# Single String
generates name: "description"

# List of named strings
generates review_summaries: [
  review: {
    movie_title: "the title of the movie",
    reviewer_name: "the name of the reviewer",
    rating: { description: "the rating given by the reviewer (out of 5 stars)", type: :integer},
    brief_comment: "a brief summary of the movie"
  }
]

Where we'd do a bunch of processing behind the scenes to map them to the different output adapters.

The benefits of going down this route are that you're able to use the symbols and literals that you're familiar with to imply the structure you want back, simply write out the names and descriptions of the variables that you want the llm to generate, and implies the perspective that you should be describing the output as: "from the perspective of the model"

The one downside I see here is that it does somewhat look like a giant blob of json, but the more complex output adapters I've been putting out feel like they're getting kind of ugly and we're reaching the end of usefulness of that design...

swerner commented 1 month ago

Spent a bunch of time exploring this path today but ran into a bit of a wall. It seems like using this syntax we'd need to make the description key required in a bunch of different places (like when you start defining a new object) and this gets kind of messy and surprising in certain cases and I haven't come up with a good solution.

For example, in that example above you'd need to add a description key to the review object and the review_summaries object and would look something like this:

generates review_summaries: [
  description: "some description",
   review: {
    description: "an individual review object",
    movie_title: "the title of the movie",
    reviewer_name: "the name of the reviewer",
    rating: { description: "the rating given by the reviewer (out of 5 stars)", type: :integer},
    brief_comment: "a brief summary of the movie"
  }
]

Part of the reason we'd be trying to build this DSL is to make it so you don't have to remember all these required fields and build out a massive structure and it feels like if we start going down this path we'll end up with a bunch more things to remember and then just end up back at writing out entire JSON schemas...so it's back to the drawing board a bit on this one...