Skip to content

snath-ai/customer-support-demo

Repository files navigation

Glass Box Ready Sponsor

GlassBox Multi-Agent Demo (Customer Support Bot)

This repository is the "killer demo" for the Lár Engine — an open-source, "glass box" framework for building auditable, multi-agent AI systems.

This app is a live, interactive multi-agent customer support bot. It's not one "mega-agent" trying to do everything. It's a team of specialized agents, and you can watch them work together like a transparent "assembly line."

You will see the agent:

  1. Triage your question (e.g., "Billing" or "Tech Support").

  2. Plan a search query for its knowledge base.

  3. Retrieve the correct facts.

  4. Route the facts to the correct "Specialist" agent.

  5. Write a final, auditable answer.

The Lár Philosophy: Why a "Dumb" Engine Makes "Smart" Agents

The "magic" of AI agents isn't magic at all—it's just a graph. Other frameworks try to sell you a "magic" AgentExecutor that does everything at once. It's a "black box," and when it breaks, it's impossible to fix.

Lár is the opposite. It's a simple, "dumb" GraphExecutor loop. It runs one node, stops, and logs what happened.

This is the "glass box" advantage: the "intelligence" doesn't live in the engine; it lives in your nodes. This makes your agents 100% auditable and deterministic.

How it Works: The "Triage & Route" Pattern

How does lar "know" whether to use a Tech Support or a Billing agent? It doesn't. You tell it how to decide, in two simple, auditable steps:

  1. Step 1: The "Triage" (LLMNode) An LLMNode runs with a specific prompt. Its only job is to classify the user's task and create a label (e.g., "TECH_SUPPORT"). It writes this label to the GraphState

  2. Step 2: The "Manager" (RouterNode) A RouterNode (which is pure, "dumb" Python) reads that label from the GraphState. It then uses a simple if statement or a dict lookup to choose which "specialist" node to run next.

Glass Box vs Black Box

Other Frameworks (“Black Box”) Lár (“Glass Box”)
"Chaotic Chat Room" model. Agents talk to each other and you hope for a good result. "Deterministic "Assembly Line." You define the exact path of collaboration with RouterNode
No Control. The "Tech Support" agent might try to answer a "Billing" question. "Total Control." The RouterNode guarantees only the correct specialist agent ever sees the task.
Implicit Data Flow. Agents can pollute each other's context. "Explicit Data Flow." The history log proves what data was given to each agent.
Wasteful. If one step fails, other agents may still run, wasting API calls. "Efficient." If a step fails, the graph stops. The TechAgent never runs if the TriageAgent fails.

How to Run This Demo

This demo uses a local FAISS vector store, built from the document_text.txt FAQ.

  1. build_index.py — builds a FAISS vector store
  2. support_app.py — launches the interactive Streamlit GlassBox Support app

Prerequisites

  • Python 3.10+
  • Poetry
  • Google Gemini API Key
  • macOS/Linux/WSL/Windows

1 Installation

git clone https://github.com/snath-ai/customer-support-demo.git
cd customer-support-demo
# Install all dependencies (including lar-engine from PyPI)
poetry install

2 Set Up Environment Variables

Create a .env file:

GOOGLE_API_KEY="YOUR_API_KEY_HERE"

3 Build the Local Vector Index (Run Once)

poetry run python build_index.py

This creates your FAISS index in vector_store/.


4 Run the GlassBox Support App

poetry run streamlit run support_app.py

Open in browser: http://localhost:8501 and try asking:

  • How do I reset my password? (This will route to TECH_AGENT)
  • Can I get a refund? (This will route to BILLING_AGENT)

Ask:

How the Agent Works: Execution Blueprint

This is the lar assembly line in action.

graph TD
    A[Start] --> B(LLMNode<br/>'Agent 1: Triage');
    B --> C(LLMNode<br/>'Agent 2: Planner');
    C --> D(ToolNode<br/>'Retriever');
    
    %% This is the "hub" node
    D --> E{RouterNode<br/>'Manager: Route By Category'};
    
    %% Define the three parallel paths
    E -- "BILLING_AGENT" --> F;
    E -- "TECH_AGENT" --> G;
    E -- "GENERAL_AGENT" --> H;

    %% Define what's INSIDE the subgraphs
    subgraph "Billing Department"
        F(LLMNode<br/>'Agent 3: Billing Specialist');
    end

    subgraph "Tech Support Department"
        G(LLMNode<br/>'Agent 4: Tech Specialist');
    end
    
    subgraph "General"
        H(LLMNode<br/>'Agent 5: Generalist');
    end

    %% Define the "join" point
    F --> I[AddValueNode<br/>'Final Answer'];
    G --> I;
    H --> I;
    I --> J[END];
Loading

Lár Engine Architecture: The Multi-Agent Assembly Line

The core of this application is a Multi-Agent Orchestration Graph. Lár forces you to define the assembly line, which guarantees predictable, auditable results.

1. Graph Flow (Execution Sequence)

The agent executes in a fixed, 6-step sequence. The graph is defined backwards in the code, but the execution runs forwards:

Step Node Name Lár Primitive Action State Output
0 (Start) triage_node LLMNode Classifies the user's input ({task}) into a service category (BILLING, TECH, etc.). category
1 planner_node LLMNode Converts the task into a concise, high-quality search query. search_query
2 retrieve_node ToolNode Executes the local FAISS vector search and retrieves the relevant context. retrieved_context
3 specialist_router RouterNode Decision point. Reads the category and routes the flow to the appropriate specialist. (No change; routing)
4 billing/tech_agent LLMNode The chosen specialist synthesizes the final answer using the retrieved context. agent_answer
5 (End) final_node AddValueNode Saves the synthesized answer as final_response and terminates the graph. final_response

2. Architectural Primitives Used

This demo relies on the core Lár primitives to function:

  • LLMNode: Used 5 times (Triage, Plan, and the 3 Specialists) for all reasoning and synthesis steps.

  • RouterNode: Used once (specialist_router) for the deterministic if/else branching logic.

  • ToolNode: Used once (retrieve_node) to securely execute the local RAG database lookup.

  • GraphExecutor: The engine that runs this entire sequence and produces the complete audit log

This is the full logic from support_app.py. It's just a clean, explicit Python script.

'''
====================================================================
    ARCHITECTURE NOTE: Defining the Graph Backwards
    
    The Lár Engine uses a "define-by-run" philosophy. Because a node 
    references the *next_node* object (e.g., next_node=planner_node),
    the nodes MUST be defined in Python in the REVERSE order of execution 
    to ensure the next object already exists in memory.
    
    Execution runs: START (Triage) -> END (Final)
    Definition runs: END (Final) -> START (Triage)
====================================================================

'''
from lar import *
from lar.utils import compute_state_diff # (Used by executor)

# 1. Define the "choice" logic for our Router
def triage_router_function(state: GraphState) -> str:
    """Reads the 'category' from the state and returns a route key."""
    category = state.get("category", "GENERAL").strip().upper()
    
    if "BILLING" in category:
        return "BILLING_AGENT"
    elif "TECH_SUPPORT" in category:
        return "TECH_AGENT"
    else:
        return "GENERAL_AGENT"

# 2. Define the agent's nodes (the "bricks")
# We build from the end to the start.

# --- The End Nodes (the destinations) ---
final_node = AddValueNode(key="final_response", value="{agent_answer}", next_node=None)
critical_fail_node = AddValueNode(key="final_status", value="CRITICAL_FAILURE", next_node=None)

# --- The "Specialist" Agents ---
billing_agent = LLMNode(
    model_name="gemini/gemini-2.5-pro",
    prompt_template="You are a BILLING expert. Answer '{task}' using ONLY this context: {retrieved_context}",
    output_key="agent_answer",
    next_node=final_node
)
tech_agent = LLMNode(
    model_name="gemini/gemini-2.5-pro",
    prompt_template="You are a TECH SUPPORT expert. Answer '{task}' using ONLY this context: {retrieved_context}",
    output_key="agent_answer",
    next_node=final_node
)
general_agent = LLMNode(
    model_name="gemini/gemini-2.5-pro",
    prompt_template="You are a GENERAL assistant. Answer '{task}' using ONLY this context: {retrieved_context}",
    output_key="agent_answer",
    next_node=final_node
)
    
