Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Qu’est-ce qu’une réponse diffusée en continu ?
Une réponse diffusée fournit le contenu du message en petits blocs de données petit à petit. Cette approche améliore l’expérience utilisateur en leur permettant d’afficher et d’interagir avec le message au fur et à mesure qu’il se déroule, plutôt que d’attendre la totalité de la réponse à charger. Les utilisateurs peuvent commencer à traiter immédiatement les informations, ce qui améliore le sens de la réactivité et de l’interactivité. Par conséquent, il réduit les retards et maintient les utilisateurs plus engagés tout au long du processus de communication.
Références de streaming
- OpenAI Streaming Guide
- Streaming de finalisation de chat OpenAI
- Diffusion en continu de l’Assistant OpenAI
- Azure OpenAI Service REST API
Streaming dans le noyau sémantique
Les services IA qui prennent en charge la diffusion en continu dans le noyau sémantique utilisent différents types de contenu par rapport à ceux utilisés pour les messages entièrement formés. Ces types de contenu sont spécifiquement conçus pour gérer la nature incrémentielle des données de streaming. Les mêmes types de contenu sont également utilisés dans l’Infrastructure de l’agent à des fins similaires. Cela garantit la cohérence et l’efficacité entre les deux systèmes lors de la gestion des informations de diffusion en continu.
Conseil / Astuce
Informations de référence sur l’API :
Conseil / Astuce
Informations de référence sur l’API :
Fonctionnalité actuellement indisponible en Java.
Réponse diffusée en continu à partir de ChatCompletionAgent
Lors de l'appel d'une réponse diffusée en continu à partir d'un ChatCompletionAgent, le ChatHistory dans le AgentThread est mis à jour après la réception de la réponse complète. Bien que la réponse soit diffusée de manière incrémentielle, l’historique enregistre uniquement le message complet. Cela garantit que les ChatHistory reflètent des réponses complètement formées pour assurer la cohérence.
// Define agent
ChatCompletionAgent agent = ...;
ChatHistoryAgentThread agentThread = new();
// Create a user message
var message = ChatMessageContent(AuthorRole.User, "<user input>");
// Generate the streamed agent response(s)
await foreach (StreamingChatMessageContent response in agent.InvokeStreamingAsync(message, agentThread))
{
// Process streamed response(s)...
}
// It's also possible to read the messages that were added to the ChatHistoryAgentThread.
await foreach (ChatMessageContent response in agentThread.GetMessagesAsync())
{
// Process messages...
}
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
# Define agent
agent = ChatCompletionAgent(...)
# Create a thread object to maintain the conversation state.
# If no thread is provided one will be created and returned with
# the initial response.
thread: ChatHistoryAgentThread = None
# Generate the streamed agent response(s)
async for response in agent.invoke_stream(messages="user input", thread=thread)
{
# Process streamed response(s)...
thread = response.thread
}
Fonctionnalité actuellement indisponible en Java.
Réponse diffusée en continu à partir de OpenAIAssistantAgent
Lors de l’appel d’une réponse en flux continu à partir d’un OpenAIAssistantAgent, l’Assistant conserve l’état de la conversation en tant que fil distant. Il est possible de lire les messages à partir du thread distant si nécessaire.
// Define agent
OpenAIAssistantAgent agent = ...;
// Create a thread for the agent conversation.
OpenAIAssistantAgentThread agentThread = new(assistantClient);
// Create a user message
var message = new ChatMessageContent(AuthorRole.User, "<user input>");
// Generate the streamed agent response(s)
await foreach (StreamingChatMessageContent response in agent.InvokeStreamingAsync(message, agentThread))
{
// Process streamed response(s)...
}
// It's possible to read the messages from the remote thread.
await foreach (ChatMessageContent response in agentThread.GetMessagesAsync())
{
// Process messages...
}
// Delete the thread when it is no longer needed
await agentThread.DeleteAsync();
Pour créer un thread à l’aide d’un thread existant Id, passez-le au constructeur de OpenAIAssistantAgentThread:
// Define agent
OpenAIAssistantAgent agent = ...;
// Create a thread for the agent conversation.
OpenAIAssistantAgentThread agentThread = new(assistantClient, "your-existing-thread-id");
// Create a user message
var message = new ChatMessageContent(AuthorRole.User, "<user input>");
// Generate the streamed agent response(s)
await foreach (StreamingChatMessageContent response in agent.InvokeStreamingAsync(message, agentThread))
{
// Process streamed response(s)...
}
// It's possible to read the messages from the remote thread.
await foreach (ChatMessageContent response in agentThread.GetMessagesAsync())
{
// Process messages...
}
// Delete the thread when it is no longer needed
await agentThread.DeleteAsync();
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent, OpenAIAssistantAgent
# Define agent
agent = OpenAIAssistantAgent(...) # or = AzureAssistantAgent(...)
# Create a thread for the agent conversation.
# If no thread is provided one will be created and returned with
# the initial response.
thread: AssistantAgentThread = None
# Generate the streamed agent response(s)
async for response in agent.invoke_stream(messages="user input", thread=thread):
# Process streamed response(s)...
thread = response.thread
# Read the messages from the remote thread
async for response in thread.get_messages():
# Process messages
# Delete the thread
await thread.delete()
Pour créer un thread à l’aide d’un thread existant thread_id, passez-le au constructeur de AssistantAgentThread:
from semantic_kernel.agents import AssistantAgentThread, AzureAssistantAgent, OpenAIAssistantAgent
# Define agent
agent = OpenAIAssistantAgent(...) # or = AzureAssistantAgent(...)
# Create a thread for the agent conversation.
# If no thread is provided one will be created and returned with
# the initial response.
thread = AssistantAgentThread(client=client, thread_id="your-existing-thread-id")
# Generate the streamed agent response(s)
async for response in agent.invoke_stream(messages="user input", thread=thread):
# Process streamed response(s)...
thread = response.thread
# Delete the thread
await thread.delete()
Fonctionnalité actuellement indisponible en Java.
Gestion des messages intermédiaires avec une réponse en flux
La nature des réponses de diffusion en continu permet aux modèles LLM de retourner des blocs de texte incrémentiels, ce qui permet un rendu plus rapide dans une interface utilisateur ou une console sans attendre la fin de la réponse entière. En outre, un appelant peut vouloir gérer du contenu intermédiaire, tel que les résultats des appels de fonction. Pour ce faire, fournissez une fonction de rappel lors de l’utilisation de la réponse en flux. La fonction de rappel reçoit les messages complets encapsulés dans ChatMessageContent.
La documentation du callback pour
AzureAIAgentsera bientôt disponible.
La configuration de la fonction de rappel on_intermediate_message permet à l'appelant de agent.invoke_stream(...) recevoir des messages intermédiaires générés durant la formulation de la réponse finale de l'agent.
import asyncio
from typing import Annotated
from semantic_kernel.agents import AzureResponsesAgent
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
from semantic_kernel.functions import kernel_function
# Define a sample plugin for the sample
class MenuPlugin:
"""A sample Menu Plugin used for the concept sample."""
@kernel_function(description="Provides a list of specials from the menu.")
def get_specials(self, menu_item: str) -> Annotated[str, "Returns the specials from the menu."]:
return """
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
"""
@kernel_function(description="Provides the price of the requested menu item.")
def get_item_price(
self, menu_item: Annotated[str, "The name of the menu item."]
) -> Annotated[str, "Returns the price of the menu item."]:
return "$9.99"
# This callback function will be called for each intermediate message,
# which will allow one to handle FunctionCallContent and FunctionResultContent.
# If the callback is not provided, the agent will return the final response
# with no intermediate tool call steps.
async def handle_streaming_intermediate_steps(message: ChatMessageContent) -> None:
for item in message.items or []:
if isinstance(item, FunctionResultContent):
print(f"Function Result:> {item.result} for function: {item.name}")
elif isinstance(item, FunctionCallContent):
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
else:
print(f"{item}")
# Simulate a conversation with the agent
USER_INPUTS = [
"Hello",
"What is the special soup?",
"What is the special drink?",
"How much is it?",
"Thank you",
]
async def main():
# 1. Create the client using OpenAI resources and configuration
client, model = AzureResponsesAgent.setup_resources()
# 2. Create a Semantic Kernel agent for the OpenAI Responses API
agent = AzureResponsesAgent(
ai_model_id=model,
client=client,
instructions="Answer questions about the menu.",
name="Host",
plugins=[MenuPlugin()],
)
# 3. Create a thread for the agent
# If no thread is provided, a new thread will be
# created and returned with the initial response
thread = None
try:
for user_input in user_inputs:
print(f"# {AuthorRole.USER}: '{user_input}'")
first_chunk = True
async for response in agent.invoke_stream(
messages=user_input,
thread=thread,
on_intermediate_message=handle_streaming_intermediate_steps,
):
thread = response.thread
if first_chunk:
print(f"# {response.name}: ", end="", flush=True)
first_chunk = False
print(response.content, end="", flush=True)
print()
finally:
await thread.delete() if thread else None
if __name__ == "__main__":
asyncio.run(main())
Voici un exemple de résultat du processus d'invocation de l'agent :
Sample Output:
# AuthorRole.USER: 'Hello'
# Host: Hello! How can I assist you with the menu today?
# AuthorRole.USER: 'What is the special soup?'
Function Call:> MenuPlugin-get_specials with arguments: {}
Function Result:>
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
for function: MenuPlugin-get_specials
# Host: The special soup today is Clam Chowder. Would you like to know more about it or hear about other specials?
# AuthorRole.USER: 'What is the special drink?'
# Host: The special drink today is Chai Tea. Would you like more details or are you interested in ordering it?
# AuthorRole.USER: 'How much is that?'
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Chai Tea"}
Function Result:> $9.99 for function: MenuPlugin-get_item_price
# Host: The special drink, Chai Tea, is $9.99. Would you like to order one or need information on something else?
# AuthorRole.USER: 'Thank you'
# Host: You're welcome! If you have any more questions or need help with the menu, just let me know. Enjoy your day!
Fonctionnalité actuellement indisponible en Java.