Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save MuhammadYossry/5040b4b81473b1974a6ee7cfb0cf8c7a to your computer and use it in GitHub Desktop.
Save MuhammadYossry/5040b4b81473b1974a6ee7cfb0cf8c7a to your computer and use it in GitHub Desktop.
Building Unified Interfaces for AI Agents(AI generated by prompting)

Building Unified Interfaces for AI Agents

    graph TB
    subgraph Interface["Interface Layer"]
        NLI["Natural Language Interface"]
        API["API Gateway"]
    end

    subgraph Agents["Agent Layer"]
        CSA["Customer Service Agent"]
        WHA["Warehouse Agent"]
        INA["Inventory Agent"]
    end

    subgraph Knowledge["Knowledge Layer"]
        KB["Knowledge Base (JSON-LD/RDF)"]
        ONT["Ontology Manager"]
    end

    subgraph Communication["Communication Layer"]
        FIPA["FIPA-ACL Protocol"]
        MID["Middleware (ROS/JADE)"]
    end

    NLI -- "User Queries" --> CSA
    API -- "System Calls" --> Agents

    CSA -- "Data Query" --> KB
    WHA -- "Inventory Check" --> KB
    INA -- "Stock Update" --> KB

    KB -- "Semantic Rules" --> ONT
    
    Agents -- "Inter-agent Communication" --> FIPA
    FIPA -- "Message Routing" --> MID
    MID -- "Event Distribution" --> Agents
Loading

Table of Contents

Introduction

Imagine orchestrating a symphony where each musician speaks a different language and plays by different rules. This is the challenge we face when building systems of AI agents that need to work together seamlessly. This guide explores practical approaches to creating unified interfaces that enable AI agents to communicate and collaborate effectively.

Standard Protocols: Building Your Foundation

Think of standard protocols as the common language that allows different AI components to understand each other.

Example 1: FastAPI-based Agent Interface

A WebSocket-based interface for real-time agent communication, handling structured messages with intent-based routing.

from fastapi import FastAPI, WebSocket
from pydantic import BaseModel
import json

class AgentMessage(BaseModel):
    intent: str
    payload: dict
    sender: str

app = FastAPI()

class AIAgent:
    async def process_message(self, message: AgentMessage):
        # Process message based on intent
        if message.intent == "query":
            return await self.handle_query(message.payload)
        elif message.intent == "action":
            return await self.handle_action(message.payload)

@app.websocket("/agent")
async def agent_endpoint(websocket: WebSocket):
    await websocket.accept()
    agent = AIAgent()
    
    while True:
        message = await websocket.receive_json()
        response = await agent.process_message(AgentMessage(**message))
        await websocket.send_json(response)

Example 2: gRPC-based Agent Communication

Implements high-performance, protocol buffer-based communication between agents with support for streaming events.

# agent.proto
syntax = "proto3";

service AgentService {
    rpc ProcessTask (TaskRequest) returns (TaskResponse);
    rpc StreamEvents (EventRequest) returns (stream EventResponse);
}

message TaskRequest {
    string task_type = 1;
    bytes payload = 2;
}

# Implementation
from concurrent import futures
import grpc
import agent_pb2
import agent_pb2_grpc