# --- The "Manager" (Router) ---
specialist_router = RouterNode(
    decision_function=triage_router_function,
    path_map={
        "BILLING_AGENT": billing_agent,
        "TECH_AGENT": tech_agent,
        "GENERAL_AGENT": general_agent
    },
    default_node=general_agent
)
    
# --- The "Retriever" (Tool) ---
retrieve_node = ToolNode(
    tool_function=retrieve_relevant_chunks, # This is our local FAISS search
    input_keys=["search_query"],
    output_key="retrieved_context",
    next_node=specialist_router, 
    error_node=critical_fail_node
)
    
# --- The "Planner" (LLM) ---
planner_node = LLMNode(
    model_name="gemini/gemini-2.5-pro",
    prompt_template="You are a search query machine. Convert this task to a search query: {task}. Respond with ONLY the query.",
    output_key="search_query",
    next_node=retrieve_node
)
    
# --- The "Triage" Node (The *real* start) ---
triage_node = LLMNode(
    model_name="gemini/gemini-2.5-pro",
    prompt_template="You are a triage bot. Classify this task: \"{task}\". Respond ONLY with: BILLING, TECH_SUPPORT, or GENERAL.",
    output_key="category",
    next_node=planner_node
)

# 3. Run the Agent
executor = GraphExecutor()
initial_state = {"task": "How do I reset my password?"}
result_log = list(executor.run_step_by_step(
    start_node=triage_node, 
    initial_state=initial_state
))
'''
 The "glass box" log for Step 0 will show:
 "state_diff": {"added": {"category": "TECH_SUPPORT"}}

 The log for Step 1 will show:
 "Routing to LLMNode" (the tech_support_agent)
 '''

Show Your Agents are Auditable

If you build an agent using the Lár Engine, you are building a dependable, verifiable system. Help us spread the philosophy of the "Glass Box" by displaying the badge below in your project's README.

By adopting this badge, you signal to users and collaborators that your agent is built for production reliability and auditability.

Show an Auditable Badge to your project: Glass Box Ready

Badge Markdown:

[![Glass Box Ready](https://img.shields.io/badge/Auditable-Glass%20Box%20Ready-54B848?style=flat&logo=checkmarx&logoColor=white)](https://docs.snath.ai)

⚡ Ready to build with Lár? (Agentic IDEs)

Lár is designed for Agentic IDEs (Cursor, Windsurf, Antigravity) and strict code generation.

We provide a 3-Step Workflow to make your IDE an expert Lár Architect.

1. The Strategy: "Reference, Don't Copy"

Instead of pasting massive prompts, simply reference the master files in the lar/ directory (or download them from the main repo).

2. The Workflow

  1. Context (The Brain): In your IDE chat, reference @lar/IDE_MASTER_PROMPT.md. This loads the strict typing rules and "Code-as-Graph" philosophy.
  2. Integrations (The Hands): Reference @lar/IDE_INTEGRATION_PROMPT.md to generate production-ready API wrappers in seconds.
  3. Scaffold (The Ask): Open @lar/IDE_PROMPT_TEMPLATE.md, fill in your agent's goal, and ask the IDE to "Implement this."

Example Prompt to Cursor/Windsurf: "Using the rules in @lar/IDE_MASTER_PROMPT.md, implement the agent described in @lar/IDE_PROMPT_TEMPLATE.md."


Support the Project

Lár is an open-source agent framework built to be clear, debuggable, and developer-friendly. If this project helps you, consider supporting its development through GitHub Sponsors.

Become a sponsor → Sponsor on GitHub

Your support helps me continue improving the framework and building new tools for the community.

Credits

License

This Project is licensed under the Apache License 2.0

This means:

  • You are free to use Làr in personal, academic, or commercial projects.
  • You may modify and distribute the code.
  • You MUST retain the LICENSE and the NOTICE file.
  • If you distribute a modified version, you must document what you changed.

Apache 2.0 protects the original author (Aadithya Vishnu Sajeev) while encouraging broad adoption and community collaboration.

For developers building on Làr: Please ensure that the LICENSE and NOTICE files remain intact to preserve full legal compatibility with the Apache 2.0 terms.

About

A customer support agent demo built using the Làr Engine

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages