<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Thanawat Wongchai</title>
    <description>The latest articles on DEV Community by Thanawat Wongchai (@thanawat_wonchai).</description>
    <link>https://dev.to/thanawat_wonchai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3821627%2F91172568-3a21-4fd5-9802-0ebae2983f0a.png</url>
      <title>DEV Community: Thanawat Wongchai</title>
      <link>https://dev.to/thanawat_wonchai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thanawat_wonchai"/>
    <language>en</language>
    <item>
      <title>Strands Agents คืออะไร? SDK โอเพนซอร์สสำหรับเอเจนต์ที่ขับเคลื่อนด้วยโมเดลจาก AWS</title>
      <dc:creator>Thanawat Wongchai</dc:creator>
      <pubDate>Fri, 26 Jun 2026 08:34:20 +0000</pubDate>
      <link>https://dev.to/thanawat_wonchai/strands-agents-khuueaair-sdk-oephnchrssamhrabeecchntthiikhabekhluuendwyomedlcchaak-aws-2nmi</link>
      <guid>https://dev.to/thanawat_wonchai/strands-agents-khuueaair-sdk-oephnchrssamhrabeecchntthiikhabekhluuendwyomedlcchaak-aws-2nmi</guid>
      <description>&lt;p&gt;หากคุณเคยสร้าง AI agent ด้วยการต่อ if/else หรือ state machine ขนาดใหญ่ คุณจะรู้ว่ามันเปราะบางเร็วแค่ไหน Strands Agents ใช้แนวทางตรงข้าม: ให้โมเดลวางแผนเอง และให้คุณกำหนดเพียง system prompt กับรายการเครื่องมือ เป็น SDK โอเพนซอร์สจาก AWS เปิดตัวในเดือนพฤษภาคม 2025 ภายใต้ &lt;a href="https://github.com/strands-agents/sdk-python" rel="noopener noreferrer"&gt;Apache License 2.0&lt;/a&gt; และถูกใช้เป็นส่วนหนึ่งของ agent ที่ใช้งานจริงภายในทีม Amazon เช่น Amazon Q Developer และ AWS Glue&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;ลองใช้ Apidog วันนี้&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Strands Agents คืออะไร
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://strandsagents.com/" rel="noopener noreferrer"&gt;Strands Agents&lt;/a&gt; คือ SDK สำหรับสร้างและรัน AI agent โดยใช้โครงสร้างหลัก 3 ส่วน:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Model&lt;/strong&gt;: โมเดลที่ใช้ reasoning และตัดสินใจ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System prompt&lt;/strong&gt;: คำสั่งหลักที่กำหนดบทบาทและขอบเขตของ agent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt;: ฟังก์ชันหรือบริการที่ agent เรียกใช้เพื่อทำงานจริง&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ลูปการทำงานคือ: โมเดลอ่านคำสั่ง → ตัดสินใจว่าจะใช้เครื่องมือใด → เรียกเครื่องมือ → อ่านผลลัพธ์ → ทำต่อจนกว่างานจะเสร็จ&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.apidog.com%2Fblog-next%2F2026%2F06%2Fimage-473.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.apidog.com%2Fblog-next%2F2026%2F06%2Fimage-473.png" alt="" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SDK รองรับทั้ง Python และ TypeScript ชื่อ “Strands” สื่อถึงสองเส้นหลักของ agent: &lt;strong&gt;โมเดล&lt;/strong&gt; และ &lt;strong&gt;เครื่องมือ&lt;/strong&gt; AWS เปิดโอเพนซอร์สหลังจากใช้งานภายในองค์กรแล้ว จึงสะท้อนโจทย์การใช้งานจริงมากกว่าตัวอย่างเดโมทั่วไป&lt;/p&gt;

&lt;p&gt;ตั้งแต่รุ่นพรีวิว Strands มียอดดาวน์โหลดบน PyPI มากกว่า 150,000 ครั้ง และเวอร์ชัน 1.0 เพิ่มพื้นฐานสำหรับ multi-agent รวมถึงรองรับโปรโตคอล Agent-to-Agent หรือ A2A&lt;/p&gt;

&lt;p&gt;ถ้าคุณเคยใช้เฟรมเวิร์กอย่าง &lt;a href="https://apidog.com/th/blog/langgraph?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;LangGraph&lt;/a&gt; หรือ &lt;a href="https://apidog.com/th/blog/google-adk?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Google ADK&lt;/a&gt; แนวคิดจะคุ้นเคย แต่ Strands เน้นให้โมเดลควบคุม flow มากกว่าให้คุณวาด graph เองทุกขั้น&lt;/p&gt;

&lt;h2&gt;
  
  
  แนวคิดหลัก: model-driven แทน hard-coded orchestration
&lt;/h2&gt;

&lt;p&gt;เฟรมเวิร์ก agent หลายตัวให้คุณกำหนด workflow ล่วงหน้า เช่น node, edge, condition และ routing วิธีนี้ควบคุมได้ดี แต่ทุกความสามารถใหม่มักหมายถึง graph ที่ซับซ้อนขึ้น&lt;/p&gt;

&lt;p&gt;Strands ย้ายภาระการวางแผนไปให้โมเดล คุณกำหนดเป้าหมายและเครื่องมือ จากนั้นโมเดลเลือกขั้นตอนเอง&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;แนวทาง&lt;/th&gt;
&lt;th&gt;คุณต้องกำหนด&lt;/th&gt;
&lt;th&gt;Flow ถูกควบคุมโดย&lt;/th&gt;
&lt;th&gt;เมื่อเพิ่มความสามารถใหม่&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hard-coded orchestration&lt;/td&gt;
&lt;td&gt;Node, edge, condition, routing&lt;/td&gt;
&lt;td&gt;โค้ด graph&lt;/td&gt;
&lt;td&gt;แก้ graph และทดสอบ path ใหม่&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model-driven ด้วย Strands&lt;/td&gt;
&lt;td&gt;Prompt + tools&lt;/td&gt;
&lt;td&gt;Reasoning loop ของโมเดล&lt;/td&gt;
&lt;td&gt;เพิ่ม tool และปรับ prompt&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ข้อแลกเปลี่ยนคือ model-driven สร้างเร็วและปรับง่ายกว่า แต่ผลลัพธ์อาจคาดเดายากกว่า graph ที่ล็อกทุกสาขาไว้ล่วงหน้า หาก workflow ต้องทำเหมือนเดิมทุกครั้ง คุณยังใช้ hooks หรือ multi-agent pattern เพื่อเพิ่มโครงสร้างได้&lt;/p&gt;

&lt;h2&gt;
  
  
  สร้าง Strands agent ตัวแรก
&lt;/h2&gt;

&lt;p&gt;ตัวอย่างที่เล็กที่สุดคือ agent ที่มี tool หนึ่งตัว:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;

&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;word_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Count the words in a block of text.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are a concise writing assistant.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;word_count&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How many words are in this sentence?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จุดที่ควรสังเกต:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@tool&lt;/code&gt; แปลงฟังก์ชัน Python ปกติให้โมเดลเรียกใช้ได้&lt;/li&gt;
&lt;li&gt;Docstring กลายเป็นคำอธิบาย tool&lt;/li&gt;
&lt;li&gt;Type hints กลายเป็น input schema&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;agent(...)&lt;/code&gt; จะรัน reasoning loop จนกว่าโมเดลจะเห็นว่างานเสร็จ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ในโปรเจกต์จริง ให้เขียน tool ให้เล็ก ชัดเจน และคืนค่าที่มีโครงสร้าง เช่น &lt;code&gt;dict&lt;/code&gt; หรือ object ที่ schema คงที่ เพื่อให้ทดสอบง่าย&lt;/p&gt;

&lt;p&gt;ตัวอย่าง tool ที่เรียก HTTP API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Fetch a user profile by user ID.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.example.com/users/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แนวทางที่ควรทำ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ตั้ง timeout ทุกครั้ง&lt;/li&gt;
&lt;li&gt;handle error จาก API ให้ชัดเจน&lt;/li&gt;
&lt;li&gt;คืน response ที่ predictable&lt;/li&gt;
&lt;li&gt;แยก config เช่น base URL และ API key ออกจากโค้ด&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  เลือก model provider
&lt;/h2&gt;

&lt;p&gt;Strands ใช้ Amazon Bedrock เป็น provider เริ่มต้น และโดยทั่วไป agent จะใช้ Claude Sonnet ใน region &lt;code&gt;us-west-2&lt;/code&gt; แต่ ID ของโมเดลเริ่มต้นอาจเปลี่ยนตามเวอร์ชัน SDK ดังนั้นควรตรวจสอบจากเวอร์ชันที่ติดตั้ง ไม่ควร hard-code โดยไม่ตรวจสอบ&lt;/p&gt;

&lt;p&gt;Provider ที่ใช้งานได้รวมถึง:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon Bedrock model ที่รองรับ tool use และ streaming&lt;/li&gt;
&lt;li&gt;Anthropic Claude ผ่าน Anthropic API&lt;/li&gt;
&lt;li&gt;Llama ผ่าน Llama API&lt;/li&gt;
&lt;li&gt;Ollama สำหรับ local development&lt;/li&gt;
&lt;li&gt;Provider อื่น เช่น OpenAI ผ่าน LiteLLM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;แนวคิดสำคัญคือการเปลี่ยน provider ควรเป็นการเปลี่ยน model object ไม่ใช่เขียน agent ใหม่ทั้งหมด ดังนั้นคุณสามารถ prototype ด้วย Ollama ในเครื่อง แล้ว deploy ด้วย Bedrock ได้โดยยังใช้ prompt และ tools ชุดเดิม&lt;/p&gt;

&lt;h2&gt;
  
  
  ใช้ tools และ MCP ให้คุ้ม
&lt;/h2&gt;

&lt;p&gt;Tool คือช่องทางที่ agent ใช้ติดต่อโลกภายนอก อาจเป็น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ฟังก์ชัน Python ที่คุณเขียนเอง&lt;/li&gt;
&lt;li&gt;เครื่องมือจาก community&lt;/li&gt;
&lt;li&gt;HTTP API ที่ห่อด้วยฟังก์ชัน&lt;/li&gt;
&lt;li&gt;MCP server ที่ expose tools หลายตัว&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://apidog.com/th/blog/what-is-mcp-model-context-protocol?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;MCP หรือ Model Context Protocol&lt;/a&gt; เป็นมาตรฐานเปิดสำหรับเชื่อมโมเดลกับเครื่องมือและแหล่งข้อมูล เมื่อใช้กับ Strands คุณสามารถเชื่อมต่อ MCP server แล้วส่ง tools เหล่านั้นให้ agent ได้โดยตรง&lt;/p&gt;

&lt;p&gt;แนวทางใช้งานที่ practical:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;เริ่มจาก tool ที่เขียนเองก่อน หาก logic ยังเล็ก&lt;/li&gt;
&lt;li&gt;ใช้ MCP เมื่อคุณมีระบบภายนอกหลายตัวหรือมี MCP server อยู่แล้ว&lt;/li&gt;
&lt;li&gt;ทดสอบ MCP server แยกจาก agent เสมอ&lt;/li&gt;
&lt;li&gt;กำหนด fallback behavior เมื่อ tool หรือ MCP server ล่ม&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ถ้า MCP server มีปัญหา agent อาจดูเหมือน “โมเดลตอบผิด” ทั้งที่จริงแล้ว dependency ด้าน API ล้มเหลว ดังนั้นควรแยกทดสอบ transport, auth, response schema และ error case ให้ครบ&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-agent และ A2A
&lt;/h2&gt;

&lt;p&gt;Agent ตัวเดียวเพียงพอสำหรับหลาย use case แต่ระบบจริงอาจต้องแบ่งงานเป็นหลาย agent เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;agent หนึ่งวิเคราะห์ requirement&lt;/li&gt;
&lt;li&gt;agent หนึ่งเรียก API&lt;/li&gt;
&lt;li&gt;agent หนึ่งสรุปผลลัพธ์&lt;/li&gt;
&lt;li&gt;agent หนึ่งตรวจสอบความถูกต้อง&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Strands 1.0 เพิ่มพื้นฐานสำหรับ multi-agent เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent-as-Tool&lt;/strong&gt;: ให้ agent หนึ่งถูกเรียกเหมือน tool โดย agent อื่น&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swarm coordination&lt;/strong&gt;: ให้หลาย agent ร่วมกันแก้ปัญหา&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A2A protocol&lt;/strong&gt;: ให้ Strands agent สื่อสารกับ agent จากเฟรมเวิร์กอื่นได้&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ใช้ multi-agent เมื่อบทบาทแยกกันชัดเจน อย่าแยกเพียงเพราะอยากให้ architecture ดูซับซ้อนขึ้น เพราะทุก agent ที่เพิ่มเข้ามาคือ surface area เพิ่มขึ้นสำหรับ latency, cost และ debugging&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy Strands agent
&lt;/h2&gt;

&lt;p&gt;Strands ถูกออกแบบให้ย้ายจาก local development ไป production ได้โดยไม่ต้องเปลี่ยนเฟรมเวิร์ก เป้าหมาย deployment ที่พบบ่อยคือ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon Bedrock AgentCore สำหรับ managed agent runtime&lt;/li&gt;
&lt;li&gt;AWS Lambda สำหรับ event-driven agent อายุสั้น&lt;/li&gt;
&lt;li&gt;AWS Fargate หรือ Amazon EKS สำหรับ service แบบ container ที่รันต่อเนื่อง&lt;/li&gt;
&lt;li&gt;Docker runtime ทั่วไปใน environment ที่คุณควบคุมเอง&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Checklist ก่อน deploy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;แยก environment variables เช่น API keys, model ID, region&lt;/li&gt;
&lt;li&gt;ตั้ง timeout และ retry ให้ tool ที่เรียก network&lt;/li&gt;
&lt;li&gt;log tool calls และผลลัพธ์ที่สำคัญ&lt;/li&gt;
&lt;li&gt;ปิด logging สำหรับข้อมูลลับ&lt;/li&gt;
&lt;li&gt;ทดสอบ error cases เช่น API 401, 429, 500 และ timeout&lt;/li&gt;
&lt;li&gt;เพิ่ม observability hooks เพื่อติดตามว่าโมเดลเรียก tool ใดและตัดสินใจอย่างไร&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;เพราะ Strands agent เป็น Python หรือ TypeScript application ปกติ การ package จึงใช้แนวทางเดียวกับ backend service ทั่วไป&lt;/p&gt;

&lt;h2&gt;
  
  
  Apidog เหมาะกับส่วนไหนของ Strands workflow
&lt;/h2&gt;

&lt;p&gt;Strands ช่วยสร้าง agent แต่ไม่ได้สร้างหรือ validate API ที่ agent เรียกใช้ ในระบบจริง agent มักพึ่งพา HTTP endpoints อย่างน้อยสองกลุ่ม:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;LLM provider API ที่อยู่เบื้องหลัง model&lt;/li&gt;
&lt;li&gt;REST/tool API หรือ MCP endpoint ที่อยู่เบื้องหลัง tools&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ถ้า endpoint เหล่านี้ผิด schema, timeout, auth fail หรือคืน error ที่ไม่ได้คาดไว้ agent อาจล้มเหลวในรูปแบบที่ดูเหมือนปัญหาของโมเดล ทั้งที่จริงเป็นปัญหา API&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.apidog.com%2Fblog-next%2F2026%2F06%2Fimage-473.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.apidog.com%2Fblog-next%2F2026%2F06%2Fimage-473.png" alt="" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; ใช้ทดสอบและจำลอง API เหล่านี้ก่อนให้ agent เรียกจริง ตัวอย่าง workflow ที่ใช้ได้ทันที:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mock model หรือ tool endpoint&lt;/strong&gt; ระหว่างพัฒนา เพื่อไม่ต้องเสีย token หรือชน rate limit ทุกครั้ง ดูตัวอย่างแนวทางในบทความ &lt;a href="https://apidog.com/th/blog/ai-agent-apidog-test-harness?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;AI agent test harness ด้วย Apidog&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ตรวจ response schema ของ tools&lt;/strong&gt; เช่น field, type, status code และ error payload ด้วย &lt;a href="https://apidog.com/th/blog/api-assertions?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;API assertions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ตั้งค่า &lt;a href="https://apidog.com/th/blog/mock-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;mock API&lt;/a&gt;&lt;/strong&gt; เพื่อจำลอง success case และ failure case ที่ agent ต้อง handle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;จัดการ API keys ตาม environment&lt;/strong&gt; เช่น dev, staging และ production โดยไม่ hard-code credential ใน agent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;รัน regression test ใน CI&lt;/strong&gt; เพื่อให้รู้ทันทีเมื่อ backend contract เปลี่ยนและอาจทำให้ agent พัง&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apidog ไม่ใช่ agent framework และไม่ได้ orchestrate reasoning loop ให้ Strands ยังคงเป็นสมองของ agent ส่วน Apidog เป็น workbench สำหรับทดสอบ API, mock dependency และตรวจ contract ของ service ที่ agent เรียกใช้ คุณสามารถ &lt;a href="https://apidog.com/download?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ดาวน์โหลด Apidog&lt;/a&gt; แล้วเริ่ม mock tool endpoints ได้ภายในไม่กี่นาที&lt;/p&gt;

&lt;h2&gt;
  
  
  ตัวอย่าง workflow สำหรับทีม dev
&lt;/h2&gt;

&lt;p&gt;หากต้องการเริ่มใช้ Strands แบบเป็นระบบ ให้ใช้ขั้นตอนนี้:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;นิยาม use case ให้เล็ก&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เช่น “สรุปข้อมูล user จาก API แล้วตอบเป็น bullet”&lt;/li&gt;
&lt;li&gt;หลีกเลี่ยงงานกว้างเกินไปใน agent ตัวแรก&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;เขียน tools เป็นฟังก์ชันเล็ก&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;หนึ่ง tool ต่อหนึ่งความสามารถ&lt;/li&gt;
&lt;li&gt;ใช้ type hints และ docstring ชัดเจน&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;mock API ก่อนเรียกของจริง&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;สร้าง mock response สำหรับ success, not found, unauthorized, rate limit&lt;/li&gt;
&lt;li&gt;ตรวจว่า agent handle ทุกกรณีได้&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;เขียน system prompt&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ระบุบทบาท&lt;/li&gt;
&lt;li&gt;ระบุข้อจำกัด&lt;/li&gt;
&lt;li&gt;ระบุวิธีใช้ tool หากจำเป็น&lt;/li&gt;
&lt;li&gt;ระบุรูปแบบ output&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ทดสอบแบบ end-to-end&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ทดสอบ prompt + tool + API&lt;/li&gt;
&lt;li&gt;เก็บ log ของ tool calls เพื่อ debug&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;เพิ่ม observability ก่อน production&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;trace การเรียก tool&lt;/li&gt;
&lt;li&gt;record latency&lt;/li&gt;
&lt;li&gt;monitor error rate&lt;/li&gt;
&lt;li&gt;ตรวจ cost จาก model provider&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ควรใช้ Strands Agents เมื่อใด
&lt;/h2&gt;

&lt;p&gt;เลือกใช้ Strands เมื่อ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;คุณต้องการสร้าง agent ได้เร็ว&lt;/li&gt;
&lt;li&gt;คุณเชื่อให้โมเดลวางแผนขั้นตอนเองได้&lt;/li&gt;
&lt;li&gt;คุณใช้งาน AWS หรือ Bedrock อยู่แล้ว&lt;/li&gt;
&lt;li&gt;คุณต้องการเริ่มจาก agent ตัวเดียวแล้วค่อยขยายเป็น multi-agent&lt;/li&gt;
&lt;li&gt;คุณต้องการใช้ MCP tools โดยไม่เขียน integration เองทั้งหมด&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;อาจไม่เหมาะเมื่อ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;workflow ต้อง deterministic มาก&lt;/li&gt;
&lt;li&gt;ทุก branch ต้องถูกกำหนดล่วงหน้า&lt;/li&gt;
&lt;li&gt;compliance ต้องตรวจ flow แบบ static ได้ละเอียด&lt;/li&gt;
&lt;li&gt;คุณต้องการ graph-based orchestration เป็นแกนหลัก&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;สรุปคือ Strands เหมาะกับงาน model-driven ส่วน graph-based framework เหมาะกับงานที่ต้องควบคุม path อย่างเข้มงวด หลายทีมสามารถใช้ทั้งสองแนวทางใน service คนละประเภทได้&lt;/p&gt;

&lt;h2&gt;
  
  
  คำถามที่พบบ่อย
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Strands Agents เป็นโอเพนซอร์สและใช้ฟรีหรือไม่
&lt;/h3&gt;

&lt;p&gt;ใช่ Strands Agents เป็นโอเพนซอร์สภายใต้ Apache License 2.0 และมีซอร์สโค้ดบน GitHub ไม่มีค่า license สำหรับ SDK แต่คุณยังต้องจ่ายค่า model provider และ cloud resource ที่ใช้ เช่น Bedrock inference หรือ Lambda execution&lt;/p&gt;

&lt;h3&gt;
  
  
  ต้องใช้ Amazon Bedrock กับ Strands หรือไม่
&lt;/h3&gt;

&lt;p&gt;ไม่จำเป็น Bedrock เป็น provider เริ่มต้น แต่ Strands รองรับ Anthropic API, Llama API, Ollama สำหรับ local development และ provider อื่นผ่าน LiteLLM คุณเปลี่ยน model object ได้โดยไม่ต้องเขียน agent ใหม่ทั้งหมด&lt;/p&gt;

&lt;h3&gt;
  
  
  Strands ต่างจาก framework แบบ graph-first อย่างไร
&lt;/h3&gt;

&lt;p&gt;Strands เป็น model-driven: คุณให้ prompt และ tools แล้วให้โมเดลตัดสินใจขั้นตอนเอง ส่วน graph-first framework ให้คุณกำหนด flow เป็น node และ edge ล่วงหน้า Strands ปรับเร็วกว่า แต่ graph-first ควบคุมได้ละเอียดและคาดเดาได้มากกว่า&lt;/p&gt;

&lt;h3&gt;
  
  
  จะทดสอบ API ที่ Strands agent พึ่งพาได้อย่างไร
&lt;/h3&gt;

&lt;p&gt;ให้ทดสอบแยกจาก agent ตั้งแต่ต้น Mock LLM และ tool endpoints, validate response schema และรัน test เหล่านี้ใน CI เครื่องมืออย่าง &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; ช่วยจัดการ mock และ assertion ได้ รวมถึงบทความ &lt;a href="https://apidog.com/th/blog/how-to-test-chatgpt-api-with-apidog?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;การทดสอบ ChatGPT API ด้วย Apidog&lt;/a&gt; ที่ครอบคลุม authentication, streaming และ tool-call testing&lt;/p&gt;

&lt;h2&gt;
  
  
  สรุป
&lt;/h2&gt;

&lt;p&gt;Strands Agents เสนอวิธีสร้าง agent ที่เรียบง่าย: กำหนด model, prompt และ tools แล้วให้โมเดลรัน reasoning loop เอง มันเริ่มจาก agent ตัวเดียวได้ ขยายเป็น multi-agent ได้ รองรับ MCP และ A2A และ deploy บน AWS stack ได้โดยไม่ต้องเปลี่ยน architecture หลัก&lt;/p&gt;

&lt;p&gt;งานของคุณคือทำให้ tools และ API ที่ agent เรียกใช้มี contract ชัดเจน ทดสอบได้ และล้มเหลวแบบคาดเดาได้ ตรงนี้คือจุดที่ Apidog ช่วยได้: mock, test และ validate endpoints ก่อนที่ปัญหาจะไปโผล่ใน production&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Semantic Kernel คืออะไร: SDK จัดการ AI ของ Microsoft</title>
      <dc:creator>Thanawat Wongchai</dc:creator>
      <pubDate>Fri, 26 Jun 2026 08:29:04 +0000</pubDate>
      <link>https://dev.to/thanawat_wonchai/semantic-kernel-khuueaair-sdk-cchadkaar-ai-khng-microsoft-2ke6</link>
      <guid>https://dev.to/thanawat_wonchai/semantic-kernel-khuueaair-sdk-cchadkaar-ai-khng-microsoft-2ke6</guid>
      <description>&lt;p&gt;หากคุณพัฒนาซอฟต์แวร์บน Microsoft stack และต้องการเพิ่ม AI โดยไม่ต้องผูกบริการ Python เข้าไปเสริม Semantic Kernel คือ SDK โอเพนซอร์สจาก Microsoft สำหรับเชื่อมโค้ดและ API ที่มีอยู่กับโมเดลภาษาขนาดใหญ่ รองรับ C#, Python และ Java บทความนี้สรุปวิธีใช้ Semantic Kernel แบบลงมือทำ: kernel, plugins, functions, การนำเข้า &lt;a href="https://apidog.com/th/blog/openapi-specification?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;OpenAPI specification&lt;/a&gt; และแนวทางทดสอบ API ที่เอเจนต์จะเรียกใช้งาน&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;ลองใช้ Apidog วันนี้&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Semantic Kernel คืออะไร
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/semantic-kernel/" rel="noopener noreferrer"&gt;Semantic Kernel (SK)&lt;/a&gt; เป็น SDK โอเพนซอร์สจาก Microsoft สำหรับสร้างเอเจนต์ AI และผสานโมเดลเข้ากับโค้ดเบสของคุณ มองง่ายๆ คือ middleware ระหว่างแอปพลิเคชันกับโมเดล: รับคำสั่งจากโมเดล แปลงเป็นการเรียกฟังก์ชันจริง รันโค้ด แล้วส่งผลลัพธ์กลับไปให้โมเดล&lt;/p&gt;

&lt;p&gt;จุดที่ทำให้ SK เหมาะกับงานจริงมี 3 เรื่องหลัก:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;รองรับหลายภาษา&lt;/strong&gt;: มี SDK อย่างเป็นทางการสำหรับ C#/.NET, Python และ Java พร้อมความเสถียรระดับ 1.0+&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ไม่ผูกกับโมเดลเดียว&lt;/strong&gt;: เชื่อมต่อ OpenAI, Azure OpenAI และผู้ให้บริการอื่นผ่าน connector ได้&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ออกแบบสำหรับองค์กร&lt;/strong&gt;: รองรับ telemetry, hooks และ filters เพื่อบันทึก ตรวจสอบ และควบคุมสิ่งที่ AI ทำ&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ถ้า backend ของคุณเป็น .NET และต้องการนำ AI เข้ามาโดยไม่สร้าง Python sidecar เพิ่ม Semantic Kernel เป็นตัวเลือกที่ควรพิจารณา&lt;/p&gt;

&lt;h2&gt;
  
  
  แกนหลัก: kernel, plugins และ functions
&lt;/h2&gt;

&lt;p&gt;ออบเจกต์หลักของ SK คือ &lt;code&gt;Kernel&lt;/code&gt; ซึ่งทำหน้าที่คล้าย dependency injection container สำหรับ AI คุณลงทะเบียน model connector และ plugin ไว้ใน kernel จากนั้นให้ kernel จัดการลูปการทำงาน:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;รับ prompt หรือข้อความจากผู้ใช้&lt;/li&gt;
&lt;li&gt;เรียกโมเดล&lt;/li&gt;
&lt;li&gt;ตรวจว่าต้องเรียก function หรือไม่&lt;/li&gt;
&lt;li&gt;รัน function จริงในโค้ดของคุณ&lt;/li&gt;
&lt;li&gt;ส่งผลลัพธ์กลับไปยังโมเดล&lt;/li&gt;
&lt;li&gt;คืนคำตอบสุดท้าย&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ใน SK มีแนวคิดสำคัญ 2 ระดับ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Plugin&lt;/strong&gt;: กลุ่มของฟังก์ชันที่เปิดให้โมเดลเรียกใช้&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Function&lt;/strong&gt;: ความสามารถหนึ่งรายการที่โมเดลสามารถเรียกได้&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ฟังก์ชันมี 2 ประเภทหลัก:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native functions&lt;/strong&gt;: เมธอดปกติในโค้ด เช่น C# method หรือ Python function ที่ annotate เพื่อให้โมเดลเข้าใจ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt functions&lt;/strong&gt;: prompt template ที่เรียกโมเดลอีกครั้ง เหมาะกับงานสรุป จัดหมวดหมู่ หรือ rewrite ข้อความ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง C# ขั้นพื้นฐาน:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenAIChatCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;modelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"gpt-4o"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddFromType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LightsPlugin&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"Lights"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;Kernel&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;InvokePromptAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"Turn the kitchen light blue"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตัวอย่าง plugin แบบ native function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.ComponentModel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LightsPlugin&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;KernelFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"change_light_state"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Change the state and color of a light"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;ChangeLightState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The room name, for example kitchen or bedroom"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The target color"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// เรียก service หรือ API จริงของคุณที่นี่&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;$"Changed &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;room&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; light to &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เมื่อโมเดลตัดสินใจว่า intent ของผู้ใช้ต้องใช้ &lt;code&gt;change_light_state&lt;/code&gt; kernel จะรันเมธอดจริง บันทึกผลลัพธ์ และส่งกลับไปยังโมเดลเพื่อสร้างคำตอบสุดท้าย&lt;/p&gt;

&lt;h2&gt;
  
  
  รูปแบบ OpenAPI-to-plugin
&lt;/h2&gt;

&lt;p&gt;จุดที่มีประโยชน์มากของ Semantic Kernel คือการนำเข้า OpenAPI specification แล้วเปลี่ยนแต่ละ operation ให้เป็น function ที่โมเดลเรียกได้โดยอัตโนมัติ&lt;/p&gt;

&lt;p&gt;แทนที่จะเขียน wrapper เองทุก endpoint คุณสามารถ:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;เตรียม OpenAPI spec ของ REST API&lt;/li&gt;
&lt;li&gt;ให้ SK import spec&lt;/li&gt;
&lt;li&gt;ให้โมเดลเรียก operation ที่เหมาะสมผ่าน function calling&lt;/li&gt;
&lt;li&gt;ให้ SK สร้าง HTTP request และจัดการ response&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ตัวอย่าง C#:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ImportPluginFromOpenApiAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;pluginName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"lights"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/v1/swagger.json"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;executionParameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OpenApiFunctionExecutionParameters&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;EnablePayloadNamespacing&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใน Python แนวคิดเดียวกันคือใช้ &lt;code&gt;add_plugin_from_openapi&lt;/code&gt; ส่วน Java ก็มี importer ที่เทียบเท่า&lt;/p&gt;

&lt;p&gt;เบื้องหลัง SK จะ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;อ่าน path และ operation จาก OpenAPI spec&lt;/li&gt;
&lt;li&gt;ดึงชื่อ คำอธิบาย parameter type และ schema&lt;/li&gt;
&lt;li&gt;แปลง operation เป็น callable function&lt;/li&gt;
&lt;li&gt;ส่ง metadata เหล่านี้ให้โมเดล&lt;/li&gt;
&lt;li&gt;สร้าง HTTP request เมื่อโมเดลเลือกเรียก operation&lt;/li&gt;
&lt;li&gt;อ่าน response แล้วส่งกลับเข้า context ของโมเดล&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SK รองรับ OpenAPI 2.0 และ 3.0 และสามารถ downgrade 3.1 เป็น 3.0 ได้หากทำได้&lt;/p&gt;

&lt;h3&gt;
  
  
  เช็กลิสต์สำหรับทำ OpenAPI spec ให้เหมาะกับเอเจนต์
&lt;/h3&gt;

&lt;p&gt;OpenAPI spec ที่เขียนเพื่อมนุษย์อ่านได้ อาจยังไม่ชัดพอสำหรับโมเดล ก่อนนำเข้า SK ควรตรวจรายการเหล่านี้:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ใช้ &lt;code&gt;operationId&lt;/code&gt; ที่สื่อความหมาย เช่น &lt;code&gt;getCustomerById&lt;/code&gt; แทน &lt;code&gt;getData&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;เขียน &lt;code&gt;description&lt;/code&gt; ของ endpoint ให้บอก intent ชัดเจน&lt;/li&gt;
&lt;li&gt;เขียนคำอธิบาย parameter ให้บอก format และข้อจำกัด&lt;/li&gt;
&lt;li&gt;ใช้ enum เมื่อค่าที่รับได้มีจำนวนจำกัด&lt;/li&gt;
&lt;li&gt;หลีกเลี่ยง string กว้างๆ ที่ไม่มี schema ชัดเจน&lt;/li&gt;
&lt;li&gt;แยก endpoint ที่จำเป็นจริงๆ ให้โมเดลใช้ ไม่ต้องเปิดทั้งระบบ&lt;/li&gt;
&lt;li&gt;ตรวจ response schema ให้ตรงกับของจริง&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง schema ที่ช่วยให้โมเดลเลือกใช้งานได้ดีขึ้น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;/lights/{room}/state&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;changeLightState&lt;/span&gt;
      &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Change light state in a specific room&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use this operation to change the color or power state of a room light.&lt;/span&gt;
      &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;room&lt;/span&gt;
          &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;path&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Room name, such as kitchen, bedroom, or living_room.&lt;/span&gt;
          &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
            &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;kitchen&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;bedroom&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;living_room&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;requestBody&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
              &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;color&lt;/span&gt;
              &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
                  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Target light color.&lt;/span&gt;
                  &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;red&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;blue&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;green&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;white&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;คุณภาพของ spec ส่งผลโดยตรงต่อคุณภาพของการเรียก tool ของเอเจนต์&lt;/p&gt;

&lt;h2&gt;
  
  
  เอเจนต์และการวางแผน
&lt;/h2&gt;

&lt;p&gt;Semantic Kernel เริ่มจากแนวคิด planner ที่แยกเป้าหมายเป็นขั้นตอน แต่แนวทางปัจจุบันขยับไปใช้ function calling มากขึ้น โดยให้โมเดลตัดสินใจเองว่าจะเรียก function ใดและเรียกตามลำดับใด ซึ่งเข้ากับโมเดลสมัยใหม่ได้ดีกว่า&lt;/p&gt;

&lt;p&gt;นอกจากนี้ SK ยังมี Agent Framework layer สำหรับ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;session-based state&lt;/li&gt;
&lt;li&gt;agent loop&lt;/li&gt;
&lt;li&gt;multi-agent pattern&lt;/li&gt;
&lt;li&gt;การเชื่อมต่อเครื่องมือภายนอกผ่าน Model Context Protocol (MCP)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ถ้าคุณกำลังเลือก framework สำหรับงานเอเจนต์ ภาพรวมเปรียบเทียบมีดังนี้:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;เฟรมเวิร์ก&lt;/th&gt;
&lt;th&gt;ภาษาหลัก&lt;/th&gt;
&lt;th&gt;โมเดลการจัดการ&lt;/th&gt;
&lt;th&gt;เหมาะที่สุดสำหรับ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Semantic Kernel&lt;/td&gt;
&lt;td&gt;C#/.NET, Python, Java&lt;/td&gt;
&lt;td&gt;การเรียกฟังก์ชัน + เอเจนต์&lt;/td&gt;
&lt;td&gt;ทีม .NET และองค์กร&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apidog.com/th/blog/langgraph?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;LangGraph&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Python, JS&lt;/td&gt;
&lt;td&gt;กราฟสถานะที่ชัดเจน&lt;/td&gt;
&lt;td&gt;เวิร์กโฟลว์เอเจนต์ที่ซับซ้อนและมีการแตกแขนง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apidog.com/th/blog/google-adk?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Google ADK&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;โมเดลเอเจนต์ + เครื่องมือ&lt;/td&gt;
&lt;td&gt;สแต็ก Google Cloud และ Gemini&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apidog.com/th/blog/how-to-use-openai-agents-sdk?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;OpenAI Agents SDK&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Python, JS&lt;/td&gt;
&lt;td&gt;เอเจนต์ + การส่งต่อ&lt;/td&gt;
&lt;td&gt;แอปที่เน้น OpenAI เป็นหลัก&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ไม่มีตัวเลือกที่ดีที่สุดสำหรับทุกกรณี ให้เลือกจากภาษาหลักของทีม provider ของโมเดล และระดับการควบคุม workflow ที่ต้องการ&lt;/p&gt;

