آپ گوا کے سفر کی منصوبہ بندی کرنا چاہتے ہیں۔ آپ کے پاس پانچ دن ہیں، 25,000 روپے کا بجٹ ہے، اور ساحلوں (beaches) اور سمندری غذا (seafood) کے لیے واضح ترجیح ہے۔ عام طور پر، اس کا مطلب ہے دس براؤزر ٹیب کھولنا، پرانے فورم پوسٹس پڑھنا، اور دستی طور پر ایک سفری پروگرام (itinerary) تیار کرنا۔ اس کے بجائے، تصور کریں کہ آپ صرف ایک POST request بھیجتے ہیں اور کھانے پینے کی تجاویز، سرگرمیوں کی فہرستوں، اور بجٹ کی درست تقسیم کے ساتھ ایک منظم دن بہ دن منصوبہ حاصل کرتے ہیں۔ یہ پروجیکٹ یہی فراہم کرتا ہے۔

ہم Spring Boot اور Azure OpenAI کا استعمال کرتے ہوئے ایک REST API بنائیں گے۔ یہ API منزل، بجٹ، دورانیہ، اور دلچسپیوں کو قبول کرتا ہے۔ یہ صاف ستھرا JSON واپس کرتا ہے جسے فرنٹ اینڈ یا موبائل ایپ فوری طور پر رینڈر کر سکتی ہے۔ کوئی اسکریپنگ نہیں۔ کوئی ہارڈ کوڈڈ سفری پروگرام نہیں۔ بس ایک AI ماڈل جسے ٹریول پلانر کے طور پر کام کرنے کے لیے پرامپٹ کیا گیا ہو۔

API کیا واپس کرتا ہے

جواب (response) مارک ڈاؤن ٹیکسٹ کا کوئی بلاک نہیں ہے جسے آپ کو regex کے ذریعے الگ کرنا پڑے۔ یہ ایک منظم JSON آبجیکٹ ہے جس میں روزانہ کی سرگرمیاں، کھانے پینے کی سفارشات، اور بجٹ کی تفصیلات شامل ہوتی ہیں۔ گوا کے سفر کے لیے، آپ کو پہلے دن کا ایسا حصہ مل سکتا ہے جو ساحلی جھونپڑی (beach shack) پر ناشتے کے لیے 500 روپے، پالولیم (Palolem) میں صبح کا وقت، اور کسی مخصوص علاقے میں شام کے سمندری غذا کے ڈنر کے لیے مختص کرتا ہو۔ ہر دن میں ٹائم سلاٹس، تخمینہ لاگت، اور "beach" یا "food" جیسے ٹیگز شامل ہوتے ہیں۔ یہ ساخت اس لیے اہم ہے کیونکہ جدید ٹریول ایپس پیراگراف کو پروسیس نہیں کرنا چاہتیں۔ وہ ایسے آبجیکٹس چاہتے ہیں جنہیں وہ RecyclerViews یا React components کے ساتھ میپ کر سکیں۔

ٹیکنالوجی اسٹیک اور اس کی اہمیت

یہ پروجیکٹ Spring AI کے ساتھ Spring Boot 3.5 استعمال کرتا ہے۔ Spring AI اس کا اہم حصہ ہے۔ یہ ایک متحد ChatModel ایبسٹریکشن (abstraction) فراہم کرتا ہے تاکہ آپ کو Azure OpenAI کے خلاف خام (raw) HTTP کلائنٹس لکھنے کی ضرورت نہ پڑے۔ آپ سروس کوڈ کے بجائے صرف ڈیپینڈنسیز (dependencies) اور پراپرٹیز کو تبدیل کرتے ہیں۔

آپ کو اپنی بلڈ فائل میں چار ڈیپینڈنسیز کی ضرورت ہوگی:

  • REST لیئر کے لیے spring-boot-starter-web۔
  • Spring AI کے انٹرفیس کے ذریعے LLM سے منسلک ہونے کے لیے spring-ai-starter-model-azure-openai۔
  • خودکار Swagger ڈاکومنٹیشن کے لیے springdoc-openapi۔
  • آپ کے request اور response POJOs میں بوائلر پلیٹ کوڈ (boilerplate code) کو کم کرنے کے لیے Lombok۔

Spring AI آپ کے بزنس لاجک اور LLM فراہم کنندہ کے درمیان کام کرتا ہے۔ یہ پوزیشننگ جان بوجھ کر رکھی گئی ہے۔ یہ آپ کے @Service کلاسز کو صاف ستھرا اور فراہم کنندہ سے آزاد (provider-agnostic) رکھتی ہے۔

PromptTemplates کے ساتھ پرامپٹ انجینئرنگ

Java اسٹرنگز کے اندر پرامپٹس کو ہارڈ کوڈ کرنا ناقابلِ برقرار سافٹ ویئر بنانے کا ایک تیز طریقہ ہے۔ اگر پروڈکٹ ٹیم یہ فیصلہ کرتی ہے کہ AI کو زیادہ غیر رسمی (casual) ہونا چاہیے یا ایک خاص حد سے زیادہ بجٹ کا تخمینہ دینے سے انکار کرنا چاہیے، تو آپ کو اپنی سروس کو دوبارہ کمپائل کرنے کی ضرورت نہیں ہونی چاہیے۔

Spring AI PromptTemplate فراہم کرتا ہے۔ آپ پرامپٹ کا ڈھانچہ ایک ریسورس فائل یا مخصوص ٹیمپلیٹ اسٹرنگ میں محفوظ کرتے ہیں، جس میں {destination}, {budget}, {days}, اور {interests} جیسے متغیرات (variables) کے لیے جگہ چھوڑ دی جاتی ہے۔ رن ٹائم پر، سروس ایک Prompt آبجیکٹ بناتی ہے اور صارف کی ویلیوز شامل کر دیتی ہے۔

سسٹم میسجز کو صارف کے میسجز سے الگ رکھیں۔ سسٹم میسج کا استعمال شخصیت (persona) کی تعریف کرنے کے لیے کریں۔ مثال کے طور پر، آپ ماڈل کو بتاتے ہیں کہ وہ بھارتی مقامات میں مہارت رکھنے والا، بجٹ کا خیال رکھنے والا، اور صرف JSON واپس کرنے کے بارے میں سخت ہے (بغیر کسی مارک ڈاؤن فینس کے)۔ صارف کے میسج کا استعمال مخصوص سفر کی تفصیلات فراہم کرنے کے لیے کریں۔ یہ تقسیم اس وقت مددگار ہوتی ہے جب آپ بعد میں API کنٹریکٹ کو تبدیل کیے بغیر مختلف پرسنز (personas) کا A/B ٹیسٹ کرنا چاہتے ہوں۔

سروس لیئر: Azure OpenAI سے بات چیت

@Service کلاس کا ایک ہی کام ہے۔ یہ پرامپٹ بناتی ہے، ماڈل کو کال کرتی ہے، جواب کو صاف کرتی ہے، اور نتیجے کو پرس (parse) کرتی ہے۔

Spring AI کے ChatClient یا ChatModel کو انجیکٹ کریں۔ آنے والی درخواست کی ویلیوز کے ساتھ PromptTemplate کو رینڈر کریں، پھر چیٹ میتھڈ کو کال کریں۔ جواب ایک String کی صورت میں آتا ہے۔ یہ وہ مقام ہے جہاں بہت سے ٹیوٹوریلز رک جاتے ہیں اور اصل پروڈکشن کوڈ شروع ہوتا ہے۔

