- 3
- เมษายน
OpenClaw Deep Dive Series EP.3 — จาก EP.2 ที่เราเจาะลึก Skills และสร้าง Custom Skill กันไปแล้ว ตอนนี้ถึงเวลาลงลึกไปที่ "Kernel Module" — แกนกลางของ OpenClaw ที่ควบคุมทุกอย่างตั้งแต่ข้อความเข้า-ออก ไปจนถึง Tool Execution ถ้าคุณเคยอ่าน บทความ Kernel Module ภาคทฤษฎี มาแล้ว EP.3 นี้จะพาคุณ ลงมือเขียน Module จริง ตั้งแต่บรรทัดแรกจนใช้งานได้!
สรุปสั้น — สิ่งที่จะได้เรียนรู้ในบทความนี้:
- Kernel Module คืออะไร — ส่วนประกอบที่อยู่ระหว่าง AI Brain (LLM) กับโลกภายนอก
- Module Lifecycle — วงจรชีวิต init → register → process → cleanup
- API Hooks 5 ตัว — onMessage, onToolCall, onToolResult, onResponse, onError
- เขียน Module แรก — Audit Logger ที่ log ทุก message เข้า-ออก
- Real-world Module — Content Filter และ Rate Limiter ตัวอย่างจริง
- Testing & Debugging — วิธีทดสอบ Module ก่อน Deploy
Kernel Module vs Skills — ต่างกันอย่างไร?
ก่อนเริ่มเขียน Module ต้องเข้าใจความแตกต่างระหว่าง Skills กับ Kernel Module ให้ชัดเจนก่อน เพราะทั้งสองทำงานคนละระดับ — ถ้า Skill เหมือนพนักงาน ที่ทำงานเฉพาะทาง Kernel Module ก็เหมือน ผู้จัดการ ที่ดูแลระบบทั้งหมด
| เปรียบเทียบ | Skills | Kernel Module |
|---|---|---|
| ขอบเขตการทำงาน | ทำงานเฉพาะทาง trigger-based (เช่น "เช็คสต็อก") | ควบคุมระบบทั้งหมด intercept ทุก message |
| เมื่อไหร่ทำงาน | เฉพาะเมื่อ Trigger match | ทุก message ที่ผ่านระบบ |
| สิทธิ์การเข้าถึง | เข้าถึงแค่ข้อมูลที่ส่งมาให้ | เข้าถึงทุก message ทุก tool call ทุก response |
| Use Case หลัก | เพิ่มความสามารถเฉพาะทาง (ดึงข้อมูล, สั่งงาน) | Audit logging, content filtering, rate limiting, permission control |
| เปรียบเทียบ | พนักงานที่ทำงานตามคำสั่ง | ผู้จัดการที่ดูแลระบบทั้งหมด |
Kernel Module อยู่ระหว่าง AI Brain (LLM) กับโลกภายนอก ทำหน้าที่ intercept และ modify ข้อมูลทุกอย่างที่ผ่านเข้า-ออก — ทั้ง input processing, output formatting, tool execution, permission control และ logging
Module Lifecycle — วงจรชีวิต Module
Kernel Module ทำงานตามวงจรชีวิต 4 ขั้นตอน ตั้งแต่เริ่มต้นจนปิดตัว:
init() → registerHooks() → [Message Loop: onMessage → onToolCall → onToolResult → onResponse] → cleanup()
| | | |
เริ่มต้น ลงทะเบียน ประมวลผลทุก Message ปิดตัว
Module Hook ที่ต้องการ วนซ้ำจนกว่า Agent จะหยุด ทำความสะอาด
| Phase | ฟังก์ชัน | หน้าที่ | ตัวอย่าง |
|---|---|---|---|
| 1. Initialize | init(config) |
โหลด config, เชื่อมต่อ database, เตรียมทรัพยากร | เปิดไฟล์ log, เชื่อม Redis |
| 2. Register | registerHooks() |
ลงทะเบียน Hook ที่ต้องการ (onMessage, onResponse ฯลฯ) | บอกระบบว่า "ฉันจะ intercept ทุก message" |
| 3. Process | onMessage() ฯลฯ |
ประมวลผลทุก message ที่ผ่านเข้ามา — วนซ้ำไปเรื่อยๆ | log ทุกข้อความ, กรอง sensitive data |
| 4. Cleanup | cleanup() |
ปิดการเชื่อมต่อ บันทึกข้อมูลสุดท้าย ทำความสะอาด | ปิดไฟล์ log, disconnect Redis |
API Hooks — 5 จุดเชื่อมต่อสำคัญ
หัวใจของ Kernel Module คือ API Hooks — จุดที่คุณสามารถ "แทรก" โค้ดเข้าไปในกระบวนการทำงานของ OpenClaw ได้ มีทั้งหมด 5 Hooks:
| Hook | เมื่อไหร่ทำงาน | ข้อมูลที่ได้รับ | ทำอะไรได้ |
|---|---|---|---|
| onMessage | ก่อนส่ง message ให้ LLM | ข้อความจากผู้ใช้, user ID, timestamp | แก้ไข/กรอง message, log, block request |
| onToolCall | ก่อนเรียก Tool (Skill) | ชื่อ Tool, parameters, context | อนุญาต/ปฏิเสธ, แก้ไข parameters, log |
| onToolResult | หลัง Tool ทำงานเสร็จ | ผลลัพธ์จาก Tool, execution time, status | แก้ไข/กรองผลลัพธ์, log, alert ถ้าผิดปกติ |
| onResponse | ก่อนส่ง response กลับผู้ใช้ | คำตอบจาก LLM, tokens used, model info | แก้ไข response, เพิ่ม disclaimer, log |
| onError | เมื่อเกิด Error ในระบบ | error type, message, stack trace | log error, ส่ง alert, fallback response |
แต่ละ Hook สามารถ แก้ไขข้อมูล ก่อนส่งต่อ หรือ block ไม่ให้ดำเนินการต่อได้ นี่คือพลังที่ทำให้ Kernel Module ควบคุมทุกอย่างที่ AI Agent ทำ
เขียน Kernel Module แรก — Audit Logger
มาลองสร้าง Module ที่ log ทุก message เข้า-ออก เป็น Audit Trail — Module นี้จะบันทึกว่าใครส่งอะไร เมื่อไหร่ AI ตอบอะไร เหมาะสำหรับองค์กรที่ต้องการ บริหารความเสี่ยง และ compliance
Step 1: สร้างโฟลเดอร์ Module
# สร้างโครงสร้างโฟลเดอร์
mkdir -p modules/audit-logger
# โครงสร้างไฟล์
modules/audit-logger/
├── manifest.json # metadata ของ Module
├── index.js # โค้ดหลัก (hooks)
└── logs/ # โฟลเดอร์เก็บ log files
Step 2: เขียน manifest.json
{
"name": "audit-logger",
"version": "1.0.0",
"description": "Log ทุก message เข้า-ออก เพื่อเป็น Audit Trail",
"author": "Your Organization",
"hooks": ["onMessage", "onResponse", "onError"],
"config": {
"logDir": "./modules/audit-logger/logs",
"logFormat": "json",
"maxFileSize": "10MB",
"retentionDays": 90
}
}
Step 3: เขียน index.js — Hook Logic
// modules/audit-logger/index.js
const fs = require('fs');
const path = require('path');
let logStream;
module.exports = {
// Phase 1: Initialize
async init(config) {
const logDir = config.logDir || './logs';
if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true });
const logFile = path.join(logDir, `audit-${new Date().toISOString().slice(0,10)}.jsonl`);
logStream = fs.createWriteStream(logFile, { flags: 'a' });
console.log(`[AuditLogger] Initialized. Logging to ${logFile}`);
},
// Phase 2: Register Hooks
registerHooks() {
return ['onMessage', 'onResponse', 'onError'];
},
// Hook: ก่อนส่ง LLM — log ข้อความจากผู้ใช้
async onMessage(data) {
const entry = {
timestamp: new Date().toISOString(),
type: 'user_message',
userId: data.userId,
message: data.message,
sessionId: data.sessionId
};
logStream.write(JSON.stringify(entry) + '\n');
// ส่ง message ต่อโดยไม่แก้ไข
return data;
},
// Hook: ก่อนส่งกลับผู้ใช้ — log คำตอบจาก AI
async onResponse(data) {
const entry = {
timestamp: new Date().toISOString(),
type: 'ai_response',
userId: data.userId,
response: data.response.substring(0, 500),
tokensUsed: data.tokensUsed,
model: data.model
};
logStream.write(JSON.stringify(entry) + '\n');
return data;
},
// Hook: เมื่อเกิด Error
async onError(error) {
const entry = {
timestamp: new Date().toISOString(),
type: 'error',
errorType: error.type,
message: error.message,
stack: error.stack
};
logStream.write(JSON.stringify(entry) + '\n');
},
// Phase 4: Cleanup
async cleanup() {
if (logStream) logStream.end();
console.log('[AuditLogger] Cleanup complete.');
}
};
Step 4: Register Module ใน Config
# config/modules.yaml — ลงทะเบียน Kernel Module
modules:
- path: "modules/audit-logger"
enabled: true
config:
logDir: "./logs/audit"
retentionDays: 90
# เพิ่ม Module อื่นได้ตามต้องการ
# - path: "modules/content-filter"
# enabled: true
Step 5: ทดสอบ Module
# รัน Agent พร้อม Module
npm start -- --agent agents/my-agent.yaml
# ส่งข้อความทดสอบ
> สวัสดี วันนี้มีรายงานอะไรบ้าง?
# ตรวจสอบ log file
cat logs/audit/audit-2026-04-03.jsonl
# ผลลัพธ์:
{"timestamp":"2026-04-03T09:15:30.123Z","type":"user_message","userId":"user-001","message":"สวัสดี วันนี้มีรายงานอะไรบ้าง?","sessionId":"sess-abc"}
{"timestamp":"2026-04-03T09:15:32.456Z","type":"ai_response","userId":"user-001","response":"สวัสดีครับ! วันนี้มีรายงาน...","tokensUsed":245,"model":"gpt-4"}
เพียง 5 ขั้นตอนก็ได้ Audit Logger Module ที่ใช้งานได้จริง! ทุกข้อความที่ผ่านระบบจะถูกบันทึกเป็น JSON Lines — ค้นหาง่าย วิเคราะห์ได้ด้วยเครื่องมือมาตรฐาน
ตัวอย่างจริง — Content Filter Module
Module ที่ กรอง sensitive data ก่อนส่งให้ LLM — ป้องกันไม่ให้เลขบัตรประชาชน เลขบัญชีธนาคาร หรือรหัสผ่าน หลุดไปถึง AI ภายนอก เหมาะสำหรับองค์กรที่ต้องการ ความปลอดภัยระดับสูง
// modules/content-filter/index.js
const SENSITIVE_PATTERNS = [
{ name: 'Thai ID Card', regex: /\b\d{1}-\d{4}-\d{5}-\d{2}-\d{1}\b/g, mask: '[REDACTED-ID]' },
{ name: 'Bank Account', regex: /\b\d{3}-\d{1}-\d{5}-\d{1}\b/g, mask: '[REDACTED-BANK]' },
{ name: 'Credit Card', regex: /\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g, mask: '[REDACTED-CC]' },
{ name: 'Email Password', regex: /(?:password|รหัสผ่าน|pwd)[\s:=]+\S+/gi, mask: '[REDACTED-PWD]' },
{ name: 'Phone Number', regex: /\b0[689]\d{1}-\d{3}-\d{4}\b/g, mask: '[REDACTED-PHONE]' }
];
module.exports = {
registerHooks() { return ['onMessage']; },
async onMessage(data) {
let filtered = data.message;
let redactedCount = 0;
for (const pattern of SENSITIVE_PATTERNS) {
const matches = filtered.match(pattern.regex);
if (matches) {
redactedCount += matches.length;
filtered = filtered.replace(pattern.regex, pattern.mask);
}
}
if (redactedCount > 0) {
console.log(`[ContentFilter] Redacted ${redactedCount} sensitive items`);
}
return { ...data, message: filtered };
}
};
Module นี้ทำงานที่ onMessage Hook — ก่อนที่ข้อความจะถูกส่งไปยัง LLM ข้อมูลที่ตรงกับ pattern จะถูก mask ทันที ทำให้ AI ไม่เห็นข้อมูลจริง
ตัวอย่างจริง — Rate Limiter Module
Module ที่ จำกัด request ต่อ user ต่อนาที — ป้องกัน API abuse และควบคุมค่าใช้จ่าย LLM เหมาะกับระบบที่มีผู้ใช้หลายคน
// modules/rate-limiter/index.js
const userCounters = new Map();
module.exports = {
async init(config) {
this.maxRequests = config.max_requests_per_minute || 10;
this.cooldownMsg = config.cooldown_message || 'คุณส่งข้อความเร็วเกินไป กรุณารอสักครู่';
// รีเซ็ตตัวนับทุกนาที
setInterval(() => userCounters.clear(), 60 * 1000);
},
registerHooks() { return ['onMessage']; },
async onMessage(data) {
const userId = data.userId;
const count = (userCounters.get(userId) || 0) + 1;
userCounters.set(userId, count);
if (count > this.maxRequests) {
console.log(`[RateLimiter] User ${userId} exceeded limit (${count}/${this.maxRequests})`);
// Block request — ส่ง response กลับทันทีโดยไม่ผ่าน LLM
return { ...data, blocked: true, blockReason: this.cooldownMsg };
}
return data;
}
};
| Config Option | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|
max_requests_per_minute |
10 | จำนวน request สูงสุดต่อ user ต่อนาที |
cooldown_message |
"คุณส่งข้อความเร็วเกินไป..." | ข้อความที่แสดงเมื่อเกิน limit |
Module State — เก็บข้อมูลถาวร
Kernel Module มี State ที่ persist ระหว่าง restart ได้ — ทำให้ Module จดจำข้อมูลข้ามเซสชัน เช่น usage statistics, user preferences หรือ conversation history
// ตัวอย่าง: Module ที่เก็บสถิติการใช้งาน
module.exports = {
async init(config) {
// โหลด state จากไฟล์ (persist ข้าม restart)
this.state = await this.getState() || {
totalMessages: 0,
totalTokens: 0,
userStats: {},
startDate: new Date().toISOString()
};
},
async onMessage(data) {
this.state.totalMessages++;
this.state.userStats[data.userId] = (this.state.userStats[data.userId] || 0) + 1;
await this.setState(this.state); // บันทึกทันที
return data;
},
async onResponse(data) {
this.state.totalTokens += data.tokensUsed || 0;
await this.setState(this.state);
return data;
},
// เรียก state ได้จาก Skill หรือ Module อื่น
getUsageReport() {
return {
totalMessages: this.state.totalMessages,
totalTokens: this.state.totalTokens,
topUsers: Object.entries(this.state.userStats)
.sort((a, b) => b[1] - a[1])
.slice(0, 10)
};
}
};
getState() และ setState() เป็น API ของ OpenClaw ที่บันทึกข้อมูลลง disk อัตโนมัติ — ไม่ต้องจัดการ file I/O เอง Module จะจดจำข้อมูลแม้ Agent restart
ข้อควรระวังในการเขียน Kernel Module:
- Module มีสิทธิ์เข้าถึงทุก message — ต้องเขียนอย่างระมัดระวัง ห้ามเปิดเผยข้อมูลผู้ใช้โดยไม่จำเป็น
- อย่า block ใน Hook นานเกินไป — ถ้า Hook ใช้เวลาเกิน timeout ระบบจะข้ามไป อาจทำให้ Module ทำงานไม่ครบ
- Test Module แยกก่อน Deploy — อย่า Deploy Module ที่ยังไม่ได้ทดสอบไปใช้งานจริง เพราะ Module ที่ error อาจทำให้ Agent ทั้งตัวหยุดทำงาน
- เปิดใช้ 2FA — สำหรับ Module ที่เข้าถึงข้อมูลสำคัญ ควรมีการยืนยันตัวตนเพิ่มเติมก่อน Deploy
Saeree ERP + Kernel Module:
ด้วย Kernel Module องค์กรสามารถสร้าง audit trail ที่ครบถ้วน, content filter ที่ป้องกันข้อมูลรั่วไหล, compliance check อัตโนมัติ — Saeree ERP กำลังพัฒนา AI Assistant ที่จะใช้ Kernel Module เหล่านี้เป็นชั้นความปลอดภัยของระบบ สนใจระบบ ERP ที่พร้อมรองรับ AI ในอนาคต ปรึกษาทีมงานฟรี ไม่มีค่าใช้จ่าย
OpenClaw Deep Dive Series — อ่านต่อ
OpenClaw Deep Dive Series — 6 ตอนเจาะลึก AI Agent:
- EP.1: ติดตั้ง OpenClaw และสร้าง AI Agent ตัวแรก
- EP.2: เจาะลึก OpenClaw Skills — สร้าง Custom Skill ตั้งแต่ศูนย์
- EP.3: OpenClaw Kernel Module ภาคปฏิบัติ — เขียน Module เองทีละขั้น (บทความนี้)
- EP.4: สร้าง Multi-Agent Workflow ด้วย OpenClaw
- EP.5: Deploy OpenClaw สู่ Production — Security, Monitoring, Scaling
- EP.6: เชื่อม OpenClaw กับ ERP — สร้าง AI Assistant สำหรับองค์กร
"Kernel Module คือพลังที่ซ่อนอยู่ของ OpenClaw — ทำให้คุณควบคุมทุกอย่างที่ AI Agent ทำ ตั้งแต่ข้อความแรกจนถึงคำตอบสุดท้าย"
- ทีมงาน Saeree ERP




