Loop Panggilan Agent AI Kustom dan Skema Pengendalian Biaya Token Setelah Fase Demo
28 июля 2026 г.
0
Computing/SoftwareComments (0)
Log in to leave a comment
No posts yet
Log in to leave a comment
No posts yet
Mengambil framework dan membuat AI agent menggunakan data internal perusahaan biasanya berjalan lancar hingga tahap prototipe. Masalah sebenarnya baru dimulai saat kode ini diimplementasikan ke lingkungan production. Agent yang tadinya bekerja dengan baik di dalam layar tiba-tiba terjebak dalam satu input tak terduga, melakukan panggilan berulang tanpa henti, dan menghasilkan tagihan API hingga puluhan juta rupiah dalam kurun waktu akhir pekan.
Sebagian besar gangguan yang terjadi di lapangan bukan disebabkan oleh keterbatasan model LLM itu sendiri, melainkan karena kegagalan manajemen status (state management) dan ketiadaan kontrol eksternal. Kita harus mengakhiri situasi di mana kita membuat tool kustom atas perintah manajemen, tetapi malah menghabiskan seharian hanya untuk melakukan debugging pada hallucination agent yang muncul tiba-tiba serta mengurus tagihan token yang membengkak alih-alih fokus pada pekerjaan utama.
Setelah keluar dari lingkungan demo, agent akan membentur tiga dinding besar: operasional black box, loop non-deterministik, dan risiko kebocoran data.
Jika input dan output dari setiap tahap proses penalaran (Chain-of-Thought), panggilan tool eksternal (Tool Call), dan pencarian basis data vektor tidak tercatat dalam log, kita tidak akan bisa menemukan penyebabnya saat terjadi masalah. Hanya untuk melacak di mana prompt mengalami kekacauan saja bisa menghabiskan waktu seharian penuh.
Yang lebih serius adalah infinite loop. Agent dengan arsitektur ReAct (Reasoning + Acting) akan terus mengirimkan permintaan yang sama secara berulang jika hasil eksekusi tool bersifat ambigu.
`
┌─────────────────────────────────────────────────────────────────────────┐
│ ReAct Architecture Loop │
│ │
│ ┌────────────┐ User Query ┌────────────┐ Tool Call Request │
│ │ User │ ──────────────> │ Main LLM │ ────────────────────┐ │
│ └────────────┘ └────────────┘ │ │
│ ▲ ▼ │
│ │ Observation ┌──────┐ │
│ │ (Ambiguous/Failed) │ Tool │ │
│ └─────────────────────── │ A │ │
│ └──────┘ │
│ * Problem: When Observation fails, LLM retries Tool A endlessly. │
└─────────────────────────────────────────────────────────────────────────┘
`
Begitu agent gagal keluar dari kondisi berhenti dan terus-menerus memanggil API dengan argumen yang sama, anggaran token bulanan bisa habis hanya dalam beberapa menit. Kegagalan berantai di mana agent utama dan sub-agent saling memanggil dan melakukan retry menyumbang lebih dari 30% dari total penyebab gangguan sistem secara keseluruhan.
Ketika riwayat percakapan terus menumpuk dan context window menjadi penuh, kinerja model itu sendiri akan menurun. Di samping itu, prompt yang di-hardcode sebagai string di dalam kode Python membuat kita harus mem-build ulang dan mendistribusikan ulang seluruh sistem hanya untuk mengedit satu frasa sederhana.
Kita harus memisahkan solusi debugging lokal dengan tool observabilitas production untuk menentukan poin pengumpulan log. Pada tahap pengembangan, kita menggunakan Arize Phoenix berbasis OpenTelemetry untuk memeriksa kualitas embedding RAG dan panggilan tool. Pada lingkungan production, kita menghubungkan Langfuse yang menggunakan ClickHouse sebagai backend untuk memantau trace log dan konsumsi token secara real-time.
`
┌─────────────────────────────────────────────────────────────────────────┐
│ Semantic Caching & Routing Flow │
│ │
│ Client Query │
│ │ │
│ ▼ │
│ ┌───────────┐ Similarity >= 0.92? ┌─────────────────────────────┐ │
│ │ Redis Vector │ ─────────────────────────> │ Return Cached Response │ │
│ │ Cache │ (Cache Hit) │ (Latency -88%, Cost -86%) │ │
│ └───────────┘ └─────────────────────────────┘ │
│ │ │
│ │ (Cache Miss) │
│ ▼ │
│ ┌───────────┐ Execution & Save Cache ┌─────────────────────────────┐ │
│ │ External │ ────────────────────────> │ Store Result as Vector in │ │
│ │ LLM API │ │ Backend Database │ │
│ └───────────┘ └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
`
Biaya API yang timbul dari kueri berulang dipangkas menggunakan lapisan Semantic Caching.
Berdasarkan data analisis terhadap 60.000 kueri yang dirilis oleh AWS, menerapkan semantic cache dengan standar kemiripan kosinus (cosine similarity) berhasil menekan biaya inferensi LLM hingga 86% dan mengoptimalkan latensi respons sebesar 88%. Framework RouteLLM dari LMSYS juga berhasil menghemat biaya sebesar 85% dengan membagi permintaan ke model berbiaya tinggi atau berbiaya rendah berdasarkan tingkat kesulitan pertanyaan.
Semantic caching dibangun dengan urutan sebagai berikut:
Untuk menghentikan infinite loop secara mendasar, kita harus memasukkan pola circuit breaker yang memvalidasi status agent secara langsung ke dalam flow kontrol pipeline. Bergantung pada opsi retry bawaan yang disediakan oleh framework dapat menyebabkan exception pecah dan mematikan seluruh layanan. Cara yang aman adalah meng-hash nama tool dan nilai argumen menggunakan SHA-256 lalu memasukkannya ke dalam daftar; jika hash yang sama menumpuk 3 kali berturut-turut, paksa sistem untuk mengalihkan ke node lain.
`python
import hashlib
from typing import TypedDict, Annotated, List
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages
class AgentState(TypedDict):
messages: Annotated[List[BaseMessage], add_messages]
steps: int
tool_hashes: List[str]
def hash_tool_call(tool_name: str, tool_args: str) -> str:
raw_str = f"{tool_name}:{tool_args}"
return hashlib.sha256(raw_str.encode('utf-8')).hexdigest()
def agent_circuit_breaker_router(state: AgentState) -> str:
# 1. Jika total eksekusi melebihi 5 kali, beralih ke node jalur keluar yang ditentukan
if state["steps"] > 5:
return "fallback_graceful_node"
# 2. Jika Tool dan Argument yang sama dipanggil 3 kali berturut-turut, segera blokir
hashes = state.get("tool_hashes", [])
if len(hashes) >= 3 and hashes[-1] == hashes[-2] == hashes[-3]:
return "fallback_graceful_node"
# 3. Periksa kata kunci penyelesaian normal
last_message = state["messages"][-1]
if "FINAL_ANSWER" in last_message.content:
return "end"
return "continue_tools"
`
Terlepas dari status output non-deterministik LLM, router ini memvalidasi pernyataan kondisi di lingkungan eksekusi Python, sehingga secara fisik mencegah masuknya agent ke dalam loop akibat ilusi atau hallucination.
Membiarkan prompt terisolasi di dalam kode dapat menyebabkan kegagalan regresi (Regression Failure), di mana fitur yang sebelumnya berjalan lancar menjadi tidak berfungsi setelah dilakukan modifikasi model. Prompt harus dikeluarkan dari kode Python dan dikelola sebagai file YAML independen.
`yaml
name: "agent_reasoning"
version: "1.2.0"
model: "gpt-4o"
temperature: 0.1
messages:
`
Prompt yang telah dipisahkan ini digabungkan dengan DeepEval (framework evaluasi open-source) dan Pytest untuk diuji secara otomatis di dalam pipeline CI/CD. Metrik G-Eval ditetapkan sebagai tolok ukur untuk memverifikasi nilai respons model sebelum proses deployment.
`python
import pytest
from deepeval import assert_test
from deepeval.metrics import GEval, TaskCompletionMetric
from deepeval.test_case import LLMTestCase, SingleTurnParams
correctness_metric = GEval(
name="Akurasi dan Kepatuhan Skema",
criteria="Apakah respons LLM menjawab pertanyaan dengan akurat dan mematuhi format JSON yang diminta secara sempurna?",
evaluation_params=[SingleTurnParams.ACTUAL_OUTPUT, SingleTurnParams.EXPECTED_OUTPUT],
threshold=0.7
)
@pytest.mark.parametrize(
"user_input, expected_output",
[
("Rangkum data penjualan Q1 tahun 2024.", "Total penjualan Q1 adalah 5 miliar KRW."),
("Beri tahu saya peraturan perhitungan pesangon.", "Pesangon adalah rata-upah 30 hari atau lebih untuk setiap 1 tahun masa kerja.")
]
)
def test_agent_regression(user_input, expected_output):
actual_output = run_in_house_agent(user_input)
test_case = LLMTestCase(
input=user_input,
actual_output=actual_output,
expected_output=expected_output
)
# Batalkan build jika skor tidak mencapai ambang batas yang ditetapkan
assert_test(test_case, [correctness_metric, TaskCompletionMetric(threshold=0.8)])
`
Sistem evaluasi diintegrasikan melalui tiga tahap:
deepeval test run berjalan secara otomatis saat membuat PR setelah modifikasi kode.`yaml
name: AI Agent Evaluation Gate
on:
pull_request:
branches: [ main ]
jobs:
eval-gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install Dependencies
run: |
pip install poetry
poetry install
- name: Run DeepEval Suite
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
poetry run deepeval test run tests/test_evals.py
`
Untuk mencegah kebocoran data internal perusahaan, diperlukan guardrail yang melakukan de-identifikasi Informasi Identitas Pribadi (PII) sebelum permintaan API keluar ke eksternal. Dengan memasang mesin Microsoft Presidio pada gateway, sistem akan menyamarkan nomor identitas (RRN), email, nomor telepon, dan ID karyawan secara otomatis.
`python
from presidio_analyzer import AnalyzerEngine, PatternRecognizer
from presidio_anonymizer import AnonymizerEngine
from presidio_anonymizer.entities import OperatorConfig
analyzer = AnalyzerEngine()
employee_id_recognizer = PatternRecognizer(
supported_entity="EMPLOYEE_ID",
regex="EMP-[0-9]{6}",
score=0.95
)
analyzer.registry.add_recognizer(employee_id_recognizer)
anonymizer = AnonymizerEngine()
def sanitize_user_prompt(raw_prompt: str) -> str:
results = analyzer.analyze(
text=raw_prompt,
entities=["PERSON", "PHONE_NUMBER", "EMAIL_ADDRESS", "EMPLOYEE_ID"],
language="en"
)
anonymized_result = anonymizer.anonymize(
text=raw_prompt,
analyzer_results=results,
operators={
"DEFAULT": OperatorConfig("replace", {"new_value": "<REDACTED>"}),
"EMPLOYEE_ID": OperatorConfig("mask", {"chars_to_mask": 6, "masking_char": "*", "from_end": True})
}
)
return anonymized_result.text
`
Saat menghubungkan pencarian RAG, kita juga harus memastikan bahwa hanya dokumen yang sesuai dengan tingkat hak akses pengguna yang ditarik. Basis data vektor seperti Qdrant atau Pinecone menangani pemisahan hak akses menggunakan penyaringan metadata (Metadata Filtering) saat melakukan pencarian kemiripan.
`python
from qdrant_client import QdrantClient
from qdrant_client.http import models
client = QdrantClient(host="localhost", port=6333)
def search_documents_with_rbac(query_vector: list, user_department: str, user_clearance_level: int):
search_result = client.search(
collection_name="enterprise_knowledge_base",
query_vector=query_vector,
query_filter=models.Filter(
must=[
models.FieldCondition(
key="department",
match=models.MatchValue(value=user_department)
),
models.FieldCondition(
key="security_level",
range=models.Range(lte=user_clearance_level)
)
]
),
limit=5
)
return search_result
`
Pencegahan prompt injection pada dasarnya dilakukan dengan memisahkan secara total kanal system prompt dan kanal input pengguna. Tugas berisiko tinggi seperti memodifikasi database atau memanggil API eksternal harus melalui prosedur persetujuan manual oleh manusia (Human-in-the-Loop) atau dibatasi izin eksekusinya di dalam sandbox terisolasi agar tetap aman.
Jika ingin menggantikan modul SaaS dan terus mengoperasikannya sebagai sistem internal perusahaan, diperlukan rutinitas pemeriksaan secara berkala.
| Siklus | Item Pemeriksaan Operasional | Rincian Tugas |
|---|---|---|
| Setiap Hari | Tingkat Error dan Konsumsi Token | Periksa tingkat error HTTP 5xx dan konsumsi token per departemen di dashboard Langfuse |
| Setiap Hari | Riwayat Pemblokiran Circuit Breaker | Kumpulkan nama tool dan pola argumen pada sesi yang terputus akibat deteksi loop, lalu perbaiki |
| Setiap Minggu | Ekstraksi Kueri Gagal Pencarian RAG | Pilih permintaan dengan skor kemiripan di bawah 0,6 dan tambahkan ke himpunan jawaban benar untuk pengujian |
| Setiap Minggu | Verifikasi Positif Palsu Masking PII | Ambil sampel log pemrosesan Presidio untuk memverifikasi apakah ada masking yang terlewat |
| Setiap Bulan | Pembaruan Kriteria Evaluasi CI/CD | Sesuaikan test case otomatis untuk mencerminkan perubahan bisnis |
Jika Anda sedang mempertimbangkan antara hosting model mandiri (berbasis vLLM) atau berlangganan API eksternal, cobalah hitung berdasarkan traffic harian.
Biaya sewa bulanan untuk instance AWS EC2 g5.2xlarge yang dilengkapi 1 GPU NVIDIA A10G adalah sekitar $880. Di sisi lain, tarif API GPT-4o berkisar di angka $2.50 per 1 juta token input dan $10.00 per 1 juta token output. Jika traffic harian berada di bawah 50 juta token, metode berlangganan API jauh lebih menguntungkan mengingat beban kerja enginir DevOps dan biaya tetap GPU. Baru ketika traffic harian melebihi 100 juta token atau saat isolasi jaringan internal secara mutlak diperlukan, beralih ke hosting mandiri berbasis vLLM menjadi pilihan yang tepat.
Untuk mengantisipasi gangguan pada model utama, buatlah struktur routing backup 4 tingkat (4-Tier).
`
┌─────────────────────────────────────────────────────────────────────────┐
│ 4-Tier Graceful Degradation Architecture │
│ │
│ [Tier 1] Primary High-Performance Model (e.g., GPT-4o) │
│ │ │
│ ▼ (API Failure / Timeout / Circuit Breaker) │
│ [Tier 2] Lightweight Routing Model (e.g., GPT-4o-mini / On-Prem vLLM) │
│ │ │
│ ▼ (Continuous Outage) │
│ [Tier 3] Deterministic Regex & SQL Rule Engine │
│ │ │
│ ▼ (Unrecoverable Error) │
│ [Tier 4] Static Error Message & Async Admin Ticket Generation │
└─────────────────────────────────────────────────────────────────────────┘
`
Pekerjaan menyempurnakan sistem agent kustom dilakukan dalam rentang waktu 90 hari.
| Periode | Target Penerapan | Rincian Tugas Konkret |
|---|---|---|
| Hari ke-1~30 | Visibilitas dan Perlindungan Data | Menginstal mesin masking Presidio dan mengimplementasikan SDK logging Langfuse |
| Hari ke-31~60 | Pemblokiran Loop dan Penghematan Biaya | Menerapkan semantic caching Redis dan menghubungkan circuit breaker berbasis Python |
| Hari ke-61~90 | Otomatisasi Verifikasi dan Kontrol Hak Akses | Manajemen Git untuk prompt, integrasi CI/CD DeepEval, dan penerapan metadata RBAC Qdrant |
Pada bulan pertama, bangun solusi observabilitas untuk mencegah kebocoran informasi pribadi dan memastikan semua permintaan tercatat dalam log. Pada bulan kedua, pasang caching prompt berulang dan router pemblokir loop untuk memangkas pengeluaran biaya yang tidak terduga. Pada bulan terakhir, setelah manajemen versi prompt dan sistem evaluasi pengujian otomatis selesai dibangun, Anda dapat mengoperasikan agent secara stabil tanpa perlu khawatir akan malfungsi setiap kali melakukan deployment.