LLMs کبھی کبھی شائستہ تمہید (preambles) شامل کر دیتے ہیں۔ آپ کو ایسا جواب مل سکتا ہے جو "Here is your itinerary" سے شروع ہو اور پھر ٹرپل بیک ٹکس (triple backticks) میں لپٹا ہوا JSON دے دے۔ اگر آپ اسے براہ راست Jackson کے ساتھ ڈیسیرئیلائز (deserialize) کرنے کی کوشش کریں گے، تو آپ کی ایپ کریش ہو جائے گی۔ ایک چھوٹا ہیلپر میتھڈ شامل کریں جو خام اسٹرنگ کو اسکین کرے، پہلا کھلنے والا بریکٹ { اور آخری بند ہونے والا بریکٹ } تلاش کرے، اور صرف JSON پے لوڈ نکال لے۔ پھر نکالے گئے بلاک کی تصدیق کریں۔ کنٹرولر کو آبجیکٹ واپس کرنے سے پہلے چیک کریں کہ مطلوبہ فیلڈز موجود ہیں اور عددی ویلیوز (numeric values) درست ہیں۔

یہ دفاعی پرسیئنگ (defensive parsing) اختیاری نہیں ہے۔ یہ ایک ڈیمو اور ایک قابلِ اعتماد API کے درمیان فرق ہے۔

ایک پختہ سسٹم کی طرح غلطیوں کو سنبھالنا

بیرونی APIs ناکام ہو جاتی ہیں۔ Azure OpenAI ریٹ لیمٹ ایررز، آتھنٹیکیشن کی ناکامی، یا عارضی 500 ایررز واپس کرے گا۔ اگر آپ ان ایررز کو اسٹیک ٹریسز (stack traces) کی صورت میں صارف تک پہنچنے دیں گے، تو آپ اپنی ساکھ کھو دیں گے۔

Use @RestControllerAdvice to intercept exceptions globally. Map Spring AI exceptions, HttpClientErrorException, and generic RuntimeExceptions to consistent error responses. Return a JSON body with a clear message, an HTTP status like 429 for rate limits, and enough detail for the client to retry or log the issue. The user should see something like "Service temporarily busy. Please retry in 30 seconds," not a screen full of Java class names.

Never Hardcode Secrets

Your Azure OpenAI API key does not belong in application.properties checked into Git. Externalize it. Use environment variables referenced in your Spring configuration, such as ${AZURE_OPENAI_KEY} and ${AZURE_OPENAI_ENDPOINT}. Keep a local .env file for development, add it to .gitignore, and load it through Spring Boot’s relaxed binding. If a key leaks, you rotate it in one place rather than rebuilding your artifact.

Testing Through Swagger

The springdoc-openapi dependency exposes a Swagger UI endpoint at runtime. Once your application starts, open /swagger-ui.html in a browser. You can fill in the Goa example directly: destination as "Goa," budget as 25000, days as 5, interests as "beaches, food." Hit execute and watch the JSON itinerary appear. This lets you validate prompt changes, verify serialization, and share a live playground with frontend developers before either side writes a unit test.

Swapping Providers Without Rewriting Code

Startups change providers. Maybe Azure credits expire, or you want to run inference against a local Ollama instance to cut costs. Because Spring AI abstracts the ChatModel interface, the swap is mechanical. Change the Maven dependency from spring-ai-starter-model-azure-openai to another starter, update your properties file with the new endpoint and key, and leave your service class alone. The API contract seen by your mobile app stays identical.

That portability makes this architecture particularly useful for real products. You are not marrying Azure. You are using it as one engine plugged into a clean Spring pipeline.

The Real Takeaway

An AI model is not your application. It is an external service that returns unpredictable text. Treat it with the same rigor you would give a payment gateway or a third-party weather API. Externalize your credentials. Validate every response. Clean the payload before parsing. Handle errors globally so your users never see a stack trace.

Let the AI handle the creative work of building a Goa itinerary on a 25,000-rupee budget. You handle the plumbing. When the two stay separate, you get a system that actually ships.

The original walkthrough that inspired this article can be found here.

Interested in discussing Spring AI and similar projects? Join the GyaanSetu learning community.