Hôm nay tôi muốn chia sẻ với các bạn một câu chuyện thực tế mà tôi vừa trải qua tuần qua. Một khách hàng của tôi - một sàn thương mại điện tử tầm trung với khoảng 50.000 đơn hàng/ngày - đang chết chìm trong biển ticket hỗ trợ khách hàng. Đội ngũ CSKH 12 người không kham nổi, đặc biệt vào các đợt sale lớn như 11/11 và Black Friday. Họ cần một giải pháp AI có thể tích hợp sâu vào hệ thống ERP nội bộ, truy vấn được đơn hàng, kiểm tra tồn kho và tự động refund - chứ không phải một chatbot generic trả lời chung chung.
Sau khi đánh giá nhiều framework, tôi quyết định dùng Claude Code Plugin System - hệ thống plugin chính thức cho phép mở rộng Claude với các tool, slash command và hook tùy chỉnh. Bài viết này là toàn bộ những gì tôi đã học được, kèm theo code mẫu có thể chạy ngay trên môi trường của bạn.
Trước khi vào phần kỹ thuật, tôi xin giới thiệu nhanh công cụ mà tôi sử dụng để benchmark và chạy production: HolySheep AI - nền tảng cung cấp quyền truy cập API đồng nhất cho Claude, GPT, Gemini, DeepSeek với chi phí cực thấp (¥1=$1, tỷ lệ tiết kiệm hơn 85% so với giá gốc). Hỗ trợ thanh toán WeChat/Alipay, độ trễ dưới 50ms, và đăng ký mới nhận ngay tín dụng miễn phí để thử nghiệm.
1. Tổng quan kiến trúc Plugin System
Hệ thống plugin của Claude Code hoạt động theo mô hình manifest-driven. Mỗi plugin là một thư mục chứa file plugin.json mô tả metadata, kèm theo các thành phần:
- Tools: Hàm Python/Node.js mà Claude có thể gọi để thao tác với hệ thống bên ngoài (database, API, file system).
- Slash Commands: Lệnh tắt người dùng gõ vào CLI để trigger workflow cụ thể.
- Hooks: Event listener chạy trước/sau khi Claude thực thi tool, dùng để logging, validation hoặc rollback.
- Agents: Sub-agent chuyên biệt cho từng domain (ví dụ:
code-reviewer,db-migrator). - Skills: File
SKILL.mdmô tả kiến thức chuyên ngành mà plugin có thể tham chiếu.
Cấu trúc thư mục chuẩn của một plugin:
ecommerce-cs-plugin/
├── plugin.json # Manifest khai báo metadata
├── tools/
│ ├── check_order.py # Tool truy vấn đơn hàng
│ ├── refund.py # Tool xử lý hoàn tiền
│ └── inventory.py # Tool kiểm tra tồn kho
├── commands/
│ └── escalate.md # Slash command chuyển ticket lên nhân viên
├── hooks/
│ └── audit_logger.py # Hook ghi log audit
├── agents/
│ └── refund-specialist.md # Agent chuyên xử lý refund
└── skills/
└── shopee-policy.md # Kiến thức về chính sách đổi trả
2. Tạo Plugin đầu tiên - Manifest và Tool cơ bản
Đầu tiên, tạo file plugin.json khai báo thông tin plugin. Đây là file bắt buộc và phải nằm ở thư mục gốc:
{
"name": "ecommerce-cs-plugin",
"version": "1.0.0",
"description": "Plugin hỗ trợ khách hàng cho sàn thương mại điện tử - tích hợp ERP, xử lý đơn hàng và hoàn tiền tự động",
"author": "Nguyễn Văn A <[email protected]>",
"license": "MIT",
"claude_code_version": ">=1.0.0",
"entry_point": "tools/router.py",
"permissions": [
"network:https://api.erp.example.com",
"filesystem:read:/var/log/audit",
"filesystem:write:/tmp/refund-queue"
],
"tools": [
{
"name": "check_order_status",
"module": "tools.check_order",
"function": "check_order_status",
"description": "Truy vấn trạng thái đơn hàng theo mã đơn",
"input_schema": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "Mã đơn hàng (VD: SH-2026-000123)"
}
},
"required": ["order_id"]
}
}
],
"commands": [
{
"name": "escalate",
"file": "commands/escalate.md",
"description": "Chuyển ticket phức tạp cho nhân viên CSKH"
}
],
"hooks": {
"pre_tool_call": "hooks/audit_logger.py:pre_hook",
"post_tool_call": "hooks/audit_logger.py:post_hook"
}
}
Tiếp theo, viết tool kiểm tra đơn hàng. Đây là nơi tôi dùng HolySheep AI làm fallback khi ERP timeout - cực kỳ tiện vì có thể dùng chung một API key cho cả Claude và các model khác:
# tools/check_order.py
"""
Tool kiểm tra trạng thái đơn hàng.
Gọi ERP nội bộ, fallback sang HolySheep AI để summarize nếu response quá dài.
"""
import os
import json
import requests
from typing import Any
Cấu hình - nên đặt trong environment variable
ERP_BASE_URL = os.getenv("ERP_BASE_URL", "https://erp.internal/api/v1")
HOLYSHEEP_API_KEY = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY")
HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1"
def check_order_status(order_id: str) -> dict[str, Any]:
"""
Truy vấn trạng thái đơn hàng từ ERP.
Args:
order_id: Mã đơn hàng (VD: SH-2026-000123)
Returns:
Dict chứa thông tin đơn hàng hoặc lỗi
"""
try:
# Gọi API ERP nội bộ
resp = requests.get(
f"{ERP_BASE_URL}/orders/{order_id}",
headers={"Authorization": f"Bearer {os.getenv('ERP_TOKEN')}"},
timeout=5
)
resp.raise_for_status()
order_data = resp.json()
return {
"status": "success",
"order_id": order_id,
"current_state": order_data.get("state"),
"tracking_number": order_data.get("tracking"),
"total_amount": order_data.get("total"),
"items": order_data.get("items", []),
}
except requests.Timeout:
return {"status": "error", "code": "ERP_TIMEOUT", "message": "ERP không phản hồi sau 5s"}
except requests.HTTPError as e:
return {"status": "error", "code": f"HTTP_{e.response.status_code}", "message": str(e)}
def summarize_with_ai(raw_text: str) -> str:
"""Dùng Claude qua HolySheep để tóm tắt thông tin đơn hàng dài dòng."""
resp = requests.post(
f"{HOLYSHEEP_BASE_URL}/chat/completions",
headers={
"Authorization": f"Bearer {HOLYSHEEP_API_KEY}",
"Content-Type": "application/json"
},
json={
"model": "claude-sonnet-4.5",
"messages": [
{
"role": "system",
"content": "Bạn là trợ lý CSKH. Tóm tắt thông tin đơn hàng thành 2-3 câu tiếng Việt tự nhiên."
},
{
"role": "user",
"content": f"Tóm tắt: {raw_text}"
}
],
"max_tokens": 200,
"temperature": 0.3
},
timeout=10
)
resp.raise_for_status()
return resp.json()["choices"][0]["message"]["content"]
Schema cho Claude Code đăng ký tool
TOOL_SCHEMA = {
"name": "check_order_status",
"description": "Kiểm tra trạng thái đơn hàng theo mã đơn. Trả về trạng thái hiện tại, mã vận đơn, tổng tiền và danh sách sản phẩm.",
"input_schema": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "Mã đơn hàng, ví dụ SH-2026-000123"
}
},
"required": ["order_id"]
}
}
3. Hook Audit Logger và Slash Command
Hook là phần hay nhất của hệ thống - cho phép can thiệp vào pipeline trước/sau khi Claude gọi tool. Tôi dùng nó để ghi log audit tuân thủ GDPR và kiểm tra quyền truy cập:
# hooks/audit_logger.py
"""
Hook ghi log mọi tool call để audit và debug.
Chạy cả pre và post hook.
"""
import os
import json
import time
from datetime import datetime
from pathlib import Path
AUDIT_LOG_PATH = Path(os.getenv("AUDIT_LOG_PATH", "/var/log/claude-audit.log"))
def pre_hook(tool_name: str, arguments: dict) -> dict:
"""
Chạy TRƯỚC khi tool được thực thi.
Có thể block call bằng cách raise PermissionError.
"""
record = {
"timestamp": datetime.utcnow().isoformat() + "Z",
"phase": "pre",
"tool": tool_name,
"arguments": arguments,
"user": os.getenv("CLAUDE_USER", "anonymous"),
}
_write_log(record)
# Ví dụ: chặn refund > 5 triệu cần duyệt thủ công
if tool_name == "refund" and arguments.get("amount", 0) > 5_000_000:
raise PermissionError(
f"Refund {arguments.get('amount')} VND vượt ngưỡng 5 triệu, "
"cần manager duyệt qua dashboard."
)
return {"allowed": True}
def post_hook(tool_name: str, arguments: dict, result: dict, duration_ms: int) -> dict:
"""Chạy SAU khi tool trả về kết quả."""
record = {
"timestamp": datetime.utcnow().isoformat() + "Z",
"phase": "post",
"tool": tool_name,
"arguments": arguments,
"result_status": result.get("status"),
"duration_ms": duration_ms,
}
_write_log(record)
return result
def _write_log(record: dict) -> None:
AUDIT_LOG_PATH.parent.mkdir(parents=True, exist_ok=True)
with AUDIT_LOG_PATH.open("a", encoding="utf-8") as f:
f.write(json.dumps(record, ensure_ascii=False) + "\n")
Slash command giúp nhân viên CSKH trigger workflow phức tạp chỉ bằng một dòng. File commands/escalate.md:
---
name: escalate
description: Chuyển ticket phức tạp cho nhân viên CSKH cấp cao
argument-hint: <order_id> <reason>
---
Workflow: Escalate ticket
Khi người dùng gõ /escalate SH-2026-000123 khách hàng VIP yêu cầu gặp manager, bạn thực hiện:
1. Gọi tool check_order_status với order_id để lấy thông tin.
2. Phân tích lịch sử đơn hàng của khách (GTV > 50 triệu = VIP).
3. Soạn nội dung chuyển tiếp theo template:
- Mã đơn: {order_id}
- Tổng giá trị đơn: {total}
- Lý do escalate: {reason}
- Ghi chú của AI: {phân tích ngắn}
4. Gọi tool notify_slack trong channel #cs-escalation.
5. Phản hồi cho user: "Đã chuyển ticket #SH-2026-000123 lên manager. Bạn sẽ nhận phản hồi trong 30 phút."
Quy tắc bắt buộc
- KHÔNG BAO GIỜ tự ý escalate đơn < 500k VND.
- LUÔN kèm link dashboard: https://erp.internal/orders/{order_id}
4. Tích hợp Multi-Model qua HolySheep AI cho tác vụ phân loại
Đây là phần "vũ khí bí mật" mà tôi dùng để giảm chi phí: tôi không phải lúc nào cũng cần Claude Sonnet 4.5 ($15/MTok) cho mọi request. Với HolySheep AI, tôi route tự động:
# tools/smart_router.py
"""
Router thông minh: chọn model rẻ nhất đủ dùng cho từng task.
Bảng giá tham khảo 2026 (đơn vị $/1M token):
- Claude Sonnet 4.5: $15.00
- GPT-4.1: $8.00
- Gemini 2.5 Flash: $2.50
- DeepSeek V3.2: $0.42
"""
import os
import requests
from typing import Literal
HOLYSHEEP_API_KEY = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY")
HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1"
TaskType = Literal["intent_classify", "summarize", "generate", "complex_reason"]
def smart_complete(task: TaskType, prompt: str, **kwargs) -> str:
"""Route request đến model phù hợp nhất với task."""
model_map = {
"intent_classify": "deepseek-v3.2", # $0.42 - rẻ, đủ dùng
"summarize": "gemini-2.5-flash", # $2.50 - nhanh, summary tốt
"generate": "gpt-4.1", # $8.00 - cân bằng
"complex_reason": "claude-sonnet-4.5", # $15.00 - chỉ dùng khi cần
}
selected_model = model_map[task]
resp = requests.post(
f"{HOLYSHEEP_BASE_URL}/chat/completions",
headers={
"Authorization": f"Bearer {HOLYSHEEP_API_KEY}",
"Content-Type": "application/json"
},
json={
"model": selected_model,
"messages": [{"role": "user", "content": prompt}],
"max_tokens": kwargs.get("max_tokens", 500),
"temperature": kwargs.get("temperature", 0.3),
},
timeout=15
)
resp.raise_for_status()
return resp.json()["choices"][0]["message"]["content"]
Ví dụ sử dụng trong plugin CSKH
if __name__ == "__main__":
# Phân loại ý định khách hàng - dùng DeepSeek (chỉ $0.42/MTok)
intent = smart_complete(
"intent_classify",
'Phân loại ý định: "Đơn SH-2026-000123 của tôi 5 ngày rồi chưa giao?" '
"Trả lời 1 từ: TRACKING / REFUND / COMPLAINT / OTHER"
)
print(f"Intent: {intent}")
# Tính toán policy phức tạp - dùng Claude
policy = smart_complete(
"complex_reason",
"Khách VIP mua đơn 12 triệu, hủy sau 7 ngày, sản phẩm chưa sử dụng. "
"Theo chính sách, có được hoàn 100% không? Trả lời ngắn gọn 3 dòng."
)
print(f"Policy: {policy}")
Trong tháng đầu triển khai, tổng chi phí AI của dự án chỉ là $47.30 cho 2.1 triệu request - trung bình $0.0225 mỗi 1000 request. Nếu dùng giá gốc Anthropic thì sẽ là hơn $300, tức là tiết kiệm hơn 85%. Lý do chính là vì HolySheep áp dụng tỷ giá ¥1=$1 cho người dùng châu Á, thanh toán qua WeChat/Alipay rất tiện.
5. Testing Plugin với Sandbox
Trước khi deploy production, luôn test plugin trong sandbox. Đây là script test mẫu tôi dùng:
# tests/test_plugin.py
"""
Test toàn bộ plugin trong môi trường sandbox.
Chạy: python -m pytest tests/test_plugin.py -v
"""
import pytest
from unittest.mock import patch, MagicMock
import sys
sys.path.insert(0, ".")
from tools.check_order import check_order_status, TOOL_SCHEMA
from hooks.audit_logger import pre_hook, post_hook
class TestCheckOrderTool:
"""Test tool kiểm tra đơn hàng."""
@patch("tools.check_order.requests.get")
def test_check_order_success(self, mock_get):
"""Trường hợp ERP trả về 200 OK."""
mock_get.return_value.json.return_value = {
"state": "shipped",
"tracking": "VN123456789",
"total": 1_250_000,
"items": [{"sku": "AO-001", "qty": 2, "price": 625_000}],
}
mock_get.return_value.raise_for_status = MagicMock()
result = check_order_status("SH-2026-000123")
assert result["status"] == "success"
assert result["current_state"] == "shipped"
assert result["total_amount"] == 1_250_000
assert len(result["items"]) == 1
@patch("tools.check_order.requests.get")
def test_check_order_timeout(self, mock_get):
"""Trường hợp ERP timeout."""
import requests as req
mock_get.side_effect = req.Timeout("Connection timed out")
result = check_order_status("SH-2026-999999")
assert result["status"] == "error"
assert result["code"] == "ERP_TIMEOUT"
def test_tool_schema_valid(self):
"""Schema phải hợp lệ theo JSON Schema draft-07."""
schema = TOOL_SCHEMA
assert schema["name"] == "check_order_status"
assert "order_id" in schema["input_schema"]["required"]
assert schema["input_schema"]["properties"]["order_id"]["type"] == "string"
class TestAuditHook:
"""Test hook ghi log audit."""
def test_pre_hook_blocks_large_refund(self, tmp_path, monkeypatch):
"""Refund > 5 triệu phải bị block."""
monkeypatch.setenv("AUDIT_LOG_PATH", str(tmp_path / "audit.log"))
# Reload module để env có hiệu lực
import importlib
from hooks import audit_logger
importlib.reload(audit_logger)
with pytest.raises(PermissionError, match="vượt ngưỡng 5 triệu"):
audit_logger.pre_hook("refund", {"amount": 6_000_000, "order_id": "SH-001"})
def test_pre_hook_allows_small_refund(self, tmp_path, monkeypatch):
"""Refund < 5 triệu phải được cho phép."""
monkeypatch.setenv("AUDIT_LOG_PATH", str(tmp_path / "audit.log"))
import importlib
from hooks import audit_logger
importlib.reload(audit_logger)
result = audit_logger.pre_hook("refund", {"amount": 500_000})
assert result["allowed"] is True
assert (tmp_path / "audit.log").exists()
6. Deploy Plugin lên Production
Sau khi pass test, đóng gói plugin thành file .cplugin (định dạng tar.gz đơn giản) và publish lên registry nội bộ. Workflow deploy:
# scripts/deploy_plugin.sh
#!/bin/bash
set -euo pipefail
PLUGIN_NAME="ecommerce-cs-plugin"
VERSION="1.0.0"
REGISTRY_URL="https://plugins.internal.holysheep.ai"
echo "Đóng gói plugin ${PLUGIN_NAME} v${VERSION}..."
tar -czf "${PLUGIN_NAME}-${VERSION}.cplugin" \
plugin.json tools/ commands/ hooks/ agents/ skills/
echo "Upload lên registry..."
curl -X POST "${REGISTRY_URL}/v1/plugins" \
-H "Authorization: Bearer ${REGISTRY_TOKEN}" \
-F "file=@${PLUGIN_NAME}-${VERSION}.cplugin" \
-F "version=${VERSION}" \
-F "changelog=Phiên bản đầu tiên - hỗ trợ check_order, refund, escalate"
echo "Verify plugin đã được cài..."
claude-code plugin install "${PLUGIN_NAME}@${VERSION}"
echo "Test nhanh plugin sau cài đặt..."
claude-code plugin test "${PLUGIN_NAME}"
echo "Hoàn tất deploy ${PLUGIN_NAME} v${VERSION}!"
Một lưu ý quan trọng về vận hành: latency tổng thể của tôi đo được là ~120ms trung bình cho mỗi request CSKH, trong đó Claude Sonnet 4.5 mất ~80ms và phần ERP call nội bộ mất ~35ms. HolySheep AI báo latency gateway là dưới 50ms - cực kỳ ổn định. So với Anthropic API trực tiếp (thường dao động 200-400ms từ Việt Nam), HolySheep nhanh hơn rõ rệt nhờ edge nodes ở Singapore và Tokyo.
Lỗi thường gặp và cách khắc phục
Lỗi 1: Plugin không load được - "Module not found" khi Claude Code gọi tool
Triệu chứng: Log hiển thị ModuleNotFoundError: No module named 'tools.check_order' mặc dù file tồn tại.
Nguyên nhân: Claude Code chạy tool trong một subprocess với sys.path khác. Khi bạn test local bằng python tools/check_order.py thì chạy được, nhưng khi Claude gọi thì không thấy module.
Cách khắc phục: Thêm file __init__.py rỗng vào mỗi thư mục và đảm bảo plugin được cài dưới dạng package:
# tools/__init__.py - để trống
hooks/__init__.py - để trống
tests/__init__.py - để trống
Trong plugin.json, sửa entry_point thành dotted path tuyệt đối:
{
"entry_point": "ecommerce_cs_plugin.tools.router:main"
}
Thay vì relative path
Lỗi 2: Hook bị chạy 2 lần hoặc không chạy
Triệu chứng: Log audit ghi 2 entry cho cùng 1 tool call, hoặc ngược lại hoàn toàn không có log nào khi chạy production.
Nguyên nhân: Hai vấn đề thường gặp - (1) bạn đăng ký hook trong cả plugin.json lẫn file config global, gây duplicate; (2) đường dẫn trong hook config sai case-sensitive trên Linux.
Cách khắc phục:
# ĐÚNG: dùng đường dẫn tuyệt đối với function name
"hooks": {
"pre_tool_call": "/opt/plugins/ecommerce-cs/hooks/audit_logger.py:pre_hook",
"post_tool_call": "/opt/plugins/ecommerce-cs/hooks/audit_logger.py:post_hook"
}
SAI: đường dẫn tương đối
"hooks": {
"pre_tool_call": "hooks/audit_logger.py:pre_hook" # ❌
}
Thêm flag debug để xem hook nào đang chạy
import os
DEBUG = os.getenv("CLAUDE_HOOK_DEBUG", "0") == "1"
def pre_hook(tool_name, arguments):
if DEBUG:
print(f"[HOOK] pre_hook called for {tool_name}")
# ... logic chính
Lỗi 3: Slash command không nhận argument đúng cách
Triệu chứng: Gõ /escalate SH-2026-000123 khách VIP nhưng Claude chỉ thấy phần đầu, hoặc argument bị escape sai.
Nguyên nhân: Bạn quên khai báo argument-hint trong front-matter, hoặc dùng dấu nháy đơn trong nội dung command.
Cách khắc phục:
---
name: escalate
description: Chuyển ticket phức tạp cho nhân viên CSKH
argument-hint: <order_id> <reason> # <-- BẮT BUỘC có dòng này
---
Workflow: Escalate ticket
Claude Code sẽ tự inject $ARGUMENTS và $1, $2 vào context.
Bạn có thể tham chiếu trực tiếp:
#