CCA · Foundations

การส่งผลลัพธ์ tool กลับเข้าประวัติการสนทนา

แนวคิด

เมื่อ Claude ตอบด้วย stop_reason: "tool_use" มันยังไม่เห็นผลลัพธ์ของ tool มันเพียงแค่ "ขอ" ให้เรารัน หน้าที่ของแอปคือรัน tool นั้น แล้วเอาผลลัพธ์ใส่กลับเข้าไปในประวัติการสนทนาเป็น tool_result block ใน turn ถัดไป โมเดลจึงจะได้ข้อมูลใหม่มาใช้คิดก้าวต่อไป

รูปร่างของ request รอบถัดไปสำคัญมาก มันต้องประกอบด้วยของเดิมทั้งหมด บวกกับคำตอบของ assistant รอบที่แล้ว (ซึ่งมี tool_use block) และต่อท้ายด้วย user turn ใหม่ที่บรรจุ tool_result แต่ละอัน การแนบคำตอบ assistant กลับเข้าไปด้วยเป็นสิ่งที่ห้ามลืม เพราะ tool_result ต้องจับคู่กับ tool_use ที่มันตอบ

การจับคู่ทำผ่านฟิลด์ tool_use_id ทุก tool_use block มี id ประจำตัว และทุก tool_result ต้องอ้าง id เดียวกันผ่าน tool_use_id เพื่อบอกว่าผลนี้คือคำตอบของคำขอใด ถ้า Claude เรียกหลาย tool พร้อมกันในคำตอบเดียว ผลลัพธ์ทั้งหมดต้องรวมอยู่ใน user message เดียว ไม่ใช่แยกหลายข้อความ

ทำไมสำคัญ

ที่ต้องเป๊ะเรื่องนี้ เพราะการต่อประวัติการสนทนาคือช่องทางเดียวที่โมเดลจะ "รู้" ผลของการกระทำ Claude ไม่มีหน่วยความจำข้ามคำขอ ทุกอย่างที่มันเห็นคือ messages ที่เราส่งไปในรอบนั้น ถ้า tool_result หายไปหรือ id ไม่ตรง โมเดลจะเหมือนเรียกเครื่องมือแล้วไม่เคยได้คำตอบ มันจะเดา เรียกซ้ำ หรือหลุดออกนอกเรื่อง

อีกกับดักที่พบบ่อยคือการแยก tool_result ของการเรียกแบบขนานออกเป็นหลาย user message การทำแบบนั้นค่อย ๆ สอนให้โมเดลเลิกเรียก tool แบบขนาน เพราะรูปแบบข้อความที่มันเห็นไม่สอดคล้องกับที่มันส่งออกไป

ตัวอย่าง

{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
      "content": "อุณหภูมิ 31 องศา ฝนตกช่วงบ่าย"
    }
  ]
}

ถ้า tool ทำงานล้มเหลว อย่าเงียบหรือทิ้ง block ไป ให้ส่ง tool_result ที่มี is_error: true พร้อมข้อความอธิบาย โมเดลจะได้รับรู้ความผิดพลาดและปรับวิธี เช่น ลองเส้นทางอื่นหรือถามผู้ใช้เพิ่ม

เช็คความเข้าใจ

tool_result ต้องอ้างอิงฟิลด์ใดของ tool_use เพื่อจับคู่ให้ถูกอัน

ถ้า Claude เรียกสาม tool พร้อมกันในคำตอบเดียว ควรส่งผลลัพธ์กลับอย่างไร

อ่านต่อ