langchainrb 0.5.6 → 0.5.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 045a900e70f73ac0c969ea0e7cb0130d12219ad869583a55d5f5857ceccac618
4
- data.tar.gz: f6202d34280eeda69026add6cb0bcadb1625da58ed729e1b4ca02c2cfdbd76b4
3
+ metadata.gz: ba5e9e8257d18c0940fdaf4fe84c03d594d8f1151e40e1bb35de059f8e6e5094
4
+ data.tar.gz: 11310635819502b9bfbd66bc45dc7aa1ce500d4a874dcc5ab550d6c5edf7194f
5
5
  SHA512:
6
- metadata.gz: b5cd3983b8a7389baace3befd24751d1c2974b94da29868fac6bfcd048681d2b6cc603d13f791d7ca4bffbc18b9278704c3db188112b51f1c71ac528c6c04f70
7
- data.tar.gz: c061c1a877bc94488177ef79a46ed558540ba664a001a463a95fbe7f1f5f50c8895f359ab06fce26bb7dedf8cd246713b96e553fdfa55ca5b68c78f124e87a2a
6
+ metadata.gz: 4b97e21bcbc0c5f1d842271b64949c07d6d78190cd97c22fd0dab735d6b6ae2f2e6328ba2631dfc77ed0a5dd227573e3f84f064e8dd9332701848a798747ac9a
7
+ data.tar.gz: 267b2029de10acf45bb97a040d174102f666e048aaaf03ab76218cd5281574c1ae977ba8e975faf4b690e677611daba2fb0fc975801c0e41072f050ec2ac2e34
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.5.7] - 2023-06-19
4
+ - Developer can modify models used when initiliazing `Langchain::LLM::*` clients
5
+ - Improvements to the `SQLQueryAgent` and the database tool
6
+
3
7
  ## [0.5.6] - 2023-06-18
4
8
  - If used with OpenAI, Langchain::Conversation responses can now be streamed.
5
9
  - Improved logging
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- langchainrb (0.5.6)
4
+ langchainrb (0.5.7)
5
5
  baran (~> 0.1.6)
6
6
  colorize (~> 0.8.1)
7
7
  tiktoken_ruby (~> 0.0.5)
data/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
  [![Gem Version](https://badge.fury.io/rb/langchainrb.svg)](https://badge.fury.io/rb/langchainrb)
11
11
  [![Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/gems/langchainrb)
12
12
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/andreibondarev/langchainrb/blob/main/LICENSE.txt)
13
- [![](https://dcbadge.vercel.app/api/server/WWqjwxMv?compact=true&style=flat)](https://discord.gg/WWqjwxMv)
13
+ [![](https://dcbadge.vercel.app/api/server/WDARp7J2n8?compact=true&style=flat)](https://discord.gg/WDARp7J2n8)
14
14
 
15
15
 
16
16
  Langchain.rb is a library that's an abstraction layer on top many emergent AI, ML and other DS tools. The goal is to abstract complexity and difficult concepts to make building AI/ML-supercharged applications approachable for traditional software engineers.
@@ -367,7 +367,7 @@ Langchain.logger.level = :info
367
367
  5. Optionally, install lefthook git hooks for pre-commit to auto lint: `gem install lefthook && lefthook install -f`
368
368
 
369
369
  ## Discord
370
- Join us in the [Langchain.rb](https://discord.gg/hXutDWGDd) Discord server.
370
+ Join us in the [Langchain.rb](https://discord.gg/WDARp7J2n8) Discord server.
371
371
 
372
372
  ## Core Contributors
373
373
  [<img style="border-radius:50%" alt="Andrei Bondarev" src="https://avatars.githubusercontent.com/u/541665?v=4" width="80" height="80" class="avatar">](https://github.com/andreibondarev)
@@ -13,7 +13,7 @@ module Langchain::Agent
13
13
  def initialize(llm:, db:)
14
14
  @llm = llm
15
15
  @db = db
16
- @schema = @db.schema
16
+ @schema = @db.dump_schema
17
17
  end
18
18
 
19
19
  #
@@ -11,11 +11,17 @@ module Langchain::LLM
11
11
  # ai21 = Langchain::LLM::AI21.new(api_key:)
12
12
  #
13
13
  class AI21 < Base
14
- def initialize(api_key:)
14
+ DEFAULTS = {
15
+ temperature: 0.0,
16
+ model: "j2-large"
17
+ }.freeze
18
+
19
+ def initialize(api_key:, default_options: {})
15
20
  depends_on "ai21"
16
21
  require "ai21"
17
22
 
18
23
  @client = ::AI21::Client.new(api_key)
24
+ @defaults = DEFAULTS.merge(default_options)
19
25
  end
20
26
 
21
27
  #
@@ -26,7 +32,9 @@ module Langchain::LLM
26
32
  # @return [String] The completion
27
33
  #
28
34
  def complete(prompt:, **params)
29
- response = client.complete(prompt, params)
35
+ parameters = complete_parameters params
36
+
37
+ response = client.complete(prompt, parameters)
30
38
  response.dig(:completions, 0, :data, :text)
31
39
  end
32
40
 
@@ -41,5 +49,11 @@ module Langchain::LLM
41
49
  response = client.summarize(text, "TEXT", params)
42
50
  response.dig(:summary)
43
51
  end
52
+
53
+ private
54
+
55
+ def complete_parameters(params)
56
+ @defaults.dup.merge(params)
57
+ end
44
58
  end
45
59
  end
@@ -18,11 +18,12 @@ module Langchain::LLM
18
18
  dimension: 1024
19
19
  }.freeze
20
20
 
21
- def initialize(api_key:)
21
+ def initialize(api_key:, default_options: {})
22
22
  depends_on "cohere-ruby"
23
23
  require "cohere"
24
24
 
25
25
  @client = ::Cohere::Client.new(api_key: api_key)
26
+ @defaults = DEFAULTS.merge(default_options)
26
27
  end
27
28
 
28
29
  #
@@ -34,7 +35,7 @@ module Langchain::LLM
34
35
  def embed(text:)
35
36
  response = client.embed(
36
37
  texts: [text],
37
- model: DEFAULTS[:embeddings_model_name]
38
+ model: @defaults[:embeddings_model_name]
38
39
  )
39
40
  response.dig("embeddings").first
40
41
  end
@@ -49,8 +50,8 @@ module Langchain::LLM
49
50
  def complete(prompt:, **params)
50
51
  default_params = {
51
52
  prompt: prompt,
52
- temperature: DEFAULTS[:temperature],
53
- model: DEFAULTS[:completion_model_name]
53
+ temperature: @defaults[:temperature],
54
+ model: @defaults[:completion_model_name]
54
55
  }
55
56
 
56
57
  if params[:stop_sequences]
@@ -22,15 +22,19 @@ module Langchain::LLM
22
22
 
23
23
  DEFAULTS = {
24
24
  temperature: 0.0,
25
- dimension: 768 # This is what the `embedding-gecko-001` model generates
25
+ dimension: 768, # This is what the `embedding-gecko-001` model generates
26
+ completion_model_name: "text-bison-001",
27
+ chat_completion_model_name: "chat-bison-001",
28
+ embeddings_model_name: "embedding-gecko-001"
26
29
  }.freeze
27
30
  LENGTH_VALIDATOR = Langchain::Utils::TokenLength::GooglePalmValidator
28
31
 
29
- def initialize(api_key:)
32
+ def initialize(api_key:, default_options: {})
30
33
  depends_on "google_palm_api"
31
34
  require "google_palm_api"
32
35
 
33
36
  @client = ::GooglePalmApi::Client.new(api_key: api_key)
37
+ @defaults = DEFAULTS.merge(default_options)
34
38
  end
35
39
 
36
40
  #
@@ -56,7 +60,8 @@ module Langchain::LLM
56
60
  def complete(prompt:, **params)
57
61
  default_params = {
58
62
  prompt: prompt,
59
- temperature: DEFAULTS[:temperature]
63
+ temperature: @defaults[:temperature],
64
+ completion_model_name: @defaults[:completion_model_name]
60
65
  }
61
66
 
62
67
  if params[:stop_sequences]
@@ -85,12 +90,14 @@ module Langchain::LLM
85
90
  raise ArgumentError.new(":prompt or :messages argument is expected") if prompt.empty? && messages.empty?
86
91
 
87
92
  default_params = {
88
- temperature: DEFAULTS[:temperature],
93
+ temperature: @defaults[:temperature],
94
+ chat_completion_model_name: @defaults[:chat_completion_model_name],
89
95
  context: context,
90
96
  messages: compose_chat_messages(prompt: prompt, messages: messages),
91
97
  examples: compose_examples(examples)
92
98
  }
93
99
 
100
+ # chat-bison-001 is the only model that currently supports countMessageTokens functions
94
101
  LENGTH_VALIDATOR.validate_max_tokens!(default_params[:messages], "chat-bison-001", llm: self)
95
102
 
96
103
  if options[:stop_sequences]
@@ -123,7 +130,7 @@ module Langchain::LLM
123
130
 
124
131
  complete(
125
132
  prompt: prompt,
126
- temperature: DEFAULTS[:temperature],
133
+ temperature: @defaults[:temperature],
127
134
  # Most models have a context length of 2048 tokens (except for the newest models, which support 4096).
128
135
  max_tokens: 2048
129
136
  )
@@ -19,11 +19,12 @@ module Langchain::LLM
19
19
  }.freeze
20
20
  LENGTH_VALIDATOR = Langchain::Utils::TokenLength::OpenAIValidator
21
21
 
22
- def initialize(api_key:, llm_options: {})
22
+ def initialize(api_key:, llm_options: {}, default_options: {})
23
23
  depends_on "ruby-openai"
24
24
  require "openai"
25
25
 
26
26
  @client = ::OpenAI::Client.new(access_token: api_key, **llm_options)
27
+ @defaults = DEFAULTS.merge(default_options)
27
28
  end
28
29
 
29
30
  #
@@ -34,7 +35,7 @@ module Langchain::LLM
34
35
  # @return [Array] The embedding
35
36
  #
36
37
  def embed(text:, **params)
37
- parameters = {model: DEFAULTS[:embeddings_model_name], input: text}
38
+ parameters = {model: @defaults[:embeddings_model_name], input: text}
38
39
 
39
40
  validate_max_tokens(text, parameters[:model])
40
41
 
@@ -50,7 +51,7 @@ module Langchain::LLM
50
51
  # @return [String] The completion
51
52
  #
52
53
  def complete(prompt:, **params)
53
- parameters = compose_parameters DEFAULTS[:completion_model_name], params
54
+ parameters = compose_parameters @defaults[:completion_model_name], params
54
55
 
55
56
  parameters[:prompt] = prompt
56
57
  parameters[:max_tokens] = validate_max_tokens(prompt, parameters[:model])
@@ -60,20 +61,59 @@ module Langchain::LLM
60
61
  end
61
62
 
62
63
  #
63
- # Generate a chat completion for a given prompt
64
+ # Generate a chat completion for a given prompt or messages.
65
+ #
66
+ # == Examples
67
+ #
68
+ # # simplest case, just give a prompt
69
+ # openai.chat prompt: "When was Ruby first released?"
70
+ #
71
+ # # prompt plus some context about how to respond
72
+ # openai.chat context: "You are RubyGPT, a helpful chat bot for helping people learn Ruby", prompt: "Does Ruby have a REPL like IPython?"
73
+ #
74
+ # # full control over messages that get sent, equivilent to the above
75
+ # openai.chat messages: [
76
+ # {
77
+ # role: "system",
78
+ # content: "You are RubyGPT, a helpful chat bot for helping people learn Ruby", prompt: "Does Ruby have a REPL like IPython?"
79
+ # },
80
+ # {
81
+ # role: "user",
82
+ # content: "When was Ruby first released?"
83
+ # }
84
+ # ]
85
+ #
86
+ # # few-short prompting with examples
87
+ # openai.chat prompt: "When was factory_bot released?",
88
+ # examples: [
89
+ # {
90
+ # role: "user",
91
+ # content: "When was Ruby on Rails released?"
92
+ # }
93
+ # {
94
+ # role: "assistant",
95
+ # content: "2004"
96
+ # },
97
+ # ]
64
98
  #
65
99
  # @param prompt [String] The prompt to generate a chat completion for
66
- # @param messages [Array] The messages that have been sent in the conversation
67
- # @param context [String] The context of the conversation
68
- # @param examples [Array] Examples of messages provide model with
69
- # @param options extra parameters passed to OpenAI::Client#chat
70
- # @param block [Block] Pass the block to stream the response
100
+ # @param messages [Array<Hash>] The messages that have been sent in the conversation
101
+ # Each message should be a Hash with the following keys:
102
+ # - :content [String] The content of the message
103
+ # - :role [String] The role of the sender (system, user, assistant, or function)
104
+ # @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"
105
+ # @param examples [Array<Hash>] Examples of messages to provide to the model. Useful for Few-Shot Prompting
106
+ # Each message should be a Hash with the following keys:
107
+ # - :content [String] The content of the message
108
+ # - :role [String] The role of the sender (system, user, assistant, or function)
109
+ # @param options <Hash> extra parameters passed to OpenAI::Client#chat
110
+ # @yield [String] Stream responses back one String at a time
71
111
  # @return [String] The chat completion
72
112
  #
73
113
  def chat(prompt: "", messages: [], context: "", examples: [], **options)
74
114
  raise ArgumentError.new(":prompt or :messages argument is expected") if prompt.empty? && messages.empty?
75
115
 
76
- parameters = compose_parameters DEFAULTS[:chat_completion_model_name], options
116
+ parameters = compose_parameters @defaults[:chat_completion_model_name], options
77
117
  parameters[:messages] = compose_chat_messages(prompt: prompt, messages: messages, context: context, examples: examples)
78
118
  parameters[:max_tokens] = validate_max_tokens(parameters[:messages], parameters[:model])
79
119
 
@@ -104,13 +144,13 @@ module Langchain::LLM
104
144
  )
105
145
  prompt = prompt_template.format(text: text)
106
146
 
107
- complete(prompt: prompt, temperature: DEFAULTS[:temperature])
147
+ complete(prompt: prompt, temperature: @defaults[:temperature])
108
148
  end
109
149
 
110
150
  private
111
151
 
112
152
  def compose_parameters(model, params)
113
- default_params = {model: model, temperature: DEFAULTS[:temperature]}
153
+ default_params = {model: model, temperature: @defaults[:temperature]}
114
154
 
115
155
  default_params[:stop] = params.delete(:stop_sequences) if params[:stop_sequences]
116
156
 
@@ -32,7 +32,7 @@ module Langchain::LLM
32
32
  #
33
33
  # @param api_key [String] The API key to use
34
34
  #
35
- def initialize(api_key:)
35
+ def initialize(api_key:, default_options: {})
36
36
  depends_on "replicate-ruby"
37
37
  require "replicate"
38
38
 
@@ -41,6 +41,7 @@ module Langchain::LLM
41
41
  end
42
42
 
43
43
  @client = ::Replicate.client
44
+ @defaults = DEFAULTS.merge(default_options)
44
45
  end
45
46
 
46
47
  #
@@ -100,7 +101,7 @@ module Langchain::LLM
100
101
 
101
102
  complete(
102
103
  prompt: prompt,
103
- temperature: DEFAULTS[:temperature],
104
+ temperature: @defaults[:temperature],
104
105
  # Most models have a context length of 2048 tokens (except for the newest models, which support 4096).
105
106
  max_tokens: 2048
106
107
  )
@@ -111,11 +112,11 @@ module Langchain::LLM
111
112
  private
112
113
 
113
114
  def completion_model
114
- @completion_model ||= client.retrieve_model(DEFAULTS[:completion_model_name]).latest_version
115
+ @completion_model ||= client.retrieve_model(@defaults[:completion_model_name]).latest_version
115
116
  end
116
117
 
117
118
  def embeddings_model
118
- @embeddings_model ||= client.retrieve_model(DEFAULTS[:embeddings_model_name]).latest_version
119
+ @embeddings_model ||= client.retrieve_model(@defaults[:embeddings_model_name]).latest_version
119
120
  end
120
121
  end
121
122
  end
@@ -16,6 +16,11 @@ module Langchain::Tool
16
16
  Useful for getting the result of a math expression.
17
17
 
18
18
  The input to this tool should be a valid mathematical expression that could be executed by a simple calculator.
19
+ Usage:
20
+ Action Input: 1 + 1
21
+ Action Input: 3 * 2 / 4
22
+ Action Input: 9 - 7
23
+ Action Input: (4.1 + 2.3) / (2.0 - 5.6) * 3
19
24
  DESC
20
25
 
21
26
  def initialize
@@ -32,14 +37,7 @@ module Langchain::Tool
32
37
 
33
38
  Eqn::Calculator.calc(input)
34
39
  rescue Eqn::ParseError, Eqn::NoVariableValueError
35
- # Sometimes the input is not a pure math expression, e.g: "12F in Celsius"
36
- # We can use the google answer box to evaluate this expression
37
- # TODO: Figure out to find a better way to evaluate these language expressions.
38
- hash_results = Langchain::Tool::GoogleSearch
39
- .new(api_key: ENV["SERPAPI_API_KEY"])
40
- .execute_search(input: input)
41
- hash_results.dig(:answer_box, :to) ||
42
- hash_results.dig(:answer_box, :result)
40
+ "\"#{input}\" is an invalid mathematical expression"
43
41
  end
44
42
  end
45
43
  end
@@ -14,15 +14,18 @@ module Langchain::Tool
14
14
  The input to this tool should be valid SQL.
15
15
  DESC
16
16
 
17
- attr_reader :db
17
+ attr_reader :db, :requested_tables, :except_tables
18
18
 
19
19
  #
20
20
  # Establish a database connection
21
21
  #
22
22
  # @param connection_string [String] Database connection info, e.g. 'postgres://user:password@localhost:5432/db_name'
23
+ # @param tables [Array<Symbol>] The tables to use. Will use all if empty.
24
+ # @param except_tables [Array<Symbol>] The tables to exclude. Will exclude none if empty.
25
+
23
26
  # @return [Database] Database object
24
27
  #
25
- def initialize(connection_string:)
28
+ def initialize(connection_string:, tables: [], except_tables: [])
26
29
  depends_on "sequel"
27
30
  require "sequel"
28
31
  require "sequel/extensions/schema_dumper"
@@ -30,7 +33,8 @@ module Langchain::Tool
30
33
  raise StandardError, "connection_string parameter cannot be blank" if connection_string.empty?
31
34
 
32
35
  @db = Sequel.connect(connection_string)
33
- @db.extension :schema_dumper
36
+ @requested_tables = tables
37
+ @except_tables = except_tables
34
38
  end
35
39
 
36
40
  #
@@ -38,9 +42,26 @@ module Langchain::Tool
38
42
  #
39
43
  # @return [String] schema
40
44
  #
41
- def schema
42
- Langchain.logger.info("Dumping schema", for: self.class)
43
- db.dump_schema_migration(same_db: true, indexes: false) unless db.adapter_scheme == :mock
45
+ def dump_schema
46
+ Langchain.logger.info("Dumping schema tables and keys", for: self.class)
47
+ schema = ""
48
+ db.tables.each do |table|
49
+ next if except_tables.include?(table)
50
+ next unless requested_tables.empty? || requested_tables.include?(table)
51
+
52
+ schema << "CREATE TABLE #{table}(\n"
53
+ db.schema(table).each do |column|
54
+ schema << "#{column[0]} #{column[1][:type]}"
55
+ schema << " PRIMARY KEY" if column[1][:primary_key] == true
56
+ schema << "," unless column == db.schema(table).last
57
+ schema << "\n"
58
+ end
59
+ schema << ");\n"
60
+ db.foreign_key_list(table).each do |fk|
61
+ schema << "ALTER TABLE #{table} ADD FOREIGN KEY (#{fk[:columns][0]}) REFERENCES #{fk[:table]}(#{fk[:key][0]});\n"
62
+ end
63
+ end
64
+ schema
44
65
  end
45
66
 
46
67
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Langchain
4
- VERSION = "0.5.6"
4
+ VERSION = "0.5.7"
5
5
  end
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.6
4
+ version: 0.5.7
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-18 00:00:00.000000000 Z
11
+ date: 2023-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: baran