langchainrb 0.9.2 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +12 -19
  4. data/lib/langchain/agent/react_agent.rb +2 -0
  5. data/lib/langchain/agent/sql_query_agent.rb +2 -0
  6. data/lib/langchain/assistants/assistant.rb +8 -24
  7. data/lib/langchain/assistants/thread.rb +2 -2
  8. data/lib/langchain/chunker/markdown.rb +0 -2
  9. data/lib/langchain/chunker/recursive_text.rb +0 -2
  10. data/lib/langchain/chunker/semantic.rb +1 -3
  11. data/lib/langchain/chunker/sentence.rb +0 -2
  12. data/lib/langchain/chunker/text.rb +0 -2
  13. data/lib/langchain/contextual_logger.rb +1 -1
  14. data/lib/langchain/conversation/memory.rb +2 -0
  15. data/lib/langchain/conversation/message.rb +2 -0
  16. data/lib/langchain/llm/ollama.rb +40 -3
  17. data/lib/langchain/llm/openai.rb +16 -4
  18. data/lib/langchain/llm/prompts/ollama/summarize_template.yaml +9 -0
  19. data/lib/langchain/output_parsers/base.rb +0 -4
  20. data/lib/langchain/output_parsers/output_fixing_parser.rb +6 -13
  21. data/lib/langchain/output_parsers/structured_output_parser.rb +0 -10
  22. data/lib/langchain/processors/eml.rb +65 -0
  23. data/lib/langchain/tool/base.rb +17 -32
  24. data/lib/langchain/tool/calculator/calculator.json +19 -0
  25. data/lib/langchain/tool/{calculator.rb → calculator/calculator.rb} +8 -5
  26. data/lib/langchain/tool/database/database.json +46 -0
  27. data/lib/langchain/tool/database/database.rb +105 -0
  28. data/lib/langchain/tool/google_search/google_search.json +19 -0
  29. data/lib/langchain/tool/{google_search.rb → google_search/google_search.rb} +5 -6
  30. data/lib/langchain/tool/ruby_code_interpreter/ruby_code_interpreter.json +19 -0
  31. data/lib/langchain/tool/{ruby_code_interpreter.rb → ruby_code_interpreter/ruby_code_interpreter.rb} +9 -1
  32. data/lib/langchain/tool/weather/weather.json +19 -0
  33. data/lib/langchain/tool/{weather.rb → weather/weather.rb} +3 -4
  34. data/lib/langchain/tool/wikipedia/wikipedia.json +19 -0
  35. data/lib/langchain/tool/{wikipedia.rb → wikipedia/wikipedia.rb} +10 -1
  36. data/lib/langchain/vectorsearch/base.rb +1 -1
  37. data/lib/langchain/version.rb +1 -1
  38. data/lib/langchain.rb +8 -1
  39. metadata +80 -16
  40. data/lib/langchain/tool/database.rb +0 -90
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cdaafd0889d6666c7aa39d8bee71763f8baf86e0566f9e87312fc6033d07709d
4
- data.tar.gz: 7acc9f122aed92eab9ab2ac1d50f7ee59c0e24030335dc15878769b7664ffc6b
3
+ metadata.gz: 62c459d5dc2f716eaeb81697bdf45ad42ae168784d28ff8a80a89d1b3e14eadd
4
+ data.tar.gz: 8bb1f94373c54619235cb24ea705179626e398d517739b93014a514283068468
5
5
  SHA512:
6
- metadata.gz: b76f62411f75eccba98371791e63b18f0f22225de1af7449cde40680acbd1dc09c4b5a6b7eeb1ac667dd9b029c52534fbfbe10a5fa465fa0859059ddb32a400c
7
- data.tar.gz: 64052a22206ece081a2fd9fbf0233ba47f40539743b1def6d7fc9beeb31102f5559878514cbc0d503fd13681e5efbb34c2755cacbd62b1b01b67876bc9d6237e
6
+ metadata.gz: 4b6bd3fb3a983458dd0ff83573e268c4ab8ae26fcffbab93826d3f3143a648b3fa2fcb9e93ba1139551cf8b6d8641da74ea78d098e42ecd672245ca41610c137
7
+ data.tar.gz: a40d5bfb0301e7e9e4d66a708fc6bc048272da772bad21473f88be219caf139c86f8cbcf9ea73a3454642042872e796595518a75eb5e9ad3ba5288adf823bfc7
data/CHANGELOG.md CHANGED
@@ -1,4 +1,15 @@
1
1
  ## [Unreleased]
