हर LLM की एक ही समस्या होती है: बातचीत खत्म होते ही वह सब कुछ भूल जाता है—कभी-कभी तो लंबी बातचीत के दौरान भी। आप बीस मिनट लगाकर अपना प्रोजेक्ट सेटअप, अपनी बाधाएँ और अपनी प्राथमिकताएँ समझाते हैं, और वह सटीक जवाब देता है। टैब बंद करें, नया सेशन खोलें, और वह आपको अनजाने की तरह अभिवादन करता है। सारा संदर्भ, गायब।
अगर आप एक AI एजेंट बनाना चाहते हैं—कुछ ऐसा जो सच में संदर्भ याद रखे और आपके डोमेन के बारे में चीज़ें जानता हो—तो आपको उसे मेमोरी देनी होगी। व्यावहारिक किस्म की, जहाँ वह वास्तव में आपकी कही बात याद रखे और आपके सिखाए तथ्यों को ढूंढ सके।
यह एक POC है जो मैंने ठीक यही करने के लिए बनाया। तीन तरह की मेमोरी, एक डेटाबेस, बहुत कम कोड। पूरा सोर्स कोड GitHub पर उपलब्ध है।
Spring AI के साथ AI एजेंट आर्किटेक्चर
चित्र 1. Spring AI और Oracle AI Database 26ai के साथ एंड-टू-एंड एजेंट मेमोरी आर्किटेक्चर
Oracle AI Database 26ai तीनों मेमोरी स्टोर्स के लिए, जहाँ Hybrid Vector Indexes (vector + कीवर्ड सर्च को Reciprocal Rank Fusion के साथ फ्यूज़ करके) सेमांटिक रिट्रीवल के लिए और लोडेड ONNX मॉडल (all-MiniLM-L12-v2) इन-डेटाबेस एम्बेडिंग्स के लिए
Streamlit एक त्वरित वेब UI के लिए (~100 लाइनों का Python)
Java 21, Gradle 8.14
AI एजेंट मेमोरी के तीन प्रकार
एजेंट्स के लिए episodic, semantic, procedural और working मेमोरी की बात होती है।
Working मेमोरी बस LLM का context window है; वर्तमान अनुरोध के लिए सक्रिय "स्क्रैचपैड"। यह persisted नहीं होती, इसलिए यहाँ बनाने को कुछ नहीं है। मैंने बाकी तीन लागू किए हैं:
Episodic मेमोरी: चैट इतिहास को संरक्षित करना
Episodic मेमोरी चैट इतिहास है। एजेंट याद रखता है कि आपने बातचीत में पहले क्या कहा था। संदेश 1 पर "मेरा नाम Victor है" का मतलब संदेश 50 पर भी उसे आपका नाम पता है। इसे रिलेशनल टेबल में पंक्तियों के रूप में संग्रहीत किया जाता है।
चित्र 2. Episodic मेमोरी यानी चैट इतिहास
Semantic मेमोरी: RAG इंटीग्रेशन
Semantic मेमोरी डोमेन नॉलेज है। आप एजेंट को तथ्य (प्रोडक्ट डॉक्यूमेंटेशन, कंपनी नीतियाँ, आदि) खिलाते हैं और वह सवालों का जवाब देते समय प्रासंगिक तथ्यों को रिट्रीव करता है।
इसे RAG (Retrieval-Augmented Generation) कहते हैं: टेक्स्ट को dense vectors (embeddings) में बदल दिया जाता है जो अर्थ को ज्यामितीय स्पेस में मैप करते हैं, ताकि सेमांटिक रूप से मिलती-जुलती सामग्री एक-दूसरे के पास आ जाए।
लेकिन केवल vector search की कुछ सीमाएँ हैं; यह अर्थ को अच्छी तरह पकड़ता है पर ऑर्डर IDs या प्रोडक्ट कोड्स जैसे सटीक टर्म्स में संघर्ष करता है।
इसलिए यह POC Oracle के Hybrid Vector Indexes का उपयोग करता है, जो समानांतर में vector similarity search और keyword (lexical) search चलाते हैं, फिर दोनों परिणाम सूचियों को Reciprocal Rank Fusion (RRF) से फ्यूज़ करते हैं।
क्वेरी के समय, हाइब्रिड सर्च अर्थ या सटीक टर्म्स से मैच करते दस्तावेज़ ढूंढता है और शीर्ष परिणामों को LLM प्रॉम्प्ट में इंजेक्ट करता है। एम्बेडिंग्स Oracle में सीधे लोड किए गए ONNX मॉडल (all-MiniLM-L12-v2, 384 dimensions) द्वारा डेटाबेस के अंदर ही निकाली जाती हैं—किसी बाहरी एम्बेडिंग API कॉल की ज़रूरत नहीं। नीचे इस पर और विवरण है।
चित्र 3. डोमेन नॉलेज के रूप में semantic मेमोरी
Procedural मेमोरी: LLM टूल कॉलिंग
Procedural मेमोरी "कैसे" है—स्टेप-दर-स्टेप वर्कफ्लोज़ जो एजेंट निष्पादित करना जानता है। किसी ऑर्डर को देखना, रिटर्न शुरू करना, सपोर्ट तक एस्केलेट करना। Spring AI में, ये @Tool-एनोटेटेड मेथड्स होते हैं जिन्हें LLM तब कॉल कर सकता है जब उसे लगे कि कार्य केवल उत्तर नहीं, बल्कि कार्रवाई मांगता है।
चित्र 4. Procedural मेमोरी काम करते हुए—एजेंट टूल कॉल्स का उपयोग करके लाइव ऑर्डर डेटा क्वेरी करता है और कार्य-विशिष्ट परिणाम लौटाता है।
चित्र 5. AgentController के माध्यम से अनुरोध प्रवाह, जहाँ उत्तर बनाने से पहले Oracle AI Database टेबल्स से episodic, semantic और procedural मेमोरी को जोड़ा जाता है, फिर Ollama से प्रतिक्रिया जनरेट होती है।
दोनों टेबल एक ही Oracle Database में हैं। न Pinecone। न Redis। न दूसरा डेटाबेस। एक कनेक्शन पूल, एक क्रेडेंशियल सेट, एक ही चीज़ मॉनिटर करनी है।
Spring AI टूल्स लागू करना
Procedural मेमोरी को Spring कंपोनेंट में @Tool-एनोटेटेड मेथड्स के रूप में लागू किया गया है, जो असली डेटाबेस टेबल्स को क्वेरी करते हैं। यहाँ स्पष्टता के लिए दो प्रतिनिधि मेथड्स दिए हैं; पूरी क्लास में कुल छह टूल्स हैं (देखें AgentTools.java):
@Tool(description ="Look up the status of a customer order by its order ID. "+"Returns the current status including shipping information.")publicStringlookupOrderStatus(@ToolParam(description ="The order ID to look up, e.g. ORD-1001")String orderId){// Fetches order from DB via JPA, returns formatted status string}@Tool(description ="Initiate a product return for a given order. "+"Validates the order exists, checks that it is in DELIVERED status, "+"and verifies the return is within the 30-day return window.")publicStringinitiateReturn(@ToolParam(description ="The order ID to return")String orderId,@ToolParam(description ="The reason for the return")String reason){// Validates order exists, checks DELIVERED status and 30-day window, updates status via JPA}संचालित द्वारा
यहाँ @Tool का विवरण LLM को बताता है कि कब कौन-सा मेथड उपयोग करना है, और @ToolParam आर्ग्युमेंट्स का वर्णन करता है। जब उपयोगकर्ता कहता है "मैं ऑर्डर ORD-1001 रिटर्न करना चाहता/चाहती हूँ," तो LLM टूल विवरण पढ़ता है, तय करता है कि initiateReturn सही प्रक्रिया है, बातचीत से आर्ग्युमेंट्स निकालता है, मेथड कॉल करता है और परिणाम को अपने उत्तर में पिरो देता है।
बाकी चार टूल्स हैं getCurrentDateTime (डेटाबेस से करंट दिनांक/समय लाता है), listOrders, escalateToSupport, और listSupportTickets। ये सभी एक ही पैटर्न का पालन करते हैं: JPA या JDBC के जरिए डेटाबेस क्वेरीज़। LLM तय करता है कि कब कार्रवाई करनी है; Java मेथड्स परिभाषित करते हैं कि कैसे।
Spring Boot कंट्रोलर बनाना
कंट्रोलर सब कुछ जोड़ता है; दो advisors, छह टूल्स, एक ChatClient। इसका कोर हिस्सा, स्पष्टता के लिए सरल किया गया है (पूरा संस्करण इनपुट वैलिडेशन, एरर हैंडलिंग और बातचीत प्रबंधन endpoints जोड़ता है। देखें AgentController.java):
@RestController@RequestMapping("/api/v1/agent")publicclassAgentController{publicAgentController(ChatClient.Builder builder,JdbcChatMemoryRepository chatMemoryRepository,JdbcTemplate jdbcTemplate,AgentTools agentTools){// Builds a ChatClient with:// - MessageChatMemoryAdvisor (episodic: last 100 messages per conversation)// - RetrievalAugmentationAdvisor + OracleHybridDocumentRetriever (semantic: hybrid search)// - AgentTools via .defaultTools() (procedural: 6 @Tool methods)// - System prompt defining the agent persona and tool usage rules}@PostMapping("/chat")publicResponseEntity<String>chat(@RequestBodyString message,@RequestHeader("X-Conversation-Id")String conversationId){// Sends message to ChatClient with conversation ID, returns LLM response}@PostMapping("/knowledge")publicResponseEntity<String>addKnowledge(@RequestBodyString content){// Inserts text into POLICY_DOCS table via JDBC (hybrid index handles embedding)}}संचालित द्वारा
दो endpoints, दो advisors, छह टूल्स, एक ChatClient। आइए तीनों मेमोरी प्रकारों को तोड़कर देखें।
Spring Advisors के साथ चैट मेमोरी प्रबंधित करना
Spring AI का advisor पैटर्न ही वह जगह है जहाँ जादू होता है। Advisors हर LLM कॉल को इंटरसेप्ट करते हैं, आउटगोइंग प्रॉम्प्ट को संशोधित कर सकते हैं और लौटती प्रतिक्रिया को प्रोसेस कर सकते हैं।
MessageChatMemoryAdvisor episodic मेमोरी संभालता है। हर LLM कॉल से पहले, यह वर्तमान बातचीत के लिए SPRING_AI_CHAT_MEMORY टेबल से पिछली 100 संदेश लोड करता है और उन्हें प्रॉम्प्ट में prepend करता है। प्रतिक्रिया के बाद, यह नए एक्सचेंज को सेव करता है। बातचीत को X-Conversation-Id हेडर से पहचाना जाता है: अलग ID, अलग मेमोरी।
डॉक्यूमेंट रिट्रीवर्स के साथ RAG लागू करना
RetrievalAugmentationAdvisor semantic मेमोरी संभालता है। हर LLM कॉल से पहले, कस्टम OracleHybridDocumentRetrieverDBMS_HYBRID_VECTOR.SEARCH कॉल करता है, जो समानांतर में vector similarity search और Oracle Text कीवर्ड सर्च चलाता है और परिणामों को Reciprocal Rank Fusion (RRF) से फ्यूज़ करता है।
शीर्ष 5 मिलते-जुलते दस्तावेज़ों को एक कस्टम ContextualQueryAugmenter के जरिए संदर्भ के रूप में प्रॉम्प्ट में इंजेक्ट किया जाता है, जो दस्तावेज़ों को पूरक मानता है; LLM को निर्देश दिया जाता है कि वह इन्हें केवल नीति-संबंधी प्रश्नों के लिए उपयोग करे, कार्रवाई के अनुरोधों या वार्तालाप संदर्भ के लिए नहीं। इससे RAG संदर्भ चैट इतिहास को ओवरराइड नहीं करता या टूल कॉल्स को दबाता नहीं है।
हाइब्रिड क्यों, शुद्ध वेक्टर सर्च क्यों नहीं? Dense embeddings अर्थ को पकड़ते हैं: "return policy" पर क्वेरी, रिफंड और एक्सचेंज से जुड़ी नीतियों को मैच कर लेगी, भले वे सटीक शब्द न हों।
पर ये सटीक टर्म्स पर कमजोर हैं: "ORD-1001" के लिए क्वेरी बिगड़ सकती है क्योंकि एम्बेडिंग मॉडल सेमांटिक्स एन्कोड करता है, कीवर्ड्स नहीं। हाइब्रिड सर्च दोनों कवर करता है: वेक्टर साइड अर्थ संभालता है, कीवर्ड साइड सटीक मिलान संभालता है, और RRF असंगत स्कोर्स को नार्मलाइज़ करने के बजाय रैंक पोज़िशन से दोनों सूचियाँ मर्ज करता है।
एजेंट टूल्स रजिस्टर करना
AgentTools procedural मेमोरी संभालता है। .defaultTools(agentTools) कॉल कंपोनेंट के सभी छह @Tool-एनोटेटेड मेथड्स रजिस्टर करती है। हर अनुरोध पर, LLM को टूल विवरण उपयोगकर्ता के संदेश के साथ मिलते हैं। अगर कार्य केवल नॉलेज रिट्रीवल नहीं बल्कि कार्रवाई मांगता है, तो LLM उपयुक्त टूल कॉल करता है, परिणाम पाता है और उसे अपने उत्तर में जोड़ देता है। Spring AI टूल-कॉलिंग प्रोटोकॉल को स्वतः हैंडल करता है।
तीनों मेमोरी प्रकार हर अनुरोध पर साथ चलते हैं। एजेंट एक साथ आपकी कही बात याद रखता है, प्रासंगिक नॉलेज ढूंढता है, और कार्य करना जानता है।
चित्र 6 एंड-टू-एंड अनुरोध अनुक्रम, जहाँ चैट इतिहास, हाइब्रिड RAG संदर्भ, और वैकल्पिक टूल कॉल्स मिलकर अंतिम प्रतिक्रिया बनाते और उसे संरक्षित करते हैं।
RAG नॉलेज endpoint बनाना
/knowledge endpoint सरल है: कुछ टेक्स्ट POST करें, और वह JDBC के जरिए POLICY_DOCS टेबल में इन्सर्ट हो जाता है। हाइब्रिड वेक्टर इंडेक्स इन-डेटाबेस ONNX मॉडल का उपयोग करके एम्बेडिंग अपने आप संभाल लेता है—किसी बाहरी एम्बेडिंग API कॉल की ज़रूरत नहीं। अगली बार कोई संबंधित सवाल करेगा, तो हाइब्रिड सर्च उसे ढूंढ लेगा।
Oracle AI डेटाबेस को सीड करना
एक DataSeeder (Spring CommandLineRunner) स्टार्टअप पर डेटाबेस को 8 डेमो ऑर्डर्स और 12 नीति दस्तावेज़ों (रिटर्न, शिपिंग, सपोर्ट, वारंटी, पेमेंट, कैंसलेशन, एक्सचेंज, अंतरराष्ट्रीय शिपिंग, प्राइवेसी, प्रोमोशन्स, प्रोडक्ट गारंटी, और बल्क ऑर्डर नीतियाँ) से भर देता है। नीतियाँ policies.json रिसोर्स फ़ाइल से लोड होकर JDBC द्वारा POLICY_DOCS टेबल में डाली जाती हैं। ऑर्डर्स रिलेटिव डेट्स का उपयोग करते हैं ताकि 30-दिन रिटर्न विंडो लॉजिक डेमो के लिए हमेशा काम करे। सीडर मौजूदा काउंट्स जाँचता है ताकि रीस्टार्ट पर डुप्लिकेट न हों।
Semantic मेमोरी का अपग्रेड: हाइब्रिड सर्च
इस POC का पहला संस्करण Spring AI के QuestionAnswerAdvisor के साथ OracleVectorStore: शुद्ध वेक्टर similarity सर्च (cosine threshold) का उपयोग करता था। यह नीतियों पर साफ़-सुथरे, अच्छे से लिखे सवालों पर काम करता था। लेकिन सटीक टर्म्स और टाइपो पर यह बिखर जाता था। "order ORD-1001" की क्वेरी नीतिगत दस्तावेज़ों के साथ सेमांटिक मिलान करने की कोशिश करती, जिसका कोई मतलब नहीं। गलत लिखे "retrun polcy" पर similarity स्कोर गिर जाता क्योंकि एम्बेडिंग मॉडल को यह टाइपो पता नहीं।
Oracle हाइब्रिड वेक्टर इंडेक्स बनाना
Oracle 26ai DBMS_HYBRID_VECTOR.SEARCH देता है—एक PL/SQL कॉल जो समानांतर में वेक्टर similarity और Oracle Text कीवर्ड सर्च चलाता है, फिर परिणामों को फ्यूज़ करता है।
कुंजी है Reciprocal Rank Fusion (RRF): cosine similarity स्कोर्स (0-1) को BM25 कीवर्ड स्कोर्स (बिना बाउंड) के साथ नार्मलाइज़ करने की कोशिश करने के बजाय, यह दस्तावेज़ों को प्रत्येक परिणाम सूची में उनकी पोज़िशन के आधार पर रैंक करता है।
जो दस्तावेज़ वेक्टर परिणामों में #1 और कीवर्ड परिणामों में #3 है, उसे संयुक्त रैंक मिलता है जो दोनों संकेतों को दर्शाता है।
/SQL
-- Load the ONNX model for in-database embeddings
BEGIN
DBMS_VECTOR.LOAD_ONNX_MODEL(
directory => 'DM_DUMP',
file_name => 'all_MiniLM_L12_v2.onnx',
model_name => 'ALL_MINILM_L12_V2'
);
END;
/
-- Create a hybrid index: vector similarity + Oracle Text keyword search
CREATE HYBRID VECTOR INDEX POLICY_HYBRID_IDX
ON POLICY_DOCS(content)
PARAMETERS('MODEL ALL_MINILM_L12_V2 VECTOR_IDXTYPE HNSW');संचालित द्वारा
इंडेक्स बन जाने के बाद, पंक्तियाँ इन्सर्ट होते ही एम्बेडिंग अपने आप कंप्यूट हो जाती हैं — किसी बाहरी एम्बेडिंग API कॉल की ज़रूरत नहीं।
Spring AI रिट्रीवल इंटीग्रेशन
Spring AI का QuestionAnswerAdvisor केवल VectorStore.similaritySearch() रैप करता है, यानी शुद्ध वेक्टर सर्च—और कुछ नहीं। हाइब्रिड सर्च उपयोग करने के लिए, मैंने RetrievalAugmentationAdvisor पर स्विच किया, जो मॉड्यूलर विकल्प है: यह कस्टम DocumentRetriever और कस्टम QueryAugmenter स्वीकार करता है ताकि रिट्रीव्ड दस्तावेज़ों को प्रॉम्प्ट में कैसे इंजेक्ट किया जाए, उस पर नियंत्रण रहे।
कस्टम OracleHybridDocumentRetrieverDocumentRetriever को इम्प्लीमेंट करता है और JDBC के जरिए DBMS_HYBRID_VECTOR.SEARCH कॉल करता है, एक JSON पैरामीटर पास करते हुए जो हाइब्रिड इंडेक्स, स्कोरर (RRF), और कीवर्ड मैच बताता है:
publicList<Document>retrieve(Query query){// Builds a JSON spec with hybrid index name, RRF scorer, vector + text search clauses// Calls DBMS_HYBRID_VECTOR.SEARCH via JDBC, parses JSON results into List<Document>}संचालित द्वारा
यह रिट्रीवल के लिए OracleVectorStore को पूरी तरह बायपास करता है। text.contains क्लॉज़ सादा कीवर्ड OR मिलान (2 अक्षरों से लंबे शब्द) उपयोग करता है, और Oracle Text की बिल्ट-इन स्टेमिंग विविधताओं को संभालती है।
हाइब्रिड सर्च AI एजेंट्स को कैसे बेहतर बनाती है
एजेंट को अच्छे निर्णय लेने के लिए सटीक रिट्रीवल चाहिए। अगर semantic मेमोरी गलत या कम-विश्वास वाली नीति डॉक्यूमेंट्स लौटाती है, तो LLM टूल पैरामीटर्स गढ़ सकता है या वह टूल कॉल स्किप कर सकता है जो उसे करना चाहिए था।
हाइब्रिड सर्च का मतलब है उच्च-विश्वास संदर्भ, यानी बेहतर स्वायत्त निर्णय; जब अर्थ और सटीक टर्म्स दोनों मैच होते हैं, तो एजेंट के नीति गलत उद्धृत करने या प्रासंगिक दस्तावेज़ चूकने की संभावना कम होती है।
Spring AI के लिए डेटाबेस कॉन्फ़िगरेशन
कॉन्फ़िगरेशन एक ही application.yaml में है। प्रमुख डिज़ाइन निर्णय: Hibernate JPA टेबल्स खुद-ब-खुद बनाता है (ddl-auto: update), Spring AI चैट मेमोरी टेबल खुद बनाता है (initialize-schema: always), POLICY_DOCS टेबल और हाइब्रिड वेक्टर इंडेक्स एक बार चलने वाली SQL स्क्रिप्ट (setup-hybrid-search.sql) से बनते हैं, और Oracle UCP तीनों मेमोरी प्रकारों के लिए एक ही कनेक्शन पूल शेयर करता है।
न Flyway, न कस्टम @Configuration क्लासेस। Spring AI की ऑटो-कॉन्फ़िगरेशन Oracle JDBC ड्राइवर डिटेक्ट करके सब वायर कर देती है। पूरा application.yaml रेपो में देखें।
Streamlit वेब UI बनाना
Streamlit फ्रंटएंड संदेश बैकएंड को भेजता है और प्रतिक्रियाएँ रेंडर करता है। इसका कोर हिस्सा यहाँ है (पूरे ऐप में क्विक-स्टार्ट बटन और नई बातचीत का फ़ीचर शामिल है। देखें app.py):
defsend_message(prompt, url):# POSTs plain text to /api/v1/agent/chat with X-Conversation-Id header# Renders user message and assistant response in Streamlit chat UIif prompt := st.chat_input("Type a message..."):
send_message(prompt, backend_url)संचालित द्वारा
यह प्रत्येक सत्र के लिए बातचीत ID हेतु एक UUID जनरेट करता है, प्लेन टेक्स्ट बैकएंड को भेजता है, और प्रतिक्रिया रेंडर करता है। बस इतना ही।
AI एजेंट POC को लोकली चलाना
शॉर्ट वर्ज़न: एक Oracle DB कंटेनर शुरू करें, ONNX मॉडल लोड करें और हाइब्रिड इंडेक्स बनाएं (वन-टाइम सेटअप), Ollama इंस्टॉल करें और चैट मॉडल (qwen2.5) पुल करें, local प्रोफ़ाइल के साथ Spring Boot बैकएंड चलाएँ और चाहें तो Streamlit UI भी शुरू करें। एम्बेडिंग्स ONNX मॉडल द्वारा डेटाबेस के अंदर हैंडल होती हैं—किसी Ollama एम्बेडिंग मॉडल की ज़रूरत नहीं। पूरा सेटअप निर्देश e repo README में हैं।
curl से त्वरित परीक्षण:
curl-X POST http://localhost:8080/api/v1/agent/chat \-H"Content-Type: text/plain"\-H"X-Conversation-Id: test-1"\-d"What orders do I have?"संचालित द्वारा
निष्कर्ष
यह सेटअप Spring AI और Oracle Database के साथ वास्तविक एजेंट बनाने के लिए एक मज़बूत डिफ़ॉल्ट है क्योंकि यह सारी मेमोरी लेयर्स को एक ही ऑपरेशनल स्टैक में रखता है: episodic संदर्भ, semantic रिट्रीवल, और procedural एक्शंस। Spring AI साफ़ एब्स्ट्रैक्शंस देता है (Advisors + @Tool) ताकि एजेंट का व्यवहार पठनीय और टेस्टेबल रहे, जबकि Oracle एक ही सिस्टम में ट्रांज़ैक्शनल डेटा और हाइब्रिड रिट्रीवल संभालता है—इन-डेटाबेस एम्बेडिंग्स और RRF रैंकिंग के साथ, ताकि अर्थ और सटीक दोनों टर्म्स पर बेहतर प्रिसीजन मिले।
नतीजा व्यावहारिक है: कम चलती हिस्से, कम इंटीग्रेशन फेल्यर्स, कम लेटेंसी, और आसान प्रोडक्शन ऑपरेशंस। चैट इतिहास, वेक्टर सर्च, कीवर्ड सर्च और बिज़नेस टेबल्स के लिए अलग-अलग सिस्टम सिलने के बजाय, आप एक प्लेटफ़ॉर्म पर बनाते हैं और फिर भी उच्च-गुणवत्ता रिट्रीवल तथा भरोसेमंद टूल निष्पादन पाते हैं। एजेंट फीचर्स शिप करने वाली टीमों के लिए, सरलता, सटीकता और ऑपरेशनल नियंत्रण का यह संयोजन मुश्किल से मात खाता है।
एजेंट मेमोरी LLM-संचालित सिस्टम को अनुरोधों के बीच संदर्भ को संरक्षित करने देती है, ताकि वह पिछली बातचीत याद रख सके, डोमेन नॉलेज रिट्रीव कर सके, और वर्कफ्लोज़ को निरंतरता से निष्पादित कर सके।
Do I need a separate vector database for semantic memory?⌄
नहीं। इस ट्यूटोरियल में, Oracle AI Database एक ही सिस्टम में रिलेशनल डेटा, चैट इतिहास, और हाइब्रिड रिट्रीवल इंडेक्सेस स्टोर करता है।
What is the difference between episodic, semantic, and procedural memory? ⌄
Episodic मेमोरी बातचीत का इतिहास स्टोर करती है, semantic मेमोरी रिट्रीवेबल नॉलेज स्टोर करती है, और procedural मेमोरी टूल्स के जरिए executable एक्शंस परिभाषित करती है।
Why use hybrid retrieval instead of pure vector search?⌄
हाइब्रिड रिट्रीवल सेमांटिक अर्थ और सटीक कीवर्ड मैचिंग को मिलाता है, जिससे धुंधले सवालों और सटीक IDs/टर्म्स—दोनों के लिए बेहतर परिणाम मिलते हैं।
Is this architecture production-ready?⌄
यह एक मज़बूत आधार है, लेकिन प्रोडक्शन सेटअप्स में फिर भी ऑथेंटिकेशन, ऑथराइज़ेशन, ऑब्ज़र्वेबिलिटी और लोड टेस्टिंग की ज़रूरत होगी।
मैं स्केलेबल, क्लाउड-नेटिव सिस्टम बनाने में एक दशक से अधिक अनुभव वाला बैकएंड आर्किटेक्ट और टेक लीड हूं। मैं Java, Kotlin और आधुनिक क्लाउड प्लेटफ़ॉर्म का उपयोग करके वितरित आर्किटेक्चर में विशेषज्ञ हूं, और डोमेन-ड्रिवन डिज़ाइन, इवेंट-ड्रिवन सिस्टम, तथा व्यावहारिक सॉफ़्टवेयर डिज़ाइन पर केंद्रित रहता हूं।
मेरा काम मज़बूत बैकएंड प्लेटफ़ॉर्म डिज़ाइन करने और इंजीनियरिंग प्रथाओं में सुधार पर केंद्रित है, साथ ही बढ़ते तौर पर यह खोजने पर भी कि AI डेवलपर उत्पादकता और सिस्टम डिज़ाइन को कैसे बेहतर बना सकता है।
हर LLM की एक ही समस्या होती है: बातचीत खत्म होते ही वह सब कुछ भूल जाता है—कभी-कभी तो लंबी बातचीत के दौरान भी। आप बीस मिनट लगाकर अपना प्रोजेक्ट सेटअप, अपनी बाधाएँ और अपनी प्राथमिकताएँ समझाते हैं, और वह सटीक जवाब देता है। टैब बंद करें, नया सेशन खोलें, और वह आपको अनजाने की तरह अभिवादन करता है। सारा संदर्भ, गायब।
अगर आप एक AI एजेंट बनाना चाहते हैं—कुछ ऐसा जो सच में संदर्भ याद रखे और आपके डोमेन के बारे में चीज़ें जानता हो—तो आपको उसे मेमोरी देनी होगी। व्यावहारिक किस्म की, जहाँ वह वास्तव में आपकी कही बात याद रखे और आपके सिखाए तथ्यों को ढूंढ सके।
यह एक POC है जो मैंने ठीक यही करने के लिए बनाया। तीन तरह की मेमोरी, एक डेटाबेस, बहुत कम कोड। पूरा सोर्स कोड GitHub पर उपलब्ध है।
Spring AI के साथ AI एजेंट आर्किटेक्चर
चित्र 1. Spring AI और Oracle AI Database 26ai के साथ एंड-टू-एंड एजेंट मेमोरी आर्किटेक्चर
टेक स्टैक:
AI एजेंट मेमोरी के तीन प्रकार
एजेंट्स के लिए episodic, semantic, procedural और working मेमोरी की बात होती है।
Working मेमोरी बस LLM का context window है; वर्तमान अनुरोध के लिए सक्रिय "स्क्रैचपैड"। यह persisted नहीं होती, इसलिए यहाँ बनाने को कुछ नहीं है। मैंने बाकी तीन लागू किए हैं:
Episodic मेमोरी: चैट इतिहास को संरक्षित करना
Episodic मेमोरी चैट इतिहास है। एजेंट याद रखता है कि आपने बातचीत में पहले क्या कहा था। संदेश 1 पर "मेरा नाम Victor है" का मतलब संदेश 50 पर भी उसे आपका नाम पता है। इसे रिलेशनल टेबल में पंक्तियों के रूप में संग्रहीत किया जाता है।
चित्र 2. Episodic मेमोरी यानी चैट इतिहास
Semantic मेमोरी: RAG इंटीग्रेशन
Semantic मेमोरी डोमेन नॉलेज है। आप एजेंट को तथ्य (प्रोडक्ट डॉक्यूमेंटेशन, कंपनी नीतियाँ, आदि) खिलाते हैं और वह सवालों का जवाब देते समय प्रासंगिक तथ्यों को रिट्रीव करता है।
इसे RAG (Retrieval-Augmented Generation) कहते हैं: टेक्स्ट को dense vectors (embeddings) में बदल दिया जाता है जो अर्थ को ज्यामितीय स्पेस में मैप करते हैं, ताकि सेमांटिक रूप से मिलती-जुलती सामग्री एक-दूसरे के पास आ जाए।
लेकिन केवल vector search की कुछ सीमाएँ हैं; यह अर्थ को अच्छी तरह पकड़ता है पर ऑर्डर IDs या प्रोडक्ट कोड्स जैसे सटीक टर्म्स में संघर्ष करता है।
इसलिए यह POC Oracle के Hybrid Vector Indexes का उपयोग करता है, जो समानांतर में vector similarity search और keyword (lexical) search चलाते हैं, फिर दोनों परिणाम सूचियों को Reciprocal Rank Fusion (RRF) से फ्यूज़ करते हैं।
क्वेरी के समय, हाइब्रिड सर्च अर्थ या सटीक टर्म्स से मैच करते दस्तावेज़ ढूंढता है और शीर्ष परिणामों को LLM प्रॉम्प्ट में इंजेक्ट करता है। एम्बेडिंग्स Oracle में सीधे लोड किए गए ONNX मॉडल (all-MiniLM-L12-v2, 384 dimensions) द्वारा डेटाबेस के अंदर ही निकाली जाती हैं—किसी बाहरी एम्बेडिंग API कॉल की ज़रूरत नहीं। नीचे इस पर और विवरण है।
चित्र 3. डोमेन नॉलेज के रूप में semantic मेमोरी
Procedural मेमोरी: LLM टूल कॉलिंग
Procedural मेमोरी "कैसे" है—स्टेप-दर-स्टेप वर्कफ्लोज़ जो एजेंट निष्पादित करना जानता है। किसी ऑर्डर को देखना, रिटर्न शुरू करना, सपोर्ट तक एस्केलेट करना। Spring AI में, ये
@Tool-एनोटेटेड मेथड्स होते हैं जिन्हें LLM तब कॉल कर सकता है जब उसे लगे कि कार्य केवल उत्तर नहीं, बल्कि कार्रवाई मांगता है।चित्र 4. Procedural मेमोरी काम करते हुए—एजेंट टूल कॉल्स का उपयोग करके लाइव ऑर्डर डेटा क्वेरी करता है और कार्य-विशिष्ट परिणाम लौटाता है।
चित्र 5. AgentController के माध्यम से अनुरोध प्रवाह, जहाँ उत्तर बनाने से पहले Oracle AI Database टेबल्स से episodic, semantic और procedural मेमोरी को जोड़ा जाता है, फिर Ollama से प्रतिक्रिया जनरेट होती है।
दोनों टेबल एक ही Oracle Database में हैं। न Pinecone। न Redis। न दूसरा डेटाबेस। एक कनेक्शन पूल, एक क्रेडेंशियल सेट, एक ही चीज़ मॉनिटर करनी है।
Spring AI टूल्स लागू करना
Procedural मेमोरी को Spring कंपोनेंट में
@Tool-एनोटेटेड मेथड्स के रूप में लागू किया गया है, जो असली डेटाबेस टेबल्स को क्वेरी करते हैं। यहाँ स्पष्टता के लिए दो प्रतिनिधि मेथड्स दिए हैं; पूरी क्लास में कुल छह टूल्स हैं (देखें AgentTools.java):यहाँ
@Toolका विवरण LLM को बताता है कि कब कौन-सा मेथड उपयोग करना है, और@ToolParamआर्ग्युमेंट्स का वर्णन करता है। जब उपयोगकर्ता कहता है "मैं ऑर्डर ORD-1001 रिटर्न करना चाहता/चाहती हूँ," तो LLM टूल विवरण पढ़ता है, तय करता है किinitiateReturnसही प्रक्रिया है, बातचीत से आर्ग्युमेंट्स निकालता है, मेथड कॉल करता है और परिणाम को अपने उत्तर में पिरो देता है।बाकी चार टूल्स हैं
getCurrentDateTime(डेटाबेस से करंट दिनांक/समय लाता है),listOrders,escalateToSupport, औरlistSupportTickets। ये सभी एक ही पैटर्न का पालन करते हैं: JPA या JDBC के जरिए डेटाबेस क्वेरीज़। LLM तय करता है कि कब कार्रवाई करनी है; Java मेथड्स परिभाषित करते हैं कि कैसे।Spring Boot कंट्रोलर बनाना
कंट्रोलर सब कुछ जोड़ता है; दो advisors, छह टूल्स, एक
ChatClient। इसका कोर हिस्सा, स्पष्टता के लिए सरल किया गया है (पूरा संस्करण इनपुट वैलिडेशन, एरर हैंडलिंग और बातचीत प्रबंधन endpoints जोड़ता है। देखें AgentController.java):दो endpoints, दो advisors, छह टूल्स, एक
ChatClient। आइए तीनों मेमोरी प्रकारों को तोड़कर देखें।Spring Advisors के साथ चैट मेमोरी प्रबंधित करना
Spring AI का advisor पैटर्न ही वह जगह है जहाँ जादू होता है। Advisors हर LLM कॉल को इंटरसेप्ट करते हैं, आउटगोइंग प्रॉम्प्ट को संशोधित कर सकते हैं और लौटती प्रतिक्रिया को प्रोसेस कर सकते हैं।
MessageChatMemoryAdvisorepisodic मेमोरी संभालता है। हर LLM कॉल से पहले, यह वर्तमान बातचीत के लिएSPRING_AI_CHAT_MEMORYटेबल से पिछली 100 संदेश लोड करता है और उन्हें प्रॉम्प्ट में prepend करता है। प्रतिक्रिया के बाद, यह नए एक्सचेंज को सेव करता है। बातचीत कोX-Conversation-Idहेडर से पहचाना जाता है: अलग ID, अलग मेमोरी।डॉक्यूमेंट रिट्रीवर्स के साथ RAG लागू करना
RetrievalAugmentationAdvisorsemantic मेमोरी संभालता है। हर LLM कॉल से पहले, कस्टमOracleHybridDocumentRetrieverDBMS_HYBRID_VECTOR.SEARCH कॉल करता है, जो समानांतर में vector similarity search और Oracle Text कीवर्ड सर्च चलाता है और परिणामों को Reciprocal Rank Fusion (RRF) से फ्यूज़ करता है।शीर्ष 5 मिलते-जुलते दस्तावेज़ों को एक कस्टम
ContextualQueryAugmenterके जरिए संदर्भ के रूप में प्रॉम्प्ट में इंजेक्ट किया जाता है, जो दस्तावेज़ों को पूरक मानता है; LLM को निर्देश दिया जाता है कि वह इन्हें केवल नीति-संबंधी प्रश्नों के लिए उपयोग करे, कार्रवाई के अनुरोधों या वार्तालाप संदर्भ के लिए नहीं। इससे RAG संदर्भ चैट इतिहास को ओवरराइड नहीं करता या टूल कॉल्स को दबाता नहीं है।हाइब्रिड क्यों, शुद्ध वेक्टर सर्च क्यों नहीं? Dense embeddings अर्थ को पकड़ते हैं: "return policy" पर क्वेरी, रिफंड और एक्सचेंज से जुड़ी नीतियों को मैच कर लेगी, भले वे सटीक शब्द न हों।
पर ये सटीक टर्म्स पर कमजोर हैं: "ORD-1001" के लिए क्वेरी बिगड़ सकती है क्योंकि एम्बेडिंग मॉडल सेमांटिक्स एन्कोड करता है, कीवर्ड्स नहीं। हाइब्रिड सर्च दोनों कवर करता है: वेक्टर साइड अर्थ संभालता है, कीवर्ड साइड सटीक मिलान संभालता है, और RRF असंगत स्कोर्स को नार्मलाइज़ करने के बजाय रैंक पोज़िशन से दोनों सूचियाँ मर्ज करता है।
एजेंट टूल्स रजिस्टर करना
AgentToolsprocedural मेमोरी संभालता है।.defaultTools(agentTools)कॉल कंपोनेंट के सभी छह@Tool-एनोटेटेड मेथड्स रजिस्टर करती है। हर अनुरोध पर, LLM को टूल विवरण उपयोगकर्ता के संदेश के साथ मिलते हैं। अगर कार्य केवल नॉलेज रिट्रीवल नहीं बल्कि कार्रवाई मांगता है, तो LLM उपयुक्त टूल कॉल करता है, परिणाम पाता है और उसे अपने उत्तर में जोड़ देता है। Spring AI टूल-कॉलिंग प्रोटोकॉल को स्वतः हैंडल करता है।तीनों मेमोरी प्रकार हर अनुरोध पर साथ चलते हैं। एजेंट एक साथ आपकी कही बात याद रखता है, प्रासंगिक नॉलेज ढूंढता है, और कार्य करना जानता है।
चित्र 6 एंड-टू-एंड अनुरोध अनुक्रम, जहाँ चैट इतिहास, हाइब्रिड RAG संदर्भ, और वैकल्पिक टूल कॉल्स मिलकर अंतिम प्रतिक्रिया बनाते और उसे संरक्षित करते हैं।
RAG नॉलेज endpoint बनाना
/knowledgeendpoint सरल है: कुछ टेक्स्ट POST करें, और वह JDBC के जरिएPOLICY_DOCSटेबल में इन्सर्ट हो जाता है। हाइब्रिड वेक्टर इंडेक्स इन-डेटाबेस ONNX मॉडल का उपयोग करके एम्बेडिंग अपने आप संभाल लेता है—किसी बाहरी एम्बेडिंग API कॉल की ज़रूरत नहीं। अगली बार कोई संबंधित सवाल करेगा, तो हाइब्रिड सर्च उसे ढूंढ लेगा।Oracle AI डेटाबेस को सीड करना
एक
DataSeeder(SpringCommandLineRunner) स्टार्टअप पर डेटाबेस को 8 डेमो ऑर्डर्स और 12 नीति दस्तावेज़ों (रिटर्न, शिपिंग, सपोर्ट, वारंटी, पेमेंट, कैंसलेशन, एक्सचेंज, अंतरराष्ट्रीय शिपिंग, प्राइवेसी, प्रोमोशन्स, प्रोडक्ट गारंटी, और बल्क ऑर्डर नीतियाँ) से भर देता है। नीतियाँpolicies.jsonरिसोर्स फ़ाइल से लोड होकर JDBC द्वाराPOLICY_DOCSटेबल में डाली जाती हैं। ऑर्डर्स रिलेटिव डेट्स का उपयोग करते हैं ताकि 30-दिन रिटर्न विंडो लॉजिक डेमो के लिए हमेशा काम करे। सीडर मौजूदा काउंट्स जाँचता है ताकि रीस्टार्ट पर डुप्लिकेट न हों।Semantic मेमोरी का अपग्रेड: हाइब्रिड सर्च
इस POC का पहला संस्करण Spring AI के QuestionAnswerAdvisor के साथ OracleVectorStore: शुद्ध वेक्टर similarity सर्च (cosine threshold) का उपयोग करता था। यह नीतियों पर साफ़-सुथरे, अच्छे से लिखे सवालों पर काम करता था। लेकिन सटीक टर्म्स और टाइपो पर यह बिखर जाता था। "order ORD-1001" की क्वेरी नीतिगत दस्तावेज़ों के साथ सेमांटिक मिलान करने की कोशिश करती, जिसका कोई मतलब नहीं। गलत लिखे "retrun polcy" पर similarity स्कोर गिर जाता क्योंकि एम्बेडिंग मॉडल को यह टाइपो पता नहीं।
Oracle हाइब्रिड वेक्टर इंडेक्स बनाना
Oracle 26ai DBMS_HYBRID_VECTOR.SEARCH देता है—एक PL/SQL कॉल जो समानांतर में वेक्टर similarity और Oracle Text कीवर्ड सर्च चलाता है, फिर परिणामों को फ्यूज़ करता है।
कुंजी है Reciprocal Rank Fusion (RRF): cosine similarity स्कोर्स (0-1) को BM25 कीवर्ड स्कोर्स (बिना बाउंड) के साथ नार्मलाइज़ करने की कोशिश करने के बजाय, यह दस्तावेज़ों को प्रत्येक परिणाम सूची में उनकी पोज़िशन के आधार पर रैंक करता है।
जो दस्तावेज़ वेक्टर परिणामों में #1 और कीवर्ड परिणामों में #3 है, उसे संयुक्त रैंक मिलता है जो दोनों संकेतों को दर्शाता है।
सेटअप एक बार चलने वाली SQL स्क्रिप्ट है जो ONNX एम्बेडिंग मॉडल Oracle AI Database में लोड करती है और एक हाइब्रिड इंडेक्स बनाती है:
इंडेक्स बन जाने के बाद, पंक्तियाँ इन्सर्ट होते ही एम्बेडिंग अपने आप कंप्यूट हो जाती हैं — किसी बाहरी एम्बेडिंग API कॉल की ज़रूरत नहीं।
Spring AI रिट्रीवल इंटीग्रेशन
Spring AI का QuestionAnswerAdvisor केवल
VectorStore.similaritySearch()रैप करता है, यानी शुद्ध वेक्टर सर्च—और कुछ नहीं। हाइब्रिड सर्च उपयोग करने के लिए, मैंने RetrievalAugmentationAdvisor पर स्विच किया, जो मॉड्यूलर विकल्प है: यह कस्टम DocumentRetriever और कस्टमQueryAugmenterस्वीकार करता है ताकि रिट्रीव्ड दस्तावेज़ों को प्रॉम्प्ट में कैसे इंजेक्ट किया जाए, उस पर नियंत्रण रहे।कस्टम
OracleHybridDocumentRetrieverDocumentRetrieverको इम्प्लीमेंट करता है और JDBC के जरिएDBMS_HYBRID_VECTOR.SEARCHकॉल करता है, एक JSON पैरामीटर पास करते हुए जो हाइब्रिड इंडेक्स, स्कोरर (RRF), और कीवर्ड मैच बताता है:यह रिट्रीवल के लिए
OracleVectorStoreको पूरी तरह बायपास करता है।text.containsक्लॉज़ सादा कीवर्डORमिलान (2 अक्षरों से लंबे शब्द) उपयोग करता है, और Oracle Text की बिल्ट-इन स्टेमिंग विविधताओं को संभालती है।हाइब्रिड सर्च AI एजेंट्स को कैसे बेहतर बनाती है
एजेंट को अच्छे निर्णय लेने के लिए सटीक रिट्रीवल चाहिए। अगर semantic मेमोरी गलत या कम-विश्वास वाली नीति डॉक्यूमेंट्स लौटाती है, तो LLM टूल पैरामीटर्स गढ़ सकता है या वह टूल कॉल स्किप कर सकता है जो उसे करना चाहिए था।
हाइब्रिड सर्च का मतलब है उच्च-विश्वास संदर्भ, यानी बेहतर स्वायत्त निर्णय; जब अर्थ और सटीक टर्म्स दोनों मैच होते हैं, तो एजेंट के नीति गलत उद्धृत करने या प्रासंगिक दस्तावेज़ चूकने की संभावना कम होती है।
Spring AI के लिए डेटाबेस कॉन्फ़िगरेशन
कॉन्फ़िगरेशन एक ही application.yaml में है। प्रमुख डिज़ाइन निर्णय: Hibernate JPA टेबल्स खुद-ब-खुद बनाता है (ddl-auto: update), Spring AI चैट मेमोरी टेबल खुद बनाता है (initialize-schema: always), POLICY_DOCS टेबल और हाइब्रिड वेक्टर इंडेक्स एक बार चलने वाली SQL स्क्रिप्ट (setup-hybrid-search.sql) से बनते हैं, और Oracle UCP तीनों मेमोरी प्रकारों के लिए एक ही कनेक्शन पूल शेयर करता है।
न Flyway, न कस्टम
@Configurationक्लासेस। Spring AI की ऑटो-कॉन्फ़िगरेशन Oracle JDBC ड्राइवर डिटेक्ट करके सब वायर कर देती है। पूरा application.yaml रेपो में देखें।Streamlit वेब UI बनाना
Streamlit फ्रंटएंड संदेश बैकएंड को भेजता है और प्रतिक्रियाएँ रेंडर करता है। इसका कोर हिस्सा यहाँ है (पूरे ऐप में क्विक-स्टार्ट बटन और नई बातचीत का फ़ीचर शामिल है। देखें app.py):
यह प्रत्येक सत्र के लिए बातचीत ID हेतु एक UUID जनरेट करता है, प्लेन टेक्स्ट बैकएंड को भेजता है, और प्रतिक्रिया रेंडर करता है। बस इतना ही।
AI एजेंट POC को लोकली चलाना
शॉर्ट वर्ज़न: एक Oracle DB कंटेनर शुरू करें, ONNX मॉडल लोड करें और हाइब्रिड इंडेक्स बनाएं (वन-टाइम सेटअप), Ollama इंस्टॉल करें और चैट मॉडल (qwen2.5) पुल करें, local प्रोफ़ाइल के साथ Spring Boot बैकएंड चलाएँ और चाहें तो Streamlit UI भी शुरू करें। एम्बेडिंग्स ONNX मॉडल द्वारा डेटाबेस के अंदर हैंडल होती हैं—किसी Ollama एम्बेडिंग मॉडल की ज़रूरत नहीं। पूरा सेटअप निर्देश e repo README में हैं।
curl से त्वरित परीक्षण:
निष्कर्ष
यह सेटअप Spring AI और Oracle Database के साथ वास्तविक एजेंट बनाने के लिए एक मज़बूत डिफ़ॉल्ट है क्योंकि यह सारी मेमोरी लेयर्स को एक ही ऑपरेशनल स्टैक में रखता है: episodic संदर्भ, semantic रिट्रीवल, और procedural एक्शंस। Spring AI साफ़ एब्स्ट्रैक्शंस देता है (Advisors +
@Tool) ताकि एजेंट का व्यवहार पठनीय और टेस्टेबल रहे, जबकि Oracle एक ही सिस्टम में ट्रांज़ैक्शनल डेटा और हाइब्रिड रिट्रीवल संभालता है—इन-डेटाबेस एम्बेडिंग्स और RRF रैंकिंग के साथ, ताकि अर्थ और सटीक दोनों टर्म्स पर बेहतर प्रिसीजन मिले।नतीजा व्यावहारिक है: कम चलती हिस्से, कम इंटीग्रेशन फेल्यर्स, कम लेटेंसी, और आसान प्रोडक्शन ऑपरेशंस। चैट इतिहास, वेक्टर सर्च, कीवर्ड सर्च और बिज़नेस टेबल्स के लिए अलग-अलग सिस्टम सिलने के बजाय, आप एक प्लेटफ़ॉर्म पर बनाते हैं और फिर भी उच्च-गुणवत्ता रिट्रीवल तथा भरोसेमंद टूल निष्पादन पाते हैं। एजेंट फीचर्स शिप करने वाली टीमों के लिए, सरलता, सटीकता और ऑपरेशनल नियंत्रण का यह संयोजन मुश्किल से मात खाता है।
AI एजेंट्स और उनके काम करने के तरीके के बारे में अधिक जानने के लिए, DataCamp का AI Agent Fundamentals स्किल ट्रैक देखें।