Compartilhar via


Compactação

À medida que as conversas crescem, a contagem de tokens do histórico de chat pode exceder as janelas de contexto do modelo ou aumentar os custos. As estratégias de compactação reduzem o tamanho do histórico de conversas, preservando o contexto importante, para que os agentes possam continuar funcionando em interações de longa execução.

Importante

A estrutura de compactação é atualmente experimental. Para usá-lo, você precisará adicionar #pragma warning disable MAAI001.

Importante

A estrutura de compactação atualmente é experimental no Python. Importar estratégias de agent_framework._compaction.

Por que a compactação importa

Cada chamada para uma LLM inclui o histórico completo da conversa. Sem compactação:

  • Limites de token — as conversas eventualmente excedem a janela de contexto do modelo, causando erros.
  • Custo – prompts maiores consomem mais tokens, aumentando os custos da API.
  • Latência – mais tokens de entrada significa tempos de resposta mais lentos.

A compactação resolve esses problemas removendo, colapsando ou resumindo seletivamente partes mais antigas da conversa.

Conceitos principais

Aplicação: apenas para agentes de histórico em memória

A compactação se aplica somente a agentes que gerenciam seu próprio histórico de conversas na memória. Os agentes que dependem do contexto gerenciado pelo serviço ou do estado de conversa não se beneficiam da compactação porque o serviço já lida com o gerenciamento de contexto. Exemplos de agentes gerenciados pelo serviço incluem:

  • Foundry Agents — o contexto é gerenciado do lado do servidor pelo serviço Azure AI Foundry.
  • API de respostas com o repositório habilitado (o padrão) – o estado da conversa é armazenado e gerenciado pelo serviço OpenAI.
  • Agentes do Copilot Studio – o contexto de conversa é mantido pelo serviço Copilot Studio.

Para esses tipos de agente, a configuração de uma estratégia de compactação não tem efeito. A compactação só é relevante quando o agente mantém sua própria lista de mensagens na memória e passa o histórico completo para o modelo em cada chamada.

A compactação opera em uma MessageIndex exibição estruturada da lista de mensagens simples que agrupa mensagens em unidades atômicas chamadas MessageGroup instâncias. Cada grupo controla sua contagem de mensagens, contagem de bytes e contagem de tokens estimada.

Grupos de mensagens

Um MessageGroup representa mensagens logicamente relacionadas que devem ser mantidas ou removidas juntas. Por exemplo, uma mensagem de assistente que contém chamadas de ferramenta e suas mensagens de resultado de ferramenta correspondentes formam um grupo atômico, e remover uma sem a outra causaria erros de API LLM.

Cada grupo tem um MessageGroupKind:

Variante Descrição
System Uma ou mais mensagens do sistema. Sempre preservados durante a compactação.
User Uma única mensagem de usuário que inicia um novo turno.
AssistantText Uma resposta de texto de assistente sem formatação (nenhuma chamada de ferramenta).
ToolCall Uma mensagem de assistente com chamadas de ferramenta e as mensagens de resultado da ferramenta correspondentes, tratadas como uma unidade atômica.
Summary Uma mensagem condensada produzida pela compactação de resumo.

Gatilhos

Um CompactionTrigger é um delegado que avalia se a compactação deve continuar com base nas métricas atuais MessageIndex :

public delegate bool CompactionTrigger(MessageIndex index);

A CompactionTriggers classe fornece métodos comuns de fábrica:

Disparador Acionado quando
CompactionTriggers.Always Todas as vezes (incondicionalmente).
CompactionTriggers.Never Nunca (desabilita a compactação).
CompactionTriggers.TokensExceed(maxTokens) A contagem de tokens incluída excede o limite.
CompactionTriggers.MessagesExceed(maxMessages) A contagem de mensagens incluídas excede o limite.
CompactionTriggers.TurnsExceed(maxTurns) A contagem de turnos de usuário incluída excede o limite.
CompactionTriggers.GroupsExceed(maxGroups) A contagem de grupos já incluídos excede o limite máximo.
CompactionTriggers.HasToolCalls() Existe pelo menos um grupo de chamadas de ferramentas não excluído.

