Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Seiring bertambahnya percakapan, jumlah token riwayat obrolan dapat melebihi jendela konteks model atau meningkatkan biaya. Strategi pemadatan mengurangi ukuran riwayat percakapan sambil mempertahankan konteks penting, sehingga agen dapat terus berfungsi selama interaksi yang berjalan lama.
Penting
Kerangka kerja pemadatan saat ini bersifat eksperimental. Untuk menggunakannya, Anda harus menambahkan #pragma warning disable MAAI001.
Penting
Kerangka kerja pemadatan saat ini bersifat eksperimental di Python. Impor strategi dari agent_framework._compaction.
Mengapa pemadatan penting
Setiap panggilan ke LLM mencakup riwayat percakapan lengkap. Tanpa pemadatan:
- Batas token — Percakapan akhirnya melebihi jendela konteks model, menyebabkan kesalahan.
- Biaya — Permintaan yang lebih besar mengonsumsi lebih banyak token, meningkatkan biaya API.
- Latensi — Lebih banyak token input berarti waktu respons yang lebih lambat.
Pemadatan memecahkan masalah ini dengan secara selektif menghapus, menggabungkan, atau meringkas bagian percakapan yang lebih lama.
Konsep inti
Penerapan: Hanya agen riwayat dalam memori
Pemadatan hanya berlaku untuk agen yang mengelola riwayat percakapan mereka sendiri dalam memori. Agen yang mengandalkan konteks yang dikelola layanan atau status percakapan tidak mendapat manfaat dari pemadatan karena layanan sudah menangani manajemen konteks. Contoh agen yang dikelola layanan meliputi:
- Agen Foundry — konteks dikelola sisi server oleh layanan Azure AI Foundry.
- RESPONS API dengan penyimpanan diaktifkan (default) — status percakapan disimpan dan dikelola oleh layanan OpenAI.
- Agen Copilot Studio — konteks percakapan dikelola oleh layanan Copilot Studio.
Untuk jenis agen ini, mengonfigurasi strategi pemadatan tidak berpengaruh. Pemadatan hanya relevan ketika agen mempertahankan daftar pesan dalam memorinya sendiri dan meneruskan riwayat lengkap ke model pada setiap panggilan.
Pemadatan beroperasi pada MessageIndex — tampilan terstruktur dari daftar pesan datar yang mengorganisir pesan ke dalam unit atom yang disebut instance MessageGroup. Setiap grup melacak jumlah pesan, jumlah byte, dan perkiraan jumlah tokennya.
Grup pesan
Sebuah MessageGroup mewakili pesan-pesan terkait secara logis yang harus disimpan atau dihapus secara bersama-sama. Misalnya, pesan asisten yang berisi panggilan alat dan pesan hasil alat yang sesuai membentuk kelompok atomik — menghilangkan satu tanpa yang lain dapat menyebabkan kesalahan API LLM.
Setiap grup memiliki MessageGroupKind:
| Kind | Deskripsi |
|---|---|
System |
Satu atau beberapa pesan sistem. Senantiasa dipertahankan selama pemadatan. |
User |
Satu pesan pengguna yang memulai giliran baru. |
AssistantText |
Respons teks asisten biasa (tidak ada panggilan alat). |
ToolCall |
Pesan asisten dengan panggilan alat dan pesan hasil alat yang sesuai, diperlakukan sebagai kesatuan utuh. |
Summary |
Pesan ringkas yang dihasilkan oleh pemadatan ikhtisar. |
Pemicu
CompactionTrigger adalah delegat yang mengevaluasi apakah pemadatan harus dilanjutkan berdasarkan metrik saat ini MessageIndex:
public delegate bool CompactionTrigger(MessageIndex index);
Kelas ini CompactionTriggers menyediakan metode pabrikasi yang umum:
| Pemicu | Menembak ketika |
|---|---|
CompactionTriggers.Always |
Setiap kali (tanpa syarat). |
CompactionTriggers.Never |
Tidak pernah (mematikan fitur pemadatan). |
CompactionTriggers.TokensExceed(maxTokens) |
Jumlah token yang disertakan melebihi ambang batas. |
CompactionTriggers.MessagesExceed(maxMessages) |
Jumlah pesan yang disertakan melebihi ambang batas. |
CompactionTriggers.TurnsExceed(maxTurns) |
Jumlah giliran pengguna yang termasuk melebihi ambang batas. |
CompactionTriggers.GroupsExceed(maxGroups) |
Jumlah grup yang disertakan melebihi ambang batas. |
CompactionTriggers.HasToolCalls() |
Setidaknya ada satu grup panggilan alat yang tidak termasuk dalam pengecualian. |
Gabungkan pemicu dengan CompactionTriggers.All(...) (LOGICAL AND) atau CompactionTriggers.Any(...) (logis OR):
// Compact only when there are tool calls AND tokens exceed 2000
CompactionTrigger trigger = CompactionTriggers.All(
CompactionTriggers.HasToolCalls(),
CompactionTriggers.TokensExceed(2000));
Pemicu vs. Sasaran
Setiap strategi memiliki dua predikat:
-
Pemicu — Kontrol saat pemadatan dimulai. Jika pemicu kembali
false, strategi diabaikan sepenuhnya. -
Target — Kontrol saat pemadatan berhenti. Strategi secara bertahap mengecualikan grup dan mengevaluasi ulang target setelah setiap langkah, berhenti segera setelah target tercapai
true.
Ketika tidak ada target yang ditentukan, default diatur ke kebalikan dari pemicu — pemadatan berhenti segera setelah kondisi pemicu tidak lagi memenuhi syarat.
Pemadatan beroperasi pada daftar objek yang datar Message. Pesan dianotasikan dengan metadata grup ringan, dan strategi mengubah anotasi tersebut untuk menandai grup sebagai dikecualikan sebelum daftar pesan diproyeksikan ke model.
Grup pesan
Pesan dikelompokkan ke dalam unit atom. Setiap grup diberi GroupKind:
| Kind | Deskripsi |
|---|---|
system |
Pesan sistem. Senantiasa dipertahankan selama pemadatan. |
user |
Satu pesan pengguna. |
assistant_text |
Respons teks asisten biasa (tidak ada panggilan fungsi). |
tool_call |
Pesan asisten dengan panggilan fungsi ditambah pesan hasil alat yang sesuai, diperlakukan sebagai unit atomik. |
Strategi pemadatan
CompactionStrategy adalah protokol — setiap async yang dapat dipanggil yang menerima list[Message] dan mengubahnya langsung di tempat, mengembalikan True ketika ada perubahan yang terjadi.
class CompactionStrategy(Protocol):
async def __call__(self, messages: list[Message]) -> bool: ...
Pembuat token
Strategi yang memperhatikan token menerima implementasi TokenizerProtocol. Bawaan CharacterEstimatorTokenizer menggunakan heuristik 4 karakter per token:
from agent_framework._compaction import CharacterEstimatorTokenizer
tokenizer = CharacterEstimatorTokenizer()
Berikan tokenizer kustom saat Anda memerlukan jumlah token yang akurat untuk pengodean model tertentu.
Strategi pemadatan
Semua strategi diwariskan dari kelas dasar abstrak CompactionStrategy . Setiap strategi mempertahankan pesan sistem dan menghormati MinimumPreserved batas yang melindungi grup non-sistem terbaru dari penghapusan.
Strategi pemadatan diimpor dari agent_framework._compaction.
Strategi Pemotongan dan Pemadatan
Strategi Pemotongan
Pendekatan yang paling mudah: menghapus grup pesan non-sistem tertua hingga kondisi target terpenuhi.
- Menghormati batas grup atomik (panggilan perangkat dan pesan hasil dihapus bersamaan).
- Terbaik untuk backstop anggaran token keras.
-
MinimumPreserveddefaultnya adalah32.
// Drop oldest groups when tokens exceed 32K, keeping at least 10 recent groups
TruncationCompactionStrategy truncation = new(
trigger: CompactionTriggers.TokensExceed(0x8000),
minimumPreserved: 10);
- Ketika
tokenizerdisediakan, metrik adalah jumlah token; jika tidak, metriknya adalah jumlah pesan. -
preserve_systemdefaultnya adalahTrue.
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(),
)
SlidingWindowCompactionStrategy
SlidingWindowStrategy
Menghapus konten percakapan yang lebih lama untuk menyimpan hanya jendela pertukaran terbaru, menghormati unit percakapan logis daripada jumlah pesan sewenang-wenang. Pesan sistem dipertahankan secara keseluruhan.
- Terbaik untuk membatasi panjang percakapan secara dapat diprediksi.
Menghapus giliran pengguna terlama dan grup respons terkait mereka, beroperasi pada batas belokan logis daripada grup individual.
- Giliran dimulai dengan pesan pengguna dan menyertakan semua asisten dan grup panggilan alat berikutnya hingga pesan pengguna berikutnya.
-
MinimumPreserveddefault ke1(mempertahankan setidaknya grup non-sistem terbaru).
// Keep only the last 4 user turns
SlidingWindowCompactionStrategy slidingWindow = new(
trigger: CompactionTriggers.TurnsExceed(4));
Hanya menjaga grup non-sistem terbaru keep_last_groups, tidak termasuk grup yang lebih lama.
-
preserve_systemdefaultnya adalahTrue.
from agent_framework._compaction import SlidingWindowStrategy
# Keep only the last 20 non-system groups
sliding_window = SlidingWindowStrategy(keep_last_groups=20)
Strategi Pemadatan Hasil Alat
Menggabungkan grup panggilan alat yang lebih lama ke dalam pesan ringkasan ringkas, mempertahankan jejak yang dapat dibaca tanpa overhead pesan yang lengkap.
- Tidak menyentuh pesan pengguna atau respons asisten biasa.
- Terbaik sebagai strategi first-pass untuk merebut kembali ruang dari hasil alat verbose.
- Mengganti kelompok panggilan alat dengan banyak pesan (panggilan untuk asisten + hasil alat) menjadi ringkasan singkat seperti
[Tool calls: get_weather, search_docs]. -
MinimumPreservedberalih ke2, memastikan interaksi alat dalam sesi saat ini tetap terlihat.
// Collapse old tool results when tokens exceed 512
ToolResultCompactionStrategy toolCompaction = new(
trigger: CompactionTriggers.TokensExceed(0x200));
- Menguraikan ke dalam pesan ringkasan yang ringkas seperti
[Tool results: get_weather: sunny, 18°C]. - Grup panggilan alat yang paling terbaru
keep_last_tool_call_groupsdibiarkan tidak tersentuh.
from agent_framework._compaction import ToolResultCompactionStrategy
# Collapse all but the newest tool-call group
tool_result = ToolResultCompactionStrategy(keep_last_tool_call_groups=1)
SummarizationCompactionStrategy
Strategi Ringkasan
Menggunakan LLM untuk meringkas bagian percakapan yang lebih lama, menggantinya dengan satu pesan ringkasan.
- Perintah default mempertahankan fakta utama, keputusan, preferensi pengguna, dan hasil panggilan alat.
- Memerlukan klien LLM terpisah untuk ringkasan — model yang lebih kecil dan lebih cepat direkomendasikan.
- Terbaik untuk mempertahankan konteks percakapan sambil mengurangi jumlah token secara signifikan.
- Anda dapat memberikan perintah ringkasan kustom.
- Melindungi pesan sistem dan grup non-sistem terbaru
MinimumPreserved(default:4). - Memindahkan pesan lama ke
IChatClientterpisah dengan petunjuk ringkasan, lalu menyisipkan ringkasannya sebagai grupMessageGroupKind.Summary.
// Summarize older messages when tokens exceed 1280, keeping the last 4 groups
SummarizationCompactionStrategy summarization = new(
chatClient: summarizerChatClient,
trigger: CompactionTriggers.TokensExceed(0x500),
minimumPreserved: 4);
Anda dapat memberikan perintah ringkasan kustom:
SummarizationCompactionStrategy summarization = new(
chatClient: summarizerChatClient,
trigger: CompactionTriggers.TokensExceed(0x500),
summarizationPrompt: "Summarize the key decisions and user preferences only.");
- Dipicu ketika jumlah pesan non-sistem yang disertakan melebihi
target_count + threshold. - Mempertahankan pesan
target_countterbaru; meringkas semua yang lebih lama. - Membutuhkan
SupportsChatGetResponseklien.
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,
)
Berikan perintah ringkasan kustom:
summarization = SummarizationStrategy(
client=summarizer_client,
target_count=4,
prompt="Summarize the key decisions and user preferences only.",
)
Strategi Pemadatan Pipa
Menyusun beberapa strategi ke dalam alur berurutan. Setiap strategi beroperasi pada hasil strategi sebelumnya, memungkinkan kompaksi berlapis dari lembut ke agresif.
- Pemicu pipa aliran adalah
CompactionTriggers.Always— setiap strategi anak mengevaluasi pemicunya dengan mandiri. - Strategi dijalankan secara berurutan, jadi letakkan strategi paling lembut terlebih dahulu.
PipelineCompactionStrategy pipeline = new(
new ToolResultCompactionStrategy(CompactionTriggers.TokensExceed(0x200)),
new SummarizationCompactionStrategy(summarizerChatClient, CompactionTriggers.TokensExceed(0x500)),
new SlidingWindowCompactionStrategy(CompactionTriggers.TurnsExceed(4)),
new TruncationCompactionStrategy(CompactionTriggers.TokensExceed(0x8000)));
Alur ini:
- Menciutkan hasil alat lama (lembut).
- Meringkas rentang percakapan yang lebih lama (sedang).
- Hanya menyimpan 4 percakapan pengguna terakhir (agresif).
- Menjatuhkan grup tertua jika masih melebihi anggaran (backstop darurat).
Strategi Kompak Panggilan Alat Selektif
Sepenuhnya mengecualikan grup panggilan alat yang lebih lama, hanya menyimpan yang terakhir keep_last_tool_call_groups.
- Tidak menyentuh pesan pengguna atau asisten biasa.
- Terbaik ketika obrolan alat mendominasi penggunaan token dan riwayat alat lengkap tidak diperlukan.
from agent_framework._compaction import SelectiveToolCallCompactionStrategy
# Keep only the most recent tool-call group
selective_tool = SelectiveToolCallCompactionStrategy(keep_last_tool_call_groups=1)
TokenBudgetComposedStrategy
Menyusun beberapa strategi ke dalam alur berurutan yang didorong oleh anggaran token. Setiap strategi anak berjalan secara berurutan, berhenti lebih awal setelah anggaran terpenuhi. Cadangan bawaan mengecualikan grup tertua jika strategi sendiri tidak dapat mencapai target.
- Strategi dijalankan secara berurutan; menempatkan strategi paling lembut terlebih dahulu.
-
early_stop=True(default) berhenti segera setelah anggaran token terpenuhi.
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),
],
)
Alur ini:
- Menciutkan hasil perangkat lama (dengan lembut).
- Meringkas rentang percakapan yang lebih lama (sedang).
- Hanya menyimpan 20 grup terakhir (agresif).
- Kembali ke pengecualian terlama-pertama jika masih melebihi anggaran (backstop darurat).
Menggunakan pemadatan dengan agen
Bungkus strategi pemadatan menggunakan CompactionProvider dan daftarkan sebagai AIContextProvider. Teruskan satu strategi atau PipelineCompactionStrategy ke konstruktor.
Mendaftar dengan builder API
Daftarkan penyedia pada ChatClientBuilder menggunakan UseAIContextProviders. Penyedia layanan berjalan di dalam loop pemanggilan alat, memadatkan pesan sebelum setiap panggilan 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));
Petunjuk / Saran
Gunakan model yang lebih kecil dan lebih murah (seperti gpt-4o-mini) untuk ringkasan klien obrolan untuk mengurangi biaya sambil mempertahankan kualitas ringkasan.
Jika hanya satu strategi yang diperlukan, teruskan langsung ke CompactionProvider tanpa membungkusnya dalam :PipelineCompactionStrategy
agentChatClient
.AsBuilder()
.UseAIContextProviders(new CompactionProvider(
new SlidingWindowCompactionStrategy(CompactionTriggers.TurnsExceed(20))))
.BuildAIAgent(...);
Mendaftar melalui ChatClientAgentOptions
Penyedia juga dapat ditentukan langsung pada ChatClientAgentOptions.AIContextProviders:
AIAgent agent = agentChatClient
.AsBuilder()
.BuildAIAgent(new ChatClientAgentOptions
{
AIContextProviders = [new CompactionProvider(compactionPipeline)]
});
Nota
Ketika didaftarkan melalui ChatClientAgentOptions, CompactionProvidertidak terlibat selama loop pemanggilan alat. Penyedia konteks pada tingkat agen berjalan sebelum riwayat obrolan disimpan, sehingga setiap pesan ringkasan sintetis yang dihasilkan oleh CompactionProvider dapat menjadi bagian dari riwayat yang disimpan saat menggunakan ChatHistoryProvider. Untuk memadamkan hanya konteks permintaan dalam penerbangan sambil mempertahankan riwayat asli yang disimpan, daftarkan penyedia melalui ChatClientBuilderUseAIContextProviders(...) sebagai gantinya.
Pemadatan Sementara
CompactionProvider.CompactAsync menerapkan strategi ke daftar pesan arbitrer tanpa sesi agen aktif:
IEnumerable<ChatMessage> compacted = await CompactionProvider.CompactAsync(
new TruncationCompactionStrategy(CompactionTriggers.TokensExceed(8000)),
existingMessages);
CompactionProvider adalah penyedia konteks yang menerapkan strategi pemadatan sebelum dan sesudah setiap agen dijalankan. Tambahkan sebagai bagian dari penyedia riwayat dalam daftar agen context_providers.
-
before_strategy— dijalankan sebelum panggilan model, mengompres pesan yang sudah dimuat ke dalam konteks. -
after_strategy— berjalan setelah panggilan model, memadatkan pesan yang disimpan oleh penyedia riwayat sehingga giliran berikutnya dimulai dengan ukuran yang lebih kecil. -
history_source_idsource_id— penyedia riwayat yang pesanafter_strategytersimpannya harus ringkas (default ke"in_memory").
Mendaftar dengan agen
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))
Petunjuk / Saran
Gunakan model yang lebih kecil dan lebih murah (seperti gpt-4o-mini) untuk klien ringkasan guna mengurangi biaya sambil mempertahankan kualitas ringkasan.
Jika hanya satu strategi yang diperlukan, berikan langsung sebagai before_strategy:
compaction = CompactionProvider(
before_strategy=SlidingWindowStrategy(keep_last_groups=20),
history_source_id=history.source_id,
)
Memampatkan riwayat persisten setelah setiap eksekusi
Gunakan after_strategy untuk memadamkan pesan yang disimpan oleh penyedia riwayat sehingga giliran di masa mendatang dimulai dengan konteks yang dikurangi:
compaction = CompactionProvider(
before_strategy=SlidingWindowStrategy(keep_last_groups=20),
after_strategy=ToolResultCompactionStrategy(keep_last_tool_call_groups=1),
history_source_id=history.source_id,
)
Pemadatan Sementara
apply_compaction menerapkan strategi ke daftar pesan arbitrer di luar sesi agen aktif:
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,
)
Memilih strategi
| Strategi | Agresivitas | Mempertahankan konteks | Memerlukan LLM | Paling cocok untuk |
|---|---|---|---|---|
ToolResultCompactionStrategy |
Low | Tinggi — hanya menciutkan hasil alat | No | Merebut kembali ruang dari output alat verbose |
SummarizationCompactionStrategy |
Medium | Sedang — mengganti riwayat dengan ringkasan | Yes | Percakapan panjang di mana konteks penting |
SlidingWindowCompactionStrategy |
High | Rendah — melewatkan seluruh giliran | No | Batas jumlah giliran ketat |
TruncationCompactionStrategy |
High | Rendah — menghapus kelompok tertua | No | Penyangga anggaran darurat token |
PipelineCompactionStrategy |
Dapat dikonfigurasi | Tergantung pada strategi anak | Depends | Pemadatan berlapis dengan beberapa opsi cadangan |
| Strategi | Agresivitas | Mempertahankan konteks | Memerlukan LLM | Paling cocok untuk |
|---|---|---|---|---|
ToolResultCompactionStrategy |
Low | Tinggi — meringkas hasil alat ke dalam pesan ringkasan | No | Merebut kembali ruang dari output alat yang berlebihan |
SelectiveToolCallCompactionStrategy |
Rendah–Sedang | Sedang — sepenuhnya mengecualikan kelompok panggilan alat lama | No | Menghapus riwayat alat saat hasil tidak lagi diperlukan |
SummarizationStrategy |
Medium | Sedang — mengganti riwayat dengan ringkasan | Yes | Percakapan panjang di mana konteks penting |
SlidingWindowStrategy |
High | Rendah — menghapus grup paling lama | No | Batas jumlah grup yang ketat |
TruncationStrategy |
High | Rendah — menghapus grup terlama | No | Pesan darurat- atau backstop anggaran token |
TokenBudgetComposedStrategy |
Dapat dikonfigurasi | Tergantung pada strategi anak | Depends | Pemadatan berlapis dengan tujuan pengelolaan anggaran token dan beberapa alternatif |