&lt;h2&gt;
  
  
  Semantic Kernel เหมาะกับ Microsoft Agent Framework อย่างไร
&lt;/h2&gt;

&lt;p&gt;Microsoft ได้เปิดตัว Microsoft Agent Framework (MAF) และเอกสารระบุว่าเป็นผู้สืบทอดโดยตรงของทั้ง Semantic Kernel และ AutoGen ซึ่งพัฒนาโดยทีมเดียวกัน MAF รวมแนวคิดเอเจนต์จาก AutoGen เข้ากับคุณสมบัติระดับองค์กรของ SK และเพิ่ม workflow แบบ graph สำหรับ multi-agent orchestration&lt;/p&gt;

&lt;p&gt;ในทางปฏิบัติ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;แอป Semantic Kernel ที่มีอยู่ยังใช้งานต่อได้ และ SK ยังได้รับการสนับสนุน&lt;/li&gt;
&lt;li&gt;โปรเจกต์ใหม่ที่ต้องการทิศทางล่าสุดควรอ่านเอกสาร MAF ก่อนเริ่ม&lt;/li&gt;
&lt;li&gt;รูปแบบ OpenAPI-to-plugin ยังเป็นแนวทางสำคัญในทั้งสองเฟรมเวิร์ก&lt;/li&gt;
&lt;li&gt;ถ้าคุณมีโค้ด SK อยู่แล้ว ไม่จำเป็นต้องรีบย้ายทันที&lt;/li&gt;
&lt;li&gt;ถ้าคุณเริ่มใหม่และต้องทำ multi-agent ซับซ้อน ให้ประเมิน MAF ด้วย&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;สรุปคือ SK ยังเป็นตัวเลือกที่มั่นคงสำหรับ production โดยเฉพาะใน stack .NET ส่วน MAF คือทิศทางใหม่ที่ Microsoft กำลังลงทุนต่อ&lt;/p&gt;

&lt;h2&gt;
  
  
  เมื่อใดควรใช้ Semantic Kernel
&lt;/h2&gt;

&lt;p&gt;เลือกใช้ Semantic Kernel เมื่อ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;backend ของคุณคือ .NET หรือ Java&lt;/li&gt;
&lt;li&gt;คุณไม่ต้องการเพิ่ม Python service แยกเพื่อจัดการ AI&lt;/li&gt;
&lt;li&gt;คุณมี REST API อยู่แล้วและต้องการให้โมเดลเรียกผ่าน OpenAPI spec&lt;/li&gt;
&lt;li&gt;คุณต้องการ telemetry, filters, hooks และ auditability&lt;/li&gt;
&lt;li&gt;คุณต้องการเปลี่ยน provider ของโมเดลได้โดยไม่ rewrite ทั้งแอป&lt;/li&gt;
&lt;li&gt;คุณต้องการเริ่มจาก function calling ก่อน แล้วค่อยต่อยอดเป็น agent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ควรมองหาทางเลือกอื่นเมื่อ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ทีมใช้ Python เป็นหลักทั้งหมด&lt;/li&gt;
&lt;li&gt;ต้องการ multi-agent workflow ใหม่ล่าสุด&lt;/li&gt;
&lt;li&gt;ต้องการ graph-based orchestration ที่ควบคุม state ทุกจุดอย่างชัดเจน&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ในกรณีนั้น MAF หรือ framework แบบ graph-first อาจเหมาะกว่า&lt;/p&gt;

&lt;h2&gt;
  
  
  การทดสอบ API ที่อยู่เบื้องหลังเอเจนต์ Semantic Kernel
&lt;/h2&gt;

&lt;p&gt;Semantic Kernel ไม่ได้แทนที่ API ของคุณ แต่มันเรียกใช้ API เหล่านั้น ดังนั้นคุณภาพของเอเจนต์ขึ้นอยู่กับคุณภาพของ endpoint และ OpenAPI spec โดยตรง&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; มีประโยชน์ในจุดนี้ เพราะช่วยออกแบบ ทดสอบ mock และตรวจสัญญา API ก่อนนำไปใช้กับเอเจนต์&lt;/p&gt;

&lt;p&gt;งานที่ควรทำก่อนให้ SK import OpenAPI spec:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. ตรวจ OpenAPI spec ก่อนนำเข้า
&lt;/h3&gt;

&lt;p&gt;เพราะ SK ใช้ชื่อ operation, description, parameter และ schema จาก spec เพื่ออธิบาย tool ให้โมเดล ถ้า spec คลุมเครือ โมเดลก็มีโอกาสเรียก tool ผิด&lt;/p&gt;

&lt;p&gt;ตรวจให้ครบ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;endpoint มี &lt;code&gt;operationId&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;parameter มี type และ description&lt;/li&gt;
&lt;li&gt;request body มี schema&lt;/li&gt;
&lt;li&gt;response ตรงกับของจริง&lt;/li&gt;
&lt;li&gt;auth mechanism ชัดเจน&lt;/li&gt;
&lt;li&gt;error response ถูกระบุไว้&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Mock API ระหว่างพัฒนา
&lt;/h3&gt;

&lt;p&gt;ถ้า endpoint ยังไม่พร้อม คุณสามารถสร้าง &lt;a href="https://apidog.com/th/blog/mock-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;mock API&lt;/a&gt; เพื่อให้ SK เรียกได้ก่อน วิธีนี้ช่วยแยกการพัฒนา agent loop ออกจาก backend จริง&lt;/p&gt;

&lt;p&gt;ดูรูปแบบเพิ่มเติมได้ที่ &lt;a href="https://apidog.com/th/blog/how-to-mock-api-calls?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;วิธีจำลองการเรียกใช้ API&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. ยืนยัน response shape ด้วย assertions
&lt;/h3&gt;

&lt;p&gt;ใช้ &lt;a href="https://apidog.com/th/blog/api-assertions?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;API assertions&lt;/a&gt; เพื่อตรวจว่า endpoint ที่เอเจนต์เรียกยังส่ง response ตาม schema ที่คาดหวัง เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;field สำคัญต้องมีเสมอ&lt;/li&gt;
&lt;li&gt;type ต้องตรง&lt;/li&gt;
&lt;li&gt;status code ต้องถูกต้อง&lt;/li&gt;
&lt;li&gt;error format ต้องคงที่&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;วิธีนี้ช่วยลดกรณีที่ backend เปลี่ยนแล้วพฤติกรรมของเอเจนต์เสียโดยไม่รู้ตัว&lt;/p&gt;

&lt;h3&gt;
  
  
  4. แยก environment และ credential
&lt;/h3&gt;

&lt;p&gt;อย่าฮาร์ดโค้ด LLM key หรือ API key ในโค้ด agent ให้แยก environment เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dev&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;staging&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prod&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;และใช้ key คนละชุดสำหรับแต่ละ environment เพื่อลดความเสี่ยงและควบคุม quota ได้ง่ายขึ้น&lt;/p&gt;

&lt;p&gt;ถ้าต้องการตัวอย่างการทดสอบ tool call ของเอเจนต์แบบละเอียด ดู &lt;a href="https://apidog.com/th/blog/ai-agent-apidog-test-harness?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;การทดสอบการเรียกใช้เครื่องมือของเอเจนต์ด้วย Apidog&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  คำถามที่พบบ่อย
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Semantic Kernel เป็นโอเพนซอร์สและฟรีหรือไม่?
&lt;/h3&gt;

&lt;p&gt;ใช่ Semantic Kernel เป็นโอเพนซอร์สและเผยแพร่โดย Microsoft บน GitHub ภายใต้ permissive license มี SDK สำหรับ C#/.NET, Python และ Java คุณจ่ายค่าการใช้งานโมเดล เช่น OpenAI หรือ Azure OpenAI ไม่ใช่ตัว SK เอง&lt;/p&gt;

&lt;h3&gt;
  
  
  Semantic Kernel รองรับภาษาใดบ้าง?
&lt;/h3&gt;

&lt;p&gt;รองรับ C#/.NET, Python และ Java โดยทั้งหมดมีความเสถียรระดับ 1.0+ SDK สำหรับ C# มักสมบูรณ์ที่สุด แต่ Python และ Java ก็ครอบคลุมฟีเจอร์หลัก เช่น kernel, plugins และการนำเข้า OpenAPI&lt;/p&gt;

&lt;h3&gt;
  
  
  Semantic Kernel ใช้ OpenAPI specs อย่างไร?
&lt;/h3&gt;

&lt;p&gt;คุณนำเข้าสเปกด้วย &lt;code&gt;ImportPluginFromOpenApiAsync&lt;/code&gt; ใน C# หรือ &lt;code&gt;add_plugin_from_openapi&lt;/code&gt; ใน Python จากนั้น SK จะเปลี่ยนแต่ละ operation ให้เป็น function ที่โมเดลเรียกได้ พร้อม metadata ของ parameter และ schema&lt;/p&gt;

&lt;p&gt;ก่อนนำเข้า ควรตรวจ spec และทดสอบ endpoint จริงด้วย &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; เพื่อให้แน่ใจว่า contract ถูกต้อง&lt;/p&gt;

&lt;h3&gt;
  
  
  ฉันควรใช้ Semantic Kernel หรือ Microsoft Agent Framework ดี?
&lt;/h3&gt;

&lt;p&gt;ถ้ามีแอป Semantic Kernel อยู่แล้ว ให้ใช้ต่อได้ เพราะยังได้รับการสนับสนุนและมีความเสถียร ถ้าเริ่มโปรเจกต์ใหม่ ให้ตรวจเอกสาร Microsoft Agent Framework ล่าสุดก่อน เพราะ Microsoft วางให้เป็นผู้สืบทอดของ SK และ AutoGen&lt;/p&gt;

&lt;p&gt;สำหรับการทดสอบ API ที่ framework เหล่านี้เรียกใช้ ดู &lt;a href="https://apidog.com/th/blog/how-to-test-chatgpt-api-with-apidog?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;วิธีทดสอบ ChatGPT API ด้วย Apidog&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  สรุป
&lt;/h2&gt;

&lt;p&gt;Semantic Kernel เป็นวิธีที่ตรงไปตรงมาสำหรับทีมบน Microsoft stack ที่ต้องการเพิ่ม AI เข้าแอป: ใช้ kernel เชื่อมโมเดลกับโค้ด ใช้ plugins/functions เปิดความสามารถให้โมเดล และใช้ OpenAPI import เพื่อเปลี่ยน REST API ที่มีอยู่ให้เป็น tool ของเอเจนต์&lt;/p&gt;

&lt;p&gt;ถ้าคุณใช้ .NET, Java หรือมี API จำนวนมากที่ต้องการให้โมเดลเรียกใช้งาน SK เป็นตัวเลือกที่ใช้งานได้จริงและเหมาะกับ production ส่วน Microsoft Agent Framework คือทิศทางใหม่ที่ควรติดตามสำหรับโปรเจกต์เอเจนต์รุ่นถัดไป&lt;/p&gt;

&lt;p&gt;ไม่ว่าจะเลือกทางไหน API ที่เอเจนต์เรียกต้องถูกต้องและทดสอบได้ก่อนเสมอ หากต้องการออกแบบ mock และทดสอบ OpenAPI spec กับ endpoint ที่เอเจนต์พึ่งพา ให้ &lt;a href="https://apidog.com/download?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ดาวน์โหลด Apidog&lt;/a&gt; และสร้าง contract ให้ชัดเจนก่อนปล่อยให้เอเจนต์เรียกใช้งาน&lt;/p&gt;

</description>
    </item>
    <item>
      <title>PydanticAI คืออะไร: คู่มือเฟรมเวิร์กเอเจนต์ Python แบบ Type-Safe</title>
      <dc:creator>Thanawat Wongchai</dc:creator>
      <pubDate>Fri, 26 Jun 2026 08:28:02 +0000</pubDate>
      <link>https://dev.to/thanawat_wonchai/pydanticai-khuueaair-khuumuueefrmewirkeecchnt-python-aebb-type-safe-33k3</link>
      <guid>https://dev.to/thanawat_wonchai/pydanticai-khuueaair-khuumuueefrmewirkeecchnt-python-aebb-type-safe-33k3</guid>
      <description>&lt;p&gt;หากคุณเคยส่งมอบฟีเจอร์ LLM แล้วเจอ JSON รูปแบบผิดใน production, PydanticAI ถูกออกแบบมาเพื่อแก้ปัญหานี้โดยตรง มันคือเฟรมเวิร์กเอเจนต์ Python จากทีมเดียวกับ &lt;a href="https://pydantic.dev/docs/ai/overview/" rel="noopener noreferrer"&gt;Pydantic&lt;/a&gt; ที่โฟกัสเอาต์พุตแบบ type-safe และผ่าน validation เหมาะกับงานที่ผลลัพธ์จากโมเดลต้องถูกส่งต่อเข้าโค้ดจริง เช่น API, database, billing flow หรือ workflow อัตโนมัติ บทความนี้สรุปวิธีใช้ PydanticAI แบบลงมือทำ และเปรียบเทียบกับเฟรมเวิร์ก Python อื่น เช่น &lt;a href="https://apidog.com/th/blog/langgraph?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;LangGraph&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;ลองใช้ Apidog วันนี้&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  PydanticAI คืออะไร
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pydantic.dev/docs/ai/overview/" rel="noopener noreferrer"&gt;PydanticAI&lt;/a&gt; เป็นเฟรมเวิร์กเอเจนต์แบบโอเพนซอร์สสำหรับ Python ที่ไม่ผูกกับผู้ให้บริการโมเดลใดโมเดลหนึ่ง ทีมผู้ดูแลคือทีมเดียวกับ Pydantic Validation และ Pydantic Logfire เป้าหมายหลักคือทำให้การสร้างเอเจนต์มีประสบการณ์ใกล้เคียง FastAPI: ประกาศ schema ชัดเจน, validate อัตโนมัติ, และทำงานร่วมกับ type checker ได้ดี&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpydantic.dev%2Fdocs%2Fai%2Fimg%2Fpydantic-ai-dark.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpydantic.dev%2Fdocs%2Fai%2Fimg%2Fpydantic-ai-dark.svg" alt="Pydantic AI" width="741" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;แนวคิดหลักคือคุณกำหนดว่าเอเจนต์ต้องทำอะไร ใช้เครื่องมืออะไรได้บ้าง และเอาต์พุตต้องมีรูปแบบแบบใด จากนั้น PydanticAI จะจัดการการเรียกโมเดล ตรวจสอบผลลัพธ์กับโมเดล Pydantic และ retry เมื่อโมเดลตอบกลับมาไม่ตรง schema&lt;/p&gt;

&lt;p&gt;โปรเจกต์นี้ออกเวอร์ชัน v2.0.0 ที่เสถียรเมื่อวันที่ 23 มิถุนายน 2026 หลังผ่านช่วงเบต้าหลายรอบ เวอร์ชัน 2 เน้นการออกแบบแบบ harness-first โดยให้เครื่องมือ, hooks, คำสั่ง และการตั้งค่าโมเดลประกอบกันเป็นหน่วยที่นำกลับมาใช้ซ้ำได้&lt;/p&gt;

&lt;p&gt;ติดตั้งได้ด้วย:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pydantic-ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หรือถ้าใช้ &lt;code&gt;uv&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv add pydantic-ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ทำไม type safety จึงสำคัญกับเอเจนต์
&lt;/h2&gt;

&lt;p&gt;LLM ไม่ได้ให้ผลลัพธ์ที่แน่นอนเสมอไป คำถามเดียวกันอาจได้คำตอบคนละรูปแบบ ซึ่งพอรับได้ใน chatbot แต่จะกลายเป็นปัญหาทันทีเมื่อเอาต์พุตถูกส่งเข้าโค้ดจริง เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เขียนข้อมูลลงฐานข้อมูล&lt;/li&gt;
&lt;li&gt;เรียก REST API ถัดไป&lt;/li&gt;
&lt;li&gt;คำนวณราคา&lt;/li&gt;
&lt;li&gt;เปิด ticket&lt;/li&gt;
&lt;li&gt;trigger workflow อัตโนมัติ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ปัญหาที่พบบ่อยคือโมเดล “ส่วนใหญ่” ส่ง JSON ถูกต้อง แต่บางครั้งขาด field, ใช้ type ผิด, หรือห่อ JSON ด้วยข้อความอธิบาย ทำให้ parser หรือ pipeline พังใน production สุดท้ายทีมต้องเขียน regex cleanup, defensive parsing และ retry loop เอง&lt;/p&gt;

&lt;p&gt;PydanticAI แก้จุดนี้โดยให้คุณประกาศสัญญาของเอาต์พุตผ่าน &lt;code&gt;output_type&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic_ai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SupportTicket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;openai:gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;output_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SupportTicket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;My payment failed three times today.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ticket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ผลลัพธ์ที่คุณได้คือ object ที่ผ่าน validation แล้ว ไม่ใช่ string ที่ต้องเดาเอง ถ้าโมเดลส่ง &lt;code&gt;priority&lt;/code&gt; เป็นข้อความ หรือไม่ส่ง &lt;code&gt;summary&lt;/code&gt; กลับมา PydanticAI จะส่ง validation error กลับไปให้ LLM และขอให้ลองตอบใหม่&lt;/p&gt;

&lt;p&gt;หลักการเดียวกันใช้กับ tool arguments ด้วย เมื่อโมเดลเรียกใช้เครื่องมือ PydanticAI จะตรวจสอบ argument จาก type hints ก่อนเรียกฟังก์ชันจริง ทำให้ input ที่ผิดไม่ไหลเข้า business logic ของคุณ&lt;/p&gt;

&lt;h2&gt;
  
  
  แนวคิดหลักของ PydanticAI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Agent
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Agent&lt;/code&gt; คือจุดเริ่มต้นหลัก คุณสร้างเอเจนต์ด้วย model identifier และคำสั่งเสริม:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic_ai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;anthropic:claude-sonnet-4-6&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Be concise, reply with one sentence.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Where does &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello world&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; come from?&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;การสลับผู้ให้บริการมักทำได้โดยเปลี่ยน model string เพียงบรรทัดเดียว เช่นจาก Anthropic เป็น OpenAI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;openai:gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Be concise, reply with one sentence.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Typed output
&lt;/h3&gt;

&lt;p&gt;ใช้ &lt;code&gt;output_type&lt;/code&gt; เมื่อต้องการเอาต์พุตแบบมี schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic_ai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductSummary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default_factory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;openai:gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;output_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ProductSummary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Extract product info: Wireless mouse, 29.99 USD, gaming, bluetooth&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# str
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# float
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# list[str]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ข้อดีคือ IDE และ type checker เห็น field ทั้งหมด:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ProductSummary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# product.price เป็น float ที่ validate แล้ว
&lt;/span&gt;    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;คุณไม่ต้องเขียน logic แบบนี้เอง:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;call_llm&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Tools
&lt;/h3&gt;

&lt;p&gt;Tools คือฟังก์ชันที่โมเดลสามารถเรียกใช้เพื่อเข้าถึงระบบภายนอก เช่น database, REST API หรือ calculation logic&lt;/p&gt;

&lt;p&gt;ลงทะเบียน tool ด้วย &lt;code&gt;@agent.tool&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic_ai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RunContext&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;openai:gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;deps_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@agent.tool&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_balance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RunContext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;account_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return the current balance for an account.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;lookup_balance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;account_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PydanticAI จะอ่าน type hints และ docstring เพื่อสร้าง schema ที่โมเดลเห็น จากนั้น validate ทุก tool call ก่อนเรียกฟังก์ชันจริง&lt;/p&gt;

&lt;p&gt;ตัวอย่าง flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ผู้ใช้ถามว่า “บัญชี A123 เหลือเงินเท่าไร”&lt;/li&gt;
&lt;li&gt;โมเดลตัดสินใจเรียก &lt;code&gt;get_user_balance&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;PydanticAI ตรวจว่า &lt;code&gt;account_id&lt;/code&gt; เป็น &lt;code&gt;str&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ฟังก์ชัน tool ทำงาน&lt;/li&gt;
&lt;li&gt;ผลลัพธ์ถูกส่งกลับให้โมเดลใช้ตอบผู้ใช้&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  4. Dependencies
&lt;/h3&gt;

&lt;p&gt;เอเจนต์ production มักต้องใช้ dependency เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;database connection&lt;/li&gt;
&lt;li&gt;HTTP client&lt;/li&gt;
&lt;li&gt;current user&lt;/li&gt;
&lt;li&gt;API key&lt;/li&gt;
&lt;li&gt;feature flag&lt;/li&gt;
&lt;li&gt;service object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PydanticAI ใช้ dependency injection ผ่าน &lt;code&gt;deps_type&lt;/code&gt; และ &lt;code&gt;RunContext&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic_ai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RunContext&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;api_base_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;auth_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;openai:gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;deps_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Deps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@agent.tool&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_order_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RunContext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Deps&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Get the status of an order.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch_order_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api_base_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;auth_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;deps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Deps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;api_base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://api.example.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;auth_token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;secret&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Check order ORD-123&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ข้อดีคือทดสอบง่ายขึ้น เพราะคุณสามารถ inject fake dependency ใน test ได้โดยไม่ต้องแก้ logic ของ agent&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Provider flexibility และ streaming
&lt;/h3&gt;

&lt;p&gt;PydanticAI รองรับผู้ให้บริการหลายราย เช่น OpenAI, Anthropic, Gemini, DeepSeek, Grok, Cohere, Mistral, Perplexity รวมถึงตัวเลือกคลาวด์อย่าง Azure AI Foundry และ Amazon Bedrock และโมเดลที่โฮสต์เอง&lt;/p&gt;

&lt;p&gt;การสลับ provider มักทำได้ด้วยการเปลี่ยน model string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;openai:gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;anthropic:claude-sonnet-4-6&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;นอกจากนี้ยังรองรับการ stream เอาต์พุตแบบ structured พร้อม validation ระหว่างข้อมูลทยอยเข้ามา ทำให้แสดงผลลัพธ์บางส่วนได้โดยยังรักษา type guarantees และสามารถเชื่อมกับ Pydantic Logfire สำหรับ tracing, debugging และ cost tracking ได้&lt;/p&gt;

&lt;h2&gt;
  
  
  PydanticAI เทียบกับเฟรมเวิร์กเอเจนต์ Python อื่นอย่างไร
&lt;/h2&gt;

&lt;p&gt;ไม่มีเฟรมเวิร์กเดียวที่ดีที่สุดสำหรับทุกงาน ให้เลือกตามลักษณะระบบที่ต้องสร้าง:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;เฟรมเวิร์ก&lt;/th&gt;
&lt;th&gt;จุดแข็งหลัก&lt;/th&gt;
&lt;th&gt;เหมาะเมื่อคุณต้องการ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PydanticAI&lt;/td&gt;
&lt;td&gt;เอาต์พุตและ tool arguments แบบ type-safe พร้อม validation&lt;/td&gt;
&lt;td&gt;ความน่าเชื่อถือใน production และ data flow ที่มี schema ชัดเจน&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apidog.com/th/blog/langgraph?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;LangGraph&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;กราฟที่มี state และ control flow ชัดเจน&lt;/td&gt;
&lt;td&gt;workflow หลายขั้นตอน, แตกแขนง, ทำงานนาน&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apidog.com/th/blog/google-adk?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Google ADK&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;การจัดระบบ multi-agent ใน ecosystem ของ Google&lt;/td&gt;
&lt;td&gt;integration กับ Gemini และ Vertex AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://apidog.com/th/blog/how-to-use-openai-agents-sdk?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;OpenAI Agents SDK&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;integration กับ OpenAI แน่น และรองรับ handoff&lt;/td&gt;
&lt;td&gt;stack ที่เน้น OpenAI และต้องการเริ่มเร็ว&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;จุดเด่นของ PydanticAI คือ validation layer ถ้าเอเจนต์ของคุณส่งข้อมูลเข้า service อื่น การรับประกันว่า output ตรงกับ Pydantic model จะช่วยลด runtime error ได้มาก&lt;/p&gt;

&lt;p&gt;ในทางกลับกัน &lt;a href="https://apidog.com/th/blog/langgraph?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;LangGraph&lt;/a&gt; เหมาะกว่าเมื่อคุณต้องการ state machine หรือ workflow ที่มีหลาย branch ส่วน OpenAI Agents SDK เหมาะเมื่อระบบของคุณผูกกับ OpenAI เป็นหลัก และต้องการฟีเจอร์เช่น agent handoff หรือ &lt;a href="https://apidog.com/th/blog/mcp-servers-openai-agents?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;MCP server support&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;คุณยังสามารถใช้ร่วมกันได้ เช่น ใช้ LangGraph จัด orchestration ระดับ workflow และใช้ PydanticAI เป็นเลเยอร์ที่รับผิดชอบ typed output ภายในบาง node&lt;/p&gt;

&lt;h2&gt;
  
  
  ควรใช้ PydanticAI เมื่อใด
&lt;/h2&gt;

&lt;p&gt;เลือก PydanticAI เมื่อ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เอาต์พุตของเอเจนต์ต้องเข้าโค้ดจริง ไม่ใช่แค่แสดงใน chat UI&lt;/li&gt;
&lt;li&gt;รูปแบบข้อมูลต้องถูกต้อง เช่นต้องมี field ครบและ type ถูก&lt;/li&gt;
&lt;li&gt;คุณใช้ Pydantic หรือ FastAPI อยู่แล้ว&lt;/li&gt;
&lt;li&gt;คุณต้องการให้ IDE และ type checker เข้าใจ flow ของเอเจนต์&lt;/li&gt;
&lt;li&gt;คุณต้องการสลับ provider ได้โดยไม่ rewrite agent ใหม่&lt;/li&gt;
&lt;li&gt;คุณต้องการ observability เช่น tracing และ debugging ผ่าน Logfire&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;พิจารณาเฟรมเวิร์กอื่นเมื่อ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;workflow มี branch ซับซ้อนมาก&lt;/li&gt;
&lt;li&gt;ต้องเก็บ state ระยะยาวหลายขั้นตอน&lt;/li&gt;
&lt;li&gt;ต้องการ explicit graph orchestration&lt;/li&gt;
&lt;li&gt;ระบบผูกกับ provider เฉพาะและต้องใช้ feature เฉพาะของ provider นั้น&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ตัวอย่าง implementation: สร้างเอเจนต์จัดหมวดหมู่ ticket
&lt;/h2&gt;

&lt;p&gt;ตัวอย่างนี้เหมาะกับ use case ที่พบบ่อย: รับข้อความจากลูกค้า แล้วแปลงเป็น structured ticket&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic_ai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TicketClassification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;billing&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;technical&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;account&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;other&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;low&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;openai:gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;output_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TicketClassification&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Classify customer support messages. &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Return a concise summary and choose the best category and priority.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_sync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;I was charged twice this month and need a refund immediately.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ticket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# billing
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# high
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้นคุณสามารถส่ง object นี้เข้า service ภายในได้โดยตรง:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_ticket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TicketClassification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ticket ผ่าน validation แล้ว
&lt;/span&gt;    &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ตัวอย่าง implementation: Agent ที่เรียก REST API ผ่าน tool
&lt;/h2&gt;

&lt;p&gt;สมมติคุณมี order API และต้องการให้เอเจนต์ตอบสถานะคำสั่งซื้อ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic_ai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RunContext&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsyncClient&lt;/span&gt;
    &lt;span class="n"&gt;api_base_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;openai:gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;deps_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Deps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Help users check order status.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@agent.tool&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_order_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RunContext&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Deps&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return order status by order ID.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api_base_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/orders/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;รันเอเจนต์:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;deps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Deps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;api_base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://api.example.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;secret&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;What is the status of order ORD-123?&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จุดสำคัญคือ &lt;code&gt;order_id&lt;/code&gt; ถูก validate ก่อน tool ทำงาน และ dependency ถูกส่งเข้า tool อย่างชัดเจนผ่าน &lt;code&gt;RunContext&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  การทดสอบและ mock API ที่อยู่เบื้องหลังเอเจนต์
&lt;/h2&gt;

&lt;p&gt;เอเจนต์ PydanticAI จะน่าเชื่อถือได้ก็ต่อเมื่อ API ที่มันเรียกใช้มีความน่าเชื่อถือด้วย การเรียกหนึ่งครั้งอาจแตะทั้ง LLM provider และ REST endpoint ภายในหรือ third-party API หลายตัว จุดเหล่านี้คือแหล่งของ flaky behavior, cost ที่คาดไม่ถึง และ response schema ที่ไม่ตรงกัน&lt;/p&gt;

&lt;p&gt;PydanticAI ตรวจสอบ output จากโมเดลได้ แต่ไม่ได้ตรวจสอบแทนคุณว่า upstream API ที่ tool เรียกใช้นั้นส่ง response ตรงตามที่โค้ดคาดหวังหรือไม่&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffyld2yzc9x8xwd2u8f9z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffyld2yzc9x8xwd2u8f9z.png" alt="Apidog API testing" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;นี่คือจุดที่ &lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; ช่วยได้ Apidog ไม่ได้สร้างหรือ orchestrate เอเจนต์ แต่เป็นแพลตฟอร์ม API สำหรับทดสอบและ mock endpoint ที่เอเจนต์ของคุณพึ่งพา&lt;/p&gt;

&lt;p&gt;แนวทางใช้งานจริง:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mock LLM หรือ tool endpoint ระหว่างพัฒนา&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
ชี้ tool ไปยัง &lt;a href="https://apidog.com/th/blog/mock-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;mock API&lt;/a&gt; ที่คืน response คงที่ เพื่อลดการใช้ token และหลีกเลี่ยง rate limit ระหว่างปรับ logic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ตรวจ response schema ก่อนผูกกับ &lt;code&gt;@agent.tool&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
ใช้ &lt;a href="https://apidog.com/th/blog/api-assertions?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;API assertions&lt;/a&gt; ตรวจว่า endpoint จริงส่ง field และ type ตรงกับที่ tool คาดไว้&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;แยก environment สำหรับ local, staging และ CI&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
เก็บ base URL, token และ provider key ใน environment แยกกัน เพื่อลด hard-coded config ในโค้ด&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ทดสอบ LLM endpoint โดยตรง&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
ถ้าคุณเรียก provider ผ่าน HTTP สามารถ &lt;a href="https://apidog.com/th/blog/how-to-test-chatgpt-api-with-apidog?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ทดสอบ ChatGPT API ด้วย Apidog&lt;/a&gt; เพื่อตรวจ authentication, streaming และรูปแบบ tool call ก่อนนำไปใช้ใน agent&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง workflow ที่แนะนำ:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;สร้าง API spec หรือ endpoint ใน Apidog&lt;/li&gt;
&lt;li&gt;สร้าง mock response สำหรับ tool endpoint&lt;/li&gt;
&lt;li&gt;ชี้ PydanticAI tool ไปยัง mock base URL ระหว่างพัฒนา&lt;/li&gt;
&lt;li&gt;เขียน assertion ตรวจ response schema&lt;/li&gt;
&lt;li&gt;เปลี่ยนเป็น staging หรือ production URL เมื่อพร้อม&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;หากต้องการลองใช้งาน ให้ &lt;a href="https://apidog.com/download?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ดาวน์โหลด Apidog&lt;/a&gt; แล้วเริ่มจาก mock endpoint หนึ่งตัวที่ agent ของคุณต้องเรียกใช้&lt;/p&gt;

&lt;h2&gt;
  
  
  คำถามที่พบบ่อย
&lt;/h2&gt;

&lt;h3&gt;
  
  
  PydanticAI ฟรีและเป็นโอเพนซอร์สหรือไม่?
&lt;/h3&gt;

&lt;p&gt;ใช่ PydanticAI เป็นโอเพนซอร์สและติดตั้งจาก PyPI ได้ด้วย:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pydantic-ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หรือ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv add pydantic-ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;อย่างไรก็ตาม คุณยังต้องจ่ายค่าบริการ LLM provider ที่คุณใช้ เพราะเฟรมเวิร์กจะเรียก API เหล่านั้นแทนคุณ ระหว่างพัฒนา คุณสามารถลดค่าใช้จ่ายด้วยการ &lt;a href="https://apidog.com/th/blog/mock-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;mock API response&lt;/a&gt; แทนการเรียกโมเดลจริงทุกครั้ง&lt;/p&gt;

&lt;h3&gt;
  
  
  PydanticAI ทำงานร่วมกับโมเดลใดได้บ้าง?
&lt;/h3&gt;

&lt;p&gt;PydanticAI ไม่ผูกกับผู้ให้บริการรายเดียว เอกสารระบุการรองรับ OpenAI, Anthropic, Gemini, DeepSeek, Grok, Cohere, Mistral และ Perplexity รวมถึง Azure AI Foundry, Amazon Bedrock และโมเดลที่โฮสต์เอง&lt;/p&gt;

&lt;p&gt;คุณเลือกโมเดลด้วย string เช่น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;anthropic:claude-sonnet-4-6&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;openai:gpt-4o&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;การสลับ provider มักเป็นการเปลี่ยนเพียงบรรทัดเดียว&lt;/p&gt;

&lt;h3&gt;
  
  
  PydanticAI ต่างจาก LangChain หรือ LangGraph อย่างไร?
&lt;/h3&gt;

&lt;p&gt;PydanticAI โฟกัส type safety: structured output ที่ validate แล้ว และ tool arguments ที่ validate จาก type hints และ Pydantic model&lt;/p&gt;

&lt;p&gt;LangGraph โฟกัส graph-based orchestration และ stateful workflow สำหรับงานหลายขั้นตอนที่มี branch ชัดเจน&lt;/p&gt;

&lt;p&gt;ถ้าปัญหาหลักของคุณคือ “ต้องมั่นใจว่าเอาต์พุตตรง schema” ให้เริ่มจาก PydanticAI แต่ถ้าปัญหาหลักคือ “ต้องควบคุม state machine หลาย node” เฟรมเวิร์กแบบ graph อาจเหมาะกว่า&lt;/p&gt;

&lt;h3&gt;
  
  
  จำเป็นต้องรู้ Pydantic ก่อนใช้ PydanticAI หรือไม่?
&lt;/h3&gt;

