"""
Pattern 161: Deductive Reasoning
Description:
Deductive reasoning derives specific conclusions from general premises using
logical rules. If the premises are true and the logic is valid, the conclusion
must be true. This is the foundation of formal logic and mathematical proof.
Components:
- Premise collection and validation
- Logical rule application
- Inference chain construction
- Conclusion derivation
- Validity checking
Use Cases:
- Logical problem solving
- Mathematical proofs
- Rule-based systems
- Legal reasoning
- Formal verification
Benefits:
- Guaranteed valid conclusions
- Transparent reasoning
- Systematic approach
- Verifiable logic
Trade-offs:
- Requires valid premises
- Limited to formal logic
- May be rigid
- Doesn't discover new rules
LangChain Implementation:
Uses ChatOpenAI for logical inference, premise validation,
and step-by-step deduction chains
"""
import os
from typing import List, Dict, Any, Optional
from dataclasses import dataclass, field
from enum import Enum
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
load_dotenv()
class LogicalOperator(Enum):
"""Logical operators"""
AND = "and"
OR = "or"
NOT = "not"
IMPLIES = "implies"
IF_AND_ONLY_IF = "iff"
class InferenceRule(Enum):
"""Common inference rules"""
MODUS_PONENS = "modus_ponens" # If P→Q and P, then Q
MODUS_TOLLENS = "modus_tollens" # If P→Q and ¬Q, then ¬P
HYPOTHETICAL_SYLLOGISM = "hypothetical_syllogism" # If P→Q and Q→R, then P→R
DISJUNCTIVE_SYLLOGISM = "disjunctive_syllogism" # If P∨Q and ¬P, then Q
CONTRAPOSITIVE = "contrapositive" # P→Q equivalent to ¬Q→¬P
@dataclass
class Premise:
"""Logical premise or statement"""
statement: str
is_axiom: bool = False # Assumed true
confidence: float = 1.0
source: Optional[str] = None
@dataclass
class InferenceStep:
"""Single step in deductive reasoning"""
conclusion: str
rule_applied: str
premises_used: List[str]
confidence: float = 1.0
@dataclass
class DeductiveProof:
"""Complete deductive proof"""
premises: List[Premise]
steps: List[InferenceStep]
final_conclusion: str
is_valid: bool
reasoning_trace: List[str] = field(default_factory=list)
class DeductiveReasoningAgent:
"""Agent that performs deductive reasoning"""
def __init__(self, model_name: str = "gpt-3.5-turbo"):
"""
Initialize deductive reasoning agent
Args:
model_name: LLM model to use
"""
self.llm = ChatOpenAI(model=model_name, temperature=0)
self.validator_llm = ChatOpenAI(model=model_name, temperature=0)
def prove(self, premises: List[Premise],
goal: str,
max_steps: int = 10) -> DeductiveProof:
"""
Construct deductive proof from premises to goal
Args:
premises: List of premises
goal: Goal conclusion to prove
max_steps: Maximum reasoning steps
Returns:
DeductiveProof with reasoning chain
"""
reasoning_trace = []
steps = []
reasoning_trace.append("Starting deductive proof...")
reasoning_trace.append(f"Goal: {goal}")
# Format premises
premises_text = "\n".join([
f"- {p.statement}" for p in premises
])
reasoning_trace.append(f"Given premises:\n{premises_text}")
# Generate proof steps
for i in range(max_steps):
# Check if goal is reached
if steps and steps[-1].conclusion.lower() in goal.lower():
reasoning_trace.append(f"Goal reached in {i} steps!")
break
# Generate next inference step
step = self._generate_next_step(premises, steps, goal)
if step:
steps.append(step)
reasoning_trace.append(
f"Step {i+1}: {step.conclusion} (via {step.rule_applied})"
)
else:
reasoning_trace.append("No more valid inferences possible")
break
# Validate proof
is_valid = self._validate_proof(premises, steps, goal)
final_conclusion = steps[-1].conclusion if steps else "No conclusion reached"
return DeductiveProof(
premises=premises,
steps=steps,
final_conclusion=final_conclusion,
is_valid=is_valid,
reasoning_trace=reasoning_trace
)
def _generate_next_step(self, premises: List[Premise],
existing_steps: List[InferenceStep],
goal: str) -> Optional[InferenceStep]:
"""Generate next logical inference step"""
# Format context
premises_text = "\n".join([f"- {p.statement}" for p in premises])
if existing_steps:
derived_text = "\n".join([
f"- {s.conclusion}" for s in existing_steps
])
else:
derived_text = "None yet"
# Create inference prompt
prompt = ChatPromptTemplate.from_messages([
("system", """You are a logical reasoning expert. Given premises and a goal,
generate the next logical inference step using valid deductive reasoning rules.
Common rules:
- Modus Ponens: If P→Q and P, then Q
- Modus Tollens: If P→Q and ¬Q, then ¬P
- Hypothetical Syllogism: If P→Q and Q→R, then P→R
- Disjunctive Syllogism: If P∨Q and ¬P, then Q
Return only the new conclusion and the rule used."""),
("user", """Premises:
{premises}
Already derived:
{derived}
Goal: {goal}
What is the next logical inference? Format:
Conclusion: [your conclusion]
Rule: [rule name]
Uses: [which premises/conclusions]""")
])
chain = prompt | self.llm | StrOutputParser()
response = chain.invoke({
"premises": premises_text,
"derived": derived_text,
"goal": goal
})
# Parse response
return self._parse_inference_step(response)
def _parse_inference_step(self, response: str) -> Optional[InferenceStep]:
"""Parse inference step from LLM response"""
lines = response.strip().split('\n')
conclusion = None
rule = None
uses = []
for line in lines:
line = line.strip()
if line.lower().startswith('conclusion:'):
conclusion = line.split(':', 1)[1].strip()
elif line.lower().startswith('rule:'):
rule = line.split(':', 1)[1].strip()
elif line.lower().startswith('uses:'):
uses_text = line.split(':', 1)[1].strip()
uses = [u.strip() for u in uses_text.split(',')]
if conclusion and rule:
return InferenceStep(
conclusion=conclusion,
rule_applied=rule,
premises_used=uses,
confidence=1.0
)
return None
def _validate_proof(self, premises: List[Premise],
steps: List[InferenceStep],
goal: str) -> bool:
"""Validate that the proof is logically sound"""
if not steps:
return False
# Check if final conclusion matches goal
final_matches = goal.lower() in steps[-1].conclusion.lower()
# Use LLM to validate logical soundness
premises_text = "\n".join([f"- {p.statement}" for p in premises])
steps_text = "\n".join([
f"{i+1}. {s.conclusion} (via {s.rule_applied})"
for i, s in enumerate(steps)
])
prompt = ChatPromptTemplate.from_messages([
("system", "You are a logic validator. Check if the reasoning steps are logically valid."),
("user", """Premises:
{premises}
Reasoning steps:
{steps}
Goal: {goal}
Is this proof logically valid? Respond with 'yes' or 'no' and brief explanation.""")
])
chain = prompt | self.validator_llm | StrOutputParser()
response = chain.invoke({
"premises": premises_text,
"steps": steps_text,
"goal": goal
})
is_valid = 'yes' in response.lower() and final_matches
return is_valid
def apply_rule(self, rule: InferenceRule,
statements: List[str]) -> Optional[str]:
"""Apply specific inference rule to statements"""
rule_descriptions = {
InferenceRule.MODUS_PONENS: "If P implies Q, and P is true, then Q is true",
InferenceRule.MODUS_TOLLENS: "If P implies Q, and Q is false, then P is false",
InferenceRule.HYPOTHETICAL_SYLLOGISM: "If P implies Q, and Q implies R, then P implies R",
InferenceRule.DISJUNCTIVE_SYLLOGISM: "If P or Q, and not P, then Q",
}
prompt = ChatPromptTemplate.from_messages([
("system", f"Apply the logical rule: {rule_descriptions.get(rule, rule.value)}"),
("user", """Given statements:
{statements}
What conclusion can be derived? Provide just the conclusion.""")
])
chain = prompt | self.llm | StrOutputParser()
statements_text = "\n".join([f"- {s}" for s in statements])
conclusion = chain.invoke({"statements": statements_text})
return conclusion.strip()
def demonstrate_deductive_reasoning():
"""Demonstrate deductive reasoning pattern"""
print("=" * 80)
print("DEDUCTIVE REASONING PATTERN DEMONSTRATION")
print("=" * 80)
agent = DeductiveReasoningAgent()
# Example 1: Classic syllogism
print("\n" + "="*80)
print("EXAMPLE 1: Classic Syllogism (Socrates)")
print("="*80)
premises = [
Premise("All humans are mortal", is_axiom=True),
Premise("Socrates is a human", is_axiom=True)
]
goal = "Socrates is mortal"
proof = agent.prove(premises, goal, max_steps=5)
print("Premises:")
for p in proof.premises:
print(f" - {p.statement}")
print(f"\nGoal: {goal}")
print(f"\nProof steps:")
for i, step in enumerate(proof.steps, 1):
print(f" {i}. {step.conclusion}")
print(f" Rule: {step.rule_applied}")
print(f"\nConclusion: {proof.final_conclusion}")
print(f"Valid: {proof.is_valid}")
# Example 2: Modus Ponens
print("\n" + "="*80)
print("EXAMPLE 2: Modus Ponens")
print("="*80)
statements = [
"If it rains, the ground gets wet",
"It is raining"
]
conclusion = agent.apply_rule(InferenceRule.MODUS_PONENS, statements)
print("Given:")
for s in statements:
print(f" - {s}")
print(f"\nConclusion: {conclusion}")
# Example 3: Mathematical reasoning
print("\n" + "="*80)
print("EXAMPLE 3: Mathematical Reasoning")
print("="*80)
premises = [
Premise("If x > 5, then x > 3", is_axiom=True),
Premise("x = 7", is_axiom=True),
Premise("7 > 5", is_axiom=True)
]
goal = "x > 3"
proof = agent.prove(premises, goal, max_steps=5)
print("Premises:")
for p in proof.premises:
print(f" - {p.statement}")
print(f"\nReasoning:")
for trace in proof.reasoning_trace:
if "Step" in trace or "Goal" in trace:
print(f" {trace}")
print(f"\nFinal: {proof.final_conclusion}")
# Example 4: Logical chain
print("\n" + "="*80)
print("EXAMPLE 4: Hypothetical Syllogism")
print("="*80)
statements = [
"If it rains, the roads are wet",
"If the roads are wet, driving is dangerous"
]
conclusion = agent.apply_rule(InferenceRule.HYPOTHETICAL_SYLLOGISM, statements)
print("Given:")
for s in statements:
print(f" - {s}")
print(f"\nConclusion: {conclusion}")
# Example 5: Complex proof
print("\n" + "="*80)
print("EXAMPLE 5: Multi-Step Proof")
print("="*80)
premises = [
Premise("All birds have feathers", is_axiom=True),
Premise("All animals with feathers can regulate body temperature", is_axiom=True),
Premise("A penguin is a bird", is_axiom=True)
]
goal = "A penguin can regulate body temperature"
proof = agent.prove(premises, goal, max_steps=10)
print("Premises:")
for p in proof.premises:
print(f" - {p.statement}")
print(f"\nGoal: {goal}")
print(f"\nProof trace:")
for trace in proof.reasoning_trace[-5:]:
print(f" {trace}")
# Example 6: Modus Tollens
print("\n" + "="*80)
print("EXAMPLE 6: Modus Tollens (Proof by Contrapositive)")
print("="*80)
statements = [
"If the alarm is working, it would have gone off",
"The alarm did not go off"
]
conclusion = agent.apply_rule(InferenceRule.MODUS_TOLLENS, statements)
print("Given:")
for s in statements:
print(f" - {s}")
print(f"\nConclusion: {conclusion}")
# Summary
print("\n" + "="*80)
print("SUMMARY: Deductive Reasoning Best Practices")
print("="*80)
print("""
1. PREMISE VALIDATION:
- Verify premises are true
- Identify axioms vs derived facts
- Check premise consistency
- Document premise sources
2. LOGICAL RULES:
- Use established inference rules
- Apply rules systematically
- Maintain logical validity
- Document rule application
3. PROOF CONSTRUCTION:
- Build step-by-step chains
- Connect premises to conclusion
- Verify each step
- Keep proofs as simple as possible
4. COMMON RULES:
- Modus Ponens: P→Q, P ⊢ Q
- Modus Tollens: P→Q, ¬Q ⊢ ¬P
- Hypothetical Syllogism: P→Q, Q→R ⊢ P→R
- Disjunctive Syllogism: P∨Q, ¬P ⊢ Q
- Conjunction: P, Q ⊢ P∧Q
5. VALIDATION:
- Check logical soundness
- Verify conclusion follows
- Test for fallacies
- Review proof structure
6. APPLICATIONS:
- Mathematical proofs
- Legal reasoning
- Rule-based systems
- Formal verification
- Logical problem solving
Benefits:
✓ Guarantees valid conclusions
✓ Transparent reasoning process
✓ Systematic and rigorous
✓ Verifiable logic
✓ Foundation for formal systems
Limitations:
- Requires true premises
- Limited to formal logic
- May be inflexible
- Doesn't generate new knowledge
- Can be verbose for complex proofs
""")
if __name__ == "__main__":
demonstrate_deductive_reasoning()
Agentic Design Pattern: Deductive Reasoning
Pattern 161: Deductive Reasoning – Line-by-Line Explanation
Overview
This document provides a detailed line-by-line explanation of the Deductive Reasoning pattern implementation.
Pattern Description
Pattern 161: Deductive Reasoning
Description: Deductive reasoning derives specific conclusions from general premises using logical rules. If the premises are true and the logic is valid, the conclusion must be true. This is the foundation of formal logic and mathematical proof.
Components: – Premise collection and validation – Logical rule application – Inference chain construction – Conclusion derivation – Validity checking
Use Cases: – Logical problem solving – Mathematical proofs – Rule-based systems – Legal reasoning – Formal verification
Benefits: – Guaranteed valid conclusions – Transparent reasoning – Systematic approach – Verifiable logic
Trade-offs: – Requires valid premises – Limited to formal logic – May be rigid – Doesn’t discover new rules
LangChain Implementation: Uses ChatOpenAI for logical inference, premise validation, and step-by-step deduction chains
File Statistics
- Total Lines: 499
- Classes: 6
- Functions: 1
- Constants: 0
Module Documentation
"""
Pattern 161: Deductive Reasoning
Description:
Deductive reasoning derives specific conclusions from general premises using
logical rules. If the premises are true and the logic is valid, the conclusion
must be true. This is the foundation of formal logic and mathematical proof.
Components:
- Premise collection and validation
- Logical rule application
- Inference chain construction
- Conclusion derivation
- Validity checking
Use Cases:
- Logical problem solving
- Mathematical proofs
- Rule-based systems
- Legal reasoning
- Formal verification
Benefits:
- Guaranteed valid conclusions
- Transparent reasoning
- Systematic approach
- Verifiable logic
Trade-offs:
- Requires valid premises
- Limited to formal logic
- May be rigid
- Doesn't discover new rules
LangChain Implementation:
Uses ChatOpenAI for logical inference, premise validation,
and step-by-step deduction chains
"""
Purpose: This module implements the Deductive Reasoning pattern, providing a structured approach to agent design and implementation.
Import Statements
Standard Library Imports
import dataclasses.dataclass
import dataclasses.field
import enum.Enum
import langchain_core.output_parsers.StrOutputParser
import langchain_core.prompts.ChatPromptTemplate
import os
import typing.Any
import typing.Dict
import typing.List
import typing.Optional
Purpose: Core Python functionality:
– dataclasses.dataclass: Simplified class definitions with @dataclass
– dataclasses.field: Simplified class definitions with @dataclass
– enum.Enum: Enumeration support
– langchain_core.output_parsers.StrOutputParser: Regular expression operations
– langchain_core.prompts.ChatPromptTemplate: Regular expression operations
– os: Environment variable access and system operations
– typing.Any: Type hints for better code documentation (List, Dict, Any, Optional)
– typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional)
– typing.List: Type hints for better code documentation (List, Dict, Any, Optional)
– typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional)
LangChain Imports
from langchain_openai.ChatOpenAI
Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows
Other Imports
from dotenv.load_dotenv
Purpose: Additional dependencies for specialized functionality.
Classes
Class: LogicalOperator
Lines 53-59
Inherits from: Enum
Purpose:
Logical operators
Class: InferenceRule
Lines 62-68
Inherits from: Enum
Purpose:
Common inference rules
Class: Premise
Lines 72-77
Purpose:
Logical premise or statement
Class: InferenceStep
Lines 81-86
Purpose:
Single step in deductive reasoning
Class: DeductiveProof
Lines 90-96
Purpose:
Complete deductive proof
Class: DeductiveReasoningAgent
Lines 99-314
Purpose:
Agent that performs deductive reasoning
Methods:
__init__(self, model_name)
Lines 102-110
Purpose:
Initialize deductive reasoning agent
Args:
model_name: LLM model to use
Parameters:
– model_name: Language model instance
prove(self, premises, goal, max_steps)
Lines 112-167
Purpose:
Construct deductive proof from premises to goal
Args:
premises: List of premises
goal: Goal conclusion to prove
max_steps: Maximum reasoning steps
Returns:
DeductiveProof with reasoning chain
Parameters:
– premises: Premises
– goal: Goal
– max_steps: Max steps
Returns: DeductiveProof
_generate_next_step(self, premises, existing_steps, goal)
Lines 169-219
Purpose:
Generate next logical inference step
Parameters:
– premises: Premises
– existing_steps: Existing steps
– goal: Goal
Returns: <ast.Subscript object at 0x000001A06D633F10>
_parse_inference_step(self, response)
Lines 221-246
Purpose:
Parse inference step from LLM response
Parameters:
– response: Response
Returns: <ast.Subscript object at 0x000001A06E0A9710>
_validate_proof(self, premises, steps, goal)
Lines 248-288
Purpose:
Validate that the proof is logically sound
Parameters:
– premises: Premises
– steps: Steps
– goal: Goal
Returns: bool
apply_rule(self, rule, statements)
Lines 290-314
Purpose:
Apply specific inference rule to statements
Parameters:
– rule: Rule
– statements: Statements
Returns: <ast.Subscript object at 0x000001A06D888690>
Functions
demonstrate_deductive_reasoning()
Lines 317-494
Purpose:
Demonstrate deductive reasoning pattern
Key Concepts Summary
Pattern Overview
The Deductive Reasoning pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.
Core Components
- Agent Class: Main implementation of the pattern logic
- Prompt Engineering: Carefully crafted prompts to guide LLM behavior
- Tool Integration: Optional tools for extended functionality
- Memory Management: State handling across interactions
- Output Parsing: Structured response processing
When to Use
✅ Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability
❌ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)
Best Practices Demonstrated
1. Environment Configuration
- ✅ Use
.envfiles for API keys - ✅ Never hardcode credentials
- ✅ Validate environment variables on startup
2. Error Handling
- ✅ Graceful degradation on failures
- ✅ Informative error messages
- ✅ Logging for debugging
3. Prompt Engineering
- ✅ Clear, specific instructions
- ✅ Structured output formats
- ✅ Few-shot examples when beneficial
4. Code Organization
- ✅ Separation of concerns (class-based design)
- ✅ Type hints for clarity
- ✅ Docstrings for documentation
5. Performance Optimization
- ✅ Appropriate temperature settings
- ✅ Token budget management
- ✅ Caching where applicable
LangChain Components Used
- ChatOpenAI: OpenAI model interface
- Chains: Sequential component composition
Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development
Execution Flow
1. Initialize agent with configuration
↓
2. Load environment and dependencies
↓
3. Prepare prompt with input data
↓
4. Invoke LLM through LangChain
↓
5. Parse and validate response
↓
6. Return formatted result
Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation
Performance Considerations
Computational Cost
- LLM Calls: Primary cost factor (based on tokens)
- Latency: Depends on model and input size
- Memory: Minimal for most patterns
Optimization Strategies
- Prompt Optimization: Minimize tokens while maintaining clarity
- Caching: Cache repeated queries/responses
- Model Selection: Use smaller models when appropriate
- Batch Processing: Group similar requests
- Streaming: For long responses, stream tokens
Cost Estimates (Approximate)
- GPT-3.5-turbo: ~$0.002 per request
- GPT-4: ~$0.03 per request
- GPT-4-turbo: ~$0.01 per request
Actual costs vary based on input/output token counts
Common Pitfalls to Avoid
1. Prompt Design Issues
❌ Vague or ambiguous instructions
✅ Clear, specific, testable prompts
2. Error Handling
❌ Ignoring API errors or rate limits
✅ Implement retry logic and graceful degradation
3. Token Management
❌ Exceeding model token limits
✅ Truncate inputs, chunk processing
4. Security
❌ Exposing API keys in code
✅ Use environment variables
5. Testing
❌ Only testing happy paths
✅ Test edge cases, failures, malformed inputs
6. Cost Management
❌ Unmonitored API usage
✅ Implement budgets, alerts, and monitoring
Further Improvements
Production Enhancements
- Monitoring: Add logging, metrics, tracing
- Validation: Input/output schema validation
- Rate Limiting: Implement request throttling
- Caching: Redis or in-memory cache for responses
- Async Support: Non-blocking operations for scalability
Feature Extensions
- Multi-Model Support: Switch between providers
- Fallback Models: Graceful degradation strategy
- Custom Tools: Domain-specific function calling
- Advanced Memory: Vector stores for long-term memory
- Evaluation: Automated testing and benchmarking
Code Quality
- Testing: Unit tests, integration tests
- Documentation: API docs, usage examples
- Type Safety: Stricter type hints
- Configuration: Externalized config files
Related Patterns
- Pattern 160
- Pattern 162
Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…
Summary
The Deductive Reasoning pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:
✅ Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns
🎯 Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability
📚 Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/
File: 161_deductive_reasoning.py
Total Lines: 499
Pattern Category: AI Agent Design Pattern #161
Generated from actual implementation code
For educational and reference purposes
Leave a Reply