>_ INITIALIZING DATABANKS...
>_ LOADING UI MODULES...
>_ DECRYPTING ASSETS...
>_ SECURING CONNECTION...
>_ SYSTEM READY.

The Agentic Brain

LangGraph LangChain Google Gemini 2.5 Flash PostgreSQL (pgvector)
USER: SYS_ADMIN | DATE: 2026-03-27 | REF_PID: Fraud-Detection-System
Cover for The Agentic Brain

Most AI applications today use a pattern called RAG (Retrieval-Augmented Generation), where the system fetches data and rigidly stuffs it into an LLM prompt. This project uses a more advanced pattern: a ReAct (Reasoning and Acting) Agent.

  1. What is an Agent? Instead of just answering a prompt, an Agent is given a goal and a set of “tools” (Python functions). It enters a loop: it reasons about what to do, it acts by calling a tool, it observes the result, and it repeats until it solves the problem.

  2. What is Vector Search (pgvector)? Machine learning models can convert text or user behaviors into “embeddings” lists of thousands of numbers representing coordinates in a high-dimensional space. Concepts or behaviors that are similar end up physically close to each other in this space. By storing these embeddings in PostgreSQL using the pgvector extension, we can query the database not for exact matches, but for mathematical similarity.

Building the Tools (Giving the LLM Hands)

For the Gemini model to investigate fraud, it needs hands to fetch data. I created two specific tools using LangChain’s @tool decorator. The docstrings here are critical; they are not just for developers the LLM actually reads them to understand when and how to use the function.

The most complex tool is the historical vector search. If a transaction doesn’t have an embedding yet, the tool generates one “Just-In-Time” (JIT) and searches the database for similar behavioral footprints

# src/agent/tools.py (Simplified)

@tool
def search_historical_fraud(transaction_id: str) -> str:
    """
    Searches the database for past transactions that are mathematically/behaviorally 
    similar to the target transaction using vector similarity.
    """
    record = get_transaction_by_id(transaction_id)
    vector_to_search = record.get("embedding")
    
    # Just-In-Time Embedding Generation if missing
    if not vector_to_search:
        embedder = GoogleGenerativeAIEmbeddings(model="gemini-embedding-001")
        text_to_embed = f"Transaction amount: ${tx_data.get('Amount')}, Time: {tx_data.get('Time')}."
        vector_to_search = embedder.embed_query(text_to_embed)
        update_transaction_embedding(transaction_id, vector_to_search)

    # Perform Vector Search
    similar_records = search_similar_transactions(vector_to_search, exclude_id=transaction_id, limit=3)
    
    # ... formats the result into a string for the LLM to read ...

Under the hood, this tool relies on a brilliant feature of pgvector. Instead of writing complex matching algorithms, we can use the <=> operator directly in our SQL query to calculate the Cosine Distance between vectors:

# src/core/database.py - Inside search_similar_transactions()
# The <=> operator calculates Cosine Distance natively in PostgreSQL
query = text("""
    SELECT transaction_id, is_fraud, amount, embedding <=> :target_vector AS distance
    FROM predictions
    WHERE transaction_id != :target_id AND embedding IS NOT NULL
    ORDER BY distance ASC
    LIMIT :limit
""")

The LangGraph Agent Loop

With the tools ready, we initialize the agent using LangGraph. We provide the Gemini 2.5 Flash model with its tools and a strict system prompt.

Because the raw PCA-transformed features (V1 through V28) from the dataset are anonymized, the prompt explicitly instructs the LLM not to hallucinate their meanings, ensuring the final report remains highly professional.

# src/agent/agent.py (Simplified)

def run_investigation(transaction_id: str) -> dict:
    # 1. Setup the Agentic Loop
    llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash", temperature=0)
    tools = [analyze_shap_values, search_historical_fraud]
    agent_executor = create_react_agent(llm, tools)
    
    # 2. Provide strict operational boundaries
    prompt = f"""
    You are an expert financial risk analyst. Investigate transaction {transaction_id}. 
    
    INSTRUCTIONS:
    1. Use the SHAP tool to find out why the model flagged it.
    2. Use the historical search tool to see if this pattern has happened before.
    3. DATA RULE: Features V1-V28 are PCA-transformed hidden behavioral vectors. 
       Do NOT guess what they mean. Refer to them as 'anomalous behavioral vectors'.
    """
    
    # 3. Execute the Loop
    for step_event in agent_executor.stream({"messages": [("user", prompt)]}):
        pass # The agent is thinking, using tools, and observing here
        
    raw_final_message = list(step_event.values())[0]["messages"][-1].content

    # 4. Enforce Structured Output
    # We pass the raw text through a structured output chain to guarantee a JSON format 
    # that our Streamlit UI can render perfectly every time.
    structured_llm = llm.with_structured_output(InvestigationReport)
    final_report = structured_llm.invoke(f"Extract info: {raw_final_message}")
    
    return json.loads(final_report.model_dump_json())

By combining Explainable AI (SHAP) with Vector Search (pgvector) under the direction of an autonomous LangGraph agent, the system transforms raw database rows into actionable, boardroom ready intelligence in seconds

0%