Note:

Build an AI Agent with Multi-Agent Communication Protocol Server for Invoice Resolution

Introduction

Companies that deal with a large volume of products - such as distributors, industries and retail chains - often face the challenge of identifying products based on inaccurate, incomplete or varied textual descriptions. In environments where data is entered manually, typos, abbreviations and different trade names can make it difficult to correctly identify items in systems such as Enterprise Resource Planning (ERP), Customer Relationship Management (CRM) and e-commerce platforms.

In this scenario, there is a common need for tools that can:

In this tutorial, we will learn how to create an AI agent specialized in resolving inconsistencies in customer return invoices. The agent is able to interact with an MCP server that provides vector search and invoice retrieval tools, allowing the agent to automatically find the company’s original A/R invoice based on information provided by the customer.

A MCP Server (Model Context Protocol) is a software component responsible for mediating communication between intelligent agents and external services through a standardized protocol of messages and tools. It acts as a bridge between language models (LLMs) and existing APIs, allowing AI agents to access specific functionalities of legacy systems without the need to rewrite or directly adapt them.

How does it work?

The MCP server:

Usage with Legacy Applications

Legacy applications often already provide functionality through databases, files, or internal APIs. With a MCP Server, you can:

Advantages

This agent is based on an Oracle Cloud Infrastructure (OCI) Generative AI language model and integrates with dynamically declared tools managed by an MCP server.

With these two components integration, the system enables an agent based on Oracle LLM:

This modular design allows for reusability and easy evolution of the system to domains other than invoices.

Objectives

Prerequisites

Task 1: Create an Oracle Database 23ai (Always Free)

In this task, we will learn how to provision an Oracle Database 23ai in Always Free mode. This version offers a fully managed environment, ideal for development, testing and learning, at no additional cost.

  1. Log in to the OCI Console, navigate to Oracle Database, Autonomous Database and click Create Autonomous Database Instance.

  2. Enter the following information.

    • Database Name: Enter an identifying name for your instance.
    • Workload Type: Select Data Warehouse or Transaction Processing, according to your needs.
    • Compartment: Select an appropriate compartment to organize your resources.
  3. Select Always Free to ensure that the instance is provisioned for free.

  4. Create a secure password for the ADMIN user, which will be used to access the database.

  5. Review the settings and click Create Autonomous Database. Wait a few minutes for the instance to be provisioned and available for use.

Task 2: Run the Autonomous Database Table Creation Script

Prepare the database for our use case. Download and run the SQL script from here: script.sql that creates three essential tables (PRODUCTS, INVOICE and ITEM_INVOICE) for the scenario of reconciling invoices with AI agents.

  1. Go to the OCI Console, navigate to Oracle Database, Autonomous Database and click the name of the newly created instance.

  2. Click Database Actions and SQL to open the SQL console in the browser.

  3. Download and open the script.sql file locally and paste all the contents into the SQL console editor.

  4. Click Run or press Ctrl + Enter. Wait for confirmation that the commands have been executed successfully.

  5. Run the following commands to verify that the tables have been created.

    SELECT table_name FROM user_tables;
    

Task 3: Insert Example Data into Tables

Insert dummy data that will simulate a real scenario for the application of AI agents. We will use two SQL scripts:

This data will be used by AI agents to resolve inconsistencies in returns invoices.

  1. Go to the OCI Console, navigate to Oracle Database, Autonomous Database and click the name of the newly created instance.

  2. Click Database Actions and SQL to open the SQL console in the browser.

  3. Download and open the contents of the insert_products_books.sql file and paste it into the SQL editor.

  4. Click Run or press Ctrl + Enter.

  5. Now, download and open the contents of the invoice_data_insert.sql file and paste it into the editor.

  6. Click Run or press Ctrl + Enter.

  7. Run the following command to check the data.

    SELECT * FROM PRODUCTS;
    SELECT * FROM INVOICE;
    SELECT * FROM ITEM_INVOICE;
    

