
AGENT ENGINEERING · TOOL PERMISSIONS · SOURCE-PINNED ANALYSIS
ห้าม Node ส่งอีเมลใน Workflow แล้ว Agent ยังเรียกผ่านอีกเส้นทางได้หรือไม่? ต้องตามให้ถึงจุดที่เครื่องมือทำงานจริง เพราะหน้าสร้างงาน การบันทึก และตัวรันอาจเดินคนละทางกัน
Quick Answer: ต้องตรวจที่ทางเข้าเครื่องมือด้วย
การเปลี่ยนแปลงใน n8n PR #39711 เชื่อม Agent Builder เข้ากับระบบ Policy โดยแปลง Node Tools เป็นข้อมูลสำหรับตรวจนโยบาย และเพิ่มการตรวจใน EphemeralNodeExecutor ก่อนเรียก execute() หรือ supplyData() ข้อสำคัญคือผลตรวจตอนบันทึกหรือเผยแพร่ไม่ใช่ใบอนุญาตให้เรียก Tool ได้ตลอดไป เส้นทางรันต้องมีด่านของตัวเองด้วย
อ้างอิง source tag n8n@2.44.0 ซึ่งเป็น prerelease เผยแพร่ 13 ตุลาคม 2026 ดัชนีที่ตรวจซ้ำ 15 ตุลาคม 2026 แยก beta 2.44.1 จาก stable 2.43.5 ยังไม่ยืนยันว่า fix อยู่ใน stable ดังกล่าว และไม่ได้ทดสอบรุ่นที่ติดตั้งจริง
ผลการเรียนรู้: วาดเส้นทาง Tool Call แยกการตรวจล่วงหน้าจากด่านก่อนทำงาน และกำหนดหลักฐานว่า Tool ต้องห้ามไม่เริ่ม สถานะโค้ดและ Integration Test ในบทความคือ NOT RUN
1. ปัญหาไม่ได้อยู่แค่ใน Prompt
LLM Chat อาจแนะนำให้ใช้เครื่องมือ แต่ Agent มีวงจรเลือก Tool ส่ง Arguments และรับผล การบอกโมเดลว่า “อย่าใช้เครื่องมือนี้” เป็นคำแนะนำใน Context ไม่ใช่การควบคุมสิทธิ์ของตัวรัน ต้องมีหลักฐานนอกคำรายงานของโมเดล
Policy คือกฎตัดสินว่าชนิด Node ใช้ได้หรือไม่ Execution boundary คือขอบเขตก่อนเครื่องมือทำงาน ส่วน preflight คือการตรวจล่วงหน้าเพื่อแจ้งปัญหาเร็ว ทั้งสองด่านมีหน้าที่ต่างกัน
กรณีศึกษานี้จำกัดอยู่ใน Agent Builder ของโมดูล modules/agents และ Node Tools ที่ผ่านตัวรันที่ตรวจพบ ไม่ได้เหมารวมว่า PR นี้ปิดทุกช่องทางของ classic LangChain AI Agent หรือทุก Custom Node ผู้ตรวจระบบต้องเขียนรายการเส้นทางจริงของตนเองก่อนขยายข้อสรุป

2. อะไรเปลี่ยนใน Source ที่ตรวจ
Policy Infrastructure แทน Agent ด้วย PolicedWorkflow ที่มี artifactKind: 'agent' และแปลงแต่ละ Node Tool เป็น Node สำหรับตัวตรวจ จึงใช้ enforcement points ร่วมกับ Workflow ได้ โดยใช้ชนิดที่รันจริง รวมถึง …Tool เมื่อมี ชื่อเล่น “อ่านโน้ต” จึงไม่เปลี่ยนชนิดจริงให้พ้นข้อห้าม
อีกส่วนอยู่ที่ EphemeralNodeExecutor ซึ่งเป็นทางรัน Node Tool ของ Agent ไม่ได้ผ่าน WorkflowRunner ตามปกติ จึงอาศัยเฉพาะ lifecycle hook ของ Workflow ไม่พอ Source เพิ่ม workflowStart ให้ Workflow ชั่วคราวที่ตัวรันสร้าง ทั้งเส้นทาง execute และ supplyData ก่อนเริ่มเมธอดทำงานจริง
การปฏิเสธกลับเป็น Tool Error ไม่ได้หยุดทุกการกระทำของ Agent หรือย้อนงานเดิม และมีการเตรียมบริบท/credential ก่อน gate จึงไม่ได้กันทุกการอ่าน นี่เป็นหลักฐาน Source ไม่ใช่ผลทดสอบระบบจริง
3. Save ได้ ไม่ได้แปลว่า Publish หรือ Run ได้
Type Availability Policies ตั้งใจให้การบันทึกกับการเริ่มงานมีเกณฑ์ต่างกัน เพื่อไม่ให้กฎใหม่ทำให้ Workflow เก่าเปิดแก้ไขไม่ได้ การบันทึกเปรียบเทียบชนิด Node ที่ส่งมากับชนิดที่เก็บอยู่แล้ว และรายงานชนิดต้องห้ามที่เพิ่มเข้ามา หลักนี้เรียกว่า grandfathering หรือการยอมให้เนื้อหาเดิมยังแก้ไขได้ภายใต้ข้อจำกัด
| เหตุการณ์ | สิ่งที่ตรวจใน source baseline | ข้อสรุปที่ห้ามข้ามขั้น |
|---|---|---|
| Save | ชนิดที่ฉบับใหม่เพิ่มจากชนิดที่เก็บอยู่ | เก็บ Draft ได้ ไม่ใช่ยืนยันสิทธิ์รัน |
| Publish | ทุกชนิดต้องห้ามที่อยู่ในเนื้อหา | ไม่ยกเว้นเพราะมีอยู่ก่อน |
| Start / Tool execution | ใช้จุดตรวจเริ่มงานบนเส้นทางที่เกี่ยวข้อง | ต้องพิจารณา Policy ที่ตัวรันอ่านได้ขณะนั้น |
Save เปรียบเทียบชนิด ไม่ใช่จำนวน Node การย้าย เปลี่ยนชื่อ หรือทำสำเนาชนิดเดิมจึงอาจบันทึกได้ และ disabled Node ยังถูกนับ เพิ่ม gmailTool เมื่อเก่ามีเพียง gmail ถือว่าเพิ่มชื่อชนิด แม้กฎ base type อาจครอบคลุมทั้งคู่ การจับคู่กฎกับส่วนต่างตอน Save เป็นคนละเรื่อง
Publish/Start ไม่มีข้อยกเว้นแบบ Save การดูเพียงข้อความ “Saved” จึงไม่ผ่านเกณฑ์พิสูจน์สิทธิ์รัน