2
+ - `Langchain::LLM::Ollama` can now `#summarize`
3
+
4
+ ## [0.9.4]
5
+ - New `Ollama#summarize()` method
6
+ - Improved README
7
+ - Fixes + specs
8
+
9
+ ## [0.9.3]
10
+ - Add EML processor
11
+ - Tools can support multiple-methods
12
+ - Bump gems and bug fixes
2
13
 
3
14
  ## [0.9.2]
4
15
  - Fix vectorsearch#ask methods
data/README.md CHANGED
@@ -42,7 +42,7 @@ If bundler is not being used to manage dependencies, install the gem by executin
42
42
 
43
43
  gem install langchainrb
44
44
 
45
- Additional gems may be required when loading LLM Providers. These are not included by default so you can include only what you need.
45
+ Additional gems may be required. They're not included by default so you can include only what you need.
46
46
 
47
47
  ## Usage
48
48
 
@@ -51,10 +51,10 @@ require "langchain"
51
51
  ```
52
52
 
53
53
  ## Large Language Models (LLMs)
54
- Langchain.rb wraps all supported LLMs in a unified interface allowing you to easily swap out and test out different models.
54
+ Langchain.rb wraps supported LLMs in a unified interface allowing you to easily swap out and test out different models.
55
55
 
56
56
  #### Supported LLMs and features:
57
- | LLM providers | embed() | complete() | chat() | summarize() | Notes |
57
+ | LLM providers | `embed()` | `complete()` | `chat()` | `summarize()` | Notes |
58
58
  | -------- |:------------------:| :-------: | :-----------------: | :-------: | :----------------- |
59
59
  | [OpenAI](https://openai.com/?utm_source=langchainrb&utm_medium=github) | ✅ | ✅ | ✅ | ❌ | Including Azure OpenAI |
60
60
  | [AI21](https://ai21.com/?utm_source=langchainrb&utm_medium=github) | ❌ | ✅ | ❌ | ✅ | |
@@ -64,7 +64,7 @@ Langchain.rb wraps all supported LLMs in a unified interface allowing you to eas
64
64
  | [GooglePalm](https://ai.google/discover/palm2?utm_source=langchainrb&utm_medium=github) | ✅ | ✅ | ✅ | ✅ | |
65
65
  | [Google Vertex AI](https://cloud.google.com/vertex-ai?utm_source=langchainrb&utm_medium=github) | ✅ | ✅ | ❌ | ✅ | |
66
66
  | [HuggingFace](https://huggingface.co/?utm_source=langchainrb&utm_medium=github) | ✅ | ❌ | ❌ | ❌ | |
67
- | [Ollama](https://ollama.ai/?utm_source=langchainrb&utm_medium=github) | ✅ | ✅ | ✅ | | |
67
+ | [Ollama](https://ollama.ai/?utm_source=langchainrb&utm_medium=github) | ✅ | ✅ | ✅ | | |
68
68
  | [Replicate](https://replicate.com/?utm_source=langchainrb&utm_medium=github) | ✅ | ✅ | ✅ | ✅ | |
69
69
 
70
70
  #### Using standalone LLMs:
@@ -83,12 +83,7 @@ llm = Langchain::LLM::OpenAI.new(api_key: ENV["OPENAI_API_KEY"], llm_options: {
83
83
 
84
84
  Generate vector embeddings:
85
85
  ```ruby