Task 4: Create and Compile the Advanced Search Function in the Database

Create a PL/SQL function called fn_advanced_search, which performs intelligent searches for keywords in product descriptions. This function will be used by AI agents as part of the resolve_ean tool, allowing them to find the nearest EAN code based on the description provided by a customer on the returns note.

What does the function do?

Follow the steps:

  1. Copy and paste the complete similarity_search.sql script into the autonomous database SQL console.

    This includes:

    • Creating the products table (if it has not already been done).
    • Creating a text index.
    • Types product_result and product_result_tab.
    • The fn_advanced_search function.
    • Optional tests.
  2. Run the complete script. The result should be Function created and Type created.

  3. Run the following query to test the function with simulated descriptions.

    SELECT *
    FROM TABLE(fn_advanced_search('harry poter askaban'))
    ORDER BY similarity DESC;
    

Task 5: Vectorize Products for Semantic Search with AI

In this task, we will complement advanced SQL-based search with a new approach based on semantic vectors. This will be especially useful for AI agents that use embeddings (numerical representations of phrases) to compare similarity between product descriptions - more flexibly and intelligently than word or phonetic searches.

To do this, we will use the Python script (process_vector_products.py), which connects to the Oracle database, extracts the products from the PRODUCTS table, transforms their descriptions into vectors (embeddings), and builds a vector index using the Oracle database itself.

What does the script do?

Note: The embeddings are converted into bytes with np.float32.tobytes() to be stored as a BLOB. To retrieve the vectors, use np.frombuffer(blob, dtype=np.float32).

This format allows future similarity searches to be done directly using SQL or by loading the vectors from the database for operations with np.dot, cosine_similarity or integration with LLMs.

This script generates semantic embeddings for products and writes these vectors to the Oracle 23ai database. The main points are highlighted below:

Run the Script:

Remember that you need Oracle Wallet downloaded and configured. Run it in the terminal.

python process_vector_products.py

Done! The products in the database have been vectorized.

Why is this important?

Vector search is highly effective for finding products even when the description is subjective, imprecise or in natural language.

Understand the Code: LLM Agent with MCP Server

This project is made up of 3 main components:

Understand the functionality of each component and detailed highlights the most important parts of the code.

Task 6: Configure the Model and Embeddings in the MCP Agent

