채팅 기록
채팅 기록 개체는 채팅 세션에서 메시지 레코드를 유지하는 데 사용됩니다. 사용자, 도우미, 도구 또는 시스템과 같은 여러 작성자의 메시지를 저장하는 데 사용됩니다. 메시지를 보내고 받기 위한 기본 메커니즘인 채팅 기록 개체는 대화의 컨텍스트와 연속성을 유지하는 데 필수적입니다.
채팅 기록 개체 만들기
채팅 기록 개체는 내부 목록이므로 메시지를 쉽게 만들고 추가할 수 있습니다.
using Microsoft.SemanticKernel.ChatCompletion;
// Create a chat history object
ChatHistory chatHistory = [];
chatHistory.AddSystemMessage("You are a helpful assistant.");
chatHistory.AddUserMessage("What's available to order?");
chatHistory.AddAssistantMessage("We have pizza, pasta, and salad available to order. What would you like to order?");
chatHistory.AddUserMessage("I'd like to have the first option, please.");
# Create a chat history object
chat_history = ChatHistory()
chat_history.add_system_message("You are a helpful assistant.")
chat_history.add_user_message("What's available to order?")
chat_history.add_assistant_message("We have pizza, pasta, and salad available to order. What would you like to order?")
chat_history.add_user_message("I'd like to have the first option, please.")
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
// Create a chat history object
ChatHistory chatHistory = new ChatHistory();
chatHistory.addSystemMessage("You are a helpful assistant.");
chatHistory.addUserMessage("What's available to order?");
chatHistory.addAssistantMessage("We have pizza, pasta, and salad available to order. What would you like to order?");
chatHistory.addUserMessage("I'd like to have the first option, please.");
채팅 기록에 더 풍부한 메시지 추가
채팅 기록 개체에 메시지를 추가하는 가장 쉬운 방법은 위의 메서드를 사용하는 것입니다. 그러나 새 ChatMessage
개체를 만들어 메시지를 수동으로 추가할 수도 있습니다. 이를 통해 이름 및 이미지 콘텐츠와 같은 추가 정보를 제공할 수 있습니다.
using Microsoft.SemanticKernel.ChatCompletion;
// Add system message
chatHistory.Add(
new() {
Role = AuthorRole.System,
Content = "You are a helpful assistant"
}
);
// Add user message with an image
chatHistory.Add(
new() {
Role = AuthorRole.User,
AuthorName = "Laimonis Dumins",
Items = [
new TextContent { Text = "What available on this menu" },
new ImageContent { Uri = new Uri("https://example.com/menu.jpg") }
]
}
);
// Add assistant message
chatHistory.Add(
new() {
Role = AuthorRole.Assistant,
AuthorName = "Restaurant Assistant",
Content = "We have pizza, pasta, and salad available to order. What would you like to order?"
}
);
// Add additional message from a different user
chatHistory.Add(
new() {
Role = AuthorRole.User,
AuthorName = "Ema Vargova",
Content = "I'd like to have the first option, please."
}
);
from semantic_kernel.contents.chat_history import ChatHistory
from semantic_kernel.contents import ChatMessageContent, TextContent, ImageContent
from semantic_kernel.contents.utils.author_role import AuthorRole
# Add system message
chat_history.add_message(
ChatMessage(
role=AuthorRole.System,
content="You are a helpful assistant"
)
)
# Add user message with an image
chat_history.add_message(
ChatMessageContent(
role=AuthorRole.USER,
name="Laimonis Dumins",
items=[
TextContent(text="What available on this menu"),
ImageContent(uri="https://example.com/menu.jpg")
]
)
)
# Add assistant message
chat_history.add_message(
ChatMessageContent(
role=AuthorRole.ASSISTANT,
name="Restaurant Assistant",
content="We have pizza, pasta, and salad available to order. What would you like to order?"
)
)
# Add additional message from a different user
chat_history.add_message(
ChatMessageContent(
role=AuthorRole.USER,
name="Ema Vargova",
content="I'd like to have the first option, please."
)
)
import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageImageContent;
import com.microsoft.semantickernel.services.chatcompletion.message.ChatMessageTextContent;
// Add system message
chatHistory.addSystemMessage(
"You are a helpful assistant"
);
// Add user message with an image
chatHistory.addUserMessage(
"What available on this menu"
);
chatHistory.addMessage(
ChatMessageImageContent.builder()
.withImageUrl("https://example.com/menu.jpg")
.build()
);
// Add assistant message
chatHistory.addAssistantMessage(
"We have pizza, pasta, and salad available to order. What would you like to order?"
);
// Add additional message from a different user
chatHistory.addUserMessage(
"I'd like to have the first option, please."
);
함수 호출 시뮬레이션
사용자, 도우미 및 시스템 역할 외에도 도구 역할의 메시지를 추가하여 함수 호출을 시뮬레이션할 수도 있습니다. 이는 AI에서 플러그 인을 사용하는 방법을 교육하고 대화에 추가 컨텍스트를 제공하는 데 유용합니다.
예를 들어 사용자가 정보를 제공하도록 요구하거나 LLM 낭비 시간을 요구하지 않고 채팅 기록에 현재 사용자에 대한 정보를 삽입하려면 도구 역할을 사용하여 정보를 직접 제공할 수 있습니다.
다음은 플러그 인에 대한 함수 호출을 시뮬레이션하여 도우미에 사용자 알레르기를 제공할 수 있는 방법의 User
예입니다.
팁
시뮬레이션된 함수 호출은 현재 사용자에 대한 세부 정보를 제공하는 데 특히 유용합니다. 오늘날의 LLM은 사용자 정보에 특히 민감하도록 학습되었습니다. 시스템 메시지에 사용자 세부 정보를 제공하는 경우에도 LLM은 무시하도록 선택할 수 있습니다. 사용자 메시지 또는 도구 메시지를 통해 제공하는 경우 LLM은 이 메시지를 사용할 가능성이 높습니다.
// Add a simulated function call from the assistant
chatHistory.Add(
new() {
Role = AuthorRole.Assistant,
Items = [
new FunctionCallContent(
functionName: "get_user_allergies",
pluginName: "User",
id: "0001",
arguments: new () { {"username", "laimonisdumins"} }
),
new FunctionCallContent(
functionName: "get_user_allergies",
pluginName: "User",
id: "0002",
arguments: new () { {"username", "emavargova"} }
)
]
}
);
// Add a simulated function results from the tool role
chatHistory.Add(
new() {
Role = AuthorRole.Tool,
Items = [
new FunctionResultContent(
functionName: "get_user_allergies",
pluginName: "User",
id: "0001",
result: "{ \"allergies\": [\"peanuts\", \"gluten\"] }"
)
]
}
);
chatHistory.Add(
new() {
Role = AuthorRole.Tool,
Items = [
new FunctionResultContent(
functionName: "get_user_allergies",
pluginName: "User",
id: "0002",
result: "{ \"allergies\": [\"dairy\", \"soy\"] }"
)
]
}
);
from semantic_kernel.contents import ChatMessageContent, FunctionCallContent, FunctionResultContent
# Add a simulated function call from the assistant
chat_history.add_message(
ChatMessageContent(
role=AuthorRole.ASSISTANT,
items=[
FunctionCallContent(
name="get_user_allergies-User",
id="0001",
arguments=str({"username": "laimonisdumins"})
),
FunctionCallContent(
name="get_user_allergies-User",
id="0002",
arguments=str({"username": "emavargova"})
)
]
)
)
# Add a simulated function results from the tool role
chat_history.add_message(
ChatMessageContent(
role=AuthorRole.TOOL,
items=[
FunctionResultContent(
name="get_user_allergies-User",
id="0001",
result="{ \"allergies\": [\"peanuts\", \"gluten\"] }"
)
]
)
)
chat_history.add_message(
ChatMessageContent(
role=AuthorRole.TOOL,
items=[
FunctionResultContent(
name="get_user_allergies-User",
id="0002",
result="{ \"allergies\": [\"dairy\", \"gluten\"] }"
)
]
)
)
This functionality is not supported in the current version of Semantic Kernel for Java.
Important
도구 결과를 시뮬레이션할 때는 항상 결과가 해당하는 함수 호출을 제공해야 id
합니다. 이는 AI가 결과의 컨텍스트를 이해하는 데 중요합니다. OpenAI와 같은 일부 LLM은 누락되었거나 함수 호출에 해당하지 않는 경우 id
오류를 id
throw합니다.
채팅 기록 개체 검사
자동 함수 호출을 사용하도록 설정된 채팅 완료 서비스에 채팅 기록 개체를 전달할 때마다 채팅 기록 개체는 함수 호출 및 결과를 포함하도록 조작됩니다. 이렇게 하면 채팅 기록 개체에 이러한 메시지를 수동으로 추가할 필요가 없으며 채팅 기록 개체를 검사하여 함수 호출 및 결과를 볼 수도 있습니다.
그러나 채팅 기록 개체에 최종 메시지를 추가해야 합니다. 다음은 채팅 기록 개체를 검사하여 함수 호출 및 결과를 확인하는 방법의 예입니다.
using Microsoft.SemanticKernel.ChatCompletion;
ChatHistory chatHistory = [
new() {
Role = AuthorRole.User,
Content = "Please order me a pizza"
}
];
// Get the current length of the chat history object
int currentChatHistoryLength = chatHistory.Count;
// Get the chat message content
ChatMessageContent results = await chatCompletionService.GetChatMessageContentAsync(
chatHistory,
kernel: kernel
);
// Get the new messages added to the chat history object
for (int i = currentChatHistoryLength; i < chatHistory.Count; i++)
{
Console.WriteLine(chatHistory[i]);
}
// Print the final message
Console.WriteLine(results);
// Add the final message to the chat history object
chatHistory.Add(results);
from semantic_kernel.contents import ChatMessageContent
chat_history = ChatHistory([
ChatMessageContent(
role=AuthorRole.USER,
content="Please order me a pizza"
)
])
# Get the current length of the chat history object
current_chat_history_length = len(chat_history)
# Get the chat message content
results = await chat_completion.get_chat_message_content(
chat_history=history,
settings=execution_settings,
kernel=kernel,
)
# Get the new messages added to the chat history object
for i in range(current_chat_history_length, len(chat_history)):
print(chat_history[i])
# Print the final message
print(results)
# Add the final message to the chat history object
chat_history.add_message(results)
import com.microsoft.semantickernel.services.chatcompletion.ChatHistory;
ChatHistory chatHistory = new ChatHistory();
chatHistory.addUserMessage("Please order me a pizza");
// Get the chat message content
List<ChatMessageContent> results = chatCompletionService.getChatMessageContentsAsync(
chatHistory,
kernel,
null
).block();
results.forEach(result -> System.out.println(result.getContent());
// Get the new messages added to the chat history object. By default,
// the ChatCompletionService returns new messages only.
chatHistory.addAll(results);
채팅 기록 감소
채팅 기록을 관리하는 것은 효율적인 성능을 보장하면서 컨텍스트 인식 대화를 유지하는 데 필수적입니다. 대화가 진행됨에 따라 기록 개체가 모델의 컨텍스트 창의 한계를 초과하여 응답 품질에 영향을 미치고 처리 속도가 느려질 수 있습니다. 채팅 기록을 줄이는 구조화된 접근 방식을 사용하면 불필요한 오버헤드 없이 가장 관련성이 큰 정보를 계속 사용할 수 있습니다.
채팅 기록을 줄이는 이유
- 성능 최적화: 채팅 내역이 크면 처리 시간이 늘어나게 됩니다. 크기를 줄이면 빠르고 효율적인 상호 작용을 유지하는 데 도움이 됩니다.
- 컨텍스트 창 관리: 언어 모델에는 고정된 컨텍스트 창이 있습니다. 기록이 이 제한을 초과하면 이전 메시지가 손실됩니다. 채팅 기록을 관리하면 가장 중요한 컨텍스트에 계속 액세스할 수 있습니다.
- 메모리 효율성: 모바일 애플리케이션 또는 임베디드 시스템과 같은 리소스가 제한된 환경에서는 무제한 채팅 기록이 과도한 메모리 사용량과 성능 저하로 이어질 수 있습니다.
- 개인 정보 보호 및 보안: 불필요한 대화 기록을 유지하면 중요한 정보가 노출될 위험이 높아질 수 있습니다. 구조화된 감소 프로세스는 관련 컨텍스트를 유지하면서 데이터 보존을 최소화합니다.
채팅 기록을 줄이기 위한 전략
몇 가지 방법을 사용하여 중요한 정보를 유지하면서 채팅 기록을 관리하기 쉽게 유지할 수 있습니다.
- 잘림: 기록이 미리 정의된 제한을 초과하면 가장 오래된 메시지가 제거되어 최근 상호 작용만 유지됩니다.
- 요약: 이전 메시지는 요약으로 압축되어 키 세부 정보를 유지하면서 저장된 메시지 수를 줄입니다.
- 토큰 기반: 토큰 기반 감소는 총 토큰 수를 측정하고 제한을 초과할 때 이전 메시지를 제거하거나 요약하여 채팅 기록이 모델의 토큰 제한 내에서 유지되도록 합니다.
채팅 기록 리듀서는 기록의 크기를 평가하고 대상 수(보존할 원하는 메시지 수) 및 임계값 수(감소가 트리거되는 지점)와 같은 구성 가능한 매개 변수에 따라 이를 줄여 이러한 전략을 자동화합니다. 이러한 감소 기술을 통합하면 채팅 애플리케이션은 대화형 컨텍스트를 손상시키지 않고도 응답성과 성능을 유지할 수 있습니다.
.NET 버전의 시맨틱 커널에서 채팅 기록 리듀서 추상화는 IChatHistoryReducer
인터페이스로 정의됩니다.
namespace Microsoft.SemanticKernel.ChatCompletion;
[Experimental("SKEXP0001")]
public interface IChatHistoryReducer
{
Task<IEnumerable<ChatMessageContent>?> ReduceAsync(IReadOnlyList<ChatMessageContent> chatHistory, CancellationToken cancellationToken = default);
}
이 인터페이스는 채팅 기록 감소를 위한 사용자 지정 구현을 허용합니다.
또한 의미 체계 커널은 기본 제공 감속기를 제공합니다.
-
ChatHistoryTruncationReducer
- 채팅 기록을 지정된 크기로 잘라내고 제거된 메시지를 삭제합니다. 감소는 채팅 기록 길이가 제한을 초과할 때 트리거됩니다. -
ChatHistorySummarizationReducer
- 채팅 기록을 잘라내고, 제거된 메시지를 요약하고, 요약을 다시 채팅 기록에 단일 메시지로 추가합니다.
두 감환기는 항상 시스템 메시지를 유지하여 모델에 대한 필수 컨텍스트를 유지합니다.
다음 예제에서는 대화 흐름을 유지하면서 마지막 두 사용자 메시지만 유지하는 방법을 보여 줍니다.
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
var chatService = new OpenAIChatCompletionService(
modelId: "<model-id>",
apiKey: "<api-key>");
var reducer = new ChatHistoryTruncationReducer(targetCount: 2); // Keep system message and last user message
var chatHistory = new ChatHistory("You are a librarian and expert on books about cities");
string[] userMessages = [
"Recommend a list of books about Seattle",
"Recommend a list of books about Dublin",
"Recommend a list of books about Amsterdam",
"Recommend a list of books about Paris",
"Recommend a list of books about London"
];
int totalTokenCount = 0;
foreach (var userMessage in userMessages)
{
chatHistory.AddUserMessage(userMessage);
Console.WriteLine($"\n>>> User:\n{userMessage}");
var reducedMessages = await reducer.ReduceAsync(chatHistory);
if (reducedMessages is not null)
{
chatHistory = new ChatHistory(reducedMessages);
}
var response = await chatService.GetChatMessageContentAsync(chatHistory);
chatHistory.AddAssistantMessage(response.Content!);
Console.WriteLine($"\n>>> Assistant:\n{response.Content!}");
if (response.InnerContent is OpenAI.Chat.ChatCompletion chatCompletion)
{
totalTokenCount += chatCompletion.Usage?.TotalTokenCount ?? 0;
}
}
Console.WriteLine($"Total Token Count: {totalTokenCount}");
의미 체계 커널 리포지토리더 많은 예제를 찾을 수 있습니다.
이 섹션에서는 Python의 채팅 기록 감소에 대한 구현 세부 정보를 다룹니다. 이 접근 방식은 ChatHistory 개체와 원활하게 통합되는 ChatHistoryReducer를 만들어 채팅 기록이 필요한 곳마다 사용하고 전달할 수 있도록 하는 것입니다.
- 통합: Python에서
ChatHistoryReducer
ChatHistory
개체의 하위 클래스로 설계되었습니다. 이 상속을 사용하면 리듀서를 표준 채팅 기록 인스턴스와 호환하여 사용할 수 있습니다. - 감소 논리: 사용자는 채팅 기록 개체에서
reduce
메서드를 호출할 수 있습니다. 리듀서는 현재 메시지 수가target_count
및threshold_count
(설정된 경우)를 초과하는지 여부를 평가합니다. 이 경우 기록은 잘림 또는 요약을 통해target_count
로 축소됩니다. - 구성: 감소 동작은
target_count
(보존하려는 메시지 수) 및 threshold_count(감소 프로세스를 트리거하는 메시지 수)와 같은 매개 변수를 통해 구성할 수 있습니다.
지원되는 의미 체계 커널 Python 기록 감속기는 ChatHistorySummarizationReducer
및 ChatHistoryTruncationReducer
입니다. 리듀서 구성의 일부로 auto_reduce
add_message_async
사용할 때 기록 감소를 자동으로 적용하여 채팅 기록이 구성된 한도 내에서 유지되도록 할 수 있습니다.
다음 예제에서는 ChatHistoryTruncationReducer를 사용하여 대화 흐름을 유지하면서 마지막 두 메시지만 유지하는 방법을 보여 줍니다.
import asyncio
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.contents import ChatHistoryTruncationReducer
from semantic_kernel.kernel import Kernel
async def main():
kernel = Kernel()
kernel.add_service(AzureChatCompletion())
# Keep the last two messages
truncation_reducer = ChatHistoryTruncationReducer(
target_count=2,
)
truncation_reducer.add_system_message("You are a helpful chatbot.")
is_reduced = False
while True:
user_input = input("User:> ")
if user_input.lower() == "exit":
print("\n\nExiting chat...")
break
is_reduced = await truncation_reducer.reduce()
if is_reduced:
print(f"@ History reduced to {len(truncation_reducer.messages)} messages.")
response = await kernel.invoke_prompt(
prompt="{{$chat_history}}{{$user_input}}", user_input=user_input, chat_history=truncation_reducer
)
if response:
print(f"Assistant:> {response}")
truncation_reducer.add_user_message(str(user_input))
truncation_reducer.add_message(response.value[0])
if is_reduced:
for msg in truncation_reducer.messages:
print(f"{msg.role} - {msg.content}\n")
print("\n")
if __name__ == "__main__":
asyncio.run(main())
채팅 기록 감소는 현재 Java에서 사용할 수 없습니다.
다음 단계
이제 채팅 기록 개체를 만들고 관리하는 방법을 배웠으므로 함수 호출 항목에서 함수 호출에 대해 자세히 알아볼 수 있습니다.