langchainrb 0.7.5 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +78 -0
- data/README.md +113 -56
- data/lib/langchain/assistants/assistant.rb +213 -0
- data/lib/langchain/assistants/message.rb +58 -0
- data/lib/langchain/assistants/thread.rb +34 -0
- data/lib/langchain/chunker/markdown.rb +37 -0
- 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/data.rb +4 -3
- data/lib/langchain/llm/ai21.rb +1 -1
- data/lib/langchain/llm/anthropic.rb +86 -11
- data/lib/langchain/llm/aws_bedrock.rb +52 -0
- data/lib/langchain/llm/azure.rb +10 -97
- data/lib/langchain/llm/base.rb +3 -2
- data/lib/langchain/llm/cohere.rb +5 -7
- data/lib/langchain/llm/google_palm.rb +4 -2
- data/lib/langchain/llm/google_vertex_ai.rb +151 -0
- data/lib/langchain/llm/hugging_face.rb +1 -1
- data/lib/langchain/llm/llama_cpp.rb +18 -16
- data/lib/langchain/llm/mistral_ai.rb +68 -0
- data/lib/langchain/llm/ollama.rb +209 -27
- data/lib/langchain/llm/openai.rb +138 -170
- data/lib/langchain/llm/prompts/ollama/summarize_template.yaml +9 -0
- data/lib/langchain/llm/replicate.rb +1 -7
- data/lib/langchain/llm/response/anthropic_response.rb +20 -0
- data/lib/langchain/llm/response/base_response.rb +7 -0
- data/lib/langchain/llm/response/google_palm_response.rb +4 -0
- data/lib/langchain/llm/response/google_vertex_ai_response.rb +33 -0
- data/lib/langchain/llm/response/llama_cpp_response.rb +13 -0
- data/lib/langchain/llm/response/mistral_ai_response.rb +39 -0
- data/lib/langchain/llm/response/ollama_response.rb +27 -1
- data/lib/langchain/llm/response/openai_response.rb +8 -0
- data/lib/langchain/loader.rb +3 -2
- data/lib/langchain/output_parsers/base.rb +0 -4
- data/lib/langchain/output_parsers/output_fixing_parser.rb +7 -14
- data/lib/langchain/output_parsers/structured_output_parser.rb +0 -10
- data/lib/langchain/processors/csv.rb +37 -3
- data/lib/langchain/processors/eml.rb +64 -0
- data/lib/langchain/processors/markdown.rb +17 -0
- data/lib/langchain/processors/pptx.rb +29 -0
- data/lib/langchain/prompt/loading.rb +1 -1
- data/lib/langchain/tool/base.rb +21 -53
- data/lib/langchain/tool/calculator/calculator.json +19 -0
- data/lib/langchain/tool/{calculator.rb → calculator/calculator.rb} +8 -16
- data/lib/langchain/tool/database/database.json +46 -0
- data/lib/langchain/tool/database/database.rb +99 -0
- data/lib/langchain/tool/file_system/file_system.json +57 -0
- data/lib/langchain/tool/file_system/file_system.rb +32 -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 -15
- 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} +8 -4
- data/lib/langchain/tool/vectorsearch/vectorsearch.json +24 -0
- data/lib/langchain/tool/vectorsearch/vectorsearch.rb +36 -0
- data/lib/langchain/tool/weather/weather.json +19 -0
- data/lib/langchain/tool/{weather.rb → weather/weather.rb} +3 -15
- data/lib/langchain/tool/wikipedia/wikipedia.json +19 -0
- data/lib/langchain/tool/{wikipedia.rb → wikipedia/wikipedia.rb} +9 -9
- data/lib/langchain/utils/token_length/ai21_validator.rb +6 -2
- data/lib/langchain/utils/token_length/base_validator.rb +1 -1
- data/lib/langchain/utils/token_length/cohere_validator.rb +6 -2
- data/lib/langchain/utils/token_length/google_palm_validator.rb +5 -1
- data/lib/langchain/utils/token_length/openai_validator.rb +55 -1
- data/lib/langchain/utils/token_length/token_limit_exceeded.rb +1 -1
- data/lib/langchain/vectorsearch/base.rb +11 -4
- data/lib/langchain/vectorsearch/chroma.rb +10 -1
- data/lib/langchain/vectorsearch/elasticsearch.rb +53 -4
- data/lib/langchain/vectorsearch/epsilla.rb +149 -0
- data/lib/langchain/vectorsearch/hnswlib.rb +5 -1
- data/lib/langchain/vectorsearch/milvus.rb +4 -2
- data/lib/langchain/vectorsearch/pgvector.rb +14 -4
- data/lib/langchain/vectorsearch/pinecone.rb +8 -5
- data/lib/langchain/vectorsearch/qdrant.rb +16 -4
- data/lib/langchain/vectorsearch/weaviate.rb +20 -2
- data/lib/langchain/version.rb +1 -1
- data/lib/langchain.rb +20 -5
- metadata +182 -45
- data/lib/langchain/agent/agents.md +0 -54
- data/lib/langchain/agent/base.rb +0 -20
- data/lib/langchain/agent/react_agent/react_agent_prompt.yaml +0 -26
- data/lib/langchain/agent/react_agent.rb +0 -131
- data/lib/langchain/agent/sql_query_agent/sql_query_agent_answer_prompt.yaml +0 -11
- data/lib/langchain/agent/sql_query_agent/sql_query_agent_sql_prompt.yaml +0 -21
- data/lib/langchain/agent/sql_query_agent.rb +0 -82
- data/lib/langchain/conversation/context.rb +0 -8
- data/lib/langchain/conversation/memory.rb +0 -86
- data/lib/langchain/conversation/message.rb +0 -48
- data/lib/langchain/conversation/prompt.rb +0 -8
- data/lib/langchain/conversation/response.rb +0 -8
- data/lib/langchain/conversation.rb +0 -93
- data/lib/langchain/tool/database.rb +0 -90
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Langchain::Tool
|
4
|
+
class FileSystem < Base
|
5
|
+
#
|
6
|
+
# A tool that wraps the Ruby file system classes.
|
7
|
+
#
|
8
|
+
# Usage:
|
9
|
+
# file_system = Langchain::Tool::FileSystem.new
|
10
|
+
#
|
11
|
+
NAME = "file_system"
|
12
|
+
ANNOTATIONS_PATH = Langchain.root.join("./langchain/tool/#{NAME}/#{NAME}.json").to_path
|
13
|
+
|
14
|
+
def list_directory(directory_path:)
|
15
|
+
Dir.entries(directory_path)
|
16
|
+
rescue Errno::ENOENT
|
17
|
+
"No such directory: #{directory_path}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def read_file(file_path:)
|
21
|
+
File.read(file_path)
|
22
|
+
rescue Errno::ENOENT
|
23
|
+
"No such file: #{file_path}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def write_to_file(file_path:, content:)
|
27
|
+
File.write(file_path, content)
|
28
|
+
rescue Errno::EACCES
|
29
|
+
"Permission denied: #{file_path}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"type": "function",
|
4
|
+
"function": {
|
5
|
+
"name": "google_search-execute",
|
6
|
+
"description": "Executes Google Search and returns the result",
|
7
|
+
"parameters": {
|
8
|
+
"type": "object",
|
9
|
+
"properties": {
|
10
|
+
"input": {
|
11
|
+
"type": "string",
|
12
|
+
"description": "search query"
|
13
|
+
}
|
14
|
+
},
|
15
|
+
"required": ["input"]
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
]
|
@@ -5,23 +5,15 @@ module Langchain::Tool
|
|
5
5
|
#
|
6
6
|
# Wrapper around SerpApi's Google Search API
|
7
7
|
#
|
8
|
-
# Gem requirements:
|
8
|
+
# Gem requirements:
|
9
|
+
# gem "google_search_results", "~> 2.0.0"
|
9
10
|
#
|
10
11
|
# Usage:
|
11
|
-
#
|
12
|
-
#
|
12
|
+
# search = Langchain::Tool::GoogleSearch.new(api_key: "YOUR_API_KEY")
|
13
|
+
# search.execute(input: "What is the capital of France?")
|
13
14
|
#
|
14
|
-
|
15
15
|
NAME = "google_search"
|
16
|
-
|
17
|
-
description <<~DESC
|
18
|
-
A wrapper around SerpApi's Google Search API.
|
19
|
-
|
20
|
-
Useful for when you need to answer questions about current events.
|
21
|
-
Always one of the first options when you need to find information on internet.
|
22
|
-
|
23
|
-
Input should be a search query.
|
24
|
-
DESC
|
16
|
+
ANNOTATIONS_PATH = Langchain.root.join("./langchain/tool/#{NAME}/#{NAME}.json").to_path
|
25
17
|
|
26
18
|
attr_reader :api_key
|
27
19
|
|
@@ -47,12 +39,10 @@ module Langchain::Tool
|
|
47
39
|
new.execute_search(input: input)
|
48
40
|
end
|
49
41
|
|
50
|
-
#
|
51
42
|
# Executes Google Search and returns the result
|
52
43
|
#
|
53
44
|
# @param input [String] search query
|
54
45
|
# @return [String] Answer
|
55
|
-
#
|
56
46
|
def execute(input:)
|
57
47
|
Langchain.logger.info("Executing \"#{input}\"", for: self.class)
|
58
48
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"type": "function",
|
4
|
+
"function": {
|
5
|
+
"name": "ruby_code_interpreter-execute",
|
6
|
+
"description": "Executes Ruby code in a sandboxes environment.",
|
7
|
+
"parameters": {
|
8
|
+
"type": "object",
|
9
|
+
"properties": {
|
10
|
+
"input": {
|
11
|
+
"type": "string",
|
12
|
+
"description": "ruby code expression"
|
13
|
+
}
|
14
|
+
},
|
15
|
+
"required": ["input"]
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
]
|
data/lib/langchain/tool/{ruby_code_interpreter.rb → ruby_code_interpreter/ruby_code_interpreter.rb}
RENAMED
@@ -5,12 +5,14 @@ module Langchain::Tool
|
|
5
5
|
#
|
6
6
|
# A tool that execute Ruby code in a sandboxed environment.
|
7
7
|
#
|
8
|
-
# Gem requirements:
|
8
|
+
# Gem requirements:
|
9
|
+
# gem "safe_ruby", "~> 1.0.4"
|
10
|
+
#
|
11
|
+
# Usage:
|
12
|
+
# interpreter = Langchain::Tool::RubyCodeInterpreter.new
|
9
13
|
#
|
10
14
|
NAME = "ruby_code_interpreter"
|
11
|
-
|
12
|
-
A Ruby code interpreter. Use this to execute ruby expressions. Input should be a valid ruby expression. If you want to see the output of the tool, make sure to return a value.
|
13
|
-
DESC
|
15
|
+
ANNOTATIONS_PATH = Langchain.root.join("./langchain/tool/#{NAME}/#{NAME}.json").to_path
|
14
16
|
|
15
17
|
def initialize(timeout: 30)
|
16
18
|
depends_on "safe_ruby"
|
@@ -18,6 +20,8 @@ module Langchain::Tool
|
|
18
20
|
@timeout = timeout
|
19
21
|
end
|
20
22
|
|
23
|
+
# Executes Ruby code in a sandboxes environment.
|
24
|
+
#
|
21
25
|
# @param input [String] ruby code expression
|
22
26
|
# @return [String] Answer
|
23
27
|
def execute(input:)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"type": "function",
|
4
|
+
"function": {
|
5
|
+
"name": "vectorsearch-similarity_search",
|
6
|
+
"description": "Vectorsearch: Retrieves relevant document for the query",
|
7
|
+
"parameters": {
|
8
|
+
"type": "object",
|
9
|
+
"properties": {
|
10
|
+
"query": {
|
11
|
+
"type": "string",
|
12
|
+
"description": "Query to find similar documents for"
|
13
|
+
},
|
14
|
+
"k": {
|
15
|
+
"type": "integer",
|
16
|
+
"description": "Number of similar documents to retrieve",
|
17
|
+
"default": 4
|
18
|
+
}
|
19
|
+
},
|
20
|
+
"required": ["query"]
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
]
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Langchain::Tool
|
4
|
+
class Vectorsearch < Base
|
5
|
+
#
|
6
|
+
# A tool wraps vectorsearch classes
|
7
|
+
#
|
8
|
+
# Usage:
|
9
|
+
# # Initialize the LLM that will be used to generate embeddings
|
10
|
+
# ollama = Langchain::LLM::Ollama.new(url: ENV["OLLAMA_URL"]
|
11
|
+
# chroma = Langchain::Vectorsearch::Chroma.new(url: ENV["CHROMA_URL"], index_name: "my_index", llm: ollama)
|
12
|
+
#
|
13
|
+
# # This tool can now be used by the Assistant
|
14
|
+
# vectorsearch_tool = Langchain::Tool::Vectorsearch.new(vectorsearch: chroma)
|
15
|
+
#
|
16
|
+
NAME = "vectorsearch"
|
17
|
+
ANNOTATIONS_PATH = Langchain.root.join("./langchain/tool/#{NAME}/#{NAME}.json").to_path
|
18
|
+
|
19
|
+
attr_reader :vectorsearch
|
20
|
+
|
21
|
+
# Initializes the Vectorsearch tool
|
22
|
+
#
|
23
|
+
# @param vectorsearch [Langchain::Vectorsearch::Base] Vectorsearch instance to use
|
24
|
+
def initialize(vectorsearch:)
|
25
|
+
@vectorsearch = vectorsearch
|
26
|
+
end
|
27
|
+
|
28
|
+
# Executes the vector search and returns the results
|
29
|
+
#
|
30
|
+
# @param query [String] The query to search for
|
31
|
+
# @param k [Integer] The number of results to return
|
32
|
+
def similarity_search(query:, k: 4)
|
33
|
+
vectorsearch.similarity_search(query:, k: 4)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"type": "function",
|
4
|
+
"function": {
|
5
|
+
"name": "weather-execute",
|
6
|
+
"description": "Returns current weather for a city",
|
7
|
+
"parameters": {
|
8
|
+
"type": "object",
|
9
|
+
"properties": {
|
10
|
+
"input": {
|
11
|
+
"type": "string",
|
12
|
+
"description": "comma separated city and unit (optional: imperial, metric, or standard)"
|
13
|
+
}
|
14
|
+
},
|
15
|
+
"required": ["input"]
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
]
|
@@ -13,31 +13,18 @@ module Langchain::Tool
|
|
13
13
|
# api_key: https://home.openweathermap.org/api_keys
|
14
14
|
#
|
15
15
|
# Usage:
|
16
|
-
# weather = Langchain::Tool::Weather.new(api_key: "
|
16
|
+
# weather = Langchain::Tool::Weather.new(api_key: ENV["OPEN_WEATHER_API_KEY"])
|
17
17
|
# weather.execute(input: "Boston, MA; imperial")
|
18
18
|
#
|
19
|
-
|
20
19
|
NAME = "weather"
|
21
|
-
|
22
|
-
description <<~DESC
|
23
|
-
Useful for getting current weather data
|
24
|
-
|
25
|
-
The input to this tool should be a city name followed by the units (imperial, metric, or standard)
|
26
|
-
Usage:
|
27
|
-
Action Input: St Louis, Missouri; metric
|
28
|
-
Action Input: Boston, Massachusetts; imperial
|
29
|
-
Action Input: Dubai, AE; imperial
|
30
|
-
Action Input: Kiev, Ukraine; metric
|
31
|
-
DESC
|
20
|
+
ANNOTATIONS_PATH = Langchain.root.join("./langchain/tool/#{NAME}/#{NAME}.json").to_path
|
32
21
|
|
33
22
|
attr_reader :client, :units
|
34
23
|
|
35
|
-
#
|
36
24
|
# Initializes the Weather tool
|
37
25
|
#
|
38
26
|
# @param api_key [String] Open Weather API key
|
39
27
|
# @return [Langchain::Tool::Weather] Weather tool
|
40
|
-
#
|
41
28
|
def initialize(api_key:, units: "metric")
|
42
29
|
depends_on "open-weather-ruby-client"
|
43
30
|
require "open-weather-ruby-client"
|
@@ -51,6 +38,7 @@ module Langchain::Tool
|
|
51
38
|
end
|
52
39
|
|
53
40
|
# Returns current weather for a city
|
41
|
+
#
|
54
42
|
# @param input [String] comma separated city and unit (optional: imperial, metric, or standard)
|
55
43
|
# @return [String] Answer
|
56
44
|
def execute(input:)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"type": "function",
|
4
|
+
"function": {
|
5
|
+
"name": "wikipedia-execute",
|
6
|
+
"description": "Executes Wikipedia API search and returns the answer",
|
7
|
+
"parameters": {
|
8
|
+
"type": "object",
|
9
|
+
"properties": {
|
10
|
+
"input": {
|
11
|
+
"type": "string",
|
12
|
+
"description": "search query"
|
13
|
+
}
|
14
|
+
},
|
15
|
+
"required": ["input"]
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
]
|
@@ -5,23 +5,23 @@ module Langchain::Tool
|
|
5
5
|
#
|
6
6
|
# Tool that adds the capability to search using the Wikipedia API
|
7
7
|
#
|
8
|
-
# Gem requirements:
|
8
|
+
# Gem requirements:
|
9
|
+
# gem "wikipedia-client", "~> 1.17.0"
|
10
|
+
#
|
11
|
+
# Usage:
|
12
|
+
# weather = Langchain::Tool::Wikipedia.new
|
13
|
+
# weather.execute(input: "The Roman Empire")
|
9
14
|
#
|
10
15
|
NAME = "wikipedia"
|
11
|
-
|
12
|
-
A wrapper around Wikipedia.
|
13
|
-
|
14
|
-
Useful for when you need to answer general questions about
|
15
|
-
people, places, companies, facts, historical events, or other subjects.
|
16
|
-
|
17
|
-
Input should be a search query.
|
18
|
-
DESC
|
16
|
+
ANNOTATIONS_PATH = Langchain.root.join("./langchain/tool/#{NAME}/#{NAME}.json").to_path
|
19
17
|
|
18
|
+
# Initializes the Wikipedia tool
|
20
19
|
def initialize
|
21
20
|
depends_on "wikipedia-client", req: "wikipedia"
|
22
21
|
end
|
23
22
|
|
24
23
|
# Executes Wikipedia API search and returns the answer
|
24
|
+
#
|
25
25
|
# @param input [String] search query
|
26
26
|
# @return [String] Answer
|
27
27
|
def execute(input:)
|
@@ -22,8 +22,8 @@ module Langchain
|
|
22
22
|
# @param model_name [String] The model name to validate against
|
23
23
|
# @return [Integer] The token length of the text
|
24
24
|
#
|
25
|
-
def self.token_length(text, model_name,
|
26
|
-
res =
|
25
|
+
def self.token_length(text, model_name, options = {})
|
26
|
+
res = options[:llm].tokenize(text)
|
27
27
|
res.dig(:tokens).length
|
28
28
|
end
|
29
29
|
|
@@ -31,6 +31,10 @@ module Langchain
|
|
31
31
|
TOKEN_LIMITS[model_name]
|
32
32
|
end
|
33
33
|
singleton_class.alias_method :completion_token_limit, :token_limit
|
34
|
+
|
35
|
+
def self.token_length_from_messages(messages, model_name, options)
|
36
|
+
messages.sum { |message| token_length(message.to_json, model_name, options) }
|
37
|
+
end
|
34
38
|
end
|
35
39
|
end
|
36
40
|
end
|
@@ -14,7 +14,7 @@ module Langchain
|
|
14
14
|
class BaseValidator
|
15
15
|
def self.validate_max_tokens!(content, model_name, options = {})
|
16
16
|
text_token_length = if content.is_a?(Array)
|
17
|
-
content
|
17
|
+
token_length_from_messages(content, model_name, options)
|
18
18
|
else
|
19
19
|
token_length(content, model_name, options)
|
20
20
|
end
|
@@ -30,8 +30,8 @@ module Langchain
|
|
30
30
|
# @param model_name [String] The model name to validate against
|
31
31
|
# @return [Integer] The token length of the text
|
32
32
|
#
|
33
|
-
def self.token_length(text, model_name,
|
34
|
-
res =
|
33
|
+
def self.token_length(text, model_name, options = {})
|
34
|
+
res = options[:llm].tokenize(text: text)
|
35
35
|
res["tokens"].length
|
36
36
|
end
|
37
37
|
|
@@ -39,6 +39,10 @@ module Langchain
|
|
39
39
|
TOKEN_LIMITS[model_name]
|
40
40
|
end
|
41
41
|
singleton_class.alias_method :completion_token_limit, :token_limit
|
42
|
+
|
43
|
+
def self.token_length_from_messages(messages, model_name, options)
|
44
|
+
messages.sum { |message| token_length(message.to_json, model_name, options) }
|
45
|
+
end
|
42
46
|
end
|
43
47
|
end
|
44
48
|
end
|
@@ -35,7 +35,7 @@ module Langchain
|
|
35
35
|
# @option options [Langchain::LLM:GooglePalm] :llm The Langchain::LLM:GooglePalm instance
|
36
36
|
# @return [Integer] The token length of the text
|
37
37
|
#
|
38
|
-
def self.token_length(text, model_name = "chat-bison-001", options)
|
38
|
+
def self.token_length(text, model_name = "chat-bison-001", options = {})
|
39
39
|
response = options[:llm].client.count_message_tokens(model: model_name, prompt: text)
|
40
40
|
|
41
41
|
raise Langchain::LLM::ApiError.new(response["error"]["message"]) unless response["error"].nil?
|
@@ -43,6 +43,10 @@ module Langchain
|
|
43
43
|
response.dig("tokenCount")
|
44
44
|
end
|
45
45
|
|
46
|
+
def self.token_length_from_messages(messages, model_name, options = {})
|
47
|
+
messages.sum { |message| token_length(message.to_json, model_name, options) }
|
48
|
+
end
|
49
|
+
|
46
50
|
def self.token_limit(model_name)
|
47
51
|
TOKEN_LIMITS.dig(model_name, "input_token_limit")
|
48
52
|
end
|
@@ -15,17 +15,23 @@ module Langchain
|
|
15
15
|
# Source:
|
16
16
|
# https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo
|
17
17
|
"gpt-4-1106-preview" => 4096,
|
18
|
-
"gpt-4-vision-preview" => 4096
|
18
|
+
"gpt-4-vision-preview" => 4096,
|
19
|
+
"gpt-3.5-turbo-1106" => 4096
|
19
20
|
}
|
20
21
|
|
22
|
+
# NOTE: The gpt-4-turbo-preview is an alias that will always point to the latest GPT 4 Turbo preview
|
23
|
+
# the future previews may have a different token limit!
|
21
24
|
TOKEN_LIMITS = {
|
22
25
|
# Source:
|
23
26
|
# https://platform.openai.com/docs/api-reference/embeddings
|
24
27
|
# https://platform.openai.com/docs/models/gpt-4
|
28
|
+
"text-embedding-3-large" => 8191,
|
29
|
+
"text-embedding-3-small" => 8191,
|
25
30
|
"text-embedding-ada-002" => 8191,
|
26
31
|
"gpt-3.5-turbo" => 4096,
|
27
32
|
"gpt-3.5-turbo-0301" => 4096,
|
28
33
|
"gpt-3.5-turbo-0613" => 4096,
|
34
|
+
"gpt-3.5-turbo-1106" => 16385,
|
29
35
|
"gpt-3.5-turbo-16k" => 16384,
|
30
36
|
"gpt-3.5-turbo-16k-0613" => 16384,
|
31
37
|
"text-davinci-003" => 4097,
|
@@ -38,6 +44,8 @@ module Langchain
|
|
38
44
|
"gpt-4-32k-0314" => 32768,
|
39
45
|
"gpt-4-32k-0613" => 32768,
|
40
46
|
"gpt-4-1106-preview" => 128000,
|
47
|
+
"gpt-4-turbo-preview" => 128000,
|
48
|
+
"gpt-4-0125-preview" => 128000,
|
41
49
|
"gpt-4-vision-preview" => 128000,
|
42
50
|
"text-curie-001" => 2049,
|
43
51
|
"text-babbage-001" => 2049,
|
@@ -56,6 +64,11 @@ module Langchain
|
|
56
64
|
# @return [Integer] The token length of the text
|
57
65
|
#
|
58
66
|
def self.token_length(text, model_name, options = {})
|
67
|
+
# tiktoken-ruby doesn't support text-embedding-3-large or text-embedding-3-small yet
|
68
|
+
if ["text-embedding-3-large", "text-embedding-3-small"].include?(model_name)
|
69
|
+
model_name = "text-embedding-ada-002"
|
70
|
+
end
|
71
|
+
|
59
72
|
encoder = Tiktoken.encoding_for_model(model_name)
|
60
73
|
encoder.encode(text).length
|
61
74
|
end
|
@@ -73,6 +86,47 @@ module Langchain
|
|
73
86
|
max_tokens = super(content, model_name, options)
|
74
87
|
[options[:max_tokens], max_tokens].reject(&:nil?).min
|
75
88
|
end
|
89
|
+
|
90
|
+
# Copied from https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb
|
91
|
+
# Return the number of tokens used by a list of messages
|
92
|
+
#
|
93
|
+
# @param messages [Array<Hash>] The messages to calculate the token length for
|
94
|
+
# @param model [String] The model name to validate against
|
95
|
+
# @return [Integer] The token length of the messages
|
96
|
+
#
|
97
|
+
def self.token_length_from_messages(messages, model_name, options = {})
|
98
|
+
encoding = Tiktoken.encoding_for_model(model_name)
|
99
|
+
|
100
|
+
if ["gpt-3.5-turbo-0613", "gpt-3.5-turbo-16k-0613", "gpt-4-0314", "gpt-4-32k-0314", "gpt-4-0613", "gpt-4-32k-0613"].include?(model_name)
|
101
|
+
tokens_per_message = 3
|
102
|
+
tokens_per_name = 1
|
103
|
+
elsif model_name == "gpt-3.5-turbo-0301"
|
104
|
+
tokens_per_message = 4 # every message follows {role/name}\n{content}\n
|
105
|
+
tokens_per_name = -1 # if there's a name, the role is omitted
|
106
|
+
elsif model_name.include?("gpt-3.5-turbo")
|
107
|
+
# puts "Warning: gpt-3.5-turbo may update over time. Returning num tokens assuming gpt-3.5-turbo-0613."
|
108
|
+
return token_length_from_messages(messages, "gpt-3.5-turbo-0613", options)
|
109
|
+
elsif model_name.include?("gpt-4")
|
110
|
+
# puts "Warning: gpt-4 may update over time. Returning num tokens assuming gpt-4-0613."
|
111
|
+
return token_length_from_messages(messages, "gpt-4-0613", options)
|
112
|
+
else
|
113
|
+
raise NotImplementedError.new(
|
114
|
+
"token_length_from_messages() is not implemented for model #{model_name}. See https://github.com/openai/openai-python/blob/main/chatml.md for information on how messages are converted to tokens."
|
115
|
+
)
|
116
|
+
end
|
117
|
+
|
118
|
+
num_tokens = 0
|
119
|
+
messages.each do |message|
|
120
|
+
num_tokens += tokens_per_message
|
121
|
+
message.each do |key, value|
|
122
|
+
num_tokens += encoding.encode(value).length
|
123
|
+
num_tokens += tokens_per_name if ["name", :name].include?(key)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
num_tokens += 3 # every reply is primed with assistant
|
128
|
+
num_tokens
|
129
|
+
end
|
76
130
|
end
|
77
131
|
end
|
78
132
|
end
|
@@ -7,6 +7,7 @@ module Langchain::Vectorsearch
|
|
7
7
|
# == Available vector databases
|
8
8
|
#
|
9
9
|
# - {Langchain::Vectorsearch::Chroma}
|
10
|
+
# - {Langchain::Vectorsearch::Epsilla}
|
10
11
|
# - {Langchain::Vectorsearch::Elasticsearch}
|
11
12
|
# - {Langchain::Vectorsearch::Hnswlib}
|
12
13
|
# - {Langchain::Vectorsearch::Milvus}
|
@@ -29,10 +30,11 @@ module Langchain::Vectorsearch
|
|
29
30
|
# )
|
30
31
|
#
|
31
32
|
# # You can instantiate other supported vector databases the same way:
|
33
|
+
# epsilla = Langchain::Vectorsearch::Epsilla.new(...)
|
32
34
|
# milvus = Langchain::Vectorsearch::Milvus.new(...)
|
33
35
|
# qdrant = Langchain::Vectorsearch::Qdrant.new(...)
|
34
36
|
# pinecone = Langchain::Vectorsearch::Pinecone.new(...)
|
35
|
-
#
|
37
|
+
# chroma = Langchain::Vectorsearch::Chroma.new(...)
|
36
38
|
# pgvector = Langchain::Vectorsearch::Pgvector.new(...)
|
37
39
|
#
|
38
40
|
# == Schema Creation
|
@@ -122,6 +124,11 @@ module Langchain::Vectorsearch
|
|
122
124
|
raise NotImplementedError, "#{self.class.name} does not support updating texts"
|
123
125
|
end
|
124
126
|
|
127
|
+
# Method supported by Vectorsearch DB to delete a list of texts from the index
|
128
|
+
def remove_texts(...)
|
129
|
+
raise NotImplementedError, "#{self.class.name} does not support deleting texts"
|
130
|
+
end
|
131
|
+
|
125
132
|
# Method supported by Vectorsearch DB to search for similar texts in the index
|
126
133
|
def similarity_search(...)
|
127
134
|
raise NotImplementedError, "#{self.class.name} does not support similarity search"
|
@@ -134,7 +141,7 @@ module Langchain::Vectorsearch
|
|
134
141
|
# @param k [Integer] The number of results to return
|
135
142
|
# @return [String] Response
|
136
143
|
def similarity_search_with_hyde(query:, k: 4)
|
137
|
-
hyde_completion = llm.complete(prompt: generate_hyde_prompt(question: query))
|
144
|
+
hyde_completion = llm.complete(prompt: generate_hyde_prompt(question: query)).completion
|
138
145
|
similarity_search(query: hyde_completion, k: k)
|
139
146
|
end
|
140
147
|
|
@@ -173,13 +180,13 @@ module Langchain::Vectorsearch
|
|
173
180
|
prompt_template.format(question: question, context: context)
|
174
181
|
end
|
175
182
|
|
176
|
-
def add_data(paths:)
|
183
|
+
def add_data(paths:, options: {}, chunker: Langchain::Chunker::Text)
|
177
184
|
raise ArgumentError, "Paths must be provided" if Array(paths).empty?
|
178
185
|
|
179
186
|
texts = Array(paths)
|
180
187
|
.flatten
|
181
188
|
.map do |path|
|
182
|
-
data = Langchain::Loader.new(path)&.load&.chunks
|
189
|
+
data = Langchain::Loader.new(path, options, chunker: chunker)&.load&.chunks
|
183
190
|
data.map { |chunk| chunk.text }
|
184
191
|
end
|
185
192
|
|
@@ -60,6 +60,13 @@ module Langchain::Vectorsearch
|
|
60
60
|
collection.update(embeddings)
|
61
61
|
end
|
62
62
|
|
63
|
+
# Remove a list of texts from the index
|
64
|
+
# @param ids [Array<String>] The list of ids to remove
|
65
|
+
# @return [Hash] The response from the server
|
66
|
+
def remove_texts(ids:)
|
67
|
+
collection.delete(ids)
|
68
|
+
end
|
69
|
+
|
63
70
|
# Create the collection with the default schema
|
64
71
|
# @return [::Chroma::Resources::Collection] Created collection
|
65
72
|
def create_default_schema
|
@@ -126,7 +133,9 @@ module Langchain::Vectorsearch
|
|
126
133
|
|
127
134
|
prompt = generate_rag_prompt(question: question, context: context)
|
128
135
|
|
129
|
-
|
136
|
+
messages = [{role: "user", content: prompt}]
|
137
|
+
response = llm.chat(messages: messages, &block)
|
138
|
+
|
130
139
|
response.context = context
|
131
140
|
response
|
132
141
|
end
|