&lt;p&gt;ไม่จำเป็น แต่ช่วยมาก พื้นฐานที่ต้องรู้คือการประกาศ data model ด้วย &lt;code&gt;BaseModel&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้น PydanticAI จะใช้ model เหล่านี้เป็น schema สำหรับ output และ validation ถ้าคุณเคยใช้ FastAPI หรือ &lt;a href="https://apidog.com/th/blog/python-api-testing?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Python สำหรับการทดสอบ API&lt;/a&gt; มาก่อน แนวคิดจะคุ้นเคยมาก&lt;/p&gt;

&lt;h2&gt;
  
  
  บทสรุป
&lt;/h2&gt;

&lt;p&gt;PydanticAI ทำให้การสร้างเอเจนต์ Python ใช้งานจริงได้ปลอดภัยขึ้น โดยให้คุณประกาศ schema ของเอาต์พุตและ tool arguments แล้วปล่อยให้เฟรมเวิร์ก validate และ retry อัตโนมัติ เหมาะกับงาน production ที่ผลลัพธ์จาก LLM ต้องไหลเข้าโค้ดจริงและต้องเชื่อถือรูปแบบข้อมูลได้&lt;/p&gt;

&lt;p&gt;ไม่ว่าคุณจะเลือกเฟรมเวิร์กใด API ที่อยู่เบื้องหลังเอเจนต์ยังต้องถูกทดสอบเสมอ ใช้ &lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; เพื่อ mock LLM หรือ tool endpoint, ตรวจ response schema และจัดการ environment แยกตาม local, staging และ CI เพื่อให้เอเจนต์ทำงานบน API surface ที่คุณตรวจสอบแล้ว&lt;/p&gt;

</description>
    </item>
    <item>
      <title>APIDOG อัปเดตเดือนมิถุนายน: เวิร์กโฟลว์ CLI พลัง AI, นำเข้าราบรื่นยิ่งขึ้น และรีเฟรช OAuth 2.0 อัตโนมัติ</title>
      <dc:creator>Thanawat Wongchai</dc:creator>
      <pubDate>Fri, 26 Jun 2026 06:25:07 +0000</pubDate>
      <link>https://dev.to/thanawat_wonchai/apidog-apedteduuenmithunaayn-ewirkoflw-cli-phlang-ai-namekhaaraabruuenyingkhuen-aelariiefrch-oauth-20-3ba5</link>
      <guid>https://dev.to/thanawat_wonchai/apidog-apedteduuenmithunaayn-ewirkoflw-cli-phlang-ai-namekhaaraabruuenyingkhuen-aelariiefrch-oauth-20-3ba5</guid>
      <description>&lt;p&gt;การอัปเดตเดือนมิถุนายนของ Apidog ช่วยให้เวิร์กโฟลว์ API ในชีวิตประจำวันทำงานอัตโนมัติได้ง่ายขึ้นและเสถียรขึ้น ตั้งแต่ CLI ที่พร้อมใช้กับ AI, การนำเข้าข้อมูลที่สะอาดขึ้น, OAuth 2.0 ที่รีเฟรชโทเค็นอัตโนมัติ ไปจนถึงการปรับปรุงงานทดสอบและการตั้งค่าที่ทีม API ใช้บ่อย&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;ลองใช้ Apidog วันนี้&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;เป้าหมายของรอบนี้คือการลดงานซ้ำ ๆ ในทีม API: ให้เอเจนต์ AI ทำงานกับทรัพยากรโปรเจกต์จริงได้เป็นระบบมากขึ้น, ลดการแก้ไขหลังนำเข้า, ทำให้คำขอที่ใช้ OAuth ทำงานต่อเนื่อง และทำให้การตั้งค่าทดสอบ/มอนิเตอร์ทำได้เร็วขึ้น&lt;/p&gt;

&lt;h2&gt;
  
  
  การอัปเดตใหม่
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Apidog CLI รองรับเวิร์กโฟลว์ API ที่ขับเคลื่อนด้วย AI
&lt;/h3&gt;

&lt;p&gt;Apidog CLI กำลังถูกพัฒนาให้เป็นชั้นการทำงานสำหรับเวิร์กโฟลว์ API ที่ใช้ AI โดยแทนที่จะให้ผู้ใช้จำคำสั่งทั้งหมดเอง เอเจนต์ AI สามารถใช้ CLI เพื่อทำงานกับทรัพยากร Apidog จริงได้อย่างมีขอบเขตและตรวจสอบได้&lt;/p&gt;

&lt;p&gt;สิ่งที่ทำได้ดีขึ้นในรอบนี้:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ใช้ CLI เป็นชั้นการทำงานสำหรับเอเจนต์ AI ที่ต้องอ่าน/เขียนทรัพยากรในโปรเจกต์ Apidog&lt;/li&gt;
&lt;li&gt;รองรับการรันกรณีทดสอบ&lt;/li&gt;
&lt;li&gt;กรณีสถานการณ์สามารถอ้างอิงเอนด์พอยต์, กรณีทดสอบ และสถานการณ์อื่นได้&lt;/li&gt;
&lt;li&gt;การส่งออกทั้งรูปแบบเนทีฟและ OpenAPI รองรับการควบคุมขอบเขตที่ละเอียดขึ้น&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;แนวทางใช้งานที่เหมาะกับทีมพัฒนา:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ให้ AI ช่วยตรวจหรือสร้างการเปลี่ยนแปลงจากบริบทของโปรเจกต์&lt;/li&gt;
&lt;li&gt;ใช้ CLI ตรวจสอบหรือรันกรณีทดสอบก่อนบันทึกกลับ&lt;/li&gt;
&lt;li&gt;ส่งออกเฉพาะขอบเขตที่ต้องการ เช่น บางโมดูลหรือบางกลุ่ม API&lt;/li&gt;
&lt;li&gt;ลดการคาดเดาของ AI ด้วยทรัพยากรที่มีโครงสร้างจาก Apidog&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;คิดว่า CLI เป็นสะพานระหว่างคำสั่งภาษามนุษย์ของ AI กับการทำงานที่เป็นระบบในโปรเจกต์ Apidog&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;เมื่อใช้ร่วมกับ Apidog Skills เอเจนต์ AI จะมีคำแนะนำและขอบเขตการทำงานที่ปลอดภัยขึ้น เช่น เข้าใจวิธีใช้ทรัพยากร Apidog, ตรวจสอบการเปลี่ยนแปลงก่อนบันทึก และทำงาน API ให้สำเร็จโดยต้องเดาน้อยลง&lt;/p&gt;

&lt;h3&gt;
  
  
  การปรับปรุงการนำเข้าและส่งออก
&lt;/h3&gt;

&lt;p&gt;รอบนี้ปรับปรุงเวิร์กโฟลว์นำเข้า/ส่งออก โดยเฉพาะทีมที่ย้ายข้อมูลจาก Postman หรือดูแลข้อกำหนด API ผ่าน OpenAPI/Swagger&lt;/p&gt;

&lt;p&gt;สิ่งที่เปลี่ยน:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เมื่อนำเข้าผ่าน Postman API, Apidog สามารถลบช่องว่างออกจากชื่อตัวแปรได้&lt;/li&gt;
&lt;li&gt;เมื่อนำเข้าเวิร์กสเปซผ่าน Postman API, Apidog สามารถเปลี่ยนชื่อ &lt;code&gt;My Workspace&lt;/code&gt; ให้ชัดเจนขึ้นโดยอิงจากผู้สร้างเวิร์กสเปซ&lt;/li&gt;
&lt;li&gt;การนำเข้า/ส่งออก OpenAPI และ Swagger รองรับพารามิเตอร์ประเภทอ็อบเจกต์และพารามิเตอร์ประเภทการอ้างอิง&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่างปัญหาที่ลดลงหลังนำเข้า:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ก่อนหน้า&lt;/th&gt;
&lt;th&gt;ตอนนี้&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ตัวแปรที่นำเข้าอาจต้องแก้ชื่อด้วยตนเอง&lt;/td&gt;
&lt;td&gt;การนำเข้า Postman API สามารถลบช่องว่างออกจากชื่อตัวแปรได้&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;เวิร์กสเปซหลายรายการอาจใช้ชื่อที่สับสน เช่น &lt;code&gt;My Workspace&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;ชื่อเวิร์กสเปซที่ไม่ชัดเจนสามารถเปลี่ยนให้ระบุได้ง่ายขึ้น&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;พารามิเตอร์ OpenAPI ที่ซับซ้อนอาจต้องปรับหลังนำเข้า/ส่งออก&lt;/td&gt;
&lt;td&gt;OpenAPI/Swagger รองรับพารามิเตอร์ประเภทอ็อบเจกต์และการอ้างอิงมากขึ้น&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;แนวทางแนะนำหลังย้ายข้อมูล:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ตรวจสอบชื่อตัวแปร environment/collection หลังนำเข้า&lt;/li&gt;
&lt;li&gt;จัดกลุ่มเวิร์กสเปซที่นำเข้าตามผู้สร้างหรือทีมที่เกี่ยวข้อง&lt;/li&gt;
&lt;li&gt;ตรวจสอบ OpenAPI schema ที่มี object/reference parameter เพื่อยืนยันว่าโครงสร้างยังถูกต้อง&lt;/li&gt;
&lt;li&gt;รันคำขอหรือกรณีทดสอบหลักเพื่อเช็กว่า endpoint ยังทำงานตามคาด&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  OAuth 2.0 รองรับการรีเฟรชโทเค็นอัตโนมัติ
&lt;/h3&gt;

&lt;p&gt;OAuth 2.0 ใน Apidog รองรับการรีเฟรชโทเค็นอัตโนมัติแล้ว&lt;/p&gt;

&lt;p&gt;เมื่อ access token ใกล้หมดอายุหรือหมดอายุไปแล้ว Apidog สามารถรีเฟรชโทเค็นให้โดยอัตโนมัติ ทำให้คุณส่งคำขอต่อได้โดยไม่ต้องยืนยันตัวตนใหม่หรือคัดลอกโทเค็นด้วยตนเอง&lt;/p&gt;

&lt;p&gt;เหมาะกับงานเหล่านี้:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ดีบัก API ที่ป้องกันด้วย OAuth&lt;/li&gt;
&lt;li&gt;รันคำขอซ้ำระหว่างพัฒนา&lt;/li&gt;
&lt;li&gt;ตรวจสอบชุด API ที่ต้องใช้ session ต่อเนื่อง&lt;/li&gt;
&lt;li&gt;ทดสอบ flow ที่ใช้ token ระยะสั้น&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;ฟีเจอร์นี้ช่วยลดการหยุดชะงักระหว่างดีบัก API, ทดสอบ และตรวจสอบคำขอซ้ำ ๆ&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  การปรับปรุงตามคำแนะนำของผู้ใช้
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ความเข้ากันได้กับ MCP Client ที่ดีขึ้น
&lt;/h3&gt;

&lt;p&gt;Apidog ปรับปรุงความเข้ากันได้กับ MCP Client และสามารถแยกวิเคราะห์สคีมาที่ไม่ได้มาตรฐานได้เสถียรขึ้น&lt;/p&gt;

&lt;p&gt;สิ่งนี้ช่วยเมื่อเชื่อมต่อกับเซิร์ฟเวอร์หรือเครื่องมือ MCP ที่ส่ง schema ไม่ตรงรูปแบบที่คาดไว้ แทนที่จะล้มเหลวตั้งแต่แรก Apidog สามารถจัดการ response จากเครื่องมือ MCP ในโลกจริงได้มากขึ้น และช่วยเพิ่มโอกาสสำเร็จของการรวมเครื่องมือและการดีบัก&lt;/p&gt;

&lt;h3&gt;
  
  
  ค้นหาขั้นตอนแบบคงที่ด้วยชื่อในชุดทดสอบ
&lt;/h3&gt;

&lt;p&gt;เมื่อเพิ่มขั้นตอนแบบคงที่ในชุดทดสอบ ตอนนี้สามารถค้นหาด้วยชื่อได้แล้ว&lt;/p&gt;

&lt;p&gt;สำหรับโปรเจกต์ที่มีเอนด์พอยต์, กรณีทดสอบ หรือสถานการณ์จำนวนมาก วิธีนี้ช่วยลดเวลาในการเลื่อนหา item ในรายการยาว ๆ&lt;/p&gt;

&lt;p&gt;แนวทางใช้งาน:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;เปิดชุดทดสอบที่ต้องการแก้ไข&lt;/li&gt;
&lt;li&gt;เพิ่มขั้นตอนแบบคงที่&lt;/li&gt;
&lt;li&gt;ค้นหาด้วยชื่อ endpoint/test case/scenario&lt;/li&gt;
&lt;li&gt;เลือกรายการที่ต้องการและเพิ่มลงในชุดทดสอบ&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  งานที่กำหนดเวลาเพิ่มตัวเลือก “ทุก 8 ชั่วโมง”
&lt;/h3&gt;

&lt;p&gt;งานที่กำหนดเวลารองรับตัวเลือก “ทุก 8 ชั่วโมง” แล้ว&lt;/p&gt;

&lt;p&gt;เหมาะสำหรับ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;รัน automated test เป็นรอบ ๆ&lt;/li&gt;
&lt;li&gt;ตรวจสอบ API health ระหว่างวัน&lt;/li&gt;
&lt;li&gt;ทำ monitoring แบบ periodic&lt;/li&gt;
&lt;li&gt;ตรวจ regression ในช่วงเวลาที่ถี่กว่า daily แต่ไม่ถี่เกินไป&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่างรอบการรันที่พบได้บ่อย:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use case&lt;/th&gt;
&lt;th&gt;รอบที่เหมาะสม&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Smoke test ระหว่างวัน&lt;/td&gt;
&lt;td&gt;ทุก 8 ชั่วโมง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Health check รายวัน&lt;/td&gt;
&lt;td&gt;ทุก 24 ชั่วโมง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regression test หลัก&lt;/td&gt;
&lt;td&gt;ตามรอบ release หรือ CI schedule&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Apidog Web App รองรับการกำหนดค่าส่วนหัวที่สร้างขึ้นโดยอัตโนมัติ
&lt;/h3&gt;

&lt;p&gt;Apidog Web App รองรับการกำหนดค่าส่วนหัวที่สร้างขึ้นโดยอัตโนมัติแล้ว&lt;/p&gt;

&lt;p&gt;สิ่งนี้ช่วยให้ผู้ใช้ Web App ควบคุม request behavior ได้มากขึ้น โดยเฉพาะโปรเจกต์ที่มีข้อกำหนดเฉพาะเกี่ยวกับ header เช่น header มาตรฐานของทีม, header สำหรับ routing, header สำหรับ environment หรือ header ที่ต้องสอดคล้องกับ gateway/proxy&lt;/p&gt;

&lt;h2&gt;
  
  
  การแก้ไขข้อผิดพลาดและการปรับปรุงเล็กน้อย
&lt;/h2&gt;

&lt;p&gt;รายการแก้ไขและปรับปรุงในเดือนนี้ประกอบด้วย:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ปรับปรุงประสิทธิภาพเมื่อเลือกสถานการณ์ทดสอบขนาดใหญ่ไปยังสาขาย่อย ลดโอกาสเกิด timeout&lt;/li&gt;
&lt;li&gt;รายการสาขา Sprint และสาขาทั่วไปรองรับการแสดงรหัสสาขาและคัดลอกรหัส&lt;/li&gt;
&lt;li&gt;แสดงข้อความแจ้งเตือนที่เป็นมิตรขึ้นเมื่อ macOS ไม่สามารถส่งคำขออินทราเน็ตได้&lt;/li&gt;
&lt;li&gt;แก้ปัญหา Base URL ของบริการไม่ถูกนำเข้า และเอนด์พอยต์ไม่ถูกผูกกับบริการที่ระบุเมื่อนำเข้าข้อมูล Apidog ซ้ำไปยังโมดูลใหม่&lt;/li&gt;
&lt;li&gt;แก้ปัญหา OAuth 1.0 ที่ตั้งค่าให้เพิ่มใน request header แต่ไม่ได้ถูกเพิ่มจริง&lt;/li&gt;
&lt;li&gt;แก้ปัญหาโค้ดคำขอเอนด์พอยต์ที่สร้างขึ้นทำงานไม่ถูกต้องเมื่อ Basic Auth ใช้ตัวแปรภาษาจีน&lt;/li&gt;
&lt;li&gt;แก้ปัญหาโค้ดคำขอที่สร้างขึ้นใช้ HTTPS ไม่ถูกต้องเมื่อเอนด์พอยต์ใช้ HTTP&lt;/li&gt;
&lt;li&gt;แก้ปัญหาการรันสถานการณ์ CLI อาจรายงาน &lt;code&gt;Unexpected token&lt;/code&gt; เมื่อขั้นตอนสถานการณ์อ้างอิง response body ในรูปแบบ raw&lt;/li&gt;
&lt;li&gt;แก้ปัญหารายละเอียดรายงานการทดสอบยังแสดงว่ากำลังทำงาน หลังจากสถานการณ์ทดสอบอัตโนมัติถูกยกเลิกผิดปกติ&lt;/li&gt;
&lt;li&gt;แก้ปัญหารายงานที่เกี่ยวข้องไม่แสดงในรายการรายงานการทดสอบหลังจากรันกรณีสถานการณ์ในโฟลเดอร์หลัก&lt;/li&gt;
&lt;li&gt;แก้ปัญหาเมื่อรีเฟรช Apidog Web App แล้วโปรเจกต์กลับไปที่สาขาหลักโดยอัตโนมัติ&lt;/li&gt;
&lt;li&gt;แก้ปัญหาตัวเลือกตัวกรองแท็กไม่มีเนื้อหาระหว่างการนำเข้าสาขาและเมื่อแทรกเอนด์พอยต์ใน Markdown&lt;/li&gt;
&lt;li&gt;แก้ปัญหาบริการที่ไม่ใช่ค่าเริ่มต้นถูกเพิ่มซ้ำเมื่อนำเข้าไฟล์ Apidog ที่มีหลายโมดูลและบริการ&lt;/li&gt;
&lt;li&gt;แก้ปัญหาแท็กเอกสาร Markdown ไม่ถูกนำเข้าอย่างถูกต้องเมื่อนำเข้าข้อมูล Apidog&lt;/li&gt;
&lt;li&gt;แก้ปัญหายังคงแสดง conflict หลังจากรวมเอนด์พอยต์เข้ากับสาขาหลักในบางกรณี&lt;/li&gt;
&lt;li&gt;แก้ปัญหา frontend error ในบางกรณีเมื่อดีบักเอนด์พอยต์ SSE&lt;/li&gt;
&lt;li&gt;แก้ปัญหาสถิติโปรเจกต์ On-Premises นับเฉพาะข้อมูลจากโมดูลเริ่มต้น&lt;/li&gt;
&lt;li&gt;แก้ปัญหาการนำเข้าไฟล์ Apidog แบบหลายโมดูลจากหน้ารายละเอียดทีมนำเข้าเอนด์พอยต์ไปยังโมดูลเริ่มต้นผิด&lt;/li&gt;
&lt;li&gt;แก้ปัญหาการเปลี่ยนแปลงหายไปในบางกรณีหลังจากส่งการแก้ไข&lt;/li&gt;
&lt;li&gt;แก้ปัญหาแสดงข้อความข้อผิดพลาดไม่ถูกต้องในขั้นตอนยืนยันอีเมลเมื่อเปลี่ยนรหัสผ่าน&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ความหมายของการอัปเดตเหล่านี้
&lt;/h2&gt;

&lt;p&gt;การอัปเดตชุดนี้ทำให้ Apidog ใช้งานได้ดีขึ้นในเวิร์กโฟลว์ที่มีทั้งนักพัฒนา, เอเจนต์ AI, ข้อกำหนด API และการทดสอบอัตโนมัติ&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ส่วนที่เกี่ยวข้อง&lt;/th&gt;
&lt;th&gt;สิ่งที่ปรับปรุง&lt;/th&gt;
&lt;th&gt;ทำไมจึงสำคัญ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;เวิร์กโฟลว์ CLI ที่ขับเคลื่อนด้วย AI&lt;/td&gt;
&lt;td&gt;CLI ช่วยให้เอเจนต์ AI ทำงานกับทรัพยากรโปรเจกต์ Apidog, รันกรณีทดสอบ, อ้างอิงทรัพย์สินที่มีอยู่ และควบคุมการส่งออกได้ละเอียดขึ้น&lt;/td&gt;
&lt;td&gt;เอเจนต์ AI ทำงาน API ได้จากบริบทโปรเจกต์ที่เป็นระบบ แทนที่จะเดาจากข้อมูลที่ไม่มีโครงสร้าง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;การนำเข้าและส่งออก&lt;/td&gt;
&lt;td&gt;Postman API import ล้างชื่อตัวแปรและทำให้ชื่อเวิร์กสเปซชัดขึ้น; OpenAPI/Swagger รองรับพารามิเตอร์ object/reference&lt;/td&gt;
&lt;td&gt;ลดงานแก้หลังย้ายข้อมูล และรักษา API spec ที่ซับซ้อนได้ดีขึ้น&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;การยืนยันตัวตน&lt;/td&gt;
&lt;td&gt;OAuth 2.0 refresh token ได้อัตโนมัติ&lt;/td&gt;
&lt;td&gt;ลดการหยุดชะงักระหว่างดีบักและทดสอบ API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ความเข้ากันได้กับ MCP&lt;/td&gt;
&lt;td&gt;MCP Client แยกวิเคราะห์สคีมาที่ไม่ได้มาตรฐานได้มากขึ้น&lt;/td&gt;
&lt;td&gt;ทำงานกับเครื่องมือและเซิร์ฟเวอร์ MCP ในโลกจริงได้เสถียรขึ้น&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;เวิร์กโฟลว์การทดสอบ&lt;/td&gt;
&lt;td&gt;ค้นหาขั้นตอนแบบคงที่ได้ง่ายขึ้น และ scheduled job รองรับทุก 8 ชั่วโมง&lt;/td&gt;
&lt;td&gt;ตั้งค่าชุดทดสอบเร็วขึ้นและยืดหยุ่นขึ้นสำหรับการรันซ้ำ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;การกำหนดค่า Web App&lt;/td&gt;
&lt;td&gt;กำหนดค่าส่วนหัวที่สร้างอัตโนมัติได้ใน Apidog Web App&lt;/td&gt;
&lt;td&gt;ควบคุม request behavior ได้ดีขึ้นในเวิร์กโฟลว์บนเบราว์เซอร์&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;สรุปคือทีมจะได้ flow ที่สะอาดขึ้น: AI มีบริบทโปรเจกต์ดีขึ้น, ข้อมูลนำเข้าต้องแก้น้อยลง, คำขอ OAuth ถูกขัดจังหวะน้อยลง และทีมควบคุมการทดสอบซ้ำกับการตั้งค่า request ได้มากขึ้น&lt;/p&gt;

&lt;h2&gt;
  
  
  เข้าร่วมการสนทนา
&lt;/h2&gt;

&lt;p&gt;เชื่อมต่อกับวิศวกร API คนอื่น ๆ และทีม Apidog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เข้าร่วมชุมชน &lt;a href="https://discord.com/invite/ZBxrzyXfbJ?ref=apidog.com&amp;amp;utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Discord&lt;/a&gt; ของเราสำหรับการสนทนาและการสนับสนุนแบบเรียลไทม์&lt;/li&gt;
&lt;li&gt;เข้าร่วมชุมชน &lt;a href="https://join.slack.com/t/apidogcommunity/shared_invite/zt-2neie4nh2-4_zhufuNBmCq4EtI6fZUwA?ref=apidog.com&amp;amp;utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Slack&lt;/a&gt; ของเราสำหรับการสนทนาทางเทคนิค&lt;/li&gt;
&lt;li&gt;ติดตามเราบน &lt;a href="https://x.com/ApidogHQ?ref=apidog.com&amp;amp;utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;X (Twitter)&lt;/a&gt; เพื่อรับการอัปเดตล่าสุด&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ป.ล. สำหรับรายละเอียดทั้งหมดเกี่ยวกับการอัปเดตทั้งหมด โปรดดู &lt;a href="https://apidog.canny.io/changelog/?ref=apidog.com&amp;amp;utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog Changelog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ขอแสดงความนับถือ,&lt;br&gt;&lt;br&gt;
ทีมงาน Apidog&lt;/p&gt;

</description>
    </item>
    <item>
      <title>เกิดอะไรขึ้นกับ GPT-5.6?</title>
      <dc:creator>Thanawat Wongchai</dc:creator>
      <pubDate>Fri, 26 Jun 2026 05:31:30 +0000</pubDate>
      <link>https://dev.to/thanawat_wonchai/ekidaairkhuenkab-gpt-56-4kkb</link>
      <guid>https://dev.to/thanawat_wonchai/ekidaairkhuenkab-gpt-56-4kkb</guid>
      <description>&lt;p&gt;รุ่นเรือธงถัดไปของ OpenAI, GPT-5.6, จะไม่ได้เปิดตัวแบบปกติตามรายงานวันที่ 25 มิถุนายน 2026 รัฐบาลสหรัฐฯ ขอให้ OpenAI ชะลอการเปิดตัวสู่สาธารณะ และให้เปิดใช้งานกับพันธมิตรที่ผ่านการคัดเลือกจำนวนน้อยก่อน กรณีนี้คล้ายกับเหตุการณ์ที่ Anthropic ต้องถอน &lt;a href="https://apidog.com/th/blog/claude-fable-5-rate-limits?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;โมเดล Fable 5 และ Mythos 5&lt;/a&gt; ออกจากระบบภายใต้คำสั่งของรัฐบาลเมื่อไม่ถึงสองสัปดาห์ก่อน สำหรับทีมที่สร้างผลิตภัณฑ์บน AI API ประเด็นสำคัญไม่ใช่แค่ข่าวอุตสาหกรรม แต่คือความเสี่ยงด้านสถาปัตยกรรม: โมเดลที่คุณเรียกใช้วันนี้อาจถูกจำกัด ชะลอ หรือปิดใช้งานได้โดยมีเวลาเตือนน้อยมาก&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;ลองใช้ Apidog วันนี้&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  เกิดอะไรขึ้นกับ GPT-5.6
&lt;/h2&gt;

&lt;p&gt;รายละเอียดต่อไปนี้เป็น “รายงาน” ไม่ใช่การยืนยันอย่างเป็นทางการ เพราะทั้ง OpenAI และทำเนียบขาวยังไม่ได้ออกความเห็นต่อสาธารณะ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ผู้ร้องขอ:&lt;/strong&gt; รัฐบาลทรัมป์ โดยเฉพาะสำนักงานผู้อำนวยการด้านไซเบอร์แห่งชาติและสำนักงานนโยบายวิทยาศาสตร์และเทคโนโลยี มีรายงานครั้งแรกโดย &lt;a href="https://www.theinformation.com/articles/trump-administration-asks-openai-stagger-release-new-model-security-concerns" rel="noopener noreferrer"&gt;The Information&lt;/a&gt; และถูกรายงานต่อโดย &lt;a href="https://www.axios.com/2026/06/25/trump-administration-openai-gpt-model-release" rel="noopener noreferrer"&gt;Axios&lt;/a&gt; และ &lt;a href="https://siliconangle.com/2026/06/25/openai-staggers-gpt-5-6-rollout-government-vetting-eyes-2027-ipo/" rel="noopener noreferrer"&gt;SiliconANGLE&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;รูปแบบการชะลอ:&lt;/strong&gt; GPT-5.6 จะไม่เปิดสู่สาธารณะทันที แต่จะเปิดให้พันธมิตรกลุ่มเล็กก่อน มีรายงานว่ารัฐบาลต้องอนุมัติเป็นรายลูกค้าในช่วงพรีวิวนี้&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;เหตุผล:&lt;/strong&gt; ความมั่นคงของชาติ โดยเฉพาะความกังวลว่าโมเดลที่ช่วยค้นหาช่องโหว่ซอฟต์แวร์หรือเจาะระบบได้ดีขึ้น อาจถูกใช้งานโดยฝ่ายตรงข้ามก่อนที่มาตรการป้องกันจะผ่านการพิสูจน์&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ไทม์ไลน์:&lt;/strong&gt; หน้าต่างการเปิดตัวเดือนมิถุนายนถูกเลื่อนออกไป และตอนนี้การเปิดตัวในวงกว้างดูมีแนวโน้มอยู่ในเดือนกรกฎาคม 2026 มากกว่า&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;สรุป: GPT-5.6 ดูเหมือนใกล้เปิดตัว แต่ถูกจัดการเหมือนการปล่อยใช้งานแบบควบคุม ไม่ใช่การเปิดตัวผลิตภัณฑ์ทั่วไป รุ่นเรือธงที่ใช้งานใน Public API ยังเป็น GPT-5.5&lt;/p&gt;

&lt;h2&gt;
  
  
  แบบอย่างจาก Fable 5 และ Mythos 5
&lt;/h2&gt;

&lt;p&gt;กรณี GPT-5.6 ไม่ได้เกิดขึ้นเดี่ยว ๆ เมื่อวันที่ 12 มิถุนายน 2026 Anthropic ได้รับคำสั่งจากรัฐบาลให้ปิดใช้งานโมเดล Fable 5 และ Mythos 5 ที่เพิ่งประกาศไป&lt;/p&gt;

&lt;p&gt;ตามรายงานของ &lt;a href="https://www.cnbc.com/2026/06/12/anthropic-disables-access-to-fable-5-and-mythos-5-to-comply-with-government-directive.html" rel="noopener noreferrer"&gt;CNBC&lt;/a&gt;, &lt;a href="https://fortune.com/2026/06/13/anthropic-disables-fable-mythos-export-controls-national-security-threat/" rel="noopener noreferrer"&gt;Fortune&lt;/a&gt; และ &lt;a href="https://www.anthropic.com/news/fable-mythos-access" rel="noopener noreferrer"&gt;แถลงการณ์ของ Anthropic&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;คำสั่งดังกล่าวเป็นคำสั่งควบคุมการส่งออกที่อ้างอิงอำนาจด้านความมั่นคงของชาติ&lt;/li&gt;
&lt;li&gt;Anthropic ต้องระงับการเข้าถึงสำหรับพลเมืองต่างชาติ&lt;/li&gt;
&lt;li&gt;ตัวกระตุ้นคือเทคนิคหลีกเลี่ยงระบบป้องกันของ Fable 5 ซึ่งถูกออกแบบมาเพื่อจำกัดการเข้าถึงความสามารถด้านไซเบอร์ที่แรงกว่าของ Mythos 5&lt;/li&gt;
&lt;li&gt;Anthropic ไม่สามารถแยกผู้ใช้ต่างชาติออกจากผู้ใช้ในสหรัฐฯ ได้อย่างน่าเชื่อถือแบบเรียลไทม์ จึงต้องปิดโมเดลสำหรับทุกคน&lt;/li&gt;
&lt;li&gt;Anthropic ปฏิบัติตาม แต่โต้แย้งว่าการเจลเบรกเฉพาะกรณีไม่ควรนำไปสู่การเรียกคืนโมเดลที่ถูกใช้งานในวงกว้าง&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ความแตกต่างคือ Anthropic ถูกปิดใช้งานแบบเด็ดขาด ส่วน OpenAI ถูกจัดให้พรีวิวแบบทยอย แต่แรงผลักดันเหมือนกัน: ความสามารถด้านไซเบอร์ของโมเดลแนวหน้าทำให้รัฐบาลเข้ามากำหนดว่าใครใช้โมเดลได้ และใช้ได้เมื่อใด&lt;/p&gt;

&lt;h2&gt;
  
  
  ทำไมเรื่องนี้สำคัญกับนักพัฒนา API
&lt;/h2&gt;

&lt;p&gt;ถ้าผลิตภัณฑ์ของคุณเรียกใช้โมเดลแนวหน้าผ่าน API เหตุการณ์เหล่านี้คือ operational risk โดยตรง&lt;/p&gt;

&lt;p&gt;ตัวอย่างสถานการณ์:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;คุณ deploy ฟีเจอร์ที่พึ่งพาโมเดลเดียว&lt;/li&gt;
&lt;li&gt;โมเดลนั้นถูกจำกัดหรือปิดใช้งานโดยคำสั่งภายนอก&lt;/li&gt;
&lt;li&gt;retry logic ไม่ช่วย เพราะปัญหาไม่ใช่ transient error&lt;/li&gt;
&lt;li&gt;ทีมไม่สามารถเปลี่ยน provider ได้ทันที เพราะโค้ดผูกกับ request/response format ของ vendor เดียว&lt;/li&gt;
&lt;li&gt;ฟีเจอร์หยุดทำงานจนกว่าจะหาโมเดลสำรองและทดสอบใหม่&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;บทเรียนไม่ใช่ “อย่าใช้โมเดลแนวหน้า” แต่คือ “อย่าผูกแอปกับโมเดลเดียวที่คุณควบคุมไม่ได้”&lt;/p&gt;

&lt;h2&gt;
  
  
  ออกแบบแอปให้เปลี่ยนโมเดลได้
&lt;/h2&gt;

&lt;p&gt;วิธีที่ปลอดภัยกว่าคือวางโมเดลไว้หลัง abstraction layer ภายในของคุณเอง ให้แอปเรียก interface เดียว แล้วค่อย route ไปยัง OpenAI, Anthropic, Google หรือโมเดลอื่นตาม config&lt;/p&gt;