Let us configure the language model and embeddings used by the conversational agent based on the MCP protocol, using OCI Generative AI services.

  1. Configure the Language Model (LLM).

    The language model is responsible for interpreting messages, generating responses and acting as the agent’s main brain.

    • Configure in the main.py file.

      from langchain_community.chat_models.oci_generative_ai import ChatOCIGenAI
      
      llm = ChatOCIGenAI(
          model_id="cohere.command-r-08-2024",
          service_endpoint="https://inference.generativeai.us-chicago-1.oci.oraclecloud.com",
          compartment_id="ocid1.compartment.oc1..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
          auth_profile="DEFAULT",
          model_kwargs={"temperature": 0.1, "top_p": 0.75, "max_tokens": 2000}
      )
      
      Parameter Description
      model_id Generative AI model ID, e.g. cohere.command-r-08-2024
      service_endpoint Generative AI service regional endpoint
      compartment_id OCID of the OCI compartment
      auth_profile Name of the profile configured in the file ~/.oci/config
      model_kwargs Temperature, top-p and response size
    • List available models.

      • Using the OCI CLI:

        oci generative-ai model list --compartment-id <seu_compartment_id>
        
      • Using the Python SDK:

        from oci.generative_ai import GenerativeAiClient
        from oci.config import from_file
        
        config = from_file(profile_name="DEFAULT")
        client = GenerativeAiClient(config)
        
        models = client.list_models(compartment_id=config["compartment_id"])
        for model in models.data:
            print(model.display_name, model.model_id)
        
  2. Configure embeddings for semantic search.

    Search for similar products or contextual information depends on vector embeddings.

    Example of use in the agent:

    @mcp.tool()
    def search_vectorized_product(description: str) -> dict:
        """
            Searches for a product by description using embeddings.
        """
        return sercher.search_similar_products(description)
    

    Change the parameters (product_search.py) as shown below:

    
    class SimilarProductSearch:
        def __init__(
                self,
                top_k=5,
                minimum_distance=1.0,
                model_id="cohere.embed-english-light-v3.0",
                service_endpoint="https://inference.generativeai.us-chicago-1.oci.oraclecloud.com",
                compartment_id="ocid1.compartment.oc1..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                auth_profile="DEFAULT",
                wallet_path="/WALLET_PATH/Wallet_oradb23ai",
                db_alias="oradb23ai_high",
                username="USER",
                password="Password"
        ):
    
    Parameter Description
    top_k Number of suggestions returned.
    minimum_distance Maximum distance to consider relevant result.
    model_id ID of the embedding model in the OCI (e.g. cohere.embed-english-light-v3.0).
    service_endpoint OCI Generative AI regional endpoint.
    compartment_id compartment OCID.
    auth_profile Profile name in ~/.oci/config file.
    wallet_path Path to the Oracle Database 23ai wallet.
    db_alias Database alias.
    username Database user.
    password Database password.

    Configure the MCP Server:

    Just as you did when executing the process_vector_products.py code, you will need to configure the Oracle Wallet for the Oracle Database 23ai database.

    Modify the parameters according to your settings:

    import os
    
    # Oracle Wallet settings
    WALLET_PATH = "/path/to/Wallet"
    DB_ALIAS = "oradb23ai_high"
    USERNAME = "admin"
    PASSWORD = "..."
    
    # Define the environment variable required for the Oracle client
    os.environ["TNS_ADMIN"] = WALLET_PATH
    

    And then execute the process_vector_products.py to vectorize the products into the Oracle Database 23ai.

    python process_vector_products.py
    

With this, the LLM model and embeddings are ready to be used by the MCP agent with LangGraph and LangChain.

  1. Run the main.py file using the following command.

    python main.py
    
  2. When the You: prompt appears, enter the following statement.

    { "customer": "Customer 108",  "description": "Harry Poter askaban", "price": 82.26, "location": "SP"}
    

    Note: The name of the book Harry Potter and Azkaban are spelled wrong, but the engine can find it without any problems.

    img.png

    img_1.png

    Note that the services have been executed:

    fetch_vectorized_product
    resolve_ean
    search_invoices_by_criteria
    
  3. Now, enter the following statement.

    { "customer": "Customer 108",  "description": "Harry Poter askaban", "price": 82.26}
    

    You will see that there was no invoice record found. This is because location is key to finding an invoice.

    img_2.png

  4. Now, enter the following statement.

    { "customer": "Customer 108",  "description": "Harry Poter", "location": "SP"}
    

    This time, we enter the location but omit the unit price.

    img_3.png

    And yet the invoice was found. This is because the price is not fundamental, but it does help to close the gap to be more assertive.

    Some examples for testing are:

     { "customer": "Customer 108",  "description": "Harry Poter askaban", "price": 82.26, "location": "SP"}
    
     { "customer": "Customer 108",  "description": "Harry Poter askaban", "price": 82.26}
    
     { "customer": "Customer 108",  "description": "Harry Poter askaban", "location": "SP"}
    
     { "customer": "Customer 108",  "description": "Harry Poter askaban", "price": 82.26, "location": "RJ"}
    
     { "customer": "Customer 125",  "description": "Harry Potter Chamber", "price": 79.16, "location": "SP"}
    
     { "customer": "Customer 125",  "description": "Harry Potter Chamber", "price": 79.15, "location": "SP"}
    

Task 8: View the Observability with Phoenix

Enter http://localhost:6006/ in your browser to view the observability with Phoenix.

img.png

img.png

img.png

Acknowledgments

More Learning Resources

Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.

For product documentation, visit Oracle Help Center.