{"id":72486,"date":"2026-02-20T11:51:04","date_gmt":"2026-02-20T11:51:04","guid":{"rendered":"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/"},"modified":"2026-02-20T11:51:04","modified_gmt":"2026-02-20T11:51:04","slug":"how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates","status":"publish","type":"post","link":"https:\/\/youzum.net\/th\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/","title":{"rendered":"How to Build Transparent AI Agents: Traceable Decision-Making with Audit Trails and Human Gates"},"content":{"rendered":"<p>In this tutorial, we build a glass-box agentic workflow that makes every decision traceable, auditable, and explicitly governed by human approval. We design the system to log each thought, action, and observation into a tamper-evident audit ledger while enforcing dynamic permissioning for high-risk operations. By combining LangGraph\u2019s interrupt-driven human-in-the-loop control with a hash-chained database, we demonstrate how agentic systems can move beyond opaque automation and align with modern governance expectations. Throughout the tutorial, we focus on practical, runnable patterns that turn governance from an afterthought into a first-class system feature.<\/p>\n<div class=\"dm-code-snippet dark dm-normal-version default no-background-mobile\">\n<div class=\"control-language\">\n<div class=\"dm-buttons\">\n<div class=\"dm-buttons-left\">\n<div class=\"dm-button-snippet red-button\"><\/div>\n<div class=\"dm-button-snippet orange-button\"><\/div>\n<div class=\"dm-button-snippet green-button\"><\/div>\n<\/div>\n<div class=\"dm-buttons-right\"><a><span class=\"dm-copy-text\">Copy Code<\/span><span class=\"dm-copy-confirmed\">Copied<\/span><span class=\"dm-error-message\">Use a different Browser<\/span><\/a><\/div>\n<\/div>\n<pre class=\"no-line-numbers\"><code class=\"no-wrap language-php\">!pip -q install -U langgraph langchain-core openai \"pydantic&lt;=2.12.3\"\n\n\nimport os\nimport json\nimport time\nimport hmac\nimport hashlib\nimport secrets\nimport sqlite3\nimport getpass\nfrom typing import Any, Dict, List, Optional, Literal, TypedDict\n\n\nfrom openai import OpenAI\nfrom langchain_core.messages import SystemMessage, HumanMessage, AIMessage\nfrom langgraph.graph import StateGraph, END\nfrom langgraph.types import interrupt, Command\n\n\nif not os.getenv(\"OPENAI_API_KEY\"):\n   os.environ[\"OPENAI_API_KEY\"] = getpass.getpass(\"Enter OpenAI API Key: \")\n\n\nclient = OpenAI()\nMODEL = \"gpt-5\"<\/code><\/pre>\n<\/div>\n<\/div>\n<p>We install all required libraries and import the core modules needed for agentic workflows and governance. We securely collect the OpenAI API key through a terminal prompt to avoid hard-coding secrets in the notebook. We also initialize the OpenAI client and define the model that drives the agent\u2019s reasoning loop.<\/p>\n<div class=\"dm-code-snippet dark dm-normal-version default no-background-mobile\">\n<div class=\"control-language\">\n<div class=\"dm-buttons\">\n<div class=\"dm-buttons-left\">\n<div class=\"dm-button-snippet red-button\"><\/div>\n<div class=\"dm-button-snippet orange-button\"><\/div>\n<div class=\"dm-button-snippet green-button\"><\/div>\n<\/div>\n<div class=\"dm-buttons-right\"><a><span class=\"dm-copy-text\">Copy Code<\/span><span class=\"dm-copy-confirmed\">Copied<\/span><span class=\"dm-error-message\">Use a different Browser<\/span><\/a><\/div>\n<\/div>\n<pre class=\"no-line-numbers\"><code class=\"no-wrap language-php\">CREATE_SQL = \"\"\"\nCREATE TABLE IF NOT EXISTS audit_log (\n   id INTEGER PRIMARY KEY AUTOINCREMENT,\n   ts_unix INTEGER NOT NULL,\n   actor TEXT NOT NULL,\n   event_type TEXT NOT NULL,\n   payload_json TEXT NOT NULL,\n   prev_hash TEXT NOT NULL,\n   row_hash TEXT NOT NULL\n);\n\n\nCREATE TABLE IF NOT EXISTS ot_tokens (\n   token_id TEXT PRIMARY KEY,\n   token_hash TEXT NOT NULL,\n   purpose TEXT NOT NULL,\n   expires_unix INTEGER NOT NULL,\n   used INTEGER NOT NULL DEFAULT 0\n);\n\"\"\"\n\n\ndef _sha256_hex(s: bytes) -&gt; str:\n   return hashlib.sha256(s).hexdigest()\n\n\ndef _canonical_json(obj: Any) -&gt; str:\n   return json.dumps(obj, sort_keys=True, separators=(\",\", \":\"), ensure_ascii=False)\n\n\nclass AuditLedger:\n   def __init__(self, path: str = \"glassbox_audit.db\"):\n       self.conn = sqlite3.connect(path, check_same_thread=False)\n       self.conn.executescript(CREATE_SQL)\n       self.conn.commit()\n\n\n   def _last_hash(self) -&gt; str:\n       row = self.conn.execute(\"SELECT row_hash FROM audit_log ORDER BY id DESC LIMIT 1\").fetchone()\n       return row[0] if row else \"GENESIS\"\n\n\n   def append(self, actor: str, event_type: str, payload: Any) -&gt; int:\n       ts = int(time.time())\n       prev_hash = self._last_hash()\n       payload_json = _canonical_json(payload)\n       material = f\"{ts}|{actor}|{event_type}|{payload_json}|{prev_hash}\".encode(\"utf-8\")\n       row_hash = _sha256_hex(material)\n       cur = self.conn.execute(\n           \"INSERT INTO audit_log (ts_unix, actor, event_type, payload_json, prev_hash, row_hash) VALUES (?, ?, ?, ?, ?, ?)\",\n           (ts, actor, event_type, payload_json, prev_hash, row_hash),\n       )\n       self.conn.commit()\n       return cur.lastrowid\n\n\n   def fetch_recent(self, limit: int = 50) -&gt; List[Dict[str, Any]]:\n       rows = self.conn.execute(\n           \"SELECT id, ts_unix, actor, event_type, payload_json, prev_hash, row_hash FROM audit_log ORDER BY id DESC LIMIT ?\",\n           (limit,),\n       ).fetchall()\n       out = []\n       for r in rows[::-1]:\n           out.append({\n               \"id\": r[0],\n               \"ts_unix\": r[1],\n               \"actor\": r[2],\n               \"event_type\": r[3],\n               \"payload\": json.loads(r[4]),\n               \"prev_hash\": r[5],\n               \"row_hash\": r[6],\n           })\n       return out\n\n\n   def verify_integrity(self) -&gt; Dict[str, Any]:\n       rows = self.conn.execute(\n           \"SELECT id, ts_unix, actor, event_type, payload_json, prev_hash, row_hash FROM audit_log ORDER BY id ASC\"\n       ).fetchall()\n       if not rows:\n           return {\"ok\": True, \"rows\": 0, \"message\": \"Empty ledger.\"}\n\n\n       expected_prev = \"GENESIS\"\n       for (id_, ts, actor, event_type, payload_json, prev_hash, row_hash) in rows:\n           if prev_hash != expected_prev:\n               return {\"ok\": False, \"at_id\": id_, \"reason\": \"prev_hash mismatch\"}\n           material = f\"{ts}|{actor}|{event_type}|{payload_json}|{prev_hash}\".encode(\"utf-8\")\n           expected_hash = _sha256_hex(material)\n           if not hmac.compare_digest(expected_hash, row_hash):\n               return {\"ok\": False, \"at_id\": id_, \"reason\": \"row_hash mismatch\"}\n           expected_prev = row_hash\n       return {\"ok\": True, \"rows\": len(rows), \"message\": \"Hash chain valid.\"}\n\n\nledger = AuditLedger()<\/code><\/pre>\n<\/div>\n<\/div>\n<p>We design a hash-chained SQLite ledger that records every agent and system event in an append-only manner. We ensure each log entry cryptographically links to the previous one, making post-hoc tampering detectable. We also provide utilities to inspect recent events and verify the integrity of the entire audit chain.<\/p>\n<div class=\"dm-code-snippet dark dm-normal-version default no-background-mobile\">\n<div class=\"control-language\">\n<div class=\"dm-buttons\">\n<div class=\"dm-buttons-left\">\n<div class=\"dm-button-snippet red-button\"><\/div>\n<div class=\"dm-button-snippet orange-button\"><\/div>\n<div class=\"dm-button-snippet green-button\"><\/div>\n<\/div>\n<div class=\"dm-buttons-right\"><a><span class=\"dm-copy-text\">Copy Code<\/span><span class=\"dm-copy-confirmed\">Copied<\/span><span class=\"dm-error-message\">Use a different Browser<\/span><\/a><\/div>\n<\/div>\n<pre class=\"no-line-numbers\"><code class=\"no-wrap language-php\">def mint_one_time_token(purpose: str, ttl_seconds: int = 600) -&gt; Dict[str, str]:\n   token_id = secrets.token_hex(12)\n   token_plain = secrets.token_urlsafe(20)\n   token_hash = _sha256_hex(token_plain.encode(\"utf-8\"))\n   expires = int(time.time()) + ttl_seconds\n   ledger.conn.execute(\n       \"INSERT INTO ot_tokens (token_id, token_hash, purpose, expires_unix, used) VALUES (?, ?, ?, ?, 0)\",\n       (token_id, token_hash, purpose, expires),\n   )\n   ledger.conn.commit()\n   return {\"token_id\": token_id, \"token_plain\": token_plain, \"purpose\": purpose, \"expires_unix\": str(expires)}\n\n\ndef consume_one_time_token(token_id: str, token_plain: str, purpose: str) -&gt; bool:\n   row = ledger.conn.execute(\n       \"SELECT token_hash, purpose, expires_unix, used FROM ot_tokens WHERE token_id = ?\",\n       (token_id,),\n   ).fetchone()\n   if not row:\n       return False\n   token_hash_db, purpose_db, expires_unix, used = row\n   if used == 1:\n       return False\n   if purpose_db != purpose:\n       return False\n   if int(time.time()) &gt; int(expires_unix):\n       return False\n   token_hash_in = _sha256_hex(token_plain.encode(\"utf-8\"))\n   if not hmac.compare_digest(token_hash_in, token_hash_db):\n       return False\n   ledger.conn.execute(\"UPDATE ot_tokens SET used = 1 WHERE token_id = ?\", (token_id,))\n   ledger.conn.commit()\n   return True\n\n\ndef tool_financial_transfer(amount_usd: float, to_account: str) -&gt; Dict[str, Any]:\n   return {\"status\": \"success\", \"transfer_id\": \"tx_\" + secrets.token_hex(6), \"amount_usd\": amount_usd, \"to_account\": to_account}\n\n\ndef tool_rig_move(rig_id: str, direction: Literal[\"UP\", \"DOWN\"], meters: float) -&gt; Dict[str, Any]:\n   return {\"status\": \"success\", \"rig_event_id\": \"rig_\" + secrets.token_hex(6), \"rig_id\": rig_id, \"direction\": direction, \"meters\": meters}<\/code><\/pre>\n<\/div>\n<\/div>\n<p>We implement a secure, single-use token mechanism that enables human approval for high-risk actions. We generate time-limited tokens, store only their hashes, and invalidate them immediately after use. We also define simulated restricted tools that represent sensitive operations such as financial transfers or physical rig movements.<\/p>\n<div class=\"dm-code-snippet dark dm-normal-version default no-background-mobile\">\n<div class=\"control-language\">\n<div class=\"dm-buttons\">\n<div class=\"dm-buttons-left\">\n<div class=\"dm-button-snippet red-button\"><\/div>\n<div class=\"dm-button-snippet orange-button\"><\/div>\n<div class=\"dm-button-snippet green-button\"><\/div>\n<\/div>\n<div class=\"dm-buttons-right\"><a><span class=\"dm-copy-text\">Copy Code<\/span><span class=\"dm-copy-confirmed\">Copied<\/span><span class=\"dm-error-message\">Use a different Browser<\/span><\/a><\/div>\n<\/div>\n<pre class=\"no-line-numbers\"><code class=\"no-wrap language-php\">RestrictedTool = Literal[\"financial_transfer\", \"rig_move\", \"none\"]\n\n\nclass GlassBoxState(TypedDict):\n   messages: List[Any]\n   proposed_tool: RestrictedTool\n   tool_args: Dict[str, Any]\n   last_observation: Optional[Dict[str, Any]]\n\n\nSYSTEM_POLICY = \"\"\"You are a governance-first agent.\nYou MUST propose actions in a structured JSON format with these keys:\n- thought\n- action\n- args\nReturn ONLY JSON.\"\"\"\n\n\ndef llm_propose_action(messages: List[Any]) -&gt; Dict[str, Any]:\n   input_msgs = [{\"role\": \"system\", \"content\": SYSTEM_POLICY}]\n   for m in messages:\n       if isinstance(m, SystemMessage):\n           input_msgs.append({\"role\": \"system\", \"content\": m.content})\n       elif isinstance(m, HumanMessage):\n           input_msgs.append({\"role\": \"user\", \"content\": m.content})\n       elif isinstance(m, AIMessage):\n           input_msgs.append({\"role\": \"assistant\", \"content\": m.content})\n\n\n   resp = client.responses.create(model=MODEL, input=input_msgs)\n   txt = resp.output_text.strip()\n   try:\n       return json.loads(txt)\n   except Exception:\n       return {\"thought\": \"fallback\", \"action\": \"ask_human\", \"args\": {}}\n\n\ndef node_think(state: GlassBoxState) -&gt; GlassBoxState:\n   proposal = llm_propose_action(state[\"messages\"])\n   ledger.append(\"agent\", \"THOUGHT\", {\"thought\": proposal.get(\"thought\")})\n   ledger.append(\"agent\", \"ACTION\", proposal)\n\n\n   action = proposal.get(\"action\", \"no_op\")\n   args = proposal.get(\"args\", {})\n\n\n   if action in [\"financial_transfer\", \"rig_move\"]:\n       state[\"proposed_tool\"] = action\n       state[\"tool_args\"] = args\n   else:\n       state[\"proposed_tool\"] = \"none\"\n       state[\"tool_args\"] = {}\n\n\n   return state\n\n\ndef node_permission_gate(state: GlassBoxState) -&gt; GlassBoxState:\n   if state[\"proposed_tool\"] == \"none\":\n       return state\n\n\n   token = mint_one_time_token(state[\"proposed_tool\"])\n   payload = {\"token_id\": token[\"token_id\"], \"token_plain\": token[\"token_plain\"]}\n   human_input = interrupt(payload)\n\n\n   state[\"tool_args\"][\"_token_id\"] = token[\"token_id\"]\n   state[\"tool_args\"][\"_human_token_plain\"] = str(human_input)\n   return state\n\n\ndef node_execute_tool(state: GlassBoxState) -&gt; GlassBoxState:\n   tool = state[\"proposed_tool\"]\n   if tool == \"none\":\n       state[\"last_observation\"] = {\"status\": \"no_op\"}\n       return state\n\n\n   ok = consume_one_time_token(\n       state[\"tool_args\"][\"_token_id\"],\n       state[\"tool_args\"][\"_human_token_plain\"],\n       tool,\n   )\n\n\n   if not ok:\n       state[\"last_observation\"] = {\"status\": \"rejected\"}\n       return state\n\n\n   if tool == \"financial_transfer\":\n       state[\"last_observation\"] = tool_financial_transfer(**state[\"tool_args\"])\n   if tool == \"rig_move\":\n       state[\"last_observation\"] = tool_rig_move(**state[\"tool_args\"])\n\n\n   return state<\/code><\/pre>\n<\/div>\n<\/div>\n<p>We define a governance-first system policy that forces the agent to express its intent in structured JSON. We use the language model to propose actions while explicitly separating thought, action, and arguments. We then wire these decisions into LangGraph nodes that prepare, gate, and validate execution under strict control.<\/p>\n<div class=\"dm-code-snippet dark dm-normal-version default no-background-mobile\">\n<div class=\"control-language\">\n<div class=\"dm-buttons\">\n<div class=\"dm-buttons-left\">\n<div class=\"dm-button-snippet red-button\"><\/div>\n<div class=\"dm-button-snippet orange-button\"><\/div>\n<div class=\"dm-button-snippet green-button\"><\/div>\n<\/div>\n<div class=\"dm-buttons-right\"><a><span class=\"dm-copy-text\">Copy Code<\/span><span class=\"dm-copy-confirmed\">Copied<\/span><span class=\"dm-error-message\">Use a different Browser<\/span><\/a><\/div>\n<\/div>\n<pre class=\"no-line-numbers\"><code class=\"no-wrap language-php\">def node_finalize(state: GlassBoxState) -&gt; GlassBoxState:\n   state[\"messages\"].append(AIMessage(content=json.dumps(state[\"last_observation\"])))\n   return state\n\n\ndef route_after_think(state: GlassBoxState) -&gt; str:\n   return \"permission_gate\" if state[\"proposed_tool\"] != \"none\" else \"execute_tool\"\n\n\ng = StateGraph(GlassBoxState)\ng.add_node(\"think\", node_think)\ng.add_node(\"permission_gate\", node_permission_gate)\ng.add_node(\"execute_tool\", node_execute_tool)\ng.add_node(\"finalize\", node_finalize)\n\n\ng.set_entry_point(\"think\")\ng.add_conditional_edges(\"think\", route_after_think)\ng.add_edge(\"permission_gate\", \"execute_tool\")\ng.add_edge(\"execute_tool\", \"finalize\")\ng.add_edge(\"finalize\", END)\n\n\ngraph = g.compile()\n\n\ndef run_case(user_request: str):\n   state = {\n       \"messages\": [HumanMessage(content=user_request)],\n       \"proposed_tool\": \"none\",\n       \"tool_args\": {},\n       \"last_observation\": None,\n   }\n   out = graph.invoke(state)\n   if \"__interrupt__\" in out:\n       token = input(\"Enter approval token: \")\n       out = graph.invoke(Command(resume=token))\n   print(out[\"messages\"][-1].content)\n\n\nrun_case(\"Send $2500 to vendor account ACCT-99213\")<\/code><\/pre>\n<\/div>\n<\/div>\n<p>We assemble the full LangGraph workflow and connect all nodes into a controlled decision loop. We enable human-in-the-loop interruption, pausing execution until approval is granted or denied. We finally run an end-to-end example that demonstrates transparent reasoning, enforced governance, and auditable execution in practice.<\/p>\n<p>In conclusion, we implemented an agent that no longer operates as a black box but as a transparent, inspectable decision engine. We showed how real-time audit trails, one-time human approval tokens, and strict execution gates work together to prevent silent failures and uncontrolled autonomy. This approach allows us to retain the power of agentic workflows while embedding accountability directly into the execution loop. Ultimately, we demonstrated that strong governance does not slow agents down; instead, it makes them safer, more trustworthy, and better prepared for real-world deployment in regulated, high-risk environments.<\/p>\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n<p>Check out the\u00a0<strong><a href=\"https:\/\/github.com\/Marktechpost\/AI-Tutorial-Codes-Included\/blob\/main\/Agentic%20Workflows\/glass_box_governance_auditable_human_in_loop_agentic_workflows_Marktechpost.ipynb\" target=\"_blank\" rel=\"noreferrer noopener\">FULL CODES here<\/a>.\u00a0<\/strong>Also,\u00a0feel free to follow us on\u00a0<strong><a href=\"https:\/\/x.com\/intent\/follow?screen_name=marktechpost\" target=\"_blank\" rel=\"noreferrer noopener\"><mark>Twitter<\/mark><\/a><\/strong>\u00a0and don\u2019t forget to join our\u00a0<strong><a href=\"https:\/\/www.reddit.com\/r\/machinelearningnews\/\" target=\"_blank\" rel=\"noreferrer noopener\">100k+ ML SubReddit<\/a><\/strong>\u00a0and Subscribe to\u00a0<strong><a href=\"https:\/\/www.aidevsignals.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">our Newsletter<\/a><\/strong>. Wait! are you on telegram?\u00a0<strong><a href=\"https:\/\/t.me\/machinelearningresearchnews\" target=\"_blank\" rel=\"noreferrer noopener\">now you can join us on telegram as well.<\/a><\/strong><\/p>\n<p>The post <a href=\"https:\/\/www.marktechpost.com\/2026\/02\/19\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/\">How to Build Transparent AI Agents: Traceable Decision-Making with Audit Trails and Human Gates<\/a> appeared first on <a href=\"https:\/\/www.marktechpost.com\/\">MarkTechPost<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>In this tutorial, we build a glass-box agentic workflow that makes every decision traceable, auditable, and explicitly governed by human approval. We design the system to log each thought, action, and observation into a tamper-evident audit ledger while enforcing dynamic permissioning for high-risk operations. By combining LangGraph\u2019s interrupt-driven human-in-the-loop control with a hash-chained database, we demonstrate how agentic systems can move beyond opaque automation and align with modern governance expectations. Throughout the tutorial, we focus on practical, runnable patterns that turn governance from an afterthought into a first-class system feature. Copy CodeCopiedUse a different Browser !pip -q install -U langgraph langchain-core openai &#8220;pydantic&lt;=2.12.3&#8221; import os import json import time import hmac import hashlib import secrets import sqlite3 import getpass from typing import Any, Dict, List, Optional, Literal, TypedDict from openai import OpenAI from langchain_core.messages import SystemMessage, HumanMessage, AIMessage from langgraph.graph import StateGraph, END from langgraph.types import interrupt, Command if not os.getenv(&#8220;OPENAI_API_KEY&#8221;): os.environ[&#8220;OPENAI_API_KEY&#8221;] = getpass.getpass(&#8220;Enter OpenAI API Key: &#8220;) client = OpenAI() MODEL = &#8220;gpt-5&#8221; We install all required libraries and import the core modules needed for agentic workflows and governance. We securely collect the OpenAI API key through a terminal prompt to avoid hard-coding secrets in the notebook. We also initialize the OpenAI client and define the model that drives the agent\u2019s reasoning loop. Copy CodeCopiedUse a different Browser CREATE_SQL = &#8220;&#8221;&#8221; CREATE TABLE IF NOT EXISTS audit_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, ts_unix INTEGER NOT NULL, actor TEXT NOT NULL, event_type TEXT NOT NULL, payload_json TEXT NOT NULL, prev_hash TEXT NOT NULL, row_hash TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS ot_tokens ( token_id TEXT PRIMARY KEY, token_hash TEXT NOT NULL, purpose TEXT NOT NULL, expires_unix INTEGER NOT NULL, used INTEGER NOT NULL DEFAULT 0 ); &#8220;&#8221;&#8221; def _sha256_hex(s: bytes) -&gt; str: return hashlib.sha256(s).hexdigest() def _canonical_json(obj: Any) -&gt; str: return json.dumps(obj, sort_keys=True, separators=(&#8220;,&#8221;, &#8220;:&#8221;), ensure_ascii=False) class AuditLedger: def __init__(self, path: str = &#8220;glassbox_audit.db&#8221;): self.conn = sqlite3.connect(path, check_same_thread=False) self.conn.executescript(CREATE_SQL) self.conn.commit() def _last_hash(self) -&gt; str: row = self.conn.execute(&#8220;SELECT row_hash FROM audit_log ORDER BY id DESC LIMIT 1&#8221;).fetchone() return row[0] if row else &#8220;GENESIS&#8221; def append(self, actor: str, event_type: str, payload: Any) -&gt; int: ts = int(time.time()) prev_hash = self._last_hash() payload_json = _canonical_json(payload) material = f&#8221;{ts}|{actor}|{event_type}|{payload_json}|{prev_hash}&#8221;.encode(&#8220;utf-8&#8221;) row_hash = _sha256_hex(material) cur = self.conn.execute( &#8220;INSERT INTO audit_log (ts_unix, actor, event_type, payload_json, prev_hash, row_hash) VALUES (?, ?, ?, ?, ?, ?)&#8221;, (ts, actor, event_type, payload_json, prev_hash, row_hash), ) self.conn.commit() return cur.lastrowid def fetch_recent(self, limit: int = 50) -&gt; List[Dict[str, Any]]: rows = self.conn.execute( &#8220;SELECT id, ts_unix, actor, event_type, payload_json, prev_hash, row_hash FROM audit_log ORDER BY id DESC LIMIT ?&#8221;, (limit,), ).fetchall() out = [] for r in rows[::-1]: out.append({ &#8220;id&#8221;: r[0], &#8220;ts_unix&#8221;: r[1], &#8220;actor&#8221;: r[2], &#8220;event_type&#8221;: r[3], &#8220;payload&#8221;: json.loads(r[4]), &#8220;prev_hash&#8221;: r[5], &#8220;row_hash&#8221;: r[6], }) return out def verify_integrity(self) -&gt; Dict[str, Any]: rows = self.conn.execute( &#8220;SELECT id, ts_unix, actor, event_type, payload_json, prev_hash, row_hash FROM audit_log ORDER BY id ASC&#8221; ).fetchall() if not rows: return {&#8220;ok&#8221;: True, &#8220;rows&#8221;: 0, &#8220;message&#8221;: &#8220;Empty ledger.&#8221;} expected_prev = &#8220;GENESIS&#8221; for (id_, ts, actor, event_type, payload_json, prev_hash, row_hash) in rows: if prev_hash != expected_prev: return {&#8220;ok&#8221;: False, &#8220;at_id&#8221;: id_, &#8220;reason&#8221;: &#8220;prev_hash mismatch&#8221;} material = f&#8221;{ts}|{actor}|{event_type}|{payload_json}|{prev_hash}&#8221;.encode(&#8220;utf-8&#8221;) expected_hash = _sha256_hex(material) if not hmac.compare_digest(expected_hash, row_hash): return {&#8220;ok&#8221;: False, &#8220;at_id&#8221;: id_, &#8220;reason&#8221;: &#8220;row_hash mismatch&#8221;} expected_prev = row_hash return {&#8220;ok&#8221;: True, &#8220;rows&#8221;: len(rows), &#8220;message&#8221;: &#8220;Hash chain valid.&#8221;} ledger = AuditLedger() We design a hash-chained SQLite ledger that records every agent and system event in an append-only manner. We ensure each log entry cryptographically links to the previous one, making post-hoc tampering detectable. We also provide utilities to inspect recent events and verify the integrity of the entire audit chain. Copy CodeCopiedUse a different Browser def mint_one_time_token(purpose: str, ttl_seconds: int = 600) -&gt; Dict[str, str]: token_id = secrets.token_hex(12) token_plain = secrets.token_urlsafe(20) token_hash = _sha256_hex(token_plain.encode(&#8220;utf-8&#8221;)) expires = int(time.time()) + ttl_seconds ledger.conn.execute( &#8220;INSERT INTO ot_tokens (token_id, token_hash, purpose, expires_unix, used) VALUES (?, ?, ?, ?, 0)&#8221;, (token_id, token_hash, purpose, expires), ) ledger.conn.commit() return {&#8220;token_id&#8221;: token_id, &#8220;token_plain&#8221;: token_plain, &#8220;purpose&#8221;: purpose, &#8220;expires_unix&#8221;: str(expires)} def consume_one_time_token(token_id: str, token_plain: str, purpose: str) -&gt; bool: row = ledger.conn.execute( &#8220;SELECT token_hash, purpose, expires_unix, used FROM ot_tokens WHERE token_id = ?&#8221;, (token_id,), ).fetchone() if not row: return False token_hash_db, purpose_db, expires_unix, used = row if used == 1: return False if purpose_db != purpose: return False if int(time.time()) &gt; int(expires_unix): return False token_hash_in = _sha256_hex(token_plain.encode(&#8220;utf-8&#8221;)) if not hmac.compare_digest(token_hash_in, token_hash_db): return False ledger.conn.execute(&#8220;UPDATE ot_tokens SET used = 1 WHERE token_id = ?&#8221;, (token_id,)) ledger.conn.commit() return True def tool_financial_transfer(amount_usd: float, to_account: str) -&gt; Dict[str, Any]: return {&#8220;status&#8221;: &#8220;success&#8221;, &#8220;transfer_id&#8221;: &#8220;tx_&#8221; + secrets.token_hex(6), &#8220;amount_usd&#8221;: amount_usd, &#8220;to_account&#8221;: to_account} def tool_rig_move(rig_id: str, direction: Literal[&#8220;UP&#8221;, &#8220;DOWN&#8221;], meters: float) -&gt; Dict[str, Any]: return {&#8220;status&#8221;: &#8220;success&#8221;, &#8220;rig_event_id&#8221;: &#8220;rig_&#8221; + secrets.token_hex(6), &#8220;rig_id&#8221;: rig_id, &#8220;direction&#8221;: direction, &#8220;meters&#8221;: meters} We implement a secure, single-use token mechanism that enables human approval for high-risk actions. We generate time-limited tokens, store only their hashes, and invalidate them immediately after use. We also define simulated restricted tools that represent sensitive operations such as financial transfers or physical rig movements. Copy CodeCopiedUse a different Browser RestrictedTool = Literal[&#8220;financial_transfer&#8221;, &#8220;rig_move&#8221;, &#8220;none&#8221;] class GlassBoxState(TypedDict): messages: List[Any] proposed_tool: RestrictedTool tool_args: Dict[str, Any] last_observation: Optional[Dict[str, Any]] SYSTEM_POLICY = &#8220;&#8221;&#8221;You are a governance-first agent. You MUST propose actions in a structured JSON format with these keys: &#8211; thought &#8211; action &#8211; args Return ONLY JSON.&#8221;&#8221;&#8221; def llm_propose_action(messages: List[Any]) -&gt; Dict[str, Any]: input_msgs = [{&#8220;role&#8221;: &#8220;system&#8221;, &#8220;content&#8221;: SYSTEM_POLICY}] for m in messages: if isinstance(m, SystemMessage): input_msgs.append({&#8220;role&#8221;: &#8220;system&#8221;, &#8220;content&#8221;: m.content}) elif isinstance(m, HumanMessage): input_msgs.append({&#8220;role&#8221;: &#8220;user&#8221;, &#8220;content&#8221;: m.content}) elif isinstance(m, AIMessage): input_msgs.append({&#8220;role&#8221;: &#8220;assistant&#8221;, &#8220;content&#8221;: m.content}) resp = client.responses.create(model=MODEL, input=input_msgs) txt = resp.output_text.strip() try: return json.loads(txt) except Exception: return {&#8220;thought&#8221;: &#8220;fallback&#8221;, &#8220;action&#8221;: &#8220;ask_human&#8221;, &#8220;args&#8221;: {}} def node_think(state: GlassBoxState) -&gt; GlassBoxState: proposal = llm_propose_action(state[&#8220;messages&#8221;]) ledger.append(&#8220;agent&#8221;, &#8220;THOUGHT&#8221;, {&#8220;thought&#8221;: proposal.get(&#8220;thought&#8221;)}) ledger.append(&#8220;agent&#8221;, &#8220;ACTION&#8221;, proposal) action = proposal.get(&#8220;action&#8221;, &#8220;no_op&#8221;) args = proposal.get(&#8220;args&#8221;, {}) if action in [&#8220;financial_transfer&#8221;, &#8220;rig_move&#8221;]: state[&#8220;proposed_tool&#8221;] = action state[&#8220;tool_args&#8221;] = args else: state[&#8220;proposed_tool&#8221;] = &#8220;none&#8221; state[&#8220;tool_args&#8221;] = {} return state def node_permission_gate(state: GlassBoxState) -&gt; GlassBoxState: if state[&#8220;proposed_tool&#8221;] == &#8220;none&#8221;: return state token = mint_one_time_token(state[&#8220;proposed_tool&#8221;]) payload = {&#8220;token_id&#8221;: token[&#8220;token_id&#8221;], &#8220;token_plain&#8221;: token[&#8220;token_plain&#8221;]} human_input = interrupt(payload) state[&#8220;tool_args&#8221;][&#8220;_token_id&#8221;] = token[&#8220;token_id&#8221;] state[&#8220;tool_args&#8221;][&#8220;_human_token_plain&#8221;] = str(human_input) return state<\/p>","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"pmpro_default_level":"","site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"_pvb_checkbox_block_on_post":false,"footnotes":""},"categories":[52,5,7,1],"tags":[],"class_list":["post-72486","post","type-post","status-publish","format-standard","hentry","category-ai-club","category-committee","category-news","category-uncategorized","pmpro-has-access"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v25.3 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to Build Transparent AI Agents: Traceable Decision-Making with Audit Trails and Human Gates - YouZum<\/title>\n<meta name=\"description\" content=\"\u0e01\u0e34\u0e08\u0e01\u0e23\u0e23\u0e21\u0e40\u0e01\u0e35\u0e48\u0e22\u0e27\u0e01\u0e31\u0e1a\u0e42\u0e14\u0e23\u0e19\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/youzum.net\/th\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/\" \/>\n<meta property=\"og:locale\" content=\"th_TH\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Build Transparent AI Agents: Traceable Decision-Making with Audit Trails and Human Gates - YouZum\" \/>\n<meta property=\"og:description\" content=\"\u0e01\u0e34\u0e08\u0e01\u0e23\u0e23\u0e21\u0e40\u0e01\u0e35\u0e48\u0e22\u0e27\u0e01\u0e31\u0e1a\u0e42\u0e14\u0e23\u0e19\" \/>\n<meta property=\"og:url\" content=\"https:\/\/youzum.net\/th\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/\" \/>\n<meta property=\"og:site_name\" content=\"YouZum\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/DroneAssociationTH\/\" \/>\n<meta property=\"article:published_time\" content=\"2026-02-20T11:51:04+00:00\" \/>\n<meta name=\"author\" content=\"admin NU\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin NU\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 \u0e19\u0e32\u0e17\u0e35\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/\"},\"author\":{\"name\":\"admin NU\",\"@id\":\"https:\/\/yousum.gpucore.co\/#\/schema\/person\/97fa48242daf3908e4d9a5f26f4a059c\"},\"headline\":\"How to Build Transparent AI Agents: Traceable Decision-Making with Audit Trails and Human Gates\",\"datePublished\":\"2026-02-20T11:51:04+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/\"},\"wordCount\":533,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/yousum.gpucore.co\/#organization\"},\"articleSection\":[\"AI\",\"Committee\",\"News\",\"Uncategorized\"],\"inLanguage\":\"th\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/\",\"url\":\"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/\",\"name\":\"How to Build Transparent AI Agents: Traceable Decision-Making with Audit Trails and Human Gates - YouZum\",\"isPartOf\":{\"@id\":\"https:\/\/yousum.gpucore.co\/#website\"},\"datePublished\":\"2026-02-20T11:51:04+00:00\",\"description\":\"\u0e01\u0e34\u0e08\u0e01\u0e23\u0e23\u0e21\u0e40\u0e01\u0e35\u0e48\u0e22\u0e27\u0e01\u0e31\u0e1a\u0e42\u0e14\u0e23\u0e19\",\"breadcrumb\":{\"@id\":\"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/#breadcrumb\"},\"inLanguage\":\"th\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/youzum.net\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Build Transparent AI Agents: Traceable Decision-Making with Audit Trails and Human Gates\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/yousum.gpucore.co\/#website\",\"url\":\"https:\/\/yousum.gpucore.co\/\",\"name\":\"YouSum\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/yousum.gpucore.co\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/yousum.gpucore.co\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"th\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/yousum.gpucore.co\/#organization\",\"name\":\"Drone Association Thailand\",\"url\":\"https:\/\/yousum.gpucore.co\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"th\",\"@id\":\"https:\/\/yousum.gpucore.co\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/youzum.net\/wp-content\/uploads\/2024\/11\/tranparent-logo.png\",\"contentUrl\":\"https:\/\/youzum.net\/wp-content\/uploads\/2024\/11\/tranparent-logo.png\",\"width\":300,\"height\":300,\"caption\":\"Drone Association Thailand\"},\"image\":{\"@id\":\"https:\/\/yousum.gpucore.co\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/DroneAssociationTH\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/yousum.gpucore.co\/#\/schema\/person\/97fa48242daf3908e4d9a5f26f4a059c\",\"name\":\"admin NU\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"th\",\"@id\":\"https:\/\/yousum.gpucore.co\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/youzum.net\/wp-content\/uploads\/avatars\/2\/1746849356-bpfull.png\",\"contentUrl\":\"https:\/\/youzum.net\/wp-content\/uploads\/avatars\/2\/1746849356-bpfull.png\",\"caption\":\"admin NU\"},\"url\":\"https:\/\/youzum.net\/th\/members\/adminnu\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to Build Transparent AI Agents: Traceable Decision-Making with Audit Trails and Human Gates - YouZum","description":"\u0e01\u0e34\u0e08\u0e01\u0e23\u0e23\u0e21\u0e40\u0e01\u0e35\u0e48\u0e22\u0e27\u0e01\u0e31\u0e1a\u0e42\u0e14\u0e23\u0e19","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/youzum.net\/th\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/","og_locale":"th_TH","og_type":"article","og_title":"How to Build Transparent AI Agents: Traceable Decision-Making with Audit Trails and Human Gates - YouZum","og_description":"\u0e01\u0e34\u0e08\u0e01\u0e23\u0e23\u0e21\u0e40\u0e01\u0e35\u0e48\u0e22\u0e27\u0e01\u0e31\u0e1a\u0e42\u0e14\u0e23\u0e19","og_url":"https:\/\/youzum.net\/th\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/","og_site_name":"YouZum","article_publisher":"https:\/\/www.facebook.com\/DroneAssociationTH\/","article_published_time":"2026-02-20T11:51:04+00:00","author":"admin NU","twitter_card":"summary_large_image","twitter_misc":{"Written by":"admin NU","Est. reading time":"9 \u0e19\u0e32\u0e17\u0e35"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/#article","isPartOf":{"@id":"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/"},"author":{"name":"admin NU","@id":"https:\/\/yousum.gpucore.co\/#\/schema\/person\/97fa48242daf3908e4d9a5f26f4a059c"},"headline":"How to Build Transparent AI Agents: Traceable Decision-Making with Audit Trails and Human Gates","datePublished":"2026-02-20T11:51:04+00:00","mainEntityOfPage":{"@id":"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/"},"wordCount":533,"commentCount":0,"publisher":{"@id":"https:\/\/yousum.gpucore.co\/#organization"},"articleSection":["AI","Committee","News","Uncategorized"],"inLanguage":"th","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/","url":"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/","name":"How to Build Transparent AI Agents: Traceable Decision-Making with Audit Trails and Human Gates - YouZum","isPartOf":{"@id":"https:\/\/yousum.gpucore.co\/#website"},"datePublished":"2026-02-20T11:51:04+00:00","description":"\u0e01\u0e34\u0e08\u0e01\u0e23\u0e23\u0e21\u0e40\u0e01\u0e35\u0e48\u0e22\u0e27\u0e01\u0e31\u0e1a\u0e42\u0e14\u0e23\u0e19","breadcrumb":{"@id":"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/#breadcrumb"},"inLanguage":"th","potentialAction":[{"@type":"ReadAction","target":["https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/youzum.net\/how-to-build-transparent-ai-agents-traceable-decision-making-with-audit-trails-and-human-gates\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/youzum.net\/"},{"@type":"ListItem","position":2,"name":"How to Build Transparent AI Agents: Traceable Decision-Making with Audit Trails and Human Gates"}]},{"@type":"WebSite","@id":"https:\/\/yousum.gpucore.co\/#website","url":"https:\/\/yousum.gpucore.co\/","name":"YouSum","description":"","publisher":{"@id":"https:\/\/yousum.gpucore.co\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/yousum.gpucore.co\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"th"},{"@type":"Organization","@id":"https:\/\/yousum.gpucore.co\/#organization","name":"Drone Association Thailand","url":"https:\/\/yousum.gpucore.co\/","logo":{"@type":"ImageObject","inLanguage":"th","@id":"https:\/\/yousum.gpucore.co\/#\/schema\/logo\/image\/","url":"https:\/\/youzum.net\/wp-content\/uploads\/2024\/11\/tranparent-logo.png","contentUrl":"https:\/\/youzum.net\/wp-content\/uploads\/2024\/11\/tranparent-logo.png","width":300,"height":300,"caption":"Drone Association Thailand"},"image":{"@id":"https:\/\/yousum.gpucore.co\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/DroneAssociationTH\/"]},{"@type":"Person","@id":"https:\/\/yousum.gpucore.co\/#\/schema\/person\/97fa48242daf3908e4d9a5f26f4a059c","name":"admin NU","image":{"@type":"ImageObject","inLanguage":"th","@id":"https:\/\/yousum.gpucore.co\/#\/schema\/person\/image\/","url":"https:\/\/youzum.net\/wp-content\/uploads\/avatars\/2\/1746849356-bpfull.png","contentUrl":"https:\/\/youzum.net\/wp-content\/uploads\/avatars\/2\/1746849356-bpfull.png","caption":"admin NU"},"url":"https:\/\/youzum.net\/th\/members\/adminnu\/"}]}},"rttpg_featured_image_url":null,"rttpg_author":{"display_name":"admin NU","author_link":"https:\/\/youzum.net\/th\/members\/adminnu\/"},"rttpg_comment":0,"rttpg_category":"<a href=\"https:\/\/youzum.net\/th\/category\/ai-club\/\" rel=\"category tag\">AI<\/a> <a href=\"https:\/\/youzum.net\/th\/category\/committee\/\" rel=\"category tag\">Committee<\/a> <a href=\"https:\/\/youzum.net\/th\/category\/news\/\" rel=\"category tag\">News<\/a> <a href=\"https:\/\/youzum.net\/th\/category\/uncategorized\/\" rel=\"category tag\">Uncategorized<\/a>","rttpg_excerpt":"In this tutorial, we build a glass-box agentic workflow that makes every decision traceable, auditable, and explicitly governed by human approval. We design the system to log each thought, action, and observation into a tamper-evident audit ledger while enforcing dynamic permissioning for high-risk operations. By combining LangGraph\u2019s interrupt-driven human-in-the-loop control with a hash-chained database, we&hellip;","_links":{"self":[{"href":"https:\/\/youzum.net\/th\/wp-json\/wp\/v2\/posts\/72486","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/youzum.net\/th\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/youzum.net\/th\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/youzum.net\/th\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/youzum.net\/th\/wp-json\/wp\/v2\/comments?post=72486"}],"version-history":[{"count":0,"href":"https:\/\/youzum.net\/th\/wp-json\/wp\/v2\/posts\/72486\/revisions"}],"wp:attachment":[{"href":"https:\/\/youzum.net\/th\/wp-json\/wp\/v2\/media?parent=72486"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/youzum.net\/th\/wp-json\/wp\/v2\/categories?post=72486"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/youzum.net\/th\/wp-json\/wp\/v2\/tags?post=72486"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}