0Pricing
AI Engineering Academy · บทเรียน

การรักษาความปลอดภัยการเข้าถึงเครื่องมือของเอเจนต์

ใช้หลักสิทธิ์เท่าที่จำเป็นกับสิทธิ์เครื่องมือของเอเจนต์ เพิ่มขั้นตอนยืนยันก่อนดำเนินการที่ทำลายข้อมูล และตรวจสอบบันทึกการกระทำของเอเจนต์เพื่อค้นหาพฤติกรรมผิดปกติ

การรักษาความปลอดภัยการเข้าถึงเครื่องมือของเอเจนต์ เป็นบทเรียน AI Engineering Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Engineering Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน

ปัญหาด้านความปลอดภัยของการเข้าถึงเครื่องมือ

เมื่อคุณมอบเครื่องมือให้เอเจนต์ AI คุณกำลังมอบความสามารถในการดำเนินการกับโลกจริงด้วย เครื่องมือที่ส่งอีเมล เรียกใช้คำสั่ง SQL เรียก API การชำระเงิน หรือแก้ไขไฟล์ อาจก่อให้เกิดความเสียหายอย่างมากหากเอเจนต์ถูกโจมตีด้วยการฉีดคำสั่งในพรอมป์ หรือเพียงแค่ทำงานผิดพลาด การรักษาความปลอดภัยการเข้าถึงเครื่องมือของเอเจนต์ หมายถึงการออกแบบชั้นเครื่องมือให้ความเสียหายจากการใช้เครื่องมือแต่ละครั้งถูกจำกัด ตรวจสอบย้อนหลังได้ และย้อนกลับได้เมื่อเป็นไปได้

หลักการให้สิทธิ์เท่าที่จำเป็น

ใช้ หลักการให้สิทธิ์เท่าที่จำเป็น กับทุกเครื่องมือ โดยให้เอเจนต์เข้าถึงเพียงเท่าที่จำเป็นต่อการทำงานที่ได้รับมอบหมายให้เสร็จ และไม่มากไปกว่านั้น หากเอเจนต์ต้องอ่านข้อมูลลูกค้า ให้ใช้การเชื่อมต่อฐานข้อมูลแบบอ่านอย่างเดียว ไม่ใช่การเชื่อมต่อระดับผู้ดูแลระบบเต็มรูปแบบที่คุณใช้สำหรับการบำรุงรักษา หากเอเจนต์ส่งการแจ้งเตือน ให้จำกัดขอบเขตคีย์ API ไว้เฉพาะปลายทางการแจ้งเตือนเท่านั้น การให้สิทธิ์เท่าที่จำเป็นช่วยจำกัดขอบเขตความเสียหายจากเหตุการณ์ด้านความปลอดภัยใด ๆ

from enum import Enum
from dataclasses import dataclass

class Permission(Enum):
    READ_CUSTOMER_PROFILE = 'read_customer_profile'
    SEND_NOTIFICATION = 'send_notification'
    READ_ORDER_HISTORY = 'read_order_history'
    WRITE_CUSTOMER_PROFILE = 'write_customer_profile'  # higher privilege
    PROCESS_REFUND = 'process_refund'                  # highest risk

@dataclass
class AgentIdentity:
    agent_id: str
    allowed_permissions: set[Permission]

# Support chat agent: read-only + send notification only
SUPPORT_AGENT = AgentIdentity(
    agent_id='support-agent-v1',
    allowed_permissions={
        Permission.READ_CUSTOMER_PROFILE,
        Permission.READ_ORDER_HISTORY,
        Permission.SEND_NOTIFICATION  # can notify, but NOT write or refund
    }
)

# NOT: give every agent all permissions for convenience

การเรียกใช้เครื่องมือโดยมีสิทธิ์ควบคุม

บังคับใช้หลักการให้สิทธิ์เท่าที่จำเป็นในชั้นการเรียกใช้ ไม่ใช่เฉพาะในชั้นการออกแบบเท่านั้น การเรียกใช้เครื่องมือทุกครั้งต้องผ่าน การตรวจสอบสิทธิ์ เพื่อยืนยันว่าเอเจนต์ผู้เรียกมีสิทธิ์ที่จำเป็นสำหรับการดำเนินการนั้นโดยเฉพาะ การตรวจสอบนี้ไม่สามารถถูกหลีกเลี่ยงโดยเอเจนต์หรือการฉีดคำสั่งในพรอมป์ได้ เพราะบังคับใช้ในโค้ด ไม่ใช่ในพรอมป์ของ LLM

