Generative Feedback Loop is a technique where we save LLM-generated responses back into the vector database. However, sometimes there is no relevant information in our knowledge base, and the LLM generates irrelevant information that can lead to completely different outcomes.
To address this, we modified the technique by improving the generated answer manually before saving it back into the vector database. This helps chatbots and RAG (Retrieval-Augmented Generation) systems stay up to date and provide accurate and relevant information.
- Whenever a chatbot gives an irrelevant response, we modify that response and save that improved answer back in our vector database.
- The next time a similar question is asked, the chatbot should pull the most recently added response from the vector database and give a better answer.
- This process not only improves how the chatbot responds but also we can directly add new questions in our vector database.
The Problem We Faced
In one of our previous projects, our assistant was generating responses based on irrelevant information and providing incorrect details and numbers from the LLM's knowledge. Additionally, this information was not present in our vector database. As a result, we needed two things:
First, a way to directly add missing information into our vector database, and second, a method to improve the responses generated by the chatbot when it was providing false information.
How We Solved It
We implemented a way to allow users to improve the answer whenever the assistant generates incorrect information.
User Interface for Editing Response
Users can edit the generated answer and submit the corrected version.
Edited Answer Submission
We then take the improved answer and save it back into the vector database.
Saving to Vector Database
We ensured that only the most recent and relevant data was used by adding a Unix timestamp to the dataset, which helped us track the latest version of the information. We used this process to make sure that the chatbot always had the most current and accurate answers.
We have also developed a direct method for adding missing information. In this system, the user can directly add both the question and answer into the vector database.
How It Works
Chunking the text, embedding them, and adding them into Pinecone to save.
const chunks = await chunkText(text) // Making chunks
const embeddings = await createEmbeddings(chunks) // Creating Embeddings
await uploadToVectorDB(chunks, embeddings, index) // Saving into Vector DatabaseComplete Implementation
import { NextRequest, NextResponse } from 'next/server'
import { OpenAI } from 'openai'
import { Pinecone } from '@pinecone-database/pinecone'
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
const pinecone = new Pinecone({ apiKey: process.env.PINECONE_API_KEY })
// Function to chunk text into smaller pieces
async function chunkText(text: string, chunkSize: number = 500): Promise<string[]> {
const words = text.split(' ')
const chunks: string[] = []
for (let i = 0; i < words.length; i += chunkSize) {
chunks.push(words.slice(i, i + chunkSize).join(' '))
}
return chunks
}
// Function to create embeddings for chunks
async function createEmbeddings(chunks: string[]): Promise<number[][]> {
const embeddings: number[][] = []
for (const chunk of chunks) {
const response = await openai.embeddings.create({
model: 'text-embedding-ada-002',
input: chunk,
})
embeddings.push(response.data[0].embedding)
}
return embeddings
}
// Function to upload chunks and embeddings to Pinecone
async function uploadToVectorDB(
chunks: string[],
embeddings: number[][],
index: any
): Promise<void> {
const vectors = chunks.map((chunk, i) => ({
id: `doc_${Date.now()}_${i}`,
values: embeddings[i],
metadata: {
text: chunk,
timestamp: Date.now(),
},
}))
await index.upsert(vectors)
}
// Main API route handler
export async function POST(req: NextRequest) {
try {
const { question, answer } = await req.json()
const text = `Question: ${question}
Answer: ${answer}`
const index = pinecone.index(process.env.PINECONE_INDEX_NAME!)
// Process and upload the improved answer
const chunks = await chunkText(text)
const embeddings = await createEmbeddings(chunks)
await uploadToVectorDB(chunks, embeddings, index)
return NextResponse.json({ success: true, message: 'Answer improved and saved' })
} catch (error) {
console.error('Error saving improved answer:', error)
return NextResponse.json({ success: false, error: 'Failed to save answer' }, { status: 500 })
}
}Results
By modifying the Generative Feedback Loop, we were able to improve the chatbot's responses and add the missing information directly in our vector database.
Generative Feedback Loop Demo
Conclusion
Overall, this approach gives us more control over how the chatbot learns and adapts, while also ensuring that our knowledge base remains accurate, up-to-date, and comprehensive.
