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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +15 -0
  4. data/lib/langchain/active_record/hooks.rb +14 -0
  5. data/lib/langchain/agent/react_agent.rb +1 -1
  6. data/lib/langchain/agent/sql_query_agent.rb +2 -2
  7. data/lib/langchain/chunk.rb +16 -0
  8. data/lib/langchain/chunker/base.rb +4 -0
  9. data/lib/langchain/chunker/recursive_text.rb +5 -2
  10. data/lib/langchain/chunker/semantic.rb +4 -1
  11. data/lib/langchain/chunker/sentence.rb +4 -2
  12. data/lib/langchain/chunker/text.rb +5 -2
  13. data/lib/langchain/conversation.rb +1 -1
  14. data/lib/langchain/llm/ai21.rb +4 -3
  15. data/lib/langchain/llm/anthropic.rb +3 -3
  16. data/lib/langchain/llm/cohere.rb +6 -5
  17. data/lib/langchain/llm/google_palm.rb +14 -10
  18. data/lib/langchain/llm/hugging_face.rb +4 -3
  19. data/lib/langchain/llm/llama_cpp.rb +1 -1
  20. data/lib/langchain/llm/ollama.rb +18 -6
  21. data/lib/langchain/llm/openai.rb +7 -6
  22. data/lib/langchain/llm/replicate.rb +6 -10
  23. data/lib/langchain/llm/response/ai21_response.rb +13 -0
  24. data/lib/langchain/llm/response/anthropic_response.rb +29 -0
  25. data/lib/langchain/llm/response/base_response.rb +79 -0
  26. data/lib/langchain/llm/response/cohere_response.rb +21 -0
  27. data/lib/langchain/llm/response/google_palm_response.rb +36 -0
  28. data/lib/langchain/llm/response/hugging_face_response.rb +13 -0
  29. data/lib/langchain/llm/response/ollama_response.rb +26 -0
  30. data/lib/langchain/llm/response/openai_response.rb +51 -0
  31. data/lib/langchain/llm/response/replicate_response.rb +28 -0
  32. data/lib/langchain/vectorsearch/base.rb +1 -1
  33. data/lib/langchain/vectorsearch/chroma.rb +5 -5
  34. data/lib/langchain/vectorsearch/hnswlib.rb +5 -5
  35. data/lib/langchain/vectorsearch/milvus.rb +2 -2
  36. data/lib/langchain/vectorsearch/pgvector.rb +3 -3
  37. data/lib/langchain/vectorsearch/pinecone.rb +10 -10
  38. data/lib/langchain/vectorsearch/qdrant.rb +5 -5
  39. data/lib/langchain/vectorsearch/weaviate.rb +6 -6
  40. data/lib/langchain/version.rb +1 -1
  41. data/lib/langchain.rb +3 -0
  42. metadata +12 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b9bca59bfb5909f6ac24ebf6dba6074f5faf3d2cdadab1a3b3a8a0f75f98adc
4
- data.tar.gz: a202726d383d2dc691cb4146e9b36cb7ea6f8ac35382a3df67f6e11d35b3562e
3
+ metadata.gz: 437c6387ded139ed1a513414bfb7242cdbadf1ba6526c7a89346aa2fa9490fc2
4
+ data.tar.gz: dd6f437a4bbc4807a16631dd790f66c9de4e9456011b2c4f84302fe3fab1377b
5
5
  SHA512:
6
- metadata.gz: b4eaf631f22236035c9e29b3618a70d14487cc9e39b6885e44497ebad2a98670ce88997fdb25144b6467e0caa69a04ce7e625c9e10bc88322131181c2254a570
7
- data.tar.gz: 981199fe2a0123e46ac3af54946c03d5eaa827473eae02f2e60accd0c680a0bbd40741800e05b79e890038523a1b910502a6cf4ed1f4ebf77845f4b2a2dbc5d9
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
@@ -13,6 +13,10 @@ module Langchain
13
13
  # - {Langchain::Chunker::Semantic}
14
14
  # - {Langchain::Chunker::Sentence}
15
15
  class Base
16
+ # @return [Array<Langchain::Chunk>]
17
+ def chunks
18
+ raise NotImplementedError
19
+ end
16
20
  end
17
21
  end
18
22
  end
@@ -24,14 +24,17 @@ module Langchain
24
24
  @separators = separators
25
25
  end
26
26
 
27
- # @return [Array<String>]
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
- splitter.chunks(text)
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<String>]
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<String>]
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<String>]
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
- splitter.chunks(text)
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
@@ -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 [String] The completion
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
- response.dig(:completions, 0, :data, :text)
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 [String] The completion
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
- response.dig("completion")
46
+ Langchain::LLM::AnthropicResponse.new(response)
47
47
  end
48
48
 
49
49
  private
@@ -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: "YOUR_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 [Hash] The embedding
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
- response.dig("embeddings").first
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 [Hash] The completion
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.dig("generations").first.dig("text")
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: "YOUR_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 [Array] The embedding
37
+ # @return [Langchain::LLM::GooglePalmResponse] Response object
38
38
  #
39
39
  def embed(text:)
40
- response = client.embed(
41
- text: text
42
- )
43
- response.dig("embedding", "value")
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 [String] The completion
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
- response.dig("candidates", 0, "output")
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 [String] The chat completion
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
- response.dig("candidates", 0, "content")
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: "YOUR_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 [Array] The embedding
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
@@ -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 [String] The completed prompt
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"] = model || DEFAULTS[:completion_model_name]
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"] = model || DEFAULTS[:embeddings_model_name]
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.dig("embedding")
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
@@ -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 [Array] The embedding
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
- response.dig("data").first.dig("embedding")
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 [String] The completion
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
- response.dig("choices", 0, "message", "content")
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 [String|Array<String>] The chat completion
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
- extract_response response
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 [Hash] The embedding
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.output
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 [Hash] The completion
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
- # Response comes back as an array of strings, e.g.: ["Hi", "how ", "are ", "you?"]
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,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Langchain::LLM
4
+ class AI21Response < BaseResponse
5
+ def completions
6
+ raw_response.dig(:completions)
7
+ end
8
+
9
+ def completion
10
+ completions.dig(0, :data, :text)
11
+ end
12
+ end
13
+ end
@@ -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,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Langchain::LLM
4
+ class HuggingFaceResponse < BaseResponse
5
+ def embeddings
6
+ [raw_response]
7
+ end
8
+
9
+ def embedding
10
+ embeddings.first
11
+ end
12
+ end
13
+ 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
@@ -184,7 +184,7 @@ module Langchain::Vectorsearch
184
184
  .flatten
185
185
  .map do |path|
186
186
  data = Langchain::Loader.new(path)&.load&.chunks
187
- data.map { |chunk| chunk[:text] }
187
+ data.map { |chunk| chunk.text }
188
188
  end
189
189
 
190
190
  texts.flatten!
@@ -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[:text] }
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Langchain
4
- VERSION = "0.6.17"
4
+ VERSION = "0.6.18"
5
5
  end
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.17
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-10 00:00:00.000000000 Z
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