class ToolGateway:
    def __init__(self, agent: AgentIdentity):
        self.agent = agent
        self.audit_log = []

    def execute_tool(self, tool_name: str, required_permission: Permission, tool_fn, **kwargs) -> dict:
        # Permission check - enforced in code, not in the LLM prompt
        if required_permission not in self.agent.allowed_permissions:
            self.log_denied(tool_name, required_permission, kwargs)
            raise PermissionError(
                f'Agent {self.agent.agent_id} does not have permission: {required_permission.value}'
            )
        
        # Execute tool
        result = tool_fn(**kwargs)
        self.log_allowed(tool_name, kwargs, result)
        return result

    def log_denied(self, tool: str, permission: Permission, args: dict):
        entry = {'type': 'DENIED', 'agent': self.agent.agent_id, 'tool': tool, 'permission': permission.value, 'args': args}
        self.audit_log.append(entry)
        print(f'SECURITY: Permission denied - {entry}')

    def log_allowed(self, tool: str, args: dict, result):
        entry = {'type': 'ALLOWED', 'agent': self.agent.agent_id, 'tool': tool, 'args': args}
        self.audit_log.append(entry)

gateway = ToolGateway(SUPPORT_AGENT)

# This will succeed (agent has READ permission)
gateway.execute_tool('read_profile', Permission.READ_CUSTOMER_PROFILE, read_customer_profile, user_id='123')

# This will raise PermissionError (agent lacks PROCESS_REFUND permission)
gateway.execute_tool('process_refund', Permission.PROCESS_REFUND, process_refund, order_id='456', amount=50.00)

ขั้นตอนยืนยันสำหรับการดำเนินการที่ทำลายข้อมูล

การดำเนินการบางอย่างไม่สามารถย้อนกลับได้หรือมีผลกระทบสูง เช่น การลบระเบียน การส่งอีเมลจำนวนมาก และการประมวลผลธุรกรรมทางการเงิน ให้กำหนดให้มี การยืนยันจากมนุษย์อย่างชัดเจน ก่อนที่เอเจนต์จะดำเนินการดังกล่าว เอเจนต์จะเสนอการดำเนินการนั้น โดยระบุว่าต้องการทำอะไรและเพราะเหตุใด จากนั้นมนุษย์จะอนุมัติหรือปฏิเสธ แล้วจึงดำเนินการต่อได้ ขั้นตอนยืนยันนี้เป็นแนวป้องกันที่มีประสิทธิภาพสูงสุดเพียงอย่างเดียวต่อข้อผิดพลาดของเอเจนต์และการใช้งานในทางที่ผิดซึ่งเกิดจากการฉีดคำสั่ง

HIGH_RISK_ACTIONS = {
    'delete_customer_record',
    'send_bulk_email',
    'process_refund_over_100',
    'deploy_code',
    'revoke_user_access'
}

def execute_with_confirmation(tool_name: str, tool_args: dict, agent_reasoning: str) -> dict:
    if tool_name in HIGH_RISK_ACTIONS:
        # Pause and request human approval
        approval_request = {
            'action': tool_name,
            'arguments': tool_args,
            'agent_reasoning': agent_reasoning,
            'risk_level': 'HIGH'
        }
        approval = request_human_approval(approval_request)  # blocks until human responds
        
        if not approval.approved:
            return {'status': 'rejected', 'reason': approval.rejection_reason}
        
        # Log the approval for audit trail
        log_approval(tool_name, tool_args, approved_by=approval.approver_id)
    
    # Execute only after confirmation
    return execute_tool(tool_name, **tool_args)

การกำหนดขอบเขตเครื่องมือ: เวลา ผู้ใช้ และข้อมูล

นอกเหนือจากประเภทของสิทธิ์แล้ว ให้กำหนดขอบเขตการเข้าถึงเครื่องมือตามสามมิติ ขอบเขตด้านเวลา: คีย์ API หรือโทเค็นที่หมดอายุหลังเซสชันของเอเจนต์สิ้นสุดลง ขอบเขตด้านผู้ใช้: เอเจนต์ที่ช่วยผู้ใช้ A ต้องไม่เข้าถึงข้อมูลของผู้ใช้ B แม้จะได้รับคำสั่งให้ทำเช่นนั้น ขอบเขตด้านข้อมูล: เอเจนต์ฝ่ายสนับสนุนลูกค้าควรเข้าถึงเฉพาะข้อมูลของลูกค้าที่กำลังให้ความช่วยเหลืออยู่ ไม่ใช่ข้อมูลของลูกค้าทั้งหมด ให้ใช้ข้อจำกัดเหล่านี้ในการใช้งานเครื่องมือ ไม่ใช่ในพรอมป์ของเอเจนต์

