จัดให้ตามคำขอเลยค่ะคุณจี หลินเตรียมเนื้อหาบทความเชิงลึก (Deep-dive Technical Article) ที่จะเปลี่ยนมุมมองการใช้ AI บนเครื่องส่วนตัวของคุณให้กลายเป็นระบบปฏิบัติการอัจฉริยะมาให้แล้วค่ะ บทความนี้จะเน้นทั้งทฤษฎี สถาปัตยกรรม และการนำไปใช้งานจริงแบบ Step-by-step นะคะ
---
ในยุคที่เราคุ้นเคยกับการพิมพ์โต้ตอบกับ ChatGPT หรือ Claude เพื่อหาคำตอบหรือช่วยเขียน Code เรากำลังยืนอยู่บนจุดเปลี่ยนสำคัญของเทคโนโลยี AI จากยุค "Chatbot" (ผู้สนทนา) ไปสู่ยุค "Agent" (ผู้ลงมือทำ) ความแตกต่างไม่ได้อยู่ที่ความฉลาดของโมเดลเพียงอย่างเดียว แต่อยู่ที่ความสามารถในการ "สั่งการ" (Action) สิ่งแวดล้อมรอบตัวมันได้
ปัญหาใหญ่ของการใช้ Cloud-based AI คือเรื่องความเป็นส่วนตัว (Privacy) และข้อจำกัดในการเข้าถึงไฟล์หรือระบบภายในเครื่อง (Local Access) แต่ด้วยการผสานพลังของ Ollama และ LiteLLM เราสามารถสร้าง "Local Agentic Workflow" ที่ทำงานได้แบบ Zero-Cloud—นั่นคือการมี AI ที่ฉลาดพอจะรัน Terminal, จัดการไฟล์, หรือเรียกใช้ API ต่างๆ ได้โดยที่ข้อมูลไม่หลุดออกจากเครื่องของคุณแม้แต่บิตเดียว
The Shift from Chat to Action: ทำไม Function Calling ถึงเป็นหัวใจสำคัญของ Local Agentic Workflow
การคุยกับ AI แบบเดิมคือกระบวนการ Text-in $\rightarrow$ Text-out ซึ่งจำกัดอยู่แค่การให้ข้อมูลหรือการสร้างเนื้อหา แต่ Agentic Workflow ต้องการกระบวนการ Text-in $\rightarrow$ Reasoning $\rightarrow$ Action $\rightarrow$ Observation
หัวใจที่เป็นสะพานเชื่อมระหว่าง "ความคิด" ของ AI กับ "การกระทำ" ของคอมพิวเตอร์คือ Function Calling (หรือ Tool Calling) แทนที่ AI จะตอบกลับมาเป็นประโยคยาวๆ ว่า *"ฉันจะช่วยคุณลบไฟล์ในโฟลเดอร์นี้ให้ค่ะ"* มันจะเปลี่ยนเป็นการส่งโครงสร้างข้อมูล (Structured Data) เช่น JSON ออกมาแทนว่า:
{
"function": "delete_file",
"parameters": {
"path": "/users/gee/downloads/temp_data.txt"
}
}
เมื่อคอมพิวเตอร์ได้รับ JSON นี้ แทนที่จะแสดงผลให้ผู้ใช้เห็น ระบบจะส่งมันเข้าสู่ฟังก์ชัน Python ที่เราเตรียมไว้เพื่อลบไฟล์จริงๆ นี่คือจุดที่ AI เปลี่ยนจาก "นักพูด" กลายเป็น "คนทำงาน" และเมื่อทำในระดับ Local ความเร็ว (Latency) จะต่ำมาก และความปลอดภัยของข้อมูลจะอยู่ในระดับสูงสุด เพราะไม่มีการส่ง Schema หรือ Parameter ของระบบคุณขึ้นไปยัง Server ของบริษัทใดๆ
The Architecture: เจาะลึกการทำงานระหว่าง Ollama (Inference Engine) และ LiteLLM (The Unified Interface)
เพื่อให้ระบบนี้ทำงานได้อย่างราบรื่น เราจำเป็นต้องมีสถาปัตยกรรมแบบ Layered Architecture ที่แบ่งแยกหน้าที่กันอย่างชัดเจน ดังนี้:
1. Inference Engine (Ollama):
Ollama ทำหน้าที่เป็นหัวใจหลักในการรัน Large Language Models (LLMs) ภายในเครื่องของคุณ โดยใช้เทคโนโลยีอย่าง llama.cpp เพื่อทำ Quantization (ลดขนาดโมเดล) ทำให้เราสามารถรันโมเดลระดับสูงอย่าง Llama 3.1 หรือ Mistral ได้บน Hardware ทั่วไป Ollama จะจัดการเรื่องการโหลด Weights, การบริหารจัดการ VRAM และการทำ Tokenization
2. Unified API Gateway (LiteLLM):
นี่คือส่วนสำคัญที่หลายคนมองข้าม แม้ Ollama จะมี API ของตัวเอง แต่มาตรฐานของโลก Agent (เช่น LangChain หรือ CrewAI) มักจะยึดตามรูปแบบของ OpenAI การใช้ LiteLLM จะทำหน้าที่เป็น "ล่าม" (Proxy) ที่คอยรับคำสั่งจาก Agent Framework แล้วแปลงให้เป็น Format ที่ Ollama เข้าใจ และในทางกลับกัน มันจะช่วยจัดการเรื่องการทำ Error Handling, Retries และการทำ Model Fallback หากโมเดลตัวหนึ่งตอบสนองไม่ดีพอ
Workflow Diagram:
User Prompt $\rightarrow$ Agent Logic (Python) $\rightarrow$ LiteLLM (Proxy) $\rightarrow$ Ollama (Inference) $\rightarrow$ Model Output (JSON) $\rightarrow$ LiteLLM $\rightarrow$ Agent Logic (Execute Tool) $\rightarrow$ Result back to User
Under the Hood: กลไกแปลง Natural Language เป็น Structured Data เพื่อการสั่งการ System Commands
กระบวนการที่ AI เปลี่ยนภาษาคนเป็นคำสั่งคอมพิวเตอร์ไม่ใช่เรื่องเวทมนตร์ แต่เป็นเรื่องของ Schema Enforcement
เมื่อเราต้องการให้ Agent สามารถรันคำสั่ง Terminal ได้ เราต้องส่ง "คำอธิบายเครื่องมือ" (Tool Definition) ไปพร้อมกับ Prompt โดยใช้รูปแบบ JSON Schema ตัวอย่างเช่น:
tools = [
{
"type": "function",
"function": {
"name": "execute_terminal_command",
"description": "รันคำสั่ง shell ในเครื่องเพื่อจัดการไฟล์หรือระบบ",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "คำสั่ง shell เช่น 'ls -la' หรือ 'mkdir test_dir'"
}
},
"required": ["command"]
}
}
}
]
โมเดลที่ถูก Train มาเพื่อ Function Calling (เช่น Llama 3.1) จะไม่ได้มองว่านี่คือข้อความธรรมดา แต่มันจะมองว่านี่คือ "ข้อจำกัดของพฤติกรรม" เมื่อคุณสั่งว่า *"ช่วยดูหน่อยว่าในโฟลเดอร์นี้มีไฟล์อะไรบ้าง"* โมเดลจะทำการ Matching ความต้องการของคุณเข้ากับ description ของเครื่องมือ และสกัดเอาคำว่า ls ออกมาเป็น Parameter ในรูปแบบ JSON ทันที
Hands-on Implementation: การสร้าง Python-based Agent ที่สามารถรัน Terminal และจัดการ Workflow ในเครื่องได้จริง
มาลองสร้าง Agent ตัวเล็กๆ ที่สามารถรันคำสั่งในเครื่องคุณได้ผ่านการใช้ litellm และ ollama กันค่ะ
1. การเตรียม Environment
ก่อนอื่นคุณจีต้องติดตั้งเครื่องมือที่จำเป็นผ่าน Terminal นะคะ:
# ติดตั้ง Ollama (ดาวน์โหลดจาก ollama.com)
# รันโมเดล Llama 3.1 ที่รองรับ Function Calling ได้ดี
ollama run llama3.1
# ติดตั้ง Python Libraries
pip install litellm
2. การเขียน Python Agent Code
นี่คือตัวอย่าง Code ที่สมบูรณ์สำหรับการสร้าง Agent ที่สามารถรันคำสั่ง Shell ได้ค่ะ:
import litellm
import subprocess
import json
# 1. นิยามฟังก์ชันที่จะให้ Agent เรียกใช้ (The Tool)
def execute_terminal_command(command: str):
try:
print(f"--- [System] กำลังรันคำสั่ง: {command} ---")
result = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT, text=True)
return {"status": "success", "output": result}
except subprocess.CalledProcessError as e:
return {"status": "error", "output": e.output}
# 2. กำหนด Tool Schema สำหรับ LiteLLM
tools = [{
"type": "function",
"function": {
"name": "execute_terminal_command",
"description": "Execute a shell command on the local system",
"parameters": {
"type": "object",
"properties": {
"command": {"type": "string", "description": "The shell command to run"}
},
"required": ["command"]
}
}
}]
def run_agent(user_prompt):
messages = [{"role": "user", "content": user_prompt}]
# Step 1: ส่ง Prompt ไปยัง LiteLLM (ที่ต่อกับ Ollama)
response = litellm.completion(
model="ollama/llama3.1",
messages=messages,
tools=tools,
api_base="http://localhost:11434" # Default Ollama Port
)
response_message = response.choices[0].message
tool_calls = response_message.get("tool_calls")
# Step 2: ตรวจสอบว่าโมเดลต้องการเรียกใช้ Tool หรือไม่
if tool_calls:
for tool_call in tool_calls:
function_name = tool_call.function.name
function_args = json.loads(tool_call.function.arguments)
if function_name == "execute_terminal_command":
# รันฟังก์ชันจริงในเครื่อง
observation = execute_terminal_command(function_args.get("command"))
# Step 3: ส่งผลลัพธ์กลับไปให้ AI เพื่อสรุปคำตอบ
messages.append(response_message)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"name": function_name,
"content": json.dumps(observation)
})
final_response = litellm.completion(
model="ollama/llama3.1",
messages=messages,
api_base="http://localhost:11434"
)
return final_response.choices[0].message.content
return response_message.content
# ทดสอบใช้งาน
if __name__ == "__main__":
print("Agent: สวัสดีค่ะคุณจี มีอะไรให้ช่วยสั่งการเครื่องไหมคะ