class AgentServicer(agent_pb2_grpc.AgentServiceServicer):
    def ProcessTask(self, request, context):
        task_result = self.execute_task(request.task_type, request.payload)
        return agent_pb2.TaskResponse(result=task_result)

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    agent_pb2_grpc.add_AgentServiceServicer_to_server(
        AgentServicer(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    server.wait_for_termination()

Knowledge Representation: Practical Examples

Example 1: RDF-based Knowledge Store

Graph-based knowledge representation using RDF, enabling semantic queries and relationship modeling for products.

from rdflib import Graph, Literal, RDF, URIRef
from rdflib.namespace import FOAF, XSD

class KnowledgeBase:
    def __init__(self):
        self.g = Graph()
        self.namespace = "http://example.org/"

    def add_product(self, product_id, properties):
        product = URIRef(self.namespace + product_id)
        self.g.add((product, RDF.type, FOAF.Product))
        
        for key, value in properties.items():
            predicate = URIRef(self.namespace + key)
            self.g.add((product, predicate, Literal(value)))

    def query_products(self, criteria):
        query = """
        SELECT ?product ?property ?value
        WHERE {
            ?product rdf:type foaf:Product .
            ?product ?property ?value .
            FILTER(%s)
        }
        """ % criteria
        
        return self.g.query(query)

# Usage
kb = KnowledgeBase()
kb.add_product("laptop-x1", {
    "price": 999.99,
    "category": "Electronics",
    "inStock": True
})

Example 2: Neo4j Knowledge Graph Integration

Graph database implementation for managing product relationships with support for complex queries and traversals.

from neo4j import GraphDatabase

class ProductKnowledgeGraph:
    def __init__(self, uri, user, password):
        self.driver = GraphDatabase.driver(uri, auth=(user, password))

    def add_product_relationship(self, product1, product2, relationship):
        with self.driver.session() as session:
            session.write_transaction(
                self._create_relationship,
                product1, product2, relationship
            )

    @staticmethod
    def _create_relationship(tx, prod1, prod2, rel):
        query = (
            "MERGE (p1:Product {id: $prod1}) "
            "MERGE (p2:Product {id: $prod2}) "
            "CREATE (p1)-[r:$rel]->(p2)"
        )
        tx.run(query, prod1=prod1, prod2=prod2, rel=rel)

    def find_related_products(self, product_id):
        with self.driver.session() as session:
            return session.read_transaction(
                self._get_related_products, product_id
            )

Agent Communication: Advanced Patterns

Example: RabbitMQ-based Agent Communication System

Message broker implementation supporting topic-based routing and reliable message delivery between agents.

import pika
import json

class AgentCommunicator:
    def __init__(self, agent_id):
        self.agent_id = agent_id
        self.connection = pika.BlockingConnection(
            pika.ConnectionParameters('localhost')
        )
        self.channel = self.connection.channel()
        
        # Setup exchanges for different message types
        self.channel.exchange_declare(
            exchange='agent_messages',
            exchange_type='topic'
        )
        
        # Create queue for this agent
        result = self.channel.queue_declare(queue='', exclusive=True)
        self.queue_name = result.method.queue
        
        # Bind to relevant topics
        self.channel.queue_bind(
            exchange='agent_messages',
            queue=self.queue_name,
            routing_key=f'agent.{self.agent_id}.*'
        )

    def send_message(self, target_agent, message_type, payload):
        routing_key = f'agent.{target_agent}.{message_type}'
        self.channel.basic_publish(
            exchange='agent_messages',
            routing_key=routing_key,
            body=json.dumps({
                'sender': self.agent_id,
                'type': message_type,
                'payload': payload
            })
        )

    def start_listening(self, callback):
        self.channel.basic_consume(
            queue=self.queue_name,
            on_message_callback=callback,
            auto_ack=True
        )
        self.channel.start_consuming()

# Usage example
def message_handler(ch, method, properties, body):
    message = json.loads(body)
    print(f"Received: {message}")

agent = AgentCommunicator('agent1')
agent.start_listening(message_handler)

Middleware Integration: Real-world Example

Example: Redis-based Event-Driven System

Pub/sub system for real-time event handling and distribution among multiple agents.

import redis
import json
from typing import Callable

class EventDrivenAgent:
    def __init__(self, agent_id: str):
        self.agent_id = agent_id
        self.redis = redis.Redis(host='localhost', port=6379, db=0)
        self.pubsub = self.redis.pubsub()
        self.handlers: dict[str, Callable] = {}

    def register_handler(self, event_type: str, handler: Callable):
        self.handlers[event_type] = handler
        self.pubsub.subscribe(event_type)

    def emit_event(self, event_type: str, data: dict):
        event = {
            'type': event_type,
            'sender': self.agent_id,
            'data': data,
            'timestamp': datetime.now().isoformat()
        }
        self.redis.publish(event_type, json.dumps(event))

    def start(self):
        for message in self.pubsub.listen():
            if message['type'] == 'message':
                event = json.loads(message['data'])
                if event['type'] in self.handlers:
                    self.handlers[event['type']](event['data'])

# Usage
def handle_inventory_update(data):
    print(f"Processing inventory update: {data}")

agent = EventDrivenAgent('inventory_manager')
agent.register_handler('inventory_update', handle_inventory_update)
agent.start()

Example: Building a Customer Service Agent

The OpenAI API and LangChain have emerged as fundamental building blocks for creating interoperable AI systems. Here's how we might implement a customer service agent using standard protocols:

from langchain import OpenAI, LLMChain, PromptTemplate
from langchain.memory import ConversationBufferMemory

# Define the conversation pattern
template = """
Context: You are a customer service agent for an electronics store.
Previous conversation: {chat_history}
Customer: {customer_input}
Agent: Let's think about this step by step:
1) First, understand the customer's need
2) Check if we have relevant information
3) Provide a helpful response

Response:"""

# Create a chain that maintains conversation context
customer_service_chain = LLMChain(
    llm=OpenAI(temperature=0.7),
    prompt=PromptTemplate(
        input_variables=["chat_history", "customer_input"],
        template=template
    ),
    memory=ConversationBufferMemory(
        memory_key="chat_history"
    )
)

# Example interaction
response = customer_service_chain.predict(
    customer_input="My new headphones won't connect to my phone"
)

This code demonstrates how LangChain simplifies the creation of conversational agents by handling:

  • Conversation memory management
  • Context preservation
  • Structured response generation

Knowledge Representation: Making Information Meaningful

When AI agents need to share complex information, they need more than just data – they need context and relationships. This is where semantic frameworks like JSON-LD and RDF shine.

Example: Product Recommendation System

Here's how we might represent product knowledge in a way that AI agents can understand and reason about:

{
  "@context": {
    "@vocab": "https://schema.org/",
    "features": "hasFeature",
    "compatibleWith": "isCompatibleWith",
    "recommendedFor": "suggestedUse"
  },
  "@graph": [
    {
      "@type": "Product",
      "@id": "product:noise-cancelling-headphones",
      "name": "ProAudio NC-1000",
      "category": "Electronics",
      "features": ["Active Noise Cancellation", "Bluetooth 5.0"],
      "compatibleWith": [
        "product:iphone-12",
        "product:samsung-galaxy-s21"
      ],
      "recommendedFor": [
        "Travel",
        "Office Work",
        "Music Production"
      ],
      "price": {
        "@type": "PriceSpecification",
        "price": 299.99,
        "currency": "USD"
      }
    }
  ]
}

This structured representation enables AI agents to:

  • Understand product relationships
  • Make informed recommendations
  • Answer complex queries about compatibility and features

Agent Communication Languages: Coordinating Multiple Agents

When multiple AI agents need to work together, they need a formal way to communicate intentions and actions. FIPA-ACL provides this structure through standardized message types.

Example: Supply Chain Coordination

Here's how multiple agents might coordinate in a supply chain system: FIPA-ACL based message passing system for inventory management and warehouse coordination.

class SupplyChainAgent:
    def send_message(self, receiver, performative, content):
        message = {
            "sender": self.name,
            "receiver": receiver,
            "performative": performative,
            "content": content,
            "timestamp": datetime.now()
        }
        return message

class WarehouseAgent(SupplyChainAgent):
    def request_inventory_update(self, item_id, quantity):
        return self.send_message(
            receiver="inventory_manager",
            performative="REQUEST",
            content={
                "action": "update_inventory",
                "item_id": item_id,
                "quantity": quantity,
                "reason": "stock_level_low"
            }
        )

class InventoryManager(SupplyChainAgent):
    def process_request(self, message):
        if message["performative"] == "REQUEST":
            # Process inventory update
            success = self.update_inventory(
                message["content"]["item_id"],
                message["content"]["quantity"]
            )
            
            # Send response
            return self.send_message(
                receiver=message["sender"],
                performative="INFORM" if success else "FAILURE",
                content={
                    "status": "updated" if success else "failed",
                    "item_id": message["content"]["item_id"]
                }
            )

This example shows how agents can:

  • Make formal requests
  • Process and respond to messages
  • Maintain clear communication protocols
  • Handle success and failure cases

Middleware Solutions: Building Robust Systems

Middleware frameworks like ROS and JADE provide the infrastructure for complex agent interactions. They're particularly valuable in systems that need real-time coordination and reliability.

Example: Smart Factory System

Here's a simplified example of how middleware might coordinate manufacturing agents: ROS-based implementation demonstrating real-time monitoring and quality control in manufacturing.

from ros import Node, Publisher, Subscriber

class ProductionLineNode(Node):
    def __init__(self):
        super().__init__('production_line')
        
        # Create publishers for different topics
        self.status_pub = self.create_publisher(
            msg_type=ProductionStatus,
            topic='production_status',
            qos_profile=10
        )
        
        # Subscribe to relevant topics
        self.create_subscription(
            msg_type=QualityMetrics,
            topic='quality_metrics',
            callback=self.quality_callback,
            qos_profile=10
        )
        
        # Create timers for periodic checks
        self.create_timer(1.0, self.check_production_status)
    
    def quality_callback(self, msg):
        """Handle quality control messages"""
        if msg.defect_rate > 0.01:  # 1% threshold
            self.adjust_production_parameters(msg.metrics)
            self.notify_maintenance()
    
    def check_production_status(self):
        """Periodic production line status check"""
        status = self.get_line_status()
        self.status_pub.publish(status)

This code demonstrates:

  • Real-time monitoring and response
  • Event-driven architecture
  • Distributed system coordination
  • Quality control integration

Conclusion

Building unified interfaces for AI agents is about creating systems that can grow and adapt while maintaining reliable communication. Start with standard protocols for basic functionality, then add semantic understanding and formal communication as your system grows. These examples demonstrate practical implementations of unified interfaces using various technologies. The key is selecting the right combination of tools based on your specific requirements while maintaining flexibility for future expansion.

Each approach has its strengths:

  • gRPC for high-performance, structured communication
  • RDF/Neo4j for complex knowledge representation
  • RabbitMQ for reliable message passing
  • Redis for event-driven architectures

Choose the appropriate combination based on your scalability, reliability, and performance requirements.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment