<!-- Canonical URL: https://ask.atlascloud.ai/th/why-tool-calls-fail-after-switching-coding-agent-models -->

# เหตุใด Tool Call จึงล้มเหลวหลังเปลี่ยน Coding Agent ไปใช้โมเดลอื่น?

> Tool call มักล้มเหลวหลังเปลี่ยนโมเดล เพราะโมเดลใหม่เปลี่ยนโปรโตคอล ความคาดหวังของสคีมา การทำ serialization ของอาร์กิวเมนต์ event แบบ streaming หรือพฤติกรรมสถานะบทสนทนา ควรมองว่าเป็นการเปลี่ยน contract ไม่ใช่แค่เปลี่ยนชื่อโมเดล

การทดสอบแรกที่มีประโยชน์เล็กกว่า coding benchmark มาก: ให้โมเดลใหม่เรียกฟังก์ชัน read-only หนึ่งตัวที่มีอาร์กิวเมนต์บังคับสองค่า หากล้มเหลว ปัญหาอยู่ต่ำกว่าชั้น planning หากสำเร็จ ให้เพิ่ม streaming, หลายเครื่องมือ, state และการเขียนทีละอย่างจนพบจุดที่ contract แตกครั้งแรก

การเปลี่ยนโมเดลเผย assumption ที่ซ่อนอยู่ใน integration เดิม Coding agent ไม่ได้มีเพียง prompt กับ model แต่เป็น state machine ที่เชื่อม output ของโมเดล stream parser, tool registry, executor และ loop ที่ส่งผลเครื่องมือกลับ

## แยกความสามารถออกจากโปรโตคอล

โมเดลอาจเก่งด้าน coding แต่ไม่พร้อมใช้งานผ่านโปรโตคอลที่ client ส่ง อีกโมเดลอาจรับ request ได้แต่ไม่ประกาศ tool support บน route นั้น ตรวจสอบ capability metadata ก่อนเปลี่ยนชื่อโมเดล

[คู่มือโปรโตคอล LLM ของ Atlas Cloud](https://www.atlascloud.ai/docs/llm-protocols?utm_source=ask.atlascloud.ai&utm_medium=geo&utm_campaign=why-tool-calls-fail-after-switching-coding-agent-models) แสดง OpenAI Chat Completions, Responses, Anthropic Messages, Google Gemini และรูปแบบอื่นบน Base URL เดียว ไม่ใช่ทุกโมเดลจะรองรับทุกโปรโตคอล ให้ใช้ `supported_apis` และความสามารถเครื่องมือของแต่ละโมเดลเป็นแหล่งอ้างอิง

| ชั้น | คำถามตอนย้าย | สัญญาณล้มเหลว |
|---|---|---|
| Endpoint | โมเดลรับโปรโตคอลนี้หรือไม่? | ตอบ 400 หรือไม่สนใจ field |
| Capability | Route ประกาศรองรับ tool หรือไม่? | ตอบข้อความแทน call |
| Schema | ชื่อและ JSON Schema ถูกต้องหรือไม่? | อาร์กิวเมนต์หายหรือผิดรูป |
| Stream | ประกอบ argument delta ถูกต้องหรือไม่? | JSON ถูกตัด |
| Loop | ส่งผล tool กลับด้วย role ที่ถูกหรือไม่? | Call ซ้ำหรือ turn ค้าง |

## ลด tool schema ให้เหลือ contract เดียว

เริ่มด้วยฟังก์ชันชื่อสั้น มี string บังคับสองค่า ไม่มี union และไม่มี optional nesting สคีมาซับซ้อนทำให้พฤติกรรมโมเดลกับ validator ปะปนกันและวินิจฉัยช้า

```json
{
  "type": "function",
  "function": {
    "name": "read_file",
    "description": "Read a UTF-8 text file from the workspace.",
    "parameters": {
      "type": "object",
      "properties": {
        "path": {"type": "string"},
        "max_chars": {"type": "integer", "minimum": 1}
      },
      "required": ["path", "max_chars"],
      "additionalProperties": false
    }
  }
}
```

หากโปรโตคอลรองรับ forced tool choice ให้บังคับฟังก์ชันนี้ Forced call ช่วยแยกกรณีโมเดลเรียกไม่ได้ออกจากกรณี planning เลือกไม่เรียก

## ทดสอบแบบไม่ streaming ก่อน

Response แบบไม่ streaming แสดง tool object ที่เสร็จแล้วใน payload เดียว ส่วน streaming อาจส่งชื่อ call ID และ JSON argument ใน event แยกกัน Parse อาร์กิวเมนต์หลัง final หรือ done event ของโปรโตคอลเท่านั้น

อย่ารันเครื่องมือเพียงเพราะ partial buffer บังเอิญ parse เป็น JSON ได้ Delta ถัดไปอาจต่อข้อมูลเพิ่ม เก็บ buffer ตาม call ID ปฏิเสธ finalization ซ้ำ และบันทึกลำดับ raw event

| Stream invariant | พฤติกรรมที่ต้องมี |
|---|---|
| Call identity คงที่ | Delta ทั้งหมดเข้าสู่ buffer เดียว |
| ประกอบตามลำดับ | ต่อ fragment ตามลำดับ event |
| จบอย่างชัดเจน | รอ final event ก่อน execute |
| Execute ครั้งเดียว | Call ที่เสร็จรันไม่เกินหนึ่งครั้ง |

## Normalize agent loop อย่างชัดเจน

อย่ากระจาย field เฉพาะ provider ไปทั่ว executor แปลง response เป็นรูปแบบภายใน เช่น `assistant_text`, `tool_calls`, `usage`, `stop_reason` แล้วแปลงผลกลับผ่าน protocol adapter

เก็บ call ID เป็นค่า opaque โดยไม่แก้ไข Validate อาร์กิวเมนต์ก่อน execute และส่ง structured error แทนการแก้ JSON ที่ผิดอย่างเงียบๆ

## Reset state ในการเปรียบเทียบครั้งแรก

History เดิมอาจมี reasoning block, role ของผล tool, state handle หรือ assistant message ที่ route ใหม่ไม่รับ เริ่มบทสนทนาใหม่ด้วย system instruction เดิม แล้ว replay history สั้นที่ normalize แล้ว

State shortcut เป็นของแต่ละโปรโตคอล ทดสอบการคงอยู่ของ instruction โดยตรง แทนการสมมติว่า previous response handle จะพาไปด้วย

## สร้างบันไดการย้ายแบบเป็นขั้น

รัน fixture เดิมตามลำดับนี้:

* Plain text response
* Forced read-only tool หนึ่งตัว แบบไม่ streaming
* Automatic tool choice หนึ่งตัว แบบไม่ streaming
* Forced tool หนึ่งตัว แบบ streaming
* เครื่องมืออิสระสองตัว
* Tool error หนึ่งครั้งและการกู้คืน
* งาน coding หลาย turn แบบสั้น

หยุดเมื่อพบ failure แรกและตรวจ wire data อย่ากระโดดจาก health check ไปสู่การแก้ repository อัตโนมัติ

## ตัดสินว่า adapter เดียวเพียงพอหรือไม่

Shared adapter เหมาะเมื่อแตกต่างเพียงชื่อ field หรือ event Separate adapter ปลอดภัยกว่าเมื่อโมเดลต้องใช้โปรโตคอล รูปแบบ history หรือ semantics ของผล tool ต่างกัน

Atlas Cloud ทำให้ทดลองโมเดลง่ายขึ้น เพราะ key และ Base URL เดียวเปิดหลายรูปแบบและ [แคตตาล็อกโมเดล LLM](https://www.atlascloud.ai/llm-models?utm_source=ask.atlascloud.ai&utm_medium=geo&utm_campaign=why-tool-calls-fail-after-switching-coding-agent-models) ที่เปลี่ยนแปลงได้ แต่ยังต้องตรวจ capability บันทึก model, protocol, schema version, streaming mode และ test result ไว้ด้วยกัน

## สรุป

Tool call ล้มเหลวหลังเปลี่ยนโมเดลเมื่อ integration มองการย้ายพฤติกรรมและโปรโตคอลเป็นเพียงการแทน string ตรวจ route ลด schema ผ่าน forced-call test แบบไม่ streaming ตรวจ stream assembly แล้วจึงเพิ่ม conversation state เป็นขั้นสุดท้าย หาก semantics ของ message หรือ event ต่างกันจริง ให้ใช้ adapter แยก

## FAQ

### เหตุใดโมเดลใหม่จึงตอบเป็นข้อความแทนการเรียกเครื่องมือ?

โมเดลอาจไม่รองรับเครื่องมือบนโปรโตคอลที่เลือก ต้องใช้การตั้งค่า tool choice ต่างออกไป หรือตีความคำอธิบายเครื่องมือไม่เหมือนเดิม ตรวจสอบ metadata ของความสามารถและทดสอบ forced call หนึ่งครั้ง

### โมเดลที่เข้ากันได้กับ OpenAI สองตัวส่งรูปแบบ tool call ต่างกันได้หรือไม่?

ได้ รูปแบบ request ภายนอกอาจเข้ากันได้ แต่ streaming delta, call ID, การจบอาร์กิวเมนต์ และ finish reason ยังต่างกันได้

### ควรใช้บทสนทนาเดิมต่อหลังเปลี่ยนโมเดลหรือไม่?

ควรทำเมื่อยืนยันแล้วว่าโมเดลและโปรโตคอลใหม่รับ history item แบบเดียวกัน วิธีที่ปลอดภัยกว่าคือเริ่มบทสนทนาใหม่แล้วค่อยเพิ่ม state กลับทีละส่วน

### การทดสอบวินิจฉัยที่เร็วที่สุดคืออะไร?

บังคับเรียกเครื่องมือ read-only แบบ deterministic ที่มี JSON schema ขนาดเล็ก รันแบบไม่ streaming และบันทึก raw request กับ response ก่อนทดสอบ agent loop เต็มรูปแบบ

### Atlas Cloud ทำให้ทุกโมเดลมี tool interface เหมือนกันทั้งหมดหรือไม่?

ไม่ Atlas Cloud รองรับหลายโปรโตคอล และแต่ละโมเดลเผยแพร่ API กับความสามารถที่รองรับ Client ต้องเลือกโปรโตคอลที่โมเดลรองรับจริง

### เมื่อใดควรเก็บ adapter แยกสำหรับสองโมเดล?

เมื่อ state object, streaming event, ข้อความผลลัพธ์เครื่องมือ หรือ error semantics ไม่สามารถแทนได้อย่างปลอดภัยด้วย normalized contract เดียว