86
- llm.embed(text: "foo bar")
87
- ```
88
-
89
- Generate a text completion:
90
- ```ruby
91
- llm.complete(prompt: "What is the meaning of life?").completion
86
+ llm.embed(text: "foo bar").embedding
92
87
  ```
93
88
 
94
89
  Generate a chat completion:
@@ -249,7 +244,7 @@ Then parse the llm response:
249
244
 
250
245
  ```ruby
251
246
  llm = Langchain::LLM::OpenAI.new(api_key: ENV["OPENAI_API_KEY"])
252
- llm_response = llm.chat(prompt: prompt_text).completion
247
+ llm_response = llm.chat(messages: [{role: "user", content: prompt_text}]).completion
253
248
  parser.parse(llm_response)
254
249
  # {
255
250
  # "name" => "Kim Ji-hyun",
@@ -373,7 +368,7 @@ my_docx = Langchain.root.join("path/to/my.docx")
373
368
 
374
369
  client.add_data(paths: [my_pdf, my_text, my_docx])
375
370
  ```
376
- Supported file formats: docx, html, pdf, text, json, jsonl, csv, xlsx.
371
+ Supported file formats: docx, html, pdf, text, json, jsonl, csv, xlsx, eml.
377
372
 
378
373
  Retrieve similar documents based on the query string passed in:
379
374
  ```ruby