4. สถาปัตยกรรม: ตามให้ถึงก่อนเครื่องมือทำงาน
เส้นทางคือ คำสั่ง → Agent เลือก Tool → Host หา Tool ใน Registry → ตรวจบริบทและกฎ → อนุญาตหรือปฏิเสธ → เริ่มเครื่องมือ → เก็บหลักฐาน Registry คือทะเบียนที่ Host เชื่อถือได้ ไม่รับชนิด Tool ที่โมเดลอ้างมาเอง ต้องส่ง Project และชนิดจริงไปถึงด่านตัดสิน
แยกผล advisory ที่ช่วยวางแผนจากผล enforcement ที่กั้นการทำงาน อย่าใช้ Boolean ว่าเคยผ่านหลังเปลี่ยน Tool หรือกฎ การตรวจซ้ำยังไม่รับรองว่าทุก process เห็นข้อมูลใหม่พร้อมกัน
baseline นี้ใช้ Cache และระบุหน้าต่างความสดถึงประมาณหนึ่งวินาทีในเงื่อนไขปกติ พร้อมข้อจำกัดการ invalidation ข้าม process “ตรวจขณะรัน” จึงไม่เท่ากับอ่านฐานข้อมูลใหม่ทุกครั้งหรือถอนสิทธิ์ทันที ต้องกำหนดเกณฑ์ cache propagation และงานที่เริ่มไปแล้วแยก
Inline Agent ที่กำหนดค่าคงที่ใน Message an Agent ถูกขยาย Node Tools เพื่อให้ตัวตรวจเห็นได้ รวมถึงกรณีซ้อนกัน แต่ inline ที่มาจาก expression ไม่ถูกขยายใน static check แบบนั้น ตัวรันยังเป็นจุดตรวจเมื่อ Tool ทำงาน ไม่ควรเขียนว่า static validation เห็นค่าที่จะเกิดในอนาคตทุกกรณี
5. เงื่อนไขที่ทำให้คำว่า Fail-closed ต้องพูดให้ครบ
Fail-closed คือหยุดการกระทำเมื่อกลไกตรวจทำงานไม่ได้ แต่ baseline นี้ต้องมี license feature feat:typeAvailabilityPolicies, เปิด module type-availability-policies และมี Policy Infrastructure backend ทำงาน Module ไม่ใช่ค่าเริ่มต้นและต้องเปิดทุก process เปิดเฉพาะ main ไม่ครอบคลุม queue workers
ความต่างที่ต้องแยกคือ ไม่มี check ลงทะเบียน กับ check ที่ลงทะเบียนแล้วล้มเหลว กรณีแรกระบบอนุญาต ส่วนกรณีหลัง Infrastructure ปฏิเสธเมื่อ check โยนข้อผิดพลาดหรือเกิน deadline โดยแยกจากการปฏิเสธเพราะพบ violation การหยุดจากตรวจผิดพลาดกับการพบชนิดต้องห้ามจึงไม่ควรถูกรวมเป็นหมวดเดียวใน Log
Node Type Check และ Credential Type Check อ่าน LicenseState ต่อการตัดสิน เมื่อ license หมดอายุจะหยุดบังคับกฎ จึงกล่าวว่า fail-closed เสมอไม่ได้ ต้องติดตาม license/module และการตั้งค่าที่คลาดกัน บทความไม่ได้เปลี่ยน configuration เหล่านี้
6. Worked example: ผ่านตอนวางแผน แต่ถูกห้ามก่อนเรียก
ตัวอย่างสมมติแบบ MOCK: Agent มี mail_summary กับ notes_read ซึ่ง Host ผูกกับชนิด mailTool และ notesTool ตามลำดับ งานคืออ่านข้อมูลสรุปที่เป็น fixture ในหน่วยความจำ ไม่มี API จริง ที่นโยบายรุ่น p1 ทั้งสองชนิดยังใช้ได้ การตรวจล่วงหน้าจึงบันทึกว่าไม่พบข้อห้ามในขณะนั้น
ก่อนเรียกเครื่องมือ ผู้ดูแลในสถานการณ์สมมติเปลี่ยนเป็น p2 ที่ห้าม mailTool ตัวรันอ่าน snapshot ปัจจุบันอีกครั้ง ผลที่คาดคือ mail_summary ได้ AUTHOR_TYPE_BLOCKED และไม่เพิ่มรายการ executed ส่วน notes_read ได้ข้อความ fixture note บัญชีการตัดสินทั้งสองรายการระบุ p2 แทนการอ้างผล preflight p1
เกณฑ์สำเร็จคือ fixture ต้องห้ามไม่ถูกเรียก พร้อมชนิดที่ Host resolve และ revision ที่ใช้ ข้อความปฏิเสธหลังเครื่องมือทำงานแล้วไม่ผ่านเกณฑ์นี้
7. Python example และวิธีอ่านโค้ด
ใช้ Python 3.12+ และ Standard Library ไม่มี dependency หรือ environment variable สำเนาไฟล์ไว้โฟลเดอร์เดียวกัน ตัวอย่างเขียนขึ้นใหม่ ไม่ใช่ n8n SDK หรือ policy resolver ทั้งชุด
code/policy_gate_mock.py · NOT RUN
"""Original teaching MOCK, Python 3.12; NOT n8n code or an n8n policy resolver.
No network, credentials, external writes or real tool execution. Tests NOT RUN.
The AUTHOR'S stricter missing-context refusal is not n8n's module/license posture.
"""
from dataclasses import dataclass
import json
from typing import Callable, Mapping
class Stopped(Exception):
pass
@dataclass(frozen=True)
class PolicySnapshot:
revision: str
blocked_types: frozenset[str]
@dataclass(frozen=True)
class ToolDefinition:
canonical_type: str
fixture_result: str
class PolicyGateMock:
"""Synchronous single-worker fixture; deliberately no rule inheritance/cache."""
def __init__(
self,
registry: Mapping[str, ToolDefinition],
current_policy: Callable[[], PolicySnapshot | None],
) -> None:
self._registry = dict(registry) # Host-owned, never supplied by the model.
self._current_policy = current_policy
self.executed: list[str] = []
self.ledger: list[dict[str, str]] = []
def _record(self, tool_id: str, node_type: str, revision: str, reason: str) -> None:
# No user request, arguments, result, token or credential in this ledger.
self.ledger.append({
"tool_id": tool_id,
"canonical_type": node_type,
"policy_revision": revision,
"decision": reason,
})
def _read_snapshot(self) -> PolicySnapshot:
snapshot = self._current_policy()
if snapshot is None:
raise Stopped("AUTHOR_POLICY_UNAVAILABLE")
if not isinstance(snapshot.revision, str) or not snapshot.revision.strip():
raise Stopped("AUTHOR_REVISION_MISSING")
if not isinstance(snapshot.blocked_types, frozenset) or any(
not isinstance(name, str) or not name.strip()
for name in snapshot.blocked_types
):
raise Stopped("AUTHOR_POLICY_INVALID")
return snapshot
def _definition(self, tool_id: str) -> ToolDefinition:
if not isinstance(tool_id, str) or tool_id not in self._registry:
raise Stopped("AUTHOR_UNKNOWN_TOOL")
definition = self._registry[tool_id]
if not isinstance(definition.canonical_type, str) or not definition.canonical_type.strip():
raise Stopped("AUTHOR_TYPE_MISSING")
return definition
def preflight(self, tool_ids: list[str]) -> str:
"""Author's strict advisory check; no save grandfathering is modelled."""
snapshot = self._read_snapshot()
for tool_id in tool_ids:
if self._definition(tool_id).canonical_type in snapshot.blocked_types:
raise Stopped("AUTHOR_PREFLIGHT_BLOCKED")
return snapshot.revision # Evidence of that check, not an execution permit.
def call(self, identity: str, tool_id: str) -> str:
revision, node_type = "UNKNOWN", "UNKNOWN"
try:
if not isinstance(identity, str) or not identity.strip():
raise Stopped("AUTHOR_IDENTITY_MISSING")
definition = self._definition(tool_id)
node_type = definition.canonical_type
# Fresh provider read on EACH call, even if preflight was clear.
snapshot = self._read_snapshot()
revision = snapshot.revision
if node_type in snapshot.blocked_types:
raise Stopped("AUTHOR_TYPE_BLOCKED")
except Stopped as error:
safe_id = tool_id if isinstance(tool_id, str) and tool_id in self._registry else "UNKNOWN"
self._record(safe_id, node_type, revision, str(error))
raise
# Only this in-memory fixture runs. This is NOT execute()/supplyData() in n8n.
self.executed.append(tool_id)
self._record(tool_id, node_type, revision, "AUTHOR_FIXTURE_ALLOWED")
return definition.fixture_result
def demo() -> dict[str, object]:
holder = {"policy": PolicySnapshot("p1", frozenset())}
gate = PolicyGateMock({
"mail_summary": ToolDefinition("mailTool", "fixture mail summary"),
"notes_read": ToolDefinition("notesTool", "fixture note"),
}, lambda: holder["policy"])
preflight_revision = gate.preflight(["mail_summary", "notes_read"])
holder["policy"] = PolicySnapshot("p2", frozenset({"mailTool"}))
outcomes = []
for tool_id in ["mail_summary", "notes_read"]:
try:
outcomes.append(gate.call("fixture-reader", tool_id))
except Stopped as error:
outcomes.append(str(error))
return {
"mode": "SYNTHETIC_MOCK",
"preflight_revision": preflight_revision,
"outcomes": outcomes,
"executed": gate.executed,
"ledger": gate.ledger,
}
if __name__ == "__main__":
print(json.dumps(demo(), indent=2, ensure_ascii=False))
code/test_policy_gate_mock.py · NOT RUN
"""Eight authored synthetic unit tests. NOT RUN. Python standard library only."""
import unittest
from policy_gate_mock import PolicyGateMock, PolicySnapshot, Stopped, ToolDefinition
class PolicyGateTests(unittest.TestCase):
def setUp(self):
self.holder = {"policy": PolicySnapshot("p1", frozenset())}
self.registry = {
"mail": ToolDefinition("mailTool", "fixture mail"),
"notes": ToolDefinition("notesTool", "fixture note"),
}
self.gate = PolicyGateMock(self.registry, lambda: self.holder["policy"])
def test_changed_policy_after_preflight_prevents_fixture(self):
self.assertEqual(self.gate.preflight(["mail"]), "p1")
self.holder["policy"] = PolicySnapshot("p2", frozenset({"mailTool"}))
with self.assertRaisesRegex(Stopped, "AUTHOR_TYPE_BLOCKED"):
self.gate.call("reader", "mail")
self.assertEqual(self.gate.executed, [])
self.assertEqual(self.gate.ledger[-1]["policy_revision"], "p2")
def test_allowed_fixture_only(self):
self.assertEqual(self.gate.call("reader", "notes"), "fixture note")
self.assertEqual(self.gate.executed, ["notes"])
def test_unknown_tool_stops(self):
with self.assertRaisesRegex(Stopped, "AUTHOR_UNKNOWN_TOOL"):
self.gate.call("reader", "model_invented")
self.assertEqual(self.gate.executed, [])
def test_missing_identity_stops(self):
with self.assertRaisesRegex(Stopped, "AUTHOR_IDENTITY_MISSING"):
self.gate.call(" ", "notes")
self.assertEqual(self.gate.executed, [])
def test_missing_policy_stops_under_author_policy(self):
self.holder["policy"] = None
with self.assertRaisesRegex(Stopped, "AUTHOR_POLICY_UNAVAILABLE"):
self.gate.call("reader", "notes")
self.assertEqual(self.gate.executed, [])
def test_missing_revision_stops_under_author_policy(self):
self.holder["policy"] = PolicySnapshot("", frozenset())
with self.assertRaisesRegex(Stopped, "AUTHOR_REVISION_MISSING"):
self.gate.call("reader", "notes")
self.assertEqual(self.gate.executed, [])
def test_friendly_tool_id_cannot_override_registry_type(self):
gate = PolicyGateMock({
"friendly_notes": ToolDefinition("mailTool", "fixture only")
}, lambda: PolicySnapshot("p2", frozenset({"mailTool"})))
with self.assertRaisesRegex(Stopped, "AUTHOR_TYPE_BLOCKED"):
gate.call("reader", "friendly_notes")
self.assertEqual(gate.executed, [])
def test_ledger_has_only_fixed_decision_fields(self):
self.gate.call("reader", "notes")
self.assertEqual(set(self.gate.ledger[-1]), {
"tool_id", "canonical_type", "policy_revision", "decision"
})
self.assertNotIn("fixture note", str(self.gate.ledger))
if __name__ == "__main__":
unittest.main()
code/README.md · NOT RUN
# Policy boundary teaching fixture
Status: **NOT RUN**. Neither the example nor these eight synthetic tests was executed,
imported or compiled during editorial production. This is original teaching code,
not an n8n SDK, not an implementation of its policy resolver and not production middleware.
- Runtime: Python 3.12 or newer, standard library only.
- Dependencies: none; no pip installation is required.
- Environment variables: none. Never add a real token to this fixture.
- Installation: copy `policy_gate_mock.py` and `test_policy_gate_mock.py` into one local directory.
- Run, only when authorized: `python policy_gate_mock.py`.
- Input: the in-file trusted registry, initial policy `p1`, then policy `p2` blocking `mailTool`.
- Expected semantic output: `mode=SYNTHETIC_MOCK`, preflight `p1`, outcomes
`AUTHOR_TYPE_BLOCKED` and `fixture note`, executed list contains only `notes_read`.
Both decisions in the ledger use current revision `p2`.
- Test instructions, only when authorized: `python -m unittest -v test_policy_gate_mock.py`.
Eight synthetic cases are authored; no pass count is reported because they were not run.
- Permissions: local memory and stdout only. No network, database, credentials, files written,
actual node execution or external effects. Tool names and results are invented fixtures.
- Cost: no external provider/API fee in this fixture; local execution resources remain the user's.
## What the example teaches
An advisory preflight at `p1` is evidence of that moment, not a reusable execution permit.
The call resolves the model's tool ID through a host-owned registry and reads a policy
snapshot again immediately before its in-memory fixture. A friendly tool ID cannot supply
an alternative type. A blocked call never reaches `executed`.
Missing identity, unknown tool, missing policy or revision stops under **the author's strict
sample policy**. This deliberately differs from the inspected n8n feature: missing module /
unregistered check allows, and an expired license stops enforcement. Do not use this fixture
to infer n8n's fail posture.
## Limits
Synchronous single worker only. There is no policy store, distributed invalidation, license,
module loader, type variant normalization, project/instance intersection, rule priority,
credential rule, save grandfathering, deadline, transport authentication, authorization of
the supplied identity, atomic policy-and-execute transaction, concurrency control or rollback.
The string identity is an input-presence demonstration, not an authenticated identity.
The provider may change policy immediately after the read; no zero-race claim is made.
Unexpected provider exceptions propagate without executing the fixture but do not produce
the structured refusal ledger. That is a limitation to address before building a service.
The ledger is an in-memory list, not persistent/tamper-resistant audit evidence.
## Separate n8n live verification plan — NOT RUN
Have an authorized administrator inspect the installed version, release channel, relevant
license feature and `type-availability-policies` module on every main/worker process. Inspect
the actual policy and project without editing production settings. The article's source
baseline is `n8n@2.44.0`; it is a prerelease, not a recommendation to upgrade production.
Read current official release notes before deciding compatibility.
In an independently authorized, isolated test environment, design cases for Agent Builder
node tools: existing blocked type can save; publish/start denies it; an allowed preflight
followed by a changed rule is rechecked at tool execution; unknown/dynamic inline contents
are not claimed statically covered; main/worker configuration and license-loss posture are
observed explicitly. Check execute and supplyData paths, policy versions/cache propagation,
error records and whether an actual fixture-side counter remains untouched after refusal.
Do not call real write tools merely to prove denial. Use disposable read-only fixtures and
capture the real results before claiming integration PASS.
This editorial run did not install/upgrade n8n, call its API, modify rules, start workflows,
run nodes or contact any external service from this example.
preflight() คืน revision เพื่อบอกว่าเคยตรวจอะไร ไม่คืนสิทธิ์รันถาวร ส่วน call() resolve ชนิดจาก Registry แล้วอ่าน snapshot ก่อนถึง fixture รายการ executed เป็นตัวนับการถึงขอบเขตทำงานใน Mock และ ledger เก็บเฉพาะ Tool ID ชนิด revision และเหตุผล ไม่เก็บ Prompt ผลเครื่องมือหรือ credential
เมื่อได้รับอนุญาต รัน python policy_gate_mock.py ผลที่คาดคือ JSON mode SYNTHETIC_MOCK, preflight_revision p1, outcomes เป็น AUTHOR_TYPE_BLOCKED กับ fixture note และ executed มีเฉพาะ notes_read นี่คือ expected output ไม่ใช่ผลรันจริง
มีไฟล์ test_policy_gate_mock.py พร้อมแปดกรณี Synthetic Test และคำสั่ง python -m unittest -v test_policy_gate_mock.py สถานะทั้งหมดคือ NOT RUN สิทธิ์ตัวอย่างมีแค่ข้อมูลในหน่วยความจำกับ stdout ไม่เรียกเครือข่าย ไม่เขียนไฟล์ ไม่ใช้ key และไม่มีค่าบริการ API ภายนอก ค่า CPU/เวลาของเครื่องที่ผู้อ่านใช้ยังเป็นต้นทุนของตนเอง
Mock หยุดเมื่อขาด identity, revision, Policy หรือไม่รู้จัก Tool ตามกฎที่เข้มขึ้นของผู้เขียน Identity ตรวจเพียงว่ามีค่า ไม่ใช่ Authentication ห้ามอ้างเป็น posture ของ n8n ตัวอย่างไม่มี atomic transaction, หลาย worker, cache invalidation หรือ rollback
8. Tool Integration ที่ควรตรวจในระบบจริง
ผู้ดูแลที่มีสิทธิ์เริ่มจาก read-only inventory: รุ่น/channel, license, modules ของ main/workers, Project และกฎจริง จากนั้นไล่ config ไปหา canonical Node Type กับตัวรัน ห้ามเปลี่ยน production ให้ตรงบทความโดยไม่ตรวจ compatibility
Live Integration ต้องอนุญาตแยก ใช้ fixture อ่านอย่างเดียวใน test environment ตรวจ Save/Publish/Start, กฎเปลี่ยนหลัง preflight, execute/supplyData, dynamic inline และ worker ตั้งค่าไม่ตรง เก็บหลักฐานว่า Tool ไม่เริ่ม งานนี้ไม่ได้ติดตั้ง อัปเกรด เรียก API หรือสั่ง Workflow จริง

