
در این مقاله
ایجنت پاسخ داده، کد HTTP هم موفق بوده، اما کاربر نتیجه قابل استفاده نگرفته است. شاید ابزار اشتباه انتخاب شده، یک فراخوانی چند بار تکرار شده یا پاسخ درست پشت انتظار طولانی صف مانده باشد. برای یافتن علت، لاگ پراکنده کافی نیست؛ باید مسیر یک کار را از درخواست کاربر تا فراخوانی مدل و ابزار دنبال کنیم. Trace همین ارتباط را قابل مشاهده میکند، به شرطی که مرزهای عملیات، وضعیت و داده حساس را درست ثبت کرده باشیم.
در این آموزش، یک روش مستقل برای عیبیابی AI Agent میسازیم: تعریف شناسهها، ثبت Span، تحلیل تأخیر و انتخاب اصلاح قابل آزمایش. نمونه دادهها ساختگیاند و عددهای آنها نتیجه اندازهگیری پاستا یا یک مدل واقعی نیستند. خبر Span Queries در Mastra، معرفیشده در ۲۸ اکتبر ۲۰۲۶ بهانه این بررسی است، نه الزام استفاده از یک محصول خاص. میتوانید همین اصول را در برنامهای که از API پاستا استفاده میکند پیاده کنید.
Trace و Span به زبان ساده
Trace مسیر مرتبط یک عملیات را نشان میدهد و Span بخشی از آن مسیر است؛ مانند خواندن سند، درخواست مدل یا فراخوانی ابزار. رابطه والد و فرزند کمک میکند بدانیم یک فراخوانی در پاسخ به چه کاری شروع شده است. طبق مفهوم Trace در OpenTelemetry، زمینه رهگیری باید میان بخشها منتقل شود تا عملیات پراکنده قابل دنبالکردن باشد. ثبت چند زمان مستقل بدون شناسه مشترک، این رابطه را ایجاد نمیکند.
در محصول ایجنتی، یک Trace ممکن است شامل چند نوبت مدل و چند Tool باشد. همه آنها خطاهای زیرساختی نیستند: مدل میتواند ابزار نامناسب انتخاب کند یا پاسخ بدون منبع بدهد، در حالی که شبکه سالم است. به همین دلیل نتیجه فنی هر Span و نتیجه کاربردی کل کار را جدا ثبت کنید. مقاله کنترل هزینه و Eval ایجنت درباره کیفیت خروجی است؛ اینجا روی پیدا کردن بخش مشکلدار مسیر تمرکز داریم.
اول یک سؤال تشخیصی دقیق انتخاب کنید
«ایجنت کند است» برای شروع کافی نیست. مشخص کنید کدام کاربر، کدام نوع کار و کدام بازه زمانی دچار تأخیر شدهاند. آیا زمان قبل از شروع Worker زیاد است، مدل دیر جواب میدهد یا ابزار خارجی منتظر میماند؟ اگر کار به تأیید انسان رسیده، زمان انتظار را با کندی فنی مخلوط نکنید. یک سؤال مناسب میتواند این باشد: در کارهای خلاصهسازی سند، کدام مرحله بیشترین تأخیر غیرانسانی را ایجاد کرده است؟
برای پاسخ، یک گروه کار مشابه انتخاب کنید. مقایسه تولید یک پاسخ کوتاه با پردازش یک سند بزرگ، بدون مشخصکردن اندازه ورودی، علت را روشن نمیکند. قبل از تغییر مدل یا افزایش منابع، توزیع درخواستها و نسخه برنامه را ثبت کنید. اگر همزمان پرامپت، مدل و منابع را عوض کنید، حتی بهترشدن نتیجه نشان نمیدهد کدام تغییر مؤثر بوده است. تغییر محدود، تصمیم بعدی را قابل دفاعتر میکند.
حداقل اطلاعاتی که باید ثبت شود
برای هر Span، شناسه Trace، شناسه مستقل Span، والد، نوع عملیات، نام کمحساسیت، زمان آغاز، مدت و وضعیت لازم است. شمار تلاش و شناسه اجرای کار نیز برای Retry مفیدند. در درخواست مدل، شناسه مدل و شمار توکنهای گزارششده را در صورت وجود نگه دارید. داده مصرفی گزارشنشده را صفر فرض نکنید. برای خطا، یک کد طبقهبندیشده معمولاً از ذخیره پاسخ خام حاوی داده شخصی یا کلید مفیدتر و امنتر است.
{
"trace_id": "trace-demo-001",
"span_id": "span-tool-001",
"parent_span_id": "span-agent-001",
"kind": "tool",
"name": "search_authorized_docs",
"duration_ms": 2000,
"status": "error",
"error_code": "UPSTREAM_TIMEOUT",
"attempt": 1
}
این قالب نمونه برنامه است و پیادهسازی کامل قرارداد OpenTelemetry نیست. برای استفاده از SDK رسمی، نام فیلدها و انتقال Context را مطابق نسخه آن تنظیم کنید. بدنه سند، هدر Authorization و رشته اتصال دیتابیس نباید در این رکورد باشند. اگر برای خطایابی به نمونه متن نیاز دارید، روش نمونهبرداری محدود، پوشاندن داده و دسترسی کنترلشده تعریف کنید؛ ذخیره پیشفرض همه پیامهای مشتری راهحل قابل قبولی برای مشاهدهپذیری نیست.
آزمایش کوچک: یافتن ابزار کند از داده ساختگی
کد زیر چند رکورد خطی JSON را از ورودی استاندارد میخواند و برای Spanهای ابزار، تعداد، نرخ خطا و صدک ۹۵ مدت را محاسبه میکند. روش صدک در این نمونه nearest-rank است؛ برای مجموعه کوچک، عدد به بزرگترین مقادیر حساس است. این گزارش جای سامانه جمعآوری پایدار یا Query روی همه دادههای تولید را نمیگیرد. هدف این است که ببینید خروجی تشخیصی دقیقاً از کدام داده به دست آمده و بتوانید آن را آزمایش کنید.
import fs from 'node:fs';
export function summarize(spans) {
const groups = new Map();
for (const span of spans) {
if (span.kind !== 'tool') continue;
if (typeof span.name !== 'string' ||
!['ok', 'error'].includes(span.status) ||
typeof span.duration_ms !== 'number' ||
!Number.isFinite(span.duration_ms) || span.duration_ms < 0) {
throw new Error('Invalid completed tool span');
}
const group = groups.get(span.name) || {times: [], errors: 0};
group.times.push(span.duration_ms);
group.errors += Number(span.status === 'error');
groups.set(span.name, group);
}
return [...groups].map(([name, group]) => {
group.times.sort((a, b) => a - b);
return {
name,
count: group.times.length,
error_rate: group.errors / group.times.length,
p95_ms: group.times[Math.ceil(group.times.length * 0.95) - 1],
};
});
}
if (process.argv[2] === '--stdin') {
const lines = fs.readFileSync(0, 'utf8').trim();
const spans = lines ? lines.split(/\r?\n/).map(JSON.parse) : [];
console.log(JSON.stringify(summarize(spans), null, 2));
}
آن را در فایل trace-summary.mjs ذخیره کنید. در فایل ورودی، هر خط یک رکورد کامل باشد؛ سپس فرمان زیر را اجرا کنید. دادههای ساختگی با مدتهای ۱۰، ۲۰ و ۲۰۰۰ میلیثانیه و یک خطا، برای یک ابزار باید تعداد سه، نرخ خطای یکسوم و صدک ۹۵ برابر ۲۰۰۰ نشان دهند. این نتیجه محاسبات مثال است، نه گزارشی از عملکرد یک ارائهدهنده. یک ورودی نامعتبر هم باید رد شود، نه اینکه در میانگین پنهان بماند.
node trace-summary.mjs --stdin < spans.ndjson


نظرات کاربران (۰)
هنوز نظری ثبت نشده است. اولین نفر باشید.