<RETURN_TO_BASE

Building a ReAct Agent Integrating Prolog Logic with Gemini and LangGraph: A Step-by-Step Coding Guide

Discover a step-by-step guide to building a ReAct agent that integrates Prolog logic with Gemini and LangGraph, enabling advanced reasoning and natural language querying.

Integrating Symbolic Logic with Generative AI

This tutorial demonstrates how to combine symbolic logic with generative AI by setting up PySwip to embed a Prolog knowledge base, wrapping its predicates as LangChain tools, and connecting everything into a ReAct-style agent. The setup includes crafting family-relationship rules, mathematical predicates like factorial, and list utilities. The agent can plan, call tools, and reason over the results, translating natural language queries into precise Prolog queries and returning structured JSON insights.

Setting Up Dependencies

We begin by installing SWI-Prolog and necessary Python packages:

!apt-get install swi-prolog -y
!pip install pyswip langchain-google-genai langgraph langchain-core

These allow us to bridge Prolog logic with a Gemini-powered language model agent.

Initializing the Environment and LLM

The core stack includes PySwip for Prolog integration, LangChain and LangGraph for tooling, and Gemini 1.5 Flash for the language model. The Google API key is set as an environment variable to authenticate the model.

import os
from pyswip import Prolog
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
import json
 
GOOGLE_API_KEY = "Use Your Own API Key Here"
os.environ["GOOGLE_API_KEY"] = GOOGLE_API_KEY
 
llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash", temperature=0)

Creating an Advanced Prolog Interface

We encapsulate SWI-Prolog within an AdvancedPrologInterface class that loads a knowledge base with family relationships, mathematical predicates, and list utilities. It exposes a query() method that executes Prolog queries and returns JSON-friendly results or error messages.

class AdvancedPrologInterface:
   def __init__(self):
       self.prolog = Prolog()
       self._load_knowledge_base()
  
   def _load_knowledge_base(self):
       """Load comprehensive Prolog knowledge base"""
       rules = [
           "parent(john, mary, alice)",
           "parent(john, mary, bob)",
           "parent(bob, susan, charlie)",
           "parent(alice, david, emma)",
           "parent(charlie, lisa, frank)",
          
           "male(john)", "male(bob)", "male(david)", "male(charlie)", "male(frank)",
           "female(mary)", "female(alice)", "female(susan)", "female(emma)", "female(lisa)",
          
           "grandparent(X, Z) :- parent(X, _, Y), parent(Y, _, Z)",
           "sibling(X, Y) :- parent(P1, P2, X), parent(P1, P2, Y), X \\= Y",
           "uncle(X, Y) :- sibling(X, Z), parent(Z, _, Y), male(X)",
           "aunt(X, Y) :- sibling(X, Z), parent(Z, _, Y), female(X)",
           "cousin(X, Y) :- parent(P1, _, X), parent(P2, _, Y), sibling(P1, P2)",
          
           "factorial(0, 1)",
           "factorial(N, F) :- N > 0, N1 is N - 1, factorial(N1, F1), F is N * F1",
          
           "list_member(X, [X|_])",
           "list_member(X, [_|T]) :- list_member(X, T)",
           "list_length([], 0)",
           "list_length([_|T], N) :- list_length(T, N1), N is N1 + 1",
          
           "animal(dog)", "animal(cat)", "animal(whale)", "animal(eagle)",
           "mammal(dog)", "mammal(cat)", "mammal(whale)",
           "bird(eagle)", "bird(sparrow)",
           "can_fly(eagle)", "can_fly(sparrow)",
           "can_swim(whale)", "can_swim(fish)",
           "aquatic_mammal(X) :- mammal(X), can_swim(X)"
       ]
      
       for rule in rules:
           try:
               self.prolog.assertz(rule)
           except Exception as e:
               print(f"Warning: Could not assert rule '{rule}': {e}")
  
   def query(self, query_string):
       """Execute Prolog query and return results"""
       try:
           results = list(self.prolog.query(query_string))
           return results if results else [{"result": "No solutions found"}]
       except Exception as e:
           return [{"error": f"Query failed: {str(e)}"}]

Wrapping Prolog Queries as LangChain Tools

The Prolog interface is wrapped into LangChain tools for family relationships, mathematical operations (like factorial), and advanced queries (children, siblings, cousins).

prolog_interface = AdvancedPrologInterface()
 
@tool
def family_relationships(query: str) -> str:
   """
   Query family relationships in Prolog format.
   Examples: 'parent(john, mary, X)', 'sibling(X, Y)', 'grandparent(X, charlie)'
   """
   results = prolog_interface.query(query)
   return json.dumps(results, indent=2)
 
@tool
def mathematical_operations(operation: str, number: int) -> str:
   """
   Perform mathematical operations using Prolog.
   Supported operations: 'factorial'
   Example: operation='factorial', number=5
   """
   if operation == "factorial":
       query = f"factorial({number}, Result)"
       results = prolog_interface.query(query)
       return json.dumps(results, indent=2)
   else:
       return json.dumps([{"error": f"Operation '{operation}' not supported"}])
 
@tool
def advanced_queries(query_type: str, entity: str = "") -> str:
   """
   Perform advanced relationship queries.
   Types: 'all_children', 'all_grandchildren', 'all_siblings', 'all_cousins'
   """
   queries = {
       'all_children': f"parent(_, _, {entity})" if entity else "parent(_, _, X)",
       'all_grandchildren': f"grandparent(_, {entity})" if entity else "grandparent(_, X)",
       'all_siblings': f"sibling({entity}, X)" if entity else "sibling(X, Y)",
       'all_cousins': f"cousin({entity}, X)" if entity else "cousin(X, Y)"
   }
  
   if query_type in queries:
       results = prolog_interface.query(queries[query_type])
       return json.dumps(results, indent=2)
   else:
       return json.dumps([{"error": f"Query type '{query_type}' not supported"}])

Creating and Using the ReAct Agent

We register these tools and create a ReAct agent with Gemini as the language model. Helper functions demonstrate family analysis, complex multi-step reasoning, and an interactive session.

tools = [family_relationships, mathematical_operations, advanced_queries]
agent = create_react_agent(llm, tools)
 
# Functions to run analyses, demonstrate reasoning, and interact with the agent are defined.

Testing and Running the Solution

The main function verifies direct Prolog queries, runs family relationship analyses, demonstrates complex reasoning, and shows mathematical capabilities such as factorial computations. The tutorial highlights the integration's power and flexibility.

Final Thoughts

This approach marries the correctness of symbolic Prolog reasoning with the flexibility of Gemini's language understanding. It provides a scaffold to extend knowledge bases, add new domains, or integrate alternative LLMs, suitable for interactive UI or API exposure.

Full source codes and notebooks are available, crediting the original researchers.

🇷🇺

Сменить язык

Читать эту статью на русском

Переключить на Русский