Combinar gatilhos com CompactionTriggers.All(...) (AND lógico) ou CompactionTriggers.Any(...) (OR lógico):

// Compact only when there are tool calls AND tokens exceed 2000
CompactionTrigger trigger = CompactionTriggers.All(
    CompactionTriggers.HasToolCalls(),
    CompactionTriggers.TokensExceed(2000));

Gatilho versus alvo

Cada estratégia tem dois predicados:

  • Gatilho – Controla quando a compactação começa. Se o gatilho retornar false, a estratégia será totalmente ignorada.
  • Destino – Controla quando a compactação é interrompida. As estratégias excluem incrementalmente grupos e reavaliam o alvo após cada etapa, parando assim que o alvo retornar true.

Quando nenhum destino é especificado, ele usa como padrão o inverso do gatilho – a compactação é interrompida assim que a condição de gatilho não é mais disparada.

A compactação opera em uma lista simples de Message objetos. As mensagens são anotadas com metadados de grupo leves e as estratégias modificam essas anotações em vigor para marcar grupos como excluídos antes que a lista de mensagens seja projetada para o modelo.

Grupos de mensagens

As mensagens são agrupadas em unidades atômicas. Cada grupo recebe um GroupKind:

Variante Descrição
system Mensagens do sistema. Sempre preservado durante a compactação.
user Uma única mensagem de usuário.
assistant_text Uma resposta de texto simplificada de um assistente, sem chamadas de função.
tool_call Uma mensagem de assistente com chamadas de função mais as mensagens de resultado da ferramenta correspondente, tratadas como uma unidade atômica.

Estratégias de compactação

Um CompactionStrategy é um protocolo - qualquer async chamável que aceite um list[Message] e o altere no local, retornando True quando tenha mudado qualquer coisa:

class CompactionStrategy(Protocol):
    async def __call__(self, messages: list[Message]) -> bool: ...

Gerador de token

Estratégias com reconhecimento de tokens aceitam uma TokenizerProtocol implementação. O interno CharacterEstimatorTokenizer usa uma heurística de 4 caracteres por token:

from agent_framework._compaction import CharacterEstimatorTokenizer

tokenizer = CharacterEstimatorTokenizer()

Passe um tokenizador personalizado quando for necessário obter contagens precisas de tokens para a codificação de um modelo específico.

Estratégias de compactação

Todas as estratégias herdam da classe base abstrata CompactionStrategy . Cada estratégia preserva as mensagens do sistema e mantém uma base MinimumPreserved que protege os grupos não-sistêmicos mais recentes contra remoção.

As estratégias de compressão são importadas de agent_framework._compaction.

TruncationCompactionStrategy

TruncationStrategy (EstratégiaDeTruncamento)

A abordagem mais simples: remove os grupos de mensagens mais antigos que não sejam do sistema até que a condição de destino seja atendida.

  • Respeita os limites dos grupos atômicos (as mensagens de chamada e os resultados da ferramenta são removidos juntos).
  • Melhor para backstops de orçamento de token rígido.
  • MinimumPreserved usa como padrão 32.
// Drop oldest groups when tokens exceed 32K, keeping at least 10 recent groups
TruncationCompactionStrategy truncation = new(
    trigger: CompactionTriggers.TokensExceed(0x8000),
    minimumPreserved: 10);
  • Quando uma tokenizer é fornecida, a métrica é a contagem de tokens; caso contrário, ela está incluída na contagem de mensagens.
  • preserve_system usa como padrão True.
from agent_framework._compaction import CharacterEstimatorTokenizer, TruncationStrategy

# Exclude oldest groups when tokens exceed 32 000, trimming to 16 000
truncation = TruncationStrategy(
    max_n=32_000,
    compact_to=16_000,
    tokenizer=CharacterEstimatorTokenizer(),
)

Estratégia de Compactação Janela Deslizante

Estratégia de Janela Deslizante

