Skip to content

Commit 2323ae0

Browse files
authored
Python: Cleanup ChatCompletionAgent concept samples (#10726)
### Motivation and Context Our chat completion agent concept samples need to be cleaned up to improve readability and maintainability. <!-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> ### Description Simplify the chat completion agent concept samples so we're not trying to do too much in each sample. Update some of the APIs using the new patterns. <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [X] The code builds clean without any errors or warnings - [X] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [X] All unit tests pass, and I have added new tests where possible - [X] I didn't break anyone 😄
1 parent 9ad9f2c commit 2323ae0

16 files changed

+531
-457
lines changed

python/samples/concepts/README.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,12 @@
3838
#### [Chat Completion Agent](../../semantic_kernel/agents/chat_completion/chat_completion_agent.py)
3939

4040
- [Chat Completion Function Termination](./agents/chat_completion_agent/chat_completion_function_termination.py)
41-
- [Chat Completion History Reducer](./agents/chat_completion_agent/chat_completion_history_reducer.py)
42-
- [Chat Completion Templating](./agents/chat_completion_agent/chat_completion_templating.py)
41+
- [Chat Completion Templating](./agents/chat_completion_agent/chat_completion_prompt_templating.py)
42+
- [Chat Completion Summary History Reducer Agent Chat](./agents/chat_completion_agent/chat_completion_summary_history_reducer_agent_chat.py)
43+
- [Chat Completion Summary History Reducer Single Agent](./agents/chat_completion_agent/chat_completion_summary_history_reducer_single_agent.py)
44+
- [Chat Completion Truncate History Reducer Agent Chat](./agents/chat_completion_agent/chat_completion_truncate_history_reducer_agent_chat.py)
45+
- [Chat Completion Truncate History Reducer Single Agent](./agents/chat_completion_agent/chat_completion_truncate_history_reducer_single_agent.py)
46+
4347

4448
#### [Mixed Agent Group Chat](../../semantic_kernel/agents/group_chat/agent_group_chat.py)
4549

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Chat Completion Agent Samples
2+
3+
The following samples demonstrate advanced usage of the `ChatCompletionAgent`.
4+
5+
---
6+
7+
## Chat History Reduction Strategies
8+
9+
When configuring chat history management, there are two important settings to consider:
10+
11+
### `reducer_msg_count`
12+
13+
- **Purpose:** Defines the target number of messages to retain after applying truncation or summarization.
14+
- **Controls:** Determines how much recent conversation history is preserved, while older messages are either discarded or summarized.
15+
- **Recommendations for adjustment:**
16+
- **Smaller values:** Ideal for memory-constrained environments or scenarios where brief context is sufficient.
17+
- **Larger values:** Useful when retaining extensive conversational context is critical for accurate responses or complex dialogue.
18+
19+
### `reducer_threshold`
20+
21+
- **Purpose:** Provides a buffer to prevent premature reduction when the message count slightly exceeds `reducer_msg_count`.
22+
- **Controls:** Ensures essential message pairs (e.g., a user query and the assistant’s response) aren't unintentionally truncated.
23+
- **Recommendations for adjustment:**
24+
- **Smaller values:** Use to enforce stricter message reduction criteria, potentially truncating older message pairs sooner.
25+
- **Larger values:** Recommended for preserving critical conversation segments, particularly in sensitive interactions involving API function calls or detailed responses.
26+
27+
### Interaction Between Parameters
28+
29+
The combination of these parameters determines **when** history reduction occurs and **how much** of the conversation is retained.
30+
31+
**Example:**
32+
- 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.
33+
34+
---
35+
36+
## Recommendations for Effective Configuration
37+
38+
- **Performance-focused environments:**
39+
- Lower `reducer_msg_count` to conserve memory and accelerate processing.
40+
41+
- **Context-sensitive scenarios:**
42+
- Higher `reducer_msg_count` and `reducer_threshold` help maintain continuity across multiple interactions, crucial for multi-turn conversations or complex workflows.
43+
44+
- **Iterative Experimentation:**
45+
- 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.

python/samples/concepts/agents/chat_completion_agent/chat_completion_function_termination.py

+73-59
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,18 @@
44
from typing import Annotated
55

66
from semantic_kernel.agents import ChatCompletionAgent
7-
from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior
87
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
9-
from semantic_kernel.contents.chat_history import ChatHistory
10-
from semantic_kernel.contents.chat_message_content import ChatMessageContent
11-
from semantic_kernel.contents.function_call_content import FunctionCallContent
12-
from semantic_kernel.contents.function_result_content import FunctionResultContent
13-
from semantic_kernel.contents.utils.author_role import AuthorRole
14-
from semantic_kernel.filters.auto_function_invocation.auto_function_invocation_context import (
15-
AutoFunctionInvocationContext,
16-
)
17-
from semantic_kernel.filters.filter_types import FilterTypes
18-
from semantic_kernel.functions.kernel_arguments import KernelArguments
8+
from semantic_kernel.contents import ChatHistory, ChatMessageContent, FunctionCallContent, FunctionResultContent
9+
from semantic_kernel.filters import AutoFunctionInvocationContext
1910
from semantic_kernel.functions.kernel_function_decorator import kernel_function
2011
from semantic_kernel.kernel import Kernel
2112

22-
###################################################################
23-
# The following sample demonstrates how to configure the auto #
24-
# function invocation filter with use of a ChatCompletionAgent. #
25-
###################################################################
26-
27-
28-
# Define the agent name and instructions
29-
HOST_NAME = "Host"
30-
HOST_INSTRUCTIONS = "Answer questions about the menu."
13+
"""
14+
The following sample demonstrates how to configure the auto
15+
function invocation filter while using a ChatCompletionAgent.
16+
This allows the developer or user to view the function call content
17+
and the function result content.
18+
"""
3119

3220

3321
# Define the auto function invocation filter that will be used by the kernel
@@ -58,17 +46,17 @@ def get_item_price(
5846
return "$9.99"
5947

6048

61-
def _create_kernel_with_chat_completionand_filter(service_id: str) -> Kernel:
49+
def _create_kernel_with_chat_completionand_filter() -> Kernel:
6250
"""A helper function to create a kernel with a chat completion service and a filter."""
6351
kernel = Kernel()
64-
kernel.add_service(AzureChatCompletion(service_id=service_id))
65-
kernel.add_filter(FilterTypes.AUTO_FUNCTION_INVOCATION, auto_function_invocation_filter)
52+
kernel.add_service(AzureChatCompletion())
53+
kernel.add_filter("auto_function_invocation", auto_function_invocation_filter)
6654
kernel.add_plugin(plugin=MenuPlugin(), plugin_name="menu")
6755
return kernel
6856

6957

7058
def _write_content(content: ChatMessageContent) -> None:
71-
"""Write the content to the console."""
59+
"""Write the content to the console based on the content type."""
7260
last_item_type = type(content.items[-1]).__name__ if content.items else "(empty)"
7361
message_content = ""
7462
if isinstance(last_item_type, FunctionCallContent):
@@ -80,54 +68,80 @@ def _write_content(content: ChatMessageContent) -> None:
8068
print(f"[{last_item_type}] {content.role} : '{message_content}'")
8169

8270

83-
# A helper method to invoke the agent with the user input
84-
async def invoke_agent(agent: ChatCompletionAgent, input: str, chat_history: ChatHistory) -> None:
85-
"""Invoke the agent with the user input."""
86-
chat_history.add_user_message(input)
87-
print(f"# {AuthorRole.USER}: '{input}'")
88-
89-
async for content in agent.invoke(chat_history):
90-
if not any(isinstance(item, (FunctionCallContent, FunctionResultContent)) for item in content.items):
91-
chat_history.add_message(content)
92-
_write_content(content)
93-
94-
9571
async def main():
96-
service_id = "agent"
97-
98-
# Create the kernel used by the chat completion agent
99-
kernel = _create_kernel_with_chat_completionand_filter(service_id=service_id)
100-
101-
settings = kernel.get_prompt_execution_settings_from_service_id(service_id=service_id)
102-
103-
# Configure the function choice behavior to auto invoke kernel functions
104-
settings.function_choice_behavior = FunctionChoiceBehavior.Auto()
105-
106-
# Create the agent
72+
# 1. Create the agent with a kernel instance that contains
73+
# the auto function invocation filter and the AI service
10774
agent = ChatCompletionAgent(
108-
kernel=kernel,
109-
name=HOST_NAME,
110-
instructions=HOST_INSTRUCTIONS,
111-
arguments=KernelArguments(settings=settings),
75+
kernel=_create_kernel_with_chat_completionand_filter(),
76+
name="Host",
77+
instructions="Answer questions about the menu.",
11278
)
11379

114-
# Define the chat history
115-
chat = ChatHistory()
80+
# 2. Define the chat history
81+
chat_history = ChatHistory()
11682

117-
# Respond to user input
118-
await invoke_agent(agent=agent, input="Hello", chat_history=chat)
119-
await invoke_agent(agent=agent, input="What is the special soup?", chat_history=chat)
120-
await invoke_agent(agent=agent, input="What is the special drink?", chat_history=chat)
121-
await invoke_agent(agent=agent, input="Thank you", chat_history=chat)
83+
user_inputs = [
84+
"Hello",
85+
"What is the special soup?",
86+
"What is the special drink?",
87+
"Thank you",
88+
]
89+
90+
for user_input in user_inputs:
91+
# 3. Add the user message to the chat history
92+
chat_history.add_user_message(user_input)
93+
print(f"# User: '{user_input}'")
94+
95+
# 4. Get the response from the agent
96+
content = await agent.get_response(chat_history)
97+
# Don't add the message if it is a function call or result
98+
if not any(isinstance(item, (FunctionCallContent, FunctionResultContent)) for item in content.items):
99+
chat_history.add_message(content)
100+
_write_content(content)
122101

123102
print("================================")
124103
print("CHAT HISTORY")
125104
print("================================")
126105

127106
# Print out the chat history to view the different types of messages
128-
for message in chat.messages:
107+
for message in chat_history.messages:
129108
_write_content(message)
130109

110+
"""
111+
Sample output:
112+
113+
# AuthorRole.USER: 'Hello'
114+
[TextContent] AuthorRole.ASSISTANT : 'Hello! How can I assist you today?'
115+
# AuthorRole.USER: 'What is the special soup?'
116+
[FunctionResultContent] AuthorRole.TOOL : '
117+
Special Soup: Clam Chowder
118+
Special Salad: Cobb Salad
119+
Special Drink: Chai Tea
120+
'
121+
# AuthorRole.USER: 'What is the special drink?'
122+
[TextContent] AuthorRole.ASSISTANT : 'The special drink is Chai Tea.'
123+
# AuthorRole.USER: 'Thank you'
124+
[TextContent] AuthorRole.ASSISTANT : 'You're welcome! If you have any more questions or need assistance with
125+
anything else, feel free to ask!'
126+
================================
127+
CHAT HISTORY
128+
================================
129+
[TextContent] AuthorRole.USER : 'Hello'
130+
[TextContent] AuthorRole.ASSISTANT : 'Hello! How can I assist you today?'
131+
[TextContent] AuthorRole.USER : 'What is the special soup?'
132+
[FunctionCallContent] AuthorRole.ASSISTANT : 'menu-get_specials({})'
133+
[FunctionResultContent] AuthorRole.TOOL : '
134+
Special Soup: Clam Chowder
135+
Special Salad: Cobb Salad
136+
Special Drink: Chai Tea
137+
'
138+
[TextContent] AuthorRole.USER : 'What is the special drink?'
139+
[TextContent] AuthorRole.ASSISTANT : 'The special drink is Chai Tea.'
140+
[TextContent] AuthorRole.USER : 'Thank you'
141+
[TextContent] AuthorRole.ASSISTANT : 'You're welcome! If you have any more questions or need assistance with
142+
anything else, feel free to ask!'
143+
"""
144+
131145

132146
if __name__ == "__main__":
133147
asyncio.run(main())

0 commit comments

Comments
 (0)