Membangun AI Agent Layanan Pelanggan dengan Python: Tutorial Step-by-Step
Pendahuluan
Bayangkan kamu sedang membangun aplikasi e-commerce seperti Tokopedia atau Shopee — ada ribuan pelanggan yang bertanya setiap hari soal status pesanan, kebijakan pengembalian, atau stok produk. Melayani semua pertanyaan itu secara manual tentu tidak skalabel. Di sinilah AI Agent layanan pelanggan hadir sebagai solusi.
Berbeda dengan chatbot biasa yang hanya mencocokkan kata kunci, AI Agent mampu:
- Memahami konteks percakapan secara mendalam
- Memanggil tools eksternal (cek database, kirim email, cari informasi)
- Membuat keputusan multi-langkah secara mandiri
- Menangani alur percakapan yang kompleks
Dalam tutorial ini, kita akan membangun AI Agent layanan pelanggan yang bisa menjawab pertanyaan produk, mengecek status pesanan, dan mengeskalasi tiket ke tim manusia — semuanya menggunakan Python dan OpenAI API. Jika kamu belum familiar dengan konsep dasar prompt engineering, ada baiknya membaca Tutorial Menulis Prompt Efektif untuk Pemula terlebih dahulu sebelum melanjutkan.
Konsep Dasar
Arsitektur AI Agent Layanan Pelanggan
Sebuah AI Agent layanan pelanggan terdiri dari beberapa komponen utama:
User Message → Agent Core (LLM) → Tool Selection → Tool Execution → Response
↑ ↓
Memory/Context ←————————————————— Tool Result
Komponen kunci:
- LLM Core — Model bahasa (GPT-4, Claude) yang menjadi “otak” agent
- Tools/Functions — Aksi yang bisa dilakukan agent (cek order, FAQ lookup, eskalasi)
- Memory — Riwayat percakapan agar agent memahami konteks
- System Prompt — Instruksi kepribadian dan batasan agent
Pola ReAct untuk Customer Service
Agent kita menggunakan pola Reason + Act: agent berpikir terlebih dahulu sebelum mengambil aksi. Misalnya:
User: "Pesanan saya #12345 belum sampai"
Agent thinks: "Pelanggan ingin tahu status pesanan → perlu panggil tool check_order_status"
Agent acts: check_order_status(order_id="12345")
Agent responds: "Pesanan #12345 sedang dalam proses pengiriman, estimasi tiba besok."
Contoh Kode
Setup Project
Pertama, install dependensi yang dibutuhkan:
pip install openai python-dotenv
Buat file .env:
OPENAI_API_KEY=sk-your-api-key-here
Struktur file project kita:
customer-service-agent/
├── .env
├── tools.py
├── tool_schemas.py
├── agent.py
└── main.py
Definisi Tools
Tools adalah fungsi Python yang bisa dipanggil oleh agent. Kita buat tiga tools utama:
# tools.py
import json
from datetime import datetime, timedelta
import random
# Simulasi database pesanan
ORDER_DATABASE = {
"12345": {"status": "Dalam Pengiriman", "estimasi": "Besok", "produk": "Laptop Gaming X"},
"67890": {"status": "Selesai", "estimasi": None, "produk": "Mouse Wireless Y"},
"11111": {"status": "Diproses", "estimasi": "3 hari lagi", "produk": "Keyboard Mechanical Z"},
}
# Simulasi FAQ database
FAQ_DATABASE = {
"pengembalian": "Produk dapat dikembalikan dalam 7 hari sejak diterima dengan kondisi original.",
"garansi": "Semua produk elektronik mendapat garansi resmi 1 tahun dari produsen.",
"pembayaran": "Kami menerima transfer bank, kartu kredit, QRIS, dan dompet digital.",
"pengiriman": "Pengiriman tersedia ke seluruh Indonesia dengan JNE, Sicepat, dan Anteraja.",
}
def check_order_status(order_id: str) -> str:
"""Mengecek status pesanan berdasarkan ID"""
order = ORDER_DATABASE.get(order_id)
if not order:
return json.dumps({
"success": False,
"message": f"Pesanan dengan ID {order_id} tidak ditemukan."
})
result = {
"success": True,
"order_id": order_id,
"produk": order["produk"],
"status": order["status"],
"estimasi_tiba": order["estimasi"] or "Sudah selesai"
}
return json.dumps(result, ensure_ascii=False)
def get_faq_answer(topik: str) -> str:
"""Mengambil jawaban FAQ berdasarkan topik"""
topik_lower = topik.lower()
# Cari topik yang paling relevan
for key, answer in FAQ_DATABASE.items():
if key in topik_lower or topik_lower in key:
return json.dumps({
"success": True,
"topik": key,
"jawaban": answer
}, ensure_ascii=False)
return json.dumps({
"success": False,
"message": "Informasi tidak ditemukan. Akan dieskalasi ke tim support."
})
def escalate_to_human(alasan: str, prioritas: str = "normal") -> str:
"""Mengeskalasi percakapan ke agen manusia"""
ticket_id = f"TKT-{random.randint(10000, 99999)}"
return json.dumps({
"success": True,
"ticket_id": ticket_id,
"alasan": alasan,
"prioritas": prioritas,
"estimasi_respon": "2-4 jam kerja",
"pesan": f"Tiket {ticket_id} telah dibuat dan tim kami akan menghubungi kamu segera."
}, ensure_ascii=False)
Definisi Tool Schema untuk OpenAI
# tool_schemas.py
TOOLS = [
{
"type": "function",
"function": {
"name": "check_order_status",
"description": "Mengecek status pesanan pelanggan berdasarkan nomor order ID",
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "Nomor ID pesanan, contoh: 12345"
}
},
"required": ["order_id"]
}
}
},
{
"type": "function",
"function": {
"name": "get_faq_answer",
"description": "Mengambil jawaban untuk pertanyaan umum tentang kebijakan toko",
"parameters": {
"type": "object",
"properties": {
"topik": {
"type": "string",
"description": "Topik pertanyaan, contoh: pengembalian, garansi, pembayaran, pengiriman"
}
},
"required": ["topik"]
}
}
},
{
"type": "function",
"function": {
"name": "escalate_to_human",
"description": "Mengeskalasi masalah yang tidak bisa diselesaikan AI ke agen manusia",
"parameters": {
"type": "object",
"properties": {
"alasan": {
"type": "string",
"description": "Alasan eskalasi dan ringkasan masalah pelanggan"
},
"prioritas": {
"type": "string",
"enum": ["rendah", "normal", "tinggi", "urgent"],
"description": "Tingkat urgensi masalah"
}
},
"required": ["alasan"]
}
}
}
]
Core Agent dengan Agentic Loop
Ini adalah inti dari sistem kita. Fungsi run_agent menjalankan agentic loop — agent terus berputar memanggil tools sampai menghasilkan respons final untuk pelanggan:
# agent.py
import json
import os
from openai import OpenAI
from dotenv import load_dotenv
from tool_schemas import TOOLS
from tools import check_order_status, get_faq_answer, escalate_to_human
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
SYSTEM_PROMPT = """Kamu adalah Kaka, asisten layanan pelanggan yang ramah dan profesional
untuk toko elektronik online KamusShop.
KEMAMPUANMU:
- Mengecek status pesanan pelanggan
- Menjawab pertanyaan seputar kebijakan toko (pengembalian, garansi, pembayaran, pengiriman)
- Mengeskalasi masalah kompleks ke tim manusia
PANDUAN PERILAKU:
1. Selalu sapa pelanggan dengan ramah dan gunakan bahasa Indonesia yang sopan
2. Jika pelanggan memberikan nomor pesanan, langsung cek statusnya
3. Untuk pertanyaan yang tidak bisa kamu jawab, eskalasi ke tim manusia
4. Jaga percakapan tetap fokus dan efisien
5. Akhiri setiap percakapan dengan tawaran bantuan lebih lanjut
JANGAN:
- Memberikan informasi yang tidak akurat
- Berjanji hal-hal di luar kewenanganmu
- Mendiskusikan topik di luar layanan pelanggan
"""
# Mapping nama fungsi ke fungsi Python
TOOL_FUNCTIONS = {
"check_order_status": check_order_status,
"get_faq_answer": get_faq_answer,
"escalate_to_human": escalate_to_human,
}
MAX_ITERATIONS = 10 # Batas maksimal iterasi untuk mencegah infinite loop
def run_agent(user_message: str, conversation_history: list) -> tuple[str, list]:
"""
Menjalankan agent untuk satu giliran percakapan.
Args:
user_message: Pesan dari pelanggan
conversation_history: Riwayat percakapan sebelumnya
Returns:
tuple: (response_text, updated_history)
"""
# Tambah pesan user ke history
conversation_history.append({
"role": "user",
"content": user_message
})
messages = [{"role": "system", "content": SYSTEM_PROMPT}] + conversation_history
iteration = 0
# Agentic loop — agent terus berjalan sampai memberikan respons final
while iteration < MAX_ITERATIONS:
iteration += 1
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=TOOLS,
tool_choice="auto",
temperature=0.3 # Rendah untuk konsistensi customer service
)
message = response.choices[0].message
# Jika tidak ada tool call, agent sudah punya respons final
if not message.tool_calls:
final_response = message.content
conversation_history.append({
"role": "assistant",
"content": final_response
})
return final_response, conversation_history
# Tambahkan respons agent (beserta tool calls) ke messages
messages.append(message)
# Proses semua tool calls dalam satu giliran
for tool_call in message.tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
print(f" [Agent memanggil: {function_name}({function_args})]")
# Eksekusi tool yang dipilih agent
if function_name in TOOL_FUNCTIONS:
tool_result = TOOL_FUNCTIONS[function_name](**function_args)
else:
tool_result = json.dumps({"error": f"Tool {function_name} tidak ditemukan"})
# Tambahkan hasil tool ke messages agar agent bisa memprosesnya
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": tool_result
})
# Jika mencapai batas iterasi, kembalikan pesan fallback
fallback = "Maaf, terjadi kendala teknis saat memproses permintaan kamu. Tim kami akan segera menghubungi untuk membantu lebih lanjut."
conversation_history.append({"role": "assistant", "content": fallback})
return fallback, conversation_history
Interface Percakapan
# main.py
from agent import run_agent
def main():
print("=" * 50)
print(" KamusShop - Layanan Pelanggan AI")
print(" Ketik 'keluar' untuk mengakhiri sesi")
print("=" * 50)
print()
conversation_history = []
# Sapaan pembuka
print("Kaka: Halo! Selamat datang di KamusShop. Saya Kaka, asisten virtual kamu.")
print("Kaka: Ada yang bisa saya bantu hari ini?\n")
while True:
user_input = input("Kamu: ").strip()
if not user_input:
continue
if user_input.lower() in ["keluar", "exit", "quit"]:
print("\nKaka: Terima kasih sudah menghubungi KamusShop. Sampai jumpa!")
break
print()
response, conversation_history = run_agent(user_input, conversation_history)
print(f"Kaka: {response}\n")
if __name__ == "__main__":
main()
Contoh Output Interaksi
Jalankan agent dengan perintah python main.py, lalu coba beberapa skenario berikut:
Skenario 1 — Cek status pesanan:
==================================================
KamusShop - Layanan Pelanggan AI
Ketik 'keluar' untuk mengakhiri sesi
==================================================
Kaka: Halo! Selamat datang di KamusShop. Saya Kaka, asisten virtual kamu.
Kaka: Ada yang bisa saya bantu hari ini?
Kamu: Halo, pesanan saya 12345 belum sampai nih
[Agent memanggil: check_order_status({'order_id': '12345'})]
Kaka: Halo! Saya sudah cek pesanan kamu ya.
Pesanan #12345 (Laptop Gaming X) saat ini sedang **Dalam Pengiriman**
dan diperkirakan tiba **besok**.
Jika besok pesanan belum tiba, jangan ragu untuk menghubungi kami lagi
dan saya akan bantu proses penyelidikannya. Ada yang bisa saya bantu lagi?
Skenario 2 — Pertanyaan kebijakan:
Kamu: Kalau mau retur gimana caranya?
[Agent memanggil: get_faq_answer({'topik': 'pengembalian'})]
Kaka: Untuk pengembalian produk di KamusShop, berikut ketentuannya:
Produk dapat dikembalikan dalam **7 hari sejak diterima** dengan kondisi
original (tidak rusak, kelengkapan masih ada, kemasan masih baik).
Apakah ada pertanyaan lain yang bisa saya bantu?
Skenario 3 — Eskalasi ke manusia:
Kamu: Saya mau komplain, produk yang datang cacat dan sudah lewat 7 hari
[Agent memanggil: escalate_to_human({'alasan': 'Pelanggan menerima produk cacat
dan sudah melewati batas waktu pengembalian normal 7 hari', 'prioritas': 'tinggi'})]
Kaka: Saya sangat menyesal mendengar produk yang kamu terima dalam kondisi cacat.
Untuk kasus seperti ini, saya akan langsung eskalasi ke tim senior kami.
Tiket **TKT-47823** telah dibuat dengan prioritas **tinggi**. Tim kami akan
menghubungi kamu dalam **2-4 jam kerja** untuk menyelesaikan masalah ini.
Terima kasih atas kesabaranmu, dan kami pastikan masalah ini ditangani dengan baik.
Troubleshooting: Error yang Sering Muncul
openai.AuthenticationError: Incorrect API key
Penyebab: API key tidak terbaca dari environment variable, bisa karena file .env tidak ada, nama variabel salah, atau load_dotenv() dipanggil setelah os.getenv().
Solusi:
# Pastikan load_dotenv() dipanggil SEBELUM os.getenv()
from dotenv import load_dotenv
import os
load_dotenv() # Harus dipanggil lebih dulu!
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
raise ValueError("OPENAI_API_KEY tidak ditemukan. Periksa file .env kamu.")
print(f"API key loaded: {'Yes' if api_key else 'No'}") # Debug check
Pastikan juga isi file .env tidak mengandung spasi di sekitar tanda =:
# Benar:
OPENAI_API_KEY=sk-proj-xxxxx
# Salah (ada spasi):
OPENAI_API_KEY = sk-proj-xxxxx
json.JSONDecodeError saat Parsing Tool Arguments
Penyebab: Model kadang menghasilkan JSON yang tidak valid untuk argumen tool, terutama pada input yang mengandung karakter khusus atau tanda kutip.
Solusi:
import json
def safe_parse_args(raw_args: str) -> dict:
try:
return json.loads(raw_args)
except json.JSONDecodeError as e:
print(f"Warning: Gagal parse tool args: {e}")
print(f"Raw args: {raw_args}")
# Fallback: kembalikan dict kosong agar agent bisa melanjutkan
return {}
# Gunakan di dalam agentic loop:
for tool_call in message.tool_calls:
function_args = safe_parse_args(tool_call.function.arguments)
# ... lanjutkan eksekusi tool
Agent Masuk Infinite Loop (Tool Terus Dipanggil)
Penyebab: Jika tool selalu mengembalikan error atau respons ambigu, agent bisa terus memanggil tool tanpa menghasilkan respons akhir untuk pengguna.
Solusi:
Kita sudah menambahkan MAX_ITERATIONS = 10 di agent.py. Pastikan batas ini ada dan tampilkan log iterasi untuk debugging:
MAX_ITERATIONS = 10
while iteration < MAX_ITERATIONS:
iteration += 1
print(f" [Iterasi {iteration}/{MAX_ITERATIONS}]") # Untuk debugging
response = client.chat.completions.create(...)
message = response.choices[0].message
if not message.tool_calls:
break # Respons final ditemukan, keluar dari loop
# ... proses tool calls
# Tangani kasus batas iterasi terlampaui
if iteration >= MAX_ITERATIONS:
print("Warning: Agent mencapai batas iterasi maksimal!")
return "Maaf, terjadi kendala teknis. Tim kami akan menghubungi kamu.", conversation_history
RateLimitError: Rate limit reached
Penyebab: Terlalu banyak request dalam waktu singkat, umum terjadi saat testing agent dalam volume tinggi atau menggunakan tier API gratis.
Solusi:
import time
from openai import RateLimitError
def run_agent_with_retry(
user_message: str,
conversation_history: list,
max_retries: int = 3
) -> tuple[str, list]:
"""Wrapper run_agent dengan exponential backoff untuk rate limit."""
for attempt in range(max_retries):
try:
return run_agent(user_message, conversation_history)
except RateLimitError as e:
if attempt < max_retries - 1:
wait_time = 2 ** attempt # Exponential backoff: 1s, 2s, 4s
print(f"Rate limit tercapai. Menunggu {wait_time} detik... (percobaan {attempt + 1}/{max_retries})")
time.sleep(wait_time)
else:
print("Rate limit: semua percobaan gagal.")
raise
KeyError saat Mengakses Tool Result
Penyebab: Fungsi tool mengembalikan JSON dengan struktur yang tidak sesuai ekspektasi, misalnya karena refactor atau perubahan schema response.
Solusi:
import json
def check_order_status_safe(order_id: str) -> str:
"""Versi defensif check_order_status dengan validasi output."""
try:
result = check_order_status(order_id)
# Pastikan JSON valid sebelum dikembalikan ke agent
parsed = json.loads(result)
assert "success" in parsed # Field wajib harus ada
return result
except (json.JSONDecodeError, AssertionError, Exception) as e:
# Fallback response yang tetap valid
return json.dumps({
"success": False,
"message": f"Gagal mengambil data pesanan: {str(e)}"
})
Pertanyaan yang Sering Diajukan
Apa perbedaan AI Agent layanan pelanggan dengan chatbot biasa?
Chatbot konvensional bekerja berdasarkan aturan if-else atau pencocokan kata kunci yang statis. AI Agent, sebaliknya, menggunakan LLM sebagai “otak” yang bisa bernalar, memanggil tools secara dinamis, dan menangani percakapan multi-langkah yang kompleks tanpa perlu script yang ditulis manual untuk setiap skenario.
Bagaimana cara menambahkan tool baru ke agent?
Cukup dua langkah: (1) buat fungsi Python baru di tools.py dengan logika yang diinginkan, lalu (2) tambahkan schema JSON-nya ke list TOOLS di tool_schemas.py. Agent akan otomatis bisa menggunakan tool baru tersebut berdasarkan deskripsi yang kamu tulis di schema — tidak perlu mengubah kode agent.py sama sekali.
Apakah agent ini aman untuk dipakai di produksi?
Untuk produksi, kamu perlu menambahkan beberapa hal: autentikasi pelanggan sebelum mengakses data sensitif, validasi input yang ketat di setiap tool, logging percakapan untuk keperluan audit, serta guardrail untuk mencegah prompt injection. Implementasi di tutorial ini adalah titik awal yang solid, namun perlu diperkuat keamanannya sebelum menghadapi traffic nyata.
Bagaimana cara menyimpan riwayat percakapan agar persisten?
Pada tutorial ini, conversation_history disimpan di memori (RAM) dan hilang saat program ditutup. Untuk persistensi, simpan history ke database seperti SQLite atau Redis dengan session ID sebagai key. Setiap kali sesi dibuka, muat kembali history berdasarkan ID pengguna. Kamu juga bisa mempelajari Memahami Arsitektur LLM dan Cara Kerjanya untuk memahami bagaimana model bahasa memproses konteks percakapan.
Berapa biaya API yang dibutuhkan untuk agent ini?
Dengan model gpt-4o-mini, biaya per percakapan sangat terjangkau — sekitar $0.0001–$0.001 per sesi tergantung panjang percakapan. Untuk volume tinggi, pertimbangkan caching respons untuk pertanyaan yang sering berulang, batasi panjang conversation_history yang dikirim ke API, atau eksplorasi model open-source yang bisa di-deploy sendiri.
Kesimpulan
Kita telah berhasil membangun AI Agent layanan pelanggan yang fungsional dari nol menggunakan Python. Agent ini mampu mengecek status pesanan, menjawab FAQ, hingga mengeskalasi tiket ke tim manusia — semua dengan cara yang terasa natural bagi pelanggan, berkat agentic loop yang kita implementasikan di agent.py.
Kunci keberhasilan agent layanan pelanggan terletak pada tiga hal: tools yang dirancang dengan baik, system prompt yang jelas dan terarah, serta penanganan error yang robust. Dari sini, kamu bisa mengembangkannya lebih jauh: integrasikan dengan database nyata, tambahkan autentikasi pelanggan, atau hubungkan ke platform chat seperti WhatsApp Business API — jika kamu ingin membangun sistem seperti yang digunakan aplikasi super-app besar.
Selamat bereksperimen dan terus kembangkan project-mu! Jika ada pertanyaan atau kamu ingin mengeksplorasi topik AI lainnya, jangan ragu untuk menjelajahi artikel-artikel lain di KamusNgoding — kita belajar bersama, satu baris kode setiap harinya.