Skip to content

Latest commit

 

History

26 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Project Risk Response Agent

Most project risks don't kill projects because they're unpredictable - they kill projects because nobody wrote down what to do about them until it was too late.

This is an AI-powered web application that walks project managers through identifying, validating, and responding to project risks using the four standard PMI/PMBOK strategies: Mitigate, Avoid, Transfer, and Accept. You describe a risk in plain English, and the system generates a concrete, 5-step action plan you can actually hand to your team.


Python License Streamlit LangGraph


Why This Exists

Risk registers are one of those things every project manager knows they should maintain, but few actually do well. The usual process looks like this: someone identifies a vague risk in a meeting ("the server might crash"), it gets written on a sticky note or dumped into a spreadsheet with no response plan, and it sits there until it actually happens.

This tool closes that gap. It forces specificity by asking follow-up questions when a risk is too vague, ties every risk to a concrete response strategy, and generates actionable steps, not generic advice. The entire flow takes under 3 minutes.


Architecture

The application is built around a LangGraph state machine. A shared RiskState dictionary flows through two AI-powered nodes, with a conditional router deciding what happens next based on the validation results.

┌─────────────────┐
│   User Input    │
│  (Plain English)│
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│  validate_risk  │◄──── LLM classifies: is it a real risk? Is it detailed enough?
│     (Node 1)    │      Returns structured JSON
└────────┬────────┘
         │
         ▼
┌─────────────────────┐
│ route_after_         │     ┌──────────────┐
│ validation           │────►│     END      │  (not a valid risk → rejected)
│ (Conditional Router) │     └──────────────┘
│                      │     ┌──────────────┐
│                      │────►│     END      │  (valid but vague → follow-up questions shown)
│                      │     └──────────────┘
│                      │     ┌──────────────────┐
│                      │────►│generate_response │  (valid + detailed + strategy selected)
└──────────────────────┘     │    (Node 2)      │
                             └────────┬─────────┘
                                      │
                                      ▼
                             ┌──────────────────┐
                             │   5-Step Action   │
                             │      Plan         │
                             └────────┬─────────┘
                                      │
                                      ▼
                             ┌──────────────────┐
                             │  User Feedback   │
                             │  (Like/Dislike)  │
                             └────────┬─────────┘
                                      │
                                      ▼
                             ┌──────────────────┐
                             │  Saved to SQLite │
                             │    Database      │
                             └──────────────────┘

The key design choice: invalid or vague inputs loop back to the user for correction instead of producing garbage output. The router checks three conditions (is_valid_risk, is_detailed, strategy) and only advances to response generation when all three are satisfied.


Tech Stack

Technology Role Why This
Python 3.11 Core language Type hints (TypedDict) used for the state schema
Streamlit Web UI Zero-frontend-code deployment; reruns on interaction fit the state machine model
LangChain LLM interface Standardized API layer for prompt → completion calls
LangGraph Agent flow control State machine with conditional routing — cleaner than raw if/else chains for multi-step AI flows
OpenRouter API LLM access Model-agnostic gateway — swap between GPT, Gemma, or any supported model by changing one string
SQLite Database File-based, zero-config — chosen over MySQL specifically for frictionless Streamlit Cloud deployment
SQLAlchemy ORM Database-agnostic queries — the MySQL → SQLite migration required changing exactly one line
python-dotenv Config Keeps API keys out of source code

Project Structure

Risk_Agent_Project/
├── app.py                  # Streamlit UI - all 4 screens and session state logic
├── dashboard.py            # Dashboard page - renders risk history table from DB
├── requirements.txt        # Python dependencies
├── .env.example            # Template for required environment variables
├── .gitignore
│
├── graphs/
│   ├── state.py            # RiskState TypedDict - shared state schema
│   ├── nodes.py            # validate_risk() and generate_response() - the two AI nodes
│   └── graph.py            # LangGraph wiring - nodes, edges, conditional router, compile
│
├── prompts/
│   └── prompts.py          # System prompts for validation and response generation
│
├── database/
│   ├── db.py               # SQLAlchemy engine, session factory, save_risk(), get_all_risks()
│   └── models.py           # RiskEntry ORM model - table schema definition
│
└── risks.db                # SQLite database file (auto-created on first run, gitignored)

