Skip to content
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: KernelFunctionSelectionStrategy.SelectAgentAsync and KernelFunctionTerminationStrategy.ShouldAgentTerminateAsync does not support streaming. #11505

Open
0xLiao opened this issue Apr 11, 2025 · 0 comments
Labels
bug Something isn't working .NET Issue or Pull requests regarding .NET code triage

Comments

@0xLiao
Copy link

0xLiao commented Apr 11, 2025

While following the documentation to use the Agent Collaboration capability, since the model only supports streaming mode, I modified

await foreach (ChatMessageContent response in chat.InvokeAsync())

to

await foreach (StreamingChatMessageContent response in chat.InvokeStreamingAsync())

The first Agent sent the request with streaming enabled, send:

"model":"Qwen/QwQ-32B","stream":true,"stream_options":{"include_usage":true}"

but immediately threw an exception afterward.

{"error":{"code":"invalid_parameter_error","param":null,"message":"This model only support stream mode, please enable the stream parameter to access the model. ","type":"invalid_request_error"}
      Microsoft.SemanticKernel.HttpOperationException: HTTP 400 (: 10137)
System.AggregateException: One or more errors occurred. (HTTP 400 (: 10137
)

After analyzing, I found that while the first request uses streaming mode, it switches to non-streaming when .SelectAgentAsync selects the next Agent:

at Microsoft.SemanticKernel.Connectors.OpenAI.ClientCore.RunRequestAsync[T](Func`1 request)
   at Microsoft.SemanticKernel.Connectors.OpenAI.ClientCore.GetChatMessageContentsAsync(String targetModel, ChatHistory chatHistory, PromptExecutionSettings executionSettings, Kernel kernel, CancellationToken cancellationToken)
   at Microsoft.SemanticKernel.KernelFunctionFromPrompt.GetChatCompletionResultAsync(IChatCompletionService chatCompletion, Kernel kernel, PromptRenderingResult promptRenderingResult, CancellationToken cancellationToken)
   at Microsoft.SemanticKernel.KernelFunctionFromPrompt.InvokeCoreAsync(Kernel kernel, KernelArguments arguments, CancellationToken cancellationToken)
   at Microsoft.SemanticKernel.KernelFunction.<>c__DisplayClass27_0.<<InvokeAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.SemanticKernel.Kernel.InvokeFilterOrFunctionAsync(NonNullCollection`1 functionFilters, Func`2 functionCallback, FunctionInvocationContext context, Int32 index)
   at Microsoft.SemanticKernel.Kernel.OnFunctionInvocationAsync(KernelFunction function, KernelArguments arguments, FunctionResult functionResult, Boolean isStreaming, Func`2 functionCallback, CancellationToken cancellationToken)
   at Microsoft.SemanticKernel.KernelFunction.InvokeAsync(Kernel kernel, KernelArguments arguments, CancellationToken cancellationToken)
   at Microsoft.SemanticKernel.Agents.Chat.KernelFunctionSelectionStrategy.SelectAgentAsync(IReadOnlyList`1 agents, IReadOnlyList`1 history, CancellationToken cancellationToken)
   at Microsoft.SemanticKernel.Agents.Chat.SelectionStrategy.NextAsync(IReadOnlyList`1 agents, IReadOnlyList`1 history, CancellationToken cancellationToken)
   at Microsoft.SemanticKernel.Agents.AgentGroupChat.SelectAgentAsync(CancellationToken cancellationToken)
   at Microsoft.SemanticKernel.Agents.AgentGroupChat.InvokeStreamingAsync(CancellationToken cancellationToken)+MoveNext()

Although I explicitly used AgentGroupChat.InvokeStreamingAsync, the KernelFunctionSelectionStrategy.SelectAgentAsync method always calls KernelFunction.InvokeAsync internally. I found in the source code that it's hardcoded to use non-streaming invocation without any streaming support:

    protected sealed override async Task<Agent> SelectAgentAsync(IReadOnlyList<Agent> agents, IReadOnlyList<ChatMessageContent> history, CancellationToken cancellationToken = default)
    {
        history = await history.ReduceAsync(this.HistoryReducer, cancellationToken).ConfigureAwait(false);

        KernelArguments originalArguments = this.Arguments ?? [];
        KernelArguments arguments =
            new(originalArguments, originalArguments.ExecutionSettings?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value))
            {
                { this.AgentsVariableName, string.Join(",", agents.Select(a => a.Name)) },
                { this.HistoryVariableName, ChatMessageForPrompt.Format(history, this.EvaluateNameOnly) },
            };

        this.Logger.LogKernelFunctionSelectionStrategyInvokingFunction(nameof(NextAsync), this.Function.PluginName, this.Function.Name);

        FunctionResult result = await this.Function.InvokeAsync(this.Kernel, arguments, cancellationToken).ConfigureAwait(false);

It appears there's no external configuration option to force streaming mode behavior in this case.

Platform

  • .NET
  • Microsoft.SemanticKernel 1.45.0
  • model: Qwen/QwQ-32B
  • Windows, Mac
@0xLiao 0xLiao added the bug Something isn't working label Apr 11, 2025
@markwallace-microsoft markwallace-microsoft added .NET Issue or Pull requests regarding .NET code triage labels Apr 11, 2025
@github-actions github-actions bot changed the title .NET: KernelFunctionSelectionStrategy.SelectAgentAsync and KernelFunctionTerminationStrategy.ShouldAgentTerminateAsync does not support streaming. .Net: KernelFunctionSelectionStrategy.SelectAgentAsync and KernelFunctionTerminationStrategy.ShouldAgentTerminateAsync does not support streaming. Apr 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working .NET Issue or Pull requests regarding .NET code triage
Projects
None yet
Development

No branches or pull requests

2 participants