Skip to content

歷程記錄壓縮

AI agent 會維護一個訊息歷程記錄,其中包含使用者訊息、助理回應、工具呼叫和工具回應。 此歷程記錄會隨著每次互動而增長,因為 agent 會遵循其策略。

對於長時間運作的對話,歷程記錄可能會變得非常龐大並消耗大量 token。 歷程記錄壓縮透過將完整的訊息列表摘要成一條或多條僅包含後續 agent 運作所需重要資訊的訊息,來協助減少這種消耗。

歷程記錄壓縮解決了 agent 系統中的關鍵挑戰:

  • 最佳化上下文使用量。集中且較小的上下文可提升 LLM 效能,並防止因超過 token 限制而導致的失敗。
  • 提升效能。壓縮歷程記錄可減少 LLM 處理的訊息數量,從而加快回應速度。
  • 增強準確性。專注於相關資訊有助於 LLM 保持集中並完成任務,而不會受到干擾。
  • 降低成本。減少無關訊息可降低 token 使用量,進而降低 API 呼叫的整體成本。

何時壓縮歷程記錄

歷程記錄壓縮會在 agent 工作流的特定步驟執行:

  • 在 agent 策略的邏輯步驟(子圖 subgraph)之間。
  • 當上下文變得過長時。

歷程記錄壓縮實作

在您的 agent 中實作歷程記錄壓縮有兩種主要方法:

  • 在策略圖 (strategy graph) 中
  • 在自訂節點 (custom node) 中

策略圖中的歷程記錄壓縮

要在策略圖中壓縮歷程記錄,您需要使用預定義的節點,該節點會將目前的訊息歷程記錄壓縮成簡潔的摘要:

  • KotlinnodeLLMCompressHistory
  • JavaAIAgentNode.llmCompressHistory()

如需更多資訊和具體範例,請參閱 歷程記錄壓縮節點

根據您決定執行壓縮的步驟,可以使用以下情境:

  • 若要在歷程記錄變得過長時進行壓縮,請檢查 edge 條件中的訊息數量,並新增歷程記錄壓縮節點。若要檢查歷程記錄長度,請執行以下操作:

  • Kotlin:定義一個輔助擴充 (helper extension)。

  • Java:在 .onCondition() 中使用內嵌 lambda 運算式。

=== "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 的 edge
graph.edge(AIAgentEdge.builder()
    .from(graph.nodeStart)
    .to(callLLM)
    .build());

// 收到文本回應時,從 callLLM 到 finish 的 edge
graph.edge(AIAgentEdge.builder()
    .from(callLLM)
    .to(graph.nodeFinish)
    .onTextMessage()
    .build());

// 收到工具呼叫時,從 callLLM 到 executeTool 的 edge
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 的 edge
graph.edge(AIAgentEdge.builder()
    .from(sendToolResult)
    .to(executeTool)
    .onToolCalls()
    .build());

// 收到文本回應時,從 sendToolResult 到 finish 的 edge
graph.edge(AIAgentEdge.builder()
    .from(sendToolResult)
    .to(graph.nodeFinish)
    .onTextMessage()
    .build());