Remove o conteúdo da conversa mais antigo para manter apenas a janela mais recente de trocas, respeitando unidades de conversa lógica em vez de contagens arbitrárias de mensagens. As mensagens do sistema são preservadas em todo o mundo.

  • Melhor para controlar o comprimento da conversa de forma previsível.

Remove os turnos de usuário mais antigos e seus grupos de resposta associados, operando em limites lógicos de turnos em vez de em grupos individuais.

  • Um turno começa com uma mensagem do usuário e inclui todos os grupos de assistente e chamadas de ferramenta subsequentes até a próxima mensagem do usuário.
  • MinimumPreserved é definido como 1 (preserva, pelo menos, o grupo não-sistema mais recente).
// Keep only the last 4 user turns
SlidingWindowCompactionStrategy slidingWindow = new(
    trigger: CompactionTriggers.TurnsExceed(4));

Mantém apenas os grupos não-sistema mais recentes keep_last_groups , excluindo tudo o que é mais antigo.

  • preserve_system usa como padrão True.
from agent_framework._compaction import SlidingWindowStrategy

# Keep only the last 20 non-system groups
sliding_window = SlidingWindowStrategy(keep_last_groups=20)

Estratégia de Compactação de Resultados da Ferramenta

Recolhe grupos de chamadas de ferramentas mais antigos em mensagens de resumo compactas, preservando um rastreamento legível sem a sobrecarga completa da mensagem.

  • Não toca em mensagens do usuário ou respostas diretas de assistente.
  • Melhor como uma estratégia inicial para recuperar espaço dos resultados excessivamente detalhados da ferramenta.
  • Substitui grupos de chamadas de ferramentas que envolvem várias mensagens (incluindo chamada de assistente e resultados da ferramenta) por um resumo conciso, como [Tool calls: get_weather, search_docs].
  • O padrão do MinimumPreserved é 2, garantindo que as interações de ferramenta do turno atual permaneçam visíveis.
// Collapse old tool results when tokens exceed 512
ToolResultCompactionStrategy toolCompaction = new(
    trigger: CompactionTriggers.TokensExceed(0x200));
  • Colapse em mensagens de resumo compactas, como [Tool results: get_weather: sunny, 18°C].
  • Os grupos de chamadas de ferramentas mais recentes keep_last_tool_call_groups permanecem inalterados.
from agent_framework._compaction import ToolResultCompactionStrategy

# Collapse all but the newest tool-call group
tool_result = ToolResultCompactionStrategy(keep_last_tool_call_groups=1)

SummarizationCompactionStrategy

Estratégia de Resumir

Usa uma LLM para resumir partes mais antigas da conversa, substituindo-as por uma única mensagem de resumo.

  • Um prompt padrão preserva os principais fatos, decisões, preferências do usuário e resultados de chamadas de ferramenta.
  • Requer um cliente LLM separado para resumo – é recomendável um modelo menor e mais rápido.
  • Melhor para preservar o contexto de conversa e reduzir significativamente a contagem de tokens.
  • Você pode fornecer um prompt de resumo personalizado.
  • Protege as mensagens do sistema e os grupos não-sistema mais recentes MinimumPreserved (padrão: 4).
  • Envia as mensagens mais antigas para um local separado IChatClient com um prompt de resumo e, em seguida, insere o resumo como MessageGroupKind.Summary grupo.
// Summarize older messages when tokens exceed 1280, keeping the last 4 groups
SummarizationCompactionStrategy summarization = new(
    chatClient: summarizerChatClient,
    trigger: CompactionTriggers.TokensExceed(0x500),
    minimumPreserved: 4);

Você pode fornecer um prompt de resumo personalizado:

SummarizationCompactionStrategy summarization = new(
    chatClient: summarizerChatClient,
    trigger: CompactionTriggers.TokensExceed(0x500),
    summarizationPrompt: "Summarize the key decisions and user preferences only.");
  • Dispara quando a contagem de mensagens não sistêmicas incluídas excede target_count + threshold.
  • Retém as mensagens mais recentes target_count; resume tudo que é mais antigo.
  • Requer um SupportsChatGetResponse cliente.
from agent_framework._compaction import SummarizationStrategy

# Summarize when non-system message count exceeds 6, retaining the 4 newest
summarization = SummarizationStrategy(
    client=summarizer_client,
    target_count=4,
    threshold=2,
)

Forneça um prompt de resumo personalizado:

summarization = SummarizationStrategy(
    client=summarizer_client,
    target_count=4,
    prompt="Summarize the key decisions and user preferences only.",
)

PipelineCompactionStrategy

Compõe várias estratégias em um pipeline sequencial. Cada estratégia opera com base no resultado da anterior, permitindo uma compactação em camadas que vai de leve a agressiva.

  • O próprio gatilho do pipeline é CompactionTriggers.Always, cada estratégia filha avalia seu próprio gatilho de forma independente.
  • As estratégias são executadas em ordem, portanto, coloque as estratégias mais suaves em primeiro lugar.
PipelineCompactionStrategy pipeline = new(
    new ToolResultCompactionStrategy(CompactionTriggers.TokensExceed(0x200)),
    new SummarizationCompactionStrategy(summarizerChatClient, CompactionTriggers.TokensExceed(0x500)),
    new SlidingWindowCompactionStrategy(CompactionTriggers.TurnsExceed(4)),
    new TruncationCompactionStrategy(CompactionTriggers.TokensExceed(0x8000)));

Este pipeline (fluxo de processo):

  1. Recolhe resultados antigos da ferramenta (com delicadeza).
  2. Resume intervalos de conversa mais antigos (moderado).
  3. Mantém apenas as últimas 4 voltas de usuário (agressivas).
  4. Descarta os grupos mais antigos se ainda estiver acima do orçamento (backstop de emergência).

SelectiveToolCallCompactionStrategy

Exclui totalmente grupos de chamadas de ferramentas mais antigos, mantendo apenas o último keep_last_tool_call_groups.

  • Não toca mensagens de usuário ou mensagens de assistente simples.
  • Melhor quando as conversas de ferramentas dominam o uso de token e o histórico completo de ferramentas não é necessário.
from agent_framework._compaction import SelectiveToolCallCompactionStrategy

# Keep only the most recent tool-call group
selective_tool = SelectiveToolCallCompactionStrategy(keep_last_tool_call_groups=1)

TokenBudgetComposedStrategy

Compõe várias estratégias em um pipeline sequencial impulsionado por um orçamento de tokens. Cada estratégia filial é executada em ordem, parando mais cedo quando o orçamento for atendido. Um recurso interno de reserva exclui os grupos mais antigos se as estratégias por si só não puderem atingir o destino.

  • As estratégias devem ser executadas em ordem; coloque primeiro as estratégias menos agressivas.
  • early_stop=True (o padrão) para assim que o limite de tokens é atingido.
from agent_framework._compaction import (
    CharacterEstimatorTokenizer,
    SelectiveToolCallCompactionStrategy,
    SlidingWindowStrategy,
    SummarizationStrategy,
    TokenBudgetComposedStrategy,
    ToolResultCompactionStrategy,
)

tokenizer = CharacterEstimatorTokenizer()

pipeline = TokenBudgetComposedStrategy(
    token_budget=16_000,
    tokenizer=tokenizer,
    strategies=[
        ToolResultCompactionStrategy(keep_last_tool_call_groups=1),
        SummarizationStrategy(client=summarizer_client, target_count=4, threshold=2),
        SlidingWindowStrategy(keep_last_groups=20),
    ],
)

Este processo:

  1. Recolhe resultados antigos da ferramenta de forma suave.
  2. Resume intervalos de conversa mais antigos (moderado).
  3. Mantém apenas os últimos 20 grupos (agressivos).
  4. Volta à exclusão mais antiga se ainda estiver acima do orçamento (backstop de emergência).

Usando compactação com um agente

Encapsular uma estratégia de compactação em uma CompactionProvider e registrá-la como um AIContextProvider. Passe uma única estratégia ou um PipelineCompactionStrategy ao construtor.

Registrando-se com a API do construtor

Registre o provedor no ChatClientBuilder usando UseAIContextProviders. O provedor é executado dentro do loop de chamada da ferramenta, compactando mensagens antes de cada chamada ao LLM.

IChatClient agentChatClient = openAIClient.GetChatClient(deploymentName).AsIChatClient();
IChatClient summarizerChatClient = openAIClient.GetChatClient(deploymentName).AsIChatClient();

PipelineCompactionStrategy compactionPipeline =
    new(
        new ToolResultCompactionStrategy(CompactionTriggers.TokensExceed(0x200)),
        new SummarizationCompactionStrategy(summarizerChatClient, CompactionTriggers.TokensExceed(0x500)),
        new SlidingWindowCompactionStrategy(CompactionTriggers.TurnsExceed(4)),
        new TruncationCompactionStrategy(CompactionTriggers.TokensExceed(0x8000)));

AIAgent agent =
    agentChatClient
        .AsBuilder()
        .UseAIContextProviders(new CompactionProvider(compactionPipeline))
        .BuildAIAgent(
            new ChatClientAgentOptions
            {
                Name = "ShoppingAssistant",
                ChatOptions = new()
                {
                    Instructions = "You are a helpful shopping assistant.",
                    Tools = [AIFunctionFactory.Create(LookupPrice)],
                },
            });

AgentSession session = await agent.CreateSessionAsync();
Console.WriteLine(await agent.RunAsync("What's the price of a laptop?", session));

Dica

Use um modelo menor e mais barato (como gpt-4o-mini) para o cliente de chat de resumo para reduzir os custos, mantendo a qualidade resumida.

Se apenas uma estratégia for necessária, passe-a diretamente para CompactionProvider sem envolvê-la em um PipelineCompactionStrategy.

agentChatClient
    .AsBuilder()
    .UseAIContextProviders(new CompactionProvider(
        new SlidingWindowCompactionStrategy(CompactionTriggers.TurnsExceed(20))))
    .BuildAIAgent(...);

Registrando-se por meio ChatClientAgentOptions

O provedor também pode ser especificado diretamente em ChatClientAgentOptions.AIContextProviders:

AIAgent agent = agentChatClient
    .AsBuilder()
    .BuildAIAgent(new ChatClientAgentOptions
    {
        AIContextProviders = [new CompactionProvider(compactionPipeline)]
    });

Observação

Quando registrado por meio de ChatClientAgentOptions, o CompactionProvidernão é ativado durante o loop de chamada de ferramentas. Os provedores de contexto no nível do agente são executados antes que o histórico de chat seja armazenado; portanto, quaisquer mensagens de resumo sintéticas produzidas por CompactionProvider podem se tornar parte do histórico persistente ao usar ChatHistoryProvider. Para compactar apenas o contexto de solicitação em andamento, preservando o histórico armazenado original, registre o provedor no ChatClientBuilder usando UseAIContextProviders(...).

Compactação ad hoc

CompactionProvider.CompactAsync aplica uma estratégia a uma lista de mensagens arbitrárias sem uma sessão de agente ativo:

IEnumerable<ChatMessage> compacted = await CompactionProvider.CompactAsync(
    new TruncationCompactionStrategy(CompactionTriggers.TokensExceed(8000)),
    existingMessages);

CompactionProvider é um provedor de contexto que aplica estratégias de compactação antes e depois da execução de cada agente. Adicione-o juntamente com um provedor de histórico na lista do agente context_providers.

  • before_strategy — é executado antes da chamada de modelo, compactando mensagens já carregadas no contexto.
  • after_strategy — é executado após a chamada do modelo, compactando as mensagens armazenadas pelo provedor de histórico para que a próxima interação comece de forma mais compacta.
  • history_source_id — o source_id provedor de histórico cujas mensagens after_strategy armazenadas devem ser compactadas (o padrão é "in_memory").

Registrando-se com um agente

from agent_framework import Agent, CompactionProvider, InMemoryHistoryProvider
from agent_framework._compaction import (
    CharacterEstimatorTokenizer,
    SlidingWindowStrategy,
    SummarizationStrategy,
    TokenBudgetComposedStrategy,
    ToolResultCompactionStrategy,
)

tokenizer = CharacterEstimatorTokenizer()

pipeline = TokenBudgetComposedStrategy(
    token_budget=16_000,
    tokenizer=tokenizer,
    strategies=[
        ToolResultCompactionStrategy(keep_last_tool_call_groups=1),
        SummarizationStrategy(client=summarizer_client, target_count=4, threshold=2),
        SlidingWindowStrategy(keep_last_groups=20),
    ],
)

history = InMemoryHistoryProvider()
compaction = CompactionProvider(
    before_strategy=pipeline,
    history_source_id=history.source_id,
)

agent = Agent(
    client=client,
    name="ShoppingAssistant",
    instructions="You are a helpful shopping assistant.",
    context_providers=[history, compaction],
)

session = agent.create_session()
print(await agent.run("What's the price of a laptop?", session=session))

Dica

Use um modelo menor e mais barato (como gpt-4o-mini) para o cliente de resumo para reduzir os custos, mantendo a qualidade resumida.

Se apenas uma estratégia for necessária, passe-a diretamente como before_strategy:

compaction = CompactionProvider(
    before_strategy=SlidingWindowStrategy(keep_last_groups=20),
    history_source_id=history.source_id,
)

Compactação do histórico persistente após cada execução

Use after_strategy para compactar as mensagens armazenadas pelo provedor de histórico para que as voltas futuras comecem com um contexto reduzido:

compaction = CompactionProvider(
    before_strategy=SlidingWindowStrategy(keep_last_groups=20),
    after_strategy=ToolResultCompactionStrategy(keep_last_tool_call_groups=1),
    history_source_id=history.source_id,
)

Compactação ad hoc

apply_compaction aplica uma estratégia a uma lista de mensagens arbitrária fora de uma sessão de agente ativo:

from agent_framework._compaction import apply_compaction, TruncationStrategy, CharacterEstimatorTokenizer

tokenizer = CharacterEstimatorTokenizer()

compacted = await apply_compaction(
    messages,
    strategy=TruncationStrategy(
        max_n=8_000,
        compact_to=4_000,
        tokenizer=tokenizer,
    ),
    tokenizer=tokenizer,
)

Escolhendo uma estratégia

Estratégia Agressividade Preserva o contexto Requer Modelo de Linguagem (LLM) Mais adequado para
ToolResultCompactionStrategy Baixo Alta – recolhe apenas os resultados da ferramenta No Recuperando espaço da saída verbosa da ferramenta
SummarizationCompactionStrategy Medium Médio – substitui o histórico por um resumo Sim Conversas longas em que o contexto importa
SlidingWindowCompactionStrategy Alto Baixo – descarta turnos inteiros No Limites de contagem de turnos rígidos
TruncationCompactionStrategy Alto Baixo – descarta grupos mais antigos No Sustentação de orçamento de tokens de emergência
PipelineCompactionStrategy Configurable Depende de estratégias filho Depende Compactação em camadas com várias alternativas
Estratégia Agressividade Preserva o contexto Requer LLM Mais adequado para
ToolResultCompactionStrategy Baixo Nível alto — compacta os resultados da ferramenta em mensagens resumidas No Recuperação de espaço da saída detalhada da ferramenta
SelectiveToolCallCompactionStrategy Baixo–Médio Médio – exclui totalmente grupos de chamadas de ferramentas antigos No Removendo o histórico de ferramentas quando os resultados não são mais necessários
SummarizationStrategy Medium Médio – substitui o histórico por um resumo Sim Conversas longas em que o contexto importa
SlidingWindowStrategy Alto Baixo – descarta grupos mais antigos No Rígidos limites de contagem de grupos
TruncationStrategy Alto Baixo – descarta grupos mais antigos No Mecanismos de proteção de mensagens de emergência ou de limite de token
TokenBudgetComposedStrategy Configurable Depende de estratégias filho Depende Compactação em camadas com uma meta de orçamento de tokens e várias alternativas

Próximas Etapas 

Armazenamento