Category: Builder's Corner
Keyword: build custom workflow bot LLM python 2026
Looking to automate complex approval processes with AI in 2026? This hands-on tutorial walks you through building a custom approval workflow bot using Python and a Large Language Model (LLM) API. You'll learn to automate multi-step approvals, integrate with messaging platforms, and add LLM-powered decision logic—no black-box SaaS required.
For a broader context on AI workflow automation, see The Ultimate Guide to AI Workflow Automation Platform Integrations for 2026.
Prerequisites
- Python 3.11+ (tested with Python 3.12)
- Pip (comes with Python 3.11+)
- OpenAI API key (or another LLM provider; we'll use OpenAI GPT-4o as an example)
- Basic Python knowledge (functions, classes, virtual environments)
- Familiarity with REST APIs and webhooks
- ngrok (for exposing local endpoints for testing, optional but recommended)
- Slack account (for notification integration; you can adapt for Discord, Teams, etc.)
Estimated time: 60-90 minutes
-
Set Up Your Development Environment
-
Create and activate a virtual environment:
python3 -m venv workflow-bot-env source workflow-bot-env/bin/activate
-
Install required Python packages:
pip install openai flask slack_sdk python-dotenv
openai– for LLM API calls
flask– lightweight web server for webhooks
slack_sdk– send messages to Slack
python-dotenv– manage environment variables -
Create a
.envfile for your secrets:OPENAI_API_KEY=sk-... SLACK_BOT_TOKEN=xoxb-... SLACK_CHANNEL_ID=C1234567890
-
Create and activate a virtual environment:
-
Design the Approval Workflow Logic
We'll model a multi-step approval: a user submits a request, the LLM reviews it (auto-approves simple cases, flags complex ones), and notifies a human approver in Slack.
-
Define the workflow states:
- Received
- LLM Review
- Auto-Approved / Needs Human Approval
- Final Decision
-
Create a Python class to manage workflow state:
class ApprovalRequest: def __init__(self, user, request_text): self.user = user self.request_text = request_text self.state = "Received" self.llm_decision = None self.final_decision = None
-
Define the workflow states:
-
Integrate the LLM for Automated Review
-
Create a function to call the LLM API:
import os import openai openai.api_key = os.getenv("OPENAI_API_KEY") def llm_review(request_text): prompt = f"""You are an approval bot. Review the following request: "{request_text}" If the request is routine and low-risk, reply with "APPROVE". If it needs human review, reply with "ESCALATE: [reason]". """ response = openai.ChatCompletion.create( model="gpt-4o", messages=[{"role": "system", "content": prompt}], max_tokens=32, temperature=0 ) return response.choices[0].message['content'].strip() -
Test the LLM review function:
if __name__ == "__main__": print(llm_review("Requesting access to the public marketing folder.")) print(llm_review("Requesting deletion of all customer data."))Expected output:
APPROVE(for routine)
ESCALATE: This action is high-risk and requires human approval.(for risky)
-
Create a function to call the LLM API:
-
Build the Python Bot Server (Flask)
-
Set up a Flask app to handle requests:
from flask import Flask, request, jsonify from workflow import ApprovalRequest from llm_review import llm_review import os app = Flask(__name__) requests_db = {} @app.route("/submit", methods=["POST"]) def submit(): data = request.json user = data.get("user") text = data.get("request_text") req = ApprovalRequest(user, text) req.state = "LLM Review" req.llm_decision = llm_review(text) if req.llm_decision.startswith("APPROVE"): req.state = "Auto-Approved" req.final_decision = "Approved" else: req.state = "Needs Human Approval" requests_db[user] = req return jsonify({ "user": user, "state": req.state, "llm_decision": req.llm_decision }) if __name__ == "__main__": app.run(port=5000) -
Start your Flask server:
python app.py
-
Test the endpoint:
curl -X POST http://localhost:5000/submit \ -H "Content-Type: application/json" \ -d '{"user": "alice", "request_text": "Requesting access to the public marketing folder."}'
-
Set up a Flask app to handle requests:
-
Add Slack Notification Integration
-
Set up a Slack bot and get its token + channel ID.
- Create a Slack app → Add
chat:writescope. - Install to your workspace, copy the
SLACK_BOT_TOKENand channel ID.
- Create a Slack app → Add
-
Create a function to send approval requests to Slack:
import os from slack_sdk import WebClient client = WebClient(token=os.getenv("SLACK_BOT_TOKEN")) channel_id = os.getenv("SLACK_CHANNEL_ID") def notify_human_approver(user, request_text, llm_decision): message = ( f"Approval request from {user}:\n" f"> {request_text}\n" f"LLM Decision: {llm_decision}\n" "Please review and reply with 'approve' or 'reject'." ) client.chat_postMessage(channel=channel_id, text=message) -
Update
app.pyto notify Slack when human approval is needed:from slack_notify import notify_human_approver if req.state == "Needs Human Approval": notify_human_approver(user, text, req.llm_decision) -
Test the integration:
Submit a request that should be escalated. You should see a Slack message in your chosen channel.
Screenshot description: A Slack channel showing the bot posting:
Approval request from alice:
> Requesting deletion of all customer data.
LLM Decision: ESCALATE: This action is high-risk and requires human approval.
Please review and reply with 'approve' or 'reject'.
-
Set up a Slack bot and get its token + channel ID.
-
Implement Human Approval Feedback
-
Set up a Slack event webhook for message replies:
- In your Slack app, add an
event subscriptionformessage.channels. - Point the request URL to your local server (use
ngrokif testing locally):
ngrok http 5000
Copy the https URL from ngrok and set it as your Slack event endpoint.
- In your Slack app, add an
-
Add a Flask endpoint to handle Slack events:
@app.route("/slack/events", methods=["POST"]) def slack_events(): data = request.json # Slack URL verification if data.get("type") == "url_verification": return jsonify({"challenge": data["challenge"]}) # Handle approval/rejection event = data.get("event", {}) text = event.get("text", "").lower() user = event.get("user") if "approve" in text or "reject" in text: # Find request for user (simplified for demo) req = requests_db.get(user) if req and req.state == "Needs Human Approval": req.final_decision = "Approved" if "approve" in text else "Rejected" req.state = "Final Decision" return "", 200 -
Test the full loop:
Reply in Slack with "approve" or "reject" to the bot's message. Check the
requests_dbobject in your Python shell to confirm state update.
-
Set up a Slack event webhook for message replies:
-
Persist Workflow State (Optional: SQLite)
For production, persist requests in a database. Here's a minimal SQLite example:
import sqlite3 def init_db(): conn = sqlite3.connect("approvals.db") c = conn.cursor() c.execute(''' CREATE TABLE IF NOT EXISTS requests ( id INTEGER PRIMARY KEY AUTOINCREMENT, user TEXT, request_text TEXT, state TEXT, llm_decision TEXT, final_decision TEXT ) ''') conn.commit() conn.close() def save_request(req): conn = sqlite3.connect("approvals.db") c = conn.cursor() c.execute(''' INSERT INTO requests (user, request_text, state, llm_decision, final_decision) VALUES (?, ?, ?, ?, ?) ''', (req.user, req.request_text, req.state, req.llm_decision, req.final_decision)) conn.commit() conn.close()Call
init_db()at startup andsave_request(req)after each state change.
Common Issues & Troubleshooting
-
OpenAI API errors: Check your
OPENAI_API_KEYand ensure your account has GPT-4o access. Rate limits may apply. -
Slack bot not posting: Ensure the bot is invited to the channel and has
chat:writescope. - Slack events not received: Double-check your ngrok tunnel and Slack event subscription URL. Slack may require public HTTPS.
-
State not updating: In-memory
requests_dbwill reset on server restart. Use a database for persistence. -
Webhook verification: Slack will send a
url_verificationchallenge when you first set up the event endpoint. Your Flask route must handle and echo this challenge.
For more on real-world workflow integration challenges, see 2026’s Most Common AI Workflow Integration Pitfalls—And How to Avoid Them.
Next Steps
- Add user authentication and role-based access to your endpoints.
- Integrate with other platforms (e.g., Microsoft Teams, Discord, or email). See Automating Workflow Alerts and Notifications: Best AI Tools & Integrations for 2026 for ideas.
- Expand LLM logic for multi-step, conditional approvals or dynamic escalation policies.
- Deploy to cloud (e.g., AWS Lambda, Azure Functions, GCP Cloud Run) for reliability and scale.
- Explore open-source workflow APIs and connectors. For options, see Top 10 AI Workflow Automation APIs for Developers in 2026—Open Source, SaaS & Custom Deployments.
This tutorial is just one approach to building flexible, LLM-powered workflow bots in Python. For a deeper dive into integration strategies and the future of AI workflow platforms, check out The Ultimate Guide to AI Workflow Automation Platform Integrations for 2026.