Dela via


Kompaktering

I takt med att konversationerna växer kan antalet token i chatthistoriken överstiga modellkontextens fönster eller öka kostnaderna. Komprimeringsstrategier minskar storleken på konversationshistoriken samtidigt som viktiga kontexter bevaras, så att agenter kan fortsätta att fungera under långvariga interaktioner.

Viktigt!

Komprimeringsramverket är för närvarande experimentellt. Om du vill använda den måste du lägga till #pragma warning disable MAAI001.

Viktigt!

Komprimeringsramverket är för närvarande experimentellt i Python. Importera strategier från agent_framework._compaction.

Varför komprimering spelar roll

Varje anrop till en LLM innehåller hela konversationshistoriken. Utan komprimering:

  • Tokengränser – Konversationer överskrider slutligen modellens kontextfönster, vilket orsakar fel.
  • Kostnad – Större frågor förbrukar fler token, vilket ökar API-kostnaderna.
  • Svarstid – Fler indatatoken innebär långsammare svarstider.

Komprimering löser dessa problem genom att selektivt ta bort, komprimera eller sammanfatta äldre delar av konversationen.

Grundläggande begrepp

Tillämplighet: Endast minnesinterna historikagenter

Komprimering gäller endast för agenter som hanterar sin egen konversationshistorik i minnet. Agenter som förlitar sig på tjänsthanterad kontext eller konversationstillstånd drar inte nytta av komprimering eftersom tjänsten redan hanterar kontexthantering. Exempel på tjänsthanterade agenter är:

  • Foundry Agents – kontexten hanteras på serversidan av Azure AI Foundry-tjänsten.
  • Svars-API med store aktiverat (standard) – konversationstillstånd lagras och hanteras av OpenAI-tjänsten.
  • Copilot Studio-agenter – konversationskontexten underhålls av Copilot Studio-tjänsten.

För dessa agenttyper har det ingen effekt att konfigurera en komprimeringsstrategi. Komprimering är endast relevant när agenten har en egen minnesintern meddelandelista och skickar hela historiken till modellen för varje anrop.

Komprimering fungerar på en MessageIndex – en strukturerad vy av den platta meddelandelistan som grupperar meddelanden i atomiska enheter som kallas MessageGroup instanser. Varje grupp spårar antalet meddelanden, antal byte och det uppskattade tokenantalet.

Meddelandegrupper

A MessageGroup representerar logiskt relaterade meddelanden som måste hållas eller tas bort tillsammans. Ett assistentmeddelande som innehåller verktygsanrop och dess motsvarande verktygsresultatmeddelanden utgör till exempel en atomisk grupp. Om du tar bort en utan den andra skulle det orsaka LLM API-fel.

Varje grupp har en MessageGroupKind:

Kind Beskrivning
System Ett eller flera systemmeddelanden. Bevaras alltid under komprimering.
User Ett meddelande från en enskild användare som startar en ny sväng.
AssistantText Ett oformaterat textsvar från assistenten (inga verktygsanrop).
ToolCall Ett assistentmeddelande med verktygsanrop och motsvarande verktygsresultatmeddelanden, som behandlas som en atomisk enhet.
Summary Ett komprimerat meddelande som genereras av sammanfattningskomprimering.

Utlösare

A CompactionTrigger är ett ombud som utvärderar om komprimering ska fortsätta baserat på aktuella MessageIndex mått:

public delegate bool CompactionTrigger(MessageIndex index);

Klassen CompactionTriggers innehåller vanliga fabriksmetoder:

Trigger Utlöses när
CompactionTriggers.Always Varje gång (villkorslöst).
CompactionTriggers.Never Aldrig (inaktiverar komprimering).
CompactionTriggers.TokensExceed(maxTokens) Det inkluderade antalet token överskrider tröskelvärdet.
CompactionTriggers.MessagesExceed(maxMessages) Det inkluderade antalet meddelanden överskrider tröskelvärdet.
CompactionTriggers.TurnsExceed(maxTurns) Det inkluderade antalet användarinteraktioner överskrider tröskelvärdet.
CompactionTriggers.GroupsExceed(maxGroups) Det inkluderade gruppantalet överskrider tröskelvärdet.
CompactionTriggers.HasToolCalls() Det finns minst en verktygsanropsgrupp som inte är exkluderad.

Kombinera utlösare med CompactionTriggers.All(...) (logisk AND) eller CompactionTriggers.Any(...) (logisk OR):

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

Utlösare jämfört med mål

