Skip to content

Conditional skills (If / IfElse) feature - #175

Closed
Roger Barreto (rogerbarreto) wants to merge 17 commits into
microsoft:mainfrom
rogerbarreto:features/planner-conditionalskill-ifelse
Closed

Roger Barreto (rogerbarreto) wants to merge 17 commits into
microsoft:mainfrom
rogerbarreto:features/planner-conditionalskill-ifelse

Conversation

@rogerbarreto

@rogerbarreto Roger Barreto (rogerbarreto) commented Mar 27, 2023 •

Copy link
Copy Markdown
Member

Motivation and Context

Currently, the core planner doesn’t support conditional behavior.
This design offers an initial “If” statement capability skill that allows planner control flow execution conditioned to check for equals/contains/greaterthan against context variables.

This change will allow Plan to run correctly for prompts like: Summarize an outline about AI, if the summarization contains any reference to "AGI" then Generate a summary outline for AGI. After that generate a list of synopsis for a novel using the resulting summarization.

Description

This change adds a conditional structure to the plan as a way to be able to use a standard conditional structure for branching that can be recursive as follows.

<plan>
  ... plan steps
  <if>
     <conditiongroup>
         <condition variable="variable1" equals|contains|greaterthan="value" />
     </conditiongroup>
     <then>
         ... plan steps
     </then>
     <else> (Optional)
        ... plan steps
        <if /> (nested ifs)
     </else>
  </if>
  ... plan steps
</plan>

When resolving the conditional group this skill returns the content in Then or Else branches including potential nested ifs.

This structure was build in a way that it can allow future nested complex conditions and checks like:

<conditiongroup>
  <condition variable="…" pattern|email|numeric|custom="…" />
  <and|or|xor|not …/>
  <conditiongroup> 
      (recursive and nested conditions...)
  </conditiongroup>
</conditiongroup>

The nested scenarios above were not yet fully tested and are not officially supported by this PR.

Contribution Checklist

</plan><!-- END -->

[AVAILABLE FUNCTIONS]
[EXAMPLE FUNCTIONS]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you find this improves things to help differentiate the pattern?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I was getting very frequently WriterSkill.Summarization instead of the Everything, this was happening with Skills that bumped in the examples given and for some reason the LLM was understanding AVAILABLE examples as indeed available...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something for us to consider when we start allowing users to supply their own examples.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even changing that to this pattern I see less frequently it using the wrong function, potentially we should use abstract examples that would not conflict with actual skills.

7. To save an 'output' from a <function>, to pass into a future <function>, use <function.{FunctionName} ... setContextVariable: ""$<UNIQUE_VARIABLE_KEY>""/>
8. To save an 'output' from a <function>, to return as part of a plan result, use <function.{FunctionName} ... appendToResult: ""RESULT__$<UNIQUE_RESULT_KEY>""/>
9. Append an ""END"" XML comment at the end of the plan.
9. Available conditions: greaterthan, equals, contains, startswith

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd expect more instructions about these reserved words and others.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can potentially increase but since we don't have any specific implementation the LLM is currently guessing what to do in the conditions. I'm adding this for the scope of this change but we can limit those later on

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does it know about 'if' or 'conditiongroup'? Only from examples? That will not work when we allow users to supply their own examples.

Console.WriteLine("Original plan:");
Console.WriteLine(originalPlan.Variables.ToPlan().PlanString);

await ExecutePlanAsync(kernel, planner, originalPlan, 5);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is 5 the required steps here for completion of the plan? What is the input to the first Summarize? Can you show it with two different inputs to show it goes down each branch?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The number of steps can be greater, currently the plan will resolve the if (then/else) inner steps and add them as part of the list, so if in the overall branching we end up with more than 5 steps this will abort at the given step. For branching examples I can move this number up a bit.


if (processFunctions && o2.Name.StartsWith(ConditionIfTag, StringComparison.InvariantCultureIgnoreCase))
{
if (!context.IsFunctionRegistered("Conditional", "If", out var ifCheckFunction))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if they register with a different name?

// Load native skill into the kernel skill collection, sharing its functions with prompt templates
planner = kernel.ImportSkill(new PlannerSkill(kernel), "planning");

kernel.ImportSkill(new ConditionalSkill(kernel), "conditional");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if this is how we'll want to do things going forward.

Additionally, I'm still torn on whether we need a special syntax in the prompt for these skills or not -- maybe it could just be like any other. Did you try that?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PlannerSkill has a dependency on ConditionalSkill but this is not the ideal way moving forward, the PR proved the concept that the IF behavior worked.

Will think more on changes that don't create this problem of skillname referencing/dependency potentially adding ConditionalSkill as a Planner adittional capability instead of a standalone Skill.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving more comments.

public class ConditionalSkill
{
#region Prompts
internal const string IfStructureCheckPrompt =

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe out of scope of this PR, but I'm wondering, can we store core skill prompts in separate txt files and read from them? The same applies for Planner and other skills. In this way we can keep our C# classes nice and clean.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I think this could be a improvement to tackle

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now we are using SemanticFunctionConstants for these definitions.

maxTokens: 100,
temperature: 0,
topP: 0.5
);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unnecessary new line here

using Microsoft.SemanticKernel.SkillDefinition;

namespace Microsoft.SemanticKernel.CoreSkills;
public class ConditionalSkill

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need an empty line between namespace and class declaration. Also would be nice to add XML comments. Same applies for ConditionException.cs

foreach (var v in existingVariables)
{
// Numeric don't add quotes
if (Regex.Match(v.Value, "^[0-9.,]+$").Success)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: a little simplification, feel free to skip

var value = Regex.Match(v.Value, "^[0-9.,]+$").Success ? v.Value : JsonSerializer.Serialize(v.Value);
conditionalVariables.AppendLine($"{v.Key} = {value}");

@rogerbarreto Roger Barreto (rogerbarreto) added PR: in progress Under development and/or addressing feedback .NET Issue or Pull requests regarding .NET code labels Mar 28, 2023
[END EXAMPLE FUNCTIONS]

<goal>Summarize the input, if the input length is greater than 10 then Create an outline for a children's book with 3 chapters about a group of kids in a club and then summarize it otherwise translate to japanese and email it to Martin.</goal>
<plan>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yowza, this is going to be a token eating machine! We need to drive for simplicity in this format, or it'll burn too many tokens on prompt and response, and the AI is far more likely to get things wrong.

Asks:
at minimum, let's remove . Compound conditions can be constructed by nesting one inside another, or with specialized native skills. This is more complex than required right now.

 <if>
    <conditiongroup>
       <condition variable=""$SUMMARIZED_INPUT"" greaterthan=""10"" />
    </conditiongroup>

...becomes...
<if variable=""$SUMMARIZED_INPUT"" greaterthan=""10"">

I also think we can get rid of the <then> tags, as these are token eaters and kind of redundant (the content in the <if...> tags is implicitly then).

As for else, I think this could be another conditional stacked below with the inverse condition. I wonder if the AI would do that on its own:

<if variable=""$SUMMARIZED_INPUT"" greaterthan=""10"">
    <do stuff>
</if>
<if variable=""$SUMMARIZED_INPUT"" lessthanequals=""10"">
    <do other stuff>
</if>

7. To save an 'output' from a <function>, to pass into a future <function>, use <function.{FunctionName} ... setContextVariable: ""$<UNIQUE_VARIABLE_KEY>""/>
8. To save an 'output' from a <function>, to return as part of a plan result, use <function.{FunctionName} ... appendToResult: ""RESULT__$<UNIQUE_RESULT_KEY>""/>
9. Append an ""END"" XML comment at the end of the plan.
9. Available conditions: greaterthan, equals, contains, startswith

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the most important conditions will be "isSet" (i.e. not null or empty), "isUnset".

<conditiongroup>
<condition variable=""z"" greaterthan=""10"" />
</conditiongroup>
</not>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, way too complex. These compound conditions would be difficult to maintain. Please cut the conditiongroup for this first version -- keep it simple.

@rogerbarreto Roger Barreto (rogerbarreto) closed this by deleting the head repository Mar 29, 2023
golden-aries pushed a commit to golden-aries/semantic-kernel that referenced this pull request Oct 10, 2023
### Motivation and Context

<!-- Thank you for your contribution to the copilot-chat repo!
Please help reviewers and future users, providing the following
information:
  1. Why is this change required?
  3. What problem does it solve?
  5. What scenario does it contribute to?
  7. If it fixes an open issue, please link to the issue here.
-->

I would like to provide a production-grade PaaS solution to store the
vector database.
It provides PostgreSQL database support for memory. We can now use Azure
Database for PostgreSQL or CosmosDB for PostgreSQL.

Fixes microsoft#166 

### Description

<!-- Describe your changes, the overall approach, the underlying design.
These notes will help understanding how your code works. Thanks! -->
I added configuration support for PostgreSQL. in the kernel
initialization.
Furthermore I updated the deployment script to support this
configuration.

> Note: In the deployment scripts, I've added the SqlAdminPassword
parameter, which must be supplied during provisioning. I intentionally
named it without the PostgreSQL name, as I also worked on implementing
SQL Server Memory store in the SK repository. This parameter could be
used by both databases during deployment.

### Contribution Checklist

<!-- Before submitting this PR, please make sure: -->

- [x] The code builds clean without any errors or warnings
- [x] The PR follows the [Contribution
Guidelines](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [x] All unit tests pass, and I have added new tests where possible
> Not found test project on the API part ;(
- [x] I didn't break anyone 😄

---------

Co-authored-by: Gil LaHaye <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

.NET Issue or Pull requests regarding .NET code PR: in progress Under development and/or addressing feedback

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants