به گزارش از وبسایت cncf

تصور کنید مجموعه‌ای از میکروسرویس‌ها را اجرا می‌کنید که هر کدام در حیطهٔ خود فعالیت می‌کنند؛ در این حالت با چه چالش‌هایی روبه‌رو می‌شوید؟ 🧩

یکی از مشکلات رایج، منطق تلاش مجدد (retry) است: تماس‌های سرویس‌به‌سرویس همیشه قابل اعتماد نیستند و ممکن است به‌دلایلی مانند timeout، ناپایداری شبکه یا خرابی سرویس‌های پایین‌دستی قطع شوند. برای بازیابی، اغلب برنامه‌ها منطق retry را خودشان پیاده‌سازی می‌کنند که با گذشت زمان با کد کسب‌وکار آمیخته می‌شود و از هر توسعه‌دهنده انتظار می‌رود آن را به‌درستی پیکربندی کند.

قابلیت مشاهده (observability) هم چالش دیگری است: هر سرویس نیاز به metrics، logging و tracing دارد تا جریان درخواست‌ها، تاخیرها و خطاها قابل فهم باشد. این ابزارها اغلب تکراری، مستعد اشتباه و قابل نادیده‌گرفتن‌اند و زمانی که قابلیت مشاهده نامنسجم باشد، دیباگ تولیدی بسیار دشوار می‌شود. 🔍

اینجا Dapr وارد میدان می‌شود. Dapr یک زمان‌اجرای منبع‌باز و event-driven میزبانی‌شده در CNCF است که با معماری sidecar بلوک‌های ساختمانی (building blocks) را برای برنامه‌های توزیع‌شده فراهم می‌کند. این انتزاع به توسعه‌دهندگان اجازه می‌دهد روی منطق تجاری تمرکز کنند و بسیاری از پیچیدگی‌های زیرساخت را به زمان اجرا واگذار کنند.

Dapr مجموعه‌ای از building blocks مثل گردش‌کار، pub/sub، conversation و jobs را ارائه می‌دهد و برای اغلب زبان‌های برنامه‌نویسی SDK دارد تا ادغام این قابلیت‌ها در برنامه‌ها ساده شود. به گزارش از وبسایت cncf

در این آموزش نشان می‌دهیم چطور بلوک Conversation در Dapr را برای تعامل با ارائه‌دهندگان مختلف مدل‌های زبان بزرگ (LLM) به‌کار ببرید. ارائه‌دهندگان LLM مثل Anthropic، Google، OpenAI و Ollama هرکدام API و رفتارهای متفاوتی دارند و پشتیبانی از چند ارائه‌دهنده معمولاً توسعه‌دهنده را مجبور می‌کند منطق مخصوص هر ارائه‌دهنده را در کد جاسازی کند. اما اگر زمان اجرا (runtime) مسئول مدیریت جزئیات پیاده‌سازی ارائه‌دهنده، تعاملات API و رفتارهای retry باشد، توسعه بسیار ساده‌تر خواهد شد و مهاجرت بین ارائه‌دهندگان نیز آسان‌تر خواهد.

برای نمونه، اعلام یک مؤلفه Anthropic در Dapr به‌صورت زیر انجام می‌شود:

apiVersion: dapr.io/v1alpha1
نوع: فراداده
مؤلفه:
  نام: مشخصات انسان:
    نوع: فراداده گفتگو.فراداده انسانی:
      - نام: مقدار کلید: «انتروپیک-کلید»
      - نام: مقدار مدل: claude-opus-4.5
      - نام: مقدار cacheTTL: 1

در اکوسیستم مؤلفه‌های Dapr، می‌توانید مؤلفه‌های دیگر مثل Secrets را هم اعلام کنید تا Dapr آنها را مدیریت کند. به این ترتیب اگر بخواهید از قابلیت Secrets استفاده کنید، کافی است مؤلفهٔ مربوطه را در یک فایل YAML اعلام کنید و زمان اجرا آن را مصرف می‌کند. برای جزئیات بیشتر به گزارش از وبسایت cncf

برای مثال مشابه با OpenAI، نوع مؤلفه را به صورت conversation.openai اعلام کرده و فیلدهای لازم را مشخص می‌کنیم:

apiVersion: dapr.io/v1alpha1
نوع: فراداده
کامپوننت:
  نام: مشخصات openai:
    نوع: فراداده گفتگو.openai:
      - نام: مقدار کلید: mykey
      - نام: مقدار مدل: gpt-4-turbo
      - نام: مقدار نقطه پایانی: 'https://api.openai.com/v1'
      - نام: منبع: cacheTTm

حالا بیایید عملکرد Conversation را در عمل اجرا کنیم. ابتدا Dapr CLI و Docker Desktop را نصب کنید، سپس dapr init را اجرا کنید، مخزن examples جاوا را کلون کنید، بسته‌ها را بسازید و زمان اجرا را با دستور dapr run راه‌اندازی کنید:

mvn clean install -DskipTests
dapr run --resources-path ./components/conversation --app-id myapp --app-port 8080 --dapr-http-port 3500 --dapr-grpc-port 51439 --log-level debug -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.conversation.AssistantMessageDemo

در ادامه، نمونه‌ای از کلاس Java که با DaprClient به زمان اجرا Dapr تماس می‌گیرد و پاسخ را محلی چاپ می‌کند آورده شده است:

public class AssistantMessageDemo {
  public static void main(String[] args) {
    try (var client = new DaprClientBuilder().buildPreviewClient()) {
      var messages = List.of(
        new SystemMessage(List.of(
          new ConversationMessageContent("شما یک دستیار جدید مفید برای آب و هوا هستید.")
        )),
        new UserMessage(List.of(
          new ConversationMessageContent("آب و هوای سانفرانسیسکو چگونه است؟")
        )),
        new AssistantMessage(List.of(
          new ConversationMessageContent("بررسی آب و هوا.")
        ), List.of(new ConversationToolCalls("{"Function":"getWeather","location":"San Francisco","unit":"fahrenheit"}"))),
        new ToolMessage(List.of(
          new ConversationMessageContent("{"temperature":"72F","condition":"sunny"}")
        )),
        new UserMessage(List.of(new ConversationMessageContent("آیا باید ژاکت بپوشم؟")))
      );
      var request = new ConversationRequestAlpha2("echo", List.of(new ConversationInputAlpha2(messages)));
      System.out.println(
        client.converseAlpha2(request)
          .block()
          .getOutputs().get(0)
          .getChoices().get(0)
          .getMessage().getContent()
      );
    }
  }
}

مثال بالا نشان می‌دهد که چگونه بلوک Conversation در Dapr تعامل با مدل‌های زبان بزرگ را ساده می‌کند، بدون اینکه کد شما به ارائه‌دهندهٔ خاصی قفل شود. شما مؤلفه‌های LLM را اعلام می‌کنید و Dapr مسئولیت یکپارچه‌سازی، تلاش‌های مجدد، احراز هویت و تفاوت‌های رفتاری بین ارائه‌دهندگان را برعهده می‌گیرد. 🚀

در یک جمع‌بندی کوتاه، استفاده از Dapr می‌تواند پیچیدگی‌های معمول در سیستم‌های توزیع‌شده را کاهش دهد و تجربهٔ توسعه و نگهداری را بهبود بخشد، به‌خصوص هنگام کار با چندین ارائه‌دهندهٔ LLM و نیاز به قابلیت مشاهده و احتیاط در retry.