&lt;p&gt;ตัวอย่างแนวคิดแบบ TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ChatMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ChatResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;LLMProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ChatResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้นสร้าง provider implementation แยกกัน:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OpenAIProvider&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;LLMProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ChatResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.openai.com/v1/chat/completions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`OpenAI error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แล้วเลือก provider จาก environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createLLMProvider&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;LLMProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LLM_PROVIDER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openai&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OpenAIProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPENAI_MODEL&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-5.5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Unsupported provider: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เมื่อมี provider สำรอง คุณควรเปลี่ยนการตั้งค่าได้โดยไม่ต้องแก้ business logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;LLM_PROVIDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;openai
&lt;span class="nv"&gt;OPENAI_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gpt-5.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ถ้าต้อง failover ไป provider อื่น ให้เพิ่ม implementation ใหม่ แต่ให้ interface ภายในเหมือนเดิม&lt;/p&gt;

&lt;h2&gt;
  
  
  ใช้ fallback แบบมีเงื่อนไข ไม่ใช่ retry อย่างเดียว
&lt;/h2&gt;

&lt;p&gt;การ retry เหมาะกับ timeout หรือ 5xx ชั่วคราว แต่ไม่ช่วยกับกรณีโมเดลถูกจำกัดหรือถอนออก คุณควรแยก error ที่ควร retry ออกจาก error ที่ควร fallback&lt;/p&gt;

&lt;p&gt;ตัวอย่าง pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;runWithFallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LLMProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LLMProvider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ChatResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Primary model failed, switching to fallback&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใน production ให้เพิ่มเงื่อนไขละเอียดขึ้น เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fallback เมื่อได้ &lt;code&gt;403&lt;/code&gt;, &lt;code&gt;404&lt;/code&gt;, &lt;code&gt;429&lt;/code&gt;, หรือ error ที่ระบุว่า model unavailable&lt;/li&gt;
&lt;li&gt;retry เมื่อเป็น network timeout หรือ &lt;code&gt;5xx&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;log provider/model ที่ถูกใช้จริงทุกครั้ง&lt;/li&gt;
&lt;li&gt;alert เมื่อ fallback ถูกใช้งานเกิน threshold&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ทดสอบโมเดลสำรองก่อนเกิดเหตุ
&lt;/h2&gt;

&lt;p&gt;อย่ารอให้โมเดลหลักหยุดทำงานแล้วค่อยเริ่มทดสอบโมเดลสำรอง ให้สร้าง test suite เดียวที่ใช้กับทุก provider&lt;/p&gt;

&lt;p&gt;สิ่งที่ควรตรวจ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;response มี field ที่แอปต้องใช้ครบหรือไม่&lt;/li&gt;
&lt;li&gt;output อยู่ใน format ที่ parser ของคุณรับได้หรือไม่&lt;/li&gt;
&lt;li&gt;latency อยู่ในช่วงที่ยอมรับได้หรือไม่&lt;/li&gt;
&lt;li&gt;คำตอบผ่าน business rules ขั้นต่ำหรือไม่&lt;/li&gt;
&lt;li&gt;error handling ทำงานตามที่ออกแบบหรือไม่&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง assertion ระดับ API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;คุณสามารถใช้เครื่องมือ API เช่น &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; เพื่อจัดการ request, environment, assertion และชุดทดสอบซ้ำกับหลาย endpoint ได้&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8x92bu147ypndf8phdc0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8x92bu147ypndf8phdc0.png" alt="Apidog API testing interface" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;แนวทางที่เกี่ยวข้อง:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://apidog.com/th/blog/best-openrouter-alternatives?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ทางเลือก OpenRouter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apidog.com/th/blog/how-to-use-litellm?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;การใช้ LiteLLM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apidog.com/th/blog/how-to-test-chatgpt-api-with-apidog?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;วิธีทดสอบ ChatGPT API ด้วย Apidog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apidog.com/th/blog/api-assertions?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;API assertions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  จำลอง Model API เพื่อไม่ให้ทีมพัฒนาหยุดทำงาน
&lt;/h2&gt;

&lt;p&gt;ถ้า endpoint จริงถูกจำกัดหรือ rate limit ทีม frontend, QA และ CI ไม่ควรถูกบล็อกทั้งหมด วิธีปฏิบัติที่ดีคือสร้าง mock API ที่คืน response รูปแบบเดียวกับโมเดลจริง&lt;/p&gt;

&lt;p&gt;ตัวอย่าง mock response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"นี่คือตัวอย่างคำตอบจากโมเดลจำลอง"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mock-llm"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้นให้แอปเปลี่ยน base URL ได้ผ่าน config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;LLM_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://mock-api.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เมื่อ endpoint จริงกลับมา ให้เปลี่ยนกลับ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;LLM_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://api.vendor.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mock API ช่วยให้:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;frontend พัฒนาต่อได้&lt;/li&gt;
&lt;li&gt;test pipeline ไม่ล้มเพราะ external dependency&lt;/li&gt;
&lt;li&gt;QA ทดสอบ edge case ได้ซ้ำ&lt;/li&gt;
&lt;li&gt;ทีมไม่ต้องรอสิทธิ์เข้าถึงโมเดลจริง&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ดูเพิ่มเติม: &lt;a href="https://apidog.com/th/blog/mock-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Mock API&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ติดตามต้นทุนและ latency ต่อโมเดล
&lt;/h2&gt;

&lt;p&gt;เมื่อ failover ไป provider อื่น ค่าใช้จ่ายและ latency อาจเปลี่ยนทันที ดังนั้นอย่า track usage แค่ระดับระบบรวม ให้เก็บอย่างน้อย:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provider&lt;/li&gt;
&lt;li&gt;model&lt;/li&gt;
&lt;li&gt;feature&lt;/li&gt;
&lt;li&gt;token/input size&lt;/li&gt;
&lt;li&gt;latency&lt;/li&gt;
&lt;li&gt;error rate&lt;/li&gt;
&lt;li&gt;cost estimate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"feature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"support-assistant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gpt-5.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"latency_ms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1420&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fallback_used"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เมื่อ fallback ถูกใช้งาน:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"feature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"support-assistant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fallback-provider"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fallback-model"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"latency_ms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2310&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fallback_used"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;อ่านเพิ่มเติม: &lt;a href="https://apidog.com/th/blog/track-openai-api-spend-per-feature?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ติดตามค่าใช้จ่าย API ต่อฟีเจอร์&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist สำหรับทีมที่ใช้ AI API
&lt;/h2&gt;

&lt;p&gt;ใช้ checklist นี้ตรวจสถาปัตยกรรมของคุณ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] มี interface ภายในสำหรับเรียก LLM ไม่เรียก vendor SDK กระจายทั่ว codebase&lt;/li&gt;
&lt;li&gt;[ ] เปลี่ยน provider/model ได้ผ่าน config&lt;/li&gt;
&lt;li&gt;[ ] มี fallback provider ที่ทดสอบแล้ว&lt;/li&gt;
&lt;li&gt;[ ] แยก retry error กับ fallback error&lt;/li&gt;
&lt;li&gt;[ ] มี mock API สำหรับ development และ CI&lt;/li&gt;
&lt;li&gt;[ ] มี test suite เดียวที่รันกับหลายโมเดล&lt;/li&gt;
&lt;li&gt;[ ] มี assertion ตรวจ response shape ไม่ใช่แค่ HTTP 200&lt;/li&gt;
&lt;li&gt;[ ] log provider/model/latency/cost ต่อ request&lt;/li&gt;
&lt;li&gt;[ ] มี alert เมื่อ fallback ถูกใช้มากผิดปกติ&lt;/li&gt;
&lt;li&gt;[ ] มี runbook สำหรับกรณี model unavailable&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  คำถามที่พบบ่อย
&lt;/h2&gt;

&lt;h3&gt;
  
  
  GPT-5.6 เปิดตัวแล้วหรือยัง?
&lt;/h3&gt;

&lt;p&gt;ยัง ไม่มีการเปิดตัวสู่สาธารณะจนถึงปลายเดือนมิถุนายน 2026 รายงานระบุว่า OpenAI จะเปิดให้พันธมิตรที่ได้รับการคัดเลือกจำนวนน้อยก่อน และอาจเปิดกว้างขึ้นหลังจากนั้นหากการตรวจสอบของรัฐบาลเป็นไปด้วยดี OpenAI ยังไม่ได้ยืนยันวันที่อย่างเป็นทางการ และ Public API ยังทำงานบน GPT-5.5&lt;/p&gt;

&lt;h3&gt;
  
  
  ทำไมรัฐบาลถึงเข้ามาแทรกแซง GPT-5.6?
&lt;/h3&gt;

&lt;p&gt;เหตุผลที่รายงานคือความมั่นคงของชาติ โดยเฉพาะความกังวลว่าโมเดลที่มีความสามารถสูงในการค้นหาช่องโหว่ซอฟต์แวร์หรือช่วยการเจาะระบบ อาจไปถึงมือฝ่ายตรงข้ามก่อนที่มาตรการป้องกันจะผ่านการพิสูจน์&lt;/p&gt;

&lt;h3&gt;
  
  
  เกิดอะไรขึ้นกับ Fable 5 และ Mythos 5 ของ Anthropic?
&lt;/h3&gt;

&lt;p&gt;เมื่อวันที่ 12 มิถุนายน 2026 Anthropic ได้รับคำสั่งควบคุมการส่งออกให้ระงับการเข้าถึงสำหรับพลเมืองต่างชาติ เนื่องจากไม่สามารถแยกผู้ใช้ต่างชาติออกจากผู้ใช้ในสหรัฐฯ ได้แบบเรียลไทม์ Anthropic จึงปิดใช้งาน Fable 5 และ Mythos 5 สำหรับทุกคน เหตุการณ์นี้กลายเป็นแบบอย่างที่รายงานเกี่ยวกับ GPT-5.6 อ้างอิงถึง&lt;/p&gt;

&lt;h3&gt;
  
  
  จะทำอย่างไรให้แอปยังทำงานได้หากโมเดลถูกถอนออก?
&lt;/h3&gt;

&lt;p&gt;อย่าผูกแอปกับโมเดลเดียว ให้เรียกผ่าน interface ภายใน เตรียม fallback provider ทดสอบโมเดลสำรองไว้ล่วงหน้า และสร้าง mock API เพื่อให้ development/test/CI เดินต่อได้ หากเปลี่ยน provider ได้ด้วย config การถอนโมเดลจะกลายเป็น failover แทนที่จะเป็น outage หลายวัน &lt;a href="https://apidog.com/th/blog/mock-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;เซิร์ฟเวอร์จำลอง Apidog&lt;/a&gt; และชุดทดสอบที่นำกลับมาใช้ซ้ำได้ช่วยลดความเสี่ยงนี้ได้ในระดับ implementation&lt;/p&gt;

&lt;h2&gt;
  
  
  สรุป
&lt;/h2&gt;

&lt;p&gt;การที่ GPT-5.6 ถูกรายงานว่าถูกชะลอการเปิดตัว หลังจาก Fable 5 และ Mythos 5 ถูกถอนออกไปไม่นาน ชี้ให้เห็นรูปแบบใหม่ของการปล่อยโมเดลแนวหน้า: การเข้าถึงอาจถูกตรวจสอบ จำกัด หรือเปลี่ยนแปลงด้วยเหตุผลที่อยู่นอกการควบคุมของผู้ขาย&lt;/p&gt;

&lt;p&gt;สำหรับนักพัฒนา การตอบสนองที่ถูกต้องคือออกแบบระบบให้ไม่พึ่งพาโมเดลเดียว:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;แยก LLM ออกจาก business logic&lt;/li&gt;
&lt;li&gt;ใช้ provider abstraction&lt;/li&gt;
&lt;li&gt;เตรียม fallback&lt;/li&gt;
&lt;li&gt;ทดสอบหลายโมเดลด้วยชุดเดียวกัน&lt;/li&gt;
&lt;li&gt;ใช้ mock API เมื่อ endpoint จริงไม่พร้อม&lt;/li&gt;
&lt;li&gt;ติดตาม cost และ latency ต่อโมเดล&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;คุณสามารถตั้งค่า request, assertion, mock API และชุดทดสอบซ้ำได้ใน &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; เพื่อให้โมเดลเดียวไม่กลายเป็น single point of failure ของผลิตภัณฑ์คุณ.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>วิธีใช้ OpenAI Function Calling</title>
      <dc:creator>Thanawat Wongchai</dc:creator>
      <pubDate>Fri, 26 Jun 2026 05:29:31 +0000</pubDate>
      <link>https://dev.to/thanawat_wonchai/withiiaich-openai-function-calling-1f9e</link>
      <guid>https://dev.to/thanawat_wonchai/withiiaich-openai-function-calling-1f9e</guid>
      <description>&lt;p&gt;เมื่ออ่านคู่มือนี้จบ คุณจะสามารถกำหนดเครื่องมือ ส่งไปยัง OpenAI อ่าน tool call ที่โมเดลส่งกลับมา แยกวิเคราะห์อาร์กิวเมนต์ JSON แล้วเรียกใช้ฟังก์ชันของคุณเองได้อย่างปลอดภัย จากนั้นเปิดใช้ strict mode และ parallel calls รวมถึงตรวจสอบและจำลองฝั่ง API ด้วย &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; ก่อนนำไปใช้งานจริง แนะนำให้เปิด &lt;a href="https://developers.openai.com/api/docs/guides/function-calling" rel="noopener noreferrer"&gt;เอกสาร function calling ของ OpenAI&lt;/a&gt; ไว้อ้างอิง และดูภาพรวมเพิ่มเติมจากบทความ &lt;a href="https://apidog.com/th/blog/how-to-use-openai-agents-sdk?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;สร้างเอเจนต์ด้วย OpenAI Agents SDK&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;ลองใช้ Apidog วันนี้&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  สิ่งที่คุณต้องมีก่อนเริ่มต้น
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developers.openai.com/api/docs/guides/function-calling" rel="noopener noreferrer"&gt;Function calling&lt;/a&gt; หรือ tool calling คือกลไกที่ให้โมเดลเลือก “ฟังก์ชันที่ควรเรียก” และส่งอาร์กิวเมนต์กลับมาเป็น JSON ให้แอปของคุณนำไปใช้ต่อ โมเดลไม่ได้รันโค้ดเอง หน้าที่ของโมเดลคือเลือก intent และจัดรูปแบบพารามิเตอร์ ส่วนโค้ดของคุณยังเป็นผู้ตรวจสอบและรันฟังก์ชันจริง&lt;/p&gt;

&lt;p&gt;ตัวอย่างเช่น ผู้ใช้ถามว่า:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is the weather in Paris right now?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;โมเดลอาจส่ง tool call กลับมาเป็น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;get_weather(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Paris, France"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แทนที่คุณจะต้องแยกข้อความธรรมชาติเอง คุณจะได้ชื่อฟังก์ชันและอาร์กิวเมนต์ที่มีโครงสร้างชัดเจน&lt;/p&gt;

&lt;p&gt;ก่อนเริ่ม คุณควรมี:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI API key&lt;/li&gt;
&lt;li&gt;ฟังก์ชันในแอปของคุณที่ต้องการให้โมเดลเรียกได้&lt;/li&gt;
&lt;li&gt;JSON Schema สำหรับอาร์กิวเมนต์ของฟังก์ชัน&lt;/li&gt;
&lt;li&gt;API หรือ service ปลายทางที่ฟังก์ชันของคุณจะเรียกใช้&lt;/li&gt;
&lt;li&gt;เครื่องมือทดสอบ เช่น &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; สำหรับตรวจ payload และสร้าง mock API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;คุณสามารถใช้ได้ทั้ง Chat Completions API และ Responses API ความสามารถคล้ายกัน แต่รูปแบบ request/response ต่างกันเล็กน้อย บทความนี้จะแสดงทั้งสองแนวทางในจุดที่จำเป็น&lt;/p&gt;

&lt;h2&gt;
  
  
  ขั้นตอนที่ 1: กำหนดเครื่องมือของคุณ
&lt;/h2&gt;

&lt;p&gt;เครื่องมือคือคำอธิบายฟังก์ชันที่โมเดลอ่านได้ โดยประกอบด้วย:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt;: ชื่อฟังก์ชัน&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;description&lt;/code&gt;: คำอธิบายว่าเมื่อใดควรใช้ฟังก์ชันนี้&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;parameters&lt;/code&gt;: JSON Schema ของอาร์กิวเมนต์&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;คำอธิบายสำคัญมาก เพราะโมเดลใช้ตัดสินใจว่าจะเรียกฟังก์ชันนี้หรือไม่ ให้เขียนเป็น instruction มากกว่าป้ายกำกับสั้นๆ&lt;/p&gt;

&lt;p&gt;ตัวอย่าง tool definition สำหรับ Chat Completions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"function"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"function"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get_weather"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Get the current weather for a city. Use when the user asks about temperature or conditions."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"City and country, e.g. Bogotá, Colombia"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"enum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"celsius"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fahrenheit"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"additionalProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใน Responses API รูปแบบจะ flat กว่า โดย &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;parameters&lt;/code&gt; และ &lt;code&gt;strict&lt;/code&gt; อยู่ที่ระดับบนสุดของ object เครื่องมือ ไม่ต้องซ้อนใต้คีย์ &lt;code&gt;function&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ถ้าคุณมี OpenAPI spec อยู่แล้ว สามารถนำ schema ของ request body หรือ parameters มาใช้เป็นฐานได้เกือบโดยตรง ดูแนวทางเพิ่มเติมได้จากบทความ &lt;a href="https://apidog.com/th/blog/api-test-collections-generation-openapi-specs?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;สร้างชุดการทดสอบจาก OpenAPI specs&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ขั้นตอนที่ 2: ส่งคำขอแรกพร้อม tools
&lt;/h2&gt;

&lt;p&gt;ส่งข้อความผู้ใช้พร้อมรายการเครื่องมือที่โมเดลสามารถเลือกใช้ได้ ตัวอย่าง Chat Completions request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.openai.com/v1/chat/completions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$OPENAI_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "model": "gpt-4.1",
    "messages": [
      {
        "role": "user",
        "content": "What is the weather in Paris right now?"
      }
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_weather",
          "description": "Get the current weather for a city.",
          "parameters": {
            "type": "object",
            "properties": {
              "location": {
                "type": "string"
              }
            },
            "required": ["location"],
            "additionalProperties": false
          }
        }
      }
    ]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใน request นี้:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;messages&lt;/code&gt; คือบริบทการสนทนา&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tools&lt;/code&gt; คือฟังก์ชันที่คุณเปิดให้โมเดลเรียก&lt;/li&gt;
&lt;li&gt;โมเดลจะตัดสินใจเองว่าจะตอบเป็นข้อความปกติหรือส่ง tool call กลับมา&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ถ้าโมเดลเลือกเครื่องมือ คุณจะไม่ได้คำตอบสุดท้ายทันที แต่จะได้ข้อมูลการเรียกฟังก์ชันเพื่อให้แอปของคุณนำไปดำเนินการต่อ&lt;/p&gt;

&lt;h2&gt;
  
  
  ขั้นตอนที่ 3: อ่าน tool call ที่โมเดลส่งกลับมา
&lt;/h2&gt;

&lt;p&gt;เมื่อโมเดลต้องการเรียกฟังก์ชัน มันจะส่ง tool call กลับมาแทนข้อความธรรมดา&lt;/p&gt;

&lt;p&gt;ใน &lt;strong&gt;Chat Completions&lt;/strong&gt; ให้ดูที่ &lt;code&gt;tool_calls&lt;/code&gt; ของ assistant message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"call_12345xyz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"function"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"function"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get_weather"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;location&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Paris, France&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใน &lt;strong&gt;Responses API&lt;/strong&gt; tool call จะอยู่ใน &lt;code&gt;output&lt;/code&gt; และมีรูปแบบ flat กว่า:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"function_call"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"call_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"call_12345xyz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get_weather"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;location&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Paris, France&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จุดสำคัญคือ &lt;code&gt;arguments&lt;/code&gt; เป็น string ที่ encode JSON ไว้ ไม่ใช่ object ที่ parse แล้ว ดังนั้นต้อง parse เองทุกครั้ง&lt;/p&gt;

&lt;p&gt;ตัวอย่าง Node.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toolCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tool_calls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;functionName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;toolCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toolCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;functionName&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_weather&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getWeather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;อย่าเรียกใช้ฟังก์ชันทันทีโดยไม่ตรวจสอบค่า เพราะแม้ schema จะช่วยจัดรูปแบบ แต่ business rule ยังต้องตรวจเอง เช่น เมืองนั้นอยู่ในพื้นที่ให้บริการหรือไม่&lt;/p&gt;

&lt;h2&gt;
  
  
  ขั้นตอนที่ 4: รันฟังก์ชันและส่งผลลัพธ์กลับไปยังโมเดล
&lt;/h2&gt;

&lt;p&gt;หลังจาก parse อาร์กิวเมนต์และรันฟังก์ชันแล้ว ให้ส่งผลลัพธ์กลับไปยังโมเดลเพื่อให้สร้างคำตอบสุดท้าย&lt;/p&gt;

&lt;p&gt;ใน Chat Completions ให้เพิ่ม message ที่มี role เป็น &lt;code&gt;tool&lt;/code&gt; และผูกกับ &lt;code&gt;tool_call_id&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tool"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tool_call_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"call_12345xyz"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;temperature&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:18,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;condition&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Cloudy&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ตัวอย่าง flow แบบย่อ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What is the weather in Paris right now?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// 1. ส่ง request แรก&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;tools&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// 2. อ่าน tool call&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assistantMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firstResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toolCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;assistantMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tool_calls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toolCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 3. รันฟังก์ชันจริงของคุณ&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;weather&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getWeather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 4. ส่งผลลัพธ์กลับไปให้โมเดล&lt;/span&gt;
&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;assistantMessage&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tool&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tool_call_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;toolCall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;finalResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;tools&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใน Responses API แนวคิดเหมือนกัน แต่ส่งผลลัพธ์กลับด้วย item ประเภท &lt;code&gt;function_call_output&lt;/code&gt; ที่อ้างอิง &lt;code&gt;call_id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;วงจรคือ:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;โมเดลเลือกฟังก์ชัน&lt;/li&gt;
&lt;li&gt;แอปของคุณ parse arguments&lt;/li&gt;
&lt;li&gt;แอปของคุณรันฟังก์ชัน&lt;/li&gt;
&lt;li&gt;แอปส่งผลลัพธ์กลับ&lt;/li&gt;
&lt;li&gt;โมเดลสร้างคำตอบสุดท้าย&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ขั้นตอนที่ 5: เปิด parallel calls และ strict mode
&lt;/h2&gt;

&lt;p&gt;เมื่อ flow พื้นฐานทำงานแล้ว ให้ปรับสองเรื่องนี้เพื่อเพิ่มความน่าเชื่อถือและควบคุมพฤติกรรม&lt;/p&gt;

&lt;h3&gt;
  
  
  Parallel tool calls
&lt;/h3&gt;

&lt;p&gt;โดยค่าเริ่มต้น โมเดลสามารถส่ง tool call หลายรายการใน response เดียวได้ เช่น ผู้ใช้ถามสภาพอากาศของสามเมือง โมเดลอาจส่งการเรียก &lt;code&gt;get_weather&lt;/code&gt; สามครั้งพร้อมกัน&lt;/p&gt;

&lt;p&gt;ถ้าฟังก์ชันเป็นอิสระต่อกัน คุณสามารถรันพร้อมกันได้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;toolCalls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;runTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แต่ถ้าการเรียกต้องทำตามลำดับ หรือผลลัพธ์หนึ่งเป็น input ของอีกอัน ให้ตั้งค่า:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parallel_tool_calls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Strict mode
&lt;/h3&gt;

&lt;p&gt;ตั้งค่า &lt;code&gt;strict: true&lt;/code&gt; เพื่อบังคับให้อาร์กิวเมนต์ตรงกับ JSON Schema มากขึ้น แทนที่จะเป็น best effort&lt;/p&gt;

&lt;p&gt;ตัวอย่าง schema แบบ strict:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"function"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"function"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get_weather"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Get the current weather for a city."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"null"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"enum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"celsius"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fahrenheit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"unit"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"additionalProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;กฎสำคัญของ strict mode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ทุก object ต้องมี &lt;code&gt;additionalProperties: false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ทุก field ใน &lt;code&gt;properties&lt;/code&gt; ต้องอยู่ใน &lt;code&gt;required&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ถ้าต้องการ optional field ให้ทำเป็น nullable เช่น &lt;code&gt;["string", "null"]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;โมเดลอาจส่ง &lt;code&gt;null&lt;/code&gt; แต่ไม่ควรละคีย์นั้นไป&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;การตั้งค่า&lt;/th&gt;
&lt;th&gt;สิ่งที่ควบคุม&lt;/th&gt;
&lt;th&gt;ค่าเริ่มต้น&lt;/th&gt;
&lt;th&gt;เมื่อใดควรเปลี่ยน&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;parallel_tool_calls&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;อนุญาตให้มี tool call หลายรายการใน response เดียวหรือไม่&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ตั้งเป็น &lt;code&gt;false&lt;/code&gt; เมื่อการเรียกขึ้นต่อกันหรือต้องรันตามลำดับ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;strict&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;บังคับให้อาร์กิวเมนต์ตรงกับ schema หรือไม่&lt;/td&gt;
&lt;td&gt;best effort ถ้าไม่ตั้งค่า&lt;/td&gt;
&lt;td&gt;ควรเปิดเมื่อคุณต้อง parse และใช้ payload ต่อโดยตรง&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tool_choice&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ควบคุมว่าโมเดลเรียก tool ได้หรือไม่ และเรียกตัวใด&lt;/td&gt;
&lt;td&gt;&lt;code&gt;auto&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ใช้ &lt;code&gt;required&lt;/code&gt; เพื่อบังคับเรียก, &lt;code&gt;none&lt;/code&gt; เพื่อปิด, หรือระบุชื่อ tool เพื่อบังคับฟังก์ชันเดียว&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Strict mode ช่วยลด payload ที่ผิดรูปแบบ แต่ไม่ได้รับประกัน business correctness เช่น &lt;code&gt;location&lt;/code&gt; อาจเป็น string ที่ถูกต้องตาม schema แต่เป็นเมืองที่ระบบคุณไม่รองรับ ดังนั้นยังต้อง validate ฝั่งแอปและทดสอบปลายทางจริงหรือ mock เสมอ&lt;/p&gt;

&lt;h2&gt;
  
  
  วิธีทดสอบใน Apidog
&lt;/h2&gt;

&lt;p&gt;ก่อนต่อ tool call เข้ากับ production flow คุณควรตรวจสองเรื่อง:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;อาร์กิวเมนต์จากโมเดลตรงกับ schema ที่ฟังก์ชันคาดหวังหรือไม่&lt;/li&gt;
&lt;li&gt;API ปลายทางที่ฟังก์ชันจะเรียกทำงานตามที่คาดหรือไม่&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; ช่วยตรวจและจำลองฝั่ง API ได้ แต่ไม่ได้รันฟังก์ชันในแอปของคุณเอง หน้าที่ของ Apidog คือช่วยตรวจ contract รอบๆ ฟังก์ชันเหล่านั้น&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftl41vtt267jxp6mce0sh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftl41vtt267jxp6mce0sh.png" alt="Apidog interface" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. ตรวจโครงสร้าง arguments
&lt;/h3&gt;

&lt;p&gt;นำค่า &lt;code&gt;arguments&lt;/code&gt; จาก tool call จริงมาใช้เป็น request body แล้วตรวจใน Apidog เช่น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Paris, France"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"celsius"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สิ่งที่ควร assert:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;location&lt;/code&gt; มีอยู่จริง&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;location&lt;/code&gt; เป็น string&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;unit&lt;/code&gt; อยู่ใน enum ที่อนุญาต&lt;/li&gt;
&lt;li&gt;ไม่มี field แปลกปลอมถ้า schema ใช้ &lt;code&gt;additionalProperties: false&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;field ที่จำเป็นมีครบ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;คุณสามารถใช้ &lt;a href="https://apidog.com/th/blog/jsonpath-examples?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;JSONPath&lt;/a&gt; เพื่อดึงค่าเฉพาะจาก payload และใช้ &lt;a href="https://apidog.com/th/blog/how-to-validate-json-schema?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;JSON Schema validation&lt;/a&gt; เพื่อตรวจ schema เดียวกับที่ส่งให้ OpenAI&lt;/p&gt;

&lt;p&gt;แนวทางที่ดีคือใช้ schema เดียวกันทั้งสามจุด:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tool definition ที่ส่งให้ OpenAI&lt;/li&gt;
&lt;li&gt;validation ใน Apidog&lt;/li&gt;
&lt;li&gt;validation ใน application code&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. จำลอง API ปลายทางที่ฟังก์ชันจะเรียก
&lt;/h3&gt;

&lt;p&gt;สมมติฟังก์ชัน &lt;code&gt;get_weather&lt;/code&gt; ของคุณต้องเรียก weather provider จริง ระหว่างพัฒนา provider อาจมี rate limit, มีค่าใช้จ่าย หรือยังไม่พร้อมใช้งาน&lt;/p&gt;

&lt;p&gt;ให้สร้าง &lt;a href="https://apidog.com/th/blog/mock-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;mock API&lt;/a&gt; ใน Apidog แล้วชี้ฟังก์ชันของคุณไปที่ mock แทน&lt;/p&gt;

&lt;p&gt;ตัวอย่าง mock response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Paris, France"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"temperature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"celsius"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cloudy"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้นทดสอบ flow ทั้งหมด:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ส่ง prompt ไปยัง OpenAI&lt;/li&gt;
&lt;li&gt;รับ tool call&lt;/li&gt;
&lt;li&gt;parse และ validate arguments&lt;/li&gt;
&lt;li&gt;เรียก &lt;code&gt;get_weather&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ให้ &lt;code&gt;get_weather&lt;/code&gt; เรียก Apidog mock&lt;/li&gt;
&lt;li&gt;ส่งผลลัพธ์กลับไปยังโมเดล&lt;/li&gt;
&lt;li&gt;ตรวจคำตอบสุดท้าย&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ข้อดีคือคุณสามารถจำลอง error case ได้ เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;timeout&lt;/li&gt;
&lt;li&gt;HTTP 429&lt;/li&gt;
&lt;li&gt;response body ผิดรูปแบบ&lt;/li&gt;
&lt;li&gt;field บางตัวหายไป&lt;/li&gt;
&lt;li&gt;provider ส่ง error message กลับมา&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;กรณีเหล่านี้มักทำซ้ำได้ยากกับ live API แต่จำเป็นต่อการทดสอบ production readiness&lt;/p&gt;

&lt;h2&gt;
  
  
  คำถามที่พบบ่อย
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Function calling ใช้งานได้ทั้ง Chat Completions และ Responses API หรือไม่?
&lt;/h3&gt;

&lt;p&gt;ได้ ทั้งสอง endpoint รองรับ function calling ความต่างหลักคือรูปแบบข้อมูล Chat Completions ซ้อนรายละเอียดไว้ใต้ &lt;code&gt;function&lt;/code&gt; และส่งคืน &lt;code&gt;tool_calls&lt;/code&gt; ส่วน Responses API ใช้ tool definition ที่ flat กว่า และส่งคืนรายการ &lt;code&gt;function_call&lt;/code&gt; ใน &lt;code&gt;output&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ทำไม &lt;code&gt;arguments&lt;/code&gt; เป็น string ไม่ใช่ object?
&lt;/h3&gt;

&lt;p&gt;เพราะ API ส่ง &lt;code&gt;arguments&lt;/code&gt; เป็น JSON-encoded string คุณต้อง parse เองเสมอ เช่น &lt;code&gt;JSON.parse(...)&lt;/code&gt; และควร validate ผลลัพธ์ก่อนใช้จริง การตรวจด้วย &lt;a href="https://apidog.com/th/blog/how-to-validate-json-schema?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;JSON Schema validation&lt;/a&gt; ช่วยดัก payload ที่ผิดรูปแบบก่อนถึง business logic&lt;/p&gt;

&lt;h3&gt;
  
  
  Strict mode รับประกันว่าฟังก์ชันจะสำเร็จหรือไม่?
&lt;/h3&gt;

&lt;p&gt;ไม่ Strict mode รับประกันเรื่องโครงสร้างตาม JSON Schema เท่านั้น ไม่ได้ตรวจ business rule และไม่ได้รันฟังก์ชันให้คุณ คุณยังต้องตรวจค่าด้วยตัวเอง และต้องจัดการ error จาก API ปลายทาง เช่น timeout, 404 หรือ 429&lt;/p&gt;

&lt;h3&gt;
  
  
  Apidog รันฟังก์ชันจริงของฉันได้หรือไม่?
&lt;/h3&gt;

&lt;p&gt;ไม่ Apidog ไม่ได้รัน application function ของคุณ หน้าที่ของ Apidog คือช่วยตรวจ arguments ที่โมเดลสร้างขึ้น และจำลอง API ที่ฟังก์ชันของคุณพึ่งพา แอปของคุณยังเป็นผู้รันฟังก์ชันจริง&lt;/p&gt;

&lt;h2&gt;
  
  
  สรุป
&lt;/h2&gt;

&lt;p&gt;Function calling คือ pattern ที่แบ่งหน้าที่ชัดเจน: โมเดลเลือกฟังก์ชันและสร้าง arguments ส่วนแอปของคุณ parse, validate, execute และส่งผลลัพธ์กลับไปให้โมเดลตอบผู้ใช้&lt;/p&gt;

&lt;p&gt;ขั้นตอนใช้งานจริงคือ:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;กำหนด tool ด้วยชื่อ คำอธิบาย และ JSON Schema&lt;/li&gt;
&lt;li&gt;ส่ง tool พร้อมข้อความผู้ใช้ไปยัง OpenAI&lt;/li&gt;
&lt;li&gt;อ่าน &lt;code&gt;tool_calls&lt;/code&gt; หรือ &lt;code&gt;function_call&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;parse &lt;code&gt;arguments&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;validate payload&lt;/li&gt;
&lt;li&gt;รันฟังก์ชันของคุณ&lt;/li&gt;
&lt;li&gt;ส่งผลลัพธ์กลับไปยังโมเดล&lt;/li&gt;
&lt;li&gt;เปิด &lt;code&gt;strict&lt;/code&gt; และตั้งค่า &lt;code&gt;parallel_tool_calls&lt;/code&gt; ให้เหมาะกับ flow&lt;/li&gt;
&lt;li&gt;ใช้ Apidog ตรวจ schema และ mock API ปลายทางก่อนขึ้น production&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ถ้าต้องการทดสอบด้าน API contract ให้ครบในที่เดียว ให้ &lt;a href="https://apidog.com/download?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ดาวน์โหลด Apidog&lt;/a&gt; เพื่อ validate tool call arguments กับ schema ของคุณ และจำลอง API ที่ฟังก์ชันของคุณต้องพึ่งพา&lt;/p&gt;

</description>
    </item>
    <item>
      <title>วิธีใช้งาน OpenAI API</title>
      <dc:creator>Thanawat Wongchai</dc:creator>
      <pubDate>Fri, 26 Jun 2026 03:21:35 +0000</pubDate>
      <link>https://dev.to/thanawat_wonchai/withiiaichngaan-openai-api-2iho</link>
      <guid>https://dev.to/thanawat_wonchai/withiiaichngaan-openai-api-2iho</guid>
      <description>&lt;p&gt;คู่มือนี้พาคุณใช้งาน OpenAI Responses API แบบลงมือทำ: ส่งคำขอไปยัง &lt;code&gt;POST /v1/responses&lt;/code&gt;, อ่านเอาต์พุตแบบซ้อนกัน, เปิดใช้เครื่องมือในตัว, รักษาสถานะการสนทนาข้าม request และตรวจสอบสัญญา API ด้วย &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; Responses API คืออินเทอร์เฟซใหม่ของ OpenAI สำหรับสร้างเอาต์พุตจากโมเดล และ &lt;a href="https://developers.openai.com/api/docs/guides/migrate-to-responses" rel="noopener noreferrer"&gt;คู่มือ Responses อย่างเป็นทางการ&lt;/a&gt; อธิบายว่าเหตุใด OpenAI จึงแนะนำให้โปรเจกต์ใหม่ใช้ API นี้ หากคุณเคยทดสอบเอนด์พอยต์เดิมอยู่แล้ว คุณสามารถนำ workflow ส่วนใหญ่กลับมาใช้ซ้ำได้ คล้ายกับ &lt;a href="https://apidog.com/th/blog/how-to-test-chatgpt-api-with-apidog?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;คู่มือการทดสอบ ChatGPT API ของเรา&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;ลองใช้ Apidog วันนี้&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  สิ่งที่คุณต้องมีก่อน
&lt;/h2&gt;

&lt;p&gt;ก่อนเริ่มเรียก &lt;code&gt;POST /v1/responses&lt;/code&gt; ให้เตรียมสิ่งต่อไปนี้:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI API key ที่เข้าถึงโมเดลที่ต้องการได้ เก็บไว้ใน environment variable ไม่ใส่ตรง ๆ ในคำสั่งหรือไฟล์ที่แชร์&lt;/li&gt;
&lt;li&gt;ชื่อโมเดลที่บัญชีของคุณเรียกใช้ได้ ตรวจสอบจากแดชบอร์ด OpenAI หรือทดลองเรียกเอนด์พอยต์แทนการฮาร์ดโค้ด&lt;/li&gt;
&lt;li&gt;เครื่องมือส่ง HTTP request และดู JSON response เช่น &lt;code&gt;curl&lt;/code&gt; สำหรับทดสอบเร็ว ๆ และ &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; สำหรับตรวจสอบ schema, assertion และ mock response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Responses API มีเอนด์พอยต์หลักคือ &lt;a href="https://platform.openai.com/docs/api-reference/responses" rel="noopener noreferrer"&gt;&lt;code&gt;POST /v1/responses&lt;/code&gt;&lt;/a&gt; คุณส่ง &lt;code&gt;model&lt;/code&gt; และ &lt;code&gt;input&lt;/code&gt; แล้วจะได้ response object ที่อาจมีข้อความ, function call และผลลัพธ์จากเครื่องมือที่ OpenAI โฮสต์ เช่น web search หรือ file search&lt;/p&gt;

&lt;p&gt;การเรียกครั้งเดียวอาจมีหลายขั้นตอน เช่น โมเดลตัดสินใจค้นเว็บ อ่านผลลัพธ์ แล้วจึงเขียนคำตอบ รายละเอียดแต่ละขั้นตอนจะอยู่ใน &lt;code&gt;output&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;จุดต่างหลักจาก API แบบข้อความเดิมมี 2 อย่าง:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ใช้เครื่องมือในตัวฝั่งเซิร์ฟเวอร์ได้ ไม่ต้องสร้างระบบค้นหา ไฟล์ หรือ sandbox เองทั้งหมด&lt;/li&gt;
&lt;li&gt;มี state โดยค่าเริ่มต้น ทุก response มี &lt;code&gt;id&lt;/code&gt; และคุณส่ง &lt;code&gt;id&lt;/code&gt; นั้นเป็น &lt;code&gt;previous_response_id&lt;/code&gt; ใน request ถัดไปเพื่อสนทนาต่อได้&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;OpenAI อธิบาย Responses API ว่าเป็นวิวัฒนาการของ Chat Completions และแนะนำสำหรับโปรเจกต์ใหม่ โดยรวมบทเรียนจาก Assistants API beta ให้เหลือโมเดลการทำงานเดียว&lt;/p&gt;

&lt;h2&gt;
  
  
  ทำความเข้าใจว่าต่างจาก Chat Completions อย่างไร
&lt;/h2&gt;

&lt;p&gt;ถ้าคุณเคยใช้ &lt;code&gt;POST /v1/chat/completions&lt;/code&gt; ความต่างหลักคือรูปแบบ request/response และการจัดการ state&lt;/p&gt;

&lt;p&gt;Chat Completions ใช้ &lt;code&gt;messages&lt;/code&gt; array และคืนค่าใน &lt;code&gt;choices&lt;/code&gt; คุณต้องส่งประวัติการสนทนาทั้งหมดซ้ำในการเรียกแต่ละครั้ง และต้องจัดการ tool execution เอง&lt;/p&gt;

&lt;p&gt;Responses API ใช้ &lt;code&gt;input&lt;/code&gt; ซึ่งเป็น string หรือรายการแบบระบุชนิด และคืนค่าใน &lt;code&gt;output&lt;/code&gt; ซึ่งเป็นรายการแบบระบุชนิดเช่นกัน นอกจากนี้ยังจัดเก็บสถานะและเรียกใช้เครื่องมือที่โฮสต์โดย OpenAI ได้&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ด้าน&lt;/th&gt;
&lt;th&gt;Chat Completions&lt;/th&gt;
&lt;th&gt;Responses API&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;เอนด์พอยต์&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST /v1/chat/completions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST /v1/responses&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;เนื้อหาคำขอ&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;messages&lt;/code&gt; array&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;input&lt;/code&gt; + &lt;code&gt;instructions&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;รูปแบบเอาต์พุต&lt;/td&gt;
&lt;td&gt;&lt;code&gt;choices[].message&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;output&lt;/code&gt; array ของรายการแบบระบุชนิด&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;สถานะการสนทนา&lt;/td&gt;
&lt;td&gt;ต้องส่งประวัติทั้งหมดซ้ำ&lt;/td&gt;
&lt;td&gt;ใช้ &lt;code&gt;store&lt;/code&gt; + &lt;code&gt;previous_response_id&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;เครื่องมือในตัว&lt;/td&gt;
&lt;td&gt;ต้องสร้างเอง&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;web_search&lt;/code&gt;, &lt;code&gt;file_search&lt;/code&gt;, &lt;code&gt;code_interpreter&lt;/code&gt; และอื่น ๆ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;สถานะผลิตภัณฑ์&lt;/td&gt;
&lt;td&gt;ยังรองรับ ไม่มีประกาศเลิกใช้&lt;/td&gt;
&lt;td&gt;แนะนำสำหรับโปรเจกต์ใหม่&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Chat Completions ยังไม่หายไป OpenAI ระบุว่าจะยังรองรับต่อ และคุณสามารถย้าย workflow ทีละส่วนได้ ไม่จำเป็นต้องเขียนใหม่ทั้งหมดในครั้งเดียว&lt;/p&gt;

&lt;p&gt;ส่วน Assistants API กำลังจะถูกเลิกใช้งาน: OpenAI เลิกใช้งานเมื่อวันที่ 26 สิงหาคม 2025 และมีกำหนดสิ้นสุดวันที่ 26 สิงหาคม 2026 ดังนั้นงาน agent ใหม่ควรเริ่มบน Responses API&lt;/p&gt;

&lt;h2&gt;
  
  
  เรียก Responses API ครั้งแรก
&lt;/h2&gt;

&lt;p&gt;เริ่มด้วย request ขั้นต่ำนี้ เปลี่ยนชื่อโมเดลให้ตรงกับโมเดลที่บัญชีของคุณเข้าถึงได้ และเก็บ API key ไว้ใน environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.openai.com/v1/responses &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$OPENAI_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "model": "gpt-5.5",
    "input": "Write one sentence describing what an API mock server does.",
    "instructions": "You are a concise technical writer. No marketing language.",
    "store": true
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ฟิลด์สำคัญใน request นี้คือ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;model&lt;/code&gt;: โมเดลที่ต้องการใช้&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;input&lt;/code&gt;: prompt หรือข้อมูลที่ส่งให้โมเดล&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;instructions&lt;/code&gt;: คำสั่งระดับระบบหรือแนวทางการตอบ&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;store&lt;/code&gt;: ตั้งเป็น &lt;code&gt;true&lt;/code&gt; เพื่อให้ OpenAI บันทึก response object และนำไปใช้สนทนาต่อได้&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  อ่าน response ที่ได้กลับมา
&lt;/h2&gt;

&lt;p&gt;ตัวอย่าง response แบบตัดทอน:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"resp_abc123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"response"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"completed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gpt-5.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"assistant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"output_text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A mock server returns predefined API responses so clients can be developed and tested before the real backend exists."&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"usage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"input_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"output_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"total_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จุดที่ควรสังเกต:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ข้อความอยู่ที่ &lt;code&gt;output[0].content[0].text&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ไม่ได้อยู่ใน field ระดับบนสุด&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; ระดับบนสุดคือค่าที่ใช้ต่อกับ &lt;code&gt;previous_response_id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;usage.total_tokens&lt;/code&gt; ใช้ดูปริมาณ token ของ request นั้น&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SDK อย่างเป็นทางการอาจมี helper เช่น &lt;code&gt;output_text&lt;/code&gt; เพื่อรวมข้อความให้เป็น string เดียว แต่ถ้าคุณเรียก HTTP API โดยตรง ให้ parse จาก path ที่ซ้อนอยู่ใน &lt;code&gt;output&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ตัวอย่างอ่านค่าด้วย &lt;code&gt;jq&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.openai.com/v1/responses &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$OPENAI_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "model": "gpt-5.5",
    "input": "Write one sentence describing what an API mock server does."
  }'&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.output[0].content[0].text'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  เพิ่มเครื่องมือในตัว
&lt;/h2&gt;

&lt;p&gt;Responses API สามารถให้ OpenAI เรียกใช้เครื่องมือบางอย่างให้คุณได้ โดยประกาศใน &lt;code&gt;tools&lt;/code&gt; array แล้วให้โมเดลตัดสินใจเองว่าจะเรียกใช้เมื่อใด&lt;/p&gt;

&lt;p&gt;ประเภทเครื่องมือในตัวที่กล่าวถึง ได้แก่:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;web_search&lt;/code&gt; สำหรับค้นหาอินเทอร์เน็ตแบบเรียลไทม์พร้อม citation (&lt;code&gt;web_search_preview&lt;/code&gt; แบบเก่ายังใช้ได้กับ integration เดิม แต่ไม่มี control ใหม่)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;file_search&lt;/code&gt; สำหรับดึงข้อมูลจากไฟล์ที่คุณอัปโหลด&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;code_interpreter&lt;/code&gt; สำหรับรันและวิเคราะห์โค้ดใน sandbox&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;computer_use&lt;/code&gt; สำหรับควบคุมอินเทอร์เฟซคอมพิวเตอร์&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;image_generation&lt;/code&gt; สำหรับสร้างภาพใน response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่างเปิดใช้ web search:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gpt-5.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What changed in the latest OpenAPI release? Cite sources."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"web_search"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เมื่อโมเดลใช้เครื่องมือ &lt;code&gt;output&lt;/code&gt; จะมีรายการที่บันทึกขั้นตอน เช่น &lt;code&gt;web_search_call&lt;/code&gt; และตามด้วย &lt;code&gt;message&lt;/code&gt; สุดท้าย คุณจึงตรวจสอบได้ว่าโมเดลเรียกใช้เครื่องมือจริง ไม่ใช่แค่ตอบข้อความกลับมา&lt;/p&gt;

&lt;p&gt;ตัวอย่าง assertion ที่ควรตรวจ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expected_tool_call_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"web_search_call"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;path ที่ใช้ตรวจใน response คือรายการใดรายการหนึ่งใน &lt;code&gt;output&lt;/code&gt; ที่มี:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"web_search_call"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  สนทนาต่อข้าม request
&lt;/h2&gt;

&lt;p&gt;Responses API ใช้ 2 parameter สำหรับ state:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;store&lt;/code&gt;: ควบคุมว่า OpenAI จะจัดเก็บ response object หรือไม่ ค่าเริ่มต้นเป็นจริง และเก็บไว้ 30 วันโดยค่าเริ่มต้น&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;previous_response_id&lt;/code&gt;: ใช้เชื่อม request ใหม่กับ response เดิม&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง request ถัดไป:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gpt-5.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Now rewrite that for a non-technical audience."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"previous_response_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"resp_abc123"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;คุณไม่ต้องส่งประวัติการสนทนาทั้งหมดซ้ำ เพราะ OpenAI ใช้ &lt;code&gt;previous_response_id&lt;/code&gt; เพื่อผูกบริบทให้&lt;/p&gt;

&lt;p&gt;ถ้าต้องการทำงานแบบ stateless หรือมีข้อกำหนดห้ามเก็บข้อมูล ให้ตั้งค่า:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แล้วจัดการบริบทเองในฝั่งแอป&lt;/p&gt;

&lt;p&gt;สำหรับงาน voice และ low-latency realtime audio OpenAI ใช้พื้นผิว API คนละแบบ ดูเพิ่มเติมใน &lt;a href="https://apidog.com/th/blog/gpt-realtime-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;คู่มือ GPT realtime API ของเรา&lt;/a&gt; และถ้าคุณสร้าง agent หลายขั้นตอน รูปแบบโดยรวมจะสอดคล้องกับ &lt;a href="https://apidog.com/th/blog/how-to-use-openai-agents-sdk?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;OpenAI Agents SDK&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  วิธีทดสอบใน Apidog
&lt;/h2&gt;

&lt;p&gt;Apidog เป็นแพลตฟอร์มสำหรับทดสอบ ออกแบบ และ mock API ไม่ใช่ OpenAI SDK ดังนั้น workflow คือ:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;สร้าง HTTP request ไปที่ &lt;code&gt;/v1/responses&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ส่ง request พร้อม header และ body ที่ถูกต้อง&lt;/li&gt;
&lt;li&gt;ดู JSON response จริง&lt;/li&gt;
&lt;li&gt;เขียน assertion บน field ที่แอปของคุณต้องใช้&lt;/li&gt;
&lt;li&gt;บันทึก response ที่เป็นตัวแทนไว้ใช้ mock สำหรับ dev/test&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.apidog.com%2Fblog-next%2F2026%2F06%2Fimage-468.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.apidog.com%2Fblog-next%2F2026%2F06%2Fimage-468.png" alt="" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. เก็บ API key ใน environment variable
&lt;/h3&gt;

&lt;p&gt;ใน Apidog ให้สร้าง environment เช่น &lt;code&gt;OpenAI Prod&lt;/code&gt; แล้วเพิ่มตัวแปร:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OPENAI_API_KEY=sk-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้นสร้าง request ใหม่:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST https://api.openai.com/v1/responses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพิ่ม header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authorization: Bearer {{OPENAI_API_KEY}}
Content-Type: application/json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apidog จะแทนค่าตัวแปรตอนส่ง request ทำให้ไม่ต้องใส่ secret ลงใน request ที่อาจถูกแชร์ในทีม&lt;/p&gt;

&lt;h3&gt;
  
  
  2. ใส่ JSON body
&lt;/h3&gt;

&lt;p&gt;ใช้ body แบบนี้เป็น baseline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gpt-5.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Write one sentence describing what an API mock server does."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"instructions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"You are a concise technical writer. No marketing language."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;กดส่ง แล้วตรวจ response ที่ได้ โดยเฉพาะ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;id
status
output
usage.total_tokens
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. ยืนยัน field ที่แอปต้องพึ่งพา
&lt;/h3&gt;

&lt;p&gt;HTTP 200 ไม่ได้แปลว่า response มีรูปแบบตรงกับที่แอปคาดหวังเสมอ ให้เพิ่ม assertion เพื่อให้ regression fail ชัดเจน&lt;/p&gt;

&lt;p&gt;ตัวอย่าง validation ที่ควรมี:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;status&lt;/code&gt; เท่ากับ &lt;code&gt;completed&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;output[0].content[0].text&lt;/code&gt; มีอยู่และไม่เป็นค่าว่าง&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;usage.total_tokens&lt;/code&gt; มากกว่า &lt;code&gt;0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;เมื่อส่ง &lt;code&gt;tools&lt;/code&gt; แล้ว ใน &lt;code&gt;output&lt;/code&gt; มี item ที่ &lt;code&gt;type&lt;/code&gt; เท่ากับ &lt;code&gt;web_search_call&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่างแนวคิด assertion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;status == "completed"
output[0].content[0].text exists
usage.total_tokens &amp;gt; 0
output[*].type contains "web_search_call"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เครื่องมือ assertion แบบ visual ของ Apidog ช่วยกำหนด JSON path เหล่านี้ได้โดยไม่ต้องเขียน test script เอง ดูแนวทางจัดโครงสร้างได้จาก &lt;a href="https://apidog.com/th/blog/api-test-case-example?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;เทมเพลตกรณีทดสอบ API&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;เมื่อบันทึก request ลง collection แล้ว คุณสามารถรันซ้ำใน CI เพื่อจับ breaking change ได้&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Mock response สำหรับพัฒนาแบบออฟไลน์
&lt;/h3&gt;

&lt;p&gt;การเรียก OpenAI มีค่าใช้จ่ายและต้องใช้ network ซึ่งไม่เหมาะกับทุกกรณี เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;สร้าง UI ที่อ่าน response object&lt;/li&gt;
&lt;li&gt;รัน test pipeline ที่ไม่ควรเรียก API แบบเสียเงิน&lt;/li&gt;
&lt;li&gt;ต้องการผลลัพธ์ deterministic&lt;/li&gt;
&lt;li&gt;ทำงาน offline&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;วิธีทำใน Apidog:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ส่ง request จริงไปยัง &lt;code&gt;/v1/responses&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;บันทึก payload response ที่เป็นตัวแทน&lt;/li&gt;
&lt;li&gt;สร้าง mock จาก payload นั้น&lt;/li&gt;
&lt;li&gt;ชี้ frontend หรือ test client ไปที่ mock URL ของ Apidog&lt;/li&gt;
&lt;li&gt;ใช้ JSON shape เดียวกับ production โดยไม่ใช้ token จริง&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;เมื่อ response shape ของเอนด์พอยต์จริงเปลี่ยน คุณอัปเดต mock เพียงจุดเดียว แทนที่จะไล่แก้ test หลายที่ อ่านแนวคิดเพิ่มเติมได้ใน &lt;a href="https://apidog.com/th/blog/mock-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;คำอธิบาย API จำลอง&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;แนวทางที่ดีคือแยกการใช้งานเป็น 2 ชั้น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ใช้เอนด์พอยต์จริงเพื่อตรวจ contract กับ OpenAI&lt;/li&gt;
&lt;li&gt;ใช้ mock เพื่อพัฒนาและทดสอบแบบรวดเร็ว ควบคุมได้ และไม่พึ่ง network&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ทั้งสองอย่างจัดการได้ในโปรเจกต์ Apidog เดียวกัน&lt;/p&gt;

&lt;h2&gt;
  
  
  คำถามที่พบบ่อย
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Responses API จะมาแทนที่ Chat Completions หรือไม่?
&lt;/h3&gt;

&lt;p&gt;ไม่ได้บังคับ OpenAI เรียก Responses ว่าเป็นวิวัฒนาการของ Chat Completions และแนะนำสำหรับโปรเจกต์ใหม่ แต่ Chat Completions ยังรองรับอยู่โดยไม่มีประกาศวันเลิกใช้งาน คุณสามารถย้าย workflow ทีละส่วนได้&lt;/p&gt;

&lt;p&gt;ส่วน Assistants API เป็น API ที่กำลังจะเลิกใช้งาน โดยมีวันสิ้นสุดในปี 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  ความแตกต่างระหว่าง &lt;code&gt;store&lt;/code&gt; และ &lt;code&gt;previous_response_id&lt;/code&gt; คืออะไร?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;store&lt;/code&gt; ควบคุมว่า OpenAI จะบันทึก response object หรือไม่ ค่าเริ่มต้นเป็นจริงและเก็บไว้ 30 วันโดยค่าเริ่มต้น&lt;/p&gt;

&lt;p&gt;&lt;code&gt;previous_response_id&lt;/code&gt; ใช้เชื่อม request ใหม่กับ response ที่บันทึกไว้ เพื่อให้โมเดลสนทนาต่อฝั่งเซิร์ฟเวอร์&lt;/p&gt;

&lt;p&gt;ใช้ร่วมกันเมื่อต้องการ thread แบบมี state และตั้ง &lt;code&gt;store: false&lt;/code&gt; เมื่อต้องการควบคุม context เอง&lt;/p&gt;

&lt;h3&gt;
  
  
  โมเดลใดบ้างที่รองรับ Responses API?
&lt;/h3&gt;

&lt;p&gt;โมเดลทั่วไปในปัจจุบันของ OpenAI ถูกออกแบบให้ทำงานกับ Responses API แต่ความพร้อมใช้งานขึ้นอยู่กับบัญชีและโมเดลที่คุณเลือก&lt;/p&gt;

&lt;p&gt;แนวทางที่ปลอดภัยคือ:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ตรวจรายการโมเดลในแดชบอร์ด OpenAI&lt;/li&gt;
&lt;li&gt;ส่ง request ทดสอบผ่าน Apidog หรือ &lt;code&gt;curl&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;อ่านค่า &lt;code&gt;model&lt;/code&gt; ใน response เพื่อยืนยันว่า key ของคุณเรียกใช้งานได้&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ทดสอบเครื่องมือในตัวโดยไม่เขียนโค้ดได้ไหม?
&lt;/h3&gt;

&lt;p&gt;ได้ เพิ่ม &lt;code&gt;tools&lt;/code&gt; array ใน JSON body ผ่าน Apidog ส่ง request แล้วตรวจว่า item การเรียกเครื่องมือ เช่น &lt;code&gt;web_search_call&lt;/code&gt; ปรากฏใน &lt;code&gt;output&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ตัวอย่าง body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gpt-5.5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Summarize the latest API design best practices and cite sources."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"web_search"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จากนั้น assert ว่า:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;output[*].type contains "web_search_call"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;การทดสอบนี้เป็นการตรวจพฤติกรรมผ่าน HTTP โดยตรง จึงไม่ต้องใช้ SDK สำหรับการสร้างชุดทดสอบ agent หรือ API ที่ใหญ่ขึ้น ดู &lt;a href="https://apidog.com/th/blog/api-test-collections-generation-openapi-specs?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;วิธีสร้างชุดการทดสอบ API จาก OpenAPI specs&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  สรุป
&lt;/h2&gt;

&lt;p&gt;Responses API รวมข้อความ เครื่องมือที่ OpenAI โฮสต์ และ state การสนทนาไว้ในเอนด์พอยต์เดียวคือ &lt;code&gt;POST /v1/responses&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;workflow หลักคือ:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ส่ง &lt;code&gt;model&lt;/code&gt;, &lt;code&gt;input&lt;/code&gt; และ &lt;code&gt;instructions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;อ่านผลลัพธ์จาก &lt;code&gt;output[0].content[0].text&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;เปิดใช้เครื่องมือผ่าน &lt;code&gt;tools&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ใช้ &lt;code&gt;previous_response_id&lt;/code&gt; เพื่อสนทนาต่อ&lt;/li&gt;
&lt;li&gt;เพิ่ม assertion เพื่อยืนยัน contract ของ response&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;เพราะ response shape ต่างจาก Chat Completions วิธีที่ปลอดภัยที่สุดคือทดสอบ contract จริง ไม่พึ่งความจำจาก API เดิม&lt;/p&gt;

&lt;p&gt;ใน Apidog คุณสามารถสร้าง request, เก็บ key เป็น environment variable, assert field ที่ซ้อนอยู่ใน &lt;code&gt;output&lt;/code&gt; และ mock response สำหรับงาน offline ได้ในโปรเจกต์เดียว &lt;a href="https://apidog.com/download?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ดาวน์โหลด Apidog&lt;/a&gt; แล้วชี้การทดสอบไปที่ &lt;code&gt;/v1/responses&lt;/code&gt; เพื่อดูว่า integration ของคุณได้รับ JSON แบบใดจริง ๆ หรือเริ่มตั้งค่าทั้งหมดใน &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; ได้โดยไม่ต้องเขียน test code แม้แต่บรรทัดเดียว&lt;/p&gt;

</description>
    </item>
    <item>
      <title>วิธีใช้งาน OpenAI Structured Outputs</title>
      <dc:creator>Thanawat Wongchai</dc:creator>
      <pubDate>Fri, 26 Jun 2026 03:18:39 +0000</pubDate>
      <link>https://dev.to/thanawat_wonchai/withiiaichngaan-openai-structured-outputs-3p8n</link>
      <guid>https://dev.to/thanawat_wonchai/withiiaichngaan-openai-structured-outputs-3p8n</guid>
      <description>&lt;p&gt;เมื่อจบคู่มือนี้ คุณจะสามารถเรียกใช้ structured outputs ของ OpenAI จากโค้ดของคุณเองได้: ส่ง JSON Schema ให้โมเดล, ตั้งค่า &lt;code&gt;strict: true&lt;/code&gt; และรับผลตอบกลับที่ตรงกับรูปแบบที่ต้องการ จากนั้นคุณจะได้ส่งคำขอแรก, parse ผลลัพธ์, จัดการกรณีปฏิเสธ/ตัดทอน และ&lt;a href="https://apidog.com/th/blog/api-test-collections-generation-openapi-specs?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;สร้างชุดการทดสอบ API&lt;/a&gt; ใน Apidog เพื่อยืนยันว่า payload ตรงตาม schema จริง&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;ลองใช้ Apidog วันนี้&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  สิ่งที่คุณต้องมีก่อนเริ่มต้น
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developers.openai.com/api/docs/guides/structured-outputs" rel="noopener noreferrer"&gt;Structured outputs&lt;/a&gt; จำกัดการสร้างผลลัพธ์ของโมเดลให้เป็นไปตาม JSON Schema ที่คุณกำหนด เมื่อส่ง schema พร้อม &lt;code&gt;strict: true&lt;/code&gt; โมเดลจะสร้างผลลัพธ์ที่มีคีย์, ประเภทข้อมูล และค่า enum ตรงตามข้อกำหนด แทนที่จะต้องเขียนโค้ดกัน parsing พังจาก JSON ที่รูปร่างไม่แน่นอน&lt;/p&gt;

&lt;p&gt;Structured outputs ต่างจากการ prompt แบบ “ตอบกลับเป็น JSON เท่านั้น” เพราะคำสั่งแบบนั้นรับประกันได้แค่ในเชิงพฤติกรรม ไม่ใช่ข้อบังคับระดับ schema โมเดลอาจเพิ่มข้อความอธิบาย, คืนชนิดข้อมูลผิด หรือขาดฟิลด์ที่จำเป็นได้ ส่วน structured outputs บังคับใช้ข้อจำกัด ณ เวลาถอดรหัส&lt;/p&gt;

&lt;p&gt;ก่อนเริ่ม คุณต้องมี:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI API key ที่ตั้งค่าไว้ใน environment variable ชื่อ &lt;code&gt;OPENAI_API_KEY&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;โมเดลที่รองรับ schema แบบเข้มงวด&lt;/li&gt;
&lt;li&gt;JSON Schema ที่อธิบาย output ที่ต้องการ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  เลือกโมเดลที่เหมาะสม
&lt;/h2&gt;

&lt;p&gt;Structured outputs ใช้งานได้ในโมเดล OpenAI รุ่นใหม่ตั้งแต่ตระกูล GPT-4o และต่อเนื่องถึงซีรีส์ GPT-5 เอกสารของ OpenAI แนะนำให้เริ่มโปรเจกต์ใหม่ด้วยโมเดลเรือธงล่าสุด (&lt;code&gt;gpt-5.5&lt;/code&gt; ในขณะที่เขียน)&lt;/p&gt;

&lt;p&gt;โมเดลรุ่นเก่าและโมเดลยุค &lt;code&gt;gpt-3.5&lt;/code&gt; รองรับ JSON mode แต่ไม่รองรับการบังคับใช้ schema แบบเข้มงวด หากคุณต้องพึ่ง &lt;code&gt;strict: true&lt;/code&gt; ให้ตรวจสอบ model ID ที่ใช้จริงก่อน deploy เพราะความสามารถนี้ผูกกับเวอร์ชันของโมเดล&lt;/p&gt;

&lt;p&gt;OpenAI มี 2 ฟีเจอร์ที่คล้ายกันแต่ไม่เหมือนกัน:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JSON mode&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"response_format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json_object"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JSON mode รับประกันว่า output เป็น JSON ที่ถูกต้องตามไวยากรณ์ แต่ไม่รับประกันว่าฟิลด์, ชนิดข้อมูล หรือ enum จะตรงกับ schema ของคุณ&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structured outputs&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"response_format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json_schema"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"json_schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"schema_name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Structured outputs รับประกันทั้ง JSON ที่ถูกต้องและรูปร่างที่ตรงกับ schema&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;โหมด JSON&lt;/th&gt;
&lt;th&gt;Structured outputs แบบเข้มงวด&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;พารามิเตอร์&lt;/td&gt;
&lt;td&gt;&lt;code&gt;response_format: {"type":"json_object"}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;response_format&lt;/code&gt; พร้อม &lt;code&gt;type: "json_schema"&lt;/code&gt; และ &lt;code&gt;strict: true&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON ถูกต้อง&lt;/td&gt;
&lt;td&gt;ใช่&lt;/td&gt;
&lt;td&gt;ใช่&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ตรงกับ schema&lt;/td&gt;
&lt;td&gt;ไม่&lt;/td&gt;
&lt;td&gt;ใช่&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;บังคับฟิลด์ที่จำเป็น&lt;/td&gt;
&lt;td&gt;ไม่&lt;/td&gt;
&lt;td&gt;ใช่&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;บังคับ type และ enum&lt;/td&gt;
&lt;td&gt;ไม่&lt;/td&gt;
&lt;td&gt;ใช่&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ยังควร validate ต่อไหม&lt;/td&gt;
&lt;td&gt;ควรเสมอ&lt;/td&gt;
&lt;td&gt;ควรสำหรับกฎระดับค่าและ regression test&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;หมายเหตุเรื่อง API: Chat Completions ใช้ &lt;code&gt;response_format&lt;/code&gt; ส่วน Responses API รุ่นใหม่แสดงแนวคิดเดียวกันภายใต้ &lt;code&gt;text.format&lt;/code&gt; พร้อม &lt;code&gt;type: "json_schema"&lt;/code&gt; กฎของ schema เหมือนกัน ต่างกันแค่ตำแหน่งของฟิลด์ใน request&lt;/p&gt;

&lt;h2&gt;
  
  
  ส่งคำขอ structured output ครั้งแรก
&lt;/h2&gt;

&lt;p&gt;ตัวอย่างนี้ดึงข้อมูลจากข้อความ ticket support ให้เป็น object ที่มี schema ชัดเจน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.openai.com/v1/chat/completions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$OPENAI_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "model": "gpt-5.5",
    "messages": [
      {
        "role": "system",
        "content": "Extract the ticket into the schema."
      },
      {
        "role": "user",
        "content": "My checkout 500s every time I use a saved card. Started today. Account: acct_8842."
      }
    ],
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "support_ticket",
        "strict": true,
        "schema": {
          "type": "object",
          "properties": {
            "summary": {
              "type": "string"
            },
            "category": {
              "type": "string",
              "enum": ["billing", "bug", "account", "other"]
            },
            "severity": {
              "type": "integer"
            },
            "account_id": {
              "anyOf": [
                { "type": "string" },
                { "type": "null" }
              ]
            }
          },
          "required": ["summary", "category", "severity", "account_id"],
          "additionalProperties": false
        }
      }
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จุดที่ต้องสังเกต:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;type: "json_schema"&lt;/code&gt; เปิด structured outputs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;strict: true&lt;/code&gt; บังคับให้ output ตรง schema&lt;/li&gt;
&lt;li&gt;ทุก property อยู่ใน &lt;code&gt;required&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;additionalProperties: false&lt;/code&gt; ป้องกันคีย์ส่วนเกิน&lt;/li&gt;
&lt;li&gt;ฟิลด์ที่อาจไม่มีค่าใช้ &lt;code&gt;anyOf&lt;/code&gt; ร่วมกับ &lt;code&gt;null&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  อ่านผลตอบกลับ
&lt;/h2&gt;

&lt;p&gt;โมเดลจะคืน &lt;code&gt;message.content&lt;/code&gt; เป็น string JSON ที่ตรงกับ schema เช่น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Checkout returns HTTP 500 when paying with a saved card"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bug"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"severity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"account_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"acct_8842"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ในแอปจริง คุณควร parse JSON หลังจากตรวจสอบว่าไม่มี &lt;code&gt;refusal&lt;/code&gt; และผลลัพธ์ไม่ถูกตัดทอน&lt;/p&gt;

&lt;p&gt;ตัวอย่าง Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;refusal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;handle_refusal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;refusal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;ticket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;process_ticket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ticket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  เขียน schema ให้อยู่ใน subset ที่รองรับ
&lt;/h2&gt;

&lt;p&gt;Structured outputs รองรับเพียง subset ของ &lt;a href="https://json-schema.org/" rel="noopener noreferrer"&gt;JSON Schema&lt;/a&gt; เพื่อให้ OpenAI บังคับใช้ข้อจำกัดได้อย่างน่าเชื่อถือและ cache schema ที่ compile แล้วได้&lt;/p&gt;

&lt;p&gt;กฎสำคัญ:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;root ต้องเป็น object&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ใช้ไม่ได้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"array"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใช้ object ห่อแทน:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"array"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"additionalProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ทุก property ต้องอยู่ใน &lt;code&gt;required&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Structured outputs ไม่มี optional field แบบดั้งเดิม หากค่าขาดได้ ให้ทำเป็น nullable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"account_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"anyOf"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"null"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ทุก object ต้องมี &lt;code&gt;additionalProperties: false&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;วิธีนี้ทำให้โมเดลไม่สร้างคีย์ที่ schema ไม่ได้ประกาศไว้&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;schema มีข้อจำกัดด้านขนาด&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;โดยทั่วไป schema รองรับ object properties ได้ประมาณ 100 รายการ และซ้อนกันได้สูงสุด 5 ระดับ หาก schema กว้างหรือลึกเกินไป อาจถูกปฏิเสธ ควร flatten เท่าที่เหมาะสม&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;บาง keyword ไม่ได้ถูกบังคับใช้โดยโมเดล&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;keyword อย่าง &lt;code&gt;pattern&lt;/code&gt;, &lt;code&gt;format&lt;/code&gt;, &lt;code&gt;minLength&lt;/code&gt; และ &lt;code&gt;minimum&lt;/code&gt; ไม่ได้รับประกันจากโมเดล ถ้าคุณต้องการ regex, date format หรือช่วงตัวเลขที่เข้มงวด ให้ validate ซ้ำในแอปหรือ test pipeline&lt;/p&gt;

&lt;p&gt;ดังนั้น “JSON ที่รับประกัน” หมายถึงรูปร่างของ object ถูกล็อก ไม่ได้หมายความว่ากฎทางธุรกิจถูกต้องทั้งหมด ถ้าคุณเคยใช้ &lt;a href="https://apidog.com/th/blog/api-parameters-json-schema?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;oneOf/anyOf/allOf เพื่อสร้าง optional หรือ union fields&lt;/a&gt; แนวคิดจะคล้ายกัน: schema คุมโครงสร้าง ส่วน business validation ต้องทำต่อเอง&lt;/p&gt;

&lt;h2&gt;
  
  
  จัดการ refusal และ output ที่ถูกตัดทอน
&lt;/h2&gt;

&lt;p&gt;มีกรณีที่ output จะไม่ตรง schema โดยตั้งใจ: เมื่อโมเดลปฏิเสธคำขอที่ไม่ปลอดภัย โมเดลจะคืน &lt;code&gt;refusal&lt;/code&gt; แทน content ที่เป็น JSON ตาม schema&lt;/p&gt;

&lt;p&gt;ตรวจสอบ &lt;code&gt;refusal&lt;/code&gt; ก่อน parse เสมอ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;refusal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;handle_refusal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;refusal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;

&lt;span class="n"&gt;ticket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;กรณีอื่นที่ต้องระวัง:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;response ถูกตัดกลางคันเพราะถึง &lt;code&gt;max_tokens&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ใช้ parallel tool calls ร่วมกับ structured outputs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ถ้าคุณใช้ tool calls ร่วมด้วย ให้ตั้งค่า:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parallel_tool_calls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ทดสอบ structured outputs ใน Apidog
&lt;/h2&gt;

&lt;p&gt;โหมดเข้มงวดช่วยบังคับ schema ตอนโมเดลสร้างผลลัพธ์ แต่ยังไม่แทนที่การทดสอบ เพราะ model ID อาจถูกเปลี่ยน, schema อาจถูกแก้, prompt อาจเปลี่ยน หรือเส้นทาง refusal อาจทำงานต่างจากเดิม&lt;/p&gt;

&lt;p&gt;คุณสามารถใช้ &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; เพื่อสร้าง request, assertion และ mock สำหรับ workflow นี้&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fatn7lky3ymkr76z9kvyw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fatn7lky3ymkr76z9kvyw.png" alt="Apidog interface" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;การแบ่งหน้าที่ควรเป็นแบบนี้:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI structured outputs: สร้าง JSON ให้ตรง schema&lt;/li&gt;
&lt;li&gt;Apidog: ตรวจสอบ response ที่ได้รับเทียบกับ schema และทำให้ความผิดพลาดถูกจับได้ใน CI&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ขั้นตอนใช้งาน
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;สร้าง request&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;สร้าง request ไปยัง Chat Completions ใน Apidog ใส่ headers และ body ที่มี &lt;code&gt;response_format&lt;/code&gt; ตามตัวอย่างด้านบน จากนั้นบันทึกไว้ใน collection&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;เพิ่ม assertion สำหรับ response&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ตรวจสอบค่าหลัก เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;category&lt;/code&gt; ต้องเป็น &lt;code&gt;billing&lt;/code&gt;, &lt;code&gt;bug&lt;/code&gt;, &lt;code&gt;account&lt;/code&gt; หรือ &lt;code&gt;other&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;severity&lt;/code&gt; ต้องเป็น integer&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;account_id&lt;/code&gt; ต้องเป็น string หรือ &lt;code&gt;null&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apidog สามารถ&lt;a href="https://apidog.com/th/blog/how-to-validate-json-schema?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ตรวจสอบ response เทียบกับ JSON Schema&lt;/a&gt; ได้โดยแนบ schema เดียวกับที่คุณส่งให้ OpenAI&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;รันใน CI&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ใส่ collection เข้า pipeline เพื่อให้ทุกการเปลี่ยน model, prompt หรือ schema ถูกทดสอบซ้ำ หาก response ผิด contract ให้ build fail ทันที&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;สร้าง mock API&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ก่อนต่อ OpenAI จริง หรือเมื่อต้องการทดสอบ frontend/consumer โดยไม่ใช้ token ให้ตั้งค่า &lt;a href="https://apidog.com/th/blog/mock-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;mock API&lt;/a&gt; ที่คืนตัวอย่าง response ตาม schema เดียวกัน&lt;/p&gt;

&lt;p&gt;แนวทางนี้ช่วยให้ทีมที่ consume structured output ทำงานต่อได้โดยไม่ต้องรอ integration เสร็จทั้งหมด คุณสามารถ&lt;a href="https://apidog.com/download?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ดาวน์โหลด Apidog&lt;/a&gt; แล้วจัดการ request, assertion และ mock ในที่เดียว&lt;/p&gt;

&lt;h2&gt;
  
  
  คำถามที่พบบ่อย
&lt;/h2&gt;

&lt;h3&gt;
  
  
  JSON mode ถูกแทนที่ด้วย structured outputs แล้วหรือยัง?
&lt;/h3&gt;

&lt;p&gt;ยังไม่ถูกแทนที่ JSON mode ยังใช้ได้และยังรับประกัน JSON ที่ valid แต่ไม่บังคับ schema สำหรับโค้ดใหม่ที่มีรูปแบบข้อมูลชัดเจน ควรใช้ structured outputs พร้อม &lt;code&gt;strict: true&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  root schema เป็น array ได้ไหม?
&lt;/h3&gt;

&lt;p&gt;ไม่ได้ ระดับบนสุดต้องเป็น object ให้ห่อ array ไว้ใน property เช่น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"array"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"additionalProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ทำ optional field อย่างไร?
&lt;/h3&gt;

&lt;p&gt;Structured outputs กำหนดให้ทุก property อยู่ใน &lt;code&gt;required&lt;/code&gt; ถ้าค่าหายได้ ให้ใช้ nullable field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nickname"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"anyOf"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"null"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;คีย์ &lt;code&gt;nickname&lt;/code&gt; จะมีเสมอ แต่ค่าเป็น &lt;code&gt;null&lt;/code&gt; ได้&lt;/p&gt;

&lt;h3&gt;
  
  
  ใช้ strict mode แล้วข้าม validation ได้ไหม?
&lt;/h3&gt;

&lt;p&gt;ข้ามการ validate รูปร่างพื้นฐานได้ในหลายกรณี แต่ยังควร validate กฎระดับค่า เช่น regex, format, min/max และ business rules เพราะ keyword บางตัวไม่ได้ถูกบังคับใช้โดยโมเดล นอกจากนี้ refusal และ truncation ยังต้องจัดการแยกต่างหาก หากยังไม่คุ้นกับ schema อ่านพื้นฐานได้ที่&lt;a href="https://apidog.com/th/blog/what-is-json-schema?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;บทนำ JSON Schema&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ควรใช้โมเดลใด?
&lt;/h3&gt;

&lt;p&gt;Structured outputs ใช้งานได้กับ GPT-4o และรุ่นใหม่กว่า รวมถึงซีรีส์ GPT-5 เอกสาร OpenAI แนะนำให้ใช้โมเดลเรือธงปัจจุบันสำหรับโปรเจกต์ใหม่ แต่คุณควรตรวจสอบ model ID ที่ใช้จริงว่ารองรับ &lt;code&gt;strict: true&lt;/code&gt; ก่อนนำไป production&lt;/p&gt;

&lt;h2&gt;
  
  
  สรุป
&lt;/h2&gt;

&lt;p&gt;workflow ที่ควรใช้คือ: เลือกโมเดลที่รองรับ structured outputs, ส่ง schema ผ่าน &lt;code&gt;response_format&lt;/code&gt; พร้อม &lt;code&gt;strict: true&lt;/code&gt;, เขียน schema ให้อยู่ใน subset ที่รองรับ, ตรวจ &lt;code&gt;refusal&lt;/code&gt; ก่อน parse, และ validate กฎระดับค่าซ้ำเมื่อจำเป็น จากนั้นใช้ &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; เพื่อยืนยัน response เทียบกับ schema และสร้าง mock สำหรับส่วนอื่นของระบบ โมเดลช่วยรับประกันรูปร่าง ส่วน test suite ช่วยพิสูจน์ว่าสัญญานั้นยังไม่พังเมื่อระบบเปลี่ยนแปลง&lt;/p&gt;

</description>
    </item>
    <item>
      <title>วิธีใช้ OpenAI Batch API</title>
      <dc:creator>Thanawat Wongchai</dc:creator>
      <pubDate>Thu, 25 Jun 2026 10:16:06 +0000</pubDate>
      <link>https://dev.to/thanawat_wonchai/withiiaich-openai-batch-api-10d9</link>
      <guid>https://dev.to/thanawat_wonchai/withiiaich-openai-batch-api-10d9</guid>
      <description>&lt;p&gt;เมื่ออ่านจบ คุณจะเรียกใช้ OpenAI &lt;a href="https://developers.openai.com/api/docs/guides/batch" rel="noopener noreferrer"&gt;Batch API&lt;/a&gt; เพื่อรันคำขอโมเดลจำนวนมากเป็นงานอะซิงโครนัสเดียวได้: เตรียมไฟล์ JSONL, อัปโหลด, สร้างแบทช์, ตรวจสอบสถานะ และดาวน์โหลดผลลัพธ์ โดย Batch API มีส่วนลด 50% เมื่อเทียบกับ synchronous API สำหรับโทเค็นขาเข้าและขาออก จากนั้นคุณสามารถทดสอบ flow ทั้งหมดใน &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; ก่อนนำไปใช้จริง หากงานของคุณต้องตอบกลับผู้ใช้ทันที ให้ใช้ synchronous API แทน และดูวิธี &lt;a href="https://apidog.com/th/blog/how-to-test-chatgpt-api-with-apidog?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ทดสอบ ChatGPT API ด้วย Apidog&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;ลองใช้ Apidog วันนี้&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Batch API คืออะไร และควรใช้เมื่อใด
&lt;/h2&gt;

&lt;p&gt;Batch API คือ endpoint แบบอะซิงโครนัสสำหรับงานที่มีคำขอจำนวนมากและยอมรับ latency ได้ แทนที่จะยิง HTTP request ทีละ prompt คุณรวมคำขอทั้งหมดไว้ในไฟล์ JSONL ไฟล์เดียว ส่งเป็น batch job แล้ว poll สถานะจนกว่าจะเสร็จ OpenAI จะประมวลผลและส่งผลลัพธ์กลับมาเป็นไฟล์ output&lt;/p&gt;

&lt;p&gt;เหมาะกับงาน offline ปริมาณมาก เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;จัดหมวดหมู่หรือติดแท็กข้อมูลย้อนหลัง&lt;/li&gt;
&lt;li&gt;สร้าง embeddings สำหรับ dataset ขนาดใหญ่&lt;/li&gt;
&lt;li&gt;สร้างเนื้อหาจำนวนมาก เช่น product descriptions, summaries, translations&lt;/li&gt;
&lt;li&gt;รัน evaluation suite หรือ benchmark โมเดลกับ dataset&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ไม่เหมาะกับงานที่ผู้ใช้รอผลแบบ real-time เช่น chat UI, autocomplete หรือ live agents เพราะ Batch API รับประกันกรอบเวลาสูงสุด 24 ชั่วโมง ไม่ใช่การตอบกลับทันที&lt;/p&gt;

&lt;p&gt;ถ้าคุณต้องสร้าง config หรือตัวแทนจำนวนมากพร้อมกัน การประมวลผลแบบ batch จะเหมาะกับ use case นี้ ดูตัวอย่างเพิ่มเติมได้ที่ &lt;a href="https://apidog.com/th/blog/llm-configuration-generation-agents?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;สร้างการกำหนดค่าตัวแทนมากกว่า 100 รายการด้วยการประมวลผลแบบแบทช์&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  สิ่งที่ต้องมีก่อนเริ่มต้น
&lt;/h2&gt;

&lt;p&gt;คุณจะใช้ 2 endpoints หลัก:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ขั้นตอน&lt;/th&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;หน้าที่&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. อัปโหลดไฟล์&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST /v1/files&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;อัปโหลดไฟล์ &lt;code&gt;.jsonl&lt;/code&gt; พร้อม &lt;code&gt;purpose: "batch"&lt;/code&gt; แล้วรับ file ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. สร้างแบทช์&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST /v1/batches&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ส่ง file ID, endpoint เป้าหมาย และ completion window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. ตรวจสอบสถานะ&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /v1/batches/{id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;poll &lt;code&gt;status&lt;/code&gt; จนเป็น &lt;code&gt;completed&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. ดาวน์โหลดผลลัพธ์&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /v1/files/{id}/content&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ดาวน์โหลด output ผ่าน &lt;code&gt;output_file_id&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;สิ่งที่ต้องเตรียม:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI API key ตั้งเป็น environment variable: &lt;code&gt;OPENAI_API_KEY&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ไฟล์ JSONL ที่มี request ต่อบรรทัด&lt;/li&gt;
&lt;li&gt;เครื่องมือสำหรับยิง request และตรวจสอบ response เช่น curl หรือ Apidog&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ขั้นตอนที่ 1: สร้างและอัปโหลดไฟล์ JSONL
&lt;/h2&gt;

&lt;p&gt;ไฟล์ input ต้องเป็น JSONL โดย 1 บรรทัด = 1 request ที่สมบูรณ์ แต่ละบรรทัดต้องมีฟิลด์หลัก:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;custom_id&lt;/code&gt;: ID ที่คุณกำหนดเอง ต้องไม่ซ้ำภายในไฟล์&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;method&lt;/code&gt;: โดยทั่วไปคือ &lt;code&gt;POST&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;url&lt;/code&gt;: endpoint เป้าหมาย เช่น &lt;code&gt;/v1/chat/completions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;body&lt;/code&gt;: request body จริงที่ส่งให้โมเดล&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง &lt;code&gt;requests.jsonl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"custom_id": "req-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4.1-mini", "messages": [{"role": "user", "content": "Classify the sentiment of: 'shipping was slow but the product is great'"}]}}
{"custom_id": "req-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4.1-mini", "messages": [{"role": "user", "content": "Classify the sentiment of: 'returned it the same day'"}]}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;ผลลัพธ์ไม่ได้รับประกันลำดับเดียวกับ input ดังนั้นให้ใช้ &lt;code&gt;custom_id&lt;/code&gt; เพื่อจับคู่ response กลับไปยัง request เดิมเสมอ&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ข้อจำกัดสำคัญ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 batch รองรับได้สูงสุด 50,000 requests&lt;/li&gt;
&lt;li&gt;ขนาดไฟล์สูงสุด 200 MB&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;custom_id&lt;/code&gt; ต้องไม่ซ้ำกัน&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;อัปโหลดไฟล์ไปยัง Files API โดยตั้ง &lt;code&gt;purpose=batch&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.openai.com/v1/files &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$OPENAI_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="nv"&gt;purpose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"batch"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"@requests.jsonl"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;response จะมี &lt;code&gt;id&lt;/code&gt; ของไฟล์ เช่น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"file-abc123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"purpose"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"batch"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เก็บค่านี้ไว้เป็น &lt;code&gt;input_file_id&lt;/code&gt; สำหรับขั้นตอนถัดไป&lt;/p&gt;

&lt;h2&gt;
  
  
  ขั้นตอนที่ 2: สร้างแบทช์
&lt;/h2&gt;

&lt;p&gt;สร้าง batch job โดยส่ง:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;input_file_id&lt;/code&gt;: file ID จากขั้นตอนก่อนหน้า&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;endpoint&lt;/code&gt;: endpoint ที่ตรงกับ &lt;code&gt;url&lt;/code&gt; ใน JSONL&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;completion_window&lt;/code&gt;: ปัจจุบันใช้ &lt;code&gt;"24h"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;metadata&lt;/code&gt;: optional สำหรับติด tag งาน
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.openai.com/v1/batches &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$OPENAI_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "input_file_id": "file-abc123",
    "endpoint": "/v1/chat/completions",
    "completion_window": "24h",
    "metadata": {
      "job": "sentiment-backfill"
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;endpoint&lt;/code&gt; ต้องตรงกับ &lt;code&gt;url&lt;/code&gt; ในแต่ละบรรทัดของ JSONL เช่นถ้า JSONL ใช้ &lt;code&gt;/v1/chat/completions&lt;/code&gt; batch ก็ต้องระบุ &lt;code&gt;/v1/chat/completions&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ตัวอย่าง response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"batch_abc123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"batch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"endpoint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/v1/chat/completions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input_file_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"file-abc123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"completion_window"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"24h"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"validating"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output_file_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error_file_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"request_counts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"completed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"failed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1733452800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"job"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sentiment-backfill"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ฟิลด์ที่ควรเก็บไว้:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt;: batch ID ใช้สำหรับ poll สถานะ&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;status&lt;/code&gt;: สถานะปัจจุบัน&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;output_file_id&lt;/code&gt;: ใช้ดาวน์โหลดผลลัพธ์เมื่อเสร็จ&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;error_file_id&lt;/code&gt;: ใช้ดู request ที่ error&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;request_counts&lt;/code&gt;: จำนวน request ทั้งหมด/สำเร็จ/ล้มเหลว&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ขั้นตอนที่ 3: ตรวจสอบสถานะแบทช์
&lt;/h2&gt;

&lt;p&gt;เรียก &lt;code&gt;GET /v1/batches/{batch_id}&lt;/code&gt; เพื่อดูสถานะ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.openai.com/v1/batches/batch_abc123 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$OPENAI_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สถานะที่ควรรู้:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;สถานะ&lt;/th&gt;
&lt;th&gt;ความหมาย&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;validating&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;กำลังตรวจสอบไฟล์ input&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;in_progress&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;กำลังประมวลผล request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;finalizing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ประมวลผลเสร็จและกำลังเตรียม output file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;completed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;เสร็จแล้ว ดาวน์โหลดผลลัพธ์ได้&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;failed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;validation ล้มเหลว ไม่มี request ถูกประมวลผล&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;expired&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ครบกรอบเวลา 24 ชั่วโมงก่อนประมวลผลครบ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;cancelling&lt;/code&gt; / &lt;code&gt;cancelled&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;กำลังยกเลิกหรือยกเลิกแล้ว&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ระหว่าง &lt;code&gt;in_progress&lt;/code&gt; ให้ดู progress จาก:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"request_counts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"completed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"failed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ไม่มี webhook สำหรับรอผล ดังนั้นให้ poll เป็นระยะ เช่น ทุก 2–5 นาที ไม่ควร poll ทุกวินาที&lt;/p&gt;

&lt;p&gt;ถ้าต้องการยกเลิกงาน:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.openai.com/v1/batches/batch_abc123/cancel &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$OPENAI_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ขั้นตอนที่ 4: ดาวน์โหลดผลลัพธ์
&lt;/h2&gt;

&lt;p&gt;เมื่อ &lt;code&gt;status&lt;/code&gt; เป็น &lt;code&gt;completed&lt;/code&gt; response ของ batch จะมี &lt;code&gt;output_file_id&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ดาวน์โหลดไฟล์ output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.openai.com/v1/files/file-output456/content &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$OPENAI_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; results.jsonl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ผลลัพธ์จะเป็น JSONL เช่นกัน โดย 1 บรรทัดต่อ 1 request และมี &lt;code&gt;custom_id&lt;/code&gt; สำหรับจับคู่กับ input&lt;/p&gt;

&lt;p&gt;ตัวอย่างโครงสร้างผลลัพธ์:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"custom_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"req-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"response"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status_code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"chatcmpl-..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"chat.completion"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แนวทาง parse ผลลัพธ์:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;อ่าน &lt;code&gt;results.jsonl&lt;/code&gt; ทีละบรรทัด&lt;/li&gt;
&lt;li&gt;parse เป็น JSON&lt;/li&gt;
&lt;li&gt;ใช้ &lt;code&gt;custom_id&lt;/code&gt; เพื่อ map กลับไปยัง record เดิม&lt;/li&gt;
&lt;li&gt;ตรวจสอบ &lt;code&gt;response.status_code&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ถ้ามี &lt;code&gt;error_file_id&lt;/code&gt; ให้ดาวน์โหลด error file เพิ่มเติม&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ตัวอย่าง parse ด้วย Node.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node:fs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;readline&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node:readline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createReadStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;results.jsonl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createInterface&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;crlfDelay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;rl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;customId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;custom_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hasError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ข้อควรพิจารณาเรื่องต้นทุนและกรอบเวลา
&lt;/h2&gt;

&lt;p&gt;Batch API เหมาะเมื่อคุณยอมรับ latency ได้สูงสุด 24 ชั่วโมงเพื่อแลกกับต้นทุน token ที่ลดลง 50%&lt;/p&gt;

&lt;p&gt;ใช้ได้ดีกับ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nightly jobs&lt;/li&gt;
&lt;li&gt;backfill ข้อมูล&lt;/li&gt;
&lt;li&gt;offline evaluation&lt;/li&gt;
&lt;li&gt;batch embeddings&lt;/li&gt;
&lt;li&gt;content generation จำนวนมาก&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ไม่ควรใช้กับ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;request ที่ผู้ใช้รอหน้า UI&lt;/li&gt;
&lt;li&gt;chatbot แบบ real-time&lt;/li&gt;
&lt;li&gt;workflow ที่ต้องการผลลัพธ์ภายในไม่กี่วินาที&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ข้อควรจำ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ส่วนลด 50% ใช้กับโทเค็นขาเข้าและขาออกสำหรับโมเดลที่รองรับ&lt;/li&gt;
&lt;li&gt;กรอบเวลา 24 ชั่วโมงคือเพดาน ไม่ใช่ SLA ว่าจะเสร็จเร็ว&lt;/li&gt;
&lt;li&gt;ถ้า batch เป็น &lt;code&gt;expired&lt;/code&gt; เฉพาะ request ที่ประมวลผลสำเร็จแล้วเท่านั้นที่จะถูกส่งคืนและถูกเรียกเก็บเงิน&lt;/li&gt;
&lt;li&gt;batch jobs ใช้ rate limit pool แยกจาก synchronous traffic จึงไม่กระทบ real-time API limits ของคุณ&lt;/li&gt;
&lt;li&gt;ควรใช้ &lt;code&gt;metadata&lt;/code&gt; เพื่อติด tag งานและ track cost ภายหลัง&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ถ้าคุณต้องจัดการ rate limit ฝั่ง synchronous ดูเพิ่มเติมที่ &lt;a href="https://apidog.com/th/blog/gpt-api-rate-limits?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;GPT API rate limits และวิธีการทดสอบ&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ถ้าต้องการแยกต้นทุนตาม feature หรือ job ดู &lt;a href="https://apidog.com/th/blog/track-openai-api-spend-per-feature?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;คู่มือการจัดสรรต้นทุนสำหรับการใช้จ่าย OpenAI&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  วิธีทดสอบใน Apidog
&lt;/h2&gt;

&lt;p&gt;Batch API มีจุดที่พลาดได้หลายจุด เช่น JSONL format, multipart upload, batch lifecycle, polling, output parsing และ error handling การทดสอบ flow ก่อน automate จะช่วยลดเวลารอซ้ำเมื่อ batch ล้มเหลว&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; ช่วยให้คุณทดสอบแต่ละ endpoint, chain request และตรวจสอบ response ได้โดยไม่ต้องเขียนสคริปต์ทั้งหมดตั้งแต่แรก&lt;/p&gt;

&lt;p&gt;ตั้งค่า flow ทดสอบแบบนี้:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ตรวจ JSONL ก่อนอัปโหลด&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
ตรวจว่าทุกบรรทัดมี &lt;code&gt;custom_id&lt;/code&gt;, &lt;code&gt;method&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;body&lt;/code&gt;, &lt;code&gt;body.model&lt;/code&gt; และ payload ที่ถูกต้อง&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ทดสอบ multipart upload&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
เรียก &lt;code&gt;POST /v1/files&lt;/code&gt; พร้อม &lt;code&gt;purpose=batch&lt;/code&gt; และแนบไฟล์ &lt;code&gt;.jsonl&lt;/code&gt; จากนั้นบันทึก &lt;code&gt;id&lt;/code&gt; ที่ได้เป็น environment variable เช่น &lt;code&gt;input_file_id&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;สร้าง batch&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
เรียก &lt;code&gt;POST /v1/batches&lt;/code&gt; โดยใช้ &lt;code&gt;input_file_id&lt;/code&gt; แล้วตรวจว่า:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;status&lt;/code&gt; เป็น &lt;code&gt;validating&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;endpoint&lt;/code&gt; ตรงกับที่ส่ง&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;input_file_id&lt;/code&gt; ถูกต้อง&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;poll สถานะ&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
เรียก &lt;code&gt;GET /v1/batches/{id}&lt;/code&gt; ซ้ำเป็นระยะ และดู &lt;code&gt;status&lt;/code&gt;, &lt;code&gt;request_counts&lt;/code&gt;, &lt;code&gt;output_file_id&lt;/code&gt;, &lt;code&gt;error_file_id&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ดาวน์โหลด output&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
เมื่อ &lt;code&gt;completed&lt;/code&gt; ให้ใช้ &lt;code&gt;output_file_id&lt;/code&gt; เรียก &lt;code&gt;GET /v1/files/{id}/content&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ทดสอบ error path&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
ส่ง JSONL ที่ตั้งใจให้ผิด เช่นขาด &lt;code&gt;custom_id&lt;/code&gt; หรือ &lt;code&gt;body&lt;/code&gt; เพื่อดู behavior ของ &lt;code&gt;failed&lt;/code&gt; และทดสอบ &lt;code&gt;POST /v1/batches/{id}/cancel&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;เนื่องจาก output file อาจมาช้า คุณสามารถใช้ &lt;a href="https://apidog.com/th/blog/mock-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;mock API&lt;/a&gt; เพื่อจำลอง batch ที่เสร็จแล้ว และ mock ไฟล์ผลลัพธ์สำหรับทดสอบ parser โดยไม่ต้องรอ 24 ชั่วโมงหรือใช้ token จริง&lt;/p&gt;

&lt;p&gt;ถ้าทีมทำงานแบบ spec-first คุณยังสามารถ &lt;a href="https://apidog.com/th/blog/api-test-collections-generation-openapi-specs?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;สร้างคอลเลกชันการทดสอบได้โดยตรงจาก OpenAPI spec&lt;/a&gt; เพื่อให้ endpoints ของ batch อยู่ใน regression test ได้&lt;/p&gt;

&lt;h2&gt;
  
  
  คำถามที่พบบ่อย
&lt;/h2&gt;

&lt;h3&gt;
  
  
  แบทช์ใช้เวลานานเท่าไหร่
&lt;/h3&gt;

&lt;p&gt;OpenAI รับประกันกรอบเวลาสูงสุด 24 ชั่วโมง หลายงานอาจเสร็จเร็วกว่านั้น แต่ควรออกแบบระบบโดยสมมติ worst case ที่ 24 ชั่วโมง&lt;/p&gt;

&lt;p&gt;ถ้าไม่เสร็จภายในกรอบเวลา batch จะเป็น &lt;code&gt;expired&lt;/code&gt; และเฉพาะ request ที่ประมวลผลสำเร็จแล้วเท่านั้นที่จะถูกส่งคืนและถูกเรียกเก็บเงิน&lt;/p&gt;

&lt;h3&gt;
  
  
  ส่วนลดคือเท่าไหร่
&lt;/h3&gt;

&lt;p&gt;Batch API ให้ส่วนลด 50% เมื่อเทียบกับ synchronous endpoints สำหรับโทเค็นขาเข้าและขาออก เหมาะกับงาน offline ที่มี volume สูง&lt;/p&gt;

&lt;p&gt;ถ้าต้องการแบ่งต้นทุนกลับไปยัง feature หรือ job ต่าง ๆ ดู &lt;a href="https://apidog.com/th/blog/track-openai-api-spend-per-feature?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;คู่มือการจัดสรรต้นทุน&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ใช้ endpoint ใดใน Batch API ได้บ้าง
&lt;/h3&gt;

&lt;p&gt;คุณต้องตั้ง endpoint ให้ตรงกันทั้งใน:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;url&lt;/code&gt; ของแต่ละบรรทัดใน JSONL&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;endpoint&lt;/code&gt; ตอนสร้าง batch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง endpoint ที่รองรับ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/v1/chat/completions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/v1/responses&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/v1/embeddings&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/v1/completions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/v1/moderations&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;รวมถึง endpoints รูปภาพและวิดีโอบางส่วน ควรตรวจเอกสาร OpenAI ล่าสุดก่อนใช้งานจริง เพราะรายการ endpoint อาจมีการอัปเดต&lt;/p&gt;

&lt;h3&gt;
  
  
  ทำไมผลลัพธ์ไม่เรียงตาม input
&lt;/h3&gt;

&lt;p&gt;เป็น behavior ปกติของ Batch API ไฟล์ output ไม่รับประกันลำดับเดียวกับไฟล์ input&lt;/p&gt;

&lt;p&gt;ให้ใช้ &lt;code&gt;custom_id&lt;/code&gt; เพื่อ map ผลลัพธ์กลับไปยัง request เดิมเสมอ ห้ามอ้างอิงจากลำดับบรรทัด&lt;/p&gt;

&lt;h3&gt;
  
  
  ถ้า request บางรายการล้มเหลวต้องทำอย่างไร
&lt;/h3&gt;

&lt;p&gt;ตรวจสอบทั้ง:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;output_file_id&lt;/code&gt;: request ที่มีผลลัพธ์&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;error_file_id&lt;/code&gt;: request ที่ error&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;จากนั้นใช้ &lt;code&gt;custom_id&lt;/code&gt; เพื่อแยกเฉพาะรายการที่ล้มเหลว แล้วสร้าง JSONL ใหม่สำหรับ retry เฉพาะ request เหล่านั้น&lt;/p&gt;

&lt;h2&gt;
  
  
  บทสรุป
&lt;/h2&gt;

&lt;p&gt;Flow หลักของ OpenAI Batch API คือ:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;สร้างไฟล์ JSONL&lt;/li&gt;
&lt;li&gt;อัปโหลดด้วย &lt;code&gt;POST /v1/files&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;สร้าง batch ด้วย &lt;code&gt;POST /v1/batches&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;poll สถานะด้วย &lt;code&gt;GET /v1/batches/{id}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ดาวน์โหลด output ด้วย &lt;code&gt;GET /v1/files/{id}/content&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;parse ผลลัพธ์ด้วย &lt;code&gt;custom_id&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Batch API เหมาะกับงาน offline ปริมาณมากที่รับ latency ได้สูงสุด 24 ชั่วโมง และต้องการลดต้นทุน token ลง 50%&lt;/p&gt;

&lt;p&gt;ก่อน automate ใน production ให้รัน lifecycle ด้วยตนเองใน &lt;a href="https://apidog.com/download?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; เพื่อตรวจ JSONL, ทดสอบ upload, สร้าง batch, poll สถานะ, ทดสอบ cancel/error path และยืนยัน response fields ให้ครบก่อนปล่อยงานจริงขนาดใหญ่&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Google ADK (Agent Development Kit) คืออะไร? คู่มือใช้งานจริง</title>
      <dc:creator>Thanawat Wongchai</dc:creator>
      <pubDate>Thu, 25 Jun 2026 08:15:20 +0000</pubDate>
      <link>https://dev.to/thanawat_wonchai/google-adk-agent-development-kit-khuueaair-khuumuueaichngaancchring-44aj</link>
      <guid>https://dev.to/thanawat_wonchai/google-adk-agent-development-kit-khuueaair-khuumuueaichngaancchring-44aj</guid>
      <description>&lt;p&gt;Google ADK เป็นเฟรมเวิร์กโอเพนซอร์สสำหรับสร้าง ประเมิน และปรับใช้ AI เอเจนต์ ใช้จริงภายในผลิตภัณฑ์ของ Google เช่น Agentspace หากคุณเคยใช้สแต็กเอเจนต์อย่าง &lt;a href="https://apidog.com/th/blog/how-to-use-openai-agents-sdk?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;OpenAI Agents SDK&lt;/a&gt; มาก่อน ADK จะอยู่ในกลุ่มเดียวกัน แต่ผสานกับ Gemini และ Vertex AI ได้แน่นกว่า บทความนี้สรุปวิธีคิด โครงสร้างหลัก วิธีเริ่มเขียนเอเจนต์ และจุดที่ &lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; ช่วยทดสอบ API ที่เอเจนต์เรียกใช้ได้&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;ลองใช้ Apidog วันนี้&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Google ADK คืออะไร
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://adk.dev/" rel="noopener noreferrer"&gt;ADK&lt;/a&gt; ย่อมาจาก Agent Development Kit เป็นชุดเครื่องมือโอเพนซอร์สที่ Google เปิดตัวในงาน Google Cloud Next เดือนเมษายน 2025 สำหรับวงจรชีวิตของเอเจนต์แบบครบขั้นตอน:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;กำหนดพฤติกรรมของเอเจนต์&lt;/li&gt;
&lt;li&gt;เพิ่มเครื่องมือให้เอเจนต์เรียกใช้&lt;/li&gt;
&lt;li&gt;ประกอบเอเจนต์หลายตัวเป็นระบบเดียว&lt;/li&gt;
&lt;li&gt;ประเมินผลลัพธ์และเส้นทางการทำงาน&lt;/li&gt;
&lt;li&gt;ปรับใช้บนรันไทม์จริง&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkgqe96wwtgiwfx3pacx7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkgqe96wwtgiwfx3pacx7.gif" alt="Google ADK CLI" width="600" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ADK เริ่มจาก Python เป็นหลัก และ Google ได้เพิ่ม Java เข้ามาแล้ว โดยมี Go และ TypeScript ตามมา เฟรมเวิร์กนี้เป็นชุดเดียวกับที่ Google ใช้ภายในสำหรับเอเจนต์ใน Agentspace และ Customer Engagement Suite จึงออกแบบมาสำหรับงาน production ไม่ใช่แค่ตัวอย่างทดลอง&lt;/p&gt;

&lt;p&gt;ADK เป็นแบบ model-agnostic แต่เหมาะกับระบบของ Google เป็นพิเศษ โดยทำงานได้ดีกับ Gemini และโมเดลที่อยู่ใน Vertex AI Model Garden นอกจากนี้ยังเชื่อมกับ LiteLLM เพื่อใช้โมเดลจากผู้ให้บริการอื่น เช่น Anthropic, Meta และ Mistral ได้ด้วย&lt;/p&gt;

&lt;h2&gt;
  
  
  ADK อยู่ตรงไหนในระบบ Gemini และ Vertex AI
&lt;/h2&gt;

&lt;p&gt;ให้มอง ADK เป็นหนึ่งเลเยอร์ในสแต็กเอเจนต์:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;โมเดล&lt;/strong&gt;: Gemini หรือโมเดลอื่นผ่าน Vertex AI Model Garden / LiteLLM ทำหน้าที่ reasoning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;เฟรมเวิร์ก&lt;/strong&gt;: ADK คือเลเยอร์โค้ดสำหรับกำหนดเอเจนต์ เครื่องมือ และเวิร์กโฟลว์&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;รันไทม์&lt;/strong&gt;: &lt;a href="https://cloud.google.com/vertex-ai/generative-ai/docs/agent-engine/overview" rel="noopener noreferrer"&gt;Vertex AI Agent Engine&lt;/a&gt; ใช้โฮสต์เอเจนต์แบบ managed และ scalable หรือจะปรับใช้บน Cloud Run / container runtime อื่นก็ได้&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjfin006qzylt56gd52p8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjfin006qzylt56gd52p8.png" alt="ADK ecosystem" width="800" height="767"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;สรุปคือ Gemini ให้ความสามารถด้านโมเดล, ADK ให้โครงสร้างการพัฒนา, และ Vertex AI Agent Engine ให้รันไทม์สำหรับ production คุณสามารถใช้ครบทั้งสามส่วน หรือใช้ ADK ในเครื่องแล้ว deploy ไปยังแพลตฟอร์มอื่นก็ได้&lt;/p&gt;

&lt;h2&gt;
  
  
  แนวคิดหลักของ ADK
&lt;/h2&gt;

&lt;p&gt;ส่วนที่คุณจะใช้บ่อยมีไม่กี่อย่าง: Agent, Tool, Multi-agent workflow, Runner, Evaluation และ Deployment&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Agent
&lt;/h3&gt;

&lt;p&gt;เอเจนต์คือหน่วยหลักที่ขับเคลื่อนด้วย LLM ใน Python คุณอิมพอร์ต &lt;code&gt;Agent&lt;/code&gt; จาก &lt;code&gt;google.adk.agents&lt;/code&gt; แล้วกำหนด:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt;: ชื่อเอเจนต์&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;model&lt;/code&gt;: โมเดลที่ใช้&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;instruction&lt;/code&gt;: system instruction / behavior&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tools&lt;/code&gt;: ฟังก์ชันที่เอเจนต์เรียกใช้ได้&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่างเอเจนต์สำหรับดูอัตราแลกเปลี่ยน:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.agents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_exchange_rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return the exchange rate between two currencies.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# ในงานจริง ให้เรียก FX API ของคุณตรงนี้
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.08&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;currency_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;currency_exchange_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-2.0-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;instruction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You help users convert between currencies. Stick to the facts.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;get_exchange_rate&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;โค้ดนี้สร้างเอเจนต์หนึ่งตัวที่รู้ว่าต้องตอบเรื่องการแปลงสกุลเงิน และมีเครื่องมือ &lt;code&gt;get_exchange_rate()&lt;/code&gt; ให้เรียกเมื่อจำเป็น&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Tool
&lt;/h3&gt;

&lt;p&gt;Tool คือสิ่งที่ทำให้เอเจนต์ทำงานนอกเหนือจากการสร้างข้อความ เช่น เรียก REST API, ค้นข้อมูล, อ่านฐานข้อมูล หรือรันโค้ด&lt;/p&gt;

&lt;p&gt;ใน ADK ฟังก์ชัน Python ธรรมดาสามารถเป็น tool ได้ โดยโมเดลจะใช้ข้อมูลเหล่านี้เพื่อเลือกว่าจะเรียกใช้เมื่อใด:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ชื่อฟังก์ชัน&lt;/li&gt;
&lt;li&gt;type hints&lt;/li&gt;
&lt;li&gt;docstring&lt;/li&gt;
&lt;li&gt;return shape&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง tool ที่เรียก API จริง:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;search_hotels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check_in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check_out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Search hotel options for a city and date range.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.example.com/hotels&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;check_in&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;check_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;check_out&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;check_out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ข้อควรทำ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เขียน docstring ให้ชัดว่า tool ทำอะไร&lt;/li&gt;
&lt;li&gt;กำหนด input/output ให้สม่ำเสมอ&lt;/li&gt;
&lt;li&gt;handle error จาก API ภายนอก&lt;/li&gt;
&lt;li&gt;test tool แยกจาก agent ก่อนนำไปใช้จริง&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ADK ยังมีเครื่องมือในตัว เช่น &lt;code&gt;google_search&lt;/code&gt; และ code execution รวมถึงรองรับ &lt;a href="https://apidog.com/th/blog/mcp-servers-openai-agents?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Model Context Protocol หรือ MCP&lt;/a&gt; สำหรับเชื่อมต่อ tool server ภายนอก คุณยังสามารถ wrap ไลบรารีอย่าง LangChain, LlamaIndex หรือใช้เอเจนต์อื่นเป็น tool ได้&lt;/p&gt;

&lt;h3&gt;
  
  
  3. ระบบเอเจนต์หลายตัว
&lt;/h3&gt;

&lt;p&gt;เอเจนต์ตัวเดียวเหมาะกับงานง่าย แต่ถ้างานซับซ้อน คุณสามารถแยกความรับผิดชอบเป็นหลายเอเจนต์ เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เอเจนต์ค้นเที่ยวบิน&lt;/li&gt;
&lt;li&gt;เอเจนต์ค้นโรงแรม&lt;/li&gt;
&lt;li&gt;เอเจนต์สรุปแผนเดินทาง&lt;/li&gt;
&lt;li&gt;เอเจนต์ตรวจสอบงบประมาณ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx0e23cfjmjjuvbna95qx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx0e23cfjmjjuvbna95qx.png" alt="Multi-agent workflow" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ADK มี workflow agents สำหรับควบคุม flow แบบกำหนดได้:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SequentialAgent&lt;/code&gt;: รันซับเอเจนต์ตามลำดับ&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ParallelAgent&lt;/code&gt;: รันหลายซับเอเจนต์พร้อมกัน&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LoopAgent&lt;/code&gt;: ทำซ้ำจนกว่าจะเข้าเงื่อนไข&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;รูปแบบนี้เหมาะกับงานที่ต้องแบ่งขั้นตอนชัดเจน เช่น research pipeline, customer support routing หรือ travel planning&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Runner
&lt;/h3&gt;

&lt;p&gt;ในการใช้งานจริง คุณไม่ได้เรียกเอเจนต์โดยตรงตลอดเวลา แต่ใช้ &lt;code&gt;Runner&lt;/code&gt; เป็นเอนจินประมวลผลของ ADK&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Runner&lt;/code&gt; ดูแลเรื่อง:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;session&lt;/li&gt;
&lt;li&gt;event flow&lt;/li&gt;
&lt;li&gt;state update&lt;/li&gt;
&lt;li&gt;model call&lt;/li&gt;
&lt;li&gt;tool invocation&lt;/li&gt;
&lt;li&gt;orchestration ระหว่างเอเจนต์&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ช่วงพัฒนา คุณสามารถใช้ CLI เพื่อลองเอเจนต์ได้ทันที:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adk run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;คำสั่งนี้เปิด interactive terminal session&lt;/p&gt;

&lt;p&gt;หรือใช้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adk web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;คำสั่งนี้เปิด UI บน browser เพื่อคุยกับเอเจนต์และดูแต่ละ step ระหว่าง execution เหมาะมากสำหรับ debug ว่าเอเจนต์เลือก tool ถูกหรือไม่ และ input/output ของ tool เป็นอย่างไร&lt;/p&gt;

&lt;h3&gt;
  
  
  5. การประเมินผลและการปรับใช้
&lt;/h3&gt;

&lt;p&gt;ADK มีเครื่องมือสำหรับ evaluation เพื่อให้คุณตรวจสอบได้ว่าเอเจนต์ทำงานตาม expected path และ expected response หรือไม่ ไม่ใช่ดูแค่คำตอบสุดท้าย&lt;/p&gt;

&lt;p&gt;ควรประเมินเมื่อคุณเปลี่ยน:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prompt / instruction&lt;/li&gt;
&lt;li&gt;tool&lt;/li&gt;
&lt;li&gt;model&lt;/li&gt;
&lt;li&gt;workflow&lt;/li&gt;
&lt;li&gt;routing logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;สำหรับ deployment มีสองแนวทางหลัก:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ใช้ &lt;strong&gt;Vertex AI Agent Engine&lt;/strong&gt; ถ้าต้องการ managed runtime ที่ scale ได้&lt;/li&gt;
&lt;li&gt;containerize แล้ว deploy ไปยัง &lt;strong&gt;Cloud Run&lt;/strong&gt; หรือ container platform อื่น ถ้าต้องการ portability มากกว่า&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ตัวอย่าง: สร้างระบบเอเจนต์วางแผนทริป
&lt;/h2&gt;

&lt;p&gt;ตัวอย่างนี้มี coordinator หนึ่งตัว และ sub-agent สองตัวสำหรับค้นเที่ยวบินและโรงแรม&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;google.adk.agents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;search_flights&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Search flight options for a route and date.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# เรียก flights API จริงของคุณตรงนี้
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;origin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;destination&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;options&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;search_hotels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check_in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check_out&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Search hotel options near the destination.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# เรียก hotels API จริงของคุณตรงนี้
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;check_in&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;check_in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;check_out&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;check_out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;options&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;flights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flight_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-2.0-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;instruction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Find flight options for the user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s route and dates.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;search_flights&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;hotels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hotel_agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-2.0-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;instruction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Find hotel options near the destination.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;search_hotels&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;trip_planner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trip_planner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-2.0-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;instruction&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Plan a trip. Delegate flight and hotel lookups to your sub-agents.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;sub_agents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;flights&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hotels&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;flow โดยทั่วไปคือ:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ผู้ใช้ถามให้วางแผนทริป&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;trip_planner&lt;/code&gt; วิเคราะห์คำขอ&lt;/li&gt;
&lt;li&gt;ส่งงานค้นเที่ยวบินให้ &lt;code&gt;flight_agent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ส่งงานค้นโรงแรมให้ &lt;code&gt;hotel_agent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;รวมผลลัพธ์และตอบผู้ใช้&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ตอน debug ให้เริ่มจาก &lt;code&gt;adk web&lt;/code&gt; เพื่อดูว่า coordinator ส่งงานไปยัง sub-agent ถูกต้องหรือไม่ และ tool ได้ input ตามที่คาดไว้หรือเปล่า&lt;/p&gt;

&lt;h2&gt;
  
  
  ADK vs OpenAI Agents SDK
&lt;/h2&gt;

&lt;p&gt;ทั้ง Google ADK และ OpenAI Agents SDK เป็นเฟรมเวิร์กสำหรับสร้างเอเจนต์แบบ code-first มีแนวคิดเรื่อง tools, handoffs / delegation และ tracing คล้ายกัน จุดต่างหลักคือ ecosystem ที่แต่ละตัวเน้น&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Google ADK&lt;/th&gt;
&lt;th&gt;OpenAI Agents SDK&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Default model&lt;/td&gt;
&lt;td&gt;Gemini ผ่าน Vertex AI&lt;/td&gt;
&lt;td&gt;OpenAI models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;โมเดลอื่น&lt;/td&gt;
&lt;td&gt;Vertex AI Model Garden, LiteLLM&lt;/td&gt;
&lt;td&gt;LiteLLM และอื่น ๆ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ภาษา&lt;/td&gt;
&lt;td&gt;Python, Java, Go, TypeScript&lt;/td&gt;
&lt;td&gt;Python, JavaScript/TypeScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-agent&lt;/td&gt;
&lt;td&gt;Sub-agents + Sequential, Parallel, Loop workflow agents&lt;/td&gt;
&lt;td&gt;Agents-as-tools และ handoffs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Managed runtime&lt;/td&gt;
&lt;td&gt;Vertex AI Agent Engine&lt;/td&gt;
&lt;td&gt;Bring your own&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool protocol&lt;/td&gt;
&lt;td&gt;MCP, built-in tools, function tools&lt;/td&gt;
&lt;td&gt;MCP, function tools&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ถ้าทีมของคุณอยู่บน Google Cloud อยู่แล้ว ADK + Vertex AI เป็นตัวเลือกที่เข้ากันดี ถ้าสต็กหลักเป็น OpenAI อยู่แล้ว &lt;a href="https://apidog.com/th/blog/how-to-use-openai-agents-sdk?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;OpenAI Agents SDK&lt;/a&gt; อาจเหมาะกว่า ทั้งสองรองรับ MCP จึงสามารถแชร์ tool server บางส่วนร่วมกันได้&lt;/p&gt;

&lt;h2&gt;
  
  
  ควรใช้ ADK เมื่อใด
&lt;/h2&gt;

&lt;p&gt;เลือกใช้ ADK เมื่อ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;คุณสร้างระบบบน Google Cloud และต้องการใช้ Gemini กับ Vertex AI Agent Engine&lt;/li&gt;
&lt;li&gt;คุณต้องการ orchestration ของหลายเอเจนต์แบบชัดเจน&lt;/li&gt;
&lt;li&gt;งานต้องใช้ workflow แบบ sequential, parallel หรือ loop&lt;/li&gt;
&lt;li&gt;คุณต้องการ evaluation ในเฟรมเวิร์ก ไม่ใช่เพิ่มทีหลัง&lt;/li&gt;
&lt;li&gt;คุณต้องการสลับโมเดลผ่าน Vertex AI Model Garden หรือ LiteLLM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;อาจยังไม่จำเป็นต้องใช้ ADK ถ้า:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use case เป็น prompt เดียว + function call ง่าย ๆ&lt;/li&gt;
&lt;li&gt;ไม่มี workflow หลายขั้นตอน&lt;/li&gt;
&lt;li&gt;ไม่ต้องการ multi-agent&lt;/li&gt;
&lt;li&gt;ทีมอยู่กับ ecosystem อื่นแบบชัดเจน&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;เฟรมเวิร์กเอเจนต์ช่วยเพิ่มโครงสร้าง แต่โครงสร้างก็มีต้นทุน ถ้างานเล็กมาก การเรียก LLM API ตรง ๆ อาจง่ายกว่า&lt;/p&gt;

&lt;h2&gt;
  
  
  Apidog ช่วยตรงไหน: ทดสอบและจำลอง API ที่เอเจนต์เรียกใช้
&lt;/h2&gt;

&lt;p&gt;ADK จัดการ logic ของเอเจนต์ แต่ไม่ได้แทนที่การทดสอบ API ภายนอกที่ tool ของคุณเรียกใช้ และนี่คือจุดที่ควรแยกมาทดสอบตั้งแต่ต้น&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmon27bggnyo58w1gbq5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmon27bggnyo58w1gbq5i.png" alt="Apidog API testing" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ในระบบเอเจนต์จริง tool มักจะเรียกสิ่งเหล่านี้:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LLM endpoint&lt;/li&gt;
&lt;li&gt;payment API&lt;/li&gt;
&lt;li&gt;internal microservice&lt;/li&gt;
&lt;li&gt;search service&lt;/li&gt;
&lt;li&gt;CRM / ticketing API&lt;/li&gt;
&lt;li&gt;third-party data provider&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ถ้า API เหล่านี้ส่ง response ผิดรูปแบบ เอเจนต์จะ reason ต่อจากข้อมูลผิด และ debug ยาก เพราะปัญหาอาจดูเหมือน prompt ไม่ดี ทั้งที่จริงคือ contract ของ API เปลี่ยน&lt;/p&gt;

&lt;p&gt;Apidog ไม่ใช่เฟรมเวิร์กเอเจนต์และไม่ได้แทนที่ ADK แต่ทำงานในเลเยอร์ API ที่ tool ของเอเจนต์พึ่งพา&lt;/p&gt;

&lt;h3&gt;
  
  
  วิธีใช้ Apidog ระหว่างพัฒนา ADK
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Mock endpoint ที่ tool เรียกใช้
&lt;/h4&gt;

&lt;p&gt;ตั้งค่า &lt;a href="https://apidog.com/th/blog/mock-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;mock API&lt;/a&gt; สำหรับ endpoint ที่ยังไม่พร้อม หรือ endpoint ที่ไม่อยากเรียกจริงระหว่างพัฒนา เช่น LLM, payment หรือ third-party API&lt;/p&gt;

&lt;p&gt;ข้อดี:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;พัฒนาเอเจนต์ได้โดยไม่ต้องรอ backend&lt;/li&gt;
&lt;li&gt;ลดค่า token หรือค่า API call&lt;/li&gt;
&lt;li&gt;ทดสอบ error case ได้ง่าย&lt;/li&gt;
&lt;li&gt;ควบคุม response ได้คงที่&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง tool ที่ชี้ไปยัง mock endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_customer_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Fetch a customer profile by customer ID.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CUSTOMER_API_BASE_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/customers/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ระหว่าง development ให้ &lt;code&gt;CUSTOMER_API_BASE_URL&lt;/code&gt; ชี้ไปยัง mock server ใน Apidog ส่วน staging / production ค่อยเปลี่ยนเป็น endpoint จริง&lt;/p&gt;

&lt;h4&gt;
  
  
  2. ตรวจ response schema ก่อนให้เอเจนต์ใช้
&lt;/h4&gt;

&lt;p&gt;ใช้ &lt;a href="https://apidog.com/th/blog/api-assertions?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;การยืนยัน API&lt;/a&gt; เพื่อตรวจว่า response มี field ที่เอเจนต์ต้องใช้ เช่น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customer_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cus_123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Jane Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gold"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"open_tickets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ถ้า tool คาดหวัง &lt;code&gt;tier&lt;/code&gt; แต่ API เปลี่ยนเป็น &lt;code&gt;plan&lt;/code&gt; เอเจนต์อาจตอบผิดทันที การทดสอบ contract จะจับปัญหานี้ก่อนเข้าสู่ agent transcript&lt;/p&gt;

&lt;h4&gt;
  
  
  3. แยก environment keys
&lt;/h4&gt;

&lt;p&gt;เก็บ key และ base URL แยกตาม environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dev&lt;/li&gt;
&lt;li&gt;staging&lt;/li&gt;
&lt;li&gt;production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;การทำแบบนี้ช่วยให้ tool function เดิมทำงานได้ทุก stage โดยเปลี่ยนแค่ environment config ไม่ต้องแก้โค้ด&lt;/p&gt;

&lt;h4&gt;
  
  
  4. ทดสอบ tool แยกจาก agent
&lt;/h4&gt;

&lt;p&gt;ก่อนนำ tool เข้า &lt;code&gt;tools=[...]&lt;/code&gt; ให้ทดสอบ API call ตรง ๆ ก่อน:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_get_customer_profile&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_customer_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cus_123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tier&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;open_tickets&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แนวคิดคืออย่า debug พร้อมกันทั้ง agent, prompt, model และ API ให้แยก API contract ออกมาก่อน&lt;/p&gt;

&lt;p&gt;ถ้าต้องการแนวทางเฉพาะสำหรับเอเจนต์ ดูวิธี &lt;a href="https://apidog.com/th/blog/ai-agent-apidog-test-harness?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ทดสอบการเรียกใช้เครื่องมือของ AI เอเจนต์&lt;/a&gt; ก่อนเกิดปัญหาใน production หรือ &lt;a href="https://apidog.com/download?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ดาวน์โหลด Apidog&lt;/a&gt; แล้วเริ่ม mock endpoint แรกได้ภายในไม่กี่นาที&lt;/p&gt;

&lt;h2&gt;
  
  
  คำถามที่พบบ่อย
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Google ADK ฟรีและโอเพนซอร์สหรือไม่
&lt;/h3&gt;

&lt;p&gt;ใช่ ADK เป็นโอเพนซอร์สใน &lt;a href="https://github.com/google/adk-python" rel="noopener noreferrer"&gt;repository บน GitHub&lt;/a&gt; ภายใต้ Apache license คุณสามารถรันในเครื่องได้โดยไม่มีค่าใช้จ่าย แต่ยังต้องจ่ายค่าโมเดลที่เรียกใช้ และค่า managed runtime หาก deploy ไปยังบริการอย่าง Vertex AI Agent Engine&lt;/p&gt;

&lt;h3&gt;
  
  
  ADK ทำงานกับ Gemini เท่านั้นหรือไม่
&lt;/h3&gt;

&lt;p&gt;ไม่ ADK ได้รับการปรับให้เหมาะกับ Gemini และ Vertex AI แต่ยังเป็น model-agnostic ผ่าน Vertex AI Model Garden และ LiteLLM คุณสามารถใช้โมเดลจาก Anthropic, Meta, Mistral และผู้ให้บริการอื่นได้ Gemini เป็นค่าเริ่มต้นที่เข้ากันดีที่สุด แต่ไม่ใช่ข้อบังคับ&lt;/p&gt;

&lt;h3&gt;
  
  
  ADK รองรับภาษาอะไรบ้าง
&lt;/h3&gt;

&lt;p&gt;Python เป็นภาษาแรกและยังมีความสมบูรณ์ที่สุด Google ได้เพิ่ม Java แล้ว และมี Go กับ TypeScript ตามมา หากต้องการ feature coverage ที่กว้างที่สุดตอนนี้ Python ยังเป็นตัวเลือกที่ปลอดภัยที่สุด&lt;/p&gt;

&lt;h3&gt;
  
  
  ควร debug เอเจนต์ ADK อย่างไร
&lt;/h3&gt;

&lt;p&gt;เริ่มจาก &lt;code&gt;adk web&lt;/code&gt; เพื่อดู execution step, tool call, input และ output ของแต่ละ tool จากนั้นแยกทดสอบ tool function ด้วย unit test หรือ API test อย่าแก้ prompt ก่อนถ้ายังไม่มั่นใจว่า API response ถูกต้อง&lt;/p&gt;

&lt;h3&gt;
  
  
  ฉันจะทดสอบ API ที่เอเจนต์ ADK พึ่งพาได้อย่างไร
&lt;/h3&gt;

&lt;p&gt;ทดสอบ API แยกจากเอเจนต์ก่อน จำลอง endpoint ที่ยังไม่พร้อมหรือไม่อยากเรียกจริง แล้วตรวจ response schema ให้ตรงกับสิ่งที่ tool คาดหวัง Apidog รองรับทั้ง mock และ assertion คู่มือ &lt;a href="https://apidog.com/th/blog/how-to-test-chatgpt-api-with-apidog?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ทดสอบ ChatGPT API&lt;/a&gt; ใช้ pattern เดียวกันกับ LLM endpoint ที่ tool ของคุณอาจเรียกใช้&lt;/p&gt;

&lt;h2&gt;
  
  
  สรุป
&lt;/h2&gt;

&lt;p&gt;Google ADK เป็นเฟรมเวิร์กที่เหมาะสำหรับสร้างเอเจนต์และระบบหลายเอเจนต์ โดยเฉพาะถ้าคุณใช้ Gemini, Vertex AI หรือ Google Cloud อยู่แล้ว วิธีเริ่มที่ practical คือสร้างเอเจนต์หนึ่งตัว เพิ่ม tool ไม่กี่ตัว รันด้วย &lt;code&gt;adk web&lt;/code&gt; เพื่อดูพฤติกรรม แล้วค่อยขยายเป็น sub-agents หรือ deploy ไปยัง managed runtime&lt;/p&gt;

&lt;p&gt;เมื่อเอเจนต์ของคุณเริ่มพึ่งพา API ภายนอกมากขึ้น ให้ทดสอบ API เหล่านั้นเป็น contract แยกต่างหาก จำลอง response, ตรวจ schema และแยก environment ให้ชัดเจน นั่นคือเลเยอร์ที่ &lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; ช่วยจัดการ และมักเป็นจุดเริ่มต้นของพฤติกรรมเอเจนต์ที่ดูเหมือนไม่แน่นอน&lt;/p&gt;

</description>
    </item>
    <item>
      <title>LangGraph คืออะไร? คู่มือสร้าง Stateful AI Agent</title>
      <dc:creator>Thanawat Wongchai</dc:creator>
      <pubDate>Thu, 25 Jun 2026 08:07:27 +0000</pubDate>
      <link>https://dev.to/thanawat_wonchai/langgraph-khuueaair-khuumuuesraang-stateful-ai-agent-36ek</link>
      <guid>https://dev.to/thanawat_wonchai/langgraph-khuueaair-khuumuuesraang-stateful-ai-agent-36ek</guid>
      <description>&lt;p&gt;โค้ดเอเจนต์ส่วนใหญ่เริ่มต้นง่าย ๆ แล้วเริ่มพังเมื่อเวิร์กโฟลว์ต้องวนซ้ำ แยกสาขา หรือหยุดรอมนุษย์ LangGraph แก้ปัญหานี้ด้วยการจำลองเอเจนต์เป็นกราฟที่มีสถานะร่วมกัน ทำให้การวนซ้ำและการกำหนดเส้นทางเป็นโครงสร้างหลัก ไม่ใช่ชุด &lt;code&gt;if&lt;/code&gt; ที่ซ้อนกัน คู่มือนี้อธิบายว่า LangGraph คืออะไร ควรใช้เมื่อใด และ &lt;a href="https://apidog.com/th/blog/how-to-test-ai-agents-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;การทดสอบ API มีบทบาทอย่างไรเมื่อเอเจนต์เรียกใช้บริการจริง&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;ลองใช้ Apidog วันนี้&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  LangGraph คืออะไร
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.langchain.com/oss/python/langgraph/overview" rel="noopener noreferrer"&gt;LangGraph&lt;/a&gt; เป็นเฟรมเวิร์ก orchestration ระดับต่ำและรันไทม์สำหรับสร้างเอเจนต์ที่มีสถานะและทำงานได้นาน พัฒนาโดย LangChain Inc แต่เป็นไลบรารีแยกต่างหากจาก LangChain คุณติดตั้งและใช้งานได้โดยตรง:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-U&lt;/span&gt; langgraph
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnbwl41wc4fli86l4u8wv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnbwl41wc4fli86l4u8wv.png" alt="LangGraph overview" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;แนวคิดหลักคืออธิบายเอเจนต์เป็นกราฟ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;โหนด (Nodes)&lt;/strong&gt; ทำงาน เช่น เรียกโมเดล รันเครื่องมือ หรือแปลงข้อมูล&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;เส้นเชื่อม (Edges)&lt;/strong&gt; ตัดสินใจว่าจะรันโหนดใดต่อ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;สถานะ (State)&lt;/strong&gt; เป็นข้อมูลร่วมที่ไหลผ่านทุกโหนด&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;วงจร (Cycles)&lt;/strong&gt; ทำให้เอเจนต์วนกลับไปคิดหรือเรียกเครื่องมือซ้ำได้&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ถ้า chain แบบเดิมคือ pipeline เช่น ขั้นตอน 1 → 2 → 3 → จบ LangGraph คือ state machine ที่สามารถเลือกเส้นทาง วนกลับ หรือหยุดรอ input เพิ่มได้ เหมาะกับเอเจนต์ที่ทำงานแบบ “คิด → ทำ → สังเกต → คิดอีกครั้ง”&lt;/p&gt;

&lt;h2&gt;
  
  
  ปัญหาที่ LangGraph แก้ไข
&lt;/h2&gt;

&lt;p&gt;เวิร์กโฟลว์ของเอเจนต์มักไม่เป็นเส้นตรง เอเจนต์ต้องเรียกเครื่องมือ ดูผลลัพธ์ แล้วตัดสินใจว่าจะทำต่อหรือหยุด หากเขียนทั้งหมดด้วย &lt;code&gt;if/else&lt;/code&gt; และ loop เอง โค้ดจะอ่านยากและทดสอบยาก&lt;/p&gt;

&lt;p&gt;LangGraph ช่วยจัดการสิ่งเหล่านี้:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;การวนซ้ำพร้อมเงื่อนไขหยุด&lt;/strong&gt;: เรียกเครื่องมือซ้ำจนกว่างานจะเสร็จ โดยไม่วนไม่รู้จบ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;การแยกสาขาตามสถานะ&lt;/strong&gt;: ส่งงานไปยังโหนดที่ต่างกันตามผลลัพธ์จากโมเดล&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence&lt;/strong&gt;: บันทึกสถานะเพื่อ resume หลัง timeout, crash หรือ restart&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human-in-the-loop&lt;/strong&gt;: หยุดให้มนุษย์ตรวจสอบหรือแก้ไขสถานะก่อนทำต่อ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming&lt;/strong&gt;: ส่ง token และ update ระหว่างทาง ไม่ต้องรอผลลัพธ์สุดท้ายเท่านั้น&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ผลลัพธ์คือคุณได้ runtime สำหรับเอเจนต์ที่ทนทานกว่า script เชิงเส้น โดยเฉพาะงานที่กินเวลาหลายนาทีหรือหลายชั่วโมง&lt;/p&gt;

&lt;h2&gt;
  
  
  แนวคิดหลัก: กราฟ สถานะ โหนด เส้นเชื่อม
&lt;/h2&gt;

&lt;p&gt;LangGraph ประกอบด้วย 4 ส่วนหลัก&lt;/p&gt;

&lt;h3&gt;
  
  
  1. State
&lt;/h3&gt;

&lt;p&gt;State คือออบเจกต์ที่แชร์ระหว่างทุกโหนด คุณกำหนด schema ได้ เช่น &lt;code&gt;TypedDict&lt;/code&gt; หรือใช้ schema ที่มีให้แล้วอย่าง &lt;code&gt;MessagesState&lt;/code&gt; สำหรับเก็บรายการข้อความแชท&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Nodes
&lt;/h3&gt;

&lt;p&gt;Node คือฟังก์ชันที่รับ state ปัจจุบัน แล้วคืนค่า update บางส่วน&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Edges
&lt;/h3&gt;

&lt;p&gt;Edge เชื่อมโหนดเข้าด้วยกัน:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;add_edge()&lt;/code&gt; ใช้สำหรับเส้นทางคงที่ เช่น A → B&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;add_conditional_edges()&lt;/code&gt; ใช้สำหรับ routing ตาม state เช่น ถ้าโมเดลเรียก tool ให้ไป node &lt;code&gt;tools&lt;/code&gt; ไม่เช่นนั้นจบ&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. START และ END
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;START&lt;/code&gt; และ &lt;code&gt;END&lt;/code&gt; เป็น marker พิเศษสำหรับจุดเริ่มต้นและจุดสิ้นสุดของกราฟ&lt;/p&gt;

&lt;p&gt;ตัวอย่างโครงสร้างพื้นฐาน:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langgraph.graph&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MessagesState&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MessagesState&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;should_continue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MessagesState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tool_calls&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MessagesState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;call_model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_conditional_edges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;should_continue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# loop back
&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จุดสำคัญคือบรรทัดนี้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;หลังจากรัน tool แล้ว control จะวนกลับไปที่ model เพื่อให้โมเดลตัดสินใจต่อว่าจะเรียก tool เพิ่มหรือจบงาน นี่คือ use case หลักที่ LangGraph ถูกออกแบบมาเพื่อรองรับ&lt;/p&gt;

&lt;h2&gt;
  
  
  การคงอยู่ของข้อมูลและ Human-in-the-loop
&lt;/h2&gt;

&lt;p&gt;ถ้าต้องการให้กราฟ resume ได้ ให้ compile พร้อม checkpointer จากนั้นส่ง &lt;code&gt;thread_id&lt;/code&gt; ตอนเรียกใช้งาน LangGraph จะบันทึก snapshot ของ state หลังแต่ละ step และกู้คืน checkpoint ล่าสุดในการเรียกครั้งถัดไป&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langgraph.checkpoint.memory&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;InMemorySaver&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checkpointer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;InMemorySaver&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;configurable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;thread_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user-42&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;InMemorySaver&lt;/code&gt; เหมาะสำหรับ development ถ้าต้องการให้รอดจาก process restart ให้ใช้ checkpointer ที่ backed ด้วย database เช่น SQLite สำหรับ server เดี่ยว หรือ Postgres สำหรับหลาย instance&lt;/p&gt;

&lt;p&gt;เมื่อ state ถูกบันทึกไว้ คุณสามารถสร้าง workflow แบบ human-in-the-loop ได้ เช่น:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;รันกราฟจนถึงจุดที่ต้องอนุมัติ&lt;/li&gt;
&lt;li&gt;แสดง state ปัจจุบันให้ผู้ใช้ตรวจสอบ&lt;/li&gt;
&lt;li&gt;ให้ผู้ใช้แก้ไขหรือยืนยัน&lt;/li&gt;
&lt;li&gt;Resume จาก checkpoint เดิม&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;รูปแบบนี้เหมาะกับงานเช่น approval flow, manual correction หรือขั้นตอน “ยืนยันก่อนส่งจริง”&lt;/p&gt;

&lt;p&gt;LangGraph ยังรองรับ streaming เพื่อให้ UI แสดง token หรือ node update ระหว่างรัน แทนที่จะรอ response ตอนจบเพียงครั้งเดียว&lt;/p&gt;

&lt;h2&gt;
  
  
  LangGraph เกี่ยวข้องกับ LangChain อย่างไร
&lt;/h2&gt;

&lt;p&gt;LangChain คือชุดเครื่องมือที่กว้างกว่า เช่น model wrappers, prompt templates, retrievers, document loaders และ integrations จำนวนมาก ส่วน LangGraph คือ orchestration layer สำหรับควบคุม workflow ของเอเจนต์ที่มีสถานะและมีวงจร&lt;/p&gt;

&lt;p&gt;คุณไม่จำเป็นต้องใช้ LangChain เพื่อใช้ LangGraph คุณสามารถกำหนด state, node และ edge เอง แล้วเรียก model client ใดก็ได้ภายใน node แต่หลายทีมใช้ร่วมกันเพราะ abstraction ของ LangChain ช่วยลด boilerplate สำหรับ model และ tools&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;หัวข้อ&lt;/th&gt;
&lt;th&gt;LangChain&lt;/th&gt;
&lt;th&gt;LangGraph&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;บทบาท&lt;/td&gt;
&lt;td&gt;ส่วนประกอบและ integrations&lt;/td&gt;
&lt;td&gt;Orchestration และ runtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Control flow&lt;/td&gt;
&lt;td&gt;Chain เชิงเส้น&lt;/td&gt;
&lt;td&gt;Graph ที่มีวงจรและสาขา&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State ในตัว&lt;/td&gt;
&lt;td&gt;จำกัด&lt;/td&gt;
&lt;td&gt;แชร์ได้ มี schema และทนทาน&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Persistence / Resume&lt;/td&gt;
&lt;td&gt;ไม่ใช่จุดเน้นหลัก&lt;/td&gt;
&lt;td&gt;Checkpointers + thread ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;เหมาะกับ&lt;/td&gt;
&lt;td&gt;การรวม model และ tools&lt;/td&gt;
&lt;td&gt;เอเจนต์หลายขั้นตอนที่มี state&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ข้อสังเกตสำหรับผู้ใช้ปัจจุบัน: LangGraph v1.0 ซึ่งเสถียรตั้งแต่ปลายปี 2025 ได้ย้าย helper agent ที่สร้างไว้ล่วงหน้าไปที่ &lt;code&gt;langchain.agents.create_agent&lt;/code&gt; ดังนั้นควรตรวจสอบเวอร์ชันที่ติดตั้งและ &lt;a href="https://reference.langchain.com/python/langgraph.prebuilt/chat_agent_executor/create_react_agent" rel="noopener noreferrer"&gt;เอกสารอ้างอิงทางการ&lt;/a&gt; ก่อนคัดลอกตัวอย่างเก่า ๆ&lt;/p&gt;

&lt;p&gt;ถ้าต้องการภาพรวมการสร้างเอเจนต์แบบกำหนดเอง ดูเพิ่มเติมได้ที่ &lt;a href="https://apidog.com/th/blog/create-ai-agents?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;การสร้าง AI เอเจนต์แบบกำหนดเอง&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  แพลตฟอร์มและสตูดิโอของ LangGraph
&lt;/h2&gt;

&lt;p&gt;ไลบรารีโอเพนซอร์สคือแกนหลัก แต่มีเครื่องมือเสริมที่ช่วยตอน debug และ deploy&lt;/p&gt;

&lt;h3&gt;
  
  
  LangGraph Studio
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;LangGraph Studio&lt;/strong&gt; คือ &lt;a href="https://www.langchain.com/blog/langgraph-studio-the-first-agent-ide" rel="noopener noreferrer"&gt;IDE สำหรับเอเจนต์แบบภาพ&lt;/a&gt; ใช้ดูกราฟ รัน workflow และ inspect state ในแต่ละโหนด เหมาะมากเมื่อกราฟมี loop และ conditional routing เพราะคุณเห็น path ที่เอเจนต์เลือกจริง แทนที่จะไล่อ่าน log ทีละบรรทัด&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff0ur8yc9b7shkjbvwsad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff0ur8yc9b7shkjbvwsad.png" alt="LangGraph Studio" width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  LangGraph Platform
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;LangGraph Platform&lt;/strong&gt; เป็นส่วนสำหรับ production deployment เช่น API endpoint สำหรับเอเจนต์, persistence ในตัว และตัวเลือก hosting ตั้งแต่ self-hosted ไปจนถึง managed cloud คุณไม่จำเป็นต้องใช้เพื่อเริ่มต้นกับ LangGraph แต่มีประโยชน์เมื่อ workflow เริ่มต้องการ infrastructure สำหรับ production&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F932vjtjrnw0scbab9235.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F932vjtjrnw0scbab9235.png" alt="LangGraph Platform" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  เมื่อใดควรใช้ LangGraph
&lt;/h2&gt;

&lt;p&gt;ใช้ LangGraph เมื่อ workflow ของเอเจนต์มี control flow จริง เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;งานเป็น loop ไม่ใช่ลำดับตรง ๆ เช่น call tool → inspect → retry&lt;/li&gt;
&lt;li&gt;ต้อง branch ตามการตัดสินใจของโมเดล&lt;/li&gt;
&lt;li&gt;งานใช้เวลานานและต้อง resume หลัง crash หรือ timeout&lt;/li&gt;
&lt;li&gt;ต้องมีมนุษย์อนุมัติหรือแก้ไขระหว่างทาง&lt;/li&gt;
&lt;li&gt;มีหลาย actor หรือหลาย sub-agent ที่ใช้ state ร่วมกัน&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ไม่จำเป็นต้องใช้ LangGraph ถ้างานเป็นการเรียกโมเดลครั้งเดียวหรือ chain สั้น ๆ เช่น “สรุปข้อความนี้” เพราะกราฟจะเพิ่ม overhead โดยไม่จำเป็น&lt;/p&gt;

&lt;h2&gt;
  
  
  การทดสอบ API และ Mocking มีบทบาทอย่างไร
&lt;/h2&gt;

&lt;p&gt;เอเจนต์ LangGraph จะเชื่อถือได้เท่ากับ API ที่มันเรียกใช้เท่านั้น เช่น LLM endpoint, search API, CRM, internal backend หรือ tool API อื่น ๆ LangGraph ช่วยจัดการ workflow แต่ไม่ได้ทดสอบ API เหล่านั้น นี่คือจุดที่ &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; เข้ามาช่วยในขั้นตอน development และ testing&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnbwl41wc4fli86l4u8wv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnbwl41wc4fli86l4u8wv.png" alt="Apidog" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;มี 2 ปัญหาที่ควรจัดการตั้งแต่ต้น&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Mock API เพื่อลดต้นทุนและทำให้ test repeatable
&lt;/h3&gt;

&lt;p&gt;ถ้ารัน API จริงทุกครั้ง คุณจะเจอปัญหา token cost, rate limit และผลลัพธ์ที่ไม่ deterministic ระหว่างพัฒนา logic ของกราฟ ให้ mock endpoint ที่เอเจนต์พึ่งพาแทน&lt;/p&gt;

&lt;p&gt;ตัวอย่างแนวทาง:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ระบุ tool API ทั้งหมดที่ node เรียกใช้&lt;/li&gt;
&lt;li&gt;สร้าง mock response สำหรับแต่ละ endpoint&lt;/li&gt;
&lt;li&gt;ให้ test environment ชี้ไปยัง mock server&lt;/li&gt;
&lt;li&gt;ทดสอบ routing ของกราฟโดยไม่เรียก API จริง&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;คุณสามารถใช้ &lt;a href="https://apidog.com/th/blog/mock-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;การจำลอง API&lt;/a&gt; เพื่อให้ endpoint ส่ง response ที่แน่นอนและรวดเร็ว เหมาะสำหรับทดสอบว่า conditional edge เลือก path ถูกต้องหรือไม่&lt;/p&gt;

&lt;h3&gt;
  
  
  2. ใช้ API assertions เพื่อตรวจ schema drift
&lt;/h3&gt;

&lt;p&gt;Node ของคุณมักคาดหวัง response shape ที่แน่นอน เช่น field name, status code หรือ nested object ถ้า API เปลี่ยน field แบบเงียบ ๆ conditional edge อาจอ่านค่าผิด แล้วทำให้เอเจนต์วนซ้ำหรือหยุดผิดจุด&lt;/p&gt;

&lt;p&gt;ให้กำหนด contract ด้วย &lt;a href="https://apidog.com/th/blog/api-assertions?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;API assertions&lt;/a&gt; เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;status code ต้องเป็น &lt;code&gt;200&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;response ต้องมี field ที่ node ใช้&lt;/li&gt;
&lt;li&gt;type ของ field ต้องตรงตาม schema&lt;/li&gt;
&lt;li&gt;error response ต้องอยู่ในรูปแบบที่กราฟจัดการได้&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;สำหรับ workflow ที่เน้น AI agent โดยตรง ดู &lt;a href="https://apidog.com/th/blog/ai-agent-apidog-test-harness?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ชุดทดสอบ Apidog สำหรับ AI เอเจนต์&lt;/a&gt; เพื่อวางกระบวนการ mock, assert และทดสอบ API ที่อยู่เบื้องหลังเอเจนต์&lt;/p&gt;

&lt;p&gt;ข้อสำคัญ: Apidog ไม่ได้ orchestrate agent แทน LangGraph แต่ใช้ทดสอบและจำลอง API ที่ agent เรียกใช้&lt;/p&gt;

&lt;h2&gt;
  
  
  คำถามที่พบบ่อย
&lt;/h2&gt;

&lt;h3&gt;
  
  
  LangGraph มาแทนที่ LangChain ใช่หรือไม่?
&lt;/h3&gt;

&lt;p&gt;ไม่ใช่ LangGraph คือ orchestration runtime สำหรับ workflow ที่มี state และ loop ส่วน LangChain คือชุด components และ integrations ที่กว้างกว่า คุณใช้ LangGraph โดยไม่ใช้ LangChain ได้ หรือใช้ร่วมกันก็ได้&lt;/p&gt;

&lt;h3&gt;
  
  
  ต้องรู้ LangChain ก่อนเริ่มใช้ LangGraph หรือไม่?
&lt;/h3&gt;

&lt;p&gt;ไม่จำเป็น คุณเริ่มจาก &lt;code&gt;StateGraph&lt;/code&gt; เพิ่ม node และ edge แล้วเรียก model client ที่ต้องการภายใน node ได้เลย LangChain ช่วยลด boilerplate แต่ไม่ใช่ข้อบังคับ&lt;/p&gt;

&lt;h3&gt;
  
  
  LangGraph จำ state ระหว่างการเรียกใช้ได้อย่างไร?
&lt;/h3&gt;

&lt;p&gt;ผ่าน checkpointer เมื่อ compile graph พร้อม checkpointer และส่ง &lt;code&gt;thread_id&lt;/code&gt; LangGraph จะบันทึก snapshot ของ state หลังแต่ละ step และกู้คืน checkpoint ล่าสุดในการเรียกครั้งถัดไป&lt;/p&gt;

&lt;h3&gt;
  
  
  จะทดสอบ API ที่เอเจนต์เรียกได้อย่างไร?
&lt;/h3&gt;

&lt;p&gt;แยกการทดสอบ API ออกจากกราฟ Mock LLM endpoint และ tool endpoint เพื่อให้ test เร็วและคุมผลลัพธ์ได้ จากนั้นใช้ assertions ตรวจ response schema เพื่อป้องกัน field เปลี่ยนแล้วทำให้ node ทำงานผิด ดูตัวอย่างเพิ่มเติมได้ในคู่มือ &lt;a href="https://apidog.com/th/blog/how-to-test-chatgpt-api-with-apidog?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ทดสอบ ChatGPT API&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  สรุป
&lt;/h2&gt;

&lt;p&gt;LangGraph เหมาะกับเอเจนต์ที่ต้องวนซ้ำ แยกสาขา เก็บ state และหยุดรอมนุษย์ โครงสร้างหลักคือ graph, state, node และ edge ส่วน checkpointer ช่วยให้ resume และสร้าง workflow แบบ human-in-the-loop ได้&lt;/p&gt;

&lt;p&gt;เมื่อเอเจนต์เริ่มเรียก API จริง ให้แยกการทดสอบ API ออกจาก orchestration layer ใช้ mock เพื่อลดต้นทุนและทำให้ test predictable และใช้ assertions เพื่อป้องกัน schema drift คุณสามารถทดสอบและจำลอง API เหล่านั้นใน &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; และ &lt;a href="https://apidog.com/download?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ดาวน์โหลด Apidog&lt;/a&gt; เพื่อเริ่มสร้าง mock endpoint และตรวจ response ก่อนให้เอเจนต์เรียกใช้จริง&lt;/p&gt;

</description>
    </item>
    <item>
      <title>OpenAI AgentKit คืออะไร</title>
      <dc:creator>Thanawat Wongchai</dc:creator>
      <pubDate>Thu, 25 Jun 2026 07:40:55 +0000</pubDate>
      <link>https://dev.to/thanawat_wonchai/openai-agentkit-khuueaair-290e</link>
      <guid>https://dev.to/thanawat_wonchai/openai-agentkit-khuueaair-290e</guid>
      <description>&lt;p&gt;OpenAI AgentKit คือชุดเครื่องมือสำหรับสร้าง ปรับใช้ และวัดผล AI agent บนแพลตฟอร์มของ OpenAI หากคุณเคยสร้าง agent เองและต้องดูแล orchestration, connector, prompt, eval script และ UI แยกกัน AgentKit คือแนวทางของ OpenAI ในการรวมชิ้นส่วนเหล่านี้ไว้ด้วยกัน บทความนี้สรุปว่า AgentKit มีอะไรบ้าง เหมาะกับใคร ควรเริ่มสร้างอย่างไรในปี 2026 และเครื่องมือทดสอบ API อย่าง &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; ควรอยู่ตรงไหนเมื่อ agent ของคุณเริ่มเรียกใช้บริการภายนอก&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;ลองใช้ Apidog วันนี้&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  AgentKit คืออะไร
&lt;/h2&gt;

&lt;p&gt;OpenAI เปิดตัว &lt;a href="https://openai.com/index/introducing-agentkit/" rel="noopener noreferrer"&gt;AgentKit&lt;/a&gt; ในงาน DevDay เมื่อวันที่ 6 ตุลาคม 2025 โดย AgentKit ไม่ใช่ผลิตภัณฑ์เดี่ยว แต่เป็นชุดส่วนประกอบที่ทำงานบน OpenAI API และ &lt;a href="https://apidog.com/th/blog/how-to-use-openai-agents-sdk?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;OpenAI Agents SDK&lt;/a&gt; เป้าหมายคือย่นระยะจาก “มีไอเดีย agent” ไปสู่ “มี agent ที่ใช้งานกับผู้ใช้จริงได้”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fykis93iaj0m5bvm7t7wi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fykis93iaj0m5bvm7t7wi.png" alt="AgentKit" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ก่อนมี AgentKit การสร้าง agent มักต้องทำหลายอย่างเอง เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เขียน orchestration logic&lt;/li&gt;
&lt;li&gt;สร้าง connector สำหรับแต่ละแหล่งข้อมูล&lt;/li&gt;
&lt;li&gt;ทำ evaluation pipeline เอง&lt;/li&gt;
&lt;li&gt;ปรับ prompt ด้วยมือ&lt;/li&gt;
&lt;li&gt;สร้าง UI แชทหรือ front-end สำหรับใช้งานจริง&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AgentKit รวมเครื่องมือสำหรับงานเหล่านี้ไว้ในชุดเดียว แต่มีประเด็นสำคัญในปี 2026: OpenAI ประกาศเมื่อวันที่ 3 มิถุนายน 2026 ว่าจะยุติการใช้งาน AgentKit บางส่วน ได้แก่ &lt;strong&gt;Agent Builder&lt;/strong&gt; และ &lt;strong&gt;Evals&lt;/strong&gt; ดังนั้นหากคุณต้องการสร้างระบบที่ดูแลต่อได้ระยะยาว เส้นทางหลักควรเป็น &lt;strong&gt;Agents SDK&lt;/strong&gt; มากกว่า visual workflow&lt;/p&gt;

&lt;h2&gt;
  
  
  ส่วนประกอบของ AgentKit
&lt;/h2&gt;

&lt;p&gt;AgentKit เปิดตัวพร้อมส่วนประกอบหลัก 4 ส่วน แต่ละส่วนมีบทบาทและสถานะต่างกันในปี 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent Builder
&lt;/h3&gt;

&lt;p&gt;Agent Builder คือ workspace แบบ visual สำหรับออกแบบ workflow ของ agent แบบหลายขั้นตอน คุณสามารถลากและวาง node, เชื่อม flow, preview การรันด้วย input จริง และ publish workflow snapshot แบบมี version ได้&lt;/p&gt;

&lt;p&gt;สำหรับนักพัฒนา จุดสำคัญคือ Agent Builder ไม่ได้แยกจากโค้ดโดยสิ้นเชิง เพราะมีแท็บ &lt;strong&gt;Agents SDK&lt;/strong&gt; ที่ส่งออก workflow เป็นโค้ด Python หรือ TypeScript ได้ คุณจึงใช้ visual builder เพื่อ prototype แล้วนำโค้ดไปต่อใน environment ของทีมได้&lt;/p&gt;

&lt;p&gt;อย่างไรก็ตาม OpenAI กำลังยกเลิก Agent Builder โดยจะปิดแพลตฟอร์มวันที่ &lt;strong&gt;30 พฤศจิกายน 2026&lt;/strong&gt; ตาม &lt;a href="https://developers.openai.com/api/docs/deprecations" rel="noopener noreferrer"&gt;หน้าประกาศการยุติการใช้งาน&lt;/a&gt; ดังนั้นถ้าเริ่มโปรเจกต์ใหม่ ให้ใช้ Agent Builder เป็นเครื่องมือ prototype เท่านั้น และวางแผนย้าย workflow ไปยัง Agents SDK&lt;/p&gt;

&lt;h3&gt;
  
  
  ChatKit
&lt;/h3&gt;

&lt;p&gt;ChatKit คือ UI แชทที่ฝังในแอปของคุณได้ แทนที่จะสร้าง chat interface เองตั้งแต่ศูนย์ คุณสามารถใส่ web component, ชี้ไปยัง workflow ID ที่ publish แล้ว และปรับแต่ง theme หรือ behavior ได้&lt;/p&gt;

&lt;p&gt;ChatKit จัดการงานทั่วไปของ UI agent เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;streaming response&lt;/li&gt;
&lt;li&gt;thread&lt;/li&gt;
&lt;li&gt;chat interaction&lt;/li&gt;
&lt;li&gt;embedding ลงในผลิตภัณฑ์&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ChatKit ยังใช้งานได้ และเป็นส่วนของ AgentKit ที่ได้รับผลกระทบน้อยจากการเปลี่ยนแปลงปี 2026&lt;/p&gt;

&lt;h3&gt;
  
  
  Connector Registry
&lt;/h3&gt;

&lt;p&gt;Connector Registry คือพื้นที่สำหรับ admin ในการจัดการการเชื่อมต่อข้อมูลและเครื่องมือในผลิตภัณฑ์ของ OpenAI ทั้ง ChatGPT และ API&lt;/p&gt;

&lt;p&gt;ตัวอย่าง connector ที่รองรับ ได้แก่:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dropbox&lt;/li&gt;
&lt;li&gt;Google Drive&lt;/li&gt;
&lt;li&gt;SharePoint&lt;/li&gt;
&lt;li&gt;Microsoft Teams&lt;/li&gt;
&lt;li&gt;MCP server ของบุคคลที่สาม&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;แนวคิดคือให้องค์กรควบคุมได้ว่า agent เข้าถึงข้อมูลหรือเครื่องมือใดได้บ้างจากศูนย์กลางเดียว&lt;/p&gt;

&lt;p&gt;ถ้าคุณต้องการเข้าใจฝั่ง MCP เพิ่มเติม อ่านคู่มือ &lt;a href="https://apidog.com/th/blog/mcp-servers-openai-agents?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;เซิร์ฟเวอร์ MCP และ OpenAI Agents SDK&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Evals และการเพิ่มประสิทธิภาพ
&lt;/h3&gt;

&lt;p&gt;Evals เพิ่มความสามารถด้านการวัดคุณภาพของ agent เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dataset สำหรับทดสอบ&lt;/li&gt;
&lt;li&gt;trace grading สำหรับให้คะแนนแต่ละขั้นตอนของ multi-agent run&lt;/li&gt;
&lt;li&gt;prompt optimization อัตโนมัติ&lt;/li&gt;
&lt;li&gt;การให้คะแนนเทียบกับโมเดลของบุคคลที่สาม ไม่จำกัดเฉพาะ OpenAI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;แต่เช่นเดียวกับ Agent Builder, Evals กำลังถูกยุติการใช้งาน โดยจะเป็นแบบอ่านอย่างเดียวสำหรับผู้ใช้เดิมวันที่ &lt;strong&gt;31 ตุลาคม 2026&lt;/strong&gt; และปิดตัววันที่ &lt;strong&gt;30 พฤศจิกายน 2026&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  AgentKit เกี่ยวข้องกับ Agents SDK อย่างไร
&lt;/h2&gt;

&lt;p&gt;ให้มอง AgentKit เป็นชุดเครื่องมือรอบ ๆ Agents SDK:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agents SDK&lt;/strong&gt; คือ framework ระดับโค้ดสำหรับกำหนด agent, tool, handoff และ guardrails&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent Builder&lt;/strong&gt; คือ visual layer ที่สร้าง workflow และ export เป็นโค้ด SDK ได้&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ChatKit&lt;/strong&gt; คือ layer สำหรับฝังประสบการณ์แชท&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connector Registry&lt;/strong&gt; คือ layer สำหรับจัดการ connector และ MCP server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evals&lt;/strong&gt; คือ layer สำหรับวัดผลและปรับ prompt&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;เลเยอร์&lt;/th&gt;
&lt;th&gt;คืออะไร&lt;/th&gt;
&lt;th&gt;สถานะในปี 2026&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agents SDK&lt;/td&gt;
&lt;td&gt;framework โค้ดสำหรับกำหนด agent, tool และ guardrails&lt;/td&gt;
&lt;td&gt;ใช้งานอยู่ และเป็นเส้นทางระยะยาวที่แนะนำ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent Builder&lt;/td&gt;
&lt;td&gt;workspace แบบ visual ที่ export โค้ด Agents SDK ได้&lt;/td&gt;
&lt;td&gt;ถูกยกเลิก ปิดตัว 30 พ.ย. 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChatKit&lt;/td&gt;
&lt;td&gt;UI แชทที่ฝังได้ ผูกกับ workflow ID&lt;/td&gt;
&lt;td&gt;ใช้งานได้&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connector Registry&lt;/td&gt;
&lt;td&gt;admin panel สำหรับ connector และ MCP server&lt;/td&gt;
&lt;td&gt;ใช้งานได้&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evals&lt;/td&gt;
&lt;td&gt;trace grading และ prompt optimization&lt;/td&gt;
&lt;td&gt;อ่านอย่างเดียว 31 ต.ค. 2026, ปิดตัว 30 พ.ย. 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;คำแนะนำเชิงปฏิบัติ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ถ้าคุณสร้างระบบสำหรับ production และต้อง maintain ต่อ: ใช้ &lt;strong&gt;Agents SDK&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;ถ้าคุณต้องการ prototype แบบ visual: ใช้ &lt;strong&gt;Agent Builder&lt;/strong&gt; แล้ว export เป็นโค้ด&lt;/li&gt;
&lt;li&gt;ถ้าต้องการ UI แชท: ใช้ &lt;strong&gt;ChatKit&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;ถ้าต้องควบคุม data access ในองค์กร: ใช้ &lt;strong&gt;Connector Registry&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  AgentKit เหมาะกับใคร
&lt;/h2&gt;

&lt;p&gt;AgentKit เหมาะกับทีมที่ต้องการลดงานซ้ำในการสร้าง agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ทีม product ที่ต้องการ prototype agent เร็ว&lt;/li&gt;
&lt;li&gt;ทีม engineering ที่ต้องการ framework สำหรับกำหนด agent และ tool แบบชัดเจน&lt;/li&gt;
&lt;li&gt;องค์กรที่ต้องการควบคุม connector และ data access&lt;/li&gt;
&lt;li&gt;ทีมที่ต้องการนำ agent ไปใช้งานผ่าน UI แชท&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;แต่เมื่อพิจารณาการยกเลิก Agent Builder และ Evals ในปี 2026 แนวทางที่ปลอดภัยสำหรับนักพัฒนาคือ:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;เริ่มจาก Agents SDK และใช้ส่วนอื่นของ AgentKit เฉพาะเมื่อเหมาะกับ use case&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ขั้นตอนการสร้าง agent ในระดับสูง
&lt;/h2&gt;

&lt;p&gt;ไม่ว่าคุณจะเริ่มจาก visual builder หรือโค้ด ขั้นตอนหลักจะคล้ายกัน&lt;/p&gt;

&lt;h3&gt;
  
  
  1. กำหนดหน้าที่ของ agent
&lt;/h3&gt;

&lt;p&gt;ตอบคำถามเหล่านี้ก่อน:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;agent ต้องทำงานอะไร&lt;/li&gt;
&lt;li&gt;ต้องใช้ข้อมูลจากที่ไหน&lt;/li&gt;
&lt;li&gt;ต้องเรียก API หรือ service ใด&lt;/li&gt;
&lt;li&gt;มีข้อจำกัดด้าน permission หรือ compliance หรือไม่&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่างงานของ agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ค้นหาคำสั่งซื้อล่าสุดของลูกค้า&lt;/li&gt;
&lt;li&gt;สรุป ticket จากระบบ support&lt;/li&gt;
&lt;li&gt;ตรวจสอบสถานะ shipment&lt;/li&gt;
&lt;li&gt;ดึงข้อมูลจาก CRM&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. ออกแบบ workflow
&lt;/h3&gt;

&lt;p&gt;ถ้าใช้ Agent Builder คุณจะลาก node และเชื่อม flow&lt;/p&gt;

&lt;p&gt;ถ้าใช้ Agents SDK คุณจะกำหนด agent, tool และ handoff ด้วยโค้ด เช่น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ตัวอย่างเชิงแนวคิด: กำหนด agent พร้อม tool&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;supportAgent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;support_agent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ช่วยตอบคำถามลูกค้าจากข้อมูลคำสั่งซื้อ&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;getRecentOrders&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. เพิ่ม guardrails
&lt;/h3&gt;

&lt;p&gt;ควรเพิ่ม guardrails เพื่อจัดการความเสี่ยง เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ซ่อนหรือแจ้งเตือนข้อมูล PII&lt;/li&gt;
&lt;li&gt;ตรวจจับ prompt injection&lt;/li&gt;
&lt;li&gt;จำกัด tool ที่เรียกใช้ได้&lt;/li&gt;
&lt;li&gt;validate input ก่อนส่งเข้า tool&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OpenAI มี guardrails แบบ open-source ที่ใช้เป็น workflow node หรือ standalone library ได้&lt;/p&gt;

&lt;h3&gt;
  
  
  4. เชื่อมต่อข้อมูลและเครื่องมือ
&lt;/h3&gt;

&lt;p&gt;Agent มักเรียกใช้เครื่องมือผ่าน:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;function tool&lt;/li&gt;
&lt;li&gt;HTTP API&lt;/li&gt;
&lt;li&gt;MCP server&lt;/li&gt;
&lt;li&gt;connector ที่องค์กรอนุญาต&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;จุดนี้คือส่วนที่ควรออกแบบ schema ให้ชัด เพราะโมเดลจะตัดสินใจเรียก tool จาก description และ parameter schema&lt;/p&gt;

&lt;h3&gt;
  
  
  5. ทดสอบและประเมินผล
&lt;/h3&gt;

&lt;p&gt;ทดสอบอย่างน้อย 3 ระดับ:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ทดสอบ tool/API แยกจาก agent&lt;/li&gt;
&lt;li&gt;ทดสอบ agent run ด้วย input จริง&lt;/li&gt;
&lt;li&gt;ทดสอบ edge case เช่น API timeout, empty result, invalid response&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  6. ปรับใช้
&lt;/h3&gt;

&lt;p&gt;ตัวเลือกหลักคือ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ฝัง UI ด้วย ChatKit&lt;/li&gt;
&lt;li&gt;รันโค้ด Agents SDK บน infrastructure ของคุณเอง&lt;/li&gt;
&lt;li&gt;ใช้ Connector Registry เพื่อควบคุม data access&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ตัวอย่างที่สมจริง: tool ที่ agent เรียกใช้
&lt;/h2&gt;

&lt;p&gt;agent จะทำงานได้ดีเท่ากับ tool ที่มันเรียกใช้ได้ และ tool ส่วนใหญ่คือ HTTP API&lt;/p&gt;

&lt;p&gt;สมมติคุณต้องการให้ agent ดึงคำสั่งซื้อล่าสุดของลูกค้า คุณอาจกำหนด tool schema แบบนี้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"function"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get_recent_orders"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ค้นหาคำสั่งซื้อล่าสุดของลูกค้าด้วย ID ลูกค้า"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"customer_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ตัวระบุเฉพาะของลูกค้า"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"limit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"integer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"จำนวนคำสั่งซื้อที่จะส่งคืน"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"customer_id"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"additionalProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เมื่อโมเดลตัดสินใจเรียก &lt;code&gt;get_recent_orders&lt;/code&gt; โค้ดของคุณจะรับ argument แล้วเรียก API จริง เช่น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.your-company.com/v1/customers/cus_8842/orders?limit&lt;span class="o"&gt;=&lt;/span&gt;5 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$ORDERS_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จุดที่ต้องระวังคือ agent จะ reasoning ต่อจาก response ที่ API ส่งกลับมา ถ้า API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ช้า&lt;/li&gt;
&lt;li&gt;ล่ม&lt;/li&gt;
&lt;li&gt;ส่ง field ผิดชื่อ&lt;/li&gt;
&lt;li&gt;response ไม่ตรง schema&lt;/li&gt;
&lt;li&gt;คืนข้อมูลว่างโดยไม่อธิบาย&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;agent ก็มีโอกาสตอบผิดหรือเลือก workflow ผิดได้&lt;/p&gt;

&lt;p&gt;ดังนั้น API ที่เป็น tool ของ agent ควรถูก test และ mock ตั้งแต่ต้น ไม่ใช่รอจนเชื่อม agent เสร็จแล้วค่อยตรวจ&lt;/p&gt;

&lt;h2&gt;
  
  
  การทดสอบและ Mock API เข้ามามีบทบาทอย่างไร
&lt;/h2&gt;

&lt;p&gt;Apidog ไม่ใช่ agent framework และไม่ได้สร้าง agent แทน AgentKit หรือ Agents SDK แต่ Apidog อยู่ใน layer ด้านล่าง: ใช้สำหรับทดสอบ mock และจัดทำเอกสาร API ที่ agent เรียกใช้&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fykis93iaj0m5bvm7t7wi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fykis93iaj0m5bvm7t7wi.png" alt="Apidog API testing" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Mock API ก่อน backend พร้อม
&lt;/h3&gt;

&lt;p&gt;ถ้า agent ต้องเรียก service คำสั่งซื้อ แต่ทีม backend ยังสร้างไม่เสร็จ คุณสามารถ &lt;a href="https://apidog.com/th/blog/mock-api?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;สร้าง Mock API&lt;/a&gt; ที่คืน response ตาม schema ที่ตกลงกันไว้&lt;/p&gt;

&lt;p&gt;สิ่งที่ควร mock:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;success response&lt;/li&gt;
&lt;li&gt;empty result&lt;/li&gt;
&lt;li&gt;validation error&lt;/li&gt;
&lt;li&gt;unauthorized&lt;/li&gt;
&lt;li&gt;timeout หรือ slow response&lt;/li&gt;
&lt;li&gt;field ที่ optional&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง mock response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customer_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cus_8842"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"orders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"order_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ord_1001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shipped"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1290&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"THB"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ข้อดีคือ frontend, agent logic และ backend contract พัฒนาไปพร้อมกันได้โดยไม่ต้องรอกัน&lt;/p&gt;

&lt;h3&gt;
  
  
  2. ตรวจว่า response ตรงกับสิ่งที่ agent คาดหวัง
&lt;/h3&gt;

&lt;p&gt;API ที่คืน &lt;code&gt;200 OK&lt;/code&gt; แต่ field ผิดชื่ออันตรายกว่าการ fail ชัดเจน เพราะโมเดลอาจพยายาม reasoning จากข้อมูลที่ผิด&lt;/p&gt;

&lt;p&gt;ควรเขียน &lt;a href="https://apidog.com/th/blog/api-test-case-example?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;กรณีทดสอบ API&lt;/a&gt; เพื่อตรวจอย่างน้อย:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;status code&lt;/li&gt;
&lt;li&gt;response schema&lt;/li&gt;
&lt;li&gt;required fields&lt;/li&gt;
&lt;li&gt;data type&lt;/li&gt;
&lt;li&gt;error format&lt;/li&gt;
&lt;li&gt;response time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง assertion ที่ควรมี:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;response has orders array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;an&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;array&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;order has required fields&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;order_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;have&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;total&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. แยก environment และ secret
&lt;/h3&gt;

&lt;p&gt;tool ของ agent มักต้องใช้ secret เช่น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ORDERS_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...
&lt;span class="nv"&gt;CRM_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...
&lt;span class="nv"&gt;INTERNAL_API_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ควรแยก environment อย่างน้อย:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;local&lt;/li&gt;
&lt;li&gt;dev&lt;/li&gt;
&lt;li&gt;staging&lt;/li&gt;
&lt;li&gt;production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;และไม่ควร hardcode key ในโค้ด agent&lt;/p&gt;

&lt;p&gt;คุณสามารถ &lt;a href="https://apidog.com/download?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;ดาวน์โหลด Apidog&lt;/a&gt; แล้วนำ endpoint ของ tool เข้ามาใน project เพื่อทดสอบแยกจาก runtime ของ agent ได้&lt;/p&gt;

&lt;p&gt;อ่านเพิ่มเติม: &lt;a href="https://apidog.com/th/blog/ai-agent-apidog-test-harness?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;วิธีทดสอบการเรียกใช้เครื่องมือของ AI agent&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist สำหรับสร้าง agent ที่เรียก API ภายนอก
&lt;/h2&gt;

&lt;p&gt;ใช้ checklist นี้ก่อนนำ agent ไปใช้งานจริง:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] tool ทุกตัวมี JSON schema ชัดเจน&lt;/li&gt;
&lt;li&gt;[ ] description ของ tool บอกว่าใช้เมื่อไรและไม่ควรใช้เมื่อไร&lt;/li&gt;
&lt;li&gt;[ ] API ที่ tool เรียกมี mock response&lt;/li&gt;
&lt;li&gt;[ ] มี test case สำหรับ success และ error&lt;/li&gt;
&lt;li&gt;[ ] response schema ถูก validate&lt;/li&gt;
&lt;li&gt;[ ] secret ไม่ถูก hardcode&lt;/li&gt;
&lt;li&gt;[ ] แยก base URL ตาม environment&lt;/li&gt;
&lt;li&gt;[ ] มี timeout และ retry policy&lt;/li&gt;
&lt;li&gt;[ ] มี logging สำหรับ tool call&lt;/li&gt;
&lt;li&gt;[ ] มี guardrails สำหรับข้อมูล sensitive&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  คำถามที่พบบ่อย
&lt;/h2&gt;

&lt;h3&gt;
  
  
  OpenAI AgentKit ฟรีหรือไม่
&lt;/h3&gt;

&lt;p&gt;เครื่องมือของ AgentKit ทำงานบนการใช้งาน OpenAI API ของคุณ ดังนั้นค่าใช้จ่ายหลักคือค่า token ของโมเดลและค่า API/tool call ที่ agent สร้างขึ้น ไม่มี subscription แยกเฉพาะสำหรับ AgentKit ตามข้อมูลในบทความนี้ ควรตรวจสอบราคาปัจจุบันจากแพลตฟอร์มของ OpenAI เสมอ เพราะราคาโมเดลอาจเปลี่ยนได้&lt;/p&gt;

&lt;h3&gt;
  
  
  ความแตกต่างระหว่าง AgentKit กับ Agents SDK คืออะไร
&lt;/h3&gt;

&lt;p&gt;Agents SDK คือ framework ระดับโค้ดสำหรับกำหนด agent, tool และ guardrails ส่วน AgentKit คือชุดเครื่องมือที่กว้างกว่า ซึ่งรวม Agent Builder, ChatKit, Connector Registry และ Evals ไว้รอบ SDK&lt;/p&gt;

&lt;p&gt;เมื่อ Agent Builder และ Evals ถูกยุติการใช้งานในช่วงปลายปี 2026 เส้นทางที่คงทนสำหรับทีมวิศวกรคือ Agents SDK อ่านคู่มือเพิ่มเติมได้ที่ &lt;a href="https://apidog.com/th/blog/how-to-use-openai-agents-sdk?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;คู่มือ Agents SDK&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Agent Builder กำลังจะถูกยกเลิกหรือไม่
&lt;/h3&gt;

&lt;p&gt;ใช่ OpenAI ประกาศเมื่อวันที่ 3 มิถุนายน 2026 ว่าจะยกเลิก Agent Builder และ Evals โดยทั้งสองจะปิดตัววันที่ 30 พฤศจิกายน 2026 และ Evals จะเป็นแบบอ่านอย่างเดียววันที่ 31 ตุลาคม 2026&lt;/p&gt;

&lt;p&gt;ChatKit ยังใช้งานได้ และ OpenAI แนะนำให้ย้าย workflow ที่เน้นโค้ดไปยัง Agents SDK ส่วน workflow ที่ใช้ภาษาธรรมชาติให้ใช้ Workspace Agents ใน ChatGPT&lt;/p&gt;

&lt;h3&gt;
  
  
  ฉันสามารถทดสอบ API ที่ agent ของ AgentKit เรียกใช้ได้หรือไม่
&lt;/h3&gt;

&lt;p&gt;ได้ และควรทำ ทุก tool ที่ agent เรียกใช้คือ HTTP API ที่มี request และ response คุณควร mock API เหล่านั้นระหว่างพัฒนา ตรวจ response schema และจัดการ key แยกตาม environment แพลตฟอร์มอย่าง Apidog ช่วยจัดการงานเหล่านี้ก่อนที่ agent จะไปถึงผู้ใช้จริง&lt;/p&gt;

&lt;h2&gt;
  
  
  สรุป
&lt;/h2&gt;

&lt;p&gt;AgentKit ช่วยให้นักพัฒนา OpenAI สร้าง agent ได้เร็วขึ้นผ่าน Agent Builder, ChatKit, Connector Registry และ Evals แต่ในปี 2026 Agent Builder และ Evals กำลังถูกยุติการใช้งาน ดังนั้นทีมวิศวกรควรลงทุนกับ Agents SDK เป็นหลัก และใช้ ChatKit หรือ Connector Registry เมื่อเหมาะกับงาน&lt;/p&gt;

&lt;p&gt;ไม่ว่าคุณเลือกเส้นทางใด ความน่าเชื่อถือของ agent ขึ้นอยู่กับ API ที่มันเรียกใช้ จำลอง API ตั้งแต่ต้น ตรวจ response ให้ตรง schema และจัดการ secret อย่างเป็นระบบ &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation"&gt;Apidog&lt;/a&gt; ช่วยให้คุณทดสอบและ mock endpoint ของ tool ที่ agent พึ่งพาได้ในที่เดียว ก่อนนำ agent ไปใช้งานจริงกับผู้ใช้.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
