فاز 13 · درس 20

ردگیری سرتاسری ایجنت‌ها با OpenTelemetry GenAI

نوع
ساختنی
زمان
حدود 75 دقیقه
زبان‌ها
Python (stdlib, OTel span emitter)
پیش‌نیاز
فاز 13 · درس 07 (سرور MCP)، فاز 13 · درس 08 (کلاینت MCP)
درختی از جعبه‌های متصل به هم که خطوط نوری زمان‌بندی و ردگیری فرآیندها را از ریشه تا شاخه‌ها نشان می‌دهد
فهرست مطالب
  1. اهداف یادگیری
  2. صورت مسئله
  3. مفاهیم پایه
  4. سلسله‌مراتب اسپن‌ها
  5. ویژگی‌های الزامی
  6. انواع اسپن (Span kinds)
  7. ثبت انتخابی محتوا
  8. رویدادها روی اسپن‌ها
  9. صادرکننده‌ها (Exporters)
  10. انتشار کانتکست در MCP
  11. سنجه‌ها (Metrics)
  12. لایه‌ی AgentOps
  13. استفاده از ابزارهای واقعی
  14. خروجی این درس
  15. تمرین‌ها
  16. اصطلاحات کلیدی
  17. برای مطالعه‌ی بیشتر

وقتی یک ایجنت هوش مصنوعی زنجیره‌ای از ابزارها، سرورهای MCP و فراخوانی‌های متعدد مدل زبانی را اجرا می‌کند، عیب‌یابی کندی یا خطاهای مقطعی آن به یک کابوس تبدیل می‌شود. بدون داشتن دید سرتاسری، لاگ‌های ساده فقط نشان می‌دهند که کل پردازش زمان زیادی برده است، اما مشخص نمی‌کنند گلوگاه کجاست؛ آیا مدل زبانی تأخیر داشته، یا یکی از ابزارهای جانبی و سرورهای بیرونی دچار اختلال شده است.

قراردادهای معنایی OpenTelemetry GenAI این چالش را با یک استاندارد واحد حل کرده‌اند. با مجهز کردن برنامه‌ها به این ساختار، اسپن‌ها و سنجه‌ها با قالبی یکپارچه تولید می‌شوند و به ابزارهای محلی و متن‌بازی مثل Jaeger یا پلتفرم‌های مانیتورینگ دیگر ارسال می‌گردند، بدون اینکه وابستگی به ابزار پایش خاصی در منطق برنامه ایجاد شود.

از آنجا که بسیاری از بک‌اندهای ابری خارجی مانیتورینگ به دلیل تحریم‌ها یا هزینه‌های ارزی دردسترس نیستند، مزیت بزرگ استاندارد OTel قابلیت ارسال آسان داده‌ها به کلکتورهای محلی و متن‌باز (مانند Jaeger یا نسخه‌های محلی Langfuse) است که به سادگی روی سرورهای داخلی یا سیستم شخصی بدون نیاز به سرویس‌های پرداختی خارجی راه‌اندازی می‌شوند.

فرض کنید ایجنتی پنج ابزار، سه سرور MCP و دو زیرایجنت (Sub-agent) را فراخوانی می‌کند؛ شما برای بررسی تمام این فرایندها فقط به یک ردگیری محاسبات (Trace) سرتاسری نیاز دارید. قراردادهای معنایی OpenTelemetry GenAI (ویژگی‌های پایدار در نسخه‌ی 1.37 به بالا) استاندارد سال 2026 هستند و Datadog، Langfuse، Arize Phoenix، OpenLLMetry و AgentOps به‌طور پیش‌فرض از آن‌ها پشتیبانی می‌کنند. در این درس با ویژگی‌های الزامی آشنا می‌شوید، ساختار سلسله‌مراتبی اسپن‌ها (Span؛ ایجنت ← مدل زبانی ← ابزار) را بررسی می‌کنید و یک ارسال‌کننده‌ی اسپن مبتنی بر کتابخانه‌ی استاندارد پایتون پیاده‌سازی می‌کنید که به هر صادرکننده‌ی OTel متصل می‌شود.

اهداف یادگیری

  • نام بردن ویژگی‌های الزامی OTel GenAI برای اسپن مدل زبانی و اسپن اجرای ابزار.
  • ساخت سلسله‌مراتب ردگیری محاسبات شامل حلقه‌ی ایجنت، فراخوانی مدل زبانی، فراخوانی ابزار و ارسال درخواست به کلاینت MCP.
  • تصمیم‌گیری درباره‌ی ثبت محتوا (انتخابی یا Opt-in) در برابر سانسور داده‌ها (پیش‌فرض).
  • ارسال اسپن‌ها به یک گردآورنده‌ی محلی (Jaeger، Langfuse) بدون نیاز به بازنویسی کدهای ابزار.

صورت مسئله

یک سناریوی خطایابی از فوریه‌ی 2026: کاربر گزارش می‌دهد «ایجنتم گاهی ظرف 3 ثانیه پاسخ می‌دهد و گاهی 30 ثانیه طول می‌کشد.» هیچ ردی در دست نیست. لاگ‌ها فراخوانی مدل زبانی را نشان می‌دهند، اما اثری از اجرای ابزار، رفت‌وبرگشت سرور MCP یا زیرایجنت نیست. ناچارید حدس بزنید. در نهایت متوجه می‌شوید: یکی از سرورهای MCP گه‌گاه هنگام راه‌اندازی اولیه (Cold-start) گیر می‌کند.

بدون ردگیری سرتاسری (End-to-end tracing)، پیدا کردن این مشکل غیرممکن است. OTel GenAI دقیقاً این چالش را حل می‌کند.

این قراردادها در سال‌های 2025 و 2026 در کارگروه قراردادهای معنایی OpenTelemetry نهایی شدند. آن‌ها نام‌های ثابتی برای ویژگی‌ها تعریف می‌کنند تا Datadog، Langfuse، Phoenix، OpenLLMetry و AgentOps همگی اسپن‌های یکسانی را پردازش کنند؛ یعنی یک بار سیستم را مجهز می‌کنید و داده‌ها را به هر بک‌اندی می‌فرستید.

مفاهیم پایه

سلسله‌مراتب اسپن‌ها

agent.invoke_agent  (top, INTERNAL span)
 ├── llm.chat       (CLIENT span)
 ├── tool.execute   (INTERNAL)
 │    └── mcp.call  (CLIENT span)
 ├── llm.chat       (CLIENT span)
 └── subagent.invoke (INTERNAL)

تمام این ساختار ذیل یک شناسه‌ی ردگیری (Trace ID) قرار می‌گیرد. شناسه‌های اسپن روابط والد-فرزندی را پیوند می‌دهند.

ویژگی‌های الزامی

بر اساس قراردادهای معنایی سال‌های 2025-2026:

  • gen_ai.operation.name — مقادیر "chat"، "text_completion"، "embeddings"، "execute_tool"، "invoke_agent".
  • gen_ai.provider.name — مقادیر "openai"، "anthropic"، "google"، "azure_openai".
  • gen_ai.request.model — رشته‌ی نام مدل درخواستی (مثلاً "gpt-4o-2024-08-06").
  • gen_ai.response.model — نام مدلی که در عمل پاسخ داده است.
  • gen_ai.usage.input_tokens / gen_ai.usage.output_tokens.
  • gen_ai.response.id — شناسه‌ی پاسخ ارائه‌دهنده برای تطبیق و همبستگی.

برای اسپن‌های مربوط به ابزار:

  • gen_ai.tool.name — شناسه‌ی ابزار.
  • gen_ai.tool.call.id — شناسه‌ی اختصاصی فراخوانی.
  • gen_ai.tool.description — توضیحات ابزار (اختیاری).

برای اسپن‌های مربوط به ایجنت:

  • gen_ai.agent.name / gen_ai.agent.id / gen_ai.agent.description.

انواع اسپن (Span kinds)

  • SpanKind.CLIENT برای فراخوانی‌هایی که از مرز پروسس عبور می‌کنند (ارائه‌دهنده‌ی مدل زبانی، سرور MCP).
  • SpanKind.INTERNAL برای مراحل داخلی حلقه‌ی ایجنت (Agent loop) و اجرای ابزارها.

ثبت انتخابی محتوا

اسپن‌ها به‌طور پیش‌فرض فقط سنجه‌ها و زمان‌بندی را نگه می‌دارند، نه پرامپت‌ها یا خروجی‌های مدل را. ثبت بارهای کاری حجیم و داده‌های هویتی و حساس (PII) در حالت عادی غیرفعال است. برای درج محتوا، باید متغیر محیطی OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental و متغیرهای محیطی مشخص ثبت محتوا را تنظیم کنید. پیش از فعال‌سازی این مورد در محیط عملیاتی، جوانب امنیتی را به‌دقت بسنجید.

رویدادها روی اسپن‌ها

رویدادهای در سطح توکن را می‌توان به‌صورت رویداد اسپن ثبت کرد:

  • gen_ai.content.prompt — پیام‌های ورودی.
  • gen_ai.content.completion — پیام‌های خروجی.
  • gen_ai.content.tool_call — فراخوانی ابزار به همان شکلی که ثبت شده است.

این رویدادها بر اساس زمان مرتب می‌شوند تا بازپخش و بررسی دقیق مراحل میسر شود.

صادرکننده‌ها (Exporters)