Setup & Installation

Prerequisites

  • Python 3.11+
  • An OpenRouter account (free tier works)

Steps

1. Clone the repository

git clone https://github.com/Shayan-Bhowmik/Project-Risk-Response-Agent.git
cd Project-Risk-Response-Agent

2. Create and activate a virtual environment

python -m venv venv

Windows:

venv\Scripts\activate

macOS/Linux:

source venv/bin/activate

3. Install dependencies

pip install -r requirements.txt

4. Set up environment variables

Copy the example file and add your API key:

cp .env.example .env

Open .env and replace the placeholder with your actual key:

OPENROUTER_API_KEY=your_actual_openrouter_api_key

You can get a free API key at openrouter.ai/settings/keys.

5. Run the application

streamlit run app.py

The app will open automatically at http://localhost:8501. The SQLite database (risks.db) is created automatically on first run - no manual database setup required.


How It Works

Screen 1: Risk Input Type a project risk in plain English (e.g., "Our lead developer might leave next month") and click Analyze Risk. The input is packaged into a RiskState dictionary and sent to the LangGraph engine.

Screen 2: Validation & Follow-Up The validate_risk node sends your text to the LLM with a strict system prompt. The AI returns structured JSON determining if it's a genuine project risk and if it's detailed enough. If it's too vague, custom follow-up questions appear. If it's not a project risk at all (e.g., "my ice cream is melting"), it's rejected outright.

Screen 3: Strategy Selection Once the risk is validated as detailed enough, four strategy buttons appear in a 2×2 grid:

  • Mitigate: Reduce the impact
  • Accept: Acknowledge and monitor
  • Transfer: Shift to a third party
  • Avoid: Change the plan entirely

Screen 4: AI Response & Feedback The generate_response node receives the detailed risk and chosen strategy, then produces a tailored 5-step action plan. You rate the response with Like or Dislike, and everything - the risk, strategy, response, rating, and timestamp - is saved to the SQLite database.

Dashboard Accessible via the sidebar at any time. Displays a full table of all evaluated risks with columns for Risk Input, Strategy, AI Response (truncated), Rating, and Date.


Design Decisions

SQLite over MySQL

The project was originally built on MySQL. During deployment preparation for Streamlit Cloud, it became clear that a hosted MySQL instance would add unnecessary complexity and cost for what is fundamentally a single-user tool. SQLite eliminated the need for a database server entirely — the switch required changing one connection string and adding check_same_thread=False for Streamlit's multi-threaded execution. SQLAlchemy made this a one-line migration because the ORM abstracted the database dialect.

OpenRouter over Direct API Access

Instead of hardcoding a single LLM provider, all model calls go through OpenRouter's unified API. This means swapping from GPT to Gemma to any other supported model is a single string change in nodes.py — no code rewrite, no new SDK, no different authentication flow. The free tier is sufficient for development and testing.

Hand-Written Code

Every line of this application was written by the developer. AI was used strictly as a design reviewer and debugging mentor, never as the code generator. This was a deliberate learning constraint: understanding every function, every state transition, and every edge case firsthand.


Roadmap

  • Multi-turn conversation support - Allow users to refine risks through back-and-forth dialogue instead of a single detail submission
  • PDF export - Generate downloadable risk response reports from the dashboard
  • Persistent cloud database - Option to connect a hosted database for permanent storage on Streamlit Cloud
  • Batch risk analysis - Upload a CSV of risks and generate response plans in bulk

📄 License

This project is licensed under the MIT License - you are free to use, modify, and distribute this software for any purpose, commercial or otherwise, with attribution. See the LICENSE file for the full text.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages