히스토리 압축 (History compression)
AI 에이전트는 사용자 메시지, 어시스턴트 응답, 도구 호출 및 도구 응답을 포함하는 메시지 히스토리를 유지합니다. 이 히스토리는 에이전트가 전략을 따름에 따라 각 상호작용과 함께 커집니다.
장시간 실행되는 대화의 경우, 히스토리가 거대해져서 많은 토큰을 소비할 수 있습니다. 히스토리 압축은 전체 메시지 목록을 이후 에이전트 작업에 필요한 중요한 정보만 포함하는 하나 또는 여러 개의 메시지로 요약하여 이를 줄이는 데 도움이 됩니다.
히스토리 압축은 에이전트 시스템의 주요 과제를 해결합니다:
- 컨텍스트 사용 최적화. 집중되고 더 작은 컨텍스트는 LLM 성능을 향상시키고 토큰 제한 초과로 인한 실패를 방지합니다.
- 성능 향상. 히스토리를 압축하면 LLM이 처리하는 메시지 수가 줄어들어 응답 속도가 빨라집니다.
- 정확도 향상. 관련 정보에 집중하면 LLM이 주의 산만 없이 작업에 집중하고 완료하는 데 도움이 됩니다.
- 비용 절감. 불필요한 메시지를 줄이면 토큰 사용량이 낮아져 API 호출의 전체 비용이 감소합니다.
히스토리 압축 시점
히스토리 압축은 에이전트 워크플로의 특정 단계에서 수행됩니다:
- 에이전트 전략의 논리적 단계(서브그래프) 사이.
- 컨텍스트가 너무 길어질 때.
히스토리 압축 구현
에이전트에서 히스토리 압축을 구현하는 두 가지 주요 접근 방식이 있습니다:
- 전략 그래프(Strategy graph)에서 구현
- 커스텀 노드(Custom node)에서 구현
전략 그래프에서의 히스토리 압축
전략 그래프에서 히스토리를 압축하려면, 현재 메시지 히스토리를 간결한 요약으로 압축하는 미리 정의된 노드를 사용해야 합니다:
- Kotlin:
nodeLLMCompressHistory - Java:
AIAgentNode.llmCompressHistory()
자세한 정보와 구체적인 예제는 History compression node를 참조하세요.
압축을 수행하기로 결정한 단계에 따라 다음과 같은 시나리오가 가능합니다:
히스토리가 너무 길어질 때 히스토리를 압축하려면, 에지(edge) 조건에서 메시지 수를 확인하고 히스토리 압축 노드를 추가하세요. 히스토리 길이를 확인하려면 다음을 수행합니다:
Kotlin: 헬퍼 확장(extension)을 정의합니다.
Java:
.onCondition()에서 인라인 람다 표현식을 사용합니다.
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.agent.context.AIAgentContext
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
import ai.koog.agents.core.dsl.extension.nodeExecuteTools
import ai.koog.agents.core.dsl.extension.nodeLLMCompressHistory
import ai.koog.agents.core.dsl.extension.nodeLLMRequest
import ai.koog.agents.core.dsl.extension.nodeLLMSendToolResults
import ai.koog.agents.core.dsl.extension.onTextMessage
import ai.koog.agents.core.dsl.extension.onToolCalls
import ai.koog.agents.core.dsl.extension.ReceivedToolResults
-->
```kotlin
// 메시지가 100개 이상이면 히스토리가 너무 긴 것으로 정의
private suspend fun AIAgentContext.historyIsTooLong(): Boolean = llm.readSession { prompt.messages.size > 100 }
val strategy = strategy<String, String>("execute-with-history-compression") {
val callLLM by nodeLLMRequest()
val executeTool by nodeExecuteTools()
val sendToolResult by nodeLLMSendToolResults()
// LLM 히스토리를 압축하고 다음 노드를 위해 현재 ReceivedToolResults를 유지
val compressHistory by nodeLLMCompressHistory<ReceivedToolResults>()
edge(nodeStart forwardTo callLLM)
edge(callLLM forwardTo nodeFinish onTextMessage { true })
edge(callLLM forwardTo executeTool onToolCalls { true })
// 히스토리가 너무 긴 경우 도구를 실행한 후 히스토리를 압축
edge(executeTool forwardTo compressHistory onCondition { historyIsTooLong() })
edge(compressHistory forwardTo sendToolResult)
// 그렇지 않으면 다음 LLM 요청으로 진행
edge(executeTool forwardTo sendToolResult onCondition { !historyIsTooLong() })
edge(sendToolResult forwardTo executeTool onToolCalls { true })
edge(sendToolResult forwardTo nodeFinish onTextMessage { true })
}
```
<!--- KNIT example-history-compression-01.kt -->
=== "Java"
<!--- INCLUDE
import ai.koog.agents.core.agent.entity.AIAgentEdge;
import ai.koog.agents.core.agent.entity.AIAgentGraphStrategy;
import ai.koog.agents.core.agent.entity.AIAgentNode;
import ai.koog.prompt.message.Message;
import ai.koog.agents.core.dsl.extension.ReceivedToolResults;
class exampleHistoryCompressionJava01 {
public static void main(String[] args) {
-->
<!--- SUFFIX
}
}
-->
```java
var graph = AIAgentGraphStrategy.builder("execute-with-history-compression")
.withInput(String.class)
.withOutput(String.class);
var callLLM = AIAgentNode.llmRequest(null);
var executeTool = AIAgentNode.executeTools(null);
var sendToolResult = AIAgentNode.llmSendToolResults(null);
// LLM 히스토리를 압축하고, 전달된 ReceivedToolResults가 다음 노드로 흐름
var compressHistory = AIAgentNode
.llmCompressHistory("compressHistory")
.withInput(ReceivedToolResults.class)
.build();
// 시작(start)에서 callLLM으로의 에지
graph.edge(AIAgentEdge.builder()
.from(graph.nodeStart)
.to(callLLM)
.build());
// 텍스트 응답 시 callLLM에서 종료(finish)로의 에지
graph.edge(AIAgentEdge.builder()
.from(callLLM)
.to(graph.nodeFinish)
.onTextMessage()
.build());
// 도구 호출 시 callLLM에서 executeTool로의 에지
graph.edge(AIAgentEdge.builder()
.from(callLLM)
.to(executeTool)
.onToolCalls()
.build());
// 히스토리가 너무 긴 경우 도구를 실행한 후 히스토리를 압축
graph.edge(AIAgentEdge.builder()
.from(executeTool)
.to(compressHistory)
.onCondition((message, ctx) ->
ctx.getLlm().readSession(session ->
session.getPrompt().getMessages().size() > 100
)
)
.build());
graph.edge(compressHistory, sendToolResult);
// 그렇지 않으면 다음 LLM 요청으로 진행
graph.edge(AIAgentEdge.builder()
.from(executeTool)
.to(sendToolResult)
.onCondition((message, ctx) ->
ctx.getLlm().readSession(session ->
session.getPrompt().getMessages().size() <= 100
)
)
.build());
// 도구 호출 시 sendToolResult에서 executeTool로의 에지
graph.edge(AIAgentEdge.builder()
.from(sendToolResult)
.to(executeTool)
.onToolCalls()
.build());
// 텍스트 응답 시 sendToolResult에서 종료(finish)로의 에지
graph.edge(AIAgentEdge.builder()
.from(sendToolResult)
.to(graph.nodeFinish)
.onTextMessage()
.build());
```
<!--- KNIT exampleHistoryCompressionJava01.java -->
이 예제에서 전략은 각 도구 호출 후에 히스토리가 너무 긴지 확인합니다. 도구 결과를 LLM으로 다시 보내기 전에 히스토리가 압축됩니다. 이는 긴 대화 중에 컨텍스트가 커지는 것을 방지합니다.
- 전략의 논리적 단계(서브그래프) 사이에서 히스토리를 압축하려면 다음과 같이 전략을 구현할 수 있습니다:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
import ai.koog.agents.core.dsl.extension.nodeLLMCompressHistory
-->
```kotlin
val strategy = strategy<String, String>("execute-with-history-compression") {
val collectInformation by subgraph<String, String> {
// 정보 수집을 위한 몇 가지 단계
}
val compressHistory by nodeLLMCompressHistory<String>()
val makeTheDecision by subgraph<String, String> {
// 현재 압축된 히스토리와 수집된 정보를 기반으로 의사 결정을 내리기 위한 몇 가지 단계
}
nodeStart then collectInformation then compressHistory then makeTheDecision
}
```
<!--- KNIT example-history-compression-02.kt -->
=== "Java"
<!--- INCLUDE
import ai.koog.agents.core.agent.entity.AIAgentGraphStrategy;
import ai.koog.agents.core.agent.entity.AIAgentNode;
import ai.koog.agents.core.agent.entity.AIAgentSubgraph;
import java.util.Collections;
class exampleHistoryCompressionJava02 {
public static void main(String[] args) {
-->
<!--- SUFFIX
}
}
-->
```java
var graph = AIAgentGraphStrategy.builder("execute-with-history-compression")
.withInput(String.class)
.withOutput(String.class);
// 정보 수집을 위한 서브그래프
var collectInformation = AIAgentSubgraph.builder("collectInformation")
.withInput(String.class)
.withOutput(String.class)
.limitedTools(Collections.emptyList())
.withTask(input -> "Collect information based on: " + input)
.build();
// 정보 수집 후 히스토리 압축
var compressHistory = AIAgentNode
.llmCompressHistory("compressHistory")
.withInput(String.class)
.build();
// 압축된 히스토리를 기반으로 의사 결정을 내리는 서브그래프
var makeTheDecision = AIAgentSubgraph.builder("makeTheDecision")
.withInput(String.class)
.withOutput(String.class)
.limitedTools(Collections.emptyList())
.withTask(input -> "Make a decision based on the information")
.build();
// 흐름 구성: start -> collectInformation -> compressHistory -> makeTheDecision -> finish
graph.edge(graph.nodeStart, collectInformation);
graph.edge(collectInformation, compressHistory);
graph.edge(compressHistory, makeTheDecision);
graph.edge(makeTheDecision, graph.nodeFinish);
```
<!--- KNIT exampleHistoryCompressionJava02.java -->
이 예제에서는 정보 수집 단계를 완료한 후, 의사 결정 단계로 진행하기 전에 히스토리가 압축됩니다.
커스텀 노드에서의 히스토리 압축
커스텀 노드를 구현하는 경우, 다음과 같이 replaceHistoryWithTLDR() 함수(Kotlin)를 사용하여 히스토리를 압축할 수 있습니다:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
val strategy = strategy<String, String>("strategy_name") {
val node by node<Unit, Unit> {
-->
<!--- SUFFIX
}
}
-->
```kotlin
llm.writeSession {
replaceHistoryWithTLDR()
}
```
<!--- KNIT example-history-compression-03.kt -->
이 접근 방식은 특정 요구 사항에 따라 커스텀 노드 로직의 어느 시점에서든 압축을 구현할 수 있는 더 많은 유연성을 제공합니다.
커스텀 노드에 대해 더 자세히 알아보려면 Custom nodes를 참조하세요.
히스토리 압축 전략
선택적인 strategy 매개변수를 사용하여 압축 프로세스를 커스터마이징할 수 있습니다:
- Kotlin: 전략을
nodeLLMCompressHistory(strategy=...)또는replaceHistoryWithTLDR(strategy=...)에 전달합니다. - Java:
.compressionStrategy()빌더 메서드를 사용합니다.
프레임워크는 여러 내장 전략을 제공합니다.
WholeHistory (기본값)
지금까지 달성된 내용을 요약하는 하나의 요약(TLDR) 메시지로 전체 히스토리를 압축하는 기본 전략입니다. 이 전략은 토큰 사용량을 줄이면서 전체 대화 컨텍스트에 대한 인식을 유지하려는 대부분의 일반적인 사용 사례에 잘 작동합니다.
다음과 같이 사용할 수 있습니다:
- 전략 그래프에서:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy
import ai.koog.agents.core.dsl.extension.nodeLLMCompressHistory
typealias ProcessedInput = String
val strategy = strategy<String, String>("strategy_name") {
val node by node<Unit, Unit> {
-->
<!--- SUFFIX
}
}
-->
```kotlin
val compressHistory by nodeLLMCompressHistory<ProcessedInput>(
strategy = HistoryCompressionStrategy.WholeHistory
)
```
<!--- KNIT example-history-compression-04.kt -->
=== "Java"
<!--- INCLUDE
import ai.koog.agents.core.agent.entity.AIAgentGraphStrategy;
import ai.koog.agents.core.agent.entity.AIAgentNode;
import ai.koog.agents.core.agent.entity.AIAgentSubgraph;
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy;
class exampleHistoryCompressionJava03 {
public static void main(String[] args) {
var graph = AIAgentGraphStrategy.builder("execute-with-history-compression")
.withInput(String.class)
.withOutput(String.class);
-->
<!--- SUFFIX
}
}
-->
```java
// 압축 노드에서 WholeHistory 전략 사용
var compressHistory = AIAgentNode
.llmCompressHistory("compressHistory")
.withInput(String.class)
.compressionStrategy(HistoryCompressionStrategy.WholeHistory)
.build();
// 참고: 이 예제는 노드 생성만 보여줍니다.
// 그래프를 완성하려면 에지와 다른 노드들을 추가해야 합니다.
```
<!--- KNIT exampleHistoryCompressionJava03.java -->
- 커스텀 노드에서:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy
val strategy = strategy<String, String>("strategy_name") {
val node by node<Unit, Unit> {
-->
<!--- SUFFIX
}
}
-->
```kotlin
llm.writeSession {
replaceHistoryWithTLDR(strategy = HistoryCompressionStrategy.WholeHistory)
}
```
<!--- KNIT example-history-compression-05.kt -->
=== "Java"
<!--- INCLUDE
import ai.koog.agents.core.agent.entity.AIAgentGraphStrategy;
import ai.koog.agents.core.agent.entity.AIAgentNode;
import ai.koog.agents.core.agent.entity.AIAgentSubgraph;
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy;
class exampleHistoryCompressionJava05 {
public static void main(String[] args) {
var graph = AIAgentGraphStrategy.builder("execute-with-history-compression")
.withInput(String.class)
.withOutput(String.class);
var compressHistory = AIAgentNode.builder()
.withInput(String.class)
.withOutput(String.class)
.withAction((input, ctx) -> {
-->
<!--- SUFFIX
return null;
})
.build();
}
}
-->
```java
ctx.getLlm().writeSession(session -> {
session.replaceHistoryWithTLDR(HistoryCompressionStrategy.WholeHistory);
return null;
});
```
<!--- KNIT exampleHistoryCompressionJava04.java -->
FromLastNMessages
마지막 n개의 메시지만 요약(TLDR) 메시지로 압축하고 이전 메시지는 완전히 폐기하는 전략입니다. 이는 에이전트의 최신 성과(또는 최근에 발견된 사실, 최신 컨텍스트)만 문제 해결과 관련이 있을 때 유용합니다.
다음과 같이 사용할 수 있습니다:
- 전략 그래프에서:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy
import ai.koog.agents.core.dsl.extension.nodeLLMCompressHistory
typealias ProcessedInput = String
val strategy = strategy<String, String>("strategy_name") {
val node by node<Unit, Unit> {
-->
<!--- SUFFIX
}
}
-->
```kotlin
val compressHistory by nodeLLMCompressHistory<ProcessedInput>(
strategy = HistoryCompressionStrategy.FromLastNMessages(5)
)
```
<!--- KNIT example-history-compression-06.kt -->
=== "Java"
<!--- INCLUDE
import ai.koog.agents.core.agent.entity.AIAgentGraphStrategy;
import ai.koog.agents.core.agent.entity.AIAgentNode;
import ai.koog.agents.core.agent.entity.AIAgentSubgraph;
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy;
class exampleHistoryCompressionJava04 {
public static void main(String[] args) {
var graph = AIAgentGraphStrategy.builder("execute-with-history-compression")
.withInput(String.class)
.withOutput(String.class);
-->
<!--- SUFFIX
}
}
-->
```java
// FromLastNMessages 전략을 사용하여 마지막 5개의 메시지만 압축
var compressHistory = AIAgentNode
.llmCompressHistory("compressHistory")
.withInput(String.class)
.compressionStrategy(HistoryCompressionStrategy.FromLastNMessages(5))
.build();
// 참고: 이 예제는 노드 생성만 보여줍니다.
// 그래프를 완성하려면 에지와 다른 노드들을 추가해야 합니다.
```
<!--- KNIT exampleHistoryCompressionJava05.java -->
- 커스텀 노드에서:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy
typealias ProcessedInput = String
val strategy = strategy<String, String>("strategy_name") {
val node by node<Unit, Unit> {
-->
<!--- SUFFIX
}
}
-->
```kotlin
llm.writeSession {
replaceHistoryWithTLDR(strategy = HistoryCompressionStrategy.FromLastNMessages(5))
}
```
<!--- KNIT example-history-compression-07.kt -->
=== "Java"
<!--- INCLUDE
import ai.koog.agents.core.agent.entity.AIAgentGraphStrategy;
import ai.koog.agents.core.agent.entity.AIAgentNode;
import ai.koog.agents.core.agent.entity.AIAgentSubgraph;
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy;
class exampleHistoryCompressionJava07 {
public static void main(String[] args) {
var graph = AIAgentGraphStrategy.builder("execute-with-history-compression")
.withInput(String.class)
.withOutput(String.class);
var compressHistory = AIAgentNode.builder()
.withInput(String.class)
.withOutput(String.class)
.withAction((input, ctx) -> {
-->
<!--- SUFFIX
return null;
})
.build();
}
}
-->
```java
ctx.getLlm().writeSession(session -> {
session.replaceHistoryWithTLDR(HistoryCompressionStrategy.FromLastNMessages(5));
return null;
});
```
<!--- KNIT exampleHistoryCompressionJava06.java -->
Chunked
전체 메시지 히스토리를 고정된 크기의 청크(chunk)로 나누고 각 청크를 독립적으로 요약(TLDR) 메시지로 압축하는 전략입니다. 이는 지금까지 수행된 작업에 대한 간결한 요약뿐만 아니라 전체 진행 상황을 추적해야 하고, 일부 오래된 정보도 중요할 수 있는 경우에 유용합니다.
다음과 같이 사용할 수 있습니다:
- 전략 그래프에서:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy
import ai.koog.agents.core.dsl.extension.nodeLLMCompressHistory
typealias ProcessedInput = String
val strategy = strategy<String, String>("strategy_name") {
val node by node<Unit, Unit> {
-->
<!--- SUFFIX
}
}
-->
```kotlin
val compressHistory by nodeLLMCompressHistory<ProcessedInput>(
strategy = HistoryCompressionStrategy.Chunked(10)
)
```
<!--- KNIT example-history-compression-08.kt -->
=== "Java"
<!--- INCLUDE
import ai.koog.agents.core.agent.entity.AIAgentGraphStrategy;
import ai.koog.agents.core.agent.entity.AIAgentNode;
import ai.koog.agents.core.agent.entity.AIAgentSubgraph;
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy;
class exampleHistoryCompressionJava08 {
public static void main(String[] args) {
var graph = AIAgentGraphStrategy.builder("execute-with-history-compression")
.withInput(String.class)
.withOutput(String.class);
-->
<!--- SUFFIX
}
}
-->
```java
// Chunked 전략을 사용하여 히스토리를 10개 메시지 단위의 청크로 압축
var compressHistory = AIAgentNode
.llmCompressHistory("compressHistory")
.withInput(String.class)
.compressionStrategy(HistoryCompressionStrategy.Chunked(10))
.build();
// 참고: 이 예제는 노드 생성만 보여줍니다.
// 그래프를 완성하려면 에지와 다른 노드들을 추가해야 합니다.
```
<!--- KNIT exampleHistoryCompressionJava07.java -->
- 커스텀 노드에서:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy
typealias ProcessedInput = String
val strategy = strategy<String, String>("strategy_name") {
val node by node<Unit, Unit> {
-->
<!--- SUFFIX
}
}
-->
```kotlin
llm.writeSession {
replaceHistoryWithTLDR(strategy = HistoryCompressionStrategy.Chunked(10))
}
```
<!--- KNIT example-history-compression-09.kt -->
=== "Java"
<!--- INCLUDE
import ai.koog.agents.core.agent.entity.AIAgentGraphStrategy;
import ai.koog.agents.core.agent.entity.AIAgentNode;
import ai.koog.agents.core.agent.entity.AIAgentSubgraph;
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy;
class exampleHistoryCompressionJava09 {
public static void main(String[] args) {
var graph = AIAgentGraphStrategy.builder("execute-with-history-compression")
.withInput(String.class)
.withOutput(String.class);
var compressHistory = AIAgentNode.builder()
.withInput(String.class)
.withOutput(String.class)
.withAction((input, ctx) -> {
-->
<!--- SUFFIX
return null;
})
.build();
}
}
-->
```java
ctx.getLlm().writeSession(session -> {
session.replaceHistoryWithTLDR(HistoryCompressionStrategy.Chunked(10));
return null;
});
```
<!--- KNIT exampleHistoryCompressionJava08.java -->
FactRetrievalHistoryCompressionStrategy
히스토리에서 제공된 개념(concept) 목록과 관련된 특정 사실을 검색하여 추출하는 전략입니다. 전체 히스토리를 이러한 사실로만 변경하고 향후 LLM 요청을 위한 컨텍스트로 남겨둡니다. 이는 LLM이 작업을 더 잘 수행하기 위해 어떤 정확한 사실이 관련될지 알고 있을 때 유용합니다.
다음과 같이 사용할 수 있습니다:
- 전략 그래프에서:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
import ai.koog.agents.core.dsl.extension.nodeLLMCompressHistory
import ai.koog.agents.core.dsl.extension.FactRetrievalHistoryCompressionStrategy
import ai.koog.agents.core.dsl.extension.Concept
import ai.koog.agents.core.dsl.extension.FactType
typealias ProcessedInput = String
val strategy = strategy<String, String>("strategy_name") {
val node by node<Unit, Unit> {
-->
<!--- SUFFIX
}
}
-->
```kotlin
val compressHistory by nodeLLMCompressHistory<ProcessedInput>(
strategy = FactRetrievalHistoryCompressionStrategy(
Concept(
keyword = "user_preferences",
// LLM에 대한 설명 -- 구체적으로 무엇을 검색할지
description = "User's preferences for the recommendation system, including the preferred conversation style, theme in the application, etc.",
// LLM은 이 개념과 관련된 여러 관련 사실을 검색합니다:
factType = FactType.MULTIPLE
),
Concept(
keyword = "product_details",
// LLM에 대한 설명 -- 구체적으로 무엇을 검색할지
description = "Brief details about products in the catalog the user has been checking",
// LLM은 이 개념과 관련된 여러 관련 사실을 검색합니다:
factType = FactType.MULTIPLE
),
Concept(
keyword = "issue_solved",
// LLM에 대한 설명 -- 구체적으로 무엇을 검색할지
description = "Was the initial user's issue resolved?",
// LLM은 질문에 대한 단일 답변을 검색합니다:
factType = FactType.SINGLE
)
)
)
```
<!--- KNIT example-history-compression-10.kt -->
=== "Java"
<!--- INCLUDE
import ai.koog.agents.core.agent.entity.AIAgentGraphStrategy;
import ai.koog.agents.core.agent.entity.AIAgentNode;
import ai.koog.agents.core.environment.ReceivedToolResult;
import ai.koog.agents.core.dsl.extension.FactRetrievalHistoryCompressionStrategy;
import ai.koog.agents.core.dsl.extension.Concept;
import ai.koog.agents.core.dsl.extension.FactType;
class exampleHistoryCompressionJava06 {
public static void main(String[] args) {
var graph = AIAgentGraphStrategy.builder("execute-with-history-compression")
.withInput(String.class)
.withOutput(String.class);
-->
<!--- SUFFIX
}
}
-->
```java
// FactRetrievalHistoryCompressionStrategy 전략을 사용하여 특정 사실 추출
var compressHistory = AIAgentNode
.llmCompressHistory("compressHistory")
.withInput(ReceivedToolResult.class)
.compressionStrategy(new FactRetrievalHistoryCompressionStrategy(
new Concept(
"user_preferences",
"User's preferences for the recommendation system, including the preferred conversation style, theme in the application, etc.",
FactType.MULTIPLE
),
new Concept(
"product_details",
"Brief details about products in the catalog the user has been checking",
FactType.MULTIPLE
),
new Concept(
"issue_solved",
"Was the initial user's issue resolved?",
FactType.SINGLE
)
))
.build();
// 참고: 이 예제는 노드 생성만 보여줍니다.
// 그래프를 완성하려면 에지와 다른 노드들을 추가해야 합니다.
```
<!--- KNIT exampleHistoryCompressionJava09.java -->
- 커스텀 노드에서:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
import ai.koog.agents.core.dsl.extension.FactRetrievalHistoryCompressionStrategy
import ai.koog.agents.core.dsl.extension.Concept
import ai.koog.agents.core.dsl.extension.FactType
typealias ProcessedInput = String
val strategy = strategy<String, String>("strategy_name") {
val node by node<Unit, Unit> {
-->
<!--- SUFFIX
}
}
-->
```kotlin
llm.writeSession {
replaceHistoryWithTLDR(
strategy = FactRetrievalHistoryCompressionStrategy(
Concept(
keyword = "user_preferences",
// LLM에 대한 설명 -- 구체적으로 무엇을 검색할지
description = "User's preferences for the recommendation system, including the preferred conversation style, theme in the application, etc.",
// LLM은 이 개념과 관련된 여러 관련 사실을 검색합니다:
factType = FactType.MULTIPLE
),
Concept(
keyword = "product_details",
// LLM에 대한 설명 -- 구체적으로 무엇을 검색할지
description = "Brief details about products in the catalog the user has been checking",
// LLM은 이 개념과 관련된 여러 관련 사실을 검색합니다:
factType = FactType.MULTIPLE
),
Concept(
keyword = "issue_solved",
// LLM에 대한 설명 -- 구체적으로 무엇을 검색할지
description = "Was the initial user's issue resolved?",
// LLM은 질문에 대한 단일 답변을 검색합니다:
factType = FactType.SINGLE
)
)
)
}
```
<!--- KNIT example-history-compression-11.kt -->
=== "Java"
<!--- INCLUDE
import ai.koog.agents.core.agent.entity.AIAgentGraphStrategy;
import ai.koog.agents.core.agent.entity.AIAgentNode;
import ai.koog.agents.core.agent.entity.AIAgentSubgraph;
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy;
import ai.koog.agents.core.dsl.extension.FactRetrievalHistoryCompressionStrategy;
import ai.koog.agents.core.dsl.extension.Concept;
import ai.koog.agents.core.dsl.extension.FactType;
class exampleHistoryCompressionJava11 {
public static void main(String[] args) {
var graph = AIAgentGraphStrategy.builder("execute-with-history-compression")
.withInput(String.class)
.withOutput(String.class);
var compressHistory = AIAgentNode.builder()
.withInput(String.class)
.withOutput(String.class)
.withAction((input, ctx) -> {
-->
<!--- SUFFIX
return null;
})
.build();
}
}
-->
```java
ctx.getLlm().writeSession(session -> {
session.replaceHistoryWithTLDR(new FactRetrievalHistoryCompressionStrategy(
new Concept(
"user_preferences",
// LLM에 대한 설명 -- 구체적으로 무엇을 검색할지
"User's preferences for the recommendation system, including the preferred conversation style, theme in the application, etc.",
// LLM은 이 개념과 관련된 여러 관련 사실을 검색합니다:
FactType.MULTIPLE
),
new Concept(
"product_details",
// LLM에 대한 설명 -- 구체적으로 무엇을 검색할지
"Brief details about products in the catalog the user has been checking",
// LLM은 이 개념과 관련된 여러 관련 사실을 검색합니다:
FactType.MULTIPLE
),
new Concept(
"issue_solved",
// LLM에 대한 설명 -- 구체적으로 무엇을 검색할지
"Was the initial user's issue resolved?",
// LLM은 질문에 대한 단일 답변을 검색합니다:
FactType.SINGLE
)
));
return null;
});
```
<!--- KNIT exampleHistoryCompressionJava10.java -->
커스텀 히스토리 압축 전략 구현
WARNING
커스텀 히스토리 압축 전략은 Kotlin에서만 사용할 수 있습니다.
HistoryCompressionStrategy 추상 클래스를 확장하고 compress 메서드를 구현하여 자신만의 히스토리 압축 전략을 만들 수 있습니다.
예시는 다음과 같습니다:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.agent.session.AIAgentLLMWriteSession
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy
import ai.koog.prompt.message.Message
import ai.koog.prompt.message.MessagePart
-->
```kotlin
class MyCustomCompressionStrategy : HistoryCompressionStrategy() {
override suspend fun compress(
llmSession: AIAgentLLMWriteSession,
memoryMessages: List<Message>
) {
// 1. llmSession.prompt.messages의 현재 히스토리를 처리합니다.
// 2. 새로운 압축된 메시지를 생성합니다.
// 3. 압축된 메시지로 프롬프트를 업데이트합니다.
// 보존을 위해 원본 메시지를 저장합니다.
val originalMessages = llmSession.prompt.messages
// 예시 구현:
val importantMessages = llmSession.prompt.messages
.filterIsInstance<Message.Assistant>()
.filter { message ->
// 커스텀 필터링 로직
message.parts.filterIsInstance<MessagePart.Text>().any { it.text.contains("important") }
}
// 참고: `llmSession`을 사용하여 LLM 요청을 할 수도 있으며,
// 예를 들어 `llmSession.requestLLMWithoutTools()`를 사용하여 LLM에게 작업을 요청할 수 있습니다.
// 또는 현재 모델을 변경할 수 있습니다: `llmSession.model = AnthropicModels.Opus_4_6` 그리고 다른 LLM 모델에 요청할 수 있습니다.
// 하지만 나중에 다시 변경하는 것을 잊지 마세요.
// 필터링된 메시지로 프롬프트를 구성합니다.
val compressedMessages = composeMessageHistory(
originalMessages,
importantMessages,
memoryMessages
)
}
}
```
<!--- KNIT example-history-compression-12.kt -->
이 예제에서 커스텀 전략은 "important"라는 단어가 포함된 메시지를 필터링하고 압축된 히스토리에 해당 메시지만 유지합니다.
그런 다음 다음과 같이 사용할 수 있습니다:
- 전략 그래프에서:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
import ai.koog.agents.core.dsl.extension.nodeLLMCompressHistory
import ai.koog.agents.example.exampleHistoryCompression12.MyCustomCompressionStrategy
typealias ProcessedInput = String
val strategy = strategy<String, String>("strategy_name") {
-->
<!--- SUFFIX
}
-->
```kotlin
val compressHistory by nodeLLMCompressHistory<ProcessedInput>(
strategy = MyCustomCompressionStrategy()
)
```
<!--- KNIT example-history-compression-13.kt -->
- 커스텀 노드에서:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
import ai.koog.agents.example.exampleHistoryCompression12.MyCustomCompressionStrategy
typealias ProcessedInput = String
val strategy = strategy<String, String>("strategy_name") {
val node by node<Unit, Unit> {
-->
<!--- SUFFIX
}
}
-->
```kotlin
llm.writeSession {
replaceHistoryWithTLDR(strategy = MyCustomCompressionStrategy())
}
```
<!--- KNIT example-history-compression-14.kt -->
압축 중 메모리 보존
모든 히스토리 압축 방법은 압축 중에 메모리 관련 메시지를 보존할지 여부를 결정하는 메모리 보존을 지원합니다. Kotlin에서는 preserveMemory 매개변수를 사용하세요. Java에서는 .preserveMemory() 빌더 메서드를 사용하세요. 이러한 메시지는 메모리에서 검색된 사실을 포함하거나 메모리 기능이 활성화되지 않았음을 나타내는 메시지입니다.
메모리 보존을 활성화하려면:
Kotlin:
preserveMemory매개변수를 사용합니다.Java:
.preserveMemory()빌더 메서드를 사용합니다.전략 그래프에서:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy
import ai.koog.agents.core.dsl.extension.nodeLLMCompressHistory
typealias ProcessedInput = String
val strategy = strategy<String, String>("strategy_name") {
-->
<!--- SUFFIX
}
-->
```kotlin
val compressHistory by nodeLLMCompressHistory<ProcessedInput>(
strategy = HistoryCompressionStrategy.WholeHistory,
preserveMemory = true
)
```
<!--- KNIT example-history-compression-15.kt -->
=== "Java"
<!--- INCLUDE
import ai.koog.agents.core.agent.entity.AIAgentGraphStrategy;
import ai.koog.agents.core.agent.entity.AIAgentNode;
import ai.koog.agents.core.agent.entity.AIAgentSubgraph;
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy;
class exampleHistoryCompressionJava15 {
public static void main(String[] args) {
var graph = AIAgentGraphStrategy.builder("execute-with-history-compression")
.withInput(String.class)
.withOutput(String.class);
-->
<!--- SUFFIX
}
}
-->
```java
// preserveMemory=true와 함께 WholeHistory 전략 사용
var compressHistory = AIAgentNode
.llmCompressHistory("compressHistory")
.withInput(String.class)
.compressionStrategy(HistoryCompressionStrategy.WholeHistory)
.preserveMemory(true)
.build();
// 참고: 이 예제는 노드 생성만 보여줍니다.
// 그래프를 완성하려면 에지와 다른 노드들을 추가해야 합니다.
```
<!--- KNIT exampleHistoryCompressionJava11.java -->
- 커스텀 노드에서:
=== "Kotlin"
<!--- INCLUDE
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.dsl.builder.node
import ai.koog.agents.core.dsl.builder.subgraph
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy
typealias ProcessedInput = String
val strategy = strategy<String, String>("strategy_name") {
val node by node<Unit, Unit> {
-->
<!--- SUFFIX
}
}
-->
```kotlin
llm.writeSession {
replaceHistoryWithTLDR(
strategy = HistoryCompressionStrategy.WholeHistory,
preserveMemory = true
)
}
```
<!--- KNIT example-history-compression-16.kt -->
=== "Java"
<!--- INCLUDE
import ai.koog.agents.core.agent.entity.AIAgentGraphStrategy;
import ai.koog.agents.core.agent.entity.AIAgentNode;
import ai.koog.agents.core.agent.entity.AIAgentSubgraph;
import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy;
class exampleHistoryCompressionJava16 {
public static void main(String[] args) {
var graph = AIAgentGraphStrategy.builder("execute-with-history-compression")
.withInput(String.class)
.withOutput(String.class);
var compressHistory = AIAgentNode.builder()
.withInput(String.class)
.withOutput(String.class)
.withAction((input, ctx) -> {
-->
<!--- SUFFIX
return null;
})
.build();
}
}
-->
```java
ctx.getLlm().writeSession(session -> {
session.replaceHistoryWithTLDR(
/** strategy */ HistoryCompressionStrategy.WholeHistory,
/** preserveMemory */ true
);
return null;
});
```
<!--- KNIT exampleHistoryCompressionJava12.java -->
