فرستنده تماس های عملکرد
Type: Build
Languages: Python
Prerequisites: Phase 13 lessons 01-07, Phase 14 lesson 01
Time: ~90 minutes
اهداف یادگیری
- یک دستیار ابزار را در یک زمان زمان بندی هر تماس که به جای شنیدن حلقه یک خطای تایپ شده را باز می کند، بسته کنید.
- با استفاده از "Jitter" و حداکثر تعداد تلاش ها، یک بار دیگر به صورت تعارفی تکرار کنید.
- تکرار تکرار در کلید idempotency به طوری که یک تکرار که با یک اصل آهسته مسابقه نمی دهد دو بار اجرا شود.
- استثنای های کاربری نقشه و خطاهای حمل و نقل به یک پاکت خطایی که حلقه هرنس قبلاً درک می کند.
- ارسال موازی با یک محدودیت همزمان محدود شده است بنابراین یک فان-آف از چهل تماس ابزار، حلقه رویداد را خسته نمی کند.
جایی که فرستنده میخواد
در میان حلقه استفاده (درسی بیست) و ثبت ابزار (درسی بیست و یک) ، حمل و نقل (درسی بیست و دو) حلقه را تغذیه می کند. حلقه یک تماس ابزار را به فرستنده می دهد. فرستنده به ثبت نام می خواند، دستیار را اجرا می کند و یا نتیجه ای یا یک پاکت خطای شکل JSON-RPC را باز می کند.
flowchart TD
loop[harness loop]
disp[dispatcher]
reg[tool registry]
handler[handler]
loop --> disp
disp -->|get name| reg
disp -->|validate args| reg
disp -->|asyncio.wait_for handler args timeout| handler
handler -->|success| disp
handler -->|TimeoutError -> retry or fail| disp
handler -->|Exception -> map to error code| disp
disp -->|Ok result or DispatchError| loopدیسپتچر تنها لایه ای است که می داند زمان، بازخورد و بی اختیار بودن. حلقه نمی داند. ثبت نمی کند. کنترل نمی کند. این تعزیر نقطه است.
زمان بندی
هر ابزار زمانبندی پیش فرض دارد.timeout_ms.ديسپتچر از يک تماس که از آن عبور ميکنهasyncio.wait_for. در زمان توقف، کار کنترل باز می گردد و فرستنده باز می گرددDispatchError(kind="timeout"). .
یک زمان توقف یک خطا قابل بازکرج به طور پیش فرض برای ابزارهای غیر قابل استفاده نیست.db.writeکه زمانش تموم شده و یا نه شده. دوباره امتحان کردن نوشته رو دوبرابر ميکنه.idempotentپرچم از سوابق ثبت نام ابزارهای بی اختیار دوباره امتحان کنید ابزارهای غیر بی اختیار باز نمی شود
بازتجربه با بازتجربه نمایی
قانون بازجوري سه بار حداکثر است و بازپسين با عصب
textattempt 1 -> delay 0
attempt 2 -> delay 0.1s * (1 + random[0..0.5])
attempt 3 -> delay 0.4s * (1 + random[0..0.5])فقطtimeoutوtransientاشتباهات دوباره امتحان کنید.schemaاشتباه، یکnot_found، یا یکinternalاشتباهات طرح تعیین کننده هستند. تکرار تلاش نتیجه را تغییر نمی دهد و بودجه را می سوزاند.
حلقه تکرار با احترام به بودجه از استفاده می کند. اگر بودجه تماس گیرنده صفر تماس ابزار باقی مانده است، فرستنده در اولین تلاش به سرعت شکست می خورد و بازگشت kind="budget_exceeded". .
کليد افتخاري
یک آزمایش مجدد که در حالی که اصلی هنوز در پرواز است یک خطا تولید واقعی است. اولین تماس در چهار نقطه نه ثانیه (به زودی تحت زمان توقف) می چرخد. دوباره آزمایش در پنج ثانیه می چرخد. اکنون دو درخواست در برابر همان پس زمینه مسابقه می دهند. اگر ابزار استpayments.charge، دو بار بار پرداخت کردي
فرستنده قبول ميکنه که اختیاري باشهidempotency_keyاگر همان کلید در پرواز است وقتی تماس می آید، فرستنده منتظر آینده در پرواز است و نتیجه آن را باز می گرداند. حافظه کش کلید ها را برای ۶۰ ثانیه پس از اتمام نگه می دارد تا بازخورد های دیر را جذب کند.
کلید مسئوليت تماس گرفته شده است.f"{step_id}:{tool_name}:{hash(args)}". دیسپتشر کلید را اختراع نمی کند، زیرا اخذ کلید از استدلال ها به تنهایی باعث می شود دو تماس معنوی متفاوت به نظر برسند.
پاکت خطا
یک ارسال شکست خورده یک شکل را باز می گرداند.
textDispatchError
kind : "timeout" | "transient" | "schema" | "not_found" | "internal" | "budget_exceeded"
message : str
attempts : int
jsonrpc_code: int (one of -32601, -32602, -32603)نقشه هاي حلقه هاي آداپkindبه دولت بعدیschemaوnot_foundبروon_errorو دوباره برنامه ریزی رو فعال کنمtimeoutوtransientبروon_errorو ممکن است یا ممکن است از نظر تلاش ها دوباره برنامه ریزی شود. budget_exceededمحرک هاon_budget_exceeded. .
محدودیت در برابر فان آئوتر
gather(*calls)با چهل تماس ابزار، یعنی چهل سوکت باز یا چهل لوله فرعی. اکثر پشتیبانان چهل اتصال موازی از یک مشتری را دوست ندارند.
. دستگاه بازيگر بسته ميکنهgatherدر یک سیمافور. حد متناوب پیش فرض هشت است. هر تماس قبل از ارسال سیمافور را بدست می آورد و در پایان آن را آزاد می کند. تماس گیرنده می بیند gather- شکل تولید اما برنامه ریزی واقعی محدود است
برای یک تماس جریان
flowchart TD
start([caller: dispatch name, args, opts])
validate[registry.validate name, args]
schema_err[DispatchError kind=schema]
idem_check{idempotency cache?}
in_flight[await existing future]
cached[return cached result]
attempt[asyncio.wait_for handler args, timeout]
success[cache + return result]
timeout_branch{TimeoutError + idempotent?}
retry[retry with backoff]
fail[DispatchError]
transient_branch{TransientError?}
other[map Exception to kind, no retry]
exhausted[DispatchError]
start --> validate
validate -->|errors| schema_err
validate -->|ok| idem_check
idem_check -->|hit in flight| in_flight
idem_check -->|hit recent| cached
idem_check -->|miss| attempt
attempt --> success
attempt --> timeout_branch
timeout_branch -->|yes| retry
timeout_branch -->|no| fail
attempt --> transient_branch
transient_branch -->|yes, attempts left| retry
transient_branch -->|exhausted| exhausted
attempt --> other
retry --> attemptچطور کد رو بخونيم
code/main.pyتعریف می کندDispatcher،DispatchErrorوTransientError. دستگاهي که در ساختمون ثبت ميکنه .dispatch(name, args, ...)تنها نقطه ورود است.در هر تلاش، زمان بندی ها در داخل خطی اعمال می شود._run_with_retriesاستفاده کردنasyncio.wait_for.gather_bounded(calls)خیلی از ارسال ها با محدودیت هم زمانه رو اجرا میکنه
code/tests/test_dispatcher.pyشامل وقت توقف، بازخوردن در زمان گذر، بازخوردن در خطای طرح، تخفیف idempotency (دو تماس همزمان با یک کلید یکسان به یک دعوت دستیار) و محدود کردن همزمان (سماور در عمل) می شود.
تست ها استفاده می کنندasyncio.sleep(0)و تعیین کنندهCounter-دستورهای مبتنی بر دستکاری، بنابراین آنها در میلی ثانیه تمام می شوند و به زمان ساعت دیواری وابسته نیستند.
. به جلوتر می رسیم
دو افزونه تولید فرستنده اضافه می شود. اول، ثبت ساختار در هر انتقال (که جریان رویداد حلقه به شما می دهد، اما فرستنده باید نیز انتشار dispatch.attemptوdispatch.retryدوم، قطع مدار: پس از شکست N در پنجره، یک ابزار یک دوره خنک کننده را دریافت می کند که در آن ارسال ها بلافاصله با kind="circuit_open"هر دو بدون تغییر قرارداد روی این دستگاه قرار میگیرن
درس ۲۴، فرستنده را به یک عامل برنامه ریزی و اجرا می کند تا شما همه چهار قطعه را در حرکت ببینید.
This free lesson is part of the AI Engineering from Scratch curriculum. Read the full explanation, run the lesson code, and verify the result in the interactive reader or from the repository source.
Browse the complete course catalog or open this lesson on GitHub.