Published on

Spring AI (قسمت چهارم): استفاده از ChatClient API برای مکالمات پویا

نویسندگان

Spring AI (قسمت چهارم): استفاده از ChatClient API برای مکالمات پویا

در این قسمت از مقاله اسپرینگ ای آی، به موضوع “چگونه از ChatClient API برای ساخت مکالمات پویا با مدل‌های هوش مصنوعی استفاده کنیم” می‌پردازیم. این بخش به شما کمک می‌کند تا از ابزارهای Spring AI برای برقراری ارتباط با مدل‌های هوش مصنوعی در پروژه‌های خود استفاده کنید.

ChatClient API – معرفی و استفاده عملی

ChatClient API به توسعه‌دهندگان این امکان را می‌دهد که با استفاده از یک API روان (Fluent API)، درخواست‌های خود را به مدل هوش مصنوعی ارسال کرده و پاسخ‌های مورد نظر را دریافت کنند. این API دارای قابلیت‌هایی است که به توسعه‌دهندگان کمک می‌کند مکالمات کاربرپسند و قابل مدیریت را با مدل‌های هوش مصنوعی ایجاد کنند.

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

ساخت و مدیریت Prompt

در هسته ارتباط با مدل، مفهوم Prompt قرار دارد. Prompt حاوی مجموعه‌ای از پیام‌هاست که به عنوان ورودی به مدل هوش مصنوعی ارسال می‌شود. پیام‌ها به دو نوع اصلی تقسیم می‌شوند:

  1. پیام‌های کاربر: این پیام‌ها همان چیزی هستند که کاربر به طور مستقیم وارد می‌کند. این پیام‌ها می‌توانند سوال، درخواست یا حتی فرمانی برای اجرای کاری خاص باشند.
  2. پیام‌های سیستم: پیام‌های سیستم توسط توسعه‌دهنده یا خود سیستم برای هدایت مکالمه و دادن راهنمایی‌های بیشتر به مدل ارسال می‌شوند. این پیام‌ها به مدل کمک می‌کنند تا درک بهتری از زمینه مکالمه و رفتار مورد انتظار داشته باشد.

این پیام‌ها معمولاً شامل مکان‌نماهایی هستند که در زمان اجرا با داده‌های کاربر جایگزین می‌شوند، مانند متغییر ها که مثلا با نام کاربر جایگزین می‌شود. این کار به شخصی‌سازی پاسخ مدل و مطابقت با ورودی‌های خاص کاربر کمک می‌کند.

تنظیمات Prompt و کنترل رفتار مدل

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

این تنظیمات به شما این امکان را می‌دهند که در پروژه‌های خود، تجربه‌ای دقیق و متناسب با نیازهای کاربران خود ایجاد کنید.

ایجاد ChatClient

ChatClient با استفاده از یک شیء ChatClient.Builder ساخته می‌شود. می‌توانید یک نمونه ChatClient.Builder که به طور خودکار پیکربندی شده است را برای هر مدل چت Spring Boot به‌دست آورید یا یکی را به‌صورت برنامه‌نویسی ایجاد کنید.

استفاده از ChatClient.Builder پیکربندی شده به‌صورت خودکار

در ساده‌ترین حالت استفاده، Spring AI پیکربندی خودکار Spring Boot را فراهم می‌کند و یک bean از نوع ChatClient.Builder به صورت نمونه‌ای برای شما ایجاد می‌کند تا در کلاس خود استفاده کنید.

قبل از اجرای این مثال، اطمینان حاصل کنید که وابستگی‌های مورد نیاز مانند Spring Boot و Spring AI به درستی پیکربندی شده‌اند. در زیر یک مثال ساده برای دریافت پاسخ به یک درخواست کاربر را مشاهده می‌کنید:

@RestController
class MyController {

    private final ChatClient chatClient;

    public MyController(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    @GetMapping("/ai")
    String generation(String userInput) {
        return this.chatClient.prompt()
            .user(userInput)
            .call()
            .content();
    }
}

در این مثال ساده، ورودی کاربر محتوای پیام کاربر را تنظیم می‌کند. متد call() یک درخواست به مدل هوش مصنوعی ارسال می‌کند و متد content() پاسخ مدل هوش مصنوعی را به صورت یک String برمی‌گرداند.

ایجاد ChatClient به صورت برنامه‌نویسی

شما می‌توانید پیکربندی خودکار برای ChatClient.Builder را با تنظیم ویژگی spring.ai.chat.client.enabled=false غیرفعال کنید. این کار زمانی مفید است که بخواهید از چندین مدل چت به صورت همزمان استفاده کنید. سپس، می‌توانید برای هر ChatModel که نیاز دارید، یک نمونه ChatClient.Builder به صورت برنامه‌نویسی ایجاد کنید:

ChatModel myChatModel = ... // معمولاً با Autowire ایجاد می‌شود

ChatClient.Builder builder = ChatClient.builder(myChatModel);

// یا یک ChatClient با تنظیمات پیش‌فرض بسازید:

ChatClient chatClient = ChatClient.create(myChatModel);

با این روش، شما کنترل کاملی بر روی نحوه ساخت و پیکربندی ChatClient خواهید داشت و می‌توانید آن را به گونه‌ای تنظیم کنید که نیازهای خاص پروژه شما را برآورده کند.

ChatClient Responses

ChatClient API روش‌های مختلفی برای قالب‌بندی پاسخ از مدل هوش مصنوعی با استفاده از Fluent API ارائه می‌دهد.

بازگرداندن ChatResponse

پاسخ از مدل هوش مصنوعی یک ساختار غنی است که با نوع ChatResponse تعریف شده است. این پاسخ شامل اطلاعاتی مانند زمان پاسخ، تعداد توکن‌های استفاده‌شده، و وضعیت درخواست می‌باشد. این پاسخ شامل متادیتاهایی درباره نحوه تولید پاسخ می‌باشد و ممکن است چندین پاسخ، که به عنوان Generations شناخته می‌شوند، هر کدام با متادیتای خود داشته باشد. این متادیتا شامل تعداد توکن‌های استفاده‌شده (هر توکن تقریباً معادل ۳/۴ یک کلمه است) برای ایجاد پاسخ است. این اطلاعات مهم هستند زیرا مدل‌های هوش مصنوعی میزبانی شده براساس تعداد توکن‌های استفاده‌شده به ازای هر درخواست هزینه می‌گیرند.

مثالی برای بازگرداندن شیء ChatResponse که شامل متادیتا است، در زیر با فراخوانی chatResponse() پس از متد call() نشان داده شده است:

ChatResponse chatResponse = chatClient.prompt()
    .user("Tell me a joke")
    .call()
    .chatResponse();

بازگرداندن یک موجودیت (Returning an Entity)

گاهی اوقات نیاز دارید که یک کلاس موجودیت (Entity) که از رشته بازگردانده‌شده نگاشت شده است را برگردانید. متد entity() این قابلیت را فراهم می‌کند.

به عنوان مثال، رکورد جاوا زیر را در نظر بگیرید:

record ActorFilms(String actor, List<String> movies) {}

می‌توانید به راحتی خروجی مدل هوش مصنوعی را با استفاده از متد entity() به این رکورد نگاشت کنید، همان‌طور که در مثال زیر نشان داده شده است:

ActorFilms actorFilms = chatClient.prompt()
    .user("Generate the filmography for a random actor.")
    .call()
    .entity(ActorFilms.class);

همچنین یک متد entity اضافه‌بارگذاری‌شده با امضای entity(ParameterizedTypeReference<T> type) وجود دارد که به شما امکان می‌دهد انواعی مانند لیست‌های جنریک را مشخص کنید:

List<ActorFilms> actorFilms = chatClient.prompt()
    .user("Generate the filmography of 5 movies for Tom Hanks and Bill Murray.")
    .call()
    .entity(new ParameterizedTypeReference<List<ActorFilms>>() {});

پاسخ‌های استریم (Streaming Responses)

متد stream() به شما امکان می‌دهد که یک پاسخ غیرهمزمان (asynchronous) دریافت کنید، همان‌طور که در مثال زیر نشان داده شده است:

Flux<String> output = chatClient.prompt()
    .user("Tell me a joke")
    .stream()
    .content();

شما همچنین می‌توانید ChatResponse را با استفاده از متد Flux<ChatResponse> chatResponse() استریم کنید.

استفاده از مقادیر پیش‌فرض (Using Defaults)

ایجاد یک ChatClient با متن سیستمی پیش‌فرض در یک کلاس @Configuration، کد زمان اجرا را ساده‌تر می‌کند. با تنظیم مقادیر پیش‌فرض، فقط نیاز است متن کاربر را هنگام فراخوانی ChatClient مشخص کنید و دیگر نیازی به تنظیم متن سیستم برای هر درخواست در مسیر کد زمان اجرا ندارید.

متن سیستم پیش‌فرض (Default System Text)

در مثال زیر، ما متن سیستم را به گونه‌ای پیکربندی می‌کنیم که همیشه به صدای دزدان دریایی پاسخ دهد. برای جلوگیری از تکرار متن سیستم در کد زمان اجرا، ما یک نمونه ChatClient در یک کلاس @Configuration ایجاد خواهیم کرد:

@Configuration
class Config {

    @Bean
    ChatClient chatClient(ChatClient.Builder builder) {
        return builder.defaultSystem("You are a friendly chat bot that answers question in the voice of a Pirate")
                .build();
    }
}

و یک @RestController برای فراخوانی آن:

@RestController
class AIController {

    private final ChatClient chatClient;

    AIController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

  @GetMapping("/ai/simple")
	public Map<String, String> completion(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
		return Map.of("completion", chatClient.prompt().user(message).call().content());
	}

برای مشاهده یک مثال عملی، می‌توانید به مخزن زیر مراجعه کنید:

LLM Applications with Java and Spring AI

این مخزن نمونه‌هایی از نحوه ساخت چت بات با استفاده از Spring AI و مدل‌های زبان بزرگ (LLMs) را نشان می‌دهد که به کمک هوش مصنوعی مولد قدرت می‌گیرند.

https://github.com/aminsource/gap

در قسمت‌های بعدی به جزئیات این چت‌بات به تفصیل می‌پردازیم.