From 48508de636eeb23d419e3af09eef8f16e8720658 Mon Sep 17 00:00:00 2001 From: eafif Date: Thu, 2 Jan 2025 08:39:00 -0500 Subject: [PATCH 1/2] move duplicate logic into method --- lib/langchain/vectorsearch/base.rb | 17 +++++++++++++++++ lib/langchain/vectorsearch/chroma.rb | 10 +--------- lib/langchain/vectorsearch/elasticsearch.rb | 10 ++-------- lib/langchain/vectorsearch/epsilla.rb | 9 +-------- lib/langchain/vectorsearch/milvus.rb | 12 ++---------- lib/langchain/vectorsearch/pgvector.rb | 9 +-------- lib/langchain/vectorsearch/pinecone.rb | 9 +-------- lib/langchain/vectorsearch/qdrant.rb | 9 +-------- lib/langchain/vectorsearch/weaviate.rb | 9 +-------- 9 files changed, 27 insertions(+), 67 deletions(-) diff --git a/lib/langchain/vectorsearch/base.rb b/lib/langchain/vectorsearch/base.rb index f58199a63..69bebcd50 100644 --- a/lib/langchain/vectorsearch/base.rb +++ b/lib/langchain/vectorsearch/base.rb @@ -168,6 +168,23 @@ def generate_hyde_prompt(question:) prompt_template.format(question: question) end + # Ask a question and return the answer + # @param question [String] The question to ask + # @param context [Array] The context generated by RAG + # @yield [String] Stream responses back one String at a time + # @return [String] The answer to the question + def generate_messages_and_chat(question: , context: , &block) + context = context.join("\n---\n") + + prompt = generate_rag_prompt(question: question, context: context) + + messages = [{role: "user", content: prompt}] + response = llm.chat(messages: messages, &block) + + response.context = context + response + end + # Retrieval Augmented Generation (RAG) # # @param question [String] User's question diff --git a/lib/langchain/vectorsearch/chroma.rb b/lib/langchain/vectorsearch/chroma.rb index abd3f585b..8aa390c0c 100644 --- a/lib/langchain/vectorsearch/chroma.rb +++ b/lib/langchain/vectorsearch/chroma.rb @@ -132,15 +132,7 @@ def ask(question:, k: 4, &block) result.document end - context = context.join("\n---\n") - - prompt = generate_rag_prompt(question: question, context: context) - - messages = [{role: "user", content: prompt}] - response = llm.chat(messages: messages, &block) - - response.context = context - response + generate_messages_and_chat(question: question, context: context, &block) end private diff --git a/lib/langchain/vectorsearch/elasticsearch.rb b/lib/langchain/vectorsearch/elasticsearch.rb index f9f5401bd..0b33947e1 100644 --- a/lib/langchain/vectorsearch/elasticsearch.rb +++ b/lib/langchain/vectorsearch/elasticsearch.rb @@ -148,15 +148,9 @@ def ask(question:, k: 4, &block) context = search_results.map do |result| result[:input] - end.join("\n---\n") - - prompt = generate_rag_prompt(question: question, context: context) - - messages = [{role: "user", content: prompt}] - response = llm.chat(messages: messages, &block) + end - response.context = context - response + generate_messages_and_chat(question: question, context: context, &block) end # Search for similar texts diff --git a/lib/langchain/vectorsearch/epsilla.rb b/lib/langchain/vectorsearch/epsilla.rb index a0b2857cc..01572a969 100644 --- a/lib/langchain/vectorsearch/epsilla.rb +++ b/lib/langchain/vectorsearch/epsilla.rb @@ -133,15 +133,8 @@ def ask(question:, k: 4, &block) context = search_results.map do |result| result.to_s end - context = context.join("\n---\n") - prompt = generate_rag_prompt(question: question, context: context) - - messages = [{role: "user", content: prompt}] - response = llm.chat(messages: messages, &block) - - response.context = context - response + generate_messages_and_chat(question: question, context: context, &block) end end end diff --git a/lib/langchain/vectorsearch/milvus.rb b/lib/langchain/vectorsearch/milvus.rb index a575085ff..e604c4fe7 100644 --- a/lib/langchain/vectorsearch/milvus.rb +++ b/lib/langchain/vectorsearch/milvus.rb @@ -144,17 +144,9 @@ def similarity_search_by_vector(embedding:, k: 4) def ask(question:, k: 4, &block) search_results = similarity_search(query: question, k: k) - content_data = search_results.dig("data").map { |result| result.dig("content") } + context = search_results.dig("data").map { |result| result.dig("content") } - context = content_data.join("\n---\n") - - prompt = generate_rag_prompt(question: question, context: context) - - messages = [{role: "user", content: prompt}] - response = llm.chat(messages: messages, &block) - - response.context = context - response + generate_messages_and_chat(question: question, context: context, &block) end end end diff --git a/lib/langchain/vectorsearch/pgvector.rb b/lib/langchain/vectorsearch/pgvector.rb index de29224cc..0e860caec 100644 --- a/lib/langchain/vectorsearch/pgvector.rb +++ b/lib/langchain/vectorsearch/pgvector.rb @@ -152,15 +152,8 @@ def ask(question:, k: 4, &block) context = search_results.map do |result| result.content.to_s end - context = context.join("\n---\n") - prompt = generate_rag_prompt(question: question, context: context) - - messages = [{role: "user", content: prompt}] - response = llm.chat(messages: messages, &block) - - response.context = context - response + generate_messages_and_chat(question: question, context: context, &block) end end end diff --git a/lib/langchain/vectorsearch/pinecone.rb b/lib/langchain/vectorsearch/pinecone.rb index 6cbec2569..7ce9866bd 100644 --- a/lib/langchain/vectorsearch/pinecone.rb +++ b/lib/langchain/vectorsearch/pinecone.rb @@ -177,15 +177,8 @@ def ask(question:, namespace: "", filter: nil, k: 4, &block) context = search_results.map do |result| result.dig("metadata").to_s end - context = context.join("\n---\n") - prompt = generate_rag_prompt(question: question, context: context) - - messages = [{role: "user", content: prompt}] - response = llm.chat(messages: messages, &block) - - response.context = context - response + generate_messages_and_chat(question: question, context: context, &block) end # Pinecone index diff --git a/lib/langchain/vectorsearch/qdrant.rb b/lib/langchain/vectorsearch/qdrant.rb index ade772f8a..886f73369 100644 --- a/lib/langchain/vectorsearch/qdrant.rb +++ b/lib/langchain/vectorsearch/qdrant.rb @@ -144,15 +144,8 @@ def ask(question:, k: 4, &block) context = search_results.map do |result| result.dig("payload").to_s end - context = context.join("\n---\n") - prompt = generate_rag_prompt(question: question, context: context) - - messages = [{role: "user", content: prompt}] - response = llm.chat(messages: messages, &block) - - response.context = context - response + generate_messages_and_chat(question: question, context: context, &block) end end end diff --git a/lib/langchain/vectorsearch/weaviate.rb b/lib/langchain/vectorsearch/weaviate.rb index 53440f04d..251468faa 100644 --- a/lib/langchain/vectorsearch/weaviate.rb +++ b/lib/langchain/vectorsearch/weaviate.rb @@ -150,15 +150,8 @@ def ask(question:, k: 4, &block) context = search_results.map do |result| result.dig("content").to_s end - context = context.join("\n---\n") - prompt = generate_rag_prompt(question: question, context: context) - - messages = [{role: "user", content: prompt}] - response = llm.chat(messages: messages, &block) - - response.context = context - response + generate_messages_and_chat(question: question, context: context, &block) end private From 6131c0edda45d045db42197a0e852a7731619069 Mon Sep 17 00:00:00 2001 From: eafif Date: Thu, 2 Jan 2025 09:09:39 -0500 Subject: [PATCH 2/2] allow passing of system prompt --- lib/langchain/vectorsearch/base.rb | 8 ++++++-- lib/langchain/vectorsearch/chroma.rb | 5 +++-- lib/langchain/vectorsearch/elasticsearch.rb | 5 +++-- lib/langchain/vectorsearch/epsilla.rb | 5 +++-- lib/langchain/vectorsearch/milvus.rb | 5 +++-- lib/langchain/vectorsearch/pgvector.rb | 5 +++-- lib/langchain/vectorsearch/pinecone.rb | 5 +++-- lib/langchain/vectorsearch/qdrant.rb | 5 +++-- lib/langchain/vectorsearch/weaviate.rb | 5 +++-- spec/langchain/vectorsearch/chroma_spec.rb | 12 ++++++++++++ .../langchain/vectorsearch/elasticsearch_spec.rb | 12 ++++++++++++ spec/langchain/vectorsearch/epsilla_spec.rb | 12 ++++++++++++ spec/langchain/vectorsearch/milvus_spec.rb | 12 ++++++++++++ spec/langchain/vectorsearch/pgvector_spec.rb | 11 +++++++++++ spec/langchain/vectorsearch/pinecone_spec.rb | 16 ++++++++++++++++ spec/langchain/vectorsearch/qdrant_spec.rb | 12 ++++++++++++ spec/langchain/vectorsearch/weaviate_spec.rb | 12 ++++++++++++ 17 files changed, 129 insertions(+), 18 deletions(-) diff --git a/lib/langchain/vectorsearch/base.rb b/lib/langchain/vectorsearch/base.rb index 69bebcd50..5cc054e38 100644 --- a/lib/langchain/vectorsearch/base.rb +++ b/lib/langchain/vectorsearch/base.rb @@ -171,14 +171,18 @@ def generate_hyde_prompt(question:) # Ask a question and return the answer # @param question [String] The question to ask # @param context [Array] The context generated by RAG + # @param system_prompt [String] Content of the prompt to send as "system" # @yield [String] Stream responses back one String at a time # @return [String] The answer to the question - def generate_messages_and_chat(question: , context: , &block) + def generate_messages_and_chat(question: , context: , system_prompt: nil, &block) context = context.join("\n---\n") prompt = generate_rag_prompt(question: question, context: context) - messages = [{role: "user", content: prompt}] + messages = [ + system_prompt ? {role: 'system', content: system_prompt} : nil, + {role: "user", content: prompt} + ].compact response = llm.chat(messages: messages, &block) response.context = context diff --git a/lib/langchain/vectorsearch/chroma.rb b/lib/langchain/vectorsearch/chroma.rb index 8aa390c0c..afc6c538f 100644 --- a/lib/langchain/vectorsearch/chroma.rb +++ b/lib/langchain/vectorsearch/chroma.rb @@ -123,16 +123,17 @@ def similarity_search_by_vector( # Ask a question and return the answer # @param question [String] The question to ask # @param k [Integer] The number of results to have in context + # @param system_prompt [String] Content of the prompt to send as "system" # @yield [String] Stream responses back one String at a time # @return [String] The answer to the question - def ask(question:, k: 4, &block) + def ask(question:, k: 4, system_prompt: nil, &block) search_results = similarity_search(query: question, k: k) context = search_results.map do |result| result.document end - generate_messages_and_chat(question: question, context: context, &block) + generate_messages_and_chat(question: question, context: context, system_prompt: system_prompt, &block) end private diff --git a/lib/langchain/vectorsearch/elasticsearch.rb b/lib/langchain/vectorsearch/elasticsearch.rb index 0b33947e1..19b6501ba 100644 --- a/lib/langchain/vectorsearch/elasticsearch.rb +++ b/lib/langchain/vectorsearch/elasticsearch.rb @@ -141,16 +141,17 @@ def default_query(query_vector) # Ask a question and return the answer # @param question [String] The question to ask # @param k [Integer] The number of results to have in context + # @param system_prompt [String] Content of the prompt to send as "system" # @yield [String] Stream responses back one String at a time # @return [String] The answer to the question - def ask(question:, k: 4, &block) + def ask(question:, k: 4, system_prompt: nil, &block) search_results = similarity_search(query: question, k: k) context = search_results.map do |result| result[:input] end - generate_messages_and_chat(question: question, context: context, &block) + generate_messages_and_chat(question: question, context: context, system_prompt: system_prompt, &block) end # Search for similar texts diff --git a/lib/langchain/vectorsearch/epsilla.rb b/lib/langchain/vectorsearch/epsilla.rb index 01572a969..3b91916bf 100644 --- a/lib/langchain/vectorsearch/epsilla.rb +++ b/lib/langchain/vectorsearch/epsilla.rb @@ -125,16 +125,17 @@ def similarity_search_by_vector(embedding:, k: 4) # Ask a question and return the answer # @param question [String] The question to ask # @param k [Integer] The number of results to have in context + # @param system_prompt [String] Content of the prompt to send as "system" # @yield [String] Stream responses back one String at a time # @return [String] The answer to the question - def ask(question:, k: 4, &block) + def ask(question:, k: 4, system_prompt: nil, &block) search_results = similarity_search(query: question, k: k) context = search_results.map do |result| result.to_s end - generate_messages_and_chat(question: question, context: context, &block) + generate_messages_and_chat(question: question, context: context, system_prompt: system_prompt, &block) end end end diff --git a/lib/langchain/vectorsearch/milvus.rb b/lib/langchain/vectorsearch/milvus.rb index e604c4fe7..f5d1131de 100644 --- a/lib/langchain/vectorsearch/milvus.rb +++ b/lib/langchain/vectorsearch/milvus.rb @@ -139,14 +139,15 @@ def similarity_search_by_vector(embedding:, k: 4) # Ask a question and return the answer # @param question [String] The question to ask # @param k [Integer] The number of results to have in context + # @param system_prompt [String] Content of the prompt to send as "system" # @yield [String] Stream responses back one String at a time # @return [String] The answer to the question - def ask(question:, k: 4, &block) + def ask(question:, k: 4, system_prompt: nil, &block) search_results = similarity_search(query: question, k: k) context = search_results.dig("data").map { |result| result.dig("content") } - generate_messages_and_chat(question: question, context: context, &block) + generate_messages_and_chat(question: question, context: context, system_prompt: system_prompt, &block) end end end diff --git a/lib/langchain/vectorsearch/pgvector.rb b/lib/langchain/vectorsearch/pgvector.rb index 0e860caec..122286aec 100644 --- a/lib/langchain/vectorsearch/pgvector.rb +++ b/lib/langchain/vectorsearch/pgvector.rb @@ -144,16 +144,17 @@ def similarity_search_by_vector(embedding:, k: 4) # Ask a question and return the answer # @param question [String] The question to ask # @param k [Integer] The number of results to have in context + # @param system_prompt [String] Content of the prompt to send as "system" # @yield [String] Stream responses back one String at a time # @return [String] The answer to the question - def ask(question:, k: 4, &block) + def ask(question:, k: 4, system_prompt: nil, &block) search_results = similarity_search(query: question, k: k) context = search_results.map do |result| result.content.to_s end - generate_messages_and_chat(question: question, context: context, &block) + generate_messages_and_chat(question: question, context: context, system_prompt: system_prompt, &block) end end end diff --git a/lib/langchain/vectorsearch/pinecone.rb b/lib/langchain/vectorsearch/pinecone.rb index 7ce9866bd..67b1d4b8d 100644 --- a/lib/langchain/vectorsearch/pinecone.rb +++ b/lib/langchain/vectorsearch/pinecone.rb @@ -168,17 +168,18 @@ def similarity_search_by_vector(embedding:, k: 4, namespace: "", filter: nil) # @param question [String] The question to ask # @param namespace [String] The namespace to search in # @param k [Integer] The number of results to have in context + # @param system_prompt [String] Content of the prompt to send as "system" # @param filter [String] The filter to use # @yield [String] Stream responses back one String at a time # @return [String] The answer to the question - def ask(question:, namespace: "", filter: nil, k: 4, &block) + def ask(question:, namespace: "", filter: nil, k: 4, system_prompt: nil, &block) search_results = similarity_search(query: question, namespace: namespace, filter: filter, k: k) context = search_results.map do |result| result.dig("metadata").to_s end - generate_messages_and_chat(question: question, context: context, &block) + generate_messages_and_chat(question: question, context: context, system_prompt: system_prompt, &block) end # Pinecone index diff --git a/lib/langchain/vectorsearch/qdrant.rb b/lib/langchain/vectorsearch/qdrant.rb index 886f73369..8e1ba228b 100644 --- a/lib/langchain/vectorsearch/qdrant.rb +++ b/lib/langchain/vectorsearch/qdrant.rb @@ -136,16 +136,17 @@ def similarity_search_by_vector( # Ask a question and return the answer # @param question [String] The question to ask # @param k [Integer] The number of results to have in context + # @param system_prompt [String] Content of the prompt to send as "system" # @yield [String] Stream responses back one String at a time # @return [String] The answer to the question - def ask(question:, k: 4, &block) + def ask(question:, k: 4, system_prompt: nil, &block) search_results = similarity_search(query: question, k: k) context = search_results.map do |result| result.dig("payload").to_s end - generate_messages_and_chat(question: question, context: context, &block) + generate_messages_and_chat(question: question, context: context, system_prompt: system_prompt, &block) end end end diff --git a/lib/langchain/vectorsearch/weaviate.rb b/lib/langchain/vectorsearch/weaviate.rb index 251468faa..6e8e3f363 100644 --- a/lib/langchain/vectorsearch/weaviate.rb +++ b/lib/langchain/vectorsearch/weaviate.rb @@ -142,16 +142,17 @@ def similarity_search_by_vector(embedding:, k: 4) # Ask a question and return the answer # @param question [String] The question to ask # @param k [Integer] The number of results to have in context + # @param system_prompt [String] Content of the prompt to send as "system" # @yield [String] Stream responses back one String at a time # @return [Hash] The answer - def ask(question:, k: 4, &block) + def ask(question:, k: 4, system_prompt: nil, &block) search_results = similarity_search(query: question, k: k) context = search_results.map do |result| result.dig("content").to_s end - generate_messages_and_chat(question: question, context: context, &block) + generate_messages_and_chat(question: question, context: context, system_prompt: system_prompt, &block) end private diff --git a/spec/langchain/vectorsearch/chroma_spec.rb b/spec/langchain/vectorsearch/chroma_spec.rb index 6f6dbe681..eb21c1832 100644 --- a/spec/langchain/vectorsearch/chroma_spec.rb +++ b/spec/langchain/vectorsearch/chroma_spec.rb @@ -166,6 +166,18 @@ end end + context 'with system prompt' do + let(:system_prompt) { 'You are a helpful assistant' } + before do + allow(subject.llm).to receive(:chat).with(messages: [{role: 'system', content: system_prompt}, *messages]).and_return(response) + expect(response).to receive(:context=).with(text) + end + + it "asks a question and returns the answer" do + expect(subject.ask(question: question, system_prompt: system_prompt).completion).to eq(answer) + end + end + context "with block" do let(:block) { proc { |chunk| puts "Received chunk: #{chunk}" } } diff --git a/spec/langchain/vectorsearch/elasticsearch_spec.rb b/spec/langchain/vectorsearch/elasticsearch_spec.rb index 72a753239..13b13137d 100644 --- a/spec/langchain/vectorsearch/elasticsearch_spec.rb +++ b/spec/langchain/vectorsearch/elasticsearch_spec.rb @@ -274,6 +274,18 @@ end end + context 'with system prompt' do + let(:system_prompt) { 'You are a helpful assistant' } + before do + allow(subject.llm).to receive(:chat).with(messages: [{role: 'system', content: system_prompt}, *messages]).and_return(response) + expect(response).to receive(:context=).with(text) + end + + it "asks a question and returns the answer" do + expect(subject.ask(question: question, k: 4, system_prompt: system_prompt).completion).to eq(answer) + end + end + context "with block" do let(:block) { proc { |chunk| puts "Received chunk: #{chunk}" } } diff --git a/spec/langchain/vectorsearch/epsilla_spec.rb b/spec/langchain/vectorsearch/epsilla_spec.rb index f02b1f88a..9348fcf15 100644 --- a/spec/langchain/vectorsearch/epsilla_spec.rb +++ b/spec/langchain/vectorsearch/epsilla_spec.rb @@ -236,6 +236,18 @@ end end + context 'with system prompt' do + let(:system_prompt) { 'You are a helpful assistant' } + before do + allow(subject.llm).to receive(:chat).with(messages: [{role: 'system', content: system_prompt}, *messages]).and_return(response) + expect(response).to receive(:context=).with(text) + end + + it "asks a question and returns the answer" do + expect(subject.ask(question: question, k: k, system_prompt: system_prompt).completion).to eq(answer) + end + end + context "with block" do let(:block) { proc { |chunk| puts "Received chunk: #{chunk}" } } diff --git a/spec/langchain/vectorsearch/milvus_spec.rb b/spec/langchain/vectorsearch/milvus_spec.rb index 0713930d5..9fd78a501 100644 --- a/spec/langchain/vectorsearch/milvus_spec.rb +++ b/spec/langchain/vectorsearch/milvus_spec.rb @@ -141,6 +141,18 @@ end end + context 'with system prompt' do + let(:system_prompt) { 'You are a helpful assistant' } + before do + allow(subject.llm).to receive(:chat).with(messages: [{role: 'system', content: system_prompt}, *messages]).and_return(response) + expect(response).to receive(:context=).with(text) + end + + it "asks a question and returns the answer" do + expect(subject.ask(question: question, system_prompt: system_prompt).completion).to eq(answer) + end + end + context "with block" do let(:block) { proc { |chunk| puts "Received chunk: #{chunk}" } } diff --git a/spec/langchain/vectorsearch/pgvector_spec.rb b/spec/langchain/vectorsearch/pgvector_spec.rb index 5b3d6a725..9237538e8 100644 --- a/spec/langchain/vectorsearch/pgvector_spec.rb +++ b/spec/langchain/vectorsearch/pgvector_spec.rb @@ -234,6 +234,17 @@ end end + context 'with system prompt' do + before do + allow(subject.llm).to receive(:chat).with(messages: messages).and_return(response) + expect(response).to receive(:context=).with(text) + end + + it "asks a question and returns the answer" do + expect(subject.ask(question: question, k: k, system_prompt: 'You are a helpful assistant').completion).to eq(answer) + end + end + context "with block" do let(:block) { proc { |chunk| puts "Received chunk: #{chunk}" } } diff --git a/spec/langchain/vectorsearch/pinecone_spec.rb b/spec/langchain/vectorsearch/pinecone_spec.rb index 4ef45205b..9f17d578c 100644 --- a/spec/langchain/vectorsearch/pinecone_spec.rb +++ b/spec/langchain/vectorsearch/pinecone_spec.rb @@ -410,6 +410,22 @@ end end + describe "with system prompt" do + let(:system_prompt) { 'You are a helpful assistant' } + + before do + allow(subject).to receive(:similarity_search).with( + query: question, namespace: "", filter: nil, k: k + ).and_return(matches) + allow(subject.llm).to receive(:chat).with(messages: [{role: 'system', content: system_prompt}, *messages]).and_return(response) + expect(response).to receive(:context=).with(metadata.to_s) + end + + it "asks a question" do + expect(subject.ask(question: question, system_prompt: system_prompt).completion).to eq(answer) + end + end + describe "with block" do let(:block) { proc { |chunk| puts "Received chunk: #{chunk}" } } diff --git a/spec/langchain/vectorsearch/qdrant_spec.rb b/spec/langchain/vectorsearch/qdrant_spec.rb index 68e25965d..737632e9a 100644 --- a/spec/langchain/vectorsearch/qdrant_spec.rb +++ b/spec/langchain/vectorsearch/qdrant_spec.rb @@ -157,6 +157,18 @@ end end + context 'with system prompt' do + let(:system_prompt) { 'You are a helpful assistant' } + before do + allow(subject.llm).to receive(:chat).with(messages: [{role: 'system', content: system_prompt}, *messages]).and_return(response) + expect(response).to receive(:context=).with(text) + end + + it "asks a question and returns the answer" do + expect(subject.ask(question: question, k: k, system_prompt: system_prompt).completion).to eq(answer) + end + end + context "with block" do let(:block) { proc { |chunk| puts "Received chunk: #{chunk}" } } diff --git a/spec/langchain/vectorsearch/weaviate_spec.rb b/spec/langchain/vectorsearch/weaviate_spec.rb index c09a74fb7..0467f0f4b 100644 --- a/spec/langchain/vectorsearch/weaviate_spec.rb +++ b/spec/langchain/vectorsearch/weaviate_spec.rb @@ -214,6 +214,18 @@ def stub(id) end end + context 'with system prompt' do + let(:system_prompt) { 'You are a helpful assistant' } + before do + allow(subject.llm).to receive(:chat).with(messages: [{role: 'system', content: system_prompt}, *messages]).and_return(response) + expect(response).to receive(:context=).with(matches[0]["content"]) + end + + it "asks a question and returns the answer" do + expect(subject.ask(question: question, k: k, system_prompt: system_prompt).completion).to eq(answer) + end + end + context "with block" do let(:block) { proc { |chunk| puts "Received chunk: #{chunk}" } }