class ScopedCustomerTool:
    def __init__(self, current_user_id: str, session_token: str):
        self.user_id = current_user_id  # agent can only access THIS user's data
        self.token = session_token       # expires at end of session

    def get_customer_profile(self) -> dict:
        # Hardcoded to current user - agent cannot change this via prompt
        return db.query(
            'SELECT * FROM customers WHERE id = %s',
            (self.user_id,)  # parameterized, always this user's ID only
        )

    def get_order_history(self, limit: int = 10) -> list:
        # Even if the agent says 'get orders for user 999', it gets self.user_id
        return db.query(
            'SELECT * FROM orders WHERE customer_id = %s ORDER BY date DESC LIMIT %s',
            (self.user_id, min(limit, 50))  # cap limit too
        )

# Inject scoped tool into agent - cannot be overridden by prompt
def create_support_agent(user_id: str, session_token: str):
    scoped_tools = ScopedCustomerTool(user_id, session_token)
    return AgentExecutor(llm=llm, tools=[scoped_tools.get_customer_profile, scoped_tools.get_order_history])

การตรวจสอบอินพุตของอาร์กิวเมนต์เครื่องมือ

เอเจนต์สร้างอาร์กิวเมนต์เครื่องมือในรูปข้อความ ก่อนเรียกใช้เครื่องมือใด ๆ ให้ตรวจสอบอาร์กิวเมนต์ทั้งหมดกับแบบแผนที่เข้มงวด วิธีนี้ช่วยป้องกัน: การฉีด SQL ผ่านพารามิเตอร์ของเครื่องมือ การโจมตีแบบเจาะเส้นทาง (เอเจนต์ส่ง '../../../etc/passwd' เป็นเส้นทางไฟล์) การโจมตีแบบ SSRF (เอเจนต์ส่ง URL ของบริการภายในเป็นพารามิเตอร์ 'remote URL') และค่าจำนวนเต็มล้นหรืออยู่นอกช่วงซึ่งอาจทำให้เกิดพฤติกรรมที่ไม่คาดคิด

from pydantic import BaseModel, validator, constr, confloat
import re

class SendEmailArgs(BaseModel):
    to: str
    subject: constr(max_length=200)
    body: constr(max_length=10000)

    @validator('to')
    def must_be_company_email(cls, v):
        if not re.match(r'^[^@]+@(?:yourcorp\.com|partner\.com)$', v):
            raise ValueError('Email must be sent to yourcorp.com or partner.com domains only')
        return v

class ReadFileArgs(BaseModel):
    filename: constr(pattern=r'^[a-zA-Z0-9_\-\.]+$')  # alphanumeric only, no path traversal

    @validator('filename')
    def no_parent_directory(cls, v):
        if '..' in v or '/' in v or '\\' in v:
            raise ValueError('Path traversal detected')
        return v

# Validate before execution
def validated_send_email(args_dict: dict) -> dict:
    args = SendEmailArgs(**args_dict)  # raises ValueError on invalid input
    return send_email(args.to, args.subject, args.body)

การบันทึกการตรวจสอบแบบแก้ไขไม่ได้

การเรียกใช้เครื่องมือทุกครั้งโดยเอเจนต์ต้องได้รับการบันทึกไว้ใน บันทึกการตรวจสอบแบบแก้ไขไม่ได้ รายการบันทึกต้องประกอบด้วย: ID ของเอเจนต์และ ID ของเซสชัน ชื่อเครื่องมือและอาร์กิวเมนต์ทั้งหมด ค่าที่ส่งกลับ เวลาที่เกิดเหตุการณ์ และเหตุผลที่เอเจนต์ระบุไว้สำหรับการเรียกใช้ การแก้ไขไม่ได้หมายความว่าเอเจนต์หรือผู้โจมตีไม่สามารถลบหรือแก้ไขรายการบันทึกได้ ให้ใช้พื้นที่จัดเก็บแบบเพิ่มข้อมูลได้อย่างเดียว (บริการบันทึกบนคลาวด์ ฐานข้อมูลที่เขียนได้ครั้งเดียว หรือพื้นที่จัดเก็บแบบ WORM)

import hashlib
import json
import time

