langchainrb 0.6.17 → 0.6.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +18 -3
- data/lib/langchain/active_record/hooks.rb +14 -0
- data/lib/langchain/agent/react_agent.rb +1 -1
- data/lib/langchain/agent/sql_query_agent.rb +2 -2
- data/lib/langchain/chunk.rb +16 -0
- data/lib/langchain/chunker/base.rb +4 -0
- data/lib/langchain/chunker/recursive_text.rb +5 -2
- data/lib/langchain/chunker/semantic.rb +4 -1
- data/lib/langchain/chunker/sentence.rb +4 -2
- data/lib/langchain/chunker/text.rb +5 -2
- data/lib/langchain/conversation.rb +1 -1
- data/lib/langchain/llm/ai21.rb +4 -3
- data/lib/langchain/llm/anthropic.rb +3 -3
- data/lib/langchain/llm/cohere.rb +6 -5
- data/lib/langchain/llm/google_palm.rb +14 -10
- data/lib/langchain/llm/hugging_face.rb +4 -3
- data/lib/langchain/llm/llama_cpp.rb +1 -1
- data/lib/langchain/llm/ollama.rb +18 -6
- data/lib/langchain/llm/openai.rb +7 -6
- data/lib/langchain/llm/replicate.rb +6 -10
- data/lib/langchain/llm/response/ai21_response.rb +13 -0
- data/lib/langchain/llm/response/anthropic_response.rb +29 -0
- data/lib/langchain/llm/response/base_response.rb +79 -0
- data/lib/langchain/llm/response/cohere_response.rb +21 -0
- data/lib/langchain/llm/response/google_palm_response.rb +36 -0
- data/lib/langchain/llm/response/hugging_face_response.rb +13 -0
- data/lib/langchain/llm/response/ollama_response.rb +26 -0
- data/lib/langchain/llm/response/openai_response.rb +51 -0
- data/lib/langchain/llm/response/replicate_response.rb +28 -0
- data/lib/langchain/vectorsearch/base.rb +4 -7
- data/lib/langchain/vectorsearch/chroma.rb +13 -12
- data/lib/langchain/vectorsearch/elasticsearch.rb +147 -0
- data/lib/langchain/vectorsearch/hnswlib.rb +5 -5
- data/lib/langchain/vectorsearch/milvus.rb +5 -4
- data/lib/langchain/vectorsearch/pgvector.rb +12 -6
- data/lib/langchain/vectorsearch/pinecone.rb +14 -13
- data/lib/langchain/vectorsearch/qdrant.rb +9 -8
- data/lib/langchain/vectorsearch/weaviate.rb +9 -8
- data/lib/langchain/version.rb +1 -1
- data/lib/langchain.rb +5 -0
- metadata +27 -2
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Langchain::LLM
|
4
|
+
class AnthropicResponse < BaseResponse
|
5
|
+
def model
|
6
|
+
raw_response.dig("model")
|
7
|
+
end
|
8
|
+
|
9
|
+
def completion
|
10
|
+
completions.first
|
11
|
+
end
|
12
|
+
|
13
|
+
def completions
|
14
|
+
[raw_response.dig("completion")]
|
15
|
+
end
|
16
|
+
|
17
|
+
def stop_reason
|
18
|
+
raw_response.dig("stop_reason")
|
19
|
+
end
|
20
|
+
|
21
|
+
def stop
|
22
|
+
raw_response.dig("stop")
|
23
|
+
end
|
24
|
+
|
25
|
+
def log_id
|
26
|
+
raw_response.dig("log_id")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Langchain
|
4
|
+
module LLM
|
5
|
+
class BaseResponse
|
6
|
+
attr_reader :raw_response, :model
|
7
|
+
|
8
|
+
def initialize(raw_response, model: nil)
|
9
|
+
@raw_response = raw_response
|
10
|
+
@model = model
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns the completion text
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
#
|
17
|
+
def completion
|
18
|
+
raise NotImplementedError
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the chat completion text
|
22
|
+
#
|
23
|
+
# @return [String]
|
24
|
+
#
|
25
|
+
def chat_completion
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
|
29
|
+
# Return the first embedding
|
30
|
+
#
|
31
|
+
# @return [Array<Float>]
|
32
|
+
def embedding
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return the completion candidates
|
37
|
+
#
|
38
|
+
# @return [Array]
|
39
|
+
def completions
|
40
|
+
raise NotImplementedError
|
41
|
+
end
|
42
|
+
|
43
|
+
# Return the chat completion candidates
|
44
|
+
#
|
45
|
+
# @return [Array]
|
46
|
+
def chat_completions
|
47
|
+
raise NotImplementedError
|
48
|
+
end
|
49
|
+
|
50
|
+
# Return the embeddings
|
51
|
+
#
|
52
|
+
# @return [Array<Array>]
|
53
|
+
def embeddings
|
54
|
+
raise NotImplementedError
|
55
|
+
end
|
56
|
+
|
57
|
+
# Number of tokens utilized in the prompt
|
58
|
+
#
|
59
|
+
# @return [Integer]
|
60
|
+
def prompt_tokens
|
61
|
+
raise NotImplementedError
|
62
|
+
end
|
63
|
+
|
64
|
+
# Number of tokens utilized to generate the completion
|
65
|
+
#
|
66
|
+
# @return [Integer]
|
67
|
+
def completion_tokens
|
68
|
+
raise NotImplementedError
|
69
|
+
end
|
70
|
+
|
71
|
+
# Total number of tokens utilized
|
72
|
+
#
|
73
|
+
# @return [Integer]
|
74
|
+
def total_tokens
|
75
|
+
raise NotImplementedError
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Langchain::LLM
|
4
|
+
class CohereResponse < BaseResponse
|
5
|
+
def embedding
|
6
|
+
embeddings.first
|
7
|
+
end
|
8
|
+
|
9
|
+
def embeddings
|
10
|
+
raw_response.dig("embeddings")
|
11
|
+
end
|
12
|
+
|
13
|
+
def completions
|
14
|
+
raw_response.dig("generations")
|
15
|
+
end
|
16
|
+
|
17
|
+
def completion
|
18
|
+
completions&.dig(0, "text")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Langchain::LLM
|
4
|
+
class GooglePalmResponse < BaseResponse
|
5
|
+
attr_reader :prompt_tokens
|
6
|
+
|
7
|
+
def initialize(raw_response, model: nil, prompt_tokens: nil)
|
8
|
+
@prompt_tokens = prompt_tokens
|
9
|
+
super(raw_response, model: model)
|
10
|
+
end
|
11
|
+
|
12
|
+
def completion
|
13
|
+
completions&.dig(0, "output")
|
14
|
+
end
|
15
|
+
|
16
|
+
def embedding
|
17
|
+
embeddings.first
|
18
|
+
end
|
19
|
+
|
20
|
+
def completions
|
21
|
+
raw_response.dig("candidates")
|
22
|
+
end
|
23
|
+
|
24
|
+
def chat_completion
|
25
|
+
chat_completions&.dig(0, "content")
|
26
|
+
end
|
27
|
+
|
28
|
+
def chat_completions
|
29
|
+
raw_response.dig("candidates")
|
30
|
+
end
|
31
|
+
|
32
|
+
def embeddings
|
33
|
+
[raw_response.dig("embedding", "value")]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Langchain::LLM
|
4
|
+
class OllamaResponse < BaseResponse
|
5
|
+
def initialize(raw_response, model: nil, prompt_tokens: nil)
|
6
|
+
@prompt_tokens = prompt_tokens
|
7
|
+
super(raw_response, model: model)
|
8
|
+
end
|
9
|
+
|
10
|
+
def completion
|
11
|
+
raw_response.first
|
12
|
+
end
|
13
|
+
|
14
|
+
def completions
|
15
|
+
raw_response.is_a?(String) ? [raw_response] : []
|
16
|
+
end
|
17
|
+
|
18
|
+
def embedding
|
19
|
+
embeddings.first
|
20
|
+
end
|
21
|
+
|
22
|
+
def embeddings
|
23
|
+
[raw_response&.dig("embedding")]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Langchain::LLM
|
4
|
+
class OpenAIResponse < BaseResponse
|
5
|
+
def model
|
6
|
+
raw_response["model"]
|
7
|
+
end
|
8
|
+
|
9
|
+
def created_at
|
10
|
+
if raw_response.dig("created")
|
11
|
+
Time.at(raw_response.dig("created"))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def completion
|
16
|
+
completions&.dig(0, "message", "content")
|
17
|
+
end
|
18
|
+
|
19
|
+
def chat_completion
|
20
|
+
completion
|
21
|
+
end
|
22
|
+
|
23
|
+
def embedding
|
24
|
+
embeddings&.first
|
25
|
+
end
|
26
|
+
|
27
|
+
def completions
|
28
|
+
raw_response.dig("choices")
|
29
|
+
end
|
30
|
+
|
31
|
+
def chat_completions
|
32
|
+
raw_response.dig("choices")
|
33
|
+
end
|
34
|
+
|
35
|
+
def embeddings
|
36
|
+
raw_response.dig("data")&.map { |datum| datum.dig("embedding") }
|
37
|
+
end
|
38
|
+
|
39
|
+
def prompt_tokens
|
40
|
+
raw_response.dig("usage", "prompt_tokens")
|
41
|
+
end
|
42
|
+
|
43
|
+
def completion_tokens
|
44
|
+
raw_response.dig("usage", "completion_tokens")
|
45
|
+
end
|
46
|
+
|
47
|
+
def total_tokens
|
48
|
+
raw_response.dig("usage", "total_tokens")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Langchain::LLM
|
4
|
+
class ReplicateResponse < BaseResponse
|
5
|
+
def completions
|
6
|
+
# Response comes back as an array of strings, e.g.: ["Hi", "how ", "are ", "you?"]
|
7
|
+
# The first array element is missing a space at the end, so we add it manually
|
8
|
+
raw_response.output[0] += " "
|
9
|
+
[raw_response.output.join]
|
10
|
+
end
|
11
|
+
|
12
|
+
def completion
|
13
|
+
completions.first
|
14
|
+
end
|
15
|
+
|
16
|
+
def created_at
|
17
|
+
Time.parse(raw_response.created_at)
|
18
|
+
end
|
19
|
+
|
20
|
+
def embedding
|
21
|
+
embeddings.first
|
22
|
+
end
|
23
|
+
|
24
|
+
def embeddings
|
25
|
+
[raw_response.output]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "forwardable"
|
4
|
-
|
5
3
|
module Langchain::Vectorsearch
|
6
4
|
# = Vector Databases
|
7
5
|
# A vector database a type of database that stores data as high-dimensional vectors, which are mathematical representations of features or attributes. Each vector has a certain number of dimensions, which can range from tens to thousands, depending on the complexity and granularity of the data.
|
@@ -9,11 +7,13 @@ module Langchain::Vectorsearch
|
|
9
7
|
# == Available vector databases
|
10
8
|
#
|
11
9
|
# - {Langchain::Vectorsearch::Chroma}
|
10
|
+
# - {Langchain::Vectorsearch::Elasticsearch}
|
11
|
+
# - {Langchain::Vectorsearch::Hnswlib}
|
12
12
|
# - {Langchain::Vectorsearch::Milvus}
|
13
|
+
# - {Langchain::Vectorsearch::Pgvector}
|
13
14
|
# - {Langchain::Vectorsearch::Pinecone}
|
14
15
|
# - {Langchain::Vectorsearch::Qdrant}
|
15
16
|
# - {Langchain::Vectorsearch::Weaviate}
|
16
|
-
# - {Langchain::Vectorsearch::Pgvector}
|
17
17
|
#
|
18
18
|
# == Usage
|
19
19
|
#
|
@@ -150,9 +150,6 @@ module Langchain::Vectorsearch
|
|
150
150
|
raise NotImplementedError, "#{self.class.name} does not support asking questions"
|
151
151
|
end
|
152
152
|
|
153
|
-
def_delegators :llm,
|
154
|
-
:default_dimension
|
155
|
-
|
156
153
|
# HyDE-style prompt
|
157
154
|
#
|
158
155
|
# @param [String] User's question
|
@@ -184,7 +181,7 @@ module Langchain::Vectorsearch
|
|
184
181
|
.flatten
|
185
182
|
.map do |path|
|
186
183
|
data = Langchain::Loader.new(path)&.load&.chunks
|
187
|
-
data.map { |chunk| chunk
|
184
|
+
data.map { |chunk| chunk.text }
|
188
185
|
end
|
189
186
|
|
190
187
|
texts.flatten!
|
@@ -5,7 +5,8 @@ module Langchain::Vectorsearch
|
|
5
5
|
#
|
6
6
|
# Wrapper around Chroma DB
|
7
7
|
#
|
8
|
-
# Gem requirements:
|
8
|
+
# Gem requirements:
|
9
|
+
# gem "chroma-db", "~> 0.6.0"
|
9
10
|
#
|
10
11
|
# Usage:
|
11
12
|
# chroma = Langchain::Vectorsearch::Chroma.new(url:, index_name:, llm:, llm_api_key:, api_key: nil)
|
@@ -28,15 +29,16 @@ module Langchain::Vectorsearch
|
|
28
29
|
end
|
29
30
|
|
30
31
|
# Add a list of texts to the index
|
31
|
-
# @param texts [Array] The list of texts to add
|
32
|
+
# @param texts [Array<String>] The list of texts to add
|
33
|
+
# @param ids [Array<String>] The list of ids to use for the texts (optional)
|
34
|
+
# @param metadatas [Array<Hash>] The list of metadata to use for the texts (optional)
|
32
35
|
# @return [Hash] The response from the server
|
33
|
-
def add_texts(texts:, ids: [])
|
36
|
+
def add_texts(texts:, ids: [], metadatas: [])
|
34
37
|
embeddings = Array(texts).map.with_index do |text, i|
|
35
38
|
::Chroma::Resources::Embedding.new(
|
36
39
|
id: ids[i] ? ids[i].to_s : SecureRandom.uuid,
|
37
|
-
embedding: llm.embed(text: text),
|
38
|
-
|
39
|
-
metadata: {}, # metadatas[index],
|
40
|
+
embedding: llm.embed(text: text).embedding,
|
41
|
+
metadata: metadatas[i] || {},
|
40
42
|
document: text # Do we actually need to store the whole original document?
|
41
43
|
)
|
42
44
|
end
|
@@ -45,13 +47,12 @@ module Langchain::Vectorsearch
|
|
45
47
|
collection.add(embeddings)
|
46
48
|
end
|
47
49
|
|
48
|
-
def update_texts(texts:, ids:)
|
50
|
+
def update_texts(texts:, ids:, metadatas: [])
|
49
51
|
embeddings = Array(texts).map.with_index do |text, i|
|
50
52
|
::Chroma::Resources::Embedding.new(
|
51
53
|
id: ids[i].to_s,
|
52
|
-
embedding: llm.embed(text: text),
|
53
|
-
|
54
|
-
metadata: [], # metadatas[index],
|
54
|
+
embedding: llm.embed(text: text).embedding,
|
55
|
+
metadata: metadatas[i] || {},
|
55
56
|
document: text # Do we actually need to store the whole original document?
|
56
57
|
)
|
57
58
|
end
|
@@ -85,7 +86,7 @@ module Langchain::Vectorsearch
|
|
85
86
|
query:,
|
86
87
|
k: 4
|
87
88
|
)
|
88
|
-
embedding = llm.embed(text: query)
|
89
|
+
embedding = llm.embed(text: query).embedding
|
89
90
|
|
90
91
|
similarity_search_by_vector(
|
91
92
|
embedding: embedding,
|
@@ -94,7 +95,7 @@ module Langchain::Vectorsearch
|
|
94
95
|
end
|
95
96
|
|
96
97
|
# Search for similar texts by embedding
|
97
|
-
# @param embedding [Array] The embedding to search for
|
98
|
+
# @param embedding [Array<Float>] The embedding to search for
|
98
99
|
# @param k [Integer] The number of results to return
|
99
100
|
# @return [Chroma::Resources::Embedding] The response from the server
|
100
101
|
def similarity_search_by_vector(
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Langchain::Vectorsearch
|
4
|
+
class Elasticsearch < Base
|
5
|
+
#
|
6
|
+
# Wrapper around Elasticsearch vector search capabilities.
|
7
|
+
#
|
8
|
+
# Setting up Elasticsearch:
|
9
|
+
# 1. Get Elasticsearch up and running with Docker: https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html
|
10
|
+
# 2. Copy the HTTP CA certificate SHA-256 fingerprint and set the ELASTICSEARCH_CA_FINGERPRINT environment variable
|
11
|
+
# 3. Set the ELASTICSEARCH_URL environment variable
|
12
|
+
#
|
13
|
+
# Gem requirements:
|
14
|
+
# gem "elasticsearch", "~> 8.0.0"
|
15
|
+
#
|
16
|
+
# Usage:
|
17
|
+
# llm = Langchain::LLM::OpenAI.new(api_key: ENV["OPENAI_API_KEY"])
|
18
|
+
# es = Langchain::Vectorsearch::Elasticsearch.new(
|
19
|
+
# url: ENV["ELASTICSEARCH_URL"],
|
20
|
+
# index_name: "docs",
|
21
|
+
# llm: llm,
|
22
|
+
# es_options: {
|
23
|
+
# transport_options: {ssl: {verify: false}},
|
24
|
+
# ca_fingerprint: ENV["ELASTICSEARCH_CA_FINGERPRINT"]
|
25
|
+
# }
|
26
|
+
# )
|
27
|
+
#
|
28
|
+
# es.create_default_schema
|
29
|
+
# es.add_texts(texts: ["..."])
|
30
|
+
# es.similarity_search(text: "...")
|
31
|
+
#
|
32
|
+
attr_accessor :es_client, :index_name, :options
|
33
|
+
|
34
|
+
def initialize(url:, index_name:, llm:, api_key: nil, es_options: {})
|
35
|
+
require "elasticsearch"
|
36
|
+
|
37
|
+
@options = {
|
38
|
+
url: url,
|
39
|
+
request_timeout: 20,
|
40
|
+
log: false
|
41
|
+
}.merge(es_options)
|
42
|
+
|
43
|
+
@es_client = ::Elasticsearch::Client.new(**options)
|
44
|
+
@index_name = index_name
|
45
|
+
|
46
|
+
super(llm: llm)
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_texts(texts: [])
|
50
|
+
body = texts.map do |text|
|
51
|
+
[
|
52
|
+
{index: {_index: index_name}},
|
53
|
+
{input: text, input_vector: llm.embed(text: text).embedding}
|
54
|
+
]
|
55
|
+
end.flatten
|
56
|
+
|
57
|
+
es_client.bulk(body: body)
|
58
|
+
end
|
59
|
+
|
60
|
+
def update_texts(texts: [], ids: [])
|
61
|
+
body = texts.map.with_index do |text, i|
|
62
|
+
[
|
63
|
+
{index: {_index: index_name, _id: ids[i]}},
|
64
|
+
{input: text, input_vector: llm.embed(text: text).embedding}
|
65
|
+
]
|
66
|
+
end.flatten
|
67
|
+
|
68
|
+
es_client.bulk(body: body)
|
69
|
+
end
|
70
|
+
|
71
|
+
def create_default_schema
|
72
|
+
es_client.indices.create(
|
73
|
+
index: index_name,
|
74
|
+
body: default_schema
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def delete_default_schema
|
79
|
+
es_client.indices.delete(
|
80
|
+
index: index_name
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
def default_vector_settings
|
85
|
+
{type: "dense_vector", dims: llm.default_dimension}
|
86
|
+
end
|
87
|
+
|
88
|
+
def vector_settings
|
89
|
+
options[:vector_settings] || default_vector_settings
|
90
|
+
end
|
91
|
+
|
92
|
+
def default_schema
|
93
|
+
{
|
94
|
+
mappings: {
|
95
|
+
properties: {
|
96
|
+
input: {
|
97
|
+
type: "text"
|
98
|
+
},
|
99
|
+
input_vector: vector_settings
|
100
|
+
}
|
101
|
+
}
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
def default_query(query_vector)
|
106
|
+
{
|
107
|
+
script_score: {
|
108
|
+
query: {match_all: {}},
|
109
|
+
script: {
|
110
|
+
source: "cosineSimilarity(params.query_vector, 'input_vector') + 1.0",
|
111
|
+
params: {
|
112
|
+
query_vector: query_vector
|
113
|
+
}
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
# TODO: Implement this
|
120
|
+
# def ask()
|
121
|
+
# end
|
122
|
+
|
123
|
+
def similarity_search(text: "", k: 10, query: {})
|
124
|
+
if text.empty? && query.empty?
|
125
|
+
raise "Either text or query should pass as an argument"
|
126
|
+
end
|
127
|
+
|
128
|
+
if query.empty?
|
129
|
+
query_vector = llm.embed(text: text).embedding
|
130
|
+
|
131
|
+
query = default_query(query_vector)
|
132
|
+
end
|
133
|
+
|
134
|
+
es_client.search(body: {query: query, size: k}).body
|
135
|
+
end
|
136
|
+
|
137
|
+
def similarity_search_by_vector(embedding: [], k: 10, query: {})
|
138
|
+
if embedding.empty? && query.empty?
|
139
|
+
raise "Either embedding or query should pass as an argument"
|
140
|
+
end
|
141
|
+
|
142
|
+
query = default_query(embedding) if query.empty?
|
143
|
+
|
144
|
+
es_client.search(body: {query: query, size: k}).body
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -35,15 +35,15 @@ module Langchain::Vectorsearch
|
|
35
35
|
#
|
36
36
|
# Add a list of texts and corresponding IDs to the index
|
37
37
|
#
|
38
|
-
# @param texts [Array] The list of texts to add
|
39
|
-
# @param ids [Array] The list of corresponding IDs (integers) to the texts
|
38
|
+
# @param texts [Array<String>] The list of texts to add
|
39
|
+
# @param ids [Array<Integer>] The list of corresponding IDs (integers) to the texts
|
40
40
|
# @return [Boolean] The response from the HNSW library
|
41
41
|
#
|
42
42
|
def add_texts(texts:, ids:)
|
43
43
|
resize_index(texts.size)
|
44
44
|
|
45
45
|
Array(texts).each_with_index do |text, i|
|
46
|
-
embedding = llm.embed(text: text)
|
46
|
+
embedding = llm.embed(text: text).embedding
|
47
47
|
|
48
48
|
client.add_point(embedding, ids[i])
|
49
49
|
end
|
@@ -64,7 +64,7 @@ module Langchain::Vectorsearch
|
|
64
64
|
query:,
|
65
65
|
k: 4
|
66
66
|
)
|
67
|
-
embedding = llm.embed(text: query)
|
67
|
+
embedding = llm.embed(text: query).embedding
|
68
68
|
|
69
69
|
similarity_search_by_vector(
|
70
70
|
embedding: embedding,
|
@@ -75,7 +75,7 @@ module Langchain::Vectorsearch
|
|
75
75
|
#
|
76
76
|
# Search for the K nearest neighbors of a given vector
|
77
77
|
#
|
78
|
-
# @param embedding [Array] The embedding to search for
|
78
|
+
# @param embedding [Array<Float>] The embedding to search for
|
79
79
|
# @param k [Integer] The number of results to return
|
80
80
|
# @return [Array] Results in the format `[[id1, distance3], [id2, distance2]]`
|
81
81
|
#
|
@@ -5,7 +5,8 @@ module Langchain::Vectorsearch
|
|
5
5
|
#
|
6
6
|
# Wrapper around Milvus REST APIs.
|
7
7
|
#
|
8
|
-
# Gem requirements:
|
8
|
+
# Gem requirements:
|
9
|
+
# gem "milvus", "~> 0.9.2"
|
9
10
|
#
|
10
11
|
# Usage:
|
11
12
|
# milvus = Langchain::Vectorsearch::Milvus.new(url:, index_name:, llm:, api_key:)
|
@@ -32,7 +33,7 @@ module Langchain::Vectorsearch
|
|
32
33
|
}, {
|
33
34
|
field_name: "vectors",
|
34
35
|
type: ::Milvus::DATA_TYPES["float_vector"],
|
35
|
-
field: Array(texts).map { |text| llm.embed(text: text) }
|
36
|
+
field: Array(texts).map { |text| llm.embed(text: text).embedding }
|
36
37
|
}
|
37
38
|
]
|
38
39
|
)
|
@@ -70,7 +71,7 @@ module Langchain::Vectorsearch
|
|
70
71
|
type_params: [
|
71
72
|
{
|
72
73
|
key: "dim",
|
73
|
-
value: default_dimension.to_s
|
74
|
+
value: llm.default_dimension.to_s
|
74
75
|
}
|
75
76
|
]
|
76
77
|
}
|
@@ -111,7 +112,7 @@ module Langchain::Vectorsearch
|
|
111
112
|
end
|
112
113
|
|
113
114
|
def similarity_search(query:, k: 4)
|
114
|
-
embedding = llm.embed(text: query)
|
115
|
+
embedding = llm.embed(text: query).embedding
|
115
116
|
|
116
117
|
similarity_search_by_vector(
|
117
118
|
embedding: embedding,
|
@@ -5,10 +5,12 @@ module Langchain::Vectorsearch
|
|
5
5
|
#
|
6
6
|
# The PostgreSQL vector search adapter
|
7
7
|
#
|
8
|
-
# Gem requirements:
|
8
|
+
# Gem requirements:
|
9
|
+
# gem "sequel", "~> 5.68.0"
|
10
|
+
# gem "pgvector", "~> 0.2"
|
9
11
|
#
|
10
12
|
# Usage:
|
11
|
-
#
|
13
|
+
# pgvector = Langchain::Vectorsearch::Pgvector.new(url:, index_name:, llm:, namespace: nil)
|
12
14
|
#
|
13
15
|
|
14
16
|
# The operators supported by the PostgreSQL vector search adapter
|
@@ -52,7 +54,7 @@ module Langchain::Vectorsearch
|
|
52
54
|
# the added or updated texts.
|
53
55
|
def upsert_texts(texts:, ids:)
|
54
56
|
data = texts.zip(ids).flat_map do |(text, id)|
|
55
|
-
{id: id, content: text, vectors: llm.embed(text: text).to_s, namespace: namespace}
|
57
|
+
{id: id, content: text, vectors: llm.embed(text: text).embedding.to_s, namespace: namespace}
|
56
58
|
end
|
57
59
|
# @db[table_name.to_sym].multi_insert(data, return: :primary_key)
|
58
60
|
@db[table_name.to_sym]
|
@@ -70,7 +72,7 @@ module Langchain::Vectorsearch
|
|
70
72
|
def add_texts(texts:, ids: nil)
|
71
73
|
if ids.nil? || ids.empty?
|
72
74
|
data = texts.map do |text|
|
73
|
-
{content: text, vectors: llm.embed(text: text).to_s, namespace: namespace}
|
75
|
+
{content: text, vectors: llm.embed(text: text).embedding.to_s, namespace: namespace}
|
74
76
|
end
|
75
77
|
|
76
78
|
@db[table_name.to_sym].multi_insert(data, return: :primary_key)
|
@@ -91,7 +93,7 @@ module Langchain::Vectorsearch
|
|
91
93
|
def create_default_schema
|
92
94
|
db.run "CREATE EXTENSION IF NOT EXISTS vector"
|
93
95
|
namespace_column = @namespace_column
|
94
|
-
vector_dimension = default_dimension
|
96
|
+
vector_dimension = llm.default_dimension
|
95
97
|
db.create_table? table_name.to_sym do
|
96
98
|
primary_key :id
|
97
99
|
text :content
|
@@ -110,7 +112,7 @@ module Langchain::Vectorsearch
|
|
110
112
|
# @param k [Integer] The number of top results to return
|
111
113
|
# @return [Array<Hash>] The results of the search
|
112
114
|
def similarity_search(query:, k: 4)
|
113
|
-
embedding = llm.embed(text: query)
|
115
|
+
embedding = llm.embed(text: query).embedding
|
114
116
|
|
115
117
|
similarity_search_by_vector(
|
116
118
|
embedding: embedding,
|
@@ -150,3 +152,7 @@ module Langchain::Vectorsearch
|
|
150
152
|
end
|
151
153
|
end
|
152
154
|
end
|
155
|
+
|
156
|
+
# Rails connection when configuring vectorsearch
|
157
|
+
# Update READMEs
|
158
|
+
# Rails migration to create a migration
|