9. ชนิด Node ไม่ใช่ขอบเขตข้อมูลหรือปลายทาง API
ห้าม Slack Node แต่อนุญาต HTTP Request หรือ Code ที่ออกเครือข่ายได้ ยังต้องตรวจว่าทางที่อนุญาตเข้าบริการเดียวกันได้หรือไม่ Type Policy ไม่ได้จำกัด domain, path, operation หรือข้อมูลปลายทางทั้งหมด
Credential Type Policy ตรวจชนิด credential เพิ่มจากชนิด Node แต่ไม่ได้ครอบคลุมทุกวิธีส่ง token ต้องพิจารณา credential scopes, egress/operation allowlist และสิทธิ์ข้อมูลตามความเสี่ยง ห้ามใส่ secret ในตัวอย่างหรือ ledger
การตรวจมีต้นทุนอ่านกฎและความหน่วง โดย cache ช่วยลดงานซ้ำ แต่ไม่มี benchmark จึงไม่ให้ตัวเลขวัดจริง Workflow, Agent เดียว และ Multi-Agent มีทางเข้าที่ต้องตรวจต่างกัน จำนวน Agent ไม่รับรองความถูกต้องของ Policy
10. Brief คัดลอกใช้กับงานตรวจของคุณ
เป้าหมาย: ทำแผนที่เส้นทาง Node Tool ของ Agent Builder หนึ่งงาน และพิสูจน์ใน test environment ที่อนุญาตว่า Tool ต้องห้ามไม่เริ่มทำงาน
ข้อมูลและเครื่องมือ: รุ่นที่ติดตั้ง รายการ process config ที่ปกปิด secret, Project, Policy revision, Registry และ fixture อ่านอย่างเดียว
ขอบเขตสิทธิ์: อ่าน configuration ที่ได้รับอนุญาต ไม่มีสิทธิ์แก้ production rule/upgrade/run จริงจนกว่าจะอนุญาตแยก
สิ่งส่งมอบ: ผัง preflight→runtime gate→fixture และ ledger ที่ไม่มี Prompt/key พร้อมสถานะการทดสอบจริง
เกณฑ์ตรวจรับ: บล็อกก่อน fixture, resolve ชนิดจากแหล่งเชื่อถือได้, ระบุ revision, ไม่ยืมผล Save เป็นสิทธิ์รัน, แยก config/license gap
จุดหยุด: ไม่ทราบ process/license/ชนิดหรือสิทธิ์ทดสอบ ให้ระบุ UNKNOWN และส่งผู้ดูแล ห้ามเดาว่าบล็อกแล้ว
11. Lab: มองเห็นคนละด่าน แล้วเปลี่ยนเงื่อนไข
ชุดถัดไปเป็น simulation ไม่เชื่อม n8n โมเดลหรือ Policy Store ค่า revision/license/เวลาเป็นค่าตั้ง ผลตามตัวเลือกไม่ใช่ Integration Test หรือคะแนนความปลอดภัย
3D Lab: ด่านเดียวกันต้องเห็นทั้ง Workflow และ Agent Tool
ตรวจตรงก่อนเรียก ไม่ใช่แค่ซ่อนปุ่ม
Simulation ของตำแหน่งบังคับนโยบายตาม source ที่ตรึง ไม่ใช่ตัว n8n ไม่มี Agent, API หรือ Node จริง ใช้ชนิด fixture.send ที่ตั้งขึ้นเพื่อสอน ไม่ใช่รหัส Node ที่นำไปใช้ใน n8n ได้ การอนุญาตในภาพหมายถึงผ่านเฉพาะด่านนี้ ไม่รับรองสิทธิ์อื่นหรือการทำงานสำเร็จ
ภาพรวม Workflow ใช้แทนจุดตรวจเริ่มงานเชิงแนวคิด ส่วนตำแหน่งก่อน execute / supplyData ที่อ่านจาก source เป็นของ Agent node tools โดยตรง สมมติว่า policy-infrastructure เปิดอยู่แล้ว ไม่จำลอง cache, การกระจาย policy หรือความสอดคล้องระหว่างหลาย process
ตั้งต้น: license/module พร้อม + DENY สมมติ → ปฏิเสธก่อน implementation ไม่มีการเรียก Node จริง
กฎและ fallback ที่อ่านได้
เมื่อ license กับ module ใน process นี้พร้อม ด่านนโยบายจึงมีผล: DENY หยุดก่อนเริ่ม ส่วน ALLOW ไปยังด่านอื่นได้ ไม่เท่ากับงานสำเร็จ หากขาด license/module ด่านนี้ไม่บังคับ ห้ามรายงานว่า “ตรวจผ่าน” อีกกรณีหนึ่งคือ checker ที่ลงทะเบียนไว้เกิดข้อผิดพลาด ซึ่ง source ให้หยุดด้วย error ต่างจากการไม่มีด่านตั้งแต่ต้น
ไม่มี WebGL/canvas dependency ผังเป็น DOM กับ CSS 3D มีมุม 2D และข้อความอธิบายเมื่อ transform ใช้ไม่ได้ ผลทดสอบปุ่ม คีย์บอร์ด มือถือ และ reduced motion จริงยัง UNKNOWN
Visual Interactive แยก: บันทึกได้ ทำไมเผยแพร่ยังติดนโยบาย?
เปรียบเทียบชนิดเดิมกับชนิดที่เพิ่ม
แบบจำลองนี้สมมติ license/module พร้อม และ policy ห้ามสองชนิดตัวอย่าง fixture.blocked กับ fixture.new_blocked ไม่มีตัวเลขวัดประสิทธิภาพ ไม่จำลอง resolver ทั้งระบบของ n8n
ชนิดเดิม fixture.blocked → Save ไม่เพิ่มชนิดใหม่จึงบันทึกได้ตามกฎนี้ แต่ Publish / Start ยังตรวจชนิดต้องห้ามเดิม
อ่านผลได้โดยไม่ใช้ JavaScript
Save ใช้ชนิดแบบ literal ที่เพิ่มจากฉบับเดิม การคงชนิดเดิมหรือเพิ่มอีก Node ที่เป็นชนิดเดิมไม่เพิ่มชนิดใหม่ ส่วน Publish / Start ไม่มีข้อยกเว้นเดิมนี้ Node ที่ disabled ก็ยังนับในการตรวจประเภท จึงไม่ใช้การปิด Node เป็นหลักฐานว่าผ่านนโยบาย หากเพิ่มชนิดใหม่ที่ถูกห้าม Save ก็ต้องปฏิเสธด้วย
ใช้ Video Agent Lab ฝึกจุดหยุดก่อน Tool เผยแพร่
Lab วิดีโอเดิมช่วยวางวงจรทำสคริปต์และสื่อ ตอนนี้ใช้ฝึกตรวจชนิดเครื่องมือก่อนขั้นส่งออกหรือเผยแพร่ ไม่ได้ติดตั้ง policy engine ของ n8n และไม่ทดสอบ license/module จริง ให้ตรวจ prompt ที่ Lab สร้างร่วมกับ brief หกส่วนนี้ ไม่ถือว่า generator เติมสิทธิ์และจุดหยุดครบเอง
- เป้าหมาย: เตรียมร่างวิดีโออธิบายการตรวจสิทธิ์ก่อน Agent เรียกเครื่องมือ
- ข้อมูลและเครื่องมือ: สคริปต์ตัวอย่างและภาพที่มีสิทธิ์ใช้, Tool อ่านข้อมูลกับ Tool สร้างร่างใน sandbox เท่านั้น
- ขอบเขตสิทธิ์: ทะเบียนเครื่องมือมาจากระบบที่เชื่อถือได้ ห้าม Tool ส่งข้อความ/เผยแพร่/ลบไฟล์ แม้ prompt ขอหรือเปลี่ยนชื่อเครื่องมือ
- สิ่งส่งมอบ: สคริปต์ร่าง, storyboard, รายการชนิด Tool ที่แผนใช้ และเหตุผลอนุญาต/ปฏิเสธ
- ตรวจรับ: ตรวจ policy ล่าสุดก่อนแต่ละ Tool และแยก “ด่านไม่ทำงาน” จาก “ไม่มีข้อฝ่าฝืน” ไม่รับเพียงภาพว่าปุ่มถูกซ่อน
- จุดหยุด: หากด่านไม่พร้อม ขาดหลักฐานนโยบาย หรือจะต้องใช้ Tool เขียนภายนอก ให้ส่งคนตรวจ ภายใต้นโยบายตัวอย่างนี้ไม่ดำเนินต่อ
จุดหยุดเมื่อด่านไม่พร้อมเป็นนโยบาย application ที่เสนอ ไม่ใช่พฤติกรรมอัตโนมัติของ n8n เมื่อ feature license/module หาย ค่าเวลา/เงินที่ปรับใน Video Lab เป็นสมมติฐาน ไม่ใช่ผลวัด n8n
จากคลิปดิบ
สู่จักรวาลคอนเทนต์
ChatGPT ตัดต่อวิดีโอแทนคนได้จริงแค่ไหน? สำรวจระบบ AI Video Editing Agent ผ่านฉากสามมิติที่โต้ตอบได้ พร้อมแยกข้อเท็จจริง สร้างพรอมป์ต์ และจำลองต้นทุนก่อนลงมือทำจริง
ออกแบบระบบตัดต่อในมุมมอง 3D
ลากบนฉากเพื่อหมุนมุมมอง แตะโหนดเพื่อดูหน้าที่ของ AI ในแต่ละขั้นตอน
จัดระเบียบไฟล์ ตรวจคุณภาพภาพและเสียง และกำหนดสิทธิ์เข้าถึงให้ AI Agent
แยกความสามารถจริงจากคำโฆษณา
กดแต่ละประเด็นเพื่ออ่านรายละเอียดและแหล่งข้อมูล
ChatGPT Work เข้าถึงไฟล์ในเครื่องได้ตรวจสอบแล้ว / มีเงื่อนไข+
Astra ใช้โปรแกรมคอมพิวเตอร์ทำงานได้ตรวจสอบแล้ว / ไม่ใช่โปรแกรมตัดต่อในตัว+
ตัดเสร็จใน 5–10 นาทีทุกกรณียังพิสูจน์เป็นเกณฑ์ทั่วไปไม่ได้+
ถูกกว่าจ้างคน 10 เท่าต้องกำหนดต้นทุนให้เทียบกันได้+
หนึ่งไอเดีย สามรูปแบบคอนเทนต์
ปรับรูปแบบวิดีโอ แล้วดูกรอบภาพตัวอย่างและ Prompt เปลี่ยนตามแบบเรียลไทม์
ช่วยตัดต่อ?
พร้อมนำไปใช้กับ AI Agent
ตัวสร้าง Prompt นี้ไม่อัปโหลดคลิป ไม่เรียก API เสียเงิน และไม่ตัดต่อวิดีโอจริง ต้องใช้กับเครื่องมือที่ผู้ใช้อนุญาตภายหลัง
จำลองเวลาและต้นทุนของคุณเอง
เลื่อนตัวเลขเพื่อเปรียบเทียบสถานการณ์สมมติ ไม่ใช่ผล benchmark ที่ยืนยันแล้ว
ตัวเลขเป็นตัวอย่างเพื่อช่วยตัดสินใจ ไม่ใช่ผลประหยัดที่รับประกัน
AI ที่ตัดคลิปเป็น ไม่ได้ทำงานลำพัง
สิ่งที่น่าสนใจของ GPT-6 Astra และ GPT-6.1 Sol ไม่ได้อยู่ที่ว่าตัวโมเดลมีปุ่ม Render MP4 ซ่อนอยู่ แต่คือความสามารถในการจัดการงานหลายขั้นตอนร่วมกับเครื่องมืออื่น: อ่านไฟล์ วางลำดับเรื่อง ใช้แอป ตรวจผลลัพธ์ และแก้งานตามข้อเสนอแนะของมนุษย์
สำหรับคนทำคอนเทนต์ ความต่างสำคัญคือการเปลี่ยนจาก “ส่งคลิปให้ AI แล้วหวังว่าจะได้ผลงาน” ไปเป็น Workflow ที่ตรวจรับได้ทุกขั้น ตั้งแต่การเลือกช่วงเด็ด การสร้างซับ การตรวจคำผิด จนถึงการเรนเดอร์ไฟล์ตามสัดส่วนของแต่ละแพลตฟอร์ม
ข้อควรระวังคือระบบ Work ที่รันบนเว็บหรือมือถือไม่ได้หมายความว่า AI เข้าถึงคลิปบนคอมพิวเตอร์บ้านได้ทันที ต้องทำงานในสภาพแวดล้อมที่เปิดให้เข้าถึงไฟล์จริง มีเครื่องมือตัดต่อ และมีสิทธิ์ใช้งานอย่างชัดเจน
รวบรวมไฟล์ในโฟลเดอร์ที่เข้าถึงได้ ระบุสิทธิ์และข้อจำกัด
ให้ Agent เสนอ Hook, ช่วงตัด และโครงเรื่องก่อนตัดต่อ
ตรวจชื่อเฉพาะ ตัวเลข ภาษาไทย และความถูกต้องของคำกล่าวอ้าง
ตรวจความละเอียด เสียง ระยะเวลา safe zone และคำบรรยาย
หาก Video Lab โหลดไม่ได้ ใช้ brief กับลำดับวางแผน → ตรวจชนิด/สิทธิ์ → สร้างร่าง → คนตรวจ แทน การ render shortcode ยืนยันเพียงฉบับบันทึก ไม่ยืนยันว่าปุ่มหรือทุกหน้าจอผ่านการทดสอบ
12. แบบฝึกหนึ่งข้อและเกณฑ์ตรวจรับ
ออกแบบกรณี preflight p1 อนุญาต แต่ p2 ห้ามก่อน Tool Call ระบุ expected decision, canonical type, revision และจำนวน fixture calls พร้อมอธิบายผลเมื่อ worker ไม่เปิด module หรือ license หมดอายุ
Rubric: ต้อง resolve ชนิดจาก Registry, ปฏิเสธที่ runtime, fixture ศูนย์ครั้งเมื่อห้าม, หลักฐานใช้ p2 และแยก Mock จาก n8n ถ้าดูเพียง Save หรืออ้างว่าบล็อกทุก API ยังไม่ผ่าน หากไม่ทดลองจริงคง NOT RUN
13. Checklist ก่อนนำหลักการไปออกแบบระบบ
- ระบุผลิตภัณฑ์ รุ่น channel และเส้นทาง Tool ที่ตรวจจริง
- แยก Save, Publish และ runtime decision พร้อมข้อยกเว้น
- หา canonical type จาก Host Registry และผูก Project ให้ถูก
- ตรวจ module/license ทุก process และความสดของ cache
- แยก violation, check failure และกรณีไม่มี check
- กำหนดสิทธิ์ API/data/credential เพิ่มจากชนิด Node ตามงาน
- เก็บหลักฐานว่าเครื่องมือไม่เริ่ม โดยไม่เผย Prompt หรือ secret
- ใช้ NOT RUN หรือ UNKNOWN ตามสิ่งที่ยังไม่ได้ตรวจจริง
FAQ
ห้าม Node ในหน้าออกแบบเพียงพอหรือยัง?
ต้องมี enforcement ก่อนเครื่องมือเริ่มด้วย โดยเฉพาะตัวรันที่ไม่ผ่าน WorkflowRunner
ทำไม Node ต้องห้ามเก่ายัง Save ได้?
Save ตรวจชนิดที่เพิ่มเพื่อให้แก้เนื้อหาเก่าได้ ส่วน Publish/Start ไม่มีข้อยกเว้นนี้
ตัวตรวจล้มเหลวกับไม่มี module เหมือนกันไหม?
ไม่เหมือน check ที่ลงทะเบียนแล้วล้มเหลวถูกปฏิเสธ แต่ไม่มี check จะอนุญาต และ license หมดอายุทำให้หยุดบังคับกฎ
บล็อก Node แล้ว HTTP Request เข้าบริการนั้นไม่ได้หรือ?
สรุปไม่ได้ ต้องตรวจ credential ปลายทาง และ operation ด้วย Type Policy ไม่ใช่ network firewall
พิสูจน์ว่า Production Ready แล้วหรือไม่?
ยังไม่มีผลรันจริง Source ถูก pin รุ่น แต่ Mock/tests ยัง NOT RUN, UI และ Live Integration ยัง UNKNOWN
แหล่งอ้างอิงและอ่านต่อ
แหล่งต้นทาง: PR #39711 และการเปลี่ยนแปลง; release n8n@2.44.0; Policy Infrastructure: enforcement points และ Agent path; Type Availability: license, grandfathering และข้อจำกัด; EphemeralNodeExecutor: ด่านก่อน execute/supplyData ทุกข้ออ้างผลิตภัณฑ์จำกัดตาม baseline ที่ตรวจ ไม่อ้างผลทดสอบอิสระ
ต่อยอดใน Hybrid Mind: โครงสร้าง Workflow, Single-Agent และ Multi-Agent ช่วยแยกส่วนรับผิดชอบ; ด่าน Tool Output ก่อนเข้าโมเดล แสดงว่าการกรองผลอยู่หลังการกระทำ จึงต่างจากด่านสิทธิ์ก่อนเรียก; และ Retry Budget ช่วยออกแบบการลองซ้ำโดยไม่ใช้ retry แทนสิทธิ์ที่ถูกปฏิเสธ

ใส่ความเห็น