Duration: 45 minutes
Difficulty: Intermediate
By the end of this module, you will:
- Define deterministic systems vs probabilistic systems
- Understand symbolic reasoning engines
- Grasp the "Untrusted Translator" pattern
- Know which verification engine to use when
Definition: A system is deterministic if the same input always produces the exact same output.
# ✅ Deterministic
def add(a, b):
return a + b
add(2, 3) # Always returns 5
add(2, 3) # Always returns 5
add(2, 3) # Always returns 5# ✅ Deterministic (symbolic math)
import sympy as sp
x = sp.Symbol('x')
derivative = sp.diff(x**2, x)
print(derivative) # Always prints 2*x# ❌ Non-Deterministic
import random
def random_add(a, b):
noise = random.random()
return a + b + noise
random_add(2, 3) # Returns 5.234...
random_add(2, 3) # Returns 5.891...
random_add(2, 3) # Returns 5.123...Critical Systems Need It:
- 🏦 Banking: Same transaction → Same balance
✈️ Aviation: Same controls → Same flight path- 💊 Healthcare: Same dosage calc → Same result
- ⚖️ Legal: Same contract → Same interpretation
Benefits:
- Reproducible - Bugs can be reliably reproduced
- Testable - Unit tests work consistently
- Verifiable - Can prove correctness mathematically
- Debuggable - Step through predictable execution
Symbolic AI uses explicit rules, logic, and mathematical formulas instead of pattern matching.
import sympy as sp
# Define symbolic variables
x, y = sp.symbols('x y')
# Symbolic operations
expr = x**2 + 2*x + 1
factored = sp.factor(expr)
print(factored) # (x + 1)**2
# Calculus
derivative = sp.diff(x**3, x)
print(derivative) # 3*x**2
# Solving equations
solution = sp.solve(x**2 - 4, x)
print(solution) # [-2, 2]Use Cases: Math verification, calculus, algebra, equations
from z3 import *
# Define variables
x = Int('x')
y = Int('y')
# Create solver
solver = Solver()
# Add constraints
solver.add(x + y == 10)
solver.add(x > y)
# Check satisfiability
if solver.check() == sat:
model = solver.model()
print(f"x = {model[x]}, y = {model[y]}")
# Possible output: x = 6, y = 4
# Verify logical statements
p, q = Bools('p q')
formula = Implies(And(p, q), p) # If (p AND q), then p
solver = Solver()
solver.add(Not(formula)) # Try to find counterexample
print(solver.check()) # unsat (no counterexample = proven true)Use Cases: Logic verification, constraint solving, proof checking
import ast
# Parse dangerous code
code = "eval(user_input)"
tree = ast.parse(code)
# Check for dangerous patterns
class DangerDetector(ast.NodeVisitor):
def visit_Call(self, node):
if isinstance(node.func, ast.Name):
if node.func.id in ['eval', 'exec', '__import__']:
print(f"DANGER: Found {node.func.id}()")
self.generic_visit(node)
detector = DangerDetector()
detector.visit(tree) # Output: DANGER: Found eval()Use Cases: Code security, static analysis, vulnerability detection
Don't trust LLMs to compute. Trust them only to translate.
Think of the LLM not as a "Genius Mathematician" (it isn't), but as a Compiler that translates Human Language into Verified Code.
The LLM's only job is Semantic Translation.
- Wrong Way (LLM as Computer):
- User: "Is 10 greater than 5?"
- LLM: "Yes." (Untrusted boolean - might hallucinate)
- Right Way (Untrusted Translator):
- User: "Is 10 greater than 5?"
- LLM:
x > 5(Translation to Z3 DSL) - QWED: Executes
x > 5. (Trusted verification)
User Question (Natural Language)
↓
┌────────────────────────┐
│ LLM (Translator) │ ← Probabilistic Layer
│ "Translate to DSL" │
└───────────┬────────────┘
│ Unverified DSL (Code)
▼
┌────────────────────────┐
│ Symbolic Engine (Judge)│ ← Deterministic Layer
│ SymPy / Z3 / AST │
└───────────┬────────────┘
│ Verified Result
▼
Answer
User Query: "What is the derivative of x²?"
- LLM answers "2x".
- Guardrail LLM asks "Is 2x correct?"
- Guardrail says "Yes" (but it's just guessing).
Step 1: LLM Translation (The Compiler) The LLM converts natural language into a Domain Specific Language (DSL):
# LLM Output (Code, not Answer)
sp.diff(x**2, x)Step 2: Symbolic Execution (The CPU) QWED executes the code in a deterministic sandbox:
# SymPy executes this.
# It doesn't "guess" the derivative; it computes it.
result = 2*x Step 3: Verification We prove correctness by execution, not by checking text.
graph LR
A["User Query"] --> B["LLM Translator<br/>⚠️ Untrusted"]
B -->|Generates DSL| C["Intermediate Code<br/>(SymPy/Z3)"]
C -->|Executes| D["Symbolic Engine<br/>✅ Trusted"]
D --> E{"Result"}
E -->|Success| F["Verified Proof"]
E -->|Error| G["Syntax/Logic Error"]
style B fill:#ffc107
style D fill:#2196f3
style F fill:#4caf50
style G fill:#f44336
Key Insight:
If the LLM generates the wrong DSL (e.g.,
diff(x**3)), the user gets the wrong answer for the right reason (bad translation), not a hallucination (bad logic). This is debuggable. Hallucinations are not.
| Approach | How It Works | Guarantee | Cost |
|---|---|---|---|
| Hallucination Detection | Another LLM checks first LLM | ❌ No | $$ |
| RAG Grounding | Vector similarity to docs | $ | |
| Verification | Mathematical proof | ✅ Yes | $ |
# Bad approach:
llm_answer = llm.generate("2+2=?") # Might say "5"
judge = llm.verify(llm_answer) # Might also say "correct"
# Both LLMs can be wrong!# Good approach:
llm_answer = llm.generate("2+2=?") # Says "5"
symbolic_result = 2 + 2 # Computes "4"
verified = (llm_answer == symbolic_result) # False!
# Math doesn't lie!QWED routes queries to specialized symbolic engines (11+ engines in the current 5.2.0 ecosystem):
Tech: SymPy + NumPy
Use For:
- Calculus (derivatives, integrals)
- Algebra (solving equations)
- Finance (compound interest, NPV)
- Statistics (mean, std dev)
Example:
result = client.verify_math("Integrate x^2 from 0 to 1")
# SymPy proves: 1/3Tech: Z3 SMT Solver
Use For:
- Propositional logic (AND, OR, NOT)
- First-order logic (forall, exists)
- Constraint satisfaction
- Proof checking
Example:
result = client.verify_logic("If all A are B, and x is A, is x B?")
# Z3 proves: TrueTech: AST + Semgrep patterns
Use For:
- Detecting
eval(),exec() - Finding SQL injection risks
- Checking for hardcoded secrets
- Identifying dangerous imports
Example:
result = client.verify_code("user_input = input(); eval(user_input)")
# AST detects: DANGEROUS - eval() foundTech: SQLGlot parser
Use For:
- Syntax validation
- Injection prevention
- Schema compliance
- Query optimization
Example:
result = client.verify_sql("SELECT * FROM users WHERE id = 1 OR 1=1")
# Detects: SQL injection attemptTech: Pandas + WebAssembly sandbox
Use For:
- Data analysis scripts
- Statistical calculations
- Dataframe operations
- Safe code execution
Tech: TF-IDF + NLI models
Use For:
- Grounding against source docs
- Citation verification
- Factual consistency
Tech: OpenCV + metadata analysis
Use For:
- Image dimensions
- Format validation
- Pixel data integrity
- EXIF metadata
Tech: Multi-provider cross-check
Use For:
- When symbolic verification isn't possible
- Subjective tasks needing agreement
- Cross-validation of outputs
Which QWED engine would you use for these tasks?
- Verify: "Calculate loan payment: $10K at 5% for 30 years"
- Verify: "Check if
rm -rf /is safe to run" - Verify: "Is this SQL query valid: SELECT * FROM users"
- Verify: "If A→B and B→C, does A→C?"
Answers
- Math Verifier - Financial calculation
- Code Security - Dangerous command detection
- SQL Validator - Query syntax check
- Logic Verifier - Logical implication proof
Write a simple deterministic verifier for addition:
def verify_addition(a, b, llm_answer):
"""
Verify if LLM's addition is correct.
Returns (verified: bool, correct_answer: int)
"""
# Your code here
pass
# Test it:
print(verify_addition(2, 3, "5")) # Should: (True, 5)
print(verify_addition(2, 3, "6")) # Should: (False, 5)Solution
def verify_addition(a, b, llm_answer):
correct = a + b
verified = (int(llm_answer) == correct)
return (verified, correct)Key Insight: The + operator is deterministic. We trust it, not the LLM!
Convert these natural language queries to SymPy DSL:
- "What is the derivative of sin(x)?"
- "Solve x^2 - 9 = 0"
- "Integrate e^x from 0 to 1"
Answers
import sympy as sp
x = sp.Symbol('x')
# 1. Derivative
sp.diff(sp.sin(x), x) # cos(x)
# 2. Solve equation
sp.solve(x**2 - 9, x) # [-3, 3]
# 3. Integrate
sp.integrate(sp.exp(x), (x, 0, 1)) # e - 1Ready to build your first verifier?
You'll install QWED, run actual verifications, and build production guardrails!
Questions? 💬 Discuss Module 2