ตามรอย AI agent ด้วย OpenTelemetry: อย่าเก็บพรอมป์ลับลง trace ทั้งก้อน

|ผู้เขียน: กองบรรณาธิการ QUASA|3 นาทีในการอ่าน
ตามรอย AI agent ด้วย OpenTelemetry: อย่าเก็บพรอมป์ลับลง trace ทั้งก้อน

ถ้าต้องการรู้ว่า AI agent ใช้โมเดลและเครื่องมือใด ช้าหรือล้มเหลวตรงไหน ให้เชื่อม span ของคำขอ การเรียก agent การวางแผน การเรียกโมเดล และการใช้เครื่องมือไว้ใน trace เดียวกัน ข้อกำหนด GenAI agent ของ OpenTelemetry แยก operation สำหรับงานเหล่านี้ รวมถึงระบุ attribute สำหรับชื่อการทำงานและประเภทข้อผิดพลาด

ให้เริ่มจากข้อมูลที่ตอบคำถามด้านเวลาและสถานะได้ก่อน ได้แก่ชื่อ operation, agent, โมเดลและเครื่องมือ ช่วงเวลาของแต่ละ span และ error.type เมื่อเกิดข้อผิดพลาด ปิดการเก็บข้อความพรอมป์ ผลลัพธ์ และข้อมูลลูกค้าไว้เป็นค่าเริ่มต้น เพราะโครงสร้างแม่ลูกของ span บอกเส้นทางงานได้โดยไม่ต้องคัดลอกบทสนทนาทั้งก้อนออกจากระบบต้นทาง

วาง span ตามงานที่เกิดขึ้นจริง

เริ่มด้วย span ของคำขอที่แอปรับเข้า ซึ่งครอบคลุมเวลาตั้งแต่เริ่มจัดการคำขอจนส่งคำตอบ จากนั้นวาง invoke_agent ไว้ใต้คำขอหากแอปเรียก agent ตัวเดียวโดยตรง ถ้ามีกระบวนการที่ประสานหลาย agent หรือหลายขั้นตอนของ GenAI ให้ใช้ invoke_workflow เป็นชั้นกลาง แล้ววาง span ของงานที่กระบวนการนั้นเรียกไว้ข้างใต้ ความสัมพันธ์นี้ทำให้แยกเวลาที่ผู้ใช้รอทั้งหมดออกจากเวลาที่ agent และงานย่อยใช้จริง

ไม่จำเป็นต้องสร้าง invoke_workflow ทุกครั้งที่เฟรมเวิร์กมีตัวรันงานภายใน ข้อกำหนดให้ใช้ span นี้กับกระบวนการที่แอปเรียกเป็นงานประสานจริง ไม่ใช่เพียงรายละเอียดที่ซ่อนอยู่ใน agent หรือ tool การเพิ่มชั้นที่ไม่มีความหมายต่อการทำงานจะทำให้ trace ยาวขึ้นและบังตำแหน่งที่เวลาเสียไป

ภายใน invoke_agent ให้สร้าง plan เมื่อระบบแยกช่วงกำหนดแผนหรือแตกงานออกจากการอนุมานทั่วไปได้อย่างเชื่อถือได้ หาก agent เรียกโมเดลเพื่อสร้างแผน span ของการเรียกโมเดลควรเป็นลูกของ plan ส่วนงานเครื่องมือที่เกิดหลังตัดสินใจตามแผนมักเป็น span ระดับเดียวกับ plan ภายใต้ agent เดียวกัน วิธีวางเช่นนี้แยกเวลาคิดแผน เวลารอโมเดล และเวลารอเครื่องมือได้ โดยไม่แสร้งว่าทุกการเรียกโมเดลคือขั้นวางแผน

ตัวอย่างต่อไปนี้เป็นสถานการณ์สมมติ: คำขอตรวจสถานะคำสั่งซื้อเข้าสู่ invoke_agent ชื่อ order_assistant; agent เปิด plan และเรียกโมเดลเพื่อเลือกขั้นตอน จากนั้นเรียก execute_tool ชื่อ lookup_order แล้วเรียกโมเดลอีกครั้งเพื่อร่างคำตอบ หาก lookup_order ใช้เวลานาน span ของเครื่องมือนั้นจะยาวเด่นขึ้น หากเครื่องมือจบด้วยข้อผิดพลาด ให้บันทึก error.type บน span ที่ล้มเหลวด้วย ผู้ดูแลจึงแยกได้ว่าความล่าช้าเกิดก่อนเรียกเครื่องมือ ระหว่างรอเครื่องมือ หรือระหว่างสร้างคำตอบ

