kbs 0.0.1 → 0.1.0
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/.github/workflows/deploy-github-pages.yml +52 -0
- data/CHANGELOG.md +68 -2
- data/README.md +235 -334
- data/docs/DOCUMENTATION_STATUS.md +158 -0
- data/docs/advanced/custom-persistence.md +775 -0
- data/docs/advanced/debugging.md +726 -0
- data/docs/advanced/index.md +8 -0
- data/docs/advanced/performance.md +832 -0
- data/docs/advanced/testing.md +691 -0
- data/docs/api/blackboard.md +1157 -0
- data/docs/api/engine.md +978 -0
- data/docs/api/facts.md +1212 -0
- data/docs/api/index.md +12 -0
- data/docs/api/rules.md +1034 -0
- data/docs/architecture/blackboard.md +553 -0
- data/docs/architecture/index.md +277 -0
- data/docs/architecture/network-structure.md +343 -0
- data/docs/architecture/rete-algorithm.md +737 -0
- data/docs/assets/css/custom.css +83 -0
- data/docs/assets/images/blackboard-architecture.svg +136 -0
- data/docs/assets/images/compiled-network.svg +101 -0
- data/docs/assets/images/fact-assertion-flow.svg +117 -0
- data/docs/assets/images/kbs.jpg +0 -0
- data/docs/assets/images/pattern-matching-trace.svg +136 -0
- data/docs/assets/images/rete-network-layers.svg +96 -0
- data/docs/assets/images/system-layers.svg +69 -0
- data/docs/assets/images/trading-signal-network.svg +139 -0
- data/docs/assets/js/mathjax.js +17 -0
- data/docs/examples/expert-systems.md +1031 -0
- data/docs/examples/index.md +9 -0
- data/docs/examples/multi-agent.md +1335 -0
- data/docs/examples/stock-trading.md +488 -0
- data/docs/guides/blackboard-memory.md +558 -0
- data/docs/guides/dsl.md +1321 -0
- data/docs/guides/facts.md +652 -0
- data/docs/guides/getting-started.md +383 -0
- data/docs/guides/index.md +23 -0
- data/docs/guides/negation.md +529 -0
- data/docs/guides/pattern-matching.md +561 -0
- data/docs/guides/persistence.md +451 -0
- data/docs/guides/variable-binding.md +491 -0
- data/docs/guides/writing-rules.md +755 -0
- data/docs/index.md +157 -0
- data/docs/installation.md +156 -0
- data/docs/quick-start.md +228 -0
- data/examples/README.md +2 -2
- data/examples/advanced_example.rb +2 -2
- data/examples/advanced_example_dsl.rb +224 -0
- data/examples/ai_enhanced_kbs.rb +1 -1
- data/examples/ai_enhanced_kbs_dsl.rb +538 -0
- data/examples/blackboard_demo_dsl.rb +50 -0
- data/examples/car_diagnostic.rb +1 -1
- data/examples/car_diagnostic_dsl.rb +54 -0
- data/examples/concurrent_inference_demo.rb +5 -5
- data/examples/concurrent_inference_demo_dsl.rb +363 -0
- data/examples/csv_trading_system.rb +1 -1
- data/examples/csv_trading_system_dsl.rb +525 -0
- data/examples/knowledge_base.db +0 -0
- data/examples/portfolio_rebalancing_system.rb +2 -2
- data/examples/portfolio_rebalancing_system_dsl.rb +613 -0
- data/examples/redis_trading_demo_dsl.rb +177 -0
- data/examples/run_all.rb +50 -0
- data/examples/run_all_dsl.rb +49 -0
- data/examples/stock_trading_advanced.rb +1 -1
- data/examples/stock_trading_advanced_dsl.rb +404 -0
- data/examples/temp.txt +7693 -0
- data/examples/temp_dsl.txt +8447 -0
- data/examples/timestamped_trading.rb +1 -1
- data/examples/timestamped_trading_dsl.rb +258 -0
- data/examples/trading_demo.rb +1 -1
- data/examples/trading_demo_dsl.rb +322 -0
- data/examples/working_demo.rb +1 -1
- data/examples/working_demo_dsl.rb +160 -0
- data/lib/kbs/blackboard/engine.rb +3 -3
- data/lib/kbs/blackboard/fact.rb +1 -1
- data/lib/kbs/condition.rb +1 -1
- data/lib/kbs/dsl/knowledge_base.rb +1 -1
- data/lib/kbs/dsl/variable.rb +1 -1
- data/lib/kbs/{rete_engine.rb → engine.rb} +1 -1
- data/lib/kbs/fact.rb +1 -1
- data/lib/kbs/version.rb +1 -1
- data/lib/kbs.rb +2 -2
- data/mkdocs.yml +181 -0
- metadata +66 -6
- data/examples/stock_trading_system.rb.bak +0 -563
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
Build your first knowledge-based system in 10 minutes. This hands-on tutorial teaches the fundamentals by creating a temperature monitoring system that alerts when sensors exceed thresholds.
|
|
4
|
+
|
|
5
|
+
## What You'll Learn
|
|
6
|
+
|
|
7
|
+
- Creating rules and facts
|
|
8
|
+
- Variable binding across conditions
|
|
9
|
+
- Using negation to prevent duplicate alerts
|
|
10
|
+
- Persisting facts with blackboard memory
|
|
11
|
+
- Controlling rule execution with priorities
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
Add KBS to your Gemfile:
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
gem 'kbs'
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or install directly:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
gem install kbs
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Your First Rule
|
|
28
|
+
|
|
29
|
+
Let's create a simple rule that fires when temperature exceeds a threshold.
|
|
30
|
+
|
|
31
|
+
### Step 1: Create the Engine
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
require 'kbs'
|
|
35
|
+
|
|
36
|
+
# Create the inference engine
|
|
37
|
+
engine = KBS::Engine.new
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The engine manages rules, facts, and executes the pattern matching algorithm.
|
|
41
|
+
|
|
42
|
+
### Step 2: Define a Rule
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
# Define a rule for high temperature alerts
|
|
46
|
+
high_temp_rule = KBS::Rule.new("high_temperature_alert") do |r|
|
|
47
|
+
r.conditions = [
|
|
48
|
+
KBS::Condition.new(:sensor, { id: :sensor_id?, temp: :temp? }),
|
|
49
|
+
KBS::Condition.new(:threshold, { id: :sensor_id?, max: :max? })
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
r.action = lambda do |facts, bindings|
|
|
53
|
+
if bindings[:temp?] > bindings[:max?]
|
|
54
|
+
puts "🚨 ALERT: Sensor #{bindings[:sensor_id?]} at #{bindings[:temp?]}°C"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
engine.add_rule(high_temp_rule)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**What this rule does:**
|
|
63
|
+
|
|
64
|
+
- **Condition 1**: Match any `:sensor` fact, binding its `id` to `:sensor_id?` and `temp` to `:temp?`
|
|
65
|
+
- **Condition 2**: Match a `:threshold` fact with the same `id`, binding `max` to `:max?`
|
|
66
|
+
- **Action**: When both conditions match, compare temperature against threshold
|
|
67
|
+
|
|
68
|
+
**Variable binding** (`:sensor_id?`) ensures we only compare sensors with their own thresholds.
|
|
69
|
+
|
|
70
|
+
### Step 3: Add Facts
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
# Add sensor reading
|
|
74
|
+
engine.add_fact(:sensor, id: "bedroom", temp: 28)
|
|
75
|
+
|
|
76
|
+
# Add threshold
|
|
77
|
+
engine.add_fact(:threshold, id: "bedroom", max: 25)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Facts are observations about the world. The engine automatically matches them against rule conditions.
|
|
81
|
+
|
|
82
|
+
### Step 4: Run the Engine
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
engine.run
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Output:**
|
|
89
|
+
```
|
|
90
|
+
🚨 ALERT: Sensor bedroom at 28°C
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The rule fired because the bedroom temperature (28°C) exceeds its threshold (25°C).
|
|
94
|
+
|
|
95
|
+
## Understanding Variable Binding
|
|
96
|
+
|
|
97
|
+
Variable binding connects facts across conditions. Here's how it works:
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
r.conditions = [
|
|
101
|
+
KBS::Condition.new(:sensor, { id: :sensor_id?, temp: :temp? }),
|
|
102
|
+
KBS::Condition.new(:threshold, { id: :sensor_id?, max: :max? })
|
|
103
|
+
]
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Binding Process:**
|
|
107
|
+
|
|
108
|
+
1. Engine finds a `:sensor` fact: `{ id: "bedroom", temp: 28 }`
|
|
109
|
+
2. Binds `:sensor_id?` → `"bedroom"`, `:temp?` → `28`
|
|
110
|
+
3. Searches for `:threshold` fact where `id` also equals `"bedroom"`
|
|
111
|
+
4. Finds `{ id: "bedroom", max: 25 }`
|
|
112
|
+
5. Binds `:max?` → `25`
|
|
113
|
+
6. Both conditions satisfied → rule fires with bindings: `{ :sensor_id? => "bedroom", :temp? => 28, :max? => 25 }`
|
|
114
|
+
|
|
115
|
+
Without variable binding, the rule would incorrectly match bedroom sensors with kitchen thresholds.
|
|
116
|
+
|
|
117
|
+
## Preventing Duplicate Alerts with Negation
|
|
118
|
+
|
|
119
|
+
Let's prevent the same alert from firing repeatedly:
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
smart_alert_rule = KBS::Rule.new("smart_temperature_alert") do |r|
|
|
123
|
+
r.conditions = [
|
|
124
|
+
KBS::Condition.new(:sensor, { id: :sensor_id?, temp: :temp? }),
|
|
125
|
+
KBS::Condition.new(:threshold, { id: :sensor_id?, max: :max? }),
|
|
126
|
+
# Only fire if no alert already exists for this sensor
|
|
127
|
+
KBS::Condition.new(:alert, { sensor_id: :sensor_id? }, negated: true)
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
r.action = lambda do |facts, bindings|
|
|
131
|
+
if bindings[:temp?] > bindings[:max?]
|
|
132
|
+
puts "🚨 ALERT: Sensor #{bindings[:sensor_id?]} at #{bindings[:temp?]}°C"
|
|
133
|
+
# Record that we sent this alert
|
|
134
|
+
engine.add_fact(:alert, sensor_id: bindings[:sensor_id?])
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Negated condition** (`negated: true`): Rule fires only when NO `:alert` fact exists for this sensor.
|
|
141
|
+
|
|
142
|
+
**Flow:**
|
|
143
|
+
|
|
144
|
+
1. First execution: No `:alert` fact → rule fires, creates `:alert` fact
|
|
145
|
+
2. Second execution: `:alert` fact exists → rule doesn't fire (negation blocks it)
|
|
146
|
+
|
|
147
|
+
## Persisting Facts with Blackboard Memory
|
|
148
|
+
|
|
149
|
+
So far, facts disappear when your program exits. Use blackboard memory for persistence:
|
|
150
|
+
|
|
151
|
+
```ruby
|
|
152
|
+
require 'kbs'
|
|
153
|
+
|
|
154
|
+
# Create engine with SQLite persistence
|
|
155
|
+
engine = KBS::Blackboard::Engine.new(db_path: 'sensors.db')
|
|
156
|
+
|
|
157
|
+
# Add rules (same as before)
|
|
158
|
+
engine.add_rule(smart_alert_rule)
|
|
159
|
+
|
|
160
|
+
# Add facts - these are saved to database
|
|
161
|
+
engine.add_fact(:sensor, id: "bedroom", temp: 28)
|
|
162
|
+
engine.add_fact(:threshold, id: "bedroom", max: 25)
|
|
163
|
+
|
|
164
|
+
engine.run
|
|
165
|
+
|
|
166
|
+
# Facts survive program restart
|
|
167
|
+
engine.close
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Next time you run:**
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
engine = KBS::Blackboard::Engine.new(db_path: 'sensors.db')
|
|
174
|
+
# Facts automatically loaded from database
|
|
175
|
+
puts engine.facts.size # => 2 (sensor + threshold)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Blackboard provides:
|
|
179
|
+
- **Persistence**: Facts saved to SQLite/Redis
|
|
180
|
+
- **Audit Trail**: Complete history of changes
|
|
181
|
+
- **Transactions**: ACID guarantees for multi-fact updates
|
|
182
|
+
|
|
183
|
+
Learn more: [Blackboard Memory Guide](blackboard-memory.md)
|
|
184
|
+
|
|
185
|
+
## Controlling Execution with Priorities
|
|
186
|
+
|
|
187
|
+
When multiple rules match, control firing order with priorities:
|
|
188
|
+
|
|
189
|
+
```ruby
|
|
190
|
+
critical_rule = KBS::Rule.new("critical_alert", priority: 100) do |r|
|
|
191
|
+
r.conditions = [
|
|
192
|
+
KBS::Condition.new(:sensor, { temp: :temp? })
|
|
193
|
+
]
|
|
194
|
+
|
|
195
|
+
r.action = lambda do |facts, bindings|
|
|
196
|
+
if bindings[:temp?] > 50
|
|
197
|
+
puts "🔥 CRITICAL: Immediate shutdown required!"
|
|
198
|
+
exit(1)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
normal_rule = KBS::Rule.new("normal_alert", priority: 10) do |r|
|
|
204
|
+
# ... (less urgent alerts)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
engine.add_rule(critical_rule)
|
|
208
|
+
engine.add_rule(normal_rule)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Priority:** Higher numbers fire first. Default is `0`.
|
|
212
|
+
|
|
213
|
+
**Execution order:**
|
|
214
|
+
1. `critical_alert` (priority 100) - checks for emergency shutdown
|
|
215
|
+
2. `normal_alert` (priority 10) - handles routine alerts
|
|
216
|
+
|
|
217
|
+
## Complete Working Example
|
|
218
|
+
|
|
219
|
+
Here's a complete temperature monitoring system:
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
require 'kbs'
|
|
223
|
+
|
|
224
|
+
class TemperatureMonitor
|
|
225
|
+
def initialize
|
|
226
|
+
@engine = KBS::Blackboard::Engine.new(db_path: 'sensors.db')
|
|
227
|
+
setup_rules
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def setup_rules
|
|
231
|
+
# Rule 1: Send alert when temp exceeds threshold
|
|
232
|
+
alert_rule = KBS::Rule.new("temperature_alert", priority: 50) do |r|
|
|
233
|
+
r.conditions = [
|
|
234
|
+
KBS::Condition.new(:sensor, { id: :id?, temp: :temp? }),
|
|
235
|
+
KBS::Condition.new(:threshold, { id: :id?, max: :max? }),
|
|
236
|
+
KBS::Condition.new(:alert, { sensor_id: :id? }, negated: true)
|
|
237
|
+
]
|
|
238
|
+
|
|
239
|
+
r.action = lambda do |facts, bindings|
|
|
240
|
+
if bindings[:temp?] > bindings[:max?]
|
|
241
|
+
send_alert(bindings[:id?], bindings[:temp?], bindings[:max?])
|
|
242
|
+
@engine.add_fact(:alert, sensor_id: bindings[:id?])
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Rule 2: Clear alert when temp drops below threshold
|
|
248
|
+
clear_rule = KBS::Rule.new("clear_alert", priority: 40) do |r|
|
|
249
|
+
r.conditions = [
|
|
250
|
+
KBS::Condition.new(:sensor, { id: :id?, temp: :temp? }),
|
|
251
|
+
KBS::Condition.new(:threshold, { id: :id?, max: :max? }),
|
|
252
|
+
KBS::Condition.new(:alert, { sensor_id: :id? })
|
|
253
|
+
]
|
|
254
|
+
|
|
255
|
+
r.action = lambda do |facts, bindings|
|
|
256
|
+
if bindings[:temp?] <= bindings[:max?]
|
|
257
|
+
clear_alert(bindings[:id?])
|
|
258
|
+
# Remove the alert fact
|
|
259
|
+
alert_fact = facts.find { |f| f.type == :alert && f[:sensor_id] == bindings[:id?] }
|
|
260
|
+
@engine.remove_fact(alert_fact) if alert_fact
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Rule 3: Emergency shutdown for extreme temps
|
|
266
|
+
emergency_rule = KBS::Rule.new("emergency_shutdown", priority: 100) do |r|
|
|
267
|
+
r.conditions = [
|
|
268
|
+
KBS::Condition.new(:sensor, { temp: :temp? })
|
|
269
|
+
]
|
|
270
|
+
|
|
271
|
+
r.action = lambda do |facts, bindings|
|
|
272
|
+
if bindings[:temp?] > 60
|
|
273
|
+
emergency_shutdown(bindings[:temp?])
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
@engine.add_rule(alert_rule)
|
|
279
|
+
@engine.add_rule(clear_rule)
|
|
280
|
+
@engine.add_rule(emergency_rule)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def add_sensor(id, max_temp)
|
|
284
|
+
@engine.add_fact(:threshold, id: id, max: max_temp)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def update_reading(id, temp)
|
|
288
|
+
# Remove old reading
|
|
289
|
+
old = @engine.facts.find { |f| f.type == :sensor && f[:id] == id }
|
|
290
|
+
@engine.remove_fact(old) if old
|
|
291
|
+
|
|
292
|
+
# Add new reading
|
|
293
|
+
@engine.add_fact(:sensor, id: id, temp: temp)
|
|
294
|
+
@engine.run
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def send_alert(sensor_id, temp, threshold)
|
|
298
|
+
puts "🚨 ALERT: #{sensor_id} at #{temp}°C (threshold: #{threshold}°C)"
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def clear_alert(sensor_id)
|
|
302
|
+
puts "✅ CLEAR: #{sensor_id} back to normal"
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def emergency_shutdown(temp)
|
|
306
|
+
puts "🔥 EMERGENCY SHUTDOWN: Temperature #{temp}°C!"
|
|
307
|
+
exit(1)
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def close
|
|
311
|
+
@engine.close
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
# Usage
|
|
316
|
+
monitor = TemperatureMonitor.new
|
|
317
|
+
|
|
318
|
+
# Register sensors with thresholds
|
|
319
|
+
monitor.add_sensor("bedroom", 25)
|
|
320
|
+
monitor.add_sensor("server_room", 30)
|
|
321
|
+
|
|
322
|
+
# Simulate sensor readings
|
|
323
|
+
monitor.update_reading("bedroom", 28) # => 🚨 ALERT
|
|
324
|
+
monitor.update_reading("server_room", 45) # => 🚨 ALERT
|
|
325
|
+
monitor.update_reading("bedroom", 22) # => ✅ CLEAR
|
|
326
|
+
monitor.update_reading("server_room", 65) # => 🔥 EMERGENCY SHUTDOWN
|
|
327
|
+
|
|
328
|
+
monitor.close
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## Key Concepts Learned
|
|
332
|
+
|
|
333
|
+
✅ **Rules** - Define patterns and actions
|
|
334
|
+
✅ **Facts** - Observations stored in working memory
|
|
335
|
+
✅ **Conditions** - Patterns that match facts
|
|
336
|
+
✅ **Variable Binding** - Connect facts across conditions using `:variable?`
|
|
337
|
+
✅ **Negation** - Match when patterns are absent
|
|
338
|
+
✅ **Priorities** - Control rule firing order
|
|
339
|
+
✅ **Persistence** - Save facts to database with blackboard memory
|
|
340
|
+
|
|
341
|
+
## Troubleshooting
|
|
342
|
+
|
|
343
|
+
### Rule Not Firing
|
|
344
|
+
|
|
345
|
+
**Problem**: Added facts but rule doesn't fire
|
|
346
|
+
|
|
347
|
+
**Checklist**:
|
|
348
|
+
1. Did you call `engine.run`?
|
|
349
|
+
2. Do variable bindings match? (`:sensor_id?` must appear in both conditions)
|
|
350
|
+
3. Check negated conditions - is there a blocking fact?
|
|
351
|
+
4. Verify fact types match condition types exactly (`:sensor` vs `:sensors`)
|
|
352
|
+
|
|
353
|
+
### Performance Issues
|
|
354
|
+
|
|
355
|
+
**Problem**: Slow when adding many facts
|
|
356
|
+
|
|
357
|
+
**Solutions**:
|
|
358
|
+
- Order conditions from most selective to least selective
|
|
359
|
+
- Use Redis store for high-frequency updates: `KBS::Blackboard::Engine.new(store: KBS::Blackboard::Persistence::RedisStore.new)`
|
|
360
|
+
- Minimize negated conditions
|
|
361
|
+
|
|
362
|
+
### Facts Not Persisting
|
|
363
|
+
|
|
364
|
+
**Problem**: Facts disappear after restart
|
|
365
|
+
|
|
366
|
+
**Check**:
|
|
367
|
+
- Using `KBS::Blackboard::Engine` (not `KBS::Engine`)?
|
|
368
|
+
- Provided `db_path` parameter?
|
|
369
|
+
- Called `engine.close` before exit?
|
|
370
|
+
|
|
371
|
+
## Next Steps
|
|
372
|
+
|
|
373
|
+
Now that you understand the basics, explore:
|
|
374
|
+
|
|
375
|
+
- **[Writing Rules](writing-rules.md)** - Advanced rule patterns and techniques
|
|
376
|
+
- **[Pattern Matching](pattern-matching.md)** - Deep dive into condition syntax
|
|
377
|
+
- **[Blackboard Memory](blackboard-memory.md)** - Multi-agent collaboration
|
|
378
|
+
- **[Stock Trading Example](../examples/stock-trading.md)** - Real-world application
|
|
379
|
+
- **[API Reference](../api/engine.md)** - Complete method documentation
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
**Questions?** Open an issue at [github.com/madbomber/kbs](https://github.com/madbomber/kbs)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Guides
|
|
2
|
+
|
|
3
|
+
Practical guides for using KBS effectively.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
- **[Getting Started](getting-started.md)** - Your first rule-based system
|
|
7
|
+
- **[Writing Rules](writing-rules.md)** - Rule authoring best practices
|
|
8
|
+
- **[DSL Reference](dsl.md)** - Complete syntax guide
|
|
9
|
+
|
|
10
|
+
## Core Concepts
|
|
11
|
+
- **[Facts](facts.md)** - Working with facts and queries
|
|
12
|
+
- **[Pattern Matching](pattern-matching.md)** - Pattern syntax and operators
|
|
13
|
+
- **[Variable Binding](variable-binding.md)** - Using variables in rules
|
|
14
|
+
- **[Negation](negation.md)** - Matching absent patterns
|
|
15
|
+
|
|
16
|
+
## Persistence
|
|
17
|
+
- **[Blackboard Memory](blackboard-memory.md)** - Persistent shared memory
|
|
18
|
+
- **[Persistence Options](persistence.md)** - SQLite, Redis, and Hybrid backends
|
|
19
|
+
|
|
20
|
+
## Next Steps
|
|
21
|
+
- **[Examples](../examples/index.md)** - See KBS in action
|
|
22
|
+
- **[Advanced Topics](../advanced/index.md)** - Production optimization
|
|
23
|
+
- **[API Reference](../api/index.md)** - Complete class documentation
|