Varje strategi har två predikat:

  • Utlösare – Kontroller när komprimering påbörjas. Om utlösaren returnerar false, så hoppar strategin helt över.
  • Target – Kontrollera när komprimering ska stoppas. Strategier exkluderar grupper stegvis och utvärderar målet på nytt efter varje steg och stannar när målet har återgått true.

När inget mål har angetts är standardinställningen den omvända av utlösaren – komprimering stoppas så snart utlösarvillkoret inte längre triggas.

Komprimering fungerar på en platt lista över Message objekt. Meddelanden kommenteras med enkla gruppmetadata och strategier muterar de anteckningar som finns för att markera grupper som exkluderade innan meddelandelistan projiceras till modellen.

Meddelandegrupper

Meddelanden grupperas i atomiska enheter. Varje grupp tilldelas en GroupKind:

Kind Beskrivning
system Systemmeddelanden. Bevaras alltid under komprimering.
user Ett meddelande från en enda användare.
assistant_text Ett enkelt assistenttextsvar utan funktionsanrop.
tool_call Ett assistentmeddelande med funktionsanrop plus motsvarande verktygsresultatmeddelanden, som behandlas som en atomisk enhet.

Komprimeringsstrategier

A CompactionStrategy är ett protokoll – vilken async som helst som kan anropas, som accepterar en list[Message] och ändrar det direkt, returnerar True när det ändrade något:

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

Tokeniserare

Tokenmedvetna strategier accepterar en TokenizerProtocol implementation. Den inbyggda CharacterEstimatorTokenizer använder en heuristik på 4 tecken per token.

from agent_framework._compaction import CharacterEstimatorTokenizer

tokenizer = CharacterEstimatorTokenizer()

Skicka en anpassad tokenizer när du behöver korrekta tokenantal för en specifik modells kodning.

Komprimeringsstrategier

Alla strategier ärver från den abstrakta CompactionStrategy basklassen. Varje strategi bevarar systemmeddelanden och respekterar ett MinimumPreserved golv som skyddar de senaste icke-systemgrupperna från borttagning.

Komprimeringsstrategier importeras från agent_framework._compaction.

TruncationCompactionStrategy

Trunkeringsstrategi

Den enklaste metoden: tar bort de äldsta icke-systemmeddelandegrupperna tills målvillkoret uppfylls.

  • Respekterar atomiska gruppgränser (verktygsanrop och resultatmeddelanden tas bort tillsammans).
  • Bäst för backstops med hård tokenbudget.
  • MinimumPreserved har som standard 32.
// Drop oldest groups when tokens exceed 32K, keeping at least 10 recent groups
TruncationCompactionStrategy truncation = new(
    trigger: CompactionTriggers.TokensExceed(0x8000),
    minimumPreserved: 10);
  • När ett tokenizer anges är måttet tokenantal, annars inkluderas antalet meddelanden.
  • preserve_system har som standard 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(),
)

Glidfönsterkompakteringsstrategi

GlidandeFönsterStrategi

Tar bort äldre konversationsinnehåll för att endast behålla det senaste fönstret med utbyten, med respekt för logiska konversationsenheter i stället för godtyckligt antal meddelanden. Systemmeddelanden bevaras överallt.

  • Bäst för att begränsa konversationslängden förutsägbart.

Tar bort de äldsta användarinteraktionerna och deras associerade svarsgrupper, vilket sker på logiska turgränser istället för enskilda grupper.

  • En omgång börjar med ett användarmeddelande och innehåller alla efterföljande assistent- och verktygsanrop fram till nästa användarmeddelande.
  • MinimumPreserved är förinställd på 1 (bevarar åtminstone den senaste gruppen som inte är system).
// Keep only the last 4 user turns
SlidingWindowCompactionStrategy slidingWindow = new(
    trigger: CompactionTriggers.TurnsExceed(4));

Behåller endast de senaste keep_last_groups icke-systemgrupperna, exklusive allt äldre.

  • preserve_system har som standard True.
from agent_framework._compaction import SlidingWindowStrategy

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

ToolResultCompactionStrategy

Komprimerar äldre verktygsanropsgrupper i kompakta sammanfattningsmeddelanden, vilket bevarar en läsbar spårning utan hela meddelandeomfånget.

  • Rör inte användarmeddelanden eller vanliga assistentsvar.
  • Bäst som en förstapassstrategi för att frigöra utrymme från omfångsrika verktygsresultat.
  • Ersätter samtalsgrupper för flera meddelandeverktyg (assistentsamtal + verktygsresultat) med en kort sammanfattning som [Tool calls: get_weather, search_docs].
  • MinimumPreserved standardvärdet är 2, vilket säkerställer att den aktuella svängens verktygsinteraktioner förblir synliga.
// Collapse old tool results when tokens exceed 512
ToolResultCompactionStrategy toolCompaction = new(
    trigger: CompactionTriggers.TokensExceed(0x200));
  • Komprimeras till kompakta sammanfattningsmeddelanden som [Tool results: get_weather: sunny, 18°C].
  • De senaste keep_last_tool_call_groups grupperna för verktygsanrop lämnas orörda.
from agent_framework._compaction import ToolResultCompactionStrategy

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

SammanfattningCompactionStrategy

Sammanfattningsstrategi

Använder en LLM för att sammanfatta äldre delar av konversationen och ersätta dem med ett enda sammanfattningsmeddelande.

  • En standardprompt bevarar viktiga fakta, beslut, användarinställningar och utfall för verktygsanrop.
  • Kräver en separat LLM-klient för sammanfattning – en mindre, snabbare modell rekommenderas.
  • Bäst för att bevara konversationskontexten samtidigt som antalet token minskar avsevärt.
  • Du kan ange en anpassad sammanfattningsprompt.
  • Skyddar systemmeddelanden och de senaste MinimumPreserved icke-systemgrupperna (standard: 4).
  • Skickar de äldre meddelandena separat till IChatClient för sammanfattning och infogar sedan sammanfattningen i en MessageGroupKind.Summary grupp.
// Summarize older messages when tokens exceed 1280, keeping the last 4 groups
SummarizationCompactionStrategy summarization = new(
    chatClient: summarizerChatClient,
    trigger: CompactionTriggers.TokensExceed(0x500),
    minimumPreserved: 4);

Du kan ge en anpassad sammanfattningsuppmaning:

SummarizationCompactionStrategy summarization = new(
    chatClient: summarizerChatClient,
    trigger: CompactionTriggers.TokensExceed(0x500),
    summarizationPrompt: "Summarize the key decisions and user preferences only.");
  • Utlöses när antalet ickesystemmeddelanden överskrider target_count + threshold.
  • Behåller de senaste target_count meddelandena. Sammanfattar allt äldre.
  • Kräver en SupportsChatGetResponse klient.
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,
)

Ange en anpassad sammanfattningsprompt:

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

PipelineKompakteringsStrategi

Sammanfogar flera strategier till en sekventiell pipeline. Varje strategi opererar på resultatet av den föregående, vilket möjliggör lager-på-lager-komprimering från mild till aggressiv.

  • Pipelinens egen utlösare är CompactionTriggers.Always – varje delstrategi utvärderar sin egen utlösare oberoende.
  • Strategier körs i ordning, så placera de mest skonsamma strategierna först.
PipelineCompactionStrategy pipeline = new(
    new ToolResultCompactionStrategy(CompactionTriggers.TokensExceed(0x200)),
    new SummarizationCompactionStrategy(summarizerChatClient, CompactionTriggers.TokensExceed(0x500)),
    new SlidingWindowCompactionStrategy(CompactionTriggers.TurnsExceed(4)),
    new TruncationCompactionStrategy(CompactionTriggers.TokensExceed(0x8000)));

Den här processen:

  1. Komprimerar gamla verktygsresultat (mildrat).
  2. Sammanfattar äldre konversationsintervall (måttliga).
  3. Behåller endast de senaste 4 användarinteraktionerna (aggressivt).
  4. Tar bort de äldsta grupperna om de fortfarande är över budget (nödlösning).

Strategi för selektiv verktygsanropskompaktering

Utesluter helt äldre verktygsanropsgrupper och behåller endast den sista keep_last_tool_call_groups.

  • Rör inte användar- eller oformaterade assistentmeddelanden.
  • Bäst när verktygssnack dominerar tokenanvändningen och den fullständiga verktygshistoriken inte behövs.
from agent_framework._compaction import SelectiveToolCallCompactionStrategy

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

TokenBudgetComposedStrategy

Sammanställer flera strategier i en sekventiell pipeline och styrs av en tokenbudget. Varje barnstrategi körs i ordning och avslutas tidigt när budgeten är tillfredsställd. En inbyggd reservåtgärd innebär att de äldsta grupperna utesluts om endast strategierna inte kan nå målet.

  • Strategier körs i ordning; placera de mildaste strategierna först.
  • early_stop=True (standardvärdet) stoppas så snart tokenbudgeten är uppfylld.
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),
    ],
)

Den här pipelinen:

  1. Döljer gamla verktygsresultat (skonsamt).
  2. Sammanfattar äldre konversationsintervall (måttliga).
  3. Behåller endast de senaste 20 grupperna (aggressiva).
  4. Faller tillbaka till äldsta-första exkludering om fortfarande över budget (nödbackstop).

Använda komprimering med en agent

Omslut en komprimeringsstrategi i en CompactionProvider och registrera den som en AIContextProvider. Skicka antingen en enda strategi eller en PipelineCompactionStrategy till konstruktorn.

Registrera med builder-API:et

Registrera providern på ChatClientBuilder med hjälp av UseAIContextProviders. Providern körs i loopen för verktygsanrop och komprimerar meddelanden före varje LLM-anrop.

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));

Tips/Råd

Använd en mindre, billigare modell (till exempel ) för sammanfattningschattklienten för att minska kostnaderna samtidigt som gpt-4o-minisammanfattningskvaliteten bibehålls.

Om det bara behövs en strategi, skickar du den direkt till `CompactionProvider` utan att omsluta den i en `PipelineCompactionStrategy`.

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

Registrera dig via ChatClientAgentOptions

Providern kan också anges direkt på ChatClientAgentOptions.AIContextProviders:

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

Anmärkning

När den registreras via ChatClientAgentOptionsär CompactionProvider inte aktiverad under verktygsanropsloopen. Kontextprovidrar på agentnivå körs innan chatthistoriken lagras, så alla syntetiska sammanfattningsmeddelanden som skapas av CompactionProvider kan bli en del av den bevarade historiken när du använder ChatHistoryProvider. Om du bara vill komprimera kontexten för aktiva begäranden, samtidigt som den ursprungliga historiken bevaras, registrera providern på ChatClientBuilder via UseAIContextProviders(...) i stället.

Ad hoc-komprimering

CompactionProvider.CompactAsync tillämpar en strategi på en godtycklig meddelandelista utan en aktiv agentsession:

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

CompactionProvider är en kontextleverantör som tillämpar komprimeringsstrategier före och efter varje agentexekvering. Lägg till den i agentens context_providers lista tillsammans med en historikleverantör.

  • before_strategy – körs före modellanropet och komprimerar meddelanden som redan har lästs in i kontexten.
  • after_strategy – körs efter modellanropet och komprimerar meddelandena som lagras av historikprovidern så att nästa tur börjar mindre.
  • history_source_id — den source_id historikleverantör vars lagrade meddelanden after_strategy ska komprimeras (standardvärdet är "in_memory").

Registrera dig hos en agent

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))

Tips/Råd

Använd en mindre, billigare modell (till exempel ) för sammanfattningsklienten för att minska kostnaderna samtidigt som gpt-4o-minisammanfattningskvaliteten bibehålls.

Om du bara behöver en strategi skickar du den direkt som before_strategy:

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

Komprimera beständig historik efter varje körning

Använd after_strategy för att komprimera meddelanden som lagras av historikprovidern så att framtida svängar börjar med en reducerad kontext:

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

Ad hoc-komprimering

apply_compaction tillämpar en strategi på en godtycklig meddelandelista utanför en aktiv agentsession:

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,
)

Välja en strategi

Strategi Aggressivitet Bevarar kontext Kräver LLM Bäst för
ToolResultCompactionStrategy Låg Hög – minimerar endast verktygsresultat No Frigöra utrymme från utförliga verktygsutdata
SummarizationCompactionStrategy Medium Medium – ersätter historiken med en sammanfattning Ja Långa konversationer där kontexten är viktig
SlidingWindowCompactionStrategy Högt Låg – hoppar över hela varv No Begränsningar för antal hårda svängar
TruncationCompactionStrategy Högt Låg – släpper de äldsta grupperna No Säkerhetskopiering av tokenbudget för nödsituationer
PipelineCompactionStrategy Configurable Beror på strategier för barnnivå Det beror på Skiktad komprimering med flera alternativ
Strategi Aggressivitet Bevarar kontext Kräver LLM Bäst för
ToolResultCompactionStrategy Låg Hög – komprimerar verktygsresultat i sammanfattningsmeddelanden No Frigöra utrymme från utförliga verktygsutdata
SelectiveToolCallCompactionStrategy Låg-Nivå–Medelnivå Medel – utesluter helt gamla verktygsanropsgrupper No Ta bort verktygshistorik när resultaten inte längre behövs
SummarizationStrategy Medium Medium – ersätter historiken med en sammanfattning Ja Långa konversationer där kontexten är viktig
SlidingWindowStrategy Högt Lägsta – tar bort äldsta grupper No Strikta begränsningar för gruppantal
TruncationStrategy Högt Låg – tar bort äldsta grupper No Skydd för nödmeddelande eller tokenbudget
TokenBudgetComposedStrategy Configurable Beror på barnstrategier Det beror på Skiktad komprimering med ett tokenbudgetmål och flera återställningar

Nästa steg