DEV Community

Cover image for วิธีทดสอบ AI Agent เรียก API โดยไม่ทำให้ข้อมูลสูญหาย
Thanawat Wongchai
Thanawat Wongchai

Posted on • Originally published at apidog.com

วิธีทดสอบ AI Agent เรียก API โดยไม่ทำให้ข้อมูลสูญหาย

เอเจนต์โค้ดดิ้ง AI รันสคริปต์ เห็นว่าสำเร็จ แล้วตารางฐานข้อมูลในโปรดักชันหายไป โพสต์ Hacker News ที่ว่า “AI ไม่ได้ลบฐานข้อมูลของคุณ คุณต่างหากที่เป็นคนลบ” ดังขึ้นเพราะมันจริง: เอเจนต์ทำตาม tool definition, tool เรียก API จริง, API ไม่มี guardrail และมนุษย์ให้สิทธิ์เขียนกับกระบวนการที่ไม่หยุดถามว่า DELETE FROM users ดูแปลกไหม เหตุการณ์อีกแบบคือเอเจนต์ติด retry loop จนใช้โทเค็นหลายร้อยดอลลาร์ก่อนมีคนเห็น ปัญหาไม่ใช่โมเดล “โง่” แต่คือไม่มีใครทดสอบ API ให้เหมาะกับเอเจนต์

ลองใช้ Apidog วันนี้

💡 ถ้าคุณกำลังสร้างเอเจนต์อัตโนมัติที่เรียก API ของคุณเอง บทความนี้คือเช็กลิสต์ลงมือทำ: mock endpoint ภายนอก, จำกัด operation ที่สร้างความเสียหาย, เขียน contract test ให้ tool schema, ตั้ง budget ต่อเอเจนต์ และซ้อม failure mode ก่อนขึ้นโปรดักชัน เราจะใช้ Apidog เพราะรองรับ OpenAPI, mock server และ scenario test ในโปรเจกต์เดียว

สรุปย่อ

เอเจนต์ล้มเหลวในโปรดักชันเมื่อ API ไม่มี guardrail เช่น ไม่มี rate limit, ไม่มี idempotency, ลบข้อมูลแบบ hard delete, หรือ tool schema drift จาก OpenAPI spec วิธีแก้มี 4 ชั้น:

  1. ทดสอบ tool schema กับ OpenAPI spec
  2. ใช้ mock/sandbox สำหรับ endpoint ที่เปลี่ยน state
  3. บังคับใช้ idempotency key และ soft delete
  4. จำกัด budget ต่อเอเจนต์ แล้ว replay scenario ใน CI

Apidog ช่วยรวม OpenAPI import, mocks และ scenario runner ไว้ใน workflow เดียว

ทำไมความล้มเหลวของเอเจนต์จึงมักเป็นความล้มเหลวของ API

เมื่อเอเจนต์เรียก tool จริง tool เหล่านั้นคือ API ของคุณ ดังนั้น failure mode ส่วนใหญ่จะเกิดที่ API boundary

1. Prompt injection กลายเป็น authorization bug

ตัวอย่าง:

  1. ผู้ใช้อัปโหลด PDF ที่มีคำสั่งซ่อนอยู่
  2. เอเจนต์อ่านข้อความนั้น
  3. เอเจนต์เรียก /admin/users พร้อม delete_all=true

วิธีแก้ไม่ใช่แค่เขียน prompt ให้แข็งขึ้น แต่ต้องทำให้ API ไม่ยอมรับ operation แบบนั้นจาก token ที่มาจาก user context ปกติ ถ้าผู้ใช้ไม่มีสิทธิ์ลบ user ทั้งหมด เอเจนต์ที่ทำงานแทนผู้ใช้นั้นก็ต้องไม่มีสิทธิ์เช่นกัน

2. Tool schema drift ทำให้ข้อมูลผิดหน่วย

OpenAPI ระบุว่า amount เป็น integer หน่วยเซ็นต์ แต่ tool definition บอกว่า amount เป็น decimal หน่วยดอลลาร์ ผลคือการ refund 19 เซ็นต์อาจกลายเป็น 19 ดอลลาร์ โมเดลไม่ได้ตีความผิด มันทำตาม schema ที่คุณให้ไว้