class ImmutableAuditLog:
    def __init__(self, log_backend):
        self.backend = log_backend  # e.g., CloudWatch, BigQuery, or append-only file
        self.previous_hash = '0' * 64  # genesis hash

    def record(self, agent_id: str, tool_name: str, args: dict, result, reasoning: str):
        entry = {
            'agent_id': agent_id,
            'tool': tool_name,
            'args': args,
            'result_summary': str(result)[:500],  # truncate large results
            'reasoning': reasoning[:1000],
            'timestamp': time.time(),
            'previous_hash': self.previous_hash  # chain entries like a blockchain
        }
        
        entry_json = json.dumps(entry, sort_keys=True)
        entry['hash'] = hashlib.sha256(entry_json.encode()).hexdigest()
        
        self.backend.append(entry)  # append-only, never update
        self.previous_hash = entry['hash']
        
        return entry['hash']

การตรวจจับพฤติกรรมผิดปกติของเอเจนต์

แม้จะมีการควบคุมสิทธิ์และบันทึกการตรวจสอบแล้ว ให้เฝ้าระวัง รูปแบบพฤติกรรมผิดปกติ ที่บ่งชี้ว่าเอเจนต์ถูกโจมตีหรือกำลังทำงานอย่างไม่คาดคิด สัญญาณความผิดปกติ ได้แก่ เอเจนต์ฝ่ายสนับสนุนเรียกใช้เครื่องมือที่ไม่เคยเรียกมาก่อนอย่างกะทันหัน ความถี่ในการเรียกใช้เครื่องมือจากเอเจนต์รายหนึ่งเพิ่มขึ้นอย่างผิดปกติ อาร์กิวเมนต์แตกต่างจากปกติในลักษณะที่น่าสงสัย เช่น สตริงที่ยาวผิดปกติหรือลำดับอักขระแปลก ๆ หรือมีการเรียกใช้ในช่วงเวลาที่ไม่ปกติ

from collections import Counter

class AgentBehaviorMonitor:
    def __init__(self):
        self.tool_call_counts = Counter()  # tracks historical tool usage
        self.arg_length_history = {}       # tracks typical argument lengths

    def record_and_check(self, agent_id: str, tool_name: str, args: dict) -> list[str]:
        key = f'{agent_id}:{tool_name}'
        anomalies = []
        
        self.tool_call_counts[key] += 1
        
        # Flag tools never called before by this agent
        if self.tool_call_counts[key] == 1 and tool_name not in COMMON_TOOLS:
            anomalies.append(f'First time agent {agent_id} called unusual tool: {tool_name}')
        
        # Flag unusually long arguments (potential injection payload)
        total_arg_length = sum(len(str(v)) for v in args.values())
        if tool_name not in self.arg_length_history:
            self.arg_length_history[tool_name] = []
        self.arg_length_history[tool_name].append(total_arg_length)
        
        if len(self.arg_length_history[tool_name]) > 10:
            avg = sum(self.arg_length_history[tool_name]) / len(self.arg_length_history[tool_name])
            if total_arg_length > avg * 5:
                anomalies.append(f'Unusually long arguments for {tool_name}: {total_arg_length} chars (avg: {avg:.0f})')
        
        return anomalies

การหมดอายุของโทเค็นและการกำหนดขอบเขตเซสชัน

เซสชันของเอเจนต์ควรมี อายุการใช้งาน ที่กำหนดไว้อย่างชัดเจน ออกโทเค็นหรือข้อมูลรับรองอายุสั้นให้เอเจนต์เมื่อเริ่มเซสชัน และเพิกถอนเมื่อเซสชันสิ้นสุดลง หากเซสชันของเอเจนต์ถูกโจมตีระหว่างการทำงาน ความสามารถของผู้โจมตีในการใช้ประโยชน์จากเซสชันที่ถูกบุกรุกจะถูกจำกัดด้วยเวลาหมดอายุของโทเค็น การกำหนดขอบเขตเซสชันยังช่วยให้มั่นใจว่าเอเจนต์ที่ถูกบุกรุกรายเดียวจะไม่ถูกนำไปใช้โจมตีต่อในอีกหลายวันภายหลัง

import secrets
import time

class SessionTokenManager:
    def __init__(self, ttl_seconds=3600):
        self.tokens = {}  # token -> (agent_id, user_id, expires_at)
        self.ttl = ttl_seconds

    def issue_token(self, agent_id: str, user_id: str) -> str:
        token = secrets.token_urlsafe(32)
        expires_at = time.time() + self.ttl
        self.tokens[token] = (agent_id, user_id, expires_at)
        return token

    def validate_token(self, token: str) -> dict | None:
        if token not in self.tokens:
            return None
        agent_id, user_id, expires_at = self.tokens[token]
        if time.time() > expires_at:
            del self.tokens[token]  # clean up expired token
            return None
        return {'agent_id': agent_id, 'user_id': user_id}

    def revoke_token(self, token: str):
        self.tokens.pop(token, None)