@@ -398,14 +393,9 @@ client.similarity_search_by_vector(
398
393
 
399
394
  RAG-based querying
400
395
  ```ruby
401
- client.ask(
402
- question:
403
- )
396
+ client.ask(question: "...")
404
397
  ```
405
398
 
406
- ## Evaluations (Evals)
407
- The Evaluations module is a collection of tools that can be used to evaluate and track the performance of the output products by LLM and your RAG (Retrieval Augmented Generation) pipelines.
408
-
409
399
  ## Assistants
410
400
  Assistants are Agent-like objects that leverage helpful instructions, LLMs, tools and knowledge to respond to user queries. Assistants can be configured with an LLM of your choice (currently only OpenAI), any vector search database and easily extended with additional tools.
411
401
 
@@ -473,6 +463,9 @@ assistant.thread.messages
473
463
 
474
464
  The Assistant checks the context window limits before every request to the LLM and remove oldest thread messages one by one if the context window is exceeded.
475
465
 
466
+ ## Evaluations (Evals)
467
+ The Evaluations module is a collection of tools that can be used to evaluate and track the performance of the output products by LLM and your RAG (Retrieval Augmented Generation) pipelines.
468
+
476
469
  ### RAGAS
477
470
  Ragas helps you evaluate your Retrieval Augmented Generation (RAG) pipelines. The implementation is based on this [paper](https://arxiv.org/abs/2309.15217) and the original Python [repo](https://github.com/explodinggradients/ragas). Ragas tracks the following 3 metrics and assigns the 0.0 - 1.0 scores:
478
471
  * Faithfulness - the answer is grounded in the given context.
@@ -501,7 +494,7 @@ Additional examples available: [/examples](https://github.com/andreibondarev/lan
501
494
 
502
495
  ## Logging
503
496
 
504
- LangChain.rb uses standard logging mechanisms and defaults to `:warn` level. Most messages are at info level, but we will add debug or warn statements as needed.
497
+ Langchain.rb uses standard logging mechanisms and defaults to `:warn` level. Most messages are at info level, but we will add debug or warn statements as needed.
505
498
  To show all log messages:
506
499
 
507
500
  ```ruby
@@ -26,6 +26,8 @@ module Langchain::Agent
26
26
  # @param max_iterations [Integer] The maximum number of iterations to run
27
27
  # @return [ReActAgent] The Agent::ReActAgent instance
28
28
  def initialize(llm:, tools: [], max_iterations: 10)
29
+ warn "[DEPRECATION] `Langchain::Agent::ReActAgent` is deprecated. Please use `Langchain::Assistant` instead."
30
+
29
31
  Langchain::Tool::Base.validate_tools!(tools: tools)
30
32
 
31
33
  @tools = tools
@@ -11,6 +11,8 @@ module Langchain::Agent
11
11
  # @param db [Object] Database connection info
12
12
  #
13
13
  def initialize(llm:, db:)
14
+ warn "[DEPRECATION] `Langchain::Agent::ReActAgent` is deprecated. Please use `Langchain::Assistant` instead."
15
+
14
16
  @llm = llm
15
17
  @db = db
16
18
  @schema = @db.dump_schema
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Langchain
4
+ # Assistants are Agent-like objects that leverage helpful instructions, LLMs, tools and knowledge to respond to user queries.
5
+ # Assistants can be configured with an LLM of your choice (currently only OpenAI), any vector search database and easily extended with additional tools.
4
6
  class Assistant
5
7
  attr_reader :llm, :thread, :instructions
6
8
  attr_accessor :tools
@@ -127,7 +129,7 @@ module Langchain
127
129
  params = {messages: thread.openai_messages}
128
130
 
129
131
  if tools.any?
130
- params[:tools] = tools.map(&:to_openai_tool)
132
+ params[:tools] = tools.map(&:to_openai_tools).flatten
131
133
  # TODO: Not sure that tool_choice should always be "auto"; Maybe we can let the user toggle it.
132
134
  params[:tool_choice] = "auto"
133
135
  end
@@ -142,14 +144,16 @@ module Langchain
142
144
  # Iterate over each function invocation and submit tool output
143
145
  tool_calls.each do |tool_call|
144
146
  tool_call_id = tool_call.dig("id")
145
- tool_name = tool_call.dig("function", "name")
147
+
148
+ function_name = tool_call.dig("function", "name")
149
+ tool_name, method_name = function_name.split("-")
146
150
  tool_arguments = JSON.parse(tool_call.dig("function", "arguments"), symbolize_names: true)
147
151
 
148
152
  tool_instance = tools.find do |t|
149
153
  t.name == tool_name
150
154
  end or raise ArgumentError, "Tool not found in assistant.tools"
151
155
 
152
- output = tool_instance.execute(**tool_arguments)
156
+ output = tool_instance.send(method_name, **tool_arguments)
153
157
 
154
158
  submit_tool_output(tool_call_id: tool_call_id, output: output)
155
159
  end
@@ -174,26 +178,6 @@ module Langchain
174
178
  Message.new(role: role, content: content, tool_calls: tool_calls, tool_call_id: tool_call_id)
175
179
  end
176
180
 
177
- # # TODO: Fix the message truncation when context window is exceeded
178
- # def build_assistant_prompt(instructions:, tools:)
179
- # while begin
180
- # # Check if the prompt exceeds the context window
181
- # # Return false to exit the while loop
182
- # !llm.class.const_get(:LENGTH_VALIDATOR).validate_max_tokens!(
183
- # thread.messages,
184
- # llm.defaults[:chat_completion_model_name],
185
- # {llm: llm}
186
- # )
187
- # # Rescue error if context window is exceeded and return true to continue the while loop
188
- # rescue Langchain::Utils::TokenLength::TokenLimitExceeded
189
- # # Should be using `retry` instead of while()
190
- # true
191
- # end
192
- # # Truncate the oldest messages when the context window is exceeded
193
- # thread.messages.shift
194
- # end
195
-
196
- # prompt
197
- # end
181
+ # TODO: Fix the message truncation when context window is exceeded
198
182
  end
199
183
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Langchain
4
- # Langchain::Thread keeps track of messages in a conversation
5
- # Eventually we may want to add functionality to persist to the thread to disk, DB, storage, etc.
4
+ # Langchain::Thread keeps track of messages in a conversation.
5
+ # TODO: Add functionality to persist to the thread to disk, DB, storage, etc.
6
6
  class Thread
7
7
  attr_accessor :messages
8
8
 
@@ -4,12 +4,10 @@ require "baran"
4
4
 
5
5
  module Langchain
6
6
  module Chunker
7
- #
8
7
  # Simple text chunker
9
8
  #
10
9
  # Usage:
11
10
  # Langchain::Chunker::Markdown.new(text).chunks
12
- #
13
11
  class Markdown < Base
14
12
  attr_reader :text, :chunk_size, :chunk_overlap
15
13
 
@@ -4,12 +4,10 @@ require "baran"
4
4
 
5
5
  module Langchain
6
6
  module Chunker
7
- #
8
7
  # Recursive text chunker. Preferentially splits on separators.
9
8
  #
10
9
  # Usage:
11
10
  # Langchain::Chunker::RecursiveText.new(text).chunks
12
- #
13
11
  class RecursiveText < Base
14
12
  attr_reader :text, :chunk_size, :chunk_overlap, :separators
15
13
 
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Langchain
4
4
  module Chunker
5
- #
6
5
  # LLM-powered semantic chunker.
7
6
  # Semantic chunking is a technique of splitting texts by their semantic meaning, e.g.: themes, topics, and ideas.
8
7
  # We use an LLM to accomplish this. The Anthropic LLM is highly recommended for this task as it has the longest context window (100k tokens).
@@ -12,7 +11,6 @@ module Langchain
12
11
  # text,
13
12
  # llm: Langchain::LLM::Anthropic.new(api_key: ENV["ANTHROPIC_API_KEY"])
14
13
  # ).chunks
15
- #
16
14
  class Semantic < Base
17
15
  attr_reader :text, :llm, :prompt_template
18
16
  # @param [Langchain::LLM::Base] Langchain::LLM::* instance
@@ -28,7 +26,7 @@ module Langchain
28
26
  prompt = prompt_template.format(text: text)
29
27
 
30
28
  # Replace static 50k limit with dynamic limit based on text length (max_tokens_to_sample)
31
- completion = llm.complete(prompt: prompt, max_tokens_to_sample: 50000)
29
+ completion = llm.complete(prompt: prompt, max_tokens_to_sample: 50000).completion
32
30
  completion
33
31
  .gsub("Here are the paragraphs split by topic:\n\n", "")
34
32
  .split("---")
@@ -4,12 +4,10 @@ require "pragmatic_segmenter"
4
4
 
5
5
  module Langchain
6
6
  module Chunker
7
- #
8
7
  # This chunker splits text by sentences.
9
8
  #
10
9
  # Usage:
11
10
  # Langchain::Chunker::Sentence.new(text).chunks
12
- #
13
11
  class Sentence < Base
14
12
  attr_reader :text
15
13
 
@@ -4,12 +4,10 @@ require "baran"
4
4
 
5
5
  module Langchain
6
6
  module Chunker
7
- #
8
7
  # Simple text chunker
9
8
  #
10
9
  # Usage:
11
10
  # Langchain::Chunker::Text.new(text).chunks
12
- #
13
11
  class Text < Base
14
12
  attr_reader :text, :chunk_size, :chunk_overlap, :separator
15
13
 
@@ -42,7 +42,7 @@ module Langchain
42
42
  for_class_name = for_class&.name
43
43
 
44
44
  log_line_parts = []
45
- log_line_parts << "[LangChain.rb]".colorize(color: :yellow)
45
+ log_line_parts << "[Langchain.rb]".colorize(color: :yellow)
46
46
  log_line_parts << if for_class.respond_to?(:logger_options)
47
47
  "[#{for_class_name}]".colorize(for_class.logger_options) + ":"
48
48
  elsif for_class_name
@@ -9,6 +9,8 @@ module Langchain
9
9
  TOKEN_LEEWAY = 20
10
10
 
11
11
  def initialize(llm:, messages: [], **options)
12
+ warn "[DEPRECATION] `Langchain::Conversation::Memory` is deprecated. Please use `Langchain::Assistant` instead."
13
+
12
14
  @llm = llm
13
15
  @context = nil
14
16
  @summary = nil
@@ -12,6 +12,8 @@ module Langchain
12
12
  }
13
13
 
14
14
  def initialize(content)
15
+ warn "[DEPRECATION] `Langchain::Conversation::*` is deprecated. Please use `Langchain::Assistant` and `Langchain::Messages` classes instead."
16
+
15
17
  @content = content
16
18
  end
17
19
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/hash"
4
+
3
5
  module Langchain::LLM
4
6
  # Interface to Ollama API.
5
7
  # Available models: https://ollama.ai/library
@@ -17,6 +19,16 @@ module Langchain::LLM
17
19
  chat_completion_model_name: "llama2"
18
20
  }.freeze
19
21
 
22
+ EMBEDDING_SIZES = {
23
+ codellama: 4_096,
24
+ "dolphin-mixtral": 4_096,
25
+ llama2: 4_096,
26
+ llava: 4_096,
27
+ mistral: 4_096,
28
+ "mistral-openorca": 4_096,
29
+ mixtral: 4_096
30
+ }.freeze
31
+
20
32
  # Initialize the Ollama client
21
33
  # @param url [String] The URL of the Ollama instance
22
34
  # @param default_options [Hash] The default options to use
@@ -24,7 +36,17 @@ module Langchain::LLM
24
36
  def initialize(url:, default_options: {})
25
37
  depends_on "faraday"
26
38
  @url = url
27
- @defaults = DEFAULTS.merge(default_options)
39
+ @defaults = DEFAULTS.deep_merge(default_options)
40
+ end
41
+
42
+ # Returns the # of vector dimensions for the embeddings
43
+ # @return [Integer] The # of vector dimensions
44
+ def default_dimension
45
+ # since Ollama can run multiple models, look it up or generate an embedding and return the size
46
+ @default_dimension ||=
47
+ EMBEDDING_SIZES.fetch(defaults[:embeddings_model_name].to_sym) do
48
+ embed(text: "test").embedding.size
49
+ end
28
50
  end
29
51
 
30
52
  #
@@ -108,9 +130,11 @@ module Langchain::LLM
108
130
  req.body = parameters
109
131
 
110
132
  req.options.on_data = proc do |chunk, size|
111
- json_chunk = JSON.parse(chunk)
133
+ chunk.split("\n").each do |line_chunk|
134
+ json_chunk = JSON.parse(line_chunk)
112
135
 
113
- response += json_chunk.dig("response")
136
+ response += json_chunk.dig("response")
137
+ end
114
138
 
115
139
  yield json_chunk, size if block
116
140
  end
@@ -217,6 +241,19 @@ module Langchain::LLM
217
241
  Langchain::LLM::OllamaResponse.new(response.body, model: parameters[:model])
218
242
  end
219
243
 
244
+ # Generate a summary for a given text
245
+ #
246
+ # @param text [String] The text to generate a summary for
247
+ # @return [String] The summary
248
+ def summarize(text:)
249
+ prompt_template = Langchain::Prompt.load_from_path(
250
+ file_path: Langchain.root.join("langchain/llm/prompts/ollama/summarize_template.yaml")
251
+ )
252
+ prompt = prompt_template.format(text: text)
253
+
254
+ complete(prompt: prompt)
255
+ end
256
+
220
257
  private
221
258
 
222
259
  # @return [Faraday::Connection] Faraday client
@@ -9,7 +9,7 @@ module Langchain::LLM
9
9
  # Usage:
10
10
  # openai = Langchain::LLM::OpenAI.new(
11
11
  # api_key: ENV["OPENAI_API_KEY"],
12
- # llm_options: {},
12
+ # llm_options: {}, # Available options: https://github.com/alexrudall/ruby-openai/blob/main/lib/openai/client.rb#L5-L13
13
13
  # default_options: {}
14
14
  # )
15
15
  class OpenAI < Base
@@ -17,8 +17,13 @@ module Langchain::LLM
17
17
  n: 1,
18
18
  temperature: 0.0,
19
19
  chat_completion_model_name: "gpt-3.5-turbo",
20
- embeddings_model_name: "text-embedding-ada-002",
21
- dimension: 1536
20
+ embeddings_model_name: "text-embedding-ada-002"
21
+ }.freeze
22
+
23
+ EMBEDDING_SIZES = {
24
+ "text-embedding-ada-002": 1536,
25
+ "text-embedding-3-large": 3072,
26
+ "text-embedding-3-small": 1536
22
27
  }.freeze
23
28
 
24
29
  LENGTH_VALIDATOR = Langchain::Utils::TokenLength::OpenAIValidator
@@ -56,7 +61,8 @@ module Langchain::LLM
56
61
 
57
62
  parameters = {
58
63
  input: text,
59
- model: model
64
+ model: model,
65
+ dimensions: default_dimension
60
66
  }
61
67
  parameters[:encoding_format] = encoding_format if encoding_format
62
68
  parameters[:user] = user if user
@@ -77,6 +83,8 @@ module Langchain::LLM
77
83
  # @param params [Hash] The parameters to pass to the `chat()` method
78
84
  # @return [Langchain::LLM::OpenAIResponse] Response object
79
85
  def complete(prompt:, **params)
86
+ warn "DEPRECATED: `Langchain::LLM::OpenAI#complete` is deprecated, and will be removed in the next major version. Use `Langchain::LLM::OpenAI#chat` instead."
87
+
80
88
  if params[:stop_sequences]
81
89
  params[:stop] = params.delete(:stop_sequences)
82
90
  end
@@ -170,6 +178,10 @@ module Langchain::LLM
170
178
  complete(prompt: prompt)
171
179
  end
172
180
 
181
+ def default_dimension
182
+ @defaults[:dimension] || EMBEDDING_SIZES.fetch(defaults[:embeddings_model_name].to_sym)
183
+ end
184
+
173
185
  private
174
186
 
175
187
  attr_reader :response_chunks
@@ -0,0 +1,9 @@
1
+ _type: prompt
2
+ input_variables:
3
+ - text
4
+ template: |
5
+ Write a concise summary of the following TEXT. Do not include the word summary, just provide the summary.
6
+
7
+ TEXT: {text}
8
+
9
+ CONCISE SUMMARY:
@@ -5,18 +5,15 @@ module Langchain::OutputParsers
5
5
  #
6
6
  # @abstract
7
7
  class Base
8
- #
9
8
  # Parse the output of an LLM call.
10
9
  #
11
10
  # @param text - LLM output to parse.
12
11
  #
13
12
  # @return [Object] Parsed output.
14
- #
15
13
  def parse(text:)
16
14
  raise NotImplementedError
17
15
  end
18
16
 
19
- #
20
17
  # Return a string describing the format of the output.
21
18
  #
22
19
  # @return [String] Format instructions.
@@ -27,7 +24,6 @@ module Langchain::OutputParsers
27
24
  # "foo": "bar"
28
25
  # }
29
26
  # ```
30
- #
31
27
  def get_format_instructions
32
28
  raise NotImplementedError
33
29
  end
@@ -6,13 +6,11 @@ module Langchain::OutputParsers
6
6
  class OutputFixingParser < Base
7
7
  attr_reader :llm, :parser, :prompt
8
8
 
9
- #
10
9
  # Initializes a new instance of the class.
11
10
  #
12
11
  # @param llm [Langchain::LLM] The LLM used in the fixing process
13
12
  # @param parser [Langchain::OutputParsers] The parser originally used which resulted in parsing error
14
13
  # @param prompt [Langchain::Prompt::PromptTemplate]
15
- #
16
14
  def initialize(llm:, parser:, prompt:)
17
15
  raise ArgumentError.new("llm must be an instance of Langchain::LLM got: #{llm.class}") unless llm.is_a?(Langchain::LLM::Base)
18
16
  raise ArgumentError.new("parser must be an instance of Langchain::OutputParsers got #{parser.class}") unless parser.is_a?(Langchain::OutputParsers::Base)
@@ -30,17 +28,14 @@ module Langchain::OutputParsers
30
28
  }
31
29
  end
32
30
 
33
- #
34
31
  # calls get_format_instructions on the @parser
35
32
  #
36
33
  # @return [String] Instructions for how the output of a language model should be formatted
37
34
  # according to the @schema.
38
- #
39
35
  def get_format_instructions
40
36
  parser.get_format_instructions
41
37
  end
42
38
 
43
- #
44
39
  # Parse the output of an LLM call, if fails with OutputParserException
45
40
  # then call the LLM with a fix prompt in an attempt to get the correctly
46
41
  # formatted response
@@ -48,21 +43,20 @@ module Langchain::OutputParsers
48
43
  # @param completion [String] Text output from the LLM call
49
44
  #
50
45
  # @return [Object] object that is succesfully parsed by @parser.parse
51
- #
52
46
  def parse(completion)
53
47
  parser.parse(completion)
54
48
  rescue OutputParserException => e
55
49
  new_completion = llm.chat(
56
- prompt: prompt.format(
57
- instructions: parser.get_format_instructions,
58
- completion: completion,
59
- error: e
60
- )
50
+ messages: [{role: "user",
51
+ content: prompt.format(
52
+ instructions: parser.get_format_instructions,
53
+ completion: completion,
54
+ error: e
55
+ )}]
61
56
  ).completion
62
57
  parser.parse(new_completion)
63
58
  end
64
59
 
65
- #
66
60
  # Creates a new instance of the class using the given JSON::Schema.
67
61
  #
68
62
  # @param llm [Langchain::LLM] The LLM used in the fixing process
@@ -70,7 +64,6 @@ module Langchain::OutputParsers
70
64
  # @param prompt [Langchain::Prompt::PromptTemplate]
71
65
  #
72
66
  # @return [Object] A new instance of the class
73
- #
74
67
  def self.from_llm(llm:, parser:, prompt: nil)
75
68
  new(llm: llm, parser: parser, prompt: prompt || naive_fix_prompt)
76
69
  end
@@ -5,15 +5,12 @@ require "json-schema"
5
5
 
6
6
  module Langchain::OutputParsers
7
7
  # = Structured Output Parser
8
- #
9
8
  class StructuredOutputParser < Base
10
9
  attr_reader :schema
11
10
 
12
- #
13
11
  # Initializes a new instance of the class.
14
12
  #
15
13
  # @param schema [JSON::Schema] The json schema
16
- #
17
14
  def initialize(schema:)
18
15
  @schema = validate_schema!(schema)
19
16
  end
@@ -25,24 +22,20 @@ module Langchain::OutputParsers
25
22
  }
26
23
  end
27
24
 
28
- #
29
25
  # Creates a new instance of the class using the given JSON::Schema.
30
26
  #
31
27
  # @param schema [JSON::Schema] The JSON::Schema to use
32
28
  #
33
29
  # @return [Object] A new instance of the class
34
- #
35
30
  def self.from_json_schema(schema)
36
31
  new(schema: schema)
37
32
  end
38
33
 
39
- #
40
34
  # Returns a string containing instructions for how the output of a language model should be formatted
41
35
  # according to the @schema.
42
36
  #
43
37
  # @return [String] Instructions for how the output of a language model should be formatted
44
38
  # according to the @schema.
45
- #
46
39
  def get_format_instructions
47
40
  <<~INSTRUCTIONS
48
41
  You must format your output as a JSON value that adheres to a given "JSON Schema" instance.
@@ -62,13 +55,10 @@ module Langchain::OutputParsers
62
55
  INSTRUCTIONS
63
56
  end
64
57
 
65
- #
66
58
  # Parse the output of an LLM call extracting an object that abides by the @schema
67
59
  #
68
60
  # @param text [String] Text output from the LLM call
69
- #
70
61
  # @return [Object] object that abides by the @schema
71
- #
72
62
  def parse(text)
73
63
  json = text.include?("```") ? text.strip.split(/```(?:json)?/)[1] : text.strip
74
64
  parsed = JSON.parse(json)