3. Retry loop ไม่มี rate limit

เอเจนต์ retry endpoint ส่งอีเมลหลายพันครั้งใน 2 นาที เพราะ planner ยังคิดว่างานไม่สำเร็จ ถ้า API ไม่มี rate limit และไม่มี budget cap ค่าใช้จ่ายและผลกระทบจะเกิดจริงทันที

4. ไม่มี idempotency แล้วเกิด double charge

เอเจนต์เรียก POST /payments แล้ว network timeout จากนั้น retry เพราะคิดว่าล้มเหลว แต่คำขอแรกอาจสำเร็จไปแล้ว ถ้า API ไม่มี idempotency key ลูกค้าจะถูกเรียกเก็บเงินซ้ำ

สรุป: อย่าเริ่มจาก “โมเดลฉลาดพอไหม” ให้เริ่มจาก “API มีสัญญาและระบบป้องกันพอไหม”

สี่ Guardrails ที่ Agent-API Integration ต้องมี

1. ทดสอบสัญญา Tool Schema

OpenAPI spec ควรเป็น source of truth ส่วน tool definition ของเอเจนต์ต้องถูกตรวจเทียบกับ spec ทุกครั้งใน CI

ตัวอย่าง Python สำหรับตรวจ tool definition แบบ Claude-style กับ OpenAPI:

import json
from jsonschema import Draft202012Validator

def validate_tool_against_openapi(tool_def: dict, openapi_spec: dict) -> list[str]:
    """Return a list of mismatch errors, empty list = pass."""
    errors = []

    op = openapi_spec["paths"][tool_def["path"]][tool_def["method"].lower()]
    api_schema = op["requestBody"]["content"]["application/json"]["schema"]
    tool_schema = tool_def["input_schema"]

    api_props = set(api_schema.get("properties", {}).keys())
    tool_props = set(tool_schema.get("properties", {}).keys())

    for missing in api_props - tool_props:
        if missing in api_schema.get("required", []):
            errors.append(f"Tool missing required field: {missing}")

    for extra in tool_props - api_props:
        errors.append(f"Tool defines field not in API: {extra}")

    for prop, api_def in api_schema.get("properties", {}).items():
        if prop in tool_schema.get("properties", {}):
            tool_def_prop = tool_schema["properties"][prop]
            if api_def.get("type") != tool_def_prop.get("type"):
                errors.append(
                    f"Type mismatch on {prop}: API={api_def.get('type')} "
                    f"tool={tool_def_prop.get('type')}"
                )

    return errors
Enter fullscreen mode Exit fullscreen mode

เชื่อมเข้ากับ CI:

python scripts/check_tool_schema.py
Enter fullscreen mode Exit fullscreen mode

ถ้ามี error ให้ fail build ทันที อย่าแค่ warning เพราะ schema drift หนึ่งครั้งอาจกลายเป็น incident จริง

2. ใช้ Sandbox และ Mock สำหรับ Endpoint ที่เปลี่ยน State

ทุก endpoint ที่เปลี่ยนข้อมูลต้องมี mock หรือ sandbox equivalent:

  • POST
  • PUT
  • PATCH
  • DELETE

ระหว่างพัฒนา ให้เอเจนต์เรียก mock server แทนโปรดักชัน เช่น Apidog สร้าง mock จาก OpenAPI spec ได้โดยตรง และให้ค่า response ที่สอดคล้องกับ schema

อ่านเพิ่มเติม: การพัฒนาแบบ Contract-first

3. ใช้ Idempotency Key และ Soft Delete

ทุก write endpoint ที่เอเจนต์เรียกได้ควรรับ Idempotency-Key และทุก delete ควรเป็น soft delete เป็นค่าเริ่มต้น

ตัวอย่าง Express middleware:

const idempotencyCache = new Map();

