chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
# Chat Completion Agent Samples
|
||||
|
||||
The following samples demonstrate advanced usage of the `ChatCompletionAgent`.
|
||||
|
||||
---
|
||||
|
||||
## Chat History Reduction Strategies
|
||||
|
||||
When configuring chat history management, there are two important settings to consider:
|
||||
|
||||
### `reducer_msg_count`
|
||||
|
||||
- **Purpose:** Defines the target number of messages to retain after applying truncation or summarization.
|
||||
- **Controls:** Determines how much recent conversation history is preserved, while older messages are either discarded or summarized.
|
||||
- **Recommendations for adjustment:**
|
||||
- **Smaller values:** Ideal for memory-constrained environments or scenarios where brief context is sufficient.
|
||||
- **Larger values:** Useful when retaining extensive conversational context is critical for accurate responses or complex dialogue.
|
||||
|
||||
### `reducer_threshold`
|
||||
|
||||
- **Purpose:** Provides a buffer to prevent premature reduction when the message count slightly exceeds `reducer_msg_count`.
|
||||
- **Controls:** Ensures essential message pairs (e.g., a user query and the assistant’s response) aren't unintentionally truncated.
|
||||
- **Recommendations for adjustment:**
|
||||
- **Smaller values:** Use to enforce stricter message reduction criteria, potentially truncating older message pairs sooner.
|
||||
- **Larger values:** Recommended for preserving critical conversation segments, particularly in sensitive interactions involving API function calls or detailed responses.
|
||||
|
||||
### Interaction Between Parameters
|
||||
|
||||
The combination of these parameters determines **when** history reduction occurs and **how much** of the conversation is retained.
|
||||
|
||||
**Example:**
|
||||
- If `reducer_msg_count = 10` and `reducer_threshold = 5`, message history won't be truncated until the total message count exceeds 15. This strategy maintains conversational context flexibility while respecting memory limitations.
|
||||
|
||||
---
|
||||
|
||||
## Recommendations for Effective Configuration
|
||||
|
||||
- **Performance-focused environments:**
|
||||
- Lower `reducer_msg_count` to conserve memory and accelerate processing.
|
||||
|
||||
- **Context-sensitive scenarios:**
|
||||
- Higher `reducer_msg_count` and `reducer_threshold` help maintain continuity across multiple interactions, crucial for multi-turn conversations or complex workflows.
|
||||
|
||||
- **Iterative Experimentation:**
|
||||
- Start with default values (`reducer_msg_count = 10`, `reducer_threshold = 10`), and adjust according to the specific behavior and response quality required by your application.
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel import Kernel
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.filters import FunctionInvocationContext
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create Chat Completion Agents
|
||||
and use them as tools available for a Triage Agent to delegate requests
|
||||
to the appropriate agent. A Function Invocation Filter is used to show
|
||||
the function call content and the function result content so the caller
|
||||
can see which agent was called and what the response was.
|
||||
"""
|
||||
|
||||
|
||||
# Define the auto function invocation filter that will be used by the kernel
|
||||
async def function_invocation_filter(context: FunctionInvocationContext, next):
|
||||
"""A filter that will be called for each function call in the response."""
|
||||
if "messages" not in context.arguments:
|
||||
await next(context)
|
||||
return
|
||||
print(f" Agent [{context.function.name}] called with messages: {context.arguments['messages']}")
|
||||
await next(context)
|
||||
print(f" Response from agent [{context.function.name}]: {context.result.value}")
|
||||
|
||||
|
||||
# Create and configure the kernel.
|
||||
kernel = Kernel()
|
||||
|
||||
# The filter is used for demonstration purposes to show the function invocation.
|
||||
kernel.add_filter("function_invocation", function_invocation_filter)
|
||||
|
||||
credential = AzureCliCredential()
|
||||
|
||||
billing_agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
name="BillingAgent",
|
||||
instructions=(
|
||||
"You specialize in handling customer questions related to billing issues. "
|
||||
"This includes clarifying invoice charges, payment methods, billing cycles, "
|
||||
"explaining fees, addressing discrepancies in billed amounts, updating payment details, "
|
||||
"assisting with subscription changes, and resolving payment failures. "
|
||||
"Your goal is to clearly communicate and resolve issues specifically about payments and charges."
|
||||
),
|
||||
)
|
||||
|
||||
refund_agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
name="RefundAgent",
|
||||
instructions=(
|
||||
"You specialize in addressing customer inquiries regarding refunds. "
|
||||
"This includes evaluating eligibility for refunds, explaining refund policies, "
|
||||
"processing refund requests, providing status updates on refunds, handling complaints related to refunds, "
|
||||
"and guiding customers through the refund claim process. "
|
||||
"Your goal is to assist users clearly and empathetically to successfully resolve their refund-related concerns."
|
||||
),
|
||||
)
|
||||
|
||||
triage_agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
kernel=kernel,
|
||||
name="TriageAgent",
|
||||
instructions=(
|
||||
"Your role is to evaluate the user's request and forward it to the appropriate agent based on the nature of "
|
||||
"the query. Forward requests about charges, billing cycles, payment methods, fees, or payment issues to the "
|
||||
"BillingAgent. Forward requests concerning refunds, refund eligibility, refund policies, or the status of "
|
||||
"refunds to the RefundAgent. Your goal is accurate identification of the appropriate specialist to ensure the "
|
||||
"user receives targeted assistance."
|
||||
),
|
||||
plugins=[billing_agent, refund_agent],
|
||||
)
|
||||
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
|
||||
async def chat() -> bool:
|
||||
"""
|
||||
Continuously prompt the user for input and show the assistant's response.
|
||||
Type 'exit' to exit.
|
||||
"""
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
if user_input.lower().strip() == "exit":
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
response = await triage_agent.get_response(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
)
|
||||
|
||||
if response:
|
||||
print(f"Agent :> {response}")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
User:> I was charged twice for my subscription last month, can I get one of those payments refunded?
|
||||
Agent [BillingAgent] called with messages: I was charged twice for my subscription last month.
|
||||
Agent [RefundAgent] called with messages: Can I get one of those payments refunded?
|
||||
Response from agent RefundAgent: Of course, I'll be happy to help you with your refund inquiry. Could you please
|
||||
provide a bit more detail about the specific payment you are referring to? For instance, the item or service
|
||||
purchased, the transaction date, and the reason why you're seeking a refund? This will help me understand your
|
||||
situation better and provide you with accurate guidance regarding our refund policy and process.
|
||||
Response from agent BillingAgent: I'm sorry to hear about the duplicate charge. To resolve this issue, could
|
||||
you please provide the following details:
|
||||
|
||||
1. The date(s) of the transaction(s).
|
||||
2. The last four digits of the card used for the transaction or any other payment method details.
|
||||
3. The subscription plan you are on.
|
||||
|
||||
Once I have this information, I can look into the charges and help facilitate a refund for the duplicate transaction.
|
||||
Let me know if you have any questions in the meantime!
|
||||
|
||||
Agent :> To address your concern about being charged twice and seeking a refund for one of those payments, please
|
||||
provide the following information:
|
||||
|
||||
1. **Duplicate Charge Details**: Please share the date(s) of the transaction(s), the last four digits of the card used
|
||||
or details of any other payment method, and the subscription plan you are on. This information will help us verify
|
||||
the duplicate charge and assist you with a refund.
|
||||
|
||||
2. **Refund Inquiry Details**: Please specify the transaction date, the item or service related to the payment you want
|
||||
refunded, and the reason why you're seeking a refund. This will allow us to provide accurate guidance concerning
|
||||
our refund policy and process.
|
||||
|
||||
Once we have these details, we can proceed with resolving the duplicate charge and consider your refund request. If you
|
||||
have any more questions, feel free to ask!
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
print("Welcome to the chat bot!\n Type 'exit' to exit.\n Try to get some billing or refund help.")
|
||||
chatting = True
|
||||
while chatting:
|
||||
chatting = await chat()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
|
||||
from semantic_kernel.filters import AutoFunctionInvocationContext
|
||||
from semantic_kernel.functions import kernel_function
|
||||
from semantic_kernel.kernel import Kernel
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to configure the auto
|
||||
function invocation filter while using a ChatCompletionAgent.
|
||||
This allows the developer or user to view the function call content
|
||||
and the function result content.
|
||||
"""
|
||||
|
||||
|
||||
# Define the auto function invocation filter that will be used by the kernel
|
||||
async def auto_function_invocation_filter(context: AutoFunctionInvocationContext, next):
|
||||
"""A filter that will be called for each function call in the response."""
|
||||
# if we don't call next, it will skip this function, and go to the next one
|
||||
await next(context)
|
||||
if context.function.plugin_name == "menu":
|
||||
context.terminate = True
|
||||
|
||||
|
||||
# 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) -> 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"
|
||||
|
||||
|
||||
def _create_kernel_with_chat_completionand_filter() -> Kernel:
|
||||
"""A helper function to create a kernel with a chat completion service and a filter."""
|
||||
kernel = Kernel()
|
||||
kernel.add_service(AzureChatCompletion(credential=AzureCliCredential()))
|
||||
kernel.add_filter("auto_function_invocation", auto_function_invocation_filter)
|
||||
kernel.add_plugin(plugin=MenuPlugin(), plugin_name="menu")
|
||||
return kernel
|
||||
|
||||
|
||||
def _write_content(content: ChatMessageContent) -> None:
|
||||
"""Write the content to the console based on the content type."""
|
||||
last_item_type = type(content.items[-1]).__name__ if content.items else "(empty)"
|
||||
message_content = ""
|
||||
if isinstance(last_item_type, FunctionCallContent):
|
||||
message_content = f"tool request = {content.items[-1].function_name}"
|
||||
elif isinstance(last_item_type, FunctionResultContent):
|
||||
message_content = f"function result = {content.items[-1].result}"
|
||||
else:
|
||||
message_content = str(content.items[-1])
|
||||
print(f"[{last_item_type}] {content.role} : '{message_content}'")
|
||||
|
||||
|
||||
async def main():
|
||||
# 1. Create the agent with a kernel instance that contains
|
||||
# the auto function invocation filter and the AI service
|
||||
agent = ChatCompletionAgent(
|
||||
kernel=_create_kernel_with_chat_completionand_filter(),
|
||||
name="Host",
|
||||
instructions="Answer questions about the menu.",
|
||||
)
|
||||
|
||||
# 2. Define the thread
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"What is the special drink?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input}'")
|
||||
# 3. Get the response from the agent
|
||||
response = await agent.get_response(messages=user_input, thread=thread)
|
||||
thread = response.thread
|
||||
_write_content(response)
|
||||
|
||||
print("================================")
|
||||
print("CHAT HISTORY")
|
||||
print("================================")
|
||||
|
||||
# 4. Print out the chat history to view the different types of messages
|
||||
async for message in thread.get_messages():
|
||||
_write_content(message)
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# AuthorRole.USER: 'Hello'
|
||||
[TextContent] AuthorRole.ASSISTANT : 'Hello! How can I assist you today?'
|
||||
# AuthorRole.USER: 'What is the special soup?'
|
||||
[FunctionResultContent] AuthorRole.TOOL : '
|
||||
Special Soup: Clam Chowder
|
||||
Special Salad: Cobb Salad
|
||||
Special Drink: Chai Tea
|
||||
'
|
||||
# AuthorRole.USER: 'What is the special drink?'
|
||||
[TextContent] AuthorRole.ASSISTANT : 'The special drink is Chai Tea.'
|
||||
# AuthorRole.USER: 'Thank you'
|
||||
[TextContent] AuthorRole.ASSISTANT : 'You're welcome! If you have any more questions or need assistance with
|
||||
anything else, feel free to ask!'
|
||||
================================
|
||||
CHAT HISTORY
|
||||
================================
|
||||
[TextContent] AuthorRole.USER : 'Hello'
|
||||
[TextContent] AuthorRole.ASSISTANT : 'Hello! How can I assist you today?'
|
||||
[TextContent] AuthorRole.USER : 'What is the special soup?'
|
||||
[FunctionCallContent] AuthorRole.ASSISTANT : 'menu-get_specials({})'
|
||||
[FunctionResultContent] AuthorRole.TOOL : '
|
||||
Special Soup: Clam Chowder
|
||||
Special Salad: Cobb Salad
|
||||
Special Drink: Chai Tea
|
||||
'
|
||||
[TextContent] AuthorRole.USER : 'What is the special drink?'
|
||||
[TextContent] AuthorRole.ASSISTANT : 'The special drink is Chai Tea.'
|
||||
[TextContent] AuthorRole.USER : 'Thank you'
|
||||
[TextContent] AuthorRole.ASSISTANT : 'You're welcome! If you have any more questions or need assistance with
|
||||
anything else, feel free to ask!'
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents.chat_completion.chat_completion_agent import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai.services.azure_chat_completion import AzureChatCompletion
|
||||
from semantic_kernel.contents import FunctionCallContent, FunctionResultContent
|
||||
from semantic_kernel.contents.chat_message_content import ChatMessageContent
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion agent
|
||||
and use it with functions. In order to answer user questions, the
|
||||
agent internally uses the functions. These internal steps are returned
|
||||
to the user as part of the agent's response. Thus, the invoke method
|
||||
configures a message callback to receive the agent's internal messages.
|
||||
|
||||
The agent is configured to use a plugin that provides a list of
|
||||
specials from the menu and the price of the requested menu item.
|
||||
"""
|
||||
|
||||
|
||||
# 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) -> 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_intermediate_steps(message: ChatMessageContent) -> None:
|
||||
for item in message.items or []:
|
||||
if isinstance(item, FunctionCallContent):
|
||||
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
|
||||
elif isinstance(item, FunctionResultContent):
|
||||
print(f"Function Result:> {item.result} for function: {item.name}")
|
||||
else:
|
||||
print(f"{message.role}: {message.content}")
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="Assistant",
|
||||
instructions="Answer questions about the menu.",
|
||||
plugins=[MenuPlugin()],
|
||||
)
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"How much does that cost?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
for user_input in user_inputs:
|
||||
print(f"# User: '{user_input}'")
|
||||
async for response in agent.invoke(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
on_intermediate_message=handle_intermediate_steps,
|
||||
):
|
||||
print(f"# {response.role}: {response}")
|
||||
thread = response.thread
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Hello'
|
||||
# AuthorRole.ASSISTANT: Hi there! How can I assist you today?
|
||||
# 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
|
||||
# AuthorRole.ASSISTANT: The special soup today is Clam Chowder. Would you like to know anything else from the menu?
|
||||
# User: 'How much does that cost?'
|
||||
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Clam Chowder"}
|
||||
Function Result:> $9.99 for function: MenuPlugin-get_item_price
|
||||
# AuthorRole.ASSISTANT: The Clam Chowder costs $9.99. Would you like to know more about the menu or anything else?
|
||||
# User: 'Thank you'
|
||||
# AuthorRole.ASSISTANT: You're welcome! If you have any more questions, feel free to ask. Enjoy your day!
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion agent
|
||||
and use it with streaming responses. Additionally, the invoke_stream
|
||||
configures a message callback to receive fully formed messages once
|
||||
the streaming invocation is complete. The agent is configured to use
|
||||
a plugin that provides a list of specials from the menu and the price
|
||||
of the requested menu item.
|
||||
"""
|
||||
|
||||
|
||||
# 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) -> 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, FunctionCallContent):
|
||||
print(f"Function Call:> {item.name} with arguments: {item.arguments}")
|
||||
elif isinstance(item, FunctionResultContent):
|
||||
print(f"Function Result:> {item.result} for function: {item.name}")
|
||||
else:
|
||||
print(f"{message.role}: {message.content}")
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="Assistant",
|
||||
instructions="Answer questions about the menu.",
|
||||
plugins=[MenuPlugin()],
|
||||
)
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"How much does that cost?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
for user_input in user_inputs:
|
||||
print(f"\n# User: '{user_input}'")
|
||||
async for response in agent.invoke_stream(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
on_intermediate_message=handle_streaming_intermediate_steps,
|
||||
):
|
||||
if response.content:
|
||||
print(response.content, end="", flush=True)
|
||||
thread = response.thread
|
||||
print()
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Hello'
|
||||
Hello! How can I assist you today?
|
||||
|
||||
# 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
|
||||
The special soup today is Clam Chowder. Is there anything else you'd like to know?
|
||||
|
||||
# User: 'How much does that cost?'
|
||||
Function Call:> MenuPlugin-get_item_price with arguments: {"menu_item":"Clam Chowder"}
|
||||
Function Result:> $9.99 for function: MenuPlugin-get_item_price
|
||||
The Clam Chowder costs $9.99. Would you like to know anything else about the menu?
|
||||
|
||||
# User: 'Thank you'
|
||||
You're welcome! If you have any more questions, feel free to ask. Have a great day!
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.functions import KernelArguments
|
||||
from semantic_kernel.prompt_template import PromptTemplateConfig
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion
|
||||
agent using Azure OpenAI within Semantic Kernel.
|
||||
It uses parameterized prompts and shows how to swap between
|
||||
"semantic-kernel," "jinja2," and "handlebars" template formats,
|
||||
This sample highlights the agent's chat history conversation
|
||||
is managed and how kernel arguments are passed in and used.
|
||||
"""
|
||||
|
||||
# Define the inputs and styles to be used in the agent
|
||||
inputs = [
|
||||
("Home cooking is great.", None),
|
||||
("Talk about world peace.", "iambic pentameter"),
|
||||
("Say something about doing your best.", "e. e. cummings"),
|
||||
("What do you think about having fun?", "old school rap"),
|
||||
]
|
||||
|
||||
|
||||
async def invoke_chat_completion_agent(agent: ChatCompletionAgent, inputs):
|
||||
"""Invokes the given agent with each (input, style) in inputs."""
|
||||
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
for user_input, style in inputs:
|
||||
print(f"[USER]: {user_input}\n")
|
||||
|
||||
# If style is specified, override the 'style' argument
|
||||
argument_overrides = None
|
||||
if style:
|
||||
argument_overrides = KernelArguments(style=style)
|
||||
|
||||
# Stream agent responses
|
||||
async for response in agent.invoke_stream(messages=user_input, thread=thread, arguments=argument_overrides):
|
||||
print(f"{response.content}", end="", flush=True)
|
||||
thread = response.thread
|
||||
print()
|
||||
|
||||
|
||||
async def invoke_agent_with_template(template_str: str, template_format: str, default_style: str = "haiku"):
|
||||
"""Creates an agent with the specified template and format, then invokes it using invoke_chat_completion_agent."""
|
||||
|
||||
# Configure the prompt template
|
||||
prompt_config = PromptTemplateConfig(template=template_str, template_format=template_format)
|
||||
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="MyPoetAgent",
|
||||
prompt_template_config=prompt_config,
|
||||
arguments=KernelArguments(style=default_style),
|
||||
)
|
||||
|
||||
await invoke_chat_completion_agent(agent, inputs)
|
||||
|
||||
|
||||
async def main():
|
||||
# 1) Using "semantic-kernel" format
|
||||
print("\n===== SEMANTIC-KERNEL FORMAT =====\n")
|
||||
semantic_kernel_template = """
|
||||
Write a one verse poem on the requested topic in the style of {{$style}}.
|
||||
Always state the requested style of the poem.
|
||||
"""
|
||||
await invoke_agent_with_template(
|
||||
template_str=semantic_kernel_template,
|
||||
template_format="semantic-kernel",
|
||||
default_style="haiku",
|
||||
)
|
||||
|
||||
# 2) Using "jinja2" format
|
||||
print("\n===== JINJA2 FORMAT =====\n")
|
||||
jinja2_template = """
|
||||
Write a one verse poem on the requested topic in the style of {{style}}.
|
||||
Always state the requested style of the poem.
|
||||
"""
|
||||
await invoke_agent_with_template(template_str=jinja2_template, template_format="jinja2", default_style="haiku")
|
||||
|
||||
# 3) Using "handlebars" format
|
||||
print("\n===== HANDLEBARS FORMAT =====\n")
|
||||
handlebars_template = """
|
||||
Write a one verse poem on the requested topic in the style of {{style}}.
|
||||
Always state the requested style of the poem.
|
||||
"""
|
||||
await invoke_agent_with_template(
|
||||
template_str=handlebars_template, template_format="handlebars", default_style="haiku"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.completion_usage import CompletionUsage
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion agent
|
||||
and use it with streaming responses. It also shows how to track token
|
||||
usage during the streaming process.
|
||||
"""
|
||||
|
||||
|
||||
# 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) -> 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"
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="Assistant",
|
||||
instructions="Answer questions about the menu.",
|
||||
plugins=[MenuPlugin()],
|
||||
)
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"How much does that cost?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
completion_usage = CompletionUsage()
|
||||
|
||||
for user_input in user_inputs:
|
||||
print(f"\n# User: '{user_input}'")
|
||||
async for response in agent.invoke_stream(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
):
|
||||
if response.content:
|
||||
print(response.content, end="", flush=True)
|
||||
if response.metadata.get("usage"):
|
||||
completion_usage += response.metadata["usage"]
|
||||
print(f"\nStreaming Usage: {response.metadata['usage']}")
|
||||
thread = response.thread
|
||||
print()
|
||||
|
||||
# Print the completion usage
|
||||
print(f"\nStreaming Total Completion Usage: {completion_usage.model_dump_json(indent=4)}")
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Hello'
|
||||
Hello! How can I help you with the menu today?
|
||||
|
||||
# User: 'What is the special soup?'
|
||||
The special soup today is Clam Chowder. Would you like more details or are you interested in something else from
|
||||
the menu?
|
||||
|
||||
# User: 'How much does that cost?'
|
||||
The Clam Chowder special soup costs $9.99. Would you like to add it to your order or ask about something else?
|
||||
|
||||
# User: 'Thank you'
|
||||
You're welcome! If you have any more questions or need help with the menu, just let me know. Enjoy your meal!
|
||||
|
||||
Streaming Total Completion Usage: {
|
||||
"prompt_tokens": 1150,
|
||||
"prompt_tokens_details": {
|
||||
"audio_tokens": 0,
|
||||
"cached_tokens": 0
|
||||
},
|
||||
"completion_tokens": 134,
|
||||
"completion_tokens_details": {
|
||||
"accepted_prediction_tokens": 0,
|
||||
"audio_tokens": 0,
|
||||
"reasoning_tokens": 0,
|
||||
"rejected_prediction_tokens": 0
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentGroupChat, ChatCompletionAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents import ChatHistorySummarizationReducer
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to implement a chat history
|
||||
reducer as part of the Semantic Kernel Agent Framework. For this sample,
|
||||
the ChatCompletionAgent with an AgentGroupChat is used. The Chat History
|
||||
Reducer is a Summary Reducer. View the README for more information on
|
||||
how to use the reducer and what each parameter does.
|
||||
|
||||
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
|
||||
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
|
||||
|
||||
Read more about the `GroupChatOrchestration` here:
|
||||
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
|
||||
|
||||
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
|
||||
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
"""
|
||||
Single-function approach that shows the same chat reducer behavior
|
||||
while preserving all original logic and code lines (now commented).
|
||||
"""
|
||||
|
||||
# Setup necessary parameters
|
||||
reducer_msg_count = 10
|
||||
reducer_threshold = 10
|
||||
|
||||
credential = AzureCliCredential()
|
||||
|
||||
# Create a summarization reducer and clear its history
|
||||
history_summarization_reducer = ChatHistorySummarizationReducer(
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
target_count=reducer_msg_count,
|
||||
threshold_count=reducer_threshold,
|
||||
)
|
||||
history_summarization_reducer.clear()
|
||||
|
||||
# Create our agent
|
||||
agent = ChatCompletionAgent(
|
||||
name="NumeroTranslator",
|
||||
instructions="Add one to the latest user number and spell it in Spanish without explanation.",
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
)
|
||||
|
||||
# Create a group chat using the reducer
|
||||
chat = AgentGroupChat(chat_history=history_summarization_reducer)
|
||||
|
||||
# Simulate user messages
|
||||
message_count = 50 # Number of messages to simulate
|
||||
for index in range(1, message_count, 2):
|
||||
# Add user message to the chat
|
||||
await chat.add_chat_message(message=str(index))
|
||||
print(f"# User: '{index}'")
|
||||
|
||||
# Attempt to reduce history
|
||||
is_reduced = await chat.reduce_history()
|
||||
if is_reduced:
|
||||
print(f"@ History reduced to {len(history_summarization_reducer.messages)} messages.")
|
||||
|
||||
# Invoke the agent and display responses
|
||||
async for message in chat.invoke(agent):
|
||||
print(f"# {message.role} - {message.name or '*'}: '{message.content}'")
|
||||
|
||||
# Retrieve messages
|
||||
msgs = []
|
||||
async for m in chat.get_chat_messages(agent):
|
||||
msgs.append(m)
|
||||
print(f"@ Message Count: {len(msgs)}\n")
|
||||
|
||||
# If a reduction happened and we use summarization, print the summary
|
||||
if is_reduced:
|
||||
for msg in msgs:
|
||||
if msg.metadata and msg.metadata.get("__summary__"):
|
||||
print(f"\tSummary: {msg.content}")
|
||||
break
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents import ChatHistorySummarizationReducer
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to implement a truncation chat
|
||||
history reducer as part of the Semantic Kernel Agent Framework. For
|
||||
this sample, a single ChatCompletionAgent is used.
|
||||
"""
|
||||
|
||||
|
||||
# Initialize the logger for debugging and information messages
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def main():
|
||||
# Setup necessary parameters
|
||||
reducer_msg_count = 10
|
||||
reducer_threshold = 10
|
||||
|
||||
credential = AzureCliCredential()
|
||||
|
||||
# Create a summarization reducer
|
||||
history_summarization_reducer = ChatHistorySummarizationReducer(
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
target_count=reducer_msg_count,
|
||||
threshold_count=reducer_threshold,
|
||||
)
|
||||
|
||||
thread: ChatHistoryAgentThread = ChatHistoryAgentThread(chat_history=history_summarization_reducer)
|
||||
|
||||
# Create our agent
|
||||
agent = ChatCompletionAgent(
|
||||
name="NumeroTranslator",
|
||||
instructions="Add one to the latest user number and spell it in Spanish without explanation.",
|
||||
service=AzureChatCompletion(credential=credential),
|
||||
)
|
||||
|
||||
# Number of messages to simulate
|
||||
message_count = 50
|
||||
for index in range(1, message_count + 1, 2):
|
||||
print(f"# User: '{index}'")
|
||||
|
||||
# Get agent response and store it
|
||||
response = await agent.get_response(messages=str(index), thread=thread)
|
||||
thread = response.thread
|
||||
print(f"# Agent - {response.name}: '{response.content}'")
|
||||
|
||||
# Attempt reduction
|
||||
is_reduced = await thread.reduce()
|
||||
if is_reduced:
|
||||
print(f"@ History reduced to {len(thread)} messages.")
|
||||
|
||||
print(f"@ Message Count: {len(thread)}\n")
|
||||
|
||||
# If reduced, print summary if present
|
||||
if is_reduced:
|
||||
async for msg in thread.get_messages():
|
||||
if msg.metadata and msg.metadata.get("__summary__"):
|
||||
print(f"\tSummary: {msg.content}")
|
||||
break
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
from typing import Annotated
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.completion_usage import CompletionUsage
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion agent
|
||||
and use it with non-streaming responses. It also shows how to track token
|
||||
usage during agent invoke.
|
||||
"""
|
||||
|
||||
|
||||
# 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) -> 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"
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="Assistant",
|
||||
instructions="Answer questions about the menu.",
|
||||
plugins=[MenuPlugin()],
|
||||
)
|
||||
|
||||
# Create a thread for the agent
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: ChatHistoryAgentThread = None
|
||||
|
||||
user_inputs = [
|
||||
"Hello",
|
||||
"What is the special soup?",
|
||||
"How much does that cost?",
|
||||
"Thank you",
|
||||
]
|
||||
|
||||
completion_usage = CompletionUsage()
|
||||
|
||||
for user_input in user_inputs:
|
||||
print(f"\n# User: '{user_input}'")
|
||||
async for response in agent.invoke(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
):
|
||||
if response.content:
|
||||
print(response.content)
|
||||
if response.metadata.get("usage"):
|
||||
completion_usage += response.metadata["usage"]
|
||||
thread = response.thread
|
||||
print()
|
||||
|
||||
# Print the completion usage
|
||||
print(f"\nNon-Streaming Total Completion Usage: {completion_usage.model_dump_json(indent=4)}")
|
||||
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
# User: 'Hello'
|
||||
Hello! How can I help you with the menu today?
|
||||
|
||||
|
||||
# User: 'What is the special soup?'
|
||||
The special soup today is Clam Chowder. Would you like to know more about it or see the other specials?
|
||||
|
||||
|
||||
# User: 'How much does that cost?'
|
||||
The Clam Chowder special costs $9.99. Would you like to add that to your order or need more information?
|
||||
|
||||
|
||||
# User: 'Thank you'
|
||||
You're welcome! If you have any more questions or need help with the menu, just let me know. Enjoy your day!
|
||||
|
||||
Non-Streaming Total Completion Usage: {
|
||||
"prompt_tokens": 772,
|
||||
"prompt_tokens_details": {
|
||||
"audio_tokens": 0,
|
||||
"cached_tokens": 0
|
||||
},
|
||||
"completion_tokens": 92,
|
||||
"completion_tokens_details": {
|
||||
"accepted_prediction_tokens": 0,
|
||||
"audio_tokens": 0,
|
||||
"reasoning_tokens": 0,
|
||||
"rejected_prediction_tokens": 0
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AgentGroupChat, ChatCompletionAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents import ChatHistoryTruncationReducer
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to implement a chat history
|
||||
reducer as part of the Semantic Kernel Agent Framework. For this sample,
|
||||
the ChatCompletionAgent with an AgentGroupChat is used. The Chat History
|
||||
Reducer is a Truncation Reducer. View the README for more information on
|
||||
how to use the reducer and what each parameter does.
|
||||
|
||||
Note: This sample use the `AgentGroupChat` feature of Semantic Kernel, which is
|
||||
no longer maintained. For a replacement, consider using the `GroupChatOrchestration`.
|
||||
|
||||
Read more about the `GroupChatOrchestration` here:
|
||||
https://learn.microsoft.com/semantic-kernel/frameworks/agent/agent-orchestration/group-chat?pivots=programming-language-python
|
||||
|
||||
Here is a migration guide from `AgentGroupChat` to `GroupChatOrchestration`:
|
||||
https://learn.microsoft.com/semantic-kernel/support/migration/group-chat-orchestration-migration-guide?pivots=programming-language-python
|
||||
"""
|
||||
|
||||
|
||||
# Initialize the logger for debugging and information messages
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def main():
|
||||
"""
|
||||
Single-function approach that shows the same chat reducer behavior
|
||||
while preserving all original logic and code lines (now commented).
|
||||
"""
|
||||
|
||||
# Setup necessary parameters
|
||||
reducer_msg_count = 10
|
||||
reducer_threshold = 10
|
||||
|
||||
# Create a truncation reducer and clear its history
|
||||
history_truncation_reducer = ChatHistoryTruncationReducer(
|
||||
target_count=reducer_msg_count, threshold_count=reducer_threshold
|
||||
)
|
||||
history_truncation_reducer.clear()
|
||||
|
||||
# Create our agent
|
||||
agent = ChatCompletionAgent(
|
||||
name="NumeroTranslator",
|
||||
instructions="Add one to the latest user number and spell it in Spanish without explanation.",
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
)
|
||||
|
||||
# Create a group chat using the reducer
|
||||
chat = AgentGroupChat(chat_history=history_truncation_reducer)
|
||||
|
||||
# Simulate user messages
|
||||
message_count = 50 # Number of messages to simulate
|
||||
for index in range(1, message_count, 2):
|
||||
# Add user message to the chat
|
||||
await chat.add_chat_message(message=str(index))
|
||||
print(f"# User: '{index}'")
|
||||
|
||||
# Attempt to reduce history
|
||||
is_reduced = await chat.reduce_history()
|
||||
if is_reduced:
|
||||
print(f"@ History reduced to {len(history_truncation_reducer.messages)} messages.")
|
||||
|
||||
# Invoke the agent and display responses
|
||||
async for message in chat.invoke(agent):
|
||||
print(f"# {message.role} - {message.name or '*'}: '{message.content}'")
|
||||
|
||||
# Retrieve messages
|
||||
msgs = []
|
||||
async for m in chat.get_chat_messages(agent):
|
||||
msgs.append(m)
|
||||
print(f"@ Message Count: {len(msgs)}\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import (
|
||||
ChatCompletionAgent,
|
||||
)
|
||||
from semantic_kernel.agents.chat_completion.chat_completion_agent import ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.contents import (
|
||||
ChatHistoryTruncationReducer,
|
||||
)
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to implement a truncation chat
|
||||
history reducer as part of the Semantic Kernel Agent Framework. For
|
||||
this sample, a single ChatCompletionAgent is used.
|
||||
"""
|
||||
|
||||
|
||||
# Initialize the logger for debugging and information messages
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def main():
|
||||
# Setup necessary parameters
|
||||
reducer_msg_count = 10
|
||||
reducer_threshold = 10
|
||||
|
||||
# Create a truncation reducer
|
||||
history_truncation_reducer = ChatHistoryTruncationReducer(
|
||||
target_count=reducer_msg_count,
|
||||
threshold_count=reducer_threshold,
|
||||
)
|
||||
|
||||
thread: ChatHistoryAgentThread = ChatHistoryAgentThread(chat_history=history_truncation_reducer)
|
||||
|
||||
# Create our agent
|
||||
agent = ChatCompletionAgent(
|
||||
name="NumeroTranslator",
|
||||
instructions="Add one to the latest user number and spell it in Spanish without explanation.",
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
)
|
||||
|
||||
# Number of messages to simulate
|
||||
message_count = 50
|
||||
for index in range(1, message_count + 1, 2):
|
||||
print(f"# User: '{index}'")
|
||||
|
||||
# Get agent response and store it
|
||||
response = await agent.get_response(messages=str(index), thread=thread)
|
||||
thread = response.thread
|
||||
print(f"# Agent - {response.name}: '{response.content}'")
|
||||
|
||||
# Attempt reduction
|
||||
is_reduced = await thread.reduce()
|
||||
if is_reduced:
|
||||
print(f"@ History reduced to {len(thread)} messages.")
|
||||
|
||||
print(f"@ Message Count: {len(history_truncation_reducer.messages)}\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user