create_agent เป็นอีก operation หนึ่งสำหรับการสร้าง agent ซึ่งมักเกี่ยวข้องกับบริการ agent ระยะไกล ไม่ควรสร้าง span ชื่อนี้ทุกครั้งที่มีข้อความใหม่เข้ามาหา agent ที่มีอยู่แล้ว เมื่อบริการปลายทางหรือเครื่องมือมี tracing ของตัวเอง ให้ส่งต่อ trace context ไปด้วยเพื่อให้ span ปลายทางเชื่อมกับคำขอต้นทาง และตรวจว่า instrumentation ของเฟรมเวิร์กกับ SDK ไม่บันทึกการเรียกเดียวกันซ้ำสองชั้น

เก็บ attribute ที่ตอบได้ว่าใครทำอะไรและพลาดตรงไหน

ชื่อ span ควรอธิบาย operation และชื่อ agent หรือเครื่องมือที่ระบบกำหนดไว้ อย่านำข้อความผู้ใช้ หมายเลขคำสั่งซื้อ หรืออีเมลมาเป็นชื่อ span เพราะค่าเหล่านั้นเปลี่ยนตามทุกคำขอและอาจเปิดเผยข้อมูลลูกค้า รายการต่อไปนี้เป็นชุดตั้งต้นสำหรับ trace ที่ต้องอ่านข้ามส่วนประกอบ; ค่าใดไม่มีจริงก็ไม่ต้องแต่งขึ้นเพื่อให้ช่องครบ

  • ชนิดงาน: ใช้ gen_ai.operation.name บนงาน GenAI เพื่อแยก invoke_agent, invoke_workflow, plan, การเรียกโมเดล และ execute_tool เวลาเริ่มกับเวลาจบของ span แสดงระยะเวลาของงานนั้น
  • ตัวงานที่เรียก: ใส่ gen_ai.agent.name, gen_ai.workflow.name หรือ gen_ai.tool.name ตามชนิด span เมื่อมีชื่อที่แอปกำหนดไว้ ชื่อคงที่ช่วยรวมปัญหาของเครื่องมือชนิดเดียวกันโดยไม่ต้องเห็นข้อมูลที่ส่งให้เครื่องมือ
  • การเรียกโมเดล: ใส่ gen_ai.provider.name และ gen_ai.request.model เมื่อทราบค่า หากมี gen_ai.response.model ให้เก็บด้วยเพื่อเห็นโมเดลที่ตอบจริง ชื่อ provider ตามมุมมองของ client อาจเป็นชื่อ proxy หรือแพลตฟอร์มที่รับคำขอ จึงไม่ควรตีความว่าเป็นผู้สร้างโมเดลปลายทางเสมอ
  • ความผิดพลาดและปริมาณงาน: ใส่ error.type เมื่อ operation จบด้วยข้อผิดพลาด และใช้ gen_ai.usage.input_tokens กับ gen_ai.usage.output_tokens บนการเรียกโมเดลเมื่อมีข้อมูลจำนวน token ค่าปริมาณงานช่วยอธิบายความต่างของเวลาได้บางส่วน แต่ไม่ได้บอกเนื้อหาที่โมเดลอ่านหรือคุณภาพคำตอบ

แยก span ของการเรียกโมเดลออกจาก span ของ agent เพื่อเห็นว่า agent ใช้เวลาเตรียมและจัดลำดับงานเท่าใดเมื่อเทียบกับเวลารอบริการโมเดล หาก client ลองเรียกซ้ำโดยอัตโนมัติ span ของการเรียกเชิงตรรกะควรครอบคลุมเวลาที่เสียไปกับการลองซ้ำด้วย มิฉะนั้นคำขออาจดูช้าโดยไม่มีช่วงงานใดอธิบายเวลาที่หายไป การบันทึกรายละเอียดของแต่ละครั้งที่ลองซ้ำเพิ่มได้ตามความสามารถของ instrumentation แต่ต้องไม่ทำให้การเรียกหลักถูกนับซ้ำ

กำหนดนโยบายข้อมูลก่อนเปิดการเก็บเนื้อหา

ข้อกำหนดสำหรับ GenAI client spans ระบุว่าคำสั่ง ข้อความขาเข้า และผลลัพธ์อาจมีข้อมูลอ่อนไหวและมีขนาดใหญ่ จึงแนะนำให้ instrumentation ไม่เก็บเนื้อหาเหล่านี้โดยปริยาย หากต้องเก็บเพื่อสืบสวนปัญหา แนวทางดังกล่าวเสนอทางเลือกให้เก็บเนื้อหาในระบบแยก แล้วบันทึกเพียงตัวอ้างอิงบน span เพื่อกำหนดสิทธิ์เข้าถึงต่างจากระบบ telemetry

นโยบายที่ใช้ได้จริงควรแบ่งข้อมูลตามหน้าที่ ข้อมูลที่เก็บใน trace ตามปกติคือ operation, ชื่อ agent หรือเครื่องมือที่กำหนดไว้ล่วงหน้า ชื่อโมเดล ระยะเวลา สถานะ และประเภทข้อผิดพลาด ข้อมูลที่ต้องพิจารณาเป็นรายกรณีคือข้อความใน gen_ai.system_instructions, gen_ai.input.messages และ gen_ai.output.messages รวมถึงคำอธิบายเครื่องมือที่อาจใส่รายละเอียดภายในองค์กรไว้ ส่วนรหัสผ่าน access token ข้อมูลระบุตัวบุคคล และข้อความลูกค้าทั้งก้อนควรอยู่ในระบบต้นทาง ไม่ไหลไปตาม trace เพียงเพื่ออำนวยความสะดวกในการแก้บั๊ก

การตัดพรอมป์ให้สั้นลงไม่เท่ากับการลบข้อมูลอ่อนไหว ชื่อ เบอร์โทรศัพท์หรือ token อาจอยู่ต้นข้อความ หากมีเหตุจำเป็นต้องเก็บข้อความ ให้กำหนดขอบเขตคำขอที่อนุมัติ ฟิลด์ที่อนุญาต วิธี redact ก่อนบันทึก ระยะเวลาเก็บ และผู้มีสิทธิ์อ่าน แล้วทดสอบกับข้อความที่มีข้อมูลลับอยู่หลายตำแหน่ง การสุ่มเก็บ trace ก็ไม่ใช่มาตรการลบข้อมูล: trace ที่ถูกสุ่มเก็บยังอาจมีข้อความเต็ม และข้อมูลอาจผ่าน instrumentation ก่อนถึงจุดที่ตัดสินใจส่งออก

ใช้กติกาเดียวกันกับ tool call เพราะ gen_ai.tool.call.arguments อาจมีรหัสคำสั่งซื้อ ที่อยู่ หรือคำค้นของลูกค้า ขณะที่ gen_ai.tool.call.result อาจมีข้อมูลจากฐานข้อมูลทั้งระเบียน สำหรับการหาจุดช้าโดยทั่วไป ชื่อเครื่องมือ ระยะเวลา สถานะ และ error.type เพียงพอแล้ว หากจำเป็นต้องรู้ชนิดคำขอ ให้เพิ่มค่าหมวดหมู่ที่กำหนดไว้ล่วงหน้า แทนการส่ง JSON ขาเข้าและขาออกทั้งก้อน สำหรับเครื่องมือแต่ละชนิดให้ระบุฟิลด์ที่ยอมรับได้อย่างชัดเจน เพราะผลลัพธ์ของเครื่องมือหนึ่งอาจปลอดภัยกว่าอีกเครื่องมือมาก

ตัวระบุบทสนทนาต้องมีนโยบายแยกจากข้อความสนทนา หากแอปมีรหัสบทสนทนาจริงและต้องเชื่อมหลายคำขอเข้าด้วยกัน อาจแปลงรหัสนั้นด้วย HMAC โดยเก็บกุญแจนอกระบบ telemetry แล้วใส่ค่าที่แปลงแล้วใน gen_ai.conversation.id วิธีนี้เป็นข้อเสนอด้านการออกแบบข้อมูล ไม่ใช่ข้อบังคับของ OpenTelemetry และค่าที่ได้ยังติดตามบทสนทนาเดิมได้ จึงต้องจำกัดสิทธิ์และอายุการเก็บด้วย อย่าสร้างค่าแทนจาก hash ของพรอมป์หรือจาก trace ID เพราะค่าเหล่านั้นไม่ได้ระบุบทสนทนาเดียวกันอย่างถูกต้อง

อ่านจุดช้าและจุดล้มเหลวจากโครงสร้าง trace

เมื่อคำขอช้า ให้ดูระยะเวลาของ span ลูกควบคู่กับช่วงเวลาที่ซ้อนกัน หาก invoke_agent ยาวแต่ span ของโมเดลสั้น ให้ดู plan, execute_tool และช่วงว่างระหว่างงาน หาก span ของโมเดลยาว ให้ดู provider, โมเดลที่ร้องขอ โมเดลที่ตอบ และจำนวน token ที่มีรายงาน การดูเฉพาะความยาวของ span แม่อาจทำให้เข้าใจผิด เพราะ span แม่ครอบคลุมเวลาของลูกอยู่แล้ว และงานลูกที่ทำพร้อมกันก็ไม่ควรนำเวลามาบวกตรง ๆ

เมื่อคำขอล้มเหลว ให้เริ่มที่ span ที่มี error.type แล้วไล่ความสัมพันธ์กลับขึ้นมา หาก execute_tool ล้มเหลว แต่ agent รับข้อผิดพลาดและสร้างคำตอบอื่นได้ สถานะของคำขอชั้นบนอาจต่างจากสถานะของเครื่องมือ การเก็บสถานะในตำแหน่งที่เกิดปัญหาจึงช่วยแยกความล้มเหลวที่ผู้ใช้เห็นออกจากความล้มเหลวภายในซึ่งระบบจัดการได้

หาก trace หยุดตรงจุดเรียกบริการภายนอก ให้ตรวจการส่งต่อ trace context ก่อนสรุปว่าปลายทางไม่ได้ทำงาน และหาก span ของเครื่องมือปรากฏซ้ำ ให้ตรวจว่าทั้งเฟรมเวิร์กและ SDK สร้าง span ให้การเรียกเดียวกันหรือไม่ Trace ที่ต่อเนื่องและไม่ซ้ำทำให้เห็นทางเดินของคำขอข้ามบริการ โมเดล และเครื่องมือ โดยยังคงนโยบายไม่เก็บข้อความลูกค้าไว้ได้

ตรึงเวอร์ชันของ instrumentation และตรวจ mapping เมื่ออัปเกรด

ข้อกำหนด GenAI agent ยังอยู่ในสถานะพัฒนา ชื่อ operation และ attribute ที่ระบบค้นหาใช้อาจได้รับผลจากการเปลี่ยนรุ่นของ instrumentation คู่มือ instrumentation สำหรับ Python ของ OpenTelemetry อธิบายว่า gen_ai_latest_experimental เลือกรูปแบบ GenAI ทดลองล่าสุดที่ไลบรารีรองรับ แทนรูปแบบทดลองเดิม ตัวเลือกนี้จึงควรเป็นการตัดสินใจระหว่างอัปเกรด ไม่ใช่ค่าที่เปิดทิ้งไว้โดยไม่ตรวจผล

ในระบบจริง ให้ตรึงรุ่น SDK, instrumentation และการตั้งค่า semantic conventions ที่ใช้งานร่วมกัน เก็บ trace ตัวอย่างที่ผ่านการลบข้อมูลอ่อนไหวเพื่อเทียบก่อนและหลังเปลี่ยนรุ่น แล้วตรวจชื่อ operation ความสัมพันธ์แม่ลูก ชื่อโมเดล ชื่อเครื่องมือและ error.type กับช่องค้นหาที่ทีมใช้ หาก mapping เปลี่ยนแต่รายงานยังอ้างชื่อเดิม ทีมอาจมองไม่เห็นปัญหาที่เกิดขึ้นทั้งที่ระบบยังส่ง span ตามปกติ

อ่านเพิ่มเติม:

แชร์:

สมัครรับจดหมายข่าวของเรา

รับข่าวสารล่าสุดเกี่ยวกับ Web3, AI และคริปโตส่งตรงถึงกล่องจดหมายของคุณ

0