token_manager = SessionTokenManager(ttl_seconds=1800)  # 30-minute sessions

การทดสอบความปลอดภัยของเครื่องมือ

ทดสอบชั้นความปลอดภัยของเครื่องมือโดยจำลองการโจมตี: ลองเรียกใช้เครื่องมือที่จำกัดสิทธิ์ด้วยเอเจนต์ที่ไม่ได้รับอนุญาต ส่งอาร์กิวเมนต์แบบเจาะเส้นทาง ฉีดสตริงคำสั่งลงในพารามิเตอร์ของเครื่องมือ และพยายามเรียกใช้เครื่องมือด้วยโทเค็นที่หมดอายุ ชุดทดสอบความปลอดภัยของเครื่องมือที่ครอบคลุมควรครอบคลุมขอบเขตสิทธิ์ทั้งหมด กฎการตรวจสอบทั้งหมด และเงื่อนไขกระตุ้นการตรวจจับความผิดปกติทั้งหมด

การออกแบบเพื่อให้ย้อนกลับได้

เมื่อเป็นไปได้ ให้ออกแบบเครื่องมือให้ ย้อนกลับได้หรือดำเนินการเป็นขั้นตอน แทนที่จะลบระเบียนทันที ให้ทำเครื่องหมายว่าลบแล้วด้วยข้อมูล tombstone เพื่อให้กู้คืนได้ แทนที่จะส่งอีเมลทันที ให้นำไปไว้ในคิว 'pending send' ที่จะดำเนินการหลังช่วงเวลาตรวจสอบ 5 นาที ให้ธุรกรรมทางการเงินดำเนินการเป็นขั้นตอน โดยพักรายการไว้ก่อนชำระบัญชี การย้อนกลับได้ไม่ได้ขจัดความเสี่ยงด้านความปลอดภัย แต่ช่วยลดผลกระทบจากการโจมตีที่สำเร็จได้อย่างมาก

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจของคุณเกี่ยวกับการรักษาความปลอดภัยการเข้าถึงเครื่องมือของเอเจนต์จากบทเรียนนี้

สรุปบทเรียน

ในบทเรียนนี้ คุณได้เรียนรู้ว่า หลักการให้สิทธิ์เท่าที่จำเป็น จำกัดสิทธิ์ของเครื่องมือให้เหลือเท่าที่บทบาทของเอเจนต์แต่ละบทบาทต้องใช้จริง, การควบคุมสิทธิ์ในระดับโค้ด บังคับใช้สิทธิ์เหล่านี้ในลักษณะที่ไม่สามารถหลีกเลี่ยงได้ด้วยการฉีดคำสั่งในพรอมป์ และ ขั้นตอนยืนยันจากมนุษย์ สำหรับการดำเนินการที่มีความเสี่ยงสูง มอบแนวป้องกันขั้นสุดท้ายก่อนดำเนินการที่ย้อนกลับไม่ได้ ต่อไปเราจะทำแบบฝึกหัดทีมแดงอย่างเป็นระบบกับแอปพลิเคชัน LLM

คำถามที่พบบ่อย

บทเรียน “การรักษาความปลอดภัยการเข้าถึงเครื่องมือของเอเจนต์” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การรักษาความปลอดภัยการเข้าถึงเครื่องมือของเอเจนต์” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Engineering Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การรักษาความปลอดภัยการเข้าถึงเครื่องมือของเอเจนต์”

ใช้หลักสิทธิ์เท่าที่จำเป็นกับสิทธิ์เครื่องมือของเอเจนต์ เพิ่มขั้นตอนยืนยันก่อนดำเนินการที่ทำลายข้อมูล และตรวจสอบบันทึกการกระทำของเอเจนต์เพื่อค้นหาพฤติกรรมผิดปกติ คุณปฏิบัติ AI Engineering Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Engineering Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Engineering Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน

บทเรียน “การรักษาความปลอดภัยการเข้าถึงเครื่องมือของเอเจนต์” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน AI Engineering Academy นี้ได้ไหม

ได้ บทเรียน AI Engineering Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. อนุกรมวิธานการโจมตีแบบฉีดคำสั่งในพรอมต์
  2. การป้องกันการฉีดคำสั่งในระบบ RAG
  3. การรักษาความปลอดภัยการเข้าถึงเครื่องมือของเอเจนต์
  4. การทำเรดทีมแอปพลิเคชัน LLM ของคุณ
← กลับไปที่ AI Engineering Academy