-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Idea for templates #48
Comments
Hi! I'm sorry for not getting back to you sooner. I like the idea and line of thinking! I'd be keen to explore it further, but Slack or other chats might be more suitable to ping ideas around. In general, I was always hoping someone would figure a cool DSL for working with LLMs :) I'll check out Recipes - I've never explored it. I think there are two use cases for a DSL: I think your example recipe would belong to B), which is focused on how to execute multiple LLM calls to achieve some task? Or were you looking to build just the instruction set for single-turn extraction? All my thoughts below are driven by my thinking of LLM as a way to buy back time and augment my intelligence, ie, if it takes too long to learn or too long to define, it's not worth it (and you should use chat interface or do it "the old way"). Re A) Recipes for defining instructions The challenges I see:
So I prefer having a bunch of "sub-optimal" but fully baked-out prompts that I can just replace a placeholder in. Would you mind sharing some use cases / tasks where you could see value in defining prompt recipes / principled composition? Btw. if you're interested in this topic, I liked this survey: https://arxiv.org/pdf/2312.16171.pdf and I'm watching DSPy to see if we can be more declarative in how we use LLMs (but again, it fails my "practicality" test.) Re B) Defining Task Flow
So it feels like it would be too complicated and outdated before I finish it. What I opted for is to define "lazy" primitives, like AIGenerate instead of aigenerate. It should allow people to build a DAG with LLM operations with base Julia (ie, no need to learn a DSL). Example: mapreduce(x->AIGenerate(:MyTemplate; data=x, task="..").content,join, my_dataset) Laziness allows to access kwargs (models, parameters, variables) and share and mutate them as needed. Sequential chains using simple pipes:
using @chain with current functions (not lazy): # define MyType for the data structure you need
@chain begin
aigenerate(:MyTemplate; data="..", task="..")
_.content
aiextract(:DetailedExpert; return_type = MyType)
_.content
end As always you can add sub-chains with for-loops, if-else-end, and other nested logic. Basically, we have everything we need. Potentially, we could adjust # define MyType for the data structure you need
@aichain begin
aigenerate(:MyTemplate; data="..", task="..") #--> translate to AIGenerate(...)
_.content # --> translate to LazyFunction(...)
aiextract(:DetailedExpert; return_type = MyType) #--> translate to AIExtract(...)
_.content # ditto
end Would that cover some of your use cases or do you have some specific ones that would require a different DSL? PS: I might have misunderstood but your recipe could be (mostly) built already with: # define my_text
# define MyData struct
msg = aiextract(my_text, return_type = PT.ItemsExtract(MyData)) #returns a vector of MyData
reduce(..., msg.content) # whatever reduction is needed EDIT: I think I misunderstood your DSL proposal. You probably intended to generate a prompt to return JSON spec of that type. What benefits do you expect from a DSL versus an out-of-the-box function that will take type and return a signature to add to a prompt (as currently implemented)? |
Hey @svilupp,
Awesome package; thanks for making it!
I just wanted to share an idea for how prompt building could work in an idiomatic and generic way in Julia.
One thing that has been quite successful in Plots.jl is how you can easily describe default plotting recipes for different data structures using RecipesBase.jl (https://docs.juliaplots.org/stable/RecipesBase/syntax/), so that a user can basically just call
plot(obj)
on some complicated object and get an appropriate plot as output, without needing to extract the right series manually.For example, for a custom type
Result
type defined in a library, with data in(::Result).x
and(::Result).y
, a package developer might define:This basically sets up various plotting options by default, and finally returns
r.x, r.y
which would be passed to the corresponding@recipe
defined for those types. This might just be::Array, ::Array
, and thus go into the normal plotting function.I am wondering if you might be able to do something similar here, for prompting on different types of structures.
For example, perhaps you could define a
@promptrecipe
macro that a user would evoke like:which would then get concatenated with the rest of the prompt or something. And the
children
would be recursively expanded and added to the prompt.The goal of this would both be to enable langhchain-like recipes for different tasks (mapreduce, generation, structured output, etc), and also make it easier for users to pass arbitrary data to a language model and have it simply get serialized using library-defined recipes.
This is a pretty rough idea right now but just wanted to share it in case this might inspire the syntax when you get to work on templates! I think it requires a bit more careful thinking for sure.
There is definitely a very Julian way to handle things here which would give a unique advantage over LangChain, the same way Plots.jl is much more flexible for downstream libraries compared to Matplotlib (which is basically only defined on arrays, or if the user writes a whole
.plot()
scheme themselves).The text was updated successfully, but these errors were encountered: