microsoft / semantic-kernel

Integrate cutting-edge LLM technology quickly and easily into your apps
https://aka.ms/semantic-kernel
MIT License
21.49k stars 3.17k forks source link

.Net: [Handlebars Planner] Adjustments and additional metadata to help the LLM to create proper function calls. #4439

Closed Cotspheer closed 7 months ago

Cotspheer commented 9 months ago

It would be great to have the Handblebars Planner Template to include what the function returns and the parameters default values. Currently there seems to be no way to include additional information for the LLM/Agent and I have to include this information in the function description but I would like to seperate that. Like in C# where we can describe the functions return value with <returns></returns> . For the default values we could use the DefaultValue annotation (it seems that its support was removed) but for the Return-Value there is no equivalent.

Also I'd like to propose additional changes to the yaml structure so we can extend the information we can transfer to the LLM/Agent.

Core issue: The LawLookupPlugin-Find returns multiple different chunks to one single law (thats by design to enhance the recall and to provide accurate citations). All those chunks are important but the plan generated only forwards the first single chunk. My assumption is that the LLM thinks the first entry is the most relevant and so only decides to forward the first entry.

Current output:

### `SomeApp_Knowledge_LawLookupPlugin-Find`
Description: Find related laws. Useful to find law references and to get legal arguments. Combines similarity and full text search.
Inputs:
    - input: String - Context to find related laws for. This can be quotes (direct citation of a law) or a question or fragments of a context. (required)
    - collection: String - Collection to use for the search. Only set this if instructed to do so. (optional)
    - relevance: Double - The relevance score, from 0.0 to 1.0, where 1.0 means perfect match. Good values are 0.6 to 0.8. (optional)
    - limit: Int32 - The maximum number of relevant results the search should return. Only increase this if more information is requested. Defaults to 10. (optional)
Output: Object

An example output that would be great:

### `SomeApp_Knowledge_LawLookupPlugin-Find`
Description: Find related laws. Useful to find law references and to get legal arguments. Combines similarity and full text search.
Inputs:
    - input: String - Context to find related laws for. This can be quotes (direct citation of a law) or a question or fragments of a context. (required)
    - collection: String - Collection to use for the search. Only set this if instructed to do so. (optional)
    - relevance: Double - The relevance score, from 0.0 to 1.0, where 1.0 means perfect match. Good values are 0.6 to 0.8. (optional)
    - limit: Int32 - The maximum number of relevant results the search should return. Only increase this if more information is requested. Defaults to 10. (optional)
Output: Object
Returns: A list of possible related laws to the context. Keep in mind that a single law can be chunked into multiple parts.

An example output that would be awesome:

### `SomeApp_Knowledge_LawLookupPlugin-Find`
Description: Find related laws. Useful to find law references and to get legal arguments. Combines similarity and full text search.
Inputs:
    - input:
        - Description: Context to find related laws for. This can be quotes (direct citation of a law) or a question or fragments of a context.
        - Type: String
        - Required: true
    - collection:
        - Description: Collection to use for the search. Only set this if instructed to do so.
        - Type: String
        - Required: false
        - Default: law-de-v2
    - relevance:
        - Description: The relevance score, from 0.0 to 1.0, where 1.0 means perfect match. Good values are 0.6 to 0.8.
        - Type: Double
        - Required: false
        - Default: 0.8 
    - limit:
        - Type: Int32
        - Description: The maximum number of relevant results the search should return. Only increase this if more information is requested. 
        - Required: false
        - Default: 10
Output: 
    - Type: Object
    - Description: A list of possible related laws to the context. Keep in mind that a single law can be chunked into multiple parts.

Example Plan (First attempt):

{{!-- Step 1: Set the input variable for the article we are looking for --}}
{{set "articleNumber" "Art. 4 ZGB"}}

{{!-- Step 2: Use the Law Lookup Plugin to search for the article --}}
{{set "lawSearchResults" (SomeApp_Knowledge_LawLookupPlugin-Find
  input=articleNumber
)}}

{{!-- Step 3: Check if we successfully found the law article --}}
{{#with lawSearchResults}}
  {{!-- Step 4: Extract the first law text from the results --}}
  {{set "lawText" (this.[0])}}

  {{!-- Step 5: Convey the law in a user-friendly manner --}}
  {{set "explanation" (SomeApp_Assistant_ConversationPlugin-Chat
    input=articleNumber
    laws=lawText
    shouldExplainInSimpleTerms=true
  )}}

  {{!-- Step 6: Output the result --}}
  {{json explanation}}

{{/with}}

Example Plan (Second attempt):

{{!-- Step 1: Set the input variable for the article we are looking for --}}
{{set "articleNumber" "Art. 4 ZGB"}}

{{!-- Step 2: Use the Swiss Law Lookup Plugin to search for the article --}}
{{set "lawSearchResults" (SomeApp_Knowledge_LawLookupPlugin-SearchFullText
  input=articleNumber
)}}

{{!-- Step 3: Check if we successfully found the law article --}}
{{#with lawSearchResults}}
  {{!-- Step 4: Extract the law text from the results --}}
  {{set "lawText" this}}

  {{!-- Step 5: Convey the law in a user-friendly manner --}}
  {{set "explanation" (SomeApp_Assistant_ConversationPlugin-Chat
    input=articleNumber
    laws=lawText
    shouldExplainInSimpleTerms=true
  )}}

  {{!-- Step 6: Output the result --}}
  {{json explanation}}

{{/with}}

Currently the LLM overlooks / has no way to know with certainty that the result of LawLookupPlugin is in fact an array / list of string chunks. To some degree this is an issue on my side and I have to improve the documentation / description and variable names but my hypothesis is that with a more structured output the planner prompt would perform better.

teresaqhoang commented 7 months ago

Hi @Cotspheer,

Support for complex types was addressed here: https://github.com/microsoft/semantic-kernel/issues/3258; we had a bug but it should be fixed now, so in the prompt, the definition for your function should list the output as a List. Based on the plans you provided above, it looks like the LLM doesn't know to loop through the object returned, but now that the output type can be properly defined as a list, it should know to loop through the final result.

We currently don't include the description for the return type in the Create Plan prompt. The expectation is that the description of the function should be sufficient in communicating what will be returned, but I can do a quick POC to see if we can enable the Returns field easily.

Closing this issue as resolved. If you're still running into issues, please re-open and provide the following: