langchainrb 0.6.17 → 0.6.18
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 +11 -0
- data/README.md +15 -0
- 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 +1 -1
- data/lib/langchain/vectorsearch/chroma.rb +5 -5
- data/lib/langchain/vectorsearch/hnswlib.rb +5 -5
- data/lib/langchain/vectorsearch/milvus.rb +2 -2
- data/lib/langchain/vectorsearch/pgvector.rb +3 -3
- data/lib/langchain/vectorsearch/pinecone.rb +10 -10
- data/lib/langchain/vectorsearch/qdrant.rb +5 -5
- data/lib/langchain/vectorsearch/weaviate.rb +6 -6
- data/lib/langchain/version.rb +1 -1
- data/lib/langchain.rb +3 -0
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 437c6387ded139ed1a513414bfb7242cdbadf1ba6526c7a89346aa2fa9490fc2
|
4
|
+
data.tar.gz: dd6f437a4bbc4807a16631dd790f66c9de4e9456011b2c4f84302fe3fab1377b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24748539de50dfa816fdb71173ef00a6b04f9737f32926fca919865a49b9812dd9f1fdb286c361c98e33cc994f67e8988ab688bfdf6bf3020d954eb0c791177c
|
7
|
+
data.tar.gz: 283b10460187cada7485e08a19c89e7485925ab2f73a5ad51b06a72e8fd9ee1600ddac9d000f13c0c1af13f6defece9fdcc272489d0df803f94da96fe1c76cfd
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.6.18] - 2023-10-16
|
4
|
+
- Introduce `Langchain::LLM::Response`` object
|
5
|
+
- Introduce `Langchain::Chunk` object
|
6
|
+
- Add the ask() method to the Langchain::ActiveRecord::Hooks
|
7
|
+
|
8
|
+
## [0.6.17] - 2023-10-10
|
9
|
+
- Bump weaviate and chroma-db deps
|
10
|
+
- `Langchain::Chunker::Semantic` chunker
|
11
|
+
- Re-structure Conversations class
|
12
|
+
- Bug fixes
|
13
|
+
|
3
14
|
## [0.6.16] - 2023-10-02
|
4
15
|
- HyDE-style similarity search
|
5
16
|
- `Langchain::Chunker::Sentence` chunker
|
data/README.md
CHANGED
@@ -128,6 +128,21 @@ class Product < ActiveRecord::Base
|
|
128
128
|
end
|
129
129
|
```
|
130
130
|
|
131
|
+
### Exposed ActiveRecord methods
|
132
|
+
```ruby
|
133
|
+
# Retrieve similar products based on the query string passed in
|
134
|
+
Product.similarity_search(
|
135
|
+
query:,
|
136
|
+
k: # number of results to be retrieved
|
137
|
+
)
|
138
|
+
```
|
139
|
+
```ruby
|
140
|
+
# Q&A-style querying based on the question passed in
|
141
|
+
Product.ask(
|
142
|
+
question:
|
143
|
+
)
|
144
|
+
```
|
145
|
+
|
131
146
|
Additional info [here](https://github.com/andreibondarev/langchainrb/blob/main/lib/langchain/active_record/hooks.rb#L10-L38).
|
132
147
|
|
133
148
|
### Using Standalone LLMs 🗣️
|
@@ -92,6 +92,20 @@ module Langchain
|
|
92
92
|
ids = records.map { |record| record.dig("id") || record.dig("__id") }
|
93
93
|
where(id: ids)
|
94
94
|
end
|
95
|
+
|
96
|
+
# Ask a question and return the answer
|
97
|
+
#
|
98
|
+
# @param question [String] The question to ask
|
99
|
+
# @param k [Integer] The number of results to have in context
|
100
|
+
# @yield [String] Stream responses back one String at a time
|
101
|
+
# @return [String] The answer to the question
|
102
|
+
def ask(question:, k: 4, &block)
|
103
|
+
class_variable_get(:@@provider).ask(
|
104
|
+
question: question,
|
105
|
+
k: k,
|
106
|
+
&block
|
107
|
+
)
|
108
|
+
end
|
95
109
|
end
|
96
110
|
end
|
97
111
|
end
|
@@ -58,7 +58,7 @@ module Langchain::Agent
|
|
58
58
|
max_iterations.times do
|
59
59
|
Langchain.logger.info("Sending the prompt to the #{llm.class} LLM", for: self.class)
|
60
60
|
|
61
|
-
response = llm.complete(prompt: prompt, stop_sequences: ["Observation:"])
|
61
|
+
response = llm.complete(prompt: prompt, stop_sequences: ["Observation:"]).completion
|
62
62
|
|
63
63
|
# Append the response to the prompt
|
64
64
|
prompt += response
|
@@ -27,7 +27,7 @@ module Langchain::Agent
|
|
27
27
|
|
28
28
|
# Get the SQL string to execute
|
29
29
|
Langchain.logger.info("Passing the inital prompt to the #{llm.class} LLM", for: self.class)
|
30
|
-
sql_string = llm.complete(prompt: prompt)
|
30
|
+
sql_string = llm.complete(prompt: prompt).completion
|
31
31
|
|
32
32
|
# Execute the SQL string and collect the results
|
33
33
|
Langchain.logger.info("Passing the SQL to the Database: #{sql_string}", for: self.class)
|
@@ -36,7 +36,7 @@ module Langchain::Agent
|
|
36
36
|
# Pass the results and get the LLM to synthesize the answer to the question
|
37
37
|
Langchain.logger.info("Passing the synthesize prompt to the #{llm.class} LLM with results: #{results}", for: self.class)
|
38
38
|
prompt2 = create_prompt_for_answer(question: question, sql_query: sql_string, results: results)
|
39
|
-
llm.complete(prompt: prompt2)
|
39
|
+
llm.complete(prompt: prompt2).completion
|
40
40
|
end
|
41
41
|
|
42
42
|
private
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Langchain
|
4
|
+
class Chunk
|
5
|
+
# The chunking process is the process of splitting a document into smaller chunks and creating instances of Langchain::Chunk
|
6
|
+
|
7
|
+
attr_reader :text
|
8
|
+
|
9
|
+
# Initialize a new chunk
|
10
|
+
# @param [String] text
|
11
|
+
# @return [Langchain::Chunk]
|
12
|
+
def initialize(text:)
|
13
|
+
@text = text
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -24,14 +24,17 @@ module Langchain
|
|
24
24
|
@separators = separators
|
25
25
|
end
|
26
26
|
|
27
|
-
# @return [Array<
|
27
|
+
# @return [Array<Langchain::Chunk>]
|
28
28
|
def chunks
|
29
29
|
splitter = Baran::RecursiveCharacterTextSplitter.new(
|
30
30
|
chunk_size: chunk_size,
|
31
31
|
chunk_overlap: chunk_overlap,
|
32
32
|
separators: separators
|
33
33
|
)
|
34
|
-
|
34
|
+
|
35
|
+
splitter.chunks(text).map do |chunk|
|
36
|
+
Langchain::Chunk.new(text: chunk[:text])
|
37
|
+
end
|
35
38
|
end
|
36
39
|
end
|
37
40
|
end
|
@@ -23,7 +23,7 @@ module Langchain
|
|
23
23
|
@prompt_template = prompt_template || default_prompt_template
|
24
24
|
end
|
25
25
|
|
26
|
-
# @return [Array<
|
26
|
+
# @return [Array<Langchain::Chunk>]
|
27
27
|
def chunks
|
28
28
|
prompt = prompt_template.format(text: text)
|
29
29
|
|
@@ -34,6 +34,9 @@ module Langchain
|
|
34
34
|
.split("---")
|
35
35
|
.map(&:strip)
|
36
36
|
.reject(&:empty?)
|
37
|
+
.map do |chunk|
|
38
|
+
Langchain::Chunk.new(text: chunk)
|
39
|
+
end
|
37
40
|
end
|
38
41
|
|
39
42
|
private
|
@@ -19,10 +19,12 @@ module Langchain
|
|
19
19
|
@text = text
|
20
20
|
end
|
21
21
|
|
22
|
-
# @return [Array<
|
22
|
+
# @return [Array<Langchain::Chunk>]
|
23
23
|
def chunks
|
24
24
|
ps = PragmaticSegmenter::Segmenter.new(text: text)
|
25
|
-
ps.segment
|
25
|
+
ps.segment.map do |chunk|
|
26
|
+
Langchain::Chunk.new(text: chunk)
|
27
|
+
end
|
26
28
|
end
|
27
29
|
end
|
28
30
|
end
|
@@ -24,14 +24,17 @@ module Langchain
|
|
24
24
|
@separator = separator
|
25
25
|
end
|
26
26
|
|
27
|
-
# @return [Array<
|
27
|
+
# @return [Array<Langchain::Chunk>]
|
28
28
|
def chunks
|
29
29
|
splitter = Baran::CharacterTextSplitter.new(
|
30
30
|
chunk_size: chunk_size,
|
31
31
|
chunk_overlap: chunk_overlap,
|
32
32
|
separator: separator
|
33
33
|
)
|
34
|
-
|
34
|
+
|
35
|
+
splitter.chunks(text).map do |chunk|
|
36
|
+
Langchain::Chunk.new(text: chunk[:text])
|
37
|
+
end
|
35
38
|
end
|
36
39
|
end
|
37
40
|
end
|
@@ -58,7 +58,7 @@ module Langchain
|
|
58
58
|
# @return [Response] The response from the model
|
59
59
|
def message(message)
|
60
60
|
@memory.append_message ::Langchain::Conversation::Prompt.new(message)
|
61
|
-
ai_message = ::Langchain::Conversation::Response.new(llm_response)
|
61
|
+
ai_message = ::Langchain::Conversation::Response.new(llm_response.chat_completion)
|
62
62
|
@memory.append_message(ai_message)
|
63
63
|
ai_message
|
64
64
|
end
|
data/lib/langchain/llm/ai21.rb
CHANGED
@@ -8,7 +8,7 @@ module Langchain::LLM
|
|
8
8
|
# gem "ai21", "~> 0.2.1"
|
9
9
|
#
|
10
10
|
# Usage:
|
11
|
-
# ai21 = Langchain::LLM::AI21.new(api_key:)
|
11
|
+
# ai21 = Langchain::LLM::AI21.new(api_key: ENV["AI21_API_KEY"])
|
12
12
|
#
|
13
13
|
class AI21 < Base
|
14
14
|
DEFAULTS = {
|
@@ -30,7 +30,7 @@ module Langchain::LLM
|
|
30
30
|
#
|
31
31
|
# @param prompt [String] The prompt to generate a completion for
|
32
32
|
# @param params [Hash] The parameters to pass to the API
|
33
|
-
# @return [
|
33
|
+
# @return [Langchain::LLM::AI21Response] The completion
|
34
34
|
#
|
35
35
|
def complete(prompt:, **params)
|
36
36
|
parameters = complete_parameters params
|
@@ -38,7 +38,7 @@ module Langchain::LLM
|
|
38
38
|
parameters[:maxTokens] = LENGTH_VALIDATOR.validate_max_tokens!(prompt, parameters[:model], client)
|
39
39
|
|
40
40
|
response = client.complete(prompt, parameters)
|
41
|
-
|
41
|
+
Langchain::LLM::AI21Response.new response, model: parameters[:model]
|
42
42
|
end
|
43
43
|
|
44
44
|
#
|
@@ -51,6 +51,7 @@ module Langchain::LLM
|
|
51
51
|
def summarize(text:, **params)
|
52
52
|
response = client.summarize(text, "TEXT", params)
|
53
53
|
response.dig(:summary)
|
54
|
+
# Should we update this to also return a Langchain::LLM::AI21Response?
|
54
55
|
end
|
55
56
|
|
56
57
|
private
|
@@ -8,7 +8,7 @@ module Langchain::LLM
|
|
8
8
|
# gem "anthropic", "~> 0.1.0"
|
9
9
|
#
|
10
10
|
# Usage:
|
11
|
-
# anthorpic = Langchain::LLM::Anthropic.new(api_key:)
|
11
|
+
# anthorpic = Langchain::LLM::Anthropic.new(api_key: ENV["ANTHROPIC_API_KEY"])
|
12
12
|
#
|
13
13
|
class Anthropic < Base
|
14
14
|
DEFAULTS = {
|
@@ -32,7 +32,7 @@ module Langchain::LLM
|
|
32
32
|
#
|
33
33
|
# @param prompt [String] The prompt to generate a completion for
|
34
34
|
# @param params [Hash] extra parameters passed to Anthropic::Client#complete
|
35
|
-
# @return [
|
35
|
+
# @return [Langchain::LLM::AnthropicResponse] The completion
|
36
36
|
#
|
37
37
|
def complete(prompt:, **params)
|
38
38
|
parameters = compose_parameters @defaults[:completion_model_name], params
|
@@ -43,7 +43,7 @@ module Langchain::LLM
|
|
43
43
|
# parameters[:max_tokens_to_sample] = validate_max_tokens(prompt, parameters[:completion_model_name])
|
44
44
|
|
45
45
|
response = client.complete(parameters: parameters)
|
46
|
-
|
46
|
+
Langchain::LLM::AnthropicResponse.new(response)
|
47
47
|
end
|
48
48
|
|
49
49
|
private
|
data/lib/langchain/llm/cohere.rb
CHANGED
@@ -8,7 +8,7 @@ module Langchain::LLM
|
|
8
8
|
# gem "cohere-ruby", "~> 0.9.6"
|
9
9
|
#
|
10
10
|
# Usage:
|
11
|
-
# cohere = Langchain::LLM::Cohere.new(api_key: "
|
11
|
+
# cohere = Langchain::LLM::Cohere.new(api_key: ENV["COHERE_API_KEY"])
|
12
12
|
#
|
13
13
|
class Cohere < Base
|
14
14
|
DEFAULTS = {
|
@@ -30,14 +30,15 @@ module Langchain::LLM
|
|
30
30
|
# Generate an embedding for a given text
|
31
31
|
#
|
32
32
|
# @param text [String] The text to generate an embedding for
|
33
|
-
# @return [
|
33
|
+
# @return [Langchain::LLM::CohereResponse] Response object
|
34
34
|
#
|
35
35
|
def embed(text:)
|
36
36
|
response = client.embed(
|
37
37
|
texts: [text],
|
38
38
|
model: @defaults[:embeddings_model_name]
|
39
39
|
)
|
40
|
-
|
40
|
+
|
41
|
+
Langchain::LLM::CohereResponse.new response, model: @defaults[:embeddings_model_name]
|
41
42
|
end
|
42
43
|
|
43
44
|
#
|
@@ -45,7 +46,7 @@ module Langchain::LLM
|
|
45
46
|
#
|
46
47
|
# @param prompt [String] The prompt to generate a completion for
|
47
48
|
# @param params[:stop_sequences]
|
48
|
-
# @return [
|
49
|
+
# @return [Langchain::LLM::CohereResponse] Response object
|
49
50
|
#
|
50
51
|
def complete(prompt:, **params)
|
51
52
|
default_params = {
|
@@ -64,7 +65,7 @@ module Langchain::LLM
|
|
64
65
|
default_params[:max_tokens] = Langchain::Utils::TokenLength::CohereValidator.validate_max_tokens!(prompt, default_params[:model], client)
|
65
66
|
|
66
67
|
response = client.generate(**default_params)
|
67
|
-
response
|
68
|
+
Langchain::LLM::CohereResponse.new response, model: @defaults[:completion_model_name]
|
68
69
|
end
|
69
70
|
|
70
71
|
# Cohere does not have a dedicated chat endpoint, so instead we call `complete()`
|
@@ -8,7 +8,7 @@ module Langchain::LLM
|
|
8
8
|
# gem "google_palm_api", "~> 0.1.3"
|
9
9
|
#
|
10
10
|
# Usage:
|
11
|
-
# google_palm = Langchain::LLM::GooglePalm.new(api_key: "
|
11
|
+
# google_palm = Langchain::LLM::GooglePalm.new(api_key: ENV["GOOGLE_PALM_API_KEY"])
|
12
12
|
#
|
13
13
|
class GooglePalm < Base
|
14
14
|
DEFAULTS = {
|
@@ -34,13 +34,13 @@ module Langchain::LLM
|
|
34
34
|
# Generate an embedding for a given text
|
35
35
|
#
|
36
36
|
# @param text [String] The text to generate an embedding for
|
37
|
-
# @return [
|
37
|
+
# @return [Langchain::LLM::GooglePalmResponse] Response object
|
38
38
|
#
|
39
39
|
def embed(text:)
|
40
|
-
response = client.embed(
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
response = client.embed(text: text)
|
41
|
+
|
42
|
+
Langchain::LLM::GooglePalmResponse.new response,
|
43
|
+
model: @defaults[:embeddings_model_name]
|
44
44
|
end
|
45
45
|
|
46
46
|
#
|
@@ -48,7 +48,7 @@ module Langchain::LLM
|
|
48
48
|
#
|
49
49
|
# @param prompt [String] The prompt to generate a completion for
|
50
50
|
# @param params extra parameters passed to GooglePalmAPI::Client#generate_text
|
51
|
-
# @return [
|
51
|
+
# @return [Langchain::LLM::GooglePalmResponse] Response object
|
52
52
|
#
|
53
53
|
def complete(prompt:, **params)
|
54
54
|
default_params = {
|
@@ -68,7 +68,9 @@ module Langchain::LLM
|
|
68
68
|
default_params.merge!(params)
|
69
69
|
|
70
70
|
response = client.generate_text(**default_params)
|
71
|
-
|
71
|
+
|
72
|
+
Langchain::LLM::GooglePalmResponse.new response,
|
73
|
+
model: default_params[:model]
|
72
74
|
end
|
73
75
|
|
74
76
|
#
|
@@ -79,7 +81,7 @@ module Langchain::LLM
|
|
79
81
|
# @param context [String] An initial context to provide as a system message, ie "You are RubyGPT, a helpful chat bot for helping people learn Ruby"
|
80
82
|
# @param examples [Array<Hash>] Examples of messages to provide to the model. Useful for Few-Shot Prompting
|
81
83
|
# @param options [Hash] extra parameters passed to GooglePalmAPI::Client#generate_chat_message
|
82
|
-
# @return [
|
84
|
+
# @return [Langchain::LLM::GooglePalmResponse] Response object
|
83
85
|
#
|
84
86
|
def chat(prompt: "", messages: [], context: "", examples: [], **options)
|
85
87
|
raise ArgumentError.new(":prompt or :messages argument is expected") if prompt.empty? && messages.empty?
|
@@ -108,7 +110,9 @@ module Langchain::LLM
|
|
108
110
|
response = client.generate_chat_message(**default_params)
|
109
111
|
raise "GooglePalm API returned an error: #{response}" if response.dig("error")
|
110
112
|
|
111
|
-
|
113
|
+
Langchain::LLM::GooglePalmResponse.new response,
|
114
|
+
model: default_params[:model]
|
115
|
+
# TODO: Pass in prompt_tokens: prompt_tokens
|
112
116
|
end
|
113
117
|
|
114
118
|
#
|
@@ -8,7 +8,7 @@ module Langchain::LLM
|
|
8
8
|
# gem "hugging-face", "~> 0.3.4"
|
9
9
|
#
|
10
10
|
# Usage:
|
11
|
-
# hf = Langchain::LLM::HuggingFace.new(api_key: "
|
11
|
+
# hf = Langchain::LLM::HuggingFace.new(api_key: ENV["HUGGING_FACE_API_KEY"])
|
12
12
|
#
|
13
13
|
class HuggingFace < Base
|
14
14
|
# The gem does not currently accept other models:
|
@@ -34,13 +34,14 @@ module Langchain::LLM
|
|
34
34
|
# Generate an embedding for a given text
|
35
35
|
#
|
36
36
|
# @param text [String] The text to embed
|
37
|
-
# @return [
|
37
|
+
# @return [Langchain::LLM::HuggingFaceResponse] Response object
|
38
38
|
#
|
39
39
|
def embed(text:)
|
40
|
-
client.embedding(
|
40
|
+
response = client.embedding(
|
41
41
|
input: text,
|
42
42
|
model: DEFAULTS[:embeddings_model_name]
|
43
43
|
)
|
44
|
+
Langchain::LLM::HuggingFaceResponse.new(response, model: DEFAULTS[:embeddings_model_name])
|
44
45
|
end
|
45
46
|
end
|
46
47
|
end
|
@@ -34,7 +34,7 @@ module Langchain::LLM
|
|
34
34
|
|
35
35
|
# @param text [String] The text to embed
|
36
36
|
# @param n_threads [Integer] The number of CPU threads to use
|
37
|
-
# @return [Array] The embedding
|
37
|
+
# @return [Array<Float>] The embedding
|
38
38
|
def embed(text:, n_threads: nil)
|
39
39
|
# contexts are kinda stateful when it comes to embeddings, so allocate one each time
|
40
40
|
context = embedding_context
|
data/lib/langchain/llm/ollama.rb
CHANGED
@@ -22,18 +22,23 @@ module Langchain::LLM
|
|
22
22
|
@url = url
|
23
23
|
end
|
24
24
|
|
25
|
+
#
|
25
26
|
# Generate the completion for a given prompt
|
27
|
+
#
|
26
28
|
# @param prompt [String] The prompt to complete
|
27
29
|
# @param model [String] The model to use
|
28
30
|
# @param options [Hash] The options to use (https://github.com/jmorganca/ollama/blob/main/docs/modelfile.md#valid-parameters-and-values)
|
29
|
-
# @return [
|
31
|
+
# @return [Langchain::LLM::OllamaResponse] Response object
|
32
|
+
#
|
30
33
|
def complete(prompt:, model: nil, **options)
|
31
34
|
response = +""
|
32
35
|
|
36
|
+
model_name = model || DEFAULTS[:completion_model_name]
|
37
|
+
|
33
38
|
client.post("api/generate") do |req|
|
34
39
|
req.body = {}
|
35
40
|
req.body["prompt"] = prompt
|
36
|
-
req.body["model"] =
|
41
|
+
req.body["model"] = model_name
|
37
42
|
|
38
43
|
req.body["options"] = options if options.any?
|
39
44
|
|
@@ -47,27 +52,34 @@ module Langchain::LLM
|
|
47
52
|
end
|
48
53
|
end
|
49
54
|
|
50
|
-
response
|
55
|
+
Langchain::LLM::OllamaResponse.new(response, model: model_name)
|
51
56
|
end
|
52
57
|
|
58
|
+
#
|
53
59
|
# Generate an embedding for a given text
|
60
|
+
#
|
54
61
|
# @param text [String] The text to generate an embedding for
|
55
62
|
# @param model [String] The model to use
|
56
|
-
# @param options [Hash] The options to use
|
63
|
+
# @param options [Hash] The options to use
|
64
|
+
# @return [Langchain::LLM::OllamaResponse] Response object
|
65
|
+
#
|
57
66
|
def embed(text:, model: nil, **options)
|
67
|
+
model_name = model || DEFAULTS[:embeddings_model_name]
|
68
|
+
|
58
69
|
response = client.post("api/embeddings") do |req|
|
59
70
|
req.body = {}
|
60
71
|
req.body["prompt"] = text
|
61
|
-
req.body["model"] =
|
72
|
+
req.body["model"] = model_name
|
62
73
|
|
63
74
|
req.body["options"] = options if options.any?
|
64
75
|
end
|
65
76
|
|
66
|
-
response.body
|
77
|
+
Langchain::LLM::OllamaResponse.new(response.body, model: model_name)
|
67
78
|
end
|
68
79
|
|
69
80
|
private
|
70
81
|
|
82
|
+
# @return [Faraday::Connection] Faraday client
|
71
83
|
def client
|
72
84
|
@client ||= Faraday.new(url: url) do |conn|
|
73
85
|
conn.request :json
|
data/lib/langchain/llm/openai.rb
CHANGED
@@ -42,7 +42,7 @@ module Langchain::LLM
|
|
42
42
|
#
|
43
43
|
# @param text [String] The text to generate an embedding for
|
44
44
|
# @param params extra parameters passed to OpenAI::Client#embeddings
|
45
|
-
# @return [
|
45
|
+
# @return [Langchain::LLM::OpenAIResponse] Response object
|
46
46
|
#
|
47
47
|
def embed(text:, **params)
|
48
48
|
parameters = {model: @defaults[:embeddings_model_name], input: text}
|
@@ -53,7 +53,7 @@ module Langchain::LLM
|
|
53
53
|
client.embeddings(parameters: parameters.merge(params))
|
54
54
|
end
|
55
55
|
|
56
|
-
|
56
|
+
Langchain::LLM::OpenAIResponse.new(response)
|
57
57
|
end
|
58
58
|
|
59
59
|
#
|
@@ -61,7 +61,7 @@ module Langchain::LLM
|
|
61
61
|
#
|
62
62
|
# @param prompt [String] The prompt to generate a completion for
|
63
63
|
# @param params extra parameters passed to OpenAI::Client#complete
|
64
|
-
# @return [
|
64
|
+
# @return [Langchain::LLM::Response::OpenaAI] Response object
|
65
65
|
#
|
66
66
|
def complete(prompt:, **params)
|
67
67
|
parameters = compose_parameters @defaults[:completion_model_name], params
|
@@ -75,7 +75,7 @@ module Langchain::LLM
|
|
75
75
|
client.chat(parameters: parameters)
|
76
76
|
end
|
77
77
|
|
78
|
-
|
78
|
+
Langchain::LLM::OpenAIResponse.new(response)
|
79
79
|
end
|
80
80
|
|
81
81
|
#
|
@@ -120,7 +120,7 @@ module Langchain::LLM
|
|
120
120
|
# @param examples [Array<Hash>] Examples of messages to provide to the model. Useful for Few-Shot Prompting
|
121
121
|
# @param options [Hash] extra parameters passed to OpenAI::Client#chat
|
122
122
|
# @yield [Hash] Stream responses back one token at a time
|
123
|
-
# @return [
|
123
|
+
# @return [Langchain::LLM::OpenAIResponse] Response object
|
124
124
|
#
|
125
125
|
def chat(prompt: "", messages: [], context: "", examples: [], **options, &block)
|
126
126
|
raise ArgumentError.new(":prompt or :messages argument is expected") if prompt.empty? && messages.empty?
|
@@ -138,7 +138,7 @@ module Langchain::LLM
|
|
138
138
|
|
139
139
|
return if block
|
140
140
|
|
141
|
-
|
141
|
+
Langchain::LLM::OpenAIResponse.new(response)
|
142
142
|
end
|
143
143
|
|
144
144
|
#
|
@@ -154,6 +154,7 @@ module Langchain::LLM
|
|
154
154
|
prompt = prompt_template.format(text: text)
|
155
155
|
|
156
156
|
complete(prompt: prompt, temperature: @defaults[:temperature])
|
157
|
+
# Should this return a Langchain::LLM::OpenAIResponse as well?
|
157
158
|
end
|
158
159
|
|
159
160
|
private
|
@@ -47,38 +47,34 @@ module Langchain::LLM
|
|
47
47
|
# Generate an embedding for a given text
|
48
48
|
#
|
49
49
|
# @param text [String] The text to generate an embedding for
|
50
|
-
# @return [
|
50
|
+
# @return [Langchain::LLM::ReplicateResponse] Response object
|
51
51
|
#
|
52
52
|
def embed(text:)
|
53
53
|
response = embeddings_model.predict(input: text)
|
54
54
|
|
55
55
|
until response.finished?
|
56
56
|
response.refetch
|
57
|
-
sleep(1)
|
57
|
+
sleep(0.1)
|
58
58
|
end
|
59
59
|
|
60
|
-
response
|
60
|
+
Langchain::LLM::ReplicateResponse.new(response, model: @defaults[:embeddings_model_name])
|
61
61
|
end
|
62
62
|
|
63
63
|
#
|
64
64
|
# Generate a completion for a given prompt
|
65
65
|
#
|
66
66
|
# @param prompt [String] The prompt to generate a completion for
|
67
|
-
# @return [
|
67
|
+
# @return [Langchain::LLM::ReplicateResponse] Reponse object
|
68
68
|
#
|
69
69
|
def complete(prompt:, **params)
|
70
70
|
response = completion_model.predict(prompt: prompt)
|
71
71
|
|
72
72
|
until response.finished?
|
73
73
|
response.refetch
|
74
|
-
sleep(1)
|
74
|
+
sleep(0.1)
|
75
75
|
end
|
76
76
|
|
77
|
-
|
78
|
-
# The first array element is missing a space at the end, so we add it manually
|
79
|
-
response.output[0] += " "
|
80
|
-
|
81
|
-
response.output.join
|
77
|
+
Langchain::LLM::ReplicateResponse.new(response, model: @defaults[:completion_model_name])
|
82
78
|
end
|
83
79
|
|
84
80
|
# Cohere does not have a dedicated chat endpoint, so instead we call `complete()`
|
@@ -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
|
@@ -28,13 +28,13 @@ module Langchain::Vectorsearch
|
|
28
28
|
end
|
29
29
|
|
30
30
|
# Add a list of texts to the index
|
31
|
-
# @param texts [Array] The list of texts to add
|
31
|
+
# @param texts [Array<String>] The list of texts to add
|
32
32
|
# @return [Hash] The response from the server
|
33
33
|
def add_texts(texts:, ids: [])
|
34
34
|
embeddings = Array(texts).map.with_index do |text, i|
|
35
35
|
::Chroma::Resources::Embedding.new(
|
36
36
|
id: ids[i] ? ids[i].to_s : SecureRandom.uuid,
|
37
|
-
embedding: llm.embed(text: text),
|
37
|
+
embedding: llm.embed(text: text).embedding,
|
38
38
|
# TODO: Add support for passing metadata
|
39
39
|
metadata: {}, # metadatas[index],
|
40
40
|
document: text # Do we actually need to store the whole original document?
|
@@ -49,7 +49,7 @@ module Langchain::Vectorsearch
|
|
49
49
|
embeddings = Array(texts).map.with_index do |text, i|
|
50
50
|
::Chroma::Resources::Embedding.new(
|
51
51
|
id: ids[i].to_s,
|
52
|
-
embedding: llm.embed(text: text),
|
52
|
+
embedding: llm.embed(text: text).embedding,
|
53
53
|
# TODO: Add support for passing metadata
|
54
54
|
metadata: [], # metadatas[index],
|
55
55
|
document: text # Do we actually need to store the whole original document?
|
@@ -85,7 +85,7 @@ module Langchain::Vectorsearch
|
|
85
85
|
query:,
|
86
86
|
k: 4
|
87
87
|
)
|
88
|
-
embedding = llm.embed(text: query)
|
88
|
+
embedding = llm.embed(text: query).embedding
|
89
89
|
|
90
90
|
similarity_search_by_vector(
|
91
91
|
embedding: embedding,
|
@@ -94,7 +94,7 @@ module Langchain::Vectorsearch
|
|
94
94
|
end
|
95
95
|
|
96
96
|
# Search for similar texts by embedding
|
97
|
-
# @param embedding [Array] The embedding to search for
|
97
|
+
# @param embedding [Array<Float>] The embedding to search for
|
98
98
|
# @param k [Integer] The number of results to return
|
99
99
|
# @return [Chroma::Resources::Embedding] The response from the server
|
100
100
|
def similarity_search_by_vector(
|
@@ -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
|
#
|
@@ -32,7 +32,7 @@ module Langchain::Vectorsearch
|
|
32
32
|
}, {
|
33
33
|
field_name: "vectors",
|
34
34
|
type: ::Milvus::DATA_TYPES["float_vector"],
|
35
|
-
field: Array(texts).map { |text| llm.embed(text: text) }
|
35
|
+
field: Array(texts).map { |text| llm.embed(text: text).embedding }
|
36
36
|
}
|
37
37
|
]
|
38
38
|
)
|
@@ -111,7 +111,7 @@ module Langchain::Vectorsearch
|
|
111
111
|
end
|
112
112
|
|
113
113
|
def similarity_search(query:, k: 4)
|
114
|
-
embedding = llm.embed(text: query)
|
114
|
+
embedding = llm.embed(text: query).embedding
|
115
115
|
|
116
116
|
similarity_search_by_vector(
|
117
117
|
embedding: embedding,
|
@@ -52,7 +52,7 @@ module Langchain::Vectorsearch
|
|
52
52
|
# the added or updated texts.
|
53
53
|
def upsert_texts(texts:, ids:)
|
54
54
|
data = texts.zip(ids).flat_map do |(text, id)|
|
55
|
-
{id: id, content: text, vectors: llm.embed(text: text).to_s, namespace: namespace}
|
55
|
+
{id: id, content: text, vectors: llm.embed(text: text).embedding.to_s, namespace: namespace}
|
56
56
|
end
|
57
57
|
# @db[table_name.to_sym].multi_insert(data, return: :primary_key)
|
58
58
|
@db[table_name.to_sym]
|
@@ -70,7 +70,7 @@ module Langchain::Vectorsearch
|
|
70
70
|
def add_texts(texts:, ids: nil)
|
71
71
|
if ids.nil? || ids.empty?
|
72
72
|
data = texts.map do |text|
|
73
|
-
{content: text, vectors: llm.embed(text: text).to_s, namespace: namespace}
|
73
|
+
{content: text, vectors: llm.embed(text: text).embedding.to_s, namespace: namespace}
|
74
74
|
end
|
75
75
|
|
76
76
|
@db[table_name.to_sym].multi_insert(data, return: :primary_key)
|
@@ -110,7 +110,7 @@ module Langchain::Vectorsearch
|
|
110
110
|
# @param k [Integer] The number of top results to return
|
111
111
|
# @return [Array<Hash>] The results of the search
|
112
112
|
def similarity_search(query:, k: 4)
|
113
|
-
embedding = llm.embed(text: query)
|
113
|
+
embedding = llm.embed(text: query).embedding
|
114
114
|
|
115
115
|
similarity_search_by_vector(
|
116
116
|
embedding: embedding,
|
@@ -31,7 +31,7 @@ module Langchain::Vectorsearch
|
|
31
31
|
end
|
32
32
|
|
33
33
|
# Find records by ids
|
34
|
-
# @param ids [Array] The ids to find
|
34
|
+
# @param ids [Array<Integer>] The ids to find
|
35
35
|
# @param namespace String The namespace to search through
|
36
36
|
# @return [Hash] The response from the server
|
37
37
|
def find(ids: [], namespace: "")
|
@@ -44,8 +44,8 @@ module Langchain::Vectorsearch
|
|
44
44
|
end
|
45
45
|
|
46
46
|
# Add a list of texts to the index
|
47
|
-
# @param texts [Array] The list of texts to add
|
48
|
-
# @param ids [Array] The list of IDs to add
|
47
|
+
# @param texts [Array<String>] The list of texts to add
|
48
|
+
# @param ids [Array<Integer>] The list of IDs to add
|
49
49
|
# @param namespace [String] The namespace to add the texts to
|
50
50
|
# @param metadata [Hash] The metadata to use for the texts
|
51
51
|
# @return [Hash] The response from the server
|
@@ -54,7 +54,7 @@ module Langchain::Vectorsearch
|
|
54
54
|
{
|
55
55
|
id: ids[i] ? ids[i].to_s : SecureRandom.uuid,
|
56
56
|
metadata: metadata || {content: text},
|
57
|
-
values: llm.embed(text: text)
|
57
|
+
values: llm.embed(text: text).embedding
|
58
58
|
}
|
59
59
|
end
|
60
60
|
|
@@ -70,7 +70,7 @@ module Langchain::Vectorsearch
|
|
70
70
|
.flatten
|
71
71
|
.map do |path|
|
72
72
|
data = Langchain::Loader.new(path)&.load&.chunks
|
73
|
-
data.map { |chunk| chunk
|
73
|
+
data.map { |chunk| chunk.text }
|
74
74
|
end
|
75
75
|
|
76
76
|
texts.flatten!
|
@@ -79,8 +79,8 @@ module Langchain::Vectorsearch
|
|
79
79
|
end
|
80
80
|
|
81
81
|
# Update a list of texts in the index
|
82
|
-
# @param texts [Array] The list of texts to update
|
83
|
-
# @param ids [Array] The list of IDs to update
|
82
|
+
# @param texts [Array<String>] The list of texts to update
|
83
|
+
# @param ids [Array<Integer>] The list of IDs to update
|
84
84
|
# @param namespace [String] The namespace to update the texts in
|
85
85
|
# @param metadata [Hash] The metadata to use for the texts
|
86
86
|
# @return [Array] The response from the server
|
@@ -90,7 +90,7 @@ module Langchain::Vectorsearch
|
|
90
90
|
index.update(
|
91
91
|
namespace: namespace,
|
92
92
|
id: ids[i].to_s,
|
93
|
-
values: llm.embed(text: text),
|
93
|
+
values: llm.embed(text: text).embedding,
|
94
94
|
set_metadata: metadata
|
95
95
|
)
|
96
96
|
end
|
@@ -130,7 +130,7 @@ module Langchain::Vectorsearch
|
|
130
130
|
namespace: "",
|
131
131
|
filter: nil
|
132
132
|
)
|
133
|
-
embedding = llm.embed(text: query)
|
133
|
+
embedding = llm.embed(text: query).embedding
|
134
134
|
|
135
135
|
similarity_search_by_vector(
|
136
136
|
embedding: embedding,
|
@@ -141,7 +141,7 @@ module Langchain::Vectorsearch
|
|
141
141
|
end
|
142
142
|
|
143
143
|
# Search for similar texts by embedding
|
144
|
-
# @param embedding [Array] The embedding to search for
|
144
|
+
# @param embedding [Array<Float>] The embedding to search for
|
145
145
|
# @param k [Integer] The number of results to return
|
146
146
|
# @param namespace [String] The namespace to search in
|
147
147
|
# @param filter [String] The filter to use
|
@@ -29,7 +29,7 @@ module Langchain::Vectorsearch
|
|
29
29
|
end
|
30
30
|
|
31
31
|
# Find records by ids
|
32
|
-
# @param ids [Array] The ids to find
|
32
|
+
# @param ids [Array<Integer>] The ids to find
|
33
33
|
# @return [Hash] The response from the server
|
34
34
|
def find(ids: [])
|
35
35
|
client.points.get_all(
|
@@ -41,7 +41,7 @@ module Langchain::Vectorsearch
|
|
41
41
|
end
|
42
42
|
|
43
43
|
# Add a list of texts to the index
|
44
|
-
# @param texts [Array] The list of texts to add
|
44
|
+
# @param texts [Array<String>] The list of texts to add
|
45
45
|
# @return [Hash] The response from the server
|
46
46
|
def add_texts(texts:, ids: [])
|
47
47
|
batch = {ids: [], vectors: [], payloads: []}
|
@@ -49,7 +49,7 @@ module Langchain::Vectorsearch
|
|
49
49
|
Array(texts).each_with_index do |text, i|
|
50
50
|
id = ids[i] || SecureRandom.uuid
|
51
51
|
batch[:ids].push(id)
|
52
|
-
batch[:vectors].push(llm.embed(text: text))
|
52
|
+
batch[:vectors].push(llm.embed(text: text).embedding)
|
53
53
|
batch[:payloads].push({content: text})
|
54
54
|
end
|
55
55
|
|
@@ -95,7 +95,7 @@ module Langchain::Vectorsearch
|
|
95
95
|
query:,
|
96
96
|
k: 4
|
97
97
|
)
|
98
|
-
embedding = llm.embed(text: query)
|
98
|
+
embedding = llm.embed(text: query).embedding
|
99
99
|
|
100
100
|
similarity_search_by_vector(
|
101
101
|
embedding: embedding,
|
@@ -104,7 +104,7 @@ module Langchain::Vectorsearch
|
|
104
104
|
end
|
105
105
|
|
106
106
|
# Search for similar texts by embedding
|
107
|
-
# @param embedding [Array] The embedding to search for
|
107
|
+
# @param embedding [Array<Float>] The embedding to search for
|
108
108
|
# @param k [Integer] The number of results to return
|
109
109
|
# @return [Hash] The response from the server
|
110
110
|
def similarity_search_by_vector(
|
@@ -32,7 +32,7 @@ module Langchain::Vectorsearch
|
|
32
32
|
end
|
33
33
|
|
34
34
|
# Add a list of texts to the index
|
35
|
-
# @param texts [Array] The list of texts to add
|
35
|
+
# @param texts [Array<String>] The list of texts to add
|
36
36
|
# @return [Hash] The response from the server
|
37
37
|
def add_texts(texts:, ids: [])
|
38
38
|
client.objects.batch_create(
|
@@ -41,7 +41,7 @@ module Langchain::Vectorsearch
|
|
41
41
|
end
|
42
42
|
|
43
43
|
# Update a list of texts in the index
|
44
|
-
# @param texts [Array] The list of texts to update
|
44
|
+
# @param texts [Array<String>] The list of texts to update
|
45
45
|
# @return [Hash] The response from the server
|
46
46
|
def update_texts(texts:, ids:)
|
47
47
|
uuids = []
|
@@ -65,7 +65,7 @@ module Langchain::Vectorsearch
|
|
65
65
|
__id: ids[i].to_s,
|
66
66
|
content: text
|
67
67
|
},
|
68
|
-
vector: llm.embed(text: text)
|
68
|
+
vector: llm.embed(text: text).embedding
|
69
69
|
)
|
70
70
|
end
|
71
71
|
end
|
@@ -101,13 +101,13 @@ module Langchain::Vectorsearch
|
|
101
101
|
# @param k [Integer|String] The number of results to return
|
102
102
|
# @return [Hash] The search results
|
103
103
|
def similarity_search(query:, k: 4)
|
104
|
-
embedding = llm.embed(text: query)
|
104
|
+
embedding = llm.embed(text: query).embedding
|
105
105
|
|
106
106
|
similarity_search_by_vector(embedding: embedding, k: k)
|
107
107
|
end
|
108
108
|
|
109
109
|
# Return documents similar to the vector
|
110
|
-
# @param embedding [Array] The vector to search for
|
110
|
+
# @param embedding [Array<Float>] The vector to search for
|
111
111
|
# @param k [Integer|String] The number of results to return
|
112
112
|
# @return [Hash] The search results
|
113
113
|
def similarity_search_by_vector(embedding:, k: 4)
|
@@ -154,7 +154,7 @@ module Langchain::Vectorsearch
|
|
154
154
|
__id: id.to_s,
|
155
155
|
content: text
|
156
156
|
},
|
157
|
-
vector: llm.embed(text: text)
|
157
|
+
vector: llm.embed(text: text).embedding
|
158
158
|
}
|
159
159
|
end
|
160
160
|
end
|
data/lib/langchain/version.rb
CHANGED
data/lib/langchain.rb
CHANGED
@@ -8,6 +8,7 @@ loader = Zeitwerk::Loader.for_gem
|
|
8
8
|
loader.ignore("#{__dir__}/langchainrb.rb")
|
9
9
|
loader.inflector.inflect(
|
10
10
|
"ai21" => "AI21",
|
11
|
+
"ai21_response" => "AI21Response",
|
11
12
|
"ai21_validator" => "AI21Validator",
|
12
13
|
"csv" => "CSV",
|
13
14
|
"html" => "HTML",
|
@@ -16,10 +17,12 @@ loader.inflector.inflect(
|
|
16
17
|
"llm" => "LLM",
|
17
18
|
"openai" => "OpenAI",
|
18
19
|
"openai_validator" => "OpenAIValidator",
|
20
|
+
"openai_response" => "OpenAIResponse",
|
19
21
|
"pdf" => "PDF",
|
20
22
|
"react_agent" => "ReActAgent",
|
21
23
|
"sql_query_agent" => "SQLQueryAgent"
|
22
24
|
)
|
25
|
+
loader.collapse("#{__dir__}/langchain/llm/response")
|
23
26
|
loader.setup
|
24
27
|
|
25
28
|
# Langchain.rb a is library for building LLM-backed Ruby applications. It is an abstraction layer that sits on top of the emerging AI-related tools that makes it easy for developers to consume and string those services together.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: langchainrb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.18
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrei Bondarev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-10-
|
11
|
+
date: 2023-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: baran
|
@@ -532,6 +532,7 @@ files:
|
|
532
532
|
- lib/langchain/agent/sql_query_agent.rb
|
533
533
|
- lib/langchain/agent/sql_query_agent/sql_query_agent_answer_prompt.yaml
|
534
534
|
- lib/langchain/agent/sql_query_agent/sql_query_agent_sql_prompt.yaml
|
535
|
+
- lib/langchain/chunk.rb
|
535
536
|
- lib/langchain/chunker/base.rb
|
536
537
|
- lib/langchain/chunker/prompts/semantic_prompt_template.yml
|
537
538
|
- lib/langchain/chunker/recursive_text.rb
|
@@ -558,6 +559,15 @@ files:
|
|
558
559
|
- lib/langchain/llm/openai.rb
|
559
560
|
- lib/langchain/llm/prompts/summarize_template.yaml
|
560
561
|
- lib/langchain/llm/replicate.rb
|
562
|
+
- lib/langchain/llm/response/ai21_response.rb
|
563
|
+
- lib/langchain/llm/response/anthropic_response.rb
|
564
|
+
- lib/langchain/llm/response/base_response.rb
|
565
|
+
- lib/langchain/llm/response/cohere_response.rb
|
566
|
+
- lib/langchain/llm/response/google_palm_response.rb
|
567
|
+
- lib/langchain/llm/response/hugging_face_response.rb
|
568
|
+
- lib/langchain/llm/response/ollama_response.rb
|
569
|
+
- lib/langchain/llm/response/openai_response.rb
|
570
|
+
- lib/langchain/llm/response/replicate_response.rb
|
561
571
|
- lib/langchain/loader.rb
|
562
572
|
- lib/langchain/output_parsers/base.rb
|
563
573
|
- lib/langchain/output_parsers/output_fixing_parser.rb
|