function idempotency(req, res, next) {
  const key = req.headers['idempotency-key'];

  if (!key) {
    return res.status(400).json({ error: 'Missing Idempotency-Key header' });
  }

  if (idempotencyCache.has(key)) {
    const cached = idempotencyCache.get(key);
    return res.status(cached.status).json(cached.body);
  }

  const originalJson = res.json.bind(res);

  res.json = function (body) {
    idempotencyCache.set(key, { status: res.statusCode, body });

    setTimeout(() => {
      idempotencyCache.delete(key);
    }, 24 * 60 * 60 * 1000);

    return originalJson(body);
  };

  next();
}

app.post('/payments', idempotency, createPayment);
Enter fullscreen mode Exit fullscreen mode

เอเจนต์ควรสร้าง UUID ต่อ logical operation แล้วใช้ key เดิมเมื่อ retry:

const idempotencyKey = crypto.randomUUID();

await fetch('/payments', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Idempotency-Key': idempotencyKey
  },
  body: JSON.stringify({ customerId, amount })
});
Enter fullscreen mode Exit fullscreen mode

4. จำกัด Budget ต่อเอเจนต์

เอเจนต์ทุกตัวต้องมี budget ที่ fail closed เมื่อเกินขีดจำกัด เช่น:

  • token ต่อ session: 50,000
  • API call ต่อนาที: 30
  • spending ต่อ task: 500 cents
  • tool-call depth: 10 nested calls

เมื่อเกิน limit ให้คืน 429 พร้อม header ที่อ่านได้:

HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-Budget-Exceeded: api_calls_per_minute
Enter fullscreen mode Exit fullscreen mode

เอเจนต์ควรถูกออกแบบให้ escalate ให้มนุษย์หรือหยุดงาน ไม่ใช่ retry ต่อไปเรื่อย ๆ

ทดสอบการเรียก API ของเอเจนต์ด้วย Apidog

นี่คือ workflow ที่ลงมือทำได้ใน Apidog

คุณต้องมี:

  • OpenAPI spec ของ API ที่เอเจนต์เรียก
  • tool definitions ของเอเจนต์
  • test environment หรือ mock server

สกรีนช็อตของ Apidog แสดงการตั้งค่าโปรเจกต์พร้อม endpoints และ mock server

ขั้นตอนที่ 1: นำเข้า OpenAPI Spec

สร้างโปรเจกต์ใหม่ใน Apidog แล้ว import OpenAPI 3.x

Apidog จะสร้าง endpoint, schema และ examples จาก spec ให้ หาก API ของคุณยังไม่มี OpenAPI ให้เริ่มจาก design-first workflow ก่อน เพราะเอเจนต์ต้องมี source of truth ที่อ่านได้ทั้งมนุษย์และเครื่อง

อ่านเพิ่มเติม: เวิร์กโฟลว์ API แบบ Design-first

ขั้นตอนที่ 2: สร้าง Mock Response สำหรับ Endpoint ที่อันตราย

หา endpoint ที่เปลี่ยน state ทั้งหมด แล้วสร้าง mock response:

  • POST /payments
  • PATCH /users/{id}
  • DELETE /users/{id}
  • POST /notifications

แนวทางที่ควรทำ:

  • ใช้ prefix เช่น mock_user_
  • ใช้ timestamp ทดสอบ เช่นปี 1970
  • หลีกเลี่ยงข้อมูลที่เหมือนโปรดักชันเกินไป
  • ให้ response schema เหมือนของจริง

จากนั้น start mock server แล้วชี้ base URL ของเอเจนต์ไปที่ URL เช่น:

https://mock.apidog.com/m1/your-project-id/
Enter fullscreen mode Exit fullscreen mode

ตอนนี้ถ้าเอเจนต์เรียก DELETE /users/{id} ระหว่างทดสอบ ระบบจะคืน mock response โดยไม่แตะฐานข้อมูลจริง

อ่านเพิ่มเติม: การพัฒนาแบบ Contract-first

ขั้นตอนที่ 3: เขียน Scenario Test ตามลำดับ Tool Call

ตัวอย่างเอเจนต์คัดแยก support ticket อาจมี sequence แบบนี้:

  1. POST /auth/token ด้วย test credential แล้วเก็บ Bearer token
  2. GET /tickets?status=open แล้วเก็บ ticket ID แรก
  3. POST /tickets/{id}/triage พร้อม category แล้ว assert 200
  4. POST /notifications แล้ว assert ว่า message ตรง regex

