langchainrb 0.9.2 → 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +12 -19
- data/lib/langchain/agent/react_agent.rb +2 -0
- data/lib/langchain/agent/sql_query_agent.rb +2 -0
- data/lib/langchain/assistants/assistant.rb +8 -24
- data/lib/langchain/assistants/thread.rb +2 -2
- data/lib/langchain/chunker/markdown.rb +0 -2
- data/lib/langchain/chunker/recursive_text.rb +0 -2
- data/lib/langchain/chunker/semantic.rb +1 -3
- data/lib/langchain/chunker/sentence.rb +0 -2
- data/lib/langchain/chunker/text.rb +0 -2
- data/lib/langchain/contextual_logger.rb +1 -1
- data/lib/langchain/conversation/memory.rb +2 -0
- data/lib/langchain/conversation/message.rb +2 -0
- data/lib/langchain/llm/ollama.rb +40 -3
- data/lib/langchain/llm/openai.rb +16 -4
- data/lib/langchain/llm/prompts/ollama/summarize_template.yaml +9 -0
- data/lib/langchain/output_parsers/base.rb +0 -4
- data/lib/langchain/output_parsers/output_fixing_parser.rb +6 -13
- data/lib/langchain/output_parsers/structured_output_parser.rb +0 -10
- data/lib/langchain/processors/eml.rb +65 -0
- data/lib/langchain/tool/base.rb +17 -32
- data/lib/langchain/tool/calculator/calculator.json +19 -0
- data/lib/langchain/tool/{calculator.rb → calculator/calculator.rb} +8 -5
- data/lib/langchain/tool/database/database.json +46 -0
- data/lib/langchain/tool/database/database.rb +105 -0
- data/lib/langchain/tool/google_search/google_search.json +19 -0
- data/lib/langchain/tool/{google_search.rb → google_search/google_search.rb} +5 -6
- data/lib/langchain/tool/ruby_code_interpreter/ruby_code_interpreter.json +19 -0
- data/lib/langchain/tool/{ruby_code_interpreter.rb → ruby_code_interpreter/ruby_code_interpreter.rb} +9 -1
- data/lib/langchain/tool/weather/weather.json +19 -0
- data/lib/langchain/tool/{weather.rb → weather/weather.rb} +3 -4
- data/lib/langchain/tool/wikipedia/wikipedia.json +19 -0
- data/lib/langchain/tool/{wikipedia.rb → wikipedia/wikipedia.rb} +10 -1
- data/lib/langchain/vectorsearch/base.rb +1 -1
- data/lib/langchain/version.rb +1 -1
- data/lib/langchain.rb +8 -1
- metadata +80 -16
- data/lib/langchain/tool/database.rb +0 -90
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 62c459d5dc2f716eaeb81697bdf45ad42ae168784d28ff8a80a89d1b3e14eadd
|
4
|
+
data.tar.gz: 8bb1f94373c54619235cb24ea705179626e398d517739b93014a514283068468
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
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(
|
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
|
-
|
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(&:
|
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
|
-
|
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.
|
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
|
-
#
|
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
|
-
#
|
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
|
# 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("---")
|
@@ -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 << "[
|
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
|
data/lib/langchain/llm/ollama.rb
CHANGED
@@ -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.
|
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
|
-
|
133
|
+
chunk.split("\n").each do |line_chunk|
|
134
|
+
json_chunk = JSON.parse(line_chunk)
|
112
135
|
|
113
|
-
|
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
|
data/lib/langchain/llm/openai.rb
CHANGED
@@ -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
|
-
|
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
|
@@ -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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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)
|