-
Notifications
You must be signed in to change notification settings - Fork 809
Replace AIFunctionParameterMetadata
with MethodInfo
#5886
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
Replace AIFunctionParameterMetadata
with MethodInfo
#5886
Conversation
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.
Copilot reviewed 5 out of 15 changed files in this pull request and generated no comments.
Files not reviewed (10)
- test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Functions/AIFunctionParameterMetadataTests.cs: Evaluated as low risk
- src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionParameterMetadata.cs: Evaluated as low risk
- src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionReturnParameterMetadata.cs: Evaluated as low risk
- test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Functions/AIFunctionReturnParameterMetadataTests.cs: Evaluated as low risk
- src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIModelMapper.ChatCompletion.cs: Evaluated as low risk
- src/Libraries/Microsoft.Extensions.AI/Functions/AIFunctionFactoryCreateOptions.cs: Evaluated as low risk
- test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Contents/FunctionCallContentTests..cs: Evaluated as low risk
- test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAISerializationTests.cs: Evaluated as low risk
- test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Functions/AIFunctionMetadataTests.cs: Evaluated as low risk
- src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionMetadata.cs: Evaluated as low risk
Comments suppressed due to low confidence (8)
src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Schema.cs:84
- The defaultValue is being serialized without checking if it's null. Add a null check before serializing the defaultValue.
defaultValue: parameter.HasDefaultValue ? parameter.DefaultValue : null,
src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Schema.cs:81
- Ensure that the parameterName is not null or empty before using it. This will prevent any potential runtime errors.
parameterName: parameter.Name,
src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Schema.cs:82
- Ensure that the description is not null or empty before using it. This will prevent any potential runtime errors.
description: parameter.GetCustomAttribute<DescriptionAttribute>(inherit: true)?.Description,
test/Libraries/Microsoft.Extensions.AI.Tests/Functions/AIFunctionFactoryTest.cs:136
- [nitpick] The variable name 'dotnetFunc' is not descriptive. It should be renamed to something more meaningful, such as 'testFunction'.
Func<string> dotnetFunc = () => "test";
test/Libraries/Microsoft.Extensions.AI.Tests/Functions/AIFunctionFactoryTest.cs:142
- [nitpick] The variable name 'dotnetFunc2' is not descriptive. It should be renamed to something more meaningful, such as 'concatenateFunction'.
Func<string, string> dotnetFunc2 = (string a) => a + " " + a;
test/Libraries/Microsoft.Extensions.AI.Tests/Functions/AIFunctionFactoryTest.cs:148
- [nitpick] The variable name 'dotnetFunc3' is not descriptive. It should be renamed to something more meaningful, such as 'descriptionFunction'.
Func<string, string, string> dotnetFunc3 = [Description("This is a test function")] ([Description("This is A")] string a, [Description("This is B")] string b) => b + " " + a;
src/Libraries/Microsoft.Extensions.AI/Functions/AIFunctionFactory.cs:367
- The new implementation does not include parameter descriptions in the GetParameterMarshaller method.
return (IReadOnlyDictionary<string, object?> arguments, AIFunctionContext? _) =>
src/Libraries/Microsoft.Extensions.AI/Functions/AIFunctionFactory.cs:264
- The return type description is not explicitly handled in the new implementation.
UnderlyingMethod = method,
🎉 Good job! The coverage increased 🎉
Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=950025&view=codecoverage-tab |
src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionMetadata.cs
Outdated
Show resolved
Hide resolved
src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionMetadata.cs
Outdated
Show resolved
Hide resolved
src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionMetadata.cs
Outdated
Show resolved
Hide resolved
src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Schema.cs
Outdated
Show resolved
Hide resolved
.../Libraries/Microsoft.Extensions.AI.Integration.Tests/PromptBasedFunctionCallingChatClient.cs
Outdated
Show resolved
Hide resolved
…IFunctionMetadata.cs Co-authored-by: Stephen Toub <stoub@microsoft.com>
…IFunctionMetadata.cs Co-authored-by: Stephen Toub <stoub@microsoft.com>
🎉 Good job! The coverage increased 🎉
Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=950291&view=codecoverage-tab |
@SteveSandersonMS what do you think? Is this a step in the right direction? |
src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionMetadata.cs
Outdated
Show resolved
Hide resolved
src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Schema.cs
Outdated
Show resolved
Hide resolved
src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Schema.cs
Outdated
Show resolved
Hide resolved
@eiriktsarpalis @stephentoub Can you summarize the design intent? I've read through the implementation and simplifying things certainly looks good and beneficial. But it's not obvious initially why we can get away with just removing all the metadata, unless it was just not serving a purpose before. My guess is that you've identified that it was an unnecessary extra level of indirection, e.g.:
At least, this lines up with my memory of the initial design, though I know that may have already changed. I know there was initially a lot of debate about to what extent we're willing to make a strong assumption that JSON schema is the one true format for function descriptions.
It's not clear to me which properties would remain. In this PR you've removed our abstract representation for parameter metadata, but left the abstract representation for function-level metadata (name, description). Is the intent that |
One use case for The presence of Given that
I think this has always been the assumption, what we've been changing recently (particularly with #5826) is how explicit this is being made in the API contract. We originally exposed an Assuming a new schematization format does come around in the future, the
I've kept those since they are required values in envelopes that contain the function schema. The "description" keyword is optional in JSON schema and "name" does not exist per se -- the canonical keyword in this case is "title". @stephentoub made the point that he would like to see |
I guess I'm less clear now on how to understand the situation. Could you give an outline of what's happening in this situation? Who's providing data to who else and what are they going to do with it? My guess is that, if you're on the server end of an You mention that the instances are meant to be forwarded to other chat services but surely somewhere at the end of this line, the final recipient needs the full metadata (including parameter types) in order to be able to generate valid calls to those tools. In what situation do you need a name and description but no definition of the parameter schema?
Not sure how to interpret the example given (
This sounds like JSON schema has an official spec for how functions would be represented. Is that the case? I'm guessing not. So if this is an informally-defined way to represent functions, basically just taking the de-facto standard from OpenAI, what difference does it make what is canonical for JSON schema? Apologies if my lack of context here is slowing things down. Please don't interpret any of it as blocking this change, which almost certainly is a good thing since it's removing complexity. |
Why would it need the .NET types to do so? The final recipient needn't be a .NET process; the contract is to generate argument data based on a schema that has been specified on the wire. Only an AIFunctoin that needs to invoke an underlying .NET method requires type information so that it can marshal and unmarshal data.
The "parameters" property used in Ollama (and OpenAI as well) is a bit of a misnomer since it actually contains a complete JSON schema and not just parameter keywords. Here's what the corresponding model in our code looks like: extensions/src/Libraries/Microsoft.Extensions.AI.Ollama/OllamaFunctionToolParameters.cs Lines 9 to 14 in 89b0d7e
In other words, "parameters" should be thought of as the JSON schema for parameterizing the function, but the actual schemas for individual inputs are nested inside a "properties" keyword -- in accordance with JSON schema specification.
I haven't tested, but my expection is that it would always be mandatory. Since my previous change the
Correct. De facto, schemas for functions model a pseudo-object that lists all function parameters as its properties. There are some deviations here, for example OpenAI has coined the "function" type although in my experiements it seems happy with
|
We wouldn't need to have Name and Description on AIFunction: Schema is required, and name and description are part of the schema. Having them as first-class members on AIFunction highlights them as being something that might be desirable for consumption for reasons other than function calling, e.g. for diagnostics, for telemetry, for display in a UI when getting approval from the user whether it's ok to invoke a particular function, etc. They would be duplicative, and in that sense they could just be accelerators for pulling specific pieces of information out of the schema, rather than being actually duplicate information. That's more valuable I think if we pull them down to the base AITool, where it seems like having such a Name and Description are useful for similar purposes, and where parameters aren't as applicable because there aren't necessarily parameters; the base type isn't directly invocable. As an example, OpenAI, Gemini, and Bedrock all support the concept of server-side code interpretation, so we'll likely want to expose a CodeInterpreterAITool : AITool that can be put into the Tools collection as a signal to the service that it can enable code interpretation. That won't have a schema, but it could still have a Name/Description we provide so that there's some human-consumable about it when enumerating Tools. AIFunction could override those members to pull out the relevant portions of the schema. Again, we don't have to expose Name/Description. We just might want to. |
Thanks @eiriktsarpalis and @stephentoub. Lots of it is clearer now. In particular the benefit of retaining name/description properties to simplify telemetry/debugging etc makes a lot of sense. I'm understanding now that So yes this all does seem like a good direction. Thanks for explaining the details! |
…IJsonUtilities.Schema.cs Co-authored-by: Steve Sanderson <SteveSandersonMS@users.noreply.github.com>
🎉 Good job! The coverage increased 🎉
Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=951531&view=codecoverage-tab |
src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunction.cs
Show resolved
Hide resolved
src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunction.cs
Outdated
Show resolved
Hide resolved
src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunction.cs
Outdated
Show resolved
Hide resolved
src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunction.cs
Outdated
Show resolved
Hide resolved
🎉 Good job! The coverage increased 🎉
Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=951694&view=codecoverage-tab |
🎉 Good job! The coverage increased 🎉
Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=951788&view=codecoverage-tab |
@@ -35,10 +35,10 @@ public JsonSerializerOptions SerializerOptions | |||
/// <summary> | |||
/// Gets or sets the <see cref="AIJsonSchemaCreateOptions"/> governing the generation of JSON schemas for the function. | |||
/// </summary> | |||
public AIJsonSchemaCreateOptions SchemaCreateOptions | |||
public AIJsonSchemaCreateOptions JsonSchemaCreateOptions |
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.
Would it make sense at this point for JsonSchemaCreateOptions and SerializerOptions to be nullable, and then just substitute the default values if they're null when actually constructing the AIFunction? It's not clear to me at this point why that's how Name/Description/AdditionalProperties work but not how these work.
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.
We could do that. Making JSO non-nullable specifically is a holdover from when the factory APIs not accepting an explicit JSO were being marked RUC/RDC.
Removes both
AIFunctionParameterMetadata
andAIFunctionReturnParameterMetadata
, replacing both with an optionalMethodInfo? UnderlyingMethod
property.Me and @stephentoub discussed possibly removing
AIFunctionMetadata
altogether and flattening all its remaining properties onAIFunction
itself. This PR stops short of that so we can gather feedback on the basis of this initial removal.Microsoft Reviewers: Open in CodeFlow