สิ่งที่ควร assert ในทุก step:

  • status code
  • required fields
  • enum values
  • format เช่น date, email, currency
  • side-effect markers เช่น mock_ prefix

อ่านเพิ่มเติม: การทดสอบ API สำหรับวิศวกร QA

ขั้นตอนที่ 4: รัน Scenario จาก CI

เชื่อม scenario test เข้ากับ PR pipeline เช่น GitHub Actions หรือ GitLab CI

ตัวอย่างคำสั่ง:

apidog run -t scenario-id --env test
Enter fullscreen mode Exit fullscreen mode

แนวทางใช้งาน:

  • รันเมื่อ OpenAPI spec เปลี่ยน
  • รันเมื่อ tool definition เปลี่ยน
  • รันเมื่อ endpoint ที่เอเจนต์ใช้เปลี่ยน
  • fail build เมื่อ schema หรือ behavior ไม่ตรง baseline

ขั้นตอนที่ 5: เปรียบเทียบพฤติกรรม Model A และ Model B

ก่อนอัปเกรดโมเดล ให้รัน scenario เดียวกันกับโมเดลเก่าและใหม่:

  1. รัน Agent + Model A กับ Apidog mock
  2. เก็บ trace ของ request body
  3. รัน Agent + Model B กับ scenario เดิม
  4. เปรียบเทียบ payload

สิ่งที่มักพบ:

  • โมเดลใหม่ส่ง enum ต่างจากเดิม
  • ลืม required field
  • ใช้ date format คนละแบบ
  • เรียก endpoint เพิ่มโดยไม่จำเป็น

อ่านเพิ่มเติม: การผสานรวม API ของ GPT-5.5

เทคนิคขั้นสูงที่ควรใช้

ตั้ง Temperature เป็น 0 ใน Test

เวลาทดสอบ tool calling อย่าให้ความสุ่มรบกวนผลลัพธ์:

{
  "temperature": 0,
  "seed": 1234
}
Enter fullscreen mode Exit fullscreen mode

คุณกำลังทดสอบ API contract ไม่ใช่ creativity ของโมเดล

เก็บ Tool-call Trace ทุกครั้ง

บันทึก:

  • tool name
  • endpoint
  • request body
  • response status
  • latency
  • idempotency key
  • budget counters

จากนั้นเทียบกับ baseline ถ้าเอเจนต์เริ่มเรียก /users สองครั้งแทนหนึ่งครั้ง คุณควรรู้ใน CI ไม่ใช่ตอนบิลมา

อย่าให้ Production Credential กับเอเจนต์โดยตรง

ควรใช้:

  • scoped service account
  • short-lived token
  • API proxy ที่ sign request
  • secrets ใน vault ไม่ใช่ .env ที่เอเจนต์อ่านได้

แยก API Key สำหรับ Read และ Write

งานเอเจนต์จำนวนมากเป็น read-heavy ให้ใช้ read-only key เป็นค่าเริ่มต้น ส่วน write key ควรถูกใช้เฉพาะงานที่มี approval หรือ workflow guardrail

ใช้ HTTP 423 Locked สำหรับ Operation ที่ต้องมี Human Approval

แทนที่จะคืน 403 ให้คืน 423 Locked พร้อม URL ยืนยัน:

{
  "error": "human_confirmation_required",
  "confirmation_url": "https://internal.example.com/approve/req_123"
}
Enter fullscreen mode Exit fullscreen mode

ความหมายคือ “ยังทำไม่ได้จนกว่าจะมีคนอนุมัติ” ไม่ใช่ “ห้ามทำ”

Fail Closed เมื่อ Schema Drift

ถ้า tool schema ไม่ตรง OpenAPI:

  • fail build
  • block deploy
  • แจ้งทีมที่แก้ spec หรือ tool definition

อย่าปล่อยให้ drift สะสม เพราะ incident มักเกิดจาก mismatch เล็ก ๆ ที่ไม่มีใครเห็น