اسپن‌های OTel به مقصدهای زیر صادر می‌شوند:

  • Jaeger / Tempo: متن‌باز، قابل نصب روی سرورهای محلی.
  • Langfuse: اختصاصیِ پایش‌پذیری مدل‌های زبانی؛ مصورسازی مصرف توکن‌ها.
  • Arize Phoenix: ترکیب ارزیابی‌ها و ردگیری محاسبات.
  • Datadog: تجاری؛ با پشتیبانی مستقیم از ویژگی‌های gen_ai.*.
  • Honeycomb: پایگاه داده‌ی ستون‌محور با قابلیت کوئری‌زدن سریع.

همه‌ی این ابزارها از پروتکل OTLP که فرمت انتقال داده روی شبکه است پشتیبانی می‌کنند؛ بنابراین نوع بک‌اند تفاوتی در منطق کد شما ایجاد نمی‌کند.

انتشار کانتکست در MCP

وقتی کلاینت MCP سروری را صدا می‌زند، هدر استاندارد W3C با نام traceparent را به درخواست تزریق کنید. پروتکل Streamable HTTP از هدرهای استاندارد پشتیبانی می‌کند. از آنجا که رابط stdio هدرهای HTTP را پشتیبانی نمی‌کند، نقشه‌ی راه سال 2026 این مشخصه، افزودن فیلد _meta.traceparent را در فراخوانی‌های JSON-RPC پیشنهاد کرده است.

تا زمان پیاده‌سازی رسمی این قابلیت، traceparent را به‌صورت دستی در بخش _meta هر درخواست قرار دهید تا سرور بتواند شناسه‌ی ردگیری را لاگ کند.

سنجه‌ها (Metrics)

قراردادهای معنایی GenAI در کنار اسپن‌ها، سنجه‌های زیر را هم تعریف می‌کنند:

  • gen_ai.client.token.usage — نمودار توزیع فراوانی (هیستوگرام).
  • gen_ai.client.operation.duration — هیستوگرام.
  • gen_ai.tool.execution.duration — هیستوگرام.

از این سنجه‌ها برای ساخت داشبوردهایی استفاده کنید که نیازی به جزئیات تک‌تک فراخوانی‌ها ندارند.

لایه‌ی AgentOps

پلتفرم AgentOps (تأسیس 2024) به‌طور تخصصی روی پایش‌پذیری سیستم‌های GenAI تمرکز دارد. این ابزار فریم‌ورک‌های متداول (LangGraph، Pydantic AI و CrewAI) را در بر می‌گیرد تا اسپن‌های OTel را به‌صورت خودکار تولید کند. اگر از فریم‌ورک‌های پشتیبانی‌شده استفاده می‌کنید این ابزار به کارتان می‌آید؛ در غیر این صورت باید کدها را دستی تجهیز کنید.

آبشار Spanهاایجنت، LLM، ابزار و MCP در یک ردگیری
SPAN WATERFALLOne trace id covers the whole turn. The agent span opens first and closes last; inside it, an LLM call, a tool execution, and the MCP dispatch it wraps each get their own span with gen_ai attributes. When a backend cold-starts, the mcp.call bar is the one that stretches, which is exactly the question logs alone cannot answer.یک شناسه‌ی ردگیریزمانinvoke_agentllm.chattool.executemcp.callllm.chatgen_ai.operation.name on every span links the levels
یک شناسه‌ی ردگیری کل نوبت گفت‌وگو را پوشش می‌دهد. Span مربوط به ایجنت اول از همه باز شده و در انتها بسته می‌شود؛ درون آن، فراخوانی LLM، اجرای ابزار و اعزام MCP درون آن، هرکدام Span اختصاصی خود را همراه با مشخصه‌های gen_ai دریافت می‌کنند. هنگام Cold-start بک‌اند، نوار mcp.call کش می‌آید؛ دقیقاً همان سؤالی که لاگ‌ها به‌تنهایی قادر به پاسخ‌گویی به آن نیستند.

استفاده از ابزارهای واقعی

فایل code/main.py اسپن‌هایی با استاندارد OTel را (در قالبی شبیه به OTLP-JSON) برای ایجنتی در stdout چاپ می‌کند که یک مدل زبانی را فراخوانی کرده، دو ابزار را به کار انداخته و یک رفت‌وبرگشت MCP داشته است. در اینجا صادرکننده‌ی واقعی در کار نیست؛ تمرکز این درس روی ساختار اسپن‌ها و مجموعه‌ی ویژگی‌های آن‌هاست. خروجی را در یک ابزار مشاهده‌ی OTLP کپی کنید یا مستقیماً آن را بخوانید.

به این بخش‌ها دقت کنید:

  • شناسه‌ی ردگیری میان همه‌ی اسپن‌ها یکسان است.
  • ارتباط والد-فرزندی از طریق parentSpanId ثبت شده است.
  • ویژگی‌های الزامی gen_ai.* مقداردهی شده‌اند.
  • ثبت محتوا به‌طور پیش‌فرض غیرفعال است؛ اما در یکی از سناریوها با متغیر محیطی فعال می‌شود.

خروجی این درس

این درس فایل outputs/skill-otel-genai-instrumentation.md را تولید می‌کند. با دادن کد یک ایجنت به این مهارت، برنامه‌ی دقیق تجهیز آن مشخص می‌شود: محل افزودن اسپن‌ها، ویژگی‌های موردنیاز برای مقداردهی و صادرکننده‌های مناسب برای ارسال داده.

تمرین‌ها

  1. اسکریپت code/main.py را اجرا کنید. تعداد اسپن‌ها را بشمارید و مشخص کنید کدام CLIENT و کدام INTERNAL است.

  2. ثبت محتوا را با تنظیم متغیر محیطی فعال کنید و مطمئن شوید رویدادهای gen_ai.content.prompt و gen_ai.content.completion تولید می‌شوند. پیامدهای افشای داده‌های هویتی و حساس (PII) را بررسی کنید.

  3. سنجه‌ی اجرای ابزار با نام gen_ai.tool.execution.duration را اضافه کنید و آن را برای هر فراخوانی در قالب یک نمونه‌ی هیستوگرام بفرستید.

  4. مقدار traceparent را از اسپن والدِ ایجنت به فیلد _meta.traceparent درخواست MCP منتقل کنید. بررسی کنید که آیا سرور MCP همان شناسه‌ی ردگیری را دریافت می‌کند یا خیر.

  5. مستندات OTel GenAI semconv را بخوانید. یکی از ویژگی‌های موجود در استاندارد را که در کدهای این درس نیامده است پیدا کنید و به کد بیفزایید.

اصطلاحات کلیدی

اصطلاح اصطلاح رایج مفهوم واقعی
OTel «اوپن‌تلمتری» استاندارد باز برای ردگیری‌ها، سنجه‌ها و لاگ‌ها
GenAI semconv «قراردادهای معنایی GenAI» نام‌های ثابت ویژگی‌ها برای اسپن‌های مدل زبانی / ابزار / ایجنت
gen_ai.* «فضای نام ویژگی‌ها» پیشوند مشترک تمام ویژگی‌های GenAI
Span «عملیات زمان‌دار» واحدی از کار با زمان شروع، پایان و مجموعه‌ای از ویژگی‌ها
Trace «نسب‌نامه و مسیر فراخوانی‌ها» درختی از اسپن‌ها با شناسه‌ی ردگیری یکسان
SpanKind «انواع اسپن: CLIENT / SERVER / INTERNAL» راهنمایی درباره‌ی جهت و مرز ارتباطی اسپن
OTLP «پروتکل اوپن‌تلمتری» فرمت انتقال داده روی شبکه برای صادرکننده‌ها
Opt-in content «ثبت انتخابی محتوا» ثبت پرامپت و پاسخ؛ پیش‌فرض خاموش، فعال‌سازی با متغیر محیطی
traceparent «هدر W3C» کانتکست ردگیری را میان سرویس‌ها منتقل می‌کند
Exporter «ارسال‌کننده‌ی داده به بک‌اند» مؤلفه‌ای که اسپن‌ها را به Jaeger، Datadog یا سایر مقاصد می‌فرستد

برای مطالعه‌ی بیشتر

سؤالات متداول

چرا متن پرامپت‌ها و خروجی مدل به‌طور پیش‌فرض در اسپن‌های OTel ثبت نمی‌شوند؟

برای جلوگیری از افشای ناخواسته داده‌های هویتی و حساس (PII) و همچنین کاهش حجم داده‌های ارسالی، ثبت محتوا در OTel GenAI پیش‌فرض خاموش است و باید عمداً فعال شود.

هدر traceparent چگونه کانتکست ردگیری را به سرورهای MCP منتقل می‌کند؟

در ارتباطات بر بستر HTTP از هدر استاندارد W3C استفاده می‌شود و در ارتباطات مبتنی بر stdio، این مقدار موقتاً به‌صورت دستی در فیلد _meta.traceparent قرار می‌گیرد.

تفاوت SpanKind.CLIENT با SpanKind.INTERNAL در چیست؟

اسپن‌های CLIENT برای فراخوانی‌هایی استفاده می‌شوند که از مرز پروسس برنامه عبور می‌کنند (مانند صدا زدن مدل زبانی یا سرور MCP)، در حالی که اسپن‌های INTERNAL مراحل داخلی حلقه ایجنت و اجرای ابزارها را نشان می‌دهند.

ما رو توی گوگل بیشتر ببین

با افزودن نکست ادمین به «منابع ترجیحی» گوگل، درس‌ها و مطالب ما را در بخش اخبار برتر جستجو بیشتر می‌بینید.