langchainrb 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +2 -3
- data/examples/create_and_manage_few_shot_prompt_templates.rb +3 -3
- data/examples/create_and_manage_prompt_templates.rb +8 -4
- data/examples/pdf_store_and_query_with_chroma.rb +1 -1
- data/examples/store_and_query_with_pinecone.rb +2 -2
- data/examples/store_and_query_with_qdrant.rb +1 -1
- data/examples/store_and_query_with_weaviate.rb +1 -1
- data/lib/langchain/agent/chain_of_thought_agent/chain_of_thought_agent.rb +2 -5
- data/lib/langchain/agent/sql_query_agent/sql_query_agent.rb +3 -3
- data/lib/langchain/llm/openai.rb +4 -11
- data/lib/langchain/tool/calculator.rb +2 -1
- data/lib/langchain/utils/token_length_validator.rb +35 -8
- data/lib/langchain/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d36de4206b792714ba9b6773c03272e9638b14caf7140e0bc00c3e767aa5fdef
|
4
|
+
data.tar.gz: 819fab9de55a34e4e6dc865febc19bb9979df55fa8fc6a753774cf1961c40103
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e180b41bbca96bd5523c276923f223bbebe470314086c6a909df440890793bcc70dbd66ecf59bf5d0fd52426650cc5d2684c56cc8fc643209cc1679527cbef4
|
7
|
+
data.tar.gz: af5db76c2b22b5c7bdc1170de437921e8464a16566f46a5cad465d69e6da47c97a82f7331a5ea5747840e58acc71463aa8456b03e9bc8851efda7b734e5d23cc
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -281,11 +281,10 @@ Add `gem "sequel"` to your Gemfile
|
|
281
281
|
```ruby
|
282
282
|
database = Langchain::Tool::Database.new(connection_string: "postgres://user:password@localhost:5432/db_name")
|
283
283
|
|
284
|
-
agent = Langchain::Agent::SQLQueryAgent.new(llm: Langchain::LLM::OpenAI.new(api_key: ENV["OPENAI_API_KEY"]),
|
285
|
-
|
284
|
+
agent = Langchain::Agent::SQLQueryAgent.new(llm: Langchain::LLM::OpenAI.new(api_key: ENV["OPENAI_API_KEY"]), db: database)
|
286
285
|
```
|
287
286
|
```ruby
|
288
|
-
agent.
|
287
|
+
agent.run(question: "How many users have a name with length greater than 5 in the users table?")
|
289
288
|
#=> "14 users have a name with length greater than 5 in the users table."
|
290
289
|
```
|
291
290
|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require "langchain"
|
2
2
|
|
3
3
|
# Create a prompt with a few shot examples
|
4
|
-
prompt = Prompt::FewShotPromptTemplate.new(
|
4
|
+
prompt = Langchain::Prompt::FewShotPromptTemplate.new(
|
5
5
|
prefix: "Write antonyms for the following words.",
|
6
6
|
suffix: "Input: {adjective}\nOutput:",
|
7
|
-
example_prompt: Prompt::PromptTemplate.new(
|
7
|
+
example_prompt: Langchain::Prompt::PromptTemplate.new(
|
8
8
|
input_variables: ["input", "output"],
|
9
9
|
template: "Input: {input}\nOutput: {output}"
|
10
10
|
),
|
@@ -32,5 +32,5 @@ prompt.format(adjective: "good")
|
|
32
32
|
prompt.save(file_path: "spec/fixtures/prompt/few_shot_prompt_template.json")
|
33
33
|
|
34
34
|
# Loading a new prompt template using a JSON file
|
35
|
-
prompt = Prompt.load_from_path(file_path: "spec/fixtures/prompt/few_shot_prompt_template.json")
|
35
|
+
prompt = Langchain::Prompt.load_from_path(file_path: "spec/fixtures/prompt/few_shot_prompt_template.json")
|
36
36
|
prompt.prefix # "Write antonyms for the following words."
|
@@ -1,15 +1,15 @@
|
|
1
1
|
require "langchain"
|
2
2
|
|
3
3
|
# Create a prompt with one input variable
|
4
|
-
prompt = Prompt::PromptTemplate.new(template: "Tell me a {adjective} joke.", input_variables: ["adjective"])
|
4
|
+
prompt = Langchain::Prompt::PromptTemplate.new(template: "Tell me a {adjective} joke.", input_variables: ["adjective"])
|
5
5
|
prompt.format(adjective: "funny") # "Tell me a funny joke."
|
6
6
|
|
7
7
|
# Create a prompt with multiple input variables
|
8
|
-
prompt = Prompt::PromptTemplate.new(template: "Tell me a {adjective} joke about {content}.", input_variables: ["adjective", "content"])
|
8
|
+
prompt = Langchain::Prompt::PromptTemplate.new(template: "Tell me a {adjective} joke about {content}.", input_variables: ["adjective", "content"])
|
9
9
|
prompt.format(adjective: "funny", content: "chickens") # "Tell me a funny joke about chickens."
|
10
10
|
|
11
11
|
# Creating a PromptTemplate using just a prompt and no input_variables
|
12
|
-
prompt = Prompt::PromptTemplate.from_template("Tell me a {adjective} joke about {content}.")
|
12
|
+
prompt = Langchain::Prompt::PromptTemplate.from_template("Tell me a {adjective} joke about {content}.")
|
13
13
|
prompt.input_variables # ["adjective", "content"]
|
14
14
|
prompt.format(adjective: "funny", content: "chickens") # "Tell me a funny joke about chickens."
|
15
15
|
|
@@ -17,5 +17,9 @@ prompt.format(adjective: "funny", content: "chickens") # "Tell me a funny joke a
|
|
17
17
|
prompt.save(file_path: "spec/fixtures/prompt/prompt_template.json")
|
18
18
|
|
19
19
|
# Loading a new prompt template using a JSON file
|
20
|
-
prompt = Prompt.load_from_path(file_path: "spec/fixtures/prompt/prompt_template.json")
|
20
|
+
prompt = Langchain::Prompt.load_from_path(file_path: "spec/fixtures/prompt/prompt_template.json")
|
21
|
+
prompt.input_variables # ["adjective", "content"]
|
22
|
+
|
23
|
+
# Loading a new prompt template using a YAML file
|
24
|
+
prompt = Langchain::Prompt.load_from_path(file_path: "spec/fixtures/prompt/prompt_template.yaml")
|
21
25
|
prompt.input_variables # ["adjective", "content"]
|
@@ -4,7 +4,7 @@ require "langchain"
|
|
4
4
|
# or add `gem "chroma-db", "~> 0.3.0"` to your Gemfile
|
5
5
|
|
6
6
|
# Instantiate the Chroma client
|
7
|
-
chroma = Vectorsearch::Chroma.new(
|
7
|
+
chroma = Langchain::Vectorsearch::Chroma.new(
|
8
8
|
url: ENV["CHROMA_URL"],
|
9
9
|
index_name: "documents",
|
10
10
|
llm: Langchain::LLM::OpenAI.new(api_key: ENV["OPENAI_API_KEY"])
|
@@ -4,7 +4,7 @@ require "langchain"
|
|
4
4
|
# or add `gem "pinecone"` to your Gemfile
|
5
5
|
|
6
6
|
# Instantiate the Qdrant client
|
7
|
-
pinecone = Vectorsearch::Pinecone.new(
|
7
|
+
pinecone = Langchain::Vectorsearch::Pinecone.new(
|
8
8
|
environment: ENV["PINECONE_ENVIRONMENT"],
|
9
9
|
api_key: ENV["PINECONE_API_KEY"],
|
10
10
|
index_name: "recipes",
|
@@ -37,7 +37,7 @@ pinecone.ask(
|
|
37
37
|
)
|
38
38
|
|
39
39
|
# Generate your an embedding and search by it
|
40
|
-
openai = LLM::OpenAI.new(api_key: ENV["OPENAI_API_KEY"])
|
40
|
+
openai = Langchain::LLM::OpenAI.new(api_key: ENV["OPENAI_API_KEY"])
|
41
41
|
embedding = openai.embed(text: "veggie")
|
42
42
|
|
43
43
|
pinecone.similarity_search_by_vector(
|
@@ -4,7 +4,7 @@ require "langchain"
|
|
4
4
|
# or add `gem "qdrant-ruby"` to your Gemfile
|
5
5
|
|
6
6
|
# Instantiate the Qdrant client
|
7
|
-
qdrant = Vectorsearch::Qdrant.new(
|
7
|
+
qdrant = Langchain::Vectorsearch::Qdrant.new(
|
8
8
|
url: ENV["QDRANT_URL"],
|
9
9
|
api_key: ENV["QDRANT_API_KEY"],
|
10
10
|
index_name: "recipes",
|
@@ -4,7 +4,7 @@ require "langchain"
|
|
4
4
|
# or add `gem "weaviate-ruby"` to your Gemfile
|
5
5
|
|
6
6
|
# Instantiate the Weaviate client
|
7
|
-
weaviate = Vectorsearch::Weaviate.new(
|
7
|
+
weaviate = Langchain::Vectorsearch::Weaviate.new(
|
8
8
|
url: ENV["WEAVIATE_URL"],
|
9
9
|
api_key: ENV["WEAVIATE_API_KEY"],
|
10
10
|
index_name: "Recipes",
|
@@ -39,11 +39,8 @@ module Langchain::Agent
|
|
39
39
|
|
40
40
|
loop do
|
41
41
|
Langchain.logger.info("[#{self.class.name}]".red + ": Sending the prompt to the #{llm.class} LLM")
|
42
|
-
|
43
|
-
|
44
|
-
stop_sequences: ["Observation:"],
|
45
|
-
max_tokens: 500
|
46
|
-
)
|
42
|
+
|
43
|
+
response = llm.complete(prompt: prompt, stop_sequences: ["Observation:"])
|
47
44
|
|
48
45
|
# Append the response to the prompt
|
49
46
|
prompt += response
|
@@ -22,12 +22,12 @@ module Langchain::Agent
|
|
22
22
|
# @param question [String] Question to ask the LLM/Database
|
23
23
|
# @return [String] Answer to the question
|
24
24
|
#
|
25
|
-
def
|
25
|
+
def run(question:)
|
26
26
|
prompt = create_prompt_for_sql(question: question)
|
27
27
|
|
28
28
|
# Get the SQL string to execute
|
29
29
|
Langchain.logger.info("[#{self.class.name}]".red + ": Passing the inital prompt to the #{llm.class} LLM")
|
30
|
-
sql_string = llm.complete(prompt: prompt
|
30
|
+
sql_string = llm.complete(prompt: prompt)
|
31
31
|
|
32
32
|
# Execute the SQL string and collect the results
|
33
33
|
Langchain.logger.info("[#{self.class.name}]".red + ": Passing the SQL to the Database: #{sql_string}")
|
@@ -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("[#{self.class.name}]".red + ": Passing the synthesize prompt to the #{llm.class} LLM with results: #{results}")
|
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)
|
40
40
|
end
|
41
41
|
|
42
42
|
private
|
data/lib/langchain/llm/openai.rb
CHANGED
@@ -35,7 +35,7 @@ module Langchain::LLM
|
|
35
35
|
def embed(text:, **params)
|
36
36
|
parameters = {model: DEFAULTS[:embeddings_model_name], input: text}
|
37
37
|
|
38
|
-
Langchain::Utils::TokenLengthValidator.
|
38
|
+
Langchain::Utils::TokenLengthValidator.validate_max_tokens!(text, parameters[:model])
|
39
39
|
|
40
40
|
response = client.embeddings(parameters: parameters.merge(params))
|
41
41
|
response.dig("data").first.dig("embedding")
|
@@ -50,9 +50,8 @@ module Langchain::LLM
|
|
50
50
|
def complete(prompt:, **params)
|
51
51
|
parameters = compose_parameters DEFAULTS[:completion_model_name], params
|
52
52
|
|
53
|
-
Langchain::Utils::TokenLengthValidator.validate!(prompt, parameters[:model])
|
54
|
-
|
55
53
|
parameters[:prompt] = prompt
|
54
|
+
parameters[:max_tokens] = Langchain::Utils::TokenLengthValidator.validate_max_tokens!(prompt, parameters[:model])
|
56
55
|
|
57
56
|
response = client.completions(parameters: parameters)
|
58
57
|
response.dig("choices", 0, "text")
|
@@ -67,9 +66,8 @@ module Langchain::LLM
|
|
67
66
|
def chat(prompt:, **params)
|
68
67
|
parameters = compose_parameters DEFAULTS[:chat_completion_model_name], params
|
69
68
|
|
70
|
-
Langchain::Utils::TokenLengthValidator.validate!(prompt, parameters[:model])
|
71
|
-
|
72
69
|
parameters[:messages] = [{role: "user", content: prompt}]
|
70
|
+
parameters[:max_tokens] = Langchain::Utils::TokenLengthValidator.validate_max_tokens!(prompt, parameters[:model])
|
73
71
|
|
74
72
|
response = client.chat(parameters: parameters)
|
75
73
|
response.dig("choices", 0, "message", "content")
|
@@ -87,12 +85,7 @@ module Langchain::LLM
|
|
87
85
|
)
|
88
86
|
prompt = prompt_template.format(text: text)
|
89
87
|
|
90
|
-
complete(
|
91
|
-
prompt: prompt,
|
92
|
-
temperature: DEFAULTS[:temperature],
|
93
|
-
# Most models have a context length of 2048 tokens (except for the newest models, which support 4096).
|
94
|
-
max_tokens: 2048
|
95
|
-
)
|
88
|
+
complete(prompt: prompt, temperature: DEFAULTS[:temperature])
|
96
89
|
end
|
97
90
|
|
98
91
|
private
|
@@ -38,7 +38,8 @@ module Langchain::Tool
|
|
38
38
|
hash_results = Langchain::Tool::SerpApi
|
39
39
|
.new(api_key: ENV["SERPAPI_API_KEY"])
|
40
40
|
.execute_search(input: input)
|
41
|
-
hash_results.dig(:answer_box, :to)
|
41
|
+
hash_results.dig(:answer_box, :to) ||
|
42
|
+
hash_results.dig(:answer_box, :result)
|
42
43
|
end
|
43
44
|
end
|
44
45
|
end
|
@@ -34,23 +34,50 @@ module Langchain
|
|
34
34
|
"ada" => 2049
|
35
35
|
}.freeze
|
36
36
|
|
37
|
+
# GOOGLE_PALM_TOKEN_LIMITS = {
|
38
|
+
# "chat-bison-001" => {
|
39
|
+
# "inputTokenLimit"=>4096,
|
40
|
+
# "outputTokenLimit"=>1024
|
41
|
+
# },
|
42
|
+
# "text-bison-001" => {
|
43
|
+
# "inputTokenLimit"=>8196,
|
44
|
+
# "outputTokenLimit"=>1024
|
45
|
+
# },
|
46
|
+
# "embedding-gecko-001" => {
|
47
|
+
# "inputTokenLimit"=>1024
|
48
|
+
# }
|
49
|
+
# }.freeze
|
50
|
+
|
37
51
|
#
|
38
|
-
#
|
52
|
+
# Calculate the `max_tokens:` parameter to be set by calculating the context length of the text minus the prompt length
|
39
53
|
#
|
40
54
|
# @param text [String] The text to validate
|
41
55
|
# @param model_name [String] The model name to validate against
|
42
|
-
# @return [
|
56
|
+
# @return [Integer] Whether the text is valid or not
|
43
57
|
# @raise [TokenLimitExceeded] If the text is too long
|
44
58
|
#
|
45
|
-
def self.
|
46
|
-
|
47
|
-
|
59
|
+
def self.validate_max_tokens!(text, model_name)
|
60
|
+
text_token_length = token_length(text, model_name)
|
61
|
+
max_tokens = TOKEN_LIMITS[model_name] - text_token_length
|
48
62
|
|
49
|
-
if
|
50
|
-
|
63
|
+
# Raise an error even if whole prompt is equal to the model's token limit (max_tokens == 0) since not response will be returned
|
64
|
+
if max_tokens <= 0
|
65
|
+
raise TokenLimitExceeded, "This model's maximum context length is #{TOKEN_LIMITS[model_name]} tokens, but the given text is #{text_token_length} tokens long."
|
51
66
|
end
|
52
67
|
|
53
|
-
|
68
|
+
max_tokens
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Calculate token length for a given text and model name
|
73
|
+
#
|
74
|
+
# @param text [String] The text to validate
|
75
|
+
# @param model_name [String] The model name to validate against
|
76
|
+
# @return [Integer] The token length of the text
|
77
|
+
#
|
78
|
+
def self.token_length(text, model_name)
|
79
|
+
encoder = Tiktoken.encoding_for_model(model_name)
|
80
|
+
encoder.encode(text).length
|
54
81
|
end
|
55
82
|
end
|
56
83
|
end
|
data/lib/langchain/version.rb
CHANGED
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.5.
|
4
|
+
version: 0.5.2
|
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-06-
|
11
|
+
date: 2023-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tiktoken_ruby
|