Chapter 6: rules, or how to decide without deciding
Somewhere in every program like this there is a function full of ifs.
If Jev cannot answer it, refuse. If it is a yes-or-no question, show
Jev's answer. If it needs options, call the LLM, unless... and so on,
until nobody can say what happens to a question without running it in their
head. This package is what that function became instead: a list of rules,
and an engine that runs them.
A fact is something known about the question: can Jev judge it, what kind of question is it, is it several questions. A rule is a few tests on facts and what to do when they all pass. The engine looks at what is known and says what to do next. Here is every rule the site runs, drawn by the site itself:
That picture is /rules.svg, drawn live from this package, so it is always
the network that runs. Read it left to right: the facts, one test on a fact
per box, the joins where a rule's tests meet, and the rules. Click it to see
it bigger.
Try it. https://lmjtfy.fun/rules is the same drawing with every fact clickable. Set
answerableto yes,kindto pick, and watch "draft options" light up: that is the moment the LLM would be called.
The rules, in words
Rule order is priority: of the rules that hold, the first with something left to do decides.
| Rule | When | Then |
|---|---|---|
| refuse | Jev cannot judge it | Say "No. That's not a question I can answer", and stop. |
| answer yes or no | one question, read as yes-or-no, Jev's yes is known | Show Jev's yes: Yes., No., or Yes? / No? when the likelier answer is under 70%. |
| grade it | one question, read as how-much, a general scale will do, Jev's degree is known | Show Jev's degree, from "Not at all" to "Extremely". |
| give the odds | one question, read as how-likely, Jev's chance is known | Show the chance as a percentage, 28%., and say it is a Noul. |
| draft a scale | read as how-much, but it needs its own scale ("how hot is the sun") | Ask the LLM to write the levels. |
| draft options | read as a pick | Ask the LLM to write the options. |
| split it up | several questions | Ask the LLM to write each one. |
| judge the drafts | the LLM wrote something | Ask Jev to judge it. |
| show the answers | Jev judged it | Show them. |
| list it | Jev can judge it, and it is fit to show strangers | Put it on the public feed. |
Two readings can hold at once. Jev answers "what kind of question is this?" with a probability for each kind, and the runner-up counts too when it gets at least 30%. Then the rules of both kinds hold and both are answered: "is C++ better than C#?" comes back as a yes-or-no and as a pick.
Rete, briefly
A rules engine with many rules could test every rule against the facts each time a fact changes. A Rete network (Forgy, 1979) does less: rules that start with the same tests share them, so each distinct test is one node (an alpha), and each rule is a chain of joins over those nodes, shared for as long as two rules begin alike. When a fact arrives, only the nodes that test it change, and only the joins below them are looked at again.
flowchart LR
F1["fact: answerable"] --> A1["answerable = yes"]
F1 --> A0["answerable = no"]
F2["fact: reads Noul"] --> A2["reads Noul = yes"]
A0 --> R0["rule: refuse"]
A1 --> J1(("join"))
A2 --> J1
J1 --> R1["rule: answer yes or no"]
Aside: the one trick. A textbook engine fetches a fact when a rule first needs it, one at a time. That would be slow and expensive here, because each fact from Jev is a network round trip. So this engine does something sneakier: it collects every Jev fact that any rule still alive is waiting on, and asks for them all in one request (
Next::Ask). Jev answers several questions for barely more than one, so the first request usually settles the whole question.
How the page draws it
Under every answer, the page draws this network marked with the question just asked, and it fills in as the answers arrive:
- The Jev facts sit in one frame, because they came in one request. Each shows the number Jev gave, not the yes or no it was read as.
- Filled is what a rule that fired stood on. Outlined was learned and turned out not to be needed. Dashed is a test that failed.
- A rule that holds is pink, and the ones that decided a step are numbered in the order they did.
- A line runs from a rule back round to a fact when the rule's effect is the call that teaches it. That loop is what the engine runs.
For the people who maintain it
A fact is something known about the query (Fact): whether Jev can answer
it, which kinds of question it reads as (four facts, one per Kind: Noul,
Choice, Score, Chance), whether it is several, whether it needs a scale
written for it, Jev's own answer read as yes-or-no, as how-much and as a
chance, whether it is fit to show, whether the LLM drafted anything, whether
Jev judged any of it. A rule (RULES) is a list of tests on facts and what
follows when they all hold: the query ends outright, something is done that
costs a call and teaches another fact, or something is noted that decides no
step (an answer to show, or that the question may go on the feed).
Network::compile merges the rules: one alpha node per distinct test, and
for each rule a chain of joins, shared by rules that begin with the same
tests. Network::next says what to do given what is known:
Next | When |
|---|---|
End | A rule that ends the query outright holds (Jev cannot answer it). |
Do | A rule holds whose effect has not been done yet. |
Ask | No rule decides yet. Every Jev fact that a rule not yet failed is waiting on, to be asked for in one request. |
Done | No rule has anything left to do and nothing more can be learned. What to show is in the notes (Network::shows). |
Network::decide is next with the rule that said so, which is how the
page numbers the rules in the order they decided. Network::alpha and
Network::join give each node's State (holds, fails, waits), and
Network::used says which of the nodes that hold a fired rule stands on.
apps/lmjtfy/src/diagram.rs draws all of it.
In this folder
| Path | What |
|---|---|
| src/ | The engine and the rules. |
| Cargo.toml | The crate. It depends on nothing but serde. |
← Previous: Chapter 5, packages/ · Up: packages · Next: Chapter 6½, rules/src/ →