llm_chain 0.5.3 → 0.5.5
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 +30 -2
- data/README.md +15 -6
- data/examples/quick_demo.rb +1 -1
- data/examples/tools_example.rb +2 -2
- data/exe/llm-chain +7 -4
- data/lib/llm_chain/builders/memory_context.rb +24 -0
- data/lib/llm_chain/builders/prompt.rb +26 -0
- data/lib/llm_chain/builders/rag_documents.rb +25 -0
- data/lib/llm_chain/builders/retriever_context.rb +25 -0
- data/lib/llm_chain/builders/tool_responses.rb +27 -0
- data/lib/llm_chain/chain.rb +89 -88
- data/lib/llm_chain/client_registry.rb +2 -0
- data/lib/llm_chain/clients/base.rb +24 -2
- data/lib/llm_chain/clients/deepseek_coder_v2.rb +32 -0
- data/lib/llm_chain/configuration_validator.rb +1 -1
- data/lib/llm_chain/interfaces/builders/memory_context_builder.rb +20 -0
- data/lib/llm_chain/interfaces/builders/prompt_builder.rb +23 -0
- data/lib/llm_chain/interfaces/builders/rag_documents_builder.rb +20 -0
- data/lib/llm_chain/interfaces/builders/retriever_context_builder.rb +22 -0
- data/lib/llm_chain/interfaces/builders/tool_responses_builder.rb +20 -0
- data/lib/llm_chain/interfaces/memory.rb +38 -0
- data/lib/llm_chain/interfaces/tool_manager.rb +87 -0
- data/lib/llm_chain/memory/array.rb +18 -1
- data/lib/llm_chain/memory/redis.rb +20 -3
- data/lib/llm_chain/system_diagnostics.rb +73 -0
- data/lib/llm_chain/tools/base.rb +103 -0
- data/lib/llm_chain/tools/base_tool.rb +6 -76
- data/lib/llm_chain/tools/calculator.rb +118 -45
- data/lib/llm_chain/tools/code_interpreter.rb +43 -43
- data/lib/llm_chain/tools/date_time.rb +58 -0
- data/lib/llm_chain/tools/tool_manager.rb +46 -88
- data/lib/llm_chain/tools/tool_manager_factory.rb +44 -0
- data/lib/llm_chain/tools/web_search.rb +168 -336
- data/lib/llm_chain/version.rb +1 -1
- data/lib/llm_chain.rb +58 -56
- metadata +19 -2
@@ -1,6 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../interfaces/tool_manager'
|
4
|
+
|
1
5
|
module LLMChain
|
2
6
|
module Tools
|
3
|
-
|
7
|
+
# ToolManager manages registration, selection, and execution of tools in LLMChain.
|
8
|
+
# Implements the LLMChain::Interfaces::ToolManager interface.
|
9
|
+
class ToolManager < Interfaces::ToolManager
|
4
10
|
attr_reader :tools
|
5
11
|
|
6
12
|
def initialize(tools: [])
|
@@ -8,43 +14,49 @@ module LLMChain
|
|
8
14
|
tools.each { |tool| register_tool(tool) }
|
9
15
|
end
|
10
16
|
|
11
|
-
#
|
17
|
+
# Register a new tool instance.
|
18
|
+
# @param tool [LLMChain::Tools::Base]
|
19
|
+
# @return [void]
|
12
20
|
def register_tool(tool)
|
13
|
-
unless tool.is_a?(
|
14
|
-
raise ArgumentError, "Tool must inherit from
|
21
|
+
unless tool.is_a?(Base)
|
22
|
+
raise ArgumentError, "Tool must inherit from LLMChain::Tools::Base"
|
15
23
|
end
|
16
24
|
@tools[tool.name] = tool
|
17
25
|
end
|
18
26
|
|
19
|
-
#
|
27
|
+
# Unregister a tool by name.
|
28
|
+
# @param name [String]
|
29
|
+
# @return [void]
|
20
30
|
def unregister_tool(name)
|
21
31
|
@tools.delete(name.to_s)
|
22
32
|
end
|
23
33
|
|
24
|
-
#
|
34
|
+
# Fetch a tool by its name.
|
35
|
+
# @param name [String]
|
36
|
+
# @return [LLMChain::Tools::Base, nil]
|
25
37
|
def get_tool(name)
|
26
38
|
@tools[name.to_s]
|
27
39
|
end
|
28
40
|
|
29
|
-
#
|
41
|
+
# List all registered tools.
|
42
|
+
# @return [Array<LLMChain::Tools::Base>]
|
30
43
|
def list_tools
|
31
44
|
@tools.values
|
32
45
|
end
|
33
46
|
|
34
|
-
#
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
# Находит подходящие инструменты для промпта
|
47
|
+
# Find tools whose #match? returns true for the prompt.
|
48
|
+
# @param prompt [String]
|
49
|
+
# @return [Array<LLMChain::Tools::Base>]
|
40
50
|
def find_matching_tools(prompt)
|
41
51
|
@tools.values.select { |tool| tool.match?(prompt) }
|
42
52
|
end
|
43
53
|
|
44
|
-
#
|
54
|
+
# Execute every matching tool and collect results.
|
55
|
+
# @param prompt [String]
|
56
|
+
# @param context [Hash]
|
57
|
+
# @return [Hash] mapping tool name → result hash
|
45
58
|
def execute_tools(prompt, context: {})
|
46
59
|
matching_tools = find_matching_tools(prompt)
|
47
|
-
|
48
60
|
results = {}
|
49
61
|
matching_tools.each do |tool|
|
50
62
|
begin
|
@@ -62,102 +74,45 @@ module LLMChain
|
|
62
74
|
}
|
63
75
|
end
|
64
76
|
end
|
65
|
-
|
66
77
|
results
|
67
78
|
end
|
68
79
|
|
69
|
-
#
|
70
|
-
|
71
|
-
|
72
|
-
raise ArgumentError, "Tool '#{name}' not found" unless tool
|
73
|
-
|
74
|
-
begin
|
75
|
-
result = tool.call(prompt, context: context)
|
76
|
-
{
|
77
|
-
success: true,
|
78
|
-
result: result,
|
79
|
-
formatted: tool.format_result(result)
|
80
|
-
}
|
81
|
-
rescue => e
|
82
|
-
{
|
83
|
-
success: false,
|
84
|
-
error: e.message,
|
85
|
-
formatted: "Error in #{name}: #{e.message}"
|
86
|
-
}
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
# Создает стандартный набор инструментов
|
91
|
-
def self.create_default_toolset
|
92
|
-
tools = [
|
93
|
-
Calculator.new,
|
94
|
-
WebSearch.new,
|
95
|
-
CodeInterpreter.new
|
96
|
-
]
|
97
|
-
|
98
|
-
new(tools: tools)
|
99
|
-
end
|
100
|
-
|
101
|
-
# Создает набор инструментов из конфигурации
|
102
|
-
def self.from_config(config)
|
103
|
-
tools = []
|
104
|
-
|
105
|
-
config.each do |tool_config|
|
106
|
-
tool_class = tool_config[:class] || tool_config['class']
|
107
|
-
tool_options = tool_config[:options] || tool_config['options'] || {}
|
108
|
-
|
109
|
-
case tool_class.to_s.downcase
|
110
|
-
when 'calculator'
|
111
|
-
tools << Calculator.new
|
112
|
-
when 'web_search', 'websearch'
|
113
|
-
tools << WebSearch.new(**tool_options)
|
114
|
-
when 'code_interpreter', 'codeinterpreter'
|
115
|
-
tools << CodeInterpreter.new(**tool_options)
|
116
|
-
else
|
117
|
-
raise ArgumentError, "Unknown tool class: #{tool_class}"
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
new(tools: tools)
|
122
|
-
end
|
123
|
-
|
124
|
-
# Форматирует результаты выполнения для включения в промпт
|
80
|
+
# Format tool execution results for inclusion into an LLM prompt.
|
81
|
+
# @param results [Hash]
|
82
|
+
# @return [String]
|
125
83
|
def format_tool_results(results)
|
126
84
|
return "" if results.empty?
|
127
|
-
|
128
85
|
formatted_results = results.map do |tool_name, result|
|
129
86
|
"#{tool_name}: #{result[:formatted]}"
|
130
87
|
end
|
131
|
-
|
132
88
|
"Tool Results:\n#{formatted_results.join("\n\n")}"
|
133
89
|
end
|
134
90
|
|
135
|
-
#
|
91
|
+
# Human-readable list of available tools.
|
92
|
+
# @return [String]
|
136
93
|
def tools_description
|
137
94
|
descriptions = @tools.values.map do |tool|
|
138
95
|
"- #{tool.name}: #{tool.description}"
|
139
96
|
end
|
140
|
-
|
141
97
|
"Available tools:\n#{descriptions.join("\n")}"
|
142
98
|
end
|
143
99
|
|
144
|
-
#
|
100
|
+
# Determine if prompt likely needs tool usage.
|
101
|
+
# @param prompt [String]
|
102
|
+
# @return [Boolean]
|
145
103
|
def needs_tools?(prompt)
|
146
|
-
# Проверяем явные запросы на использование инструментов
|
147
104
|
return true if prompt.match?(/\b(use tool|call tool|execute|calculate|search|run code)\b/i)
|
148
|
-
|
149
|
-
# Проверяем, есть ли подходящие инструменты
|
150
105
|
find_matching_tools(prompt).any?
|
151
106
|
end
|
152
107
|
|
153
|
-
#
|
108
|
+
# Auto-select and execute best tools for prompt.
|
109
|
+
# @param prompt [String]
|
110
|
+
# @param context [Hash]
|
111
|
+
# @return [Hash]
|
154
112
|
def auto_execute(prompt, context: {})
|
155
113
|
return {} unless needs_tools?(prompt)
|
156
|
-
|
157
|
-
# Ограничиваем количество одновременно выполняемых инструментов
|
158
114
|
matching_tools = find_matching_tools(prompt)
|
159
115
|
selected_tools = select_best_tools(matching_tools, prompt)
|
160
|
-
|
161
116
|
results = {}
|
162
117
|
selected_tools.each do |tool|
|
163
118
|
begin
|
@@ -175,15 +130,19 @@ module LLMChain
|
|
175
130
|
}
|
176
131
|
end
|
177
132
|
end
|
178
|
-
|
179
133
|
results
|
180
134
|
end
|
181
135
|
|
136
|
+
# Build JSON schemas for all registered tools.
|
137
|
+
# @return [Array<Hash>]
|
138
|
+
def get_tools_schema
|
139
|
+
@tools.values.map(&:to_schema)
|
140
|
+
end
|
141
|
+
|
182
142
|
private
|
183
143
|
|
184
|
-
#
|
144
|
+
# Simple heuristic to rank matching tools.
|
185
145
|
def select_best_tools(tools, prompt, limit: 3)
|
186
|
-
# Простая логика приоритизации
|
187
146
|
prioritized = tools.sort_by do |tool|
|
188
147
|
case tool.name
|
189
148
|
when 'calculator'
|
@@ -196,7 +155,6 @@ module LLMChain
|
|
196
155
|
1
|
197
156
|
end
|
198
157
|
end
|
199
|
-
|
200
158
|
prioritized.first(limit)
|
201
159
|
end
|
202
160
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LLMChain
|
4
|
+
module Tools
|
5
|
+
# Factory for creating ToolManager instances with default or custom toolsets.
|
6
|
+
module ToolManagerFactory
|
7
|
+
# Create a ToolManager with the default set of tools.
|
8
|
+
# @return [ToolManager]
|
9
|
+
def self.create_default_toolset
|
10
|
+
tools = [
|
11
|
+
Calculator.new,
|
12
|
+
WebSearch.new,
|
13
|
+
CodeInterpreter.new,
|
14
|
+
DateTime.new
|
15
|
+
]
|
16
|
+
ToolManager.new(tools: tools)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Create a ToolManager from a config array.
|
20
|
+
# @param config [Array<Hash>] tool config hashes
|
21
|
+
# @return [ToolManager]
|
22
|
+
def self.from_config(config)
|
23
|
+
tools = []
|
24
|
+
config.each do |tool_config|
|
25
|
+
tool_class = tool_config[:class] || tool_config['class']
|
26
|
+
tool_options = tool_config[:options] || tool_config['options'] || {}
|
27
|
+
case tool_class.to_s.downcase
|
28
|
+
when 'calculator'
|
29
|
+
tools << Calculator.new
|
30
|
+
when 'web_search', 'websearch'
|
31
|
+
tools << WebSearch.new(**tool_options)
|
32
|
+
when 'code_interpreter', 'codeinterpreter'
|
33
|
+
tools << CodeInterpreter.new(**tool_options)
|
34
|
+
when 'date_time', 'datetime'
|
35
|
+
tools << DateTime.new
|
36
|
+
else
|
37
|
+
raise ArgumentError, "Unknown tool class: #{tool_class}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
ToolManager.new(tools: tools)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|