Skip to main content Scroll Top

Evolving the Advisor Interface in Our Spring AI Application

In the journey of developing our first Generative AI-powered application, we faced numerous challenges that pushed us to evolve our approach significantly. Central to this evolution was the development of our AI Advisor Interface, which began as a simple extension of the RequestResponseAdvisor.

How it began?

Initial Concept And Challenges

Our AI Advisor was created to encapsulate the AI prompt/logic into single advisor to be called from service and that seamed like great idea. At the beginning it was!

Simple class extending RequestResponseAdvisor, with one dedicated prompt, for system message, was instructing our AI to be polite and concise with its answers to user prompt. As advertised, it chained perfectly with already available SimpleLoggerAdvisor, so, so far so good. Of course, to get some extra value from it, we needed the AI to be aware about some articles, so we could chat about them.

However, as the complexity of user interactions increased, particularly with the need to integrate knowledge from various articles, it became evident that our simple advisor needed enhancement.

You probably guess, we started reading about RAGs and how we can use them to achieve what we want.

Transition to VectorStoreDataAdvisor

After investigation, we transitioned to using Neo4j as our vector database. We decided for Neo4j because in the future we can use to build our own knowledge graph and make our simple RAG much smarter. This shift allowed us to store article content, metadata, and embeddings more effectively, turning our advisor into the VectorStoreDataAdvisor. Simple request building now included fetch data from vector store using embeddings and similarity search, incorporating those articles into String template containing information what is context, what is user question and how to answer if needed data is not present in provided context.

This new form was not just a name change but a fundamental expansion in capability, incorporating advanced data fetching from the vector store based on embeddings and similarity searches. The system could now contextualize the information around the user’s questions and provide more accurate responses.

Enhancements

As we started with some more intensive testing, we found out that our AI app is still having problem with both finding proper articles, as well as giving proper response.

We initially thought our prompt engineering skills were on a coffee break slightly smiling face, endlessly. So, we buckled down to craft a better prompt template, but no matter how hard we tried, the issues stuck around like a stubborn software bug refusing to be debugged.

Getting back to drawing board, we decided to take look into Advanced RAG principles in order to improve our search accuracy both in Vector Store and later on when sending context with the question to LLM.
In there we sound different approaches we could use to make this work. Two most promising are Pre-Retrieval and Post-Retrieval, so we started with Pre-Retrieval and Query Transformation.

In order to understand how we should approach the issue we played a bit with similarity search via our chatbot.
Using ‘Vice President Kamala Haris’ (and ‘Kamala Harris’) with date picker example, we realize that similarity search is far from full text search and if syntagm is present in the text, this doesn’t mean it will be found by the similarity search at all. As we don’t know how the embeddings are generated, chatbot was our source of truth. By playing with topK and similarityThreshold options we realized that in such cases we shouldn’t go with similarity search beyond 0.7. With 0.5 especially 0.3, we got results not containing any of words contained in the phrase ‘Kamala Harris’! What we think could increase search accuracy and data relevance inside the data store, is possible improvement on the ingestion as well as on the retrieval side (using co-reference resolution or summarization during ingestion and full text search in addition to similarity search).

During our testing, incorporating timeframes into queries did not yield any useful results. To address this, we decided to adopt a Rewrite-Retrieve-Read approach in the Pre-Retrieval and Query Transformation phase. This involves improving the queries itself and enabling the detection and understanding of timeframes.

enabling the detection and understanding of timeframes

Initially, our model lacked awareness of real-world context. For example, when asked about the current date, it responded with:

  • “I’m sorry, but I can’t provide real-time information such as today’s date. However, you can easily check the date on your device or calendar.”
    or
  • Today’s date is November 1, 2023.

Disappointing… How we overcame it is explained in When Code Gets Creative: The Birth of Our First AI Agentic Workflow

This functionality is being implemented using an AI-driven approach, leveraging smaller, chained calls to a large language model (LLM), before reaching out and retrieve from VectorStore.

Result… worked as a miracle, … we gained both improvements in performance for fetch phase (actually for whole flow even thought we had one more AI call) as well as accuracy of retrieve step.

With those results in mind, we started thinking, “what more can we do to help main AI call” and results were multiple with most prominent being:

  • ask AI to extract only semantically relevant parts of user question for actual vector database search;
  • generate n additional variations of user question and run search for all of them;
  • add one more data source (open search) to support also full text search option.

We started working on each of those, re-running our tests after we implemented any such change ensuring that every new feature not only meets but exceeds our expectations.

Optimizing AI Interactions

Our VectorStoreDataAdvisor soon got support for optimization of search request for search. By leveraging AI, we’ve honed our ability to dissect user questions, extracting only the essential elements. This distilled input is then used to generate multiple query variations, enriching the database queries and, by extension, the AI’s responses.

Growing in Capability and Complexity

Each new feature has expanded the advisor’s capabilities, enhancing the quality of context it provides. However, these improvements also increased the complexity of the system. While each adjustment proved effective in some scenarios, they often required tailored solutions, making our progress as case-dependent as it was innovative.

Navigating Challenges with Re-Ranking and Decision Making

Faced with a multitude of potential enhancements, our team tackled the challenge of use case identification. How could we ensure the AI consistently delivers the best outcomes without succumbing to pitfalls? Initially, we explored letting the AI autonomously determine the appropriate use case. However, the unique nature of our application made this approach impractical.

Instead, we turned to a custom re-ranking strategy. By processing and grading results from various sources, we could confidently utilize only the highest quality data for further interactions. We decided to execute all available processes, gather results from every possible source, and then evaluate and compare these outcomes. This approach ensured that we only utilized the top-ranked results for further AI interactions. Developing a custom re-ranking solution was our answer to streamlining this process. Testing this solution proved to be a formidable challenge, primarily due to uncertainties about how to effectively rank results, particularly for specific scenarios. However, through a meticulous process of trial and error—adjusting each part, tweaking every formula, and fine-tuning weights—we achieved a re-ranking solution that met our rigorous standards of satisfaction.

The Advisor was now equipped with advanced capabilities including preprocessing user queries, extracting structured data, expanding semantically relevant parts of queries, fetching data from multiple sources, and re-ranking this information before constructing the context.

The Quest for Optimal Structure

The Quest for Optimal Structure

 

Despite these advances, the growing complexity of our advisor posed a new challenge: maintaining clean code and good programming practices. With most of the logic tightly packed into a single agent class, we began considering a modular, chain-based approach to simplify management and enhance scalability.

🅆🄾🅄🄻🄳 🄸🅃 🄱🄴 🄱🄴🅃🅃🄴🅁 🄸🄵 🅆🄴 🅆🄴🄽🅃 🅆🄸🅃🄷 🄰 🄲🄷🄰🄸🄽 🄰🄿🄿🅁🄾🄰🄲🄷?

 

 

 

 

Looking Forward

As we continue to refine our VectorStoreDataAdvisor, we remain committed to pushing the boundaries of what our AI can achieve. The path hasn’t always been straightforward, but with each challenge comes greater insight and a clearer direction for future enhancements.

Stay tuned to our blog for more updates on our AI development journey and the innovative solutions we’re exploring at TN-Tech.

Related Posts
Clear Filters
The Art of Chunking: A Personal Journey Through Our RAG System Development

In our quest to enhance AI-driven content interactions at TN-Tech, we’ve encountered numerous challenges, none more pivotal than the concept of “chunking” in our RAG (Retrieval-Augmented Generation) system.

Leveraging Generative AI for Enhanced News Article Interaction

In the rapidly evolving landscape of artificial intelligence, integrating Generative AI into business applications presents a unique set of challenges and opportunities. Our latest project dives deep into this integration, transforming how users interact with news articles by leveraging cutting-edge AI technologies.

Let us meet to discuss how we can contribute to your goals.