```
<!--- KNIT exampleHistoryCompressionJava01.java -->

在此範例中,策略會在每次工具呼叫後檢查歷程記錄是否過長。 歷程記錄會在將工具結果傳回 LLM 之前進行壓縮。這可以防止上下文在長時間對話期間無限增長。

  • 若要在策略的邏輯步驟(子圖 subgraph)之間壓縮歷程記錄,您可以按照以下方式實作您的策略:

=== "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 -->

這種方法讓您能夠根據特定需求,在自訂節點邏輯中的任何位置靈活地實作壓縮。

若要了解更多關於自訂節點的資訊,請參閱 自訂節點

歷程記錄壓縮策略

您可以透過選用的 strategy 參數來自訂壓縮過程:

  • Kotlin:將策略傳遞給 nodeLLMCompressHistory(strategy=...)replaceHistoryWithTLDR(strategy=...)
  • Java:使用 .compressionStrategy() builder 方法。

該架構提供了幾種內建策略。

WholeHistory (預設)

這是預設策略,它將整個歷程記錄壓縮成一條 TLDR 訊息,摘要目前為止已完成的工作。 此策略適用於大多數一般使用案例,即您希望在減少 token 使用量的同時,維持對整個對話上下文的覺察。

您可以按以下方式使用它:

  • 在策略圖中:

=== "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();

// 注意:此範例僅顯示節點的建立。
// 您需要新增 edge 和其他節點來完成圖。
```
<!--- 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 訊息,並完全捨棄較早的訊息。 當只有 agent 的最新成就(或最新發現的事實、最新的上下文)與解決問題相關時,這非常有用。

您可以按以下方式使用它:

  • 在策略圖中:

=== "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();

// 注意:此範例僅顯示節點的建立。
// 您需要新增 edge 和其他節點來完成圖。
```
<!--- 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

此策略將整個訊息歷程記錄分成固定大小的區塊,並將每個區塊獨立壓縮成一條 TLDR 訊息。 當您不僅需要目前為止所做工作的簡潔 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();

// 注意:此範例僅顯示節點的建立。
// 您需要新增 edge 和其他節點來完成圖。
```
<!--- 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

此策略在歷程記錄中搜尋與提供的概念 (concepts) 列表相關的特定事實並將其擷取。 它將整個歷程記錄更改為僅包含這些事實,並將其作為未來 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 將搜尋與此 concept 相關的多個相關事實:
            factType = FactType.MULTIPLE
        ),
        Concept(
            keyword = "product_details",
            // 給 LLM 的描述 -- 具體要搜尋什麼
            description = "Brief details about products in the catalog the user has been checking",
            // LLM 將搜尋與此 concept 相關的多個相關事實:
            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();

    // 注意:此範例僅顯示節點的建立。
    // 您需要新增 edge 和其他節點來完成圖。
```
<!--- 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 將搜尋與此 concept 相關的多個相關事實:
                factType = FactType.MULTIPLE
            ),
            Concept(
                keyword = "product_details",
                // 給 LLM 的描述 -- 具體要搜尋什麼
                description = "Brief details about products in the catalog the user has been checking",
                // LLM 將搜尋與此 concept 相關的多個相關事實:
                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 將搜尋與此 concept 相關的多個相關事實:
                FactType.MULTIPLE
            ),
            new Concept(
                "product_details",
                // 給 LLM 的描述 -- 具體要搜尋什麼
                "Brief details about products in the catalog the user has been checking",
                // LLM 將搜尋與此 concept 相關的多個相關事實:
                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. 使用壓縮後的訊息更新 prompt

        // 儲存原始訊息以保留它們
        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 請求,並要求 LLM 為您執行某些工作,
        // 例如使用 `llmSession.requestLLMWithoutTools()`
        // 或者您可以更改目前的模型:`llmSession.model = AnthropicModels.Opus_4_6` 並詢問其他 LLM 模型 -- 但別忘了之後要改回來

        // 使用過濾後的訊息組成 prompt
        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() builder 方法。 這些訊息包含從記憶體中檢索到的事實,或表示記憶功能尚未啟用的訊息。

若要啟用記憶保留:

  • Kotlin:使用 preserveMemory 參數。

  • Java:使用 .preserveMemory() builder 方法。

  • 在策略圖中:

=== "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
// 使用 WholeHistory 策略並設定 preserveMemory=true
var compressHistory = AIAgentNode
    .llmCompressHistory("compressHistory")
    .withInput(String.class)
    .compressionStrategy(HistoryCompressionStrategy.WholeHistory)
    .preserveMemory(true)
    .build();

// 注意:此範例僅顯示節點的建立。
// 您需要新增 edge 和其他節點來完成圖。
```
<!--- 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 -->