-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
.Net: Handlebars syntax example #4646
.Net: Handlebars syntax example #4646
Conversation
…rom the master of Handlebars ;)
@matthewbolanos - if you want to go over this I am in anytime. |
dotnet/samples/KernelSyntaxExamples/Example77_HandlebarsPromptSyntax.cs
Outdated
Show resolved
Hide resolved
"Maybe" the issue I am having with the loops is due to this issue: #4596 |
I did not realize I had to "resolve" the conversation - just did... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you fix the typo please
@joslat Thanks for the contribution, this is a useful addition. Can you please fix the typo and formatting changes. |
Thanks @markwallace-microsoft - Unsure you want to accept the PR as it is as mentions a couple of things that did not work - haven't seen if they are fixed though. I put some code in there that is meant to be left as an example on how to do things/use handlebars... you tell me if you want me to adapt, remove any section... we can have a sync or you can tell me here - or go and do it. |
dotnet/samples/KernelSyntaxExamples/Example77_HandlebarsPromptSyntax.cs
Outdated
Show resolved
Hide resolved
dotnet/samples/KernelSyntaxExamples/Example77_HandlebarsPromptSyntax.cs
Outdated
Show resolved
Hide resolved
dotnet/samples/KernelSyntaxExamples/Example77_HandlebarsPromptSyntax.cs
Outdated
Show resolved
Hide resolved
dotnet/samples/KernelSyntaxExamples/Example77_HandlebarsPromptSyntax.cs
Outdated
Show resolved
Hide resolved
dotnet/samples/KernelSyntaxExamples/Example77_HandlebarsPromptSyntax.cs
Outdated
Show resolved
Hide resolved
dotnet/samples/KernelSyntaxExamples/Example77_HandlebarsPromptSyntax.cs
Outdated
Show resolved
Hide resolved
dotnet/samples/KernelSyntaxExamples/Example77_HandlebarsPromptSyntax.cs
Outdated
Show resolved
Hide resolved
dotnet/samples/KernelSyntaxExamples/Example77_HandlebarsPromptSyntax.cs
Outdated
Show resolved
Hide resolved
…Syntax.cs Co-authored-by: Teresa Hoang <125500434+teresaqhoang@users.noreply.github.com>
…Syntax.cs Co-authored-by: Teresa Hoang <125500434+teresaqhoang@users.noreply.github.com>
…Syntax.cs Co-authored-by: Teresa Hoang <125500434+teresaqhoang@users.noreply.github.com>
Hi @teresaqhoang, have resolved I believe all of your comments but unsure the implementation is ideal (or the prompt improvement suggestions are fully applied) - so I have not labelled them as "resolved" - also would love to get samples on two of your suggestions, if you have any code links to what you suggest it would be perfect. Also, those issues might be affecting/impacting the outcome/function of this sample:
|
@teresaqhoang, any news on this? :) |
Hey @joslat, Apologies for the delayed response - I haven't been getting notifications for changes on this PR for some reason, will be more diligent in checking the PR directly moving forward. Thanks for iterating! I can happily help you with more guidance! Can you reply on the unresolved conversation threads directly with your questions / points of concerns? And also call out the ones you want code samples for? I'll also pull this example and test it locally to see if I can better identify some pain points the model's hitting. |
… inside a handlebars prompt template, and checking if the JSON is modified to non-JSON.
@teresaqhoang "Pong" ;) - ball is in your ground :D |
await ExecuteHandlebarsPromptAsync(kernel, CompanyDescription, handlebarsTemplate2); | ||
} | ||
|
||
private async Task RunHandlebarsTemplateSample01Async(Kernel kernel) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Please omit the number and give them more descriptive names based on what the example you're demonstrating
i.e., RunSimpleHandlebarsTemplateSample
vs. RunHandlebarsTemplateWithLoopsSample
await ExecuteHandlebarsPromptAsync(kernel, CompanyDescription, handlebarsTemplate01); | ||
} | ||
|
||
private async Task RunHandlebarsPlannerSampleAsync(Kernel kernel) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this to the top since it's the main scaffolding of this example (This is where you're directly invoking the Template factory and invoking the template)
|
||
KernelFunction kernelFunctionGenerateProductNames = | ||
KernelFunctionFactory.CreateFromPrompt( | ||
"Given the company description, generate five different product names in name and with a function " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wanted to follow-up on my question here - why not just return an array of products? Is there a need to wrap in the outer JSON object? If not, you can remove the outer object to reduce complexity and probability of model error.
I recommend rather than creating the prompts inline, you leverage the YAML format so users (and the model) have sufficient context for the inputs and outputs of the function.
Here's an example of how I refactored one of your functions to make it more digestible to an LLM: 3438ec5 (Ignore the changes to use AOI)
Sone highlights of prompt improvements:
- Isolated definition on what a
product
should look like. - Defined example output before instructing the model to begin.
- Buttoned up description to clear redundancy and be straightforward with expectations.
Also, I renamed the function from GenerateJSONProductNames
to GenerateJSONProducts
since it's not returning just product names.
|
||
// Using the planner to generate a plan for the user | ||
string userPrompt = | ||
"Using as input the following company description:" + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the way your functions are set up are too complex for this example.
Either:
- Have a function that generates the products (with name and description fields) and then a second function that can iterate through those products and produce more detailed descriptions.
i.e.
var products = GenerateNewProducts(string companyDescription) // outputs `[ product1, product2, ...]`
// Either pass in the entire result and have the model handle the products array for you or parse `products` array and loop through each object
GenerateDetailedDescription(product[0]) // outputs "Some compelling description"
- Have a function that returns a list of product names (output: a list of strings) and then iterate over that list to generate descriptions for each name (output: a list of products containing name and desc)
{{!-- Example of concatenating text and variables to finally output it with json --}} | ||
{{set ""finalOutput"" (concat ""Description 1: "" productNames "" Description 2: "" productNames2)}} | ||
{{json finalOutput}} | ||
{{/if}}"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In terms of showcase a HB prompt template, these are much too complex.
Example of how you can reduce complexity:
{{!-- Omit the initial variable mapping of inputs (this is required for the planner to reduce error) but as a dev executing their own HB template, you should have full context over how input are maps. --}}
{{set ""productNames"" (productMagician-GenerateJSONProducts input)}}
{{#if generateEngagingDescriptions}}
{{!-- Since SK doesn't support mutable arrays, you must concatenate each result onto a string. --}}
{{set ""finalProducts"" """"}}
{{#each productNames}}
{{!-- Refactor your GenerateJSONProducts function to return just an array of products, then remove the inner {{#each}}} block. It's unnecessarily complex. --}}
{{set ""productDescription"" (concat ""Product Name: "" this.name "" Description: "" this.description)}}
{{set ""compellingDescription"" (productMagician-GenerateProductCompellingDescription this)}}
{{set ""outputProduct"" (concat ""PRODUCT :"" this.name "" Engaging Description: "" compellingDescription)}}
{{!-- Check if you're on the first object; if not, concatenate to end of string. --}}
{{#if @first}}{{set ""finalProducts"" outputProduct}}
{{else}}{{set ""finalProducts"" (concat finalProducts ""\n\n"" outputProduct)}}
{{/if}}
{{/each}}
{{!-- OUTPUT The following product descriptions as is, do not modify anything --}}
{{json finalProducts}}
{{else}}
{{!-- Return products as is since the conditional is checking whether descriptions should be regenerated. --}}
{{json productNames}}
{{/if}}
@joslat I see you resolved some of the conversations (thanks for that) but I'm not seeing any replies to the conversations that are still open so I'm not sure what kind of clarity you need where. I tried to reply best I could. Do you see the option to reply directly on those conversation threads? If not, we can try to troubleshoot your access issues IMO I think this example is too complex for what it's trying to showcase. We try to keep the Syntax examples as simple as possible to help users grasp the concept easier, and I think this one (since it's derived from the planner) can be hard to follow. I left more comments with suggestions on how to simplify these samples Also happy to schedule a meeting so we can parallel program this together if you'd like :) |
Hey @joslat, I discussed your PR with the team today and we think there's a lot of value in examples shown here, but some ideas are getting lost in translation and complexity. What do you think about pivoting this example to show the difference between Handlebars Plan and a Handlebars Template? It would still fit your goal of showing the Handlebars syntax. Some differences:
I created an example here that refactors your I left some prompt engineering pointers directly on that commit. Let me know if you have any questions |
Hi @teresaqhoang would be my honor to do this in "extreme programming" way, that would be fantastic for "getting it done" - also this would ensure the focus in showcasing as well the differences between Handlebars Plan and Handlebars Template. |
Hi @joslat, @matthewbolanos will handle follow-up on this moving forward! Let me know if I can help provide code reviews. |
@joslat Thanks for the PR. We have decided we're not going to invest in Handlebars for planning and instead focus on providing first class support for planning with Function Calling and Python code execution using the new Azure Container Applications functionality for serverless code interpreter sessions. |
That makes a lot of sense, but will we be able - read supported - to run python on other places like docker, locally if we dare as well? |
This example shows how to use Handlebars different syntax options
Motivation and Context
This example shows how to use Handlebars different syntax options like:
In order to create a Prompt Function that fully benefits from the Handlebars syntax power.
The example also shows how to use the HandlebarsPlanner to generate a plan (and persist it) which was used to generate the initial Handlebar template.
The example also shows how to create two prompt functions and a plugin to group them together.
Description
Contribution Checklist