ข้อผิดพลาดที่ควรหลีกเลี่ยง

  • hardcode mock URL ใน prompt ให้ใช้ environment variable แทน
  • ข้าม idempotency บน endpoint “เล็ก ๆ” เช่นส่งอีเมล
  • log full request body ในโปรดักชันจน PII หลุดเข้า observability stack
  • ให้เอเจนต์ต่อ database โดยตรง
  • เชื่อ confidence score ของโมเดลว่าเท่ากับความปลอดภัยของ API

ถ้าเอเจนต์ของคุณเรียกหลาย service ภายใน อ่านเพิ่มเรื่อง รูปแบบการทดสอบ Microservices

ทางเลือกและเครื่องมือ

แนวทาง เวลาตั้งค่า จุดแข็ง จุดอ่อน เหมาะกับ
Unit test เขียนเอง ต่ำ ควบคุมเต็มที่, ไม่ผูก vendor ดูแลยาก, drift จาก API จริงได้ง่าย โปรเจกต์เล็ก
LangSmith / LangGraph eval harness ปานกลาง trace replay, metric ฝั่ง agent เน้น agent มากกว่า API ทีม AI eval
Postman + Postbot ปานกลาง UI คุ้นเคย, template เยอะ mock/scenario อาจไม่ตรง workflow ทั้งหมด ทีมที่ใช้ Postman อยู่แล้ว
Apidog scenarios + mocks ปานกลาง OpenAPI-native, mock, scenario CLI brand awareness น้อยกว่า Postman ทีมที่ต้องการ design, mock, test ในที่เดียว

ถ้าคุณใช้ LangSmith อยู่แล้ว ให้ใช้ต่อสำหรับ prompt/model eval แล้วเพิ่ม API contract layer แยกต่างหาก ถ้าคุณกำลังมองหาเครื่องมือที่รวม OpenAPI, mock และ scenario test ไว้ด้วยกัน Apidog เป็นทางเลือกที่แข็งแกร่ง

กรณีการใช้งานจริง

เอเจนต์อัปเดตข้อมูลบัญชีลูกค้า

ทีม Customer Success สร้างเอเจนต์ที่อัปเดตฟิลด์บัญชีจาก support ticket ก่อนเปิดตัว พวกเขา:

  • บังคับใช้ idempotency key ทุก write endpoint
  • replay scenario 200 ครั้งใน Apidog กับ sandbox DB
  • พบว่าเอเจนต์ส่ง subscription_status เป็น string ที่ไม่อยู่ใน enum
  • เพิ่ม schema validation แล้ว deploy โดยไม่มี incident

เอเจนต์เรียก Payment API

ทีมฟินเทคสร้างเอเจนต์ refund อัตโนมัติและตั้ง guardrail:

  • สูงสุด 5 refund ต่อ session
  • สูงสุด 50 ดอลลาร์ต่อ refund
  • ทุก call ต้องมี idempotency key
  • รัน ชุดทดสอบสัญญา ในทุก PR

ผลคือประมวลผล refund จำนวนมากโดยไม่เกิด double charge

เอเจนต์คัดแยก GitHub Issues

ทีมแพลตฟอร์มสร้าง triage bot ที่ได้แรงบันดาลใจจาก Clawsweeper แล้ว:

  • mock GitHub API ใน Apidog
  • สร้าง scenario 50 เคส เช่น issue ถูกลบ, label หาย, user input ผิดรูปแบบ
  • พบ crash 3 จุดก่อนปล่อยจริง

เช็กลิสต์นำไปใช้ทันที

เพิ่มไฟล์ agent-api-guardrails.md ใน repo แล้วเริ่มจากรายการนี้:

# Agent API Guardrails

## Contract
- [ ] OpenAPI spec เป็น source of truth
- [ ] Tool schema ถูก generate หรือ diff กับ OpenAPI
- [ ] CI fail เมื่อ schema drift

## Mock / Sandbox
- [ ] ทุก write endpoint มี mock
- [ ] Agent dev ใช้ mock base URL
- [ ] Staging ใช้ sandbox database

## Write Safety
- [ ] ทุก write endpoint ต้องมี Idempotency-Key
- [ ] Delete เป็น soft delete โดย default
- [ ] Hard delete ต้องมี human approval

## Budget
- [ ] Token cap ต่อ session
- [ ] API rate limit ต่อ agent
- [ ] Spending cap ต่อ task
- [ ] Tool-call depth limit

## Observability
- [ ] เก็บ tool-call trace
- [ ] redact PII ใน logs
- [ ] alert เมื่อ 429 หรือ budget exceeded
Enter fullscreen mode Exit fullscreen mode

สรุป

เอเจนต์ไม่ใช่ปัญหาโดยตัวมันเอง API ต่างหากที่เป็นทั้งจุดเสี่ยงและจุดควบคุม

จำ 5 ข้อนี้:

  1. Treat tool schema as contract
  2. Mock endpoint ที่สร้างความเสียหายได้เสมอ
  3. ใช้ idempotency key กับทุก write
  4. จำกัด budget ต่อเอเจนต์
  5. Replay scenario ในทุก PR ที่แตะ API หรือ tool definition

เริ่มจาก mock server ก่อนก็ได้ แค่เปลี่ยน agent base URL จากโปรดักชันไป mock ระหว่างพัฒนา ก็ลดความเสี่ยงได้มากแล้ว ดาวน์โหลดได้ที่ Apidog

อ่านต่อ:

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

ฉันจะทดสอบการเรียก API ของเอเจนต์โดยไม่เสียค่าโทเค็นได้อย่างไร?

ใช้ mock server ระหว่างพัฒนา ตั้ง temperature เป็น 0 และใช้ prompt set ขนาดเล็กที่คงที่ Apidog mock server คืน response ตาม schema โดยไม่เรียก API จริง ดู เช็กลิสต์การทดสอบของวิศวกร QA

การทดสอบเอเจนต์ต่างจากการทดสอบ API อย่างไร?

การทดสอบเอเจนต์ตรวจว่าโมเดลเลือก tool และกรอก argument ถูกไหม ส่วนการทดสอบ API ตรวจว่า endpoint ทำงานถูกเมื่อถูกเรียก ทั้งสองเลเยอร์ต้องทดสอบแยกกัน

จำเป็นต้องมี Idempotency Key ทุก endpoint หรือไม่?

จำเป็นสำหรับทุก write endpoint การอ่านเป็น idempotent โดยธรรมชาติ แต่การเขียนไม่ใช่ และเอเจนต์จะ retry เสมอเมื่อเห็น timeout หรือ 5xx

ป้องกัน Prompt Injection ไม่ให้เรียก API ผิดได้อย่างไร?

อย่าพึ่ง prompt อย่างเดียว API ต้อง enforce authorization ตาม user context เดิม ถ้าผู้ใช้ไม่มีสิทธิ์เรียก /admin/delete-all-users เอเจนต์ที่ทำงานแทนผู้ใช้นั้นก็ต้องเรียกไม่ได้เช่นกัน

ใช้ Apidog กับ Claude หรือ GPT โดยตรงได้ไหม?

ได้ในรูปแบบการทดสอบ tool/API โดยชี้ base URL ของ tool definition ไปที่ Apidog mock URL ระหว่างทดสอบ แล้วเปลี่ยน environment variable ไป staging หรือ production เมื่อพร้อม

Budget limit ที่เหมาะสมควรเริ่มเท่าไร?

เริ่มเข้มไว้ก่อน เช่น:

  • 50,000 tokens ต่อ session
  • 30 API calls ต่อนาที
  • 5 ดอลลาร์ต่องาน

เก็บ metric 2 สัปดาห์ แล้วค่อยปรับ limit ตามพฤติกรรมจริง

ตรวจ Schema Drift ระหว่าง Tool Definition กับ API ได้อย่างไร?

รัน schema diff ใน CI ทุก PR เปรียบเทียบ JSON schema ของ tool definition กับ OpenAPI request body schema ของ endpoint เดียวกัน ถ้าต่างกันให้ fail build ทันที โค้ด Python ในบทความนี้สามารถใช้เป็นจุดเริ่มต้นได้

Top comments (0)