diff --git a/docs/en/enterprise/features/flow-hitl-management.mdx b/docs/en/enterprise/features/flow-hitl-management.mdx new file mode 100644 index 000000000..884dda4ee --- /dev/null +++ b/docs/en/enterprise/features/flow-hitl-management.mdx @@ -0,0 +1,909 @@ +--- +title: "Flow HITL Management" +description: "Enterprise-grade human review for Flows with assignment, SLA management, escalation policies, and dynamic routing" +icon: "users-gear" +mode: "wide" +--- + + +Flow HITL Management features require the `@human_feedback` decorator, available in **CrewAI version 1.8.0 or higher**. These features apply specifically to **Flows**, not Crews. + + +CrewAI Enterprise provides a comprehensive Human-in-the-Loop (HITL) management system for Flows that transforms AI workflows into collaborative human-AI processes. Beyond simple approval gates, the platform offers enterprise-grade controls for assignment, accountability, and compliance. + +## Overview + + + + Review and respond to requests directly in the Enterprise dashboard + + + Route reviews to the right people based on rules and expertise + + + Ensure timely responses with automated escalation policies + + + +## Setting Up Human Review Points in Flows + +Configure human review checkpoints within your Flows using the `@human_feedback` decorator. When execution reaches a review point, the system pauses and displays a "waiting for input" state in the UI. + +```python +from crewai.flow.flow import Flow, start, listen +from crewai.flow.human_feedback import human_feedback, HumanFeedbackResult + +class ContentApprovalFlow(Flow): + @start() + def generate_content(self): + # AI generates content + return "Generated marketing copy for Q1 campaign..." + + @listen(generate_content) + @human_feedback( + message="Please review this content for brand compliance:", + emit=["approved", "rejected", "needs_revision"], + ) + def review_content(self, content): + return content + + @listen("approved") + def publish_content(self, result: HumanFeedbackResult): + print(f"Publishing approved content. Reviewer notes: {result.feedback}") + + @listen("rejected") + def archive_content(self, result: HumanFeedbackResult): + print(f"Content rejected. Reason: {result.feedback}") + + @listen("needs_revision") + def revise_content(self, result: HumanFeedbackResult): + print(f"Revision requested: {result.feedback}") +``` + +For complete implementation details, see the [Human Feedback in Flows](/en/learn/human-feedback-in-flows) guide. + +## Assignment & Routing + +The Enterprise platform provides sophisticated assignment capabilities to ensure reviews reach the right team members. + +### Responder Assignment + +Assign specific team members or groups as responders for different task types: + + + + Go to your Flow settings and select the "Human Review" configuration section. + + + Assign individual users or groups as default responders for review requests. + + + Define fallback responders when primary assignees are unavailable. + + + + + HITL Configuration Settings + + +### Dynamic Routing Rules + +Set up intelligent routing based on flow state, content type, or custom conditions: + +| Rule Type | Description | Example | +|-----------|-------------|---------| +| **Content-Based** | Route based on the content being reviewed | Legal content → Legal team | +| **Priority-Based** | Assign reviewers based on urgency level | High priority → Senior reviewers | +| **State-Based** | Route based on flow state variables | `state.amount > 10000` → Finance director | +| **Round-Robin** | Distribute reviews evenly across team | Balance workload automatically | + + + HITL Routing Rules Configuration + + +### Role-Based Permissions + +Control who can view, respond to, or escalate HITL requests: + + + + Can view HITL requests and their status but cannot respond or take action. + + + Can view and respond to assigned HITL requests with approve/reject decisions. + + + Can view all requests, respond, reassign to other team members, and override decisions. + + + Full access including configuration of routing rules, SLAs, and escalation policies. + + + +## Review Process + +### Review Interface + +The HITL review interface provides a clean, focused experience for reviewers: + +- **Markdown Rendering**: Rich formatting for review content with syntax highlighting +- **Context Panel**: View flow state, execution history, and related information +- **Feedback Input**: Provide detailed feedback and comments with your decision +- **Quick Actions**: One-click approve/reject buttons with optional comments + + + HITL Pending Requests List + + +### Review Modes + +Choose the review approach that fits your workflow: + + + + **Block execution until approval** + + Flow pauses completely until a human provides feedback. Best for critical decisions that must not proceed without review. + + + **Queue items for efficient review** + + Collect multiple review requests and process them in focused sessions. Ideal for high-volume, lower-urgency reviews. + + + +### History & Audit Trail + +Every HITL interaction is tracked with a complete timeline: + +- Decision history (approve/reject/revise) +- Reviewer identity and timestamp +- Feedback and comments provided +- State changes and escalations +- Response time metrics + +## SLA Management & Escalation + +Ensure timely responses with automated SLA tracking and escalation policies. + +### Configuring SLAs + +Set response time expectations for different review types: + +| SLA Level | Response Time | Use Case | +|-----------|---------------|----------| +| **Critical** | 15 minutes | Production incidents, security reviews | +| **High** | 1 hour | Customer-facing content, urgent approvals | +| **Standard** | 4 hours | Regular content review, routine approvals | +| **Low** | 24 hours | Non-blocking reviews, batch processing | + +### Escalation Rules + +Configure automatic escalation when SLAs are at risk: + + + + Send reminder notification to assigned reviewer (e.g., at 50% of SLA time). + + + Escalate to manager or backup reviewer when SLA threshold is reached. + + + Configure fallback behavior if no response after extended period: + - **Auto-approve**: Proceed with execution (for non-critical reviews) + - **Auto-reject**: Fail safely and notify stakeholders + - **Re-route**: Assign to different reviewer or team + + + +### Notifications + +Automated alerts keep stakeholders informed throughout the workflow: + +- **Assignment Notifications**: Alert reviewers when new requests arrive +- **SLA Warnings**: Remind reviewers before deadlines +- **Escalation Alerts**: Notify managers when reviews are escalated +- **Completion Updates**: Inform requesters when reviews are complete + + +**Slack Integration**: Direct Slack notifications for HITL requests coming soon. + + +## Analytics & Monitoring + +Track HITL performance with comprehensive analytics. + +### Performance Dashboard + +Monitor key metrics across your HITL workflows: + + + HITL Metrics Dashboard + + + + + Track percentage of reviews completed within SLA thresholds. + + + Monitor average and median response times by reviewer, team, or flow. + + + Analyze review volume patterns to optimize team capacity. + + + View approval/rejection rates across different review types. + + + +### Individual Metrics + +Track reviewer performance for accountability and workload balancing: + +- Approval/rejection rates by reviewer +- Average response time per reviewer +- Review completion rates +- Escalation frequency + +### Audit & Compliance + +Enterprise-ready audit capabilities for regulatory requirements: + +- Complete decision history with timestamps +- Reviewer identity verification +- Immutable audit logs +- Export capabilities for compliance reporting + +## Common Use Cases + + + + **Use Case**: Internal security questionnaire automation with human validation + + - AI generates responses to security questionnaires + - Security team reviews and validates accuracy + - Approved responses are compiled into final submission + - Full audit trail for compliance + + + + **Use Case**: Marketing content requiring legal/brand review + + - AI generates marketing copy or social media content + - Route to brand team for voice/tone review + - Escalate to legal for compliance-sensitive content + - Automatic publishing upon approval + + + + **Use Case**: Expense reports, contract terms, budget allocations + + - AI pre-processes and categorizes financial requests + - Route based on amount thresholds to appropriate approvers + - Enforce segregation of duties with role-based access + - Maintain complete audit trail for financial compliance + + + + **Use Case**: Regulatory review for sensitive operations + + - AI flags potential compliance issues + - Compliance officers review flagged items + - Escalate to legal counsel as needed + - Generate compliance reports with decision history + + + + **Use Case**: AI output validation before customer delivery + + - AI generates customer-facing content or responses + - QA team samples and reviews output quality + - Feedback loops improve AI performance over time + - Track quality metrics across review cycles + + + +## Custom Webhooks API + +When your Flows pause for human feedback, you can configure webhooks to send request data to your own application. This enables: + +- Building custom approval UIs +- Integrating with internal tools (Jira, ServiceNow, custom dashboards) +- Routing approvals to third-party systems +- Mobile app notifications +- Automated decision systems + +### Configuring Webhooks + + + + Go to your **Deployment** → **Settings** → **Human in the Loop** + + + Click to expand the **Webhooks** configuration + + + Enter your webhook URL (must be HTTPS in production) + + + Click **Save Configuration** to activate + + + +You can configure multiple webhooks. Each active webhook receives all HITL events. + +### Webhook Events + +Your endpoint will receive HTTP POST requests for these events: + +| Event Type | When Triggered | +|------------|----------------| +| `new_request` | A flow pauses and requests human feedback | +| `escalation` | A pending request is escalated due to SLA timeout | + +### Webhook Payload + +All webhooks receive a JSON payload with this structure: + +```json +{ + "event_type": "new_request", + "id": "550e8400-e29b-41d4-a716-446655440000", + "status": "pending", + "flow_id": "flow_abc123", + "flow_class": "ContentReviewFlow", + "method_name": "review_article", + "message": "Please review this article for publication.", + "output": "# Article Title\n\nThis is the content that needs review...", + "emit": ["approve", "reject", "request_changes"], + "default_outcome": null, + "state": { + "article_id": 12345, + "author": "john@example.com", + "category": "technology" + }, + "metadata": { + "priority": "high", + "source": "cms" + }, + "created_at": "2026-01-12T10:30:00Z", + "callback_url": "https://api.crewai.com/crewai_plus/api/v1/human_feedback_requests/550e8400.../respond?token=abc123...", + "response_token": "abc123def456...", + "deployment_id": 12345, + "deployment_name": "Content Review Crew", + "flow_execution_id": "exec_789", + "trace_batch_id": "trace_456", + "organization_id": "org_123", + "assigned_to": { + "id": 42, + "email": "reviewer@company.com", + "name": "Jane Reviewer" + }, + "assigned_at": "2026-01-12T10:30:05Z", + "escalated_at": null, + "sla_target_minutes": 120, + "triggered_by_user_id": 99, + "routing": { + "effective_responders": [ + {"id": 42, "email": "reviewer@company.com", "name": "Jane Reviewer"}, + {"id": 43, "email": "manager@company.com", "name": "Bob Manager"} + ], + "enforce_routing_rules": true + } +} +``` + +### Field Reference + + + + | Field | Type | Description | + |-------|------|-------------| + | `event_type` | string | `"new_request"` or `"escalation"` | + | `id` | UUID | Unique identifier for this request | + | `status` | string | Always `"pending"` for active requests | + | `method_name` | string | The decorated method that requested feedback | + | `message` | string | Human-readable prompt/question for the reviewer | + | `output` | string | Content to review (may contain Markdown) | + | `emit` | array | Valid response options from the decorator | + | `default_outcome` | string | Default outcome if auto-response triggers | + | `state` | object | Flow state at the moment of pause | + | `metadata` | object | Custom metadata from the decorator | + | `created_at` | ISO8601 | When the request was created | + + + + | Field | Type | Description | + |-------|------|-------------| + | `callback_url` | string | **POST to this URL to submit feedback** (token included) | + | `response_token` | string | Single-use auth token (already in callback_url) | + + + + | Field | Type | Description | + |-------|------|-------------| + | `deployment_id` | integer | Deployment identifier | + | `deployment_name` | string | Human-readable deployment name | + | `flow_execution_id` | UUID | Links to the execution trace | + | `organization_id` | UUID | Organization identifier | + | `sla_target_minutes` | integer | Configured SLA target (null if not set) | + | `triggered_by_user_id` | integer | User who kicked off the flow (if known) | + + + + | Field | Type | Description | + |-------|------|-------------| + | `assigned_to` | object | Pre-assigned reviewer (if any) | + | `assigned_at` | ISO8601 | When assignment was made | + | `escalated_at` | ISO8601 | When request was escalated (null if not escalated) | + | `routing.effective_responders` | array | Users configured to respond | + | `routing.enforce_routing_rules` | boolean | Whether only listed responders can respond | + + + +### Responding to Requests + +To submit feedback, **POST to the `callback_url`** included in the webhook payload. + +```http +POST /crewai_plus/api/v1/human_feedback_requests/{id}/respond?token={token} +Content-Type: application/json + +{ + "feedback": "Approved. Great article!", + "source": "my_custom_app" +} +``` + +**The token is already included in `callback_url`**, so you can POST directly: + +```bash +curl -X POST "${callback_url}" \ + -H "Content-Type: application/json" \ + -d '{"feedback": "Approved with minor edits"}' +``` + +#### Parameters + +| Parameter | Required | Description | +|-----------|----------|-------------| +| `feedback` | Yes | Your feedback text (will be passed to the flow) | +| `source` | No | Identifier for your app (shows in history) | + +#### Response Examples + + +```json Success (200 OK) +{ + "status": "accepted", + "request": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "status": "responded", + "feedback": "Approved with minor edits", + "outcome": null, + "responded_at": "2026-01-12T11:45:00Z", + "responded_via": "my_custom_app" + } +} +``` + +```json Already Responded (409 Conflict) +{ + "error": "already_responded", + "message": "Feedback already provided via dashboard at 2026-01-12T11:30:00Z" +} +``` + +```json Invalid Token (401 Unauthorized) +{ + "error": "unauthorized", + "message": "Invalid response token" +} +``` + + +### Security + + +All webhook requests are cryptographically signed using HMAC-SHA256 to ensure authenticity and prevent tampering. + + +#### Webhook Security + +- **HMAC-SHA256 signatures**: Every webhook includes a cryptographic signature +- **Per-webhook secrets**: Each webhook has its own unique signing secret +- **Encrypted at rest**: Signing secrets are encrypted in our database +- **Timestamp verification**: Prevents replay attacks + +#### Response Token Security + +- **Single-use**: Tokens are invalidated after a successful response +- **256-bit entropy**: Tokens use cryptographically secure random generation + +#### Best Practices + +1. **Verify signatures**: Always validate the `X-CrewAI-Signature` header +2. **Check timestamps**: Reject requests older than 5 minutes +3. **Store secrets securely**: Treat signing secrets like passwords +4. **Use HTTPS**: Your webhook endpoint must use TLS in production +5. **Rotate secrets**: Regenerate webhook secrets periodically via the dashboard + +### Example Integrations + + +```python Python (Flask) - Complete Example +from flask import Flask, request, jsonify +import requests +import hmac +import hashlib +import time + +app = Flask(__name__) + +WEBHOOK_SECRET = "whsec_your_signing_secret_here" +MAX_TIMESTAMP_AGE = 300 + +def verify_signature(payload: bytes, signature: str, timestamp: str) -> bool: + try: + ts = int(timestamp) + if abs(time.time() - ts) > MAX_TIMESTAMP_AGE: + return False + except (ValueError, TypeError): + return False + + signature_payload = f"{timestamp}.{payload.decode('utf-8')}" + expected = hmac.new( + WEBHOOK_SECRET.encode('utf-8'), + signature_payload.encode('utf-8'), + hashlib.sha256 + ).hexdigest() + + return hmac.compare_digest(f"sha256={expected}", signature) + +@app.route('/hitl-webhook', methods=['POST']) +def handle_hitl(): + # Verify signature first + signature = request.headers.get('X-CrewAI-Signature', '') + timestamp = request.headers.get('X-CrewAI-Timestamp', '') + + if not verify_signature(request.data, signature, timestamp): + return jsonify({'error': 'Invalid signature'}), 401 + + payload = request.json + + # Store for later review + store_request(payload) + + # Or auto-approve based on rules + if should_auto_approve(payload): + response = requests.post( + payload['callback_url'], + json={'feedback': 'Auto-approved by policy', 'source': 'auto_approver'} + ) + return jsonify({'status': 'auto_approved'}) + + return jsonify({'status': 'queued_for_review'}) +``` + +```javascript Node.js (Express) - Complete Example +const express = require('express'); +const crypto = require('crypto'); +const axios = require('axios'); + +const app = express(); +const WEBHOOK_SECRET = 'whsec_your_signing_secret_here'; +const MAX_TIMESTAMP_AGE = 300; + +// Capture raw body for signature verification +app.use('/hitl-webhook', express.raw({ type: 'application/json' })); + +function verifySignature(payload, signature, timestamp) { + const ts = parseInt(timestamp, 10); + if (isNaN(ts) || Math.abs(Date.now() / 1000 - ts) > MAX_TIMESTAMP_AGE) { + return false; + } + + const signaturePayload = `${timestamp}.${payload.toString()}`; + const expected = crypto + .createHmac('sha256', WEBHOOK_SECRET) + .update(signaturePayload) + .digest('hex'); + + return crypto.timingSafeEqual( + Buffer.from(`sha256=${expected}`), + Buffer.from(signature) + ); +} + +app.post('/hitl-webhook', async (req, res) => { + const signature = req.headers['x-crewai-signature'] || ''; + const timestamp = req.headers['x-crewai-timestamp'] || ''; + + if (!verifySignature(req.body, signature, timestamp)) { + return res.status(401).json({ error: 'Invalid signature' }); + } + + const { event_type, callback_url, message, output } = JSON.parse(req.body); + + console.log(`Received ${event_type}: ${message}`); + + // Notify your team via Slack, email, etc. + await notifyTeam(payload); + + // Later, when someone approves: + // await axios.post(callback_url, { feedback: 'Approved!' }); + + res.json({ received: true }); +}); +``` + + +### Webhook Signature Verification + +All webhook requests are signed using HMAC-SHA256. You should verify the signature to ensure requests are authentic and haven't been tampered with. + +#### Signature Headers + +Each webhook request includes these headers: + +| Header | Description | +|--------|-------------| +| `X-CrewAI-Signature` | HMAC-SHA256 signature: `sha256=` | +| `X-CrewAI-Timestamp` | Unix timestamp when the request was signed | + +#### Verification Algorithm + +The signature is computed as: + +``` +HMAC-SHA256(signing_secret, timestamp + "." + raw_body) +``` + +Where: +- `signing_secret` is your webhook's unique secret (shown in dashboard) +- `timestamp` is the value from `X-CrewAI-Timestamp` header +- `raw_body` is the raw JSON request body (before parsing) + +#### Python Verification Example + +```python +import hmac +import hashlib +import time +from flask import Flask, request, jsonify + +app = Flask(__name__) + +WEBHOOK_SECRET = "whsec_your_signing_secret_here" +MAX_TIMESTAMP_AGE = 300 # 5 minutes + +def verify_signature(payload: bytes, signature: str, timestamp: str) -> bool: + """Verify the webhook signature.""" + # Check timestamp to prevent replay attacks + try: + ts = int(timestamp) + if abs(time.time() - ts) > MAX_TIMESTAMP_AGE: + return False + except (ValueError, TypeError): + return False + + # Compute expected signature + signature_payload = f"{timestamp}.{payload.decode('utf-8')}" + expected = hmac.new( + WEBHOOK_SECRET.encode('utf-8'), + signature_payload.encode('utf-8'), + hashlib.sha256 + ).hexdigest() + + expected_header = f"sha256={expected}" + + # Constant-time comparison to prevent timing attacks + return hmac.compare_digest(expected_header, signature) + +@app.route('/hitl-webhook', methods=['POST']) +def handle_hitl(): + signature = request.headers.get('X-CrewAI-Signature', '') + timestamp = request.headers.get('X-CrewAI-Timestamp', '') + + if not verify_signature(request.data, signature, timestamp): + return jsonify({'error': 'Invalid signature'}), 401 + + payload = request.json + # Process the verified webhook... + return jsonify({'status': 'received'}) +``` + +#### Node.js Verification Example + +```javascript +const express = require('express'); +const crypto = require('crypto'); + +const app = express(); +const WEBHOOK_SECRET = 'whsec_your_signing_secret_here'; +const MAX_TIMESTAMP_AGE = 300; // 5 minutes + +// Use raw body for signature verification +app.use('/hitl-webhook', express.raw({ type: 'application/json' })); + +function verifySignature(payload, signature, timestamp) { + // Check timestamp + const ts = parseInt(timestamp, 10); + if (isNaN(ts) || Math.abs(Date.now() / 1000 - ts) > MAX_TIMESTAMP_AGE) { + return false; + } + + // Compute expected signature + const signaturePayload = `${timestamp}.${payload.toString()}`; + const expected = crypto + .createHmac('sha256', WEBHOOK_SECRET) + .update(signaturePayload) + .digest('hex'); + + const expectedHeader = `sha256=${expected}`; + + // Constant-time comparison + return crypto.timingSafeEqual( + Buffer.from(expectedHeader), + Buffer.from(signature) + ); +} + +app.post('/hitl-webhook', (req, res) => { + const signature = req.headers['x-crewai-signature'] || ''; + const timestamp = req.headers['x-crewai-timestamp'] || ''; + + if (!verifySignature(req.body, signature, timestamp)) { + return res.status(401).json({ error: 'Invalid signature' }); + } + + const payload = JSON.parse(req.body); + // Process the verified webhook... + res.json({ status: 'received' }); +}); +``` + +#### Ruby Verification Example + +```ruby +require 'openssl' +require 'json' + +class HitlWebhookController < ApplicationController + WEBHOOK_SECRET = ENV['CREWAI_WEBHOOK_SECRET'] + MAX_TIMESTAMP_AGE = 300 # 5 minutes + + skip_before_action :verify_authenticity_token + + def receive + signature = request.headers['X-CrewAI-Signature'] + timestamp = request.headers['X-CrewAI-Timestamp'] + payload = request.raw_post + + unless verify_signature(payload, signature, timestamp) + render json: { error: 'Invalid signature' }, status: :unauthorized + return + end + + data = JSON.parse(payload) + # Process the verified webhook... + render json: { status: 'received' } + end + + private + + def verify_signature(payload, signature, timestamp) + return false if timestamp.blank? || signature.blank? + + # Check timestamp freshness + ts = timestamp.to_i + return false if (Time.now.to_i - ts).abs > MAX_TIMESTAMP_AGE + + # Compute expected signature + signature_payload = "#{timestamp}.#{payload}" + expected = OpenSSL::HMAC.hexdigest('SHA256', WEBHOOK_SECRET, signature_payload) + expected_header = "sha256=#{expected}" + + # Constant-time comparison + ActiveSupport::SecurityUtils.secure_compare(expected_header, signature) + end +end +``` + +#### Security Best Practices + +1. **Always verify signatures** before processing webhook data +2. **Check timestamp freshness** (we recommend 5-minute tolerance) +3. **Use constant-time comparison** to prevent timing attacks +4. **Store secrets securely** using environment variables or secret managers +5. **Rotate secrets periodically** (you can regenerate in the dashboard) + +### Error Handling + +Your webhook endpoint should return a 2xx status code to acknowledge receipt: + +| Your Response | Our Behavior | +|---------------|--------------| +| 2xx | Webhook delivered successfully | +| 4xx/5xx | Logged as failed, no retry | +| Timeout (30s) | Logged as failed, no retry | + +### Testing Your Integration + + + + Add a webhook pointing to your dev endpoint + + + For local development, use [ngrok](https://ngrok.com): + ```bash + ngrok http 3000 + # Use the HTTPS URL as your webhook endpoint + ``` + + + Run a flow with a `@human_feedback` decorator + + + Check that your endpoint receives the payload + + + POST to the `callback_url` to complete the flow + + + +## Other Integration Options + +### API Access + +Full programmatic control for custom integrations: + +```python +# Example: Programmatically check HITL status +from crewai.enterprise import HITLClient + +client = HITLClient() +pending_reviews = client.get_pending_reviews(flow_id="my-flow") + +for review in pending_reviews: + print(f"Review {review.id}: {review.status} - Assigned to: {review.assignee}") +``` + +### Coming Soon + +- **Slack Integration**: Respond to HITL requests directly from Slack +- **Microsoft Teams**: Teams-native review experience +- **Mobile App**: Review and approve on the go + +## Best Practices + + +**Start Simple**: Begin with basic approval gates, then add routing and SLAs as your workflows mature. + + +1. **Define Clear Review Criteria**: Document what reviewers should look for to ensure consistent decisions. + +2. **Set Realistic SLAs**: Balance urgency with reviewer capacity to maintain sustainable workflows. + +3. **Use Escalation Wisely**: Reserve auto-approval for truly non-critical reviews to maintain quality. + +4. **Monitor and Iterate**: Use analytics to identify bottlenecks and optimize reviewer assignments. + +5. **Train Your Team**: Ensure reviewers understand their role and the tools available to them. + +## Related Resources + + + + Implementation guide for the `@human_feedback` decorator + + + Step-by-step guide for setting up HITL workflows + + + Configure role-based access control for your organization + + + Set up real-time event notifications + + diff --git a/docs/en/enterprise/guides/human-in-the-loop.mdx b/docs/en/enterprise/guides/human-in-the-loop.mdx index 73ef82a16..00ec01da5 100644 --- a/docs/en/enterprise/guides/human-in-the-loop.mdx +++ b/docs/en/enterprise/guides/human-in-the-loop.mdx @@ -5,9 +5,53 @@ icon: "user-check" mode: "wide" --- -Human-In-The-Loop (HITL) is a powerful approach that combines artificial intelligence with human expertise to enhance decision-making and improve task outcomes. This guide shows you how to implement HITL within CrewAI. +Human-In-The-Loop (HITL) is a powerful approach that combines artificial intelligence with human expertise to enhance decision-making and improve task outcomes. This guide shows you how to implement HITL within CrewAI Enterprise. -## Setting Up HITL Workflows +## HITL Approaches in CrewAI + +CrewAI offers two approaches for implementing human-in-the-loop workflows: + +| Approach | Best For | Version | +|----------|----------|---------| +| **Flow-based** (`@human_feedback` decorator) | Production with Enterprise UI, managed workflows, full platform features | **1.8.0+** | +| **Webhook-based** | Custom integrations, external systems (Slack, Teams, etc.), legacy setups | All versions | + +## Flow-Based HITL with Enterprise Platform + + +The `@human_feedback` decorator requires **CrewAI version 1.8.0 or higher**. + + +When using the `@human_feedback` decorator in your Flows, CrewAI Enterprise provides a dedicated **HITL Management UI** that gives you full control over human feedback workflows: + + + + Review and respond to HITL requests directly within the Enterprise dashboard—no webhook setup required. + + + Assign specific team members or groups as responders for different task types or crews. + + + Define who can view, respond to, or escalate HITL requests with granular permission controls. + + + Configure automatic escalation rules when responses are delayed or require senior review. + + + Set Service Level Agreements for response times with automatic notifications and tracking. + + + Route HITL requests based on content, priority, or custom rules with enforcement policies. + + + + +For implementation details on the `@human_feedback` decorator, see the [Human Feedback in Flows](/en/learn/human-feedback-in-flows) guide. + + +## Setting Up Webhook-Based HITL Workflows + +For custom integrations with external systems like Slack, Microsoft Teams, or your own applications, you can use the webhook-based approach: @@ -99,3 +143,14 @@ HITL workflows are particularly valuable for: - Sensitive or high-stakes operations - Creative tasks requiring human judgment - Compliance and regulatory reviews + +## Learn More + + + + Explore the full Enterprise Flow HITL platform capabilities including assignment, SLA management, escalation policies, and analytics. + + + Implementation guide for the `@human_feedback` decorator in your Flows. + + diff --git a/docs/en/learn/human-in-the-loop.mdx b/docs/en/learn/human-in-the-loop.mdx index 02e327045..c9e8ba57d 100644 --- a/docs/en/learn/human-in-the-loop.mdx +++ b/docs/en/learn/human-in-the-loop.mdx @@ -151,3 +151,9 @@ HITL workflows are particularly valuable for: - Sensitive or high-stakes operations - Creative tasks requiring human judgment - Compliance and regulatory reviews + +## Enterprise Features + + + CrewAI Enterprise provides a comprehensive HITL management system for Flows with in-platform review, responder assignment, permissions, escalation policies, SLA management, dynamic routing, and full analytics. [Learn more →](/en/enterprise/features/flow-hitl-management) + diff --git a/docs/images/enterprise/hitl-list-pending-feedbacks.png b/docs/images/enterprise/hitl-list-pending-feedbacks.png new file mode 100644 index 000000000..223bcafd1 Binary files /dev/null and b/docs/images/enterprise/hitl-list-pending-feedbacks.png differ diff --git a/docs/images/enterprise/hitl-metrics.png b/docs/images/enterprise/hitl-metrics.png new file mode 100644 index 000000000..92e8a9102 Binary files /dev/null and b/docs/images/enterprise/hitl-metrics.png differ diff --git a/docs/images/enterprise/hitl-settings-1.png b/docs/images/enterprise/hitl-settings-1.png new file mode 100644 index 000000000..daf90b949 Binary files /dev/null and b/docs/images/enterprise/hitl-settings-1.png differ diff --git a/docs/images/enterprise/hitl-settings-2.png b/docs/images/enterprise/hitl-settings-2.png new file mode 100644 index 000000000..adf2aa3a9 Binary files /dev/null and b/docs/images/enterprise/hitl-settings-2.png differ diff --git a/docs/ko/enterprise/features/flow-hitl-management.mdx b/docs/ko/enterprise/features/flow-hitl-management.mdx new file mode 100644 index 000000000..9ebf19a35 --- /dev/null +++ b/docs/ko/enterprise/features/flow-hitl-management.mdx @@ -0,0 +1,910 @@ +--- +title: "Flow HITL 관리" +description: "할당, SLA 관리, 에스컬레이션 정책 및 동적 라우팅을 갖춘 Flow용 엔터프라이즈급 인간 검토" +icon: "users-gear" +mode: "wide" +--- + + +Flow HITL 관리 기능은 `@human_feedback` 데코레이터가 필요하며, **CrewAI 버전 1.8.0 이상**에서 사용할 수 있습니다. 이 기능은 Crew가 아닌 **Flow**에만 적용됩니다. + + +CrewAI Enterprise는 AI 워크플로우를 협업적인 인간-AI 프로세스로 전환하는 Flow용 포괄적인 Human-in-the-Loop(HITL) 관리 시스템을 제공합니다. 단순한 승인 게이트를 넘어, 플랫폼은 할당, 책임, 규정 준수를 위한 엔터프라이즈급 제어를 제공합니다. + +## 개요 + + + + Enterprise 대시보드에서 직접 요청을 검토하고 응답 + + + 규칙과 전문성에 따라 적합한 담당자에게 검토 라우팅 + + + 자동화된 에스컬레이션 정책으로 적시 응답 보장 + + + +## Flow에서 인간 검토 포인트 설정 + +`@human_feedback` 데코레이터를 사용하여 Flow 내에 인간 검토 체크포인트를 구성합니다. 실행이 검토 포인트에 도달하면 시스템이 일시 중지되고 UI에 "입력 대기 중" 상태가 표시됩니다. + +```python +from crewai.flow.flow import Flow, start, listen +from crewai.flow.human_feedback import human_feedback, HumanFeedbackResult + +class ContentApprovalFlow(Flow): + @start() + def generate_content(self): + # AI가 콘텐츠 생성 + return "Q1 캠페인용 마케팅 카피 생성..." + + @listen(generate_content) + @human_feedback( + message="브랜드 준수를 위해 이 콘텐츠를 검토해 주세요:", + emit=["approved", "rejected", "needs_revision"], + ) + def review_content(self, content): + return content + + @listen("approved") + def publish_content(self, result: HumanFeedbackResult): + print(f"승인된 콘텐츠 게시 중. 검토자 노트: {result.feedback}") + + @listen("rejected") + def archive_content(self, result: HumanFeedbackResult): + print(f"콘텐츠 거부됨. 사유: {result.feedback}") + + @listen("needs_revision") + def revise_content(self, result: HumanFeedbackResult): + print(f"수정 요청: {result.feedback}") +``` + +완전한 구현 세부 사항은 [Flow에서 인간 피드백](/ko/learn/human-feedback-in-flows) 가이드를 참조하세요. + +## 할당 및 라우팅 + +Enterprise 플랫폼은 검토가 적합한 팀원에게 전달되도록 정교한 할당 기능을 제공합니다. + +### 응답자 할당 + +다양한 작업 유형에 대해 특정 팀원 또는 그룹을 응답자로 할당합니다: + + + + Flow 설정으로 이동하여 "인간 검토" 구성 섹션을 선택합니다. + + + 검토 요청에 대한 기본 응답자로 개별 사용자 또는 그룹을 할당합니다. + + + 주 담당자가 부재 시 대체 응답자를 정의합니다. + + + + + HITL 구성 설정 + + +### 동적 라우팅 규칙 + +Flow 상태, 콘텐츠 유형 또는 사용자 정의 조건에 따라 지능형 라우팅을 설정합니다: + +| 규칙 유형 | 설명 | 예시 | +|-----------|------|------| +| **콘텐츠 기반** | 검토 대상 콘텐츠에 따라 라우팅 | 법률 콘텐츠 → 법무팀 | +| **우선순위 기반** | 긴급도에 따라 검토자 할당 | 높은 우선순위 → 시니어 검토자 | +| **상태 기반** | Flow 상태 변수에 따라 라우팅 | `state.amount > 10000` → 재무 이사 | +| **라운드 로빈** | 팀 전체에 검토를 균등 분배 | 워크로드 자동 균형 | + + + HITL 라우팅 규칙 구성 + + +### 역할 기반 권한 + +HITL 요청을 보거나, 응답하거나, 에스컬레이션할 수 있는 사람을 제어합니다: + + + + HITL 요청과 상태를 볼 수 있지만 응답하거나 조치를 취할 수 없습니다. + + + 할당된 HITL 요청을 보고 승인/거부 결정으로 응답할 수 있습니다. + + + 모든 요청을 보고, 응답하고, 다른 팀원에게 재할당하고, 결정을 재정의할 수 있습니다. + + + 라우팅 규칙, SLA 및 에스컬레이션 정책 구성을 포함한 전체 접근 권한. + + + +## 검토 프로세스 + +### 검토 인터페이스 + +HITL 검토 인터페이스는 검토자에게 깔끔하고 집중된 경험을 제공합니다: + +- **마크다운 렌더링**: 구문 강조가 포함된 풍부한 형식의 검토 콘텐츠 +- **컨텍스트 패널**: Flow 상태, 실행 기록 및 관련 정보 보기 +- **피드백 입력**: 결정과 함께 상세한 피드백 및 코멘트 제공 +- **빠른 작업**: 선택적 코멘트가 있는 원클릭 승인/거부 버튼 + + + HITL 대기 중인 요청 목록 + + +### 검토 모드 + +워크플로우에 맞는 검토 방식을 선택합니다: + + + + **승인까지 실행 차단** + + 인간이 피드백을 제공할 때까지 Flow가 완전히 일시 중지됩니다. 검토 없이 진행해서는 안 되는 중요한 결정에 적합합니다. + + + **효율적인 검토를 위해 항목 대기열에 추가** + + 여러 검토 요청을 수집하고 집중 세션에서 처리합니다. 대량이지만 긴급도가 낮은 검토에 이상적입니다. + + + +### 기록 및 감사 추적 + +모든 HITL 상호작용은 완전한 타임라인으로 추적됩니다: + +- 결정 기록 (승인/거부/수정) +- 검토자 신원 및 타임스탬프 +- 제공된 피드백 및 코멘트 +- 상태 변경 및 에스컬레이션 +- 응답 시간 메트릭 + +## SLA 관리 및 에스컬레이션 + +자동화된 SLA 추적 및 에스컬레이션 정책으로 적시 응답을 보장합니다. + +### SLA 구성 + +다양한 검토 유형에 대한 응답 시간 기대치를 설정합니다: + +| SLA 레벨 | 응답 시간 | 사용 사례 | +|----------|----------|----------| +| **긴급** | 15분 | 프로덕션 인시던트, 보안 검토 | +| **높음** | 1시간 | 고객 대면 콘텐츠, 긴급 승인 | +| **표준** | 4시간 | 일반 콘텐츠 검토, 일상적인 승인 | +| **낮음** | 24시간 | 비차단 검토, 배치 처리 | + +### 에스컬레이션 규칙 + +SLA가 위험에 처할 때 자동 에스컬레이션을 구성합니다: + + + + 할당된 검토자에게 알림 전송 (예: SLA 시간의 50% 도달 시). + + + SLA 임계값에 도달하면 관리자 또는 백업 검토자에게 에스컬레이션. + + + 연장된 기간 후에도 응답이 없을 경우 대체 동작 구성: + - **자동 승인**: 실행 진행 (중요하지 않은 검토의 경우) + - **자동 거부**: 안전하게 실패하고 이해관계자에게 알림 + - **재라우팅**: 다른 검토자 또는 팀에 할당 + + + +### 알림 + +자동화된 알림이 워크플로우 전반에 걸쳐 이해관계자에게 정보를 제공합니다: + +- **할당 알림**: 새 요청이 도착하면 검토자에게 알림 +- **SLA 경고**: 마감 전 검토자에게 리마인더 +- **에스컬레이션 알림**: 검토가 에스컬레이션되면 관리자에게 알림 +- **완료 업데이트**: 검토가 완료되면 요청자에게 알림 + + +**Slack 통합**: HITL 요청에 대한 직접 Slack 알림이 곧 제공됩니다. + + +## 분석 및 모니터링 + +포괄적인 분석으로 HITL 성능을 추적합니다. + +### 성능 대시보드 + +HITL 워크플로우 전반의 주요 메트릭을 모니터링합니다: + + + HITL 메트릭 대시보드 + + + + + SLA 임계값 내에 완료된 검토 비율 추적. + + + 검토자, 팀 또는 Flow별 평균 및 중앙값 응답 시간 모니터링. + + + 팀 용량 최적화를 위한 검토 볼륨 패턴 분석. + + + 다양한 검토 유형에 대한 승인/거부 비율 보기. + + + +### 개별 메트릭 + +책임 추적 및 워크로드 균형을 위한 검토자 성과 추적: + +- 검토자별 승인/거부 비율 +- 검토자별 평균 응답 시간 +- 검토 완료율 +- 에스컬레이션 빈도 + +### 감사 및 규정 준수 + +규제 요구 사항을 위한 엔터프라이즈급 감사 기능: + +- 타임스탬프가 있는 완전한 결정 기록 +- 검토자 신원 확인 +- 불변 감사 로그 +- 규정 준수 보고를 위한 내보내기 기능 + +## 일반적인 사용 사례 + + + + **사용 사례**: 인간 검증이 포함된 내부 보안 설문지 자동화 + + - AI가 보안 설문지에 대한 응답 생성 + - 보안팀이 정확성 검토 및 검증 + - 승인된 응답이 최종 제출물로 편집 + - 규정 준수를 위한 완전한 감사 추적 + + + + **사용 사례**: 법무/브랜드 검토가 필요한 마케팅 콘텐츠 + + - AI가 마케팅 카피 또는 소셜 미디어 콘텐츠 생성 + - 브랜드팀에 목소리/톤 검토를 위해 라우팅 + - 규정 준수에 민감한 콘텐츠는 법무팀으로 에스컬레이션 + - 승인 시 자동 게시 + + + + **사용 사례**: 경비 보고서, 계약 조건, 예산 배분 + + - AI가 재무 요청을 사전 처리하고 분류 + - 금액 임계값에 따라 적절한 승인자에게 라우팅 + - 역할 기반 접근으로 직무 분리 시행 + - 재무 규정 준수를 위한 완전한 감사 추적 유지 + + + + **사용 사례**: 민감한 작업에 대한 규제 검토 + + - AI가 잠재적 규정 준수 문제 플래그 + - 규정 준수 담당자가 플래그된 항목 검토 + - 필요에 따라 법률 고문에게 에스컬레이션 + - 결정 기록이 포함된 규정 준수 보고서 생성 + + + + **사용 사례**: 고객 전달 전 AI 출력 검증 + + - AI가 고객 대면 콘텐츠 또는 응답 생성 + - QA팀이 출력 품질 샘플링 및 검토 + - 피드백 루프가 시간이 지남에 따라 AI 성능 개선 + - 검토 주기 전반의 품질 메트릭 추적 + + + +## 커스텀 Webhook API + +Flow가 인간 피드백을 위해 일시 중지되면, 요청 데이터를 자체 애플리케이션으로 보내도록 webhook을 구성할 수 있습니다. 이를 통해 다음이 가능합니다: + +- 커스텀 승인 UI 구축 +- 내부 도구와 통합 (Jira, ServiceNow, 커스텀 대시보드) +- 타사 시스템으로 승인 라우팅 +- 모바일 앱 알림 +- 자동화된 결정 시스템 + +### Webhook 구성 + + + + **배포** → **설정** → **Human in the Loop**으로 이동 + + + **Webhooks** 구성을 클릭하여 확장 + + + webhook URL 입력 (프로덕션에서는 HTTPS 필수) + + + **구성 저장**을 클릭하여 활성화 + + + +여러 webhook을 구성할 수 있습니다. 각 활성 webhook은 모든 HITL 이벤트를 수신합니다. + +### Webhook 이벤트 + +엔드포인트는 다음 이벤트에 대해 HTTP POST 요청을 수신합니다: + +| 이벤트 유형 | 트리거 시점 | +|------------|------------| +| `new_request` | Flow가 일시 중지되고 인간 피드백을 요청할 때 | +| `escalation` | SLA 타임아웃으로 인해 대기 중인 요청이 에스컬레이션될 때 | + +### Webhook 페이로드 + +모든 webhook은 다음 구조의 JSON 페이로드를 수신합니다: + +```json +{ + "event_type": "new_request", + "id": "550e8400-e29b-41d4-a716-446655440000", + "status": "pending", + "flow_id": "flow_abc123", + "flow_class": "ContentReviewFlow", + "method_name": "review_article", + "message": "이 기사의 게시를 검토해 주세요.", + "output": "# 기사 제목\n\n검토가 필요한 콘텐츠입니다...", + "emit": ["approve", "reject", "request_changes"], + "default_outcome": null, + "state": { + "article_id": 12345, + "author": "john@example.com", + "category": "technology" + }, + "metadata": { + "priority": "high", + "source": "cms" + }, + "created_at": "2026-01-12T10:30:00Z", + "callback_url": "https://api.crewai.com/crewai_plus/api/v1/human_feedback_requests/550e8400.../respond?token=abc123...", + "response_token": "abc123def456...", + "deployment_id": 12345, + "deployment_name": "Content Review Crew", + "flow_execution_id": "exec_789", + "trace_batch_id": "trace_456", + "organization_id": "org_123", + "assigned_to": { + "id": 42, + "email": "reviewer@company.com", + "name": "Jane Reviewer" + }, + "assigned_at": "2026-01-12T10:30:05Z", + "escalated_at": null, + "sla_target_minutes": 120, + "triggered_by_user_id": 99, + "routing": { + "effective_responders": [ + {"id": 42, "email": "reviewer@company.com", "name": "Jane Reviewer"}, + {"id": 43, "email": "manager@company.com", "name": "Bob Manager"} + ], + "enforce_routing_rules": true + } +} +``` + +### 필드 참조 + + + + | 필드 | 유형 | 설명 | + |------|------|------| + | `event_type` | string | `"new_request"` 또는 `"escalation"` | + | `id` | UUID | 이 요청의 고유 식별자 | + | `status` | string | 활성 요청의 경우 항상 `"pending"` | + | `method_name` | string | 피드백을 요청한 데코레이터 메서드 | + | `message` | string | 검토자를 위한 사람이 읽을 수 있는 프롬프트/질문 | + | `output` | string | 검토할 콘텐츠 (Markdown 포함 가능) | + | `emit` | array | 데코레이터의 유효한 응답 옵션 | + | `default_outcome` | string | 자동 응답 트리거 시 기본 결과 | + | `state` | object | 일시 중지 시점의 Flow 상태 | + | `metadata` | object | 데코레이터의 커스텀 메타데이터 | + | `created_at` | ISO8601 | 요청 생성 시간 | + + + + | 필드 | 유형 | 설명 | + |------|------|------| + | `callback_url` | string | **피드백 제출을 위해 이 URL로 POST** (토큰 포함) | + | `response_token` | string | 일회용 인증 토큰 (이미 callback_url에 포함) | + + + + | 필드 | 유형 | 설명 | + |------|------|------| + | `deployment_id` | integer | 배포 식별자 | + | `deployment_name` | string | 사람이 읽을 수 있는 배포 이름 | + | `flow_execution_id` | UUID | 실행 트레이스에 연결 | + | `organization_id` | UUID | 조직 식별자 | + | `sla_target_minutes` | integer | 구성된 SLA 목표 (설정되지 않은 경우 null) | + | `triggered_by_user_id` | integer | Flow를 시작한 사용자 (알려진 경우) | + + + + | 필드 | 유형 | 설명 | + |------|------|------| + | `assigned_to` | object | 사전 할당된 검토자 (있는 경우) | + | `assigned_at` | ISO8601 | 할당된 시간 | + | `escalated_at` | ISO8601 | 요청이 에스컬레이션된 시간 (아닌 경우 null) | + | `routing.effective_responders` | array | 응답하도록 구성된 사용자 | + | `routing.enforce_routing_rules` | boolean | 나열된 응답자만 응답할 수 있는지 여부 | + + + +### 요청에 응답하기 + +피드백을 제출하려면 webhook 페이로드에 포함된 **`callback_url`로 POST**합니다. + +```http +POST /crewai_plus/api/v1/human_feedback_requests/{id}/respond?token={token} +Content-Type: application/json + +{ + "feedback": "승인됨. 훌륭한 기사입니다!", + "source": "my_custom_app" +} +``` + +**토큰은 이미 `callback_url`에 포함되어 있으므로** 직접 POST할 수 있습니다: + +```bash +curl -X POST "${callback_url}" \ + -H "Content-Type: application/json" \ + -d '{"feedback": "약간의 수정과 함께 승인됨"}' +``` + +#### 파라미터 + +| 파라미터 | 필수 | 설명 | +|---------|------|------| +| `feedback` | 예 | 피드백 텍스트 (flow로 전달됨) | +| `source` | 아니오 | 앱 식별자 (기록에 표시) | + +#### 응답 예시 + + +```json 성공 (200 OK) +{ + "status": "accepted", + "request": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "status": "responded", + "feedback": "약간의 수정과 함께 승인됨", + "outcome": null, + "responded_at": "2026-01-12T11:45:00Z", + "responded_via": "my_custom_app" + } +} +``` + +```json 이미 응답됨 (409 Conflict) +{ + "error": "already_responded", + "message": "2026-01-12T11:30:00Z에 대시보드를 통해 이미 피드백이 제공되었습니다" +} +``` + +```json 유효하지 않은 토큰 (401 Unauthorized) +{ + "error": "unauthorized", + "message": "유효하지 않은 응답 토큰" +} +``` + + +### 보안 + + +모든 webhook 요청은 HMAC-SHA256을 사용하여 암호화 서명되어 진위성을 보장하고 변조를 방지합니다. + + +#### Webhook 보안 + +- **HMAC-SHA256 서명**: 모든 webhook에 암호화 서명이 포함됨 +- **Webhook별 시크릿**: 각 webhook은 고유한 서명 시크릿을 가짐 +- **저장 시 암호화**: 서명 시크릿은 데이터베이스에서 암호화됨 +- **타임스탬프 검증**: 리플레이 공격 방지 + +#### 응답 토큰 보안 + +- **일회용**: 토큰은 성공적인 응답 후 무효화됨 +- **256비트 엔트로피**: 토큰은 암호학적으로 안전한 랜덤 생성 사용 +- **타이밍 안전 비교**: 타이밍 공격 방지 + +#### 모범 사례 + +1. **서명 검증**: 항상 `X-CrewAI-Signature` 헤더를 검증하세요 +2. **타임스탬프 확인**: 5분 이상 된 요청은 거부하세요 +3. **시크릿 안전 저장**: 서명 시크릿을 비밀번호처럼 취급하세요 +4. **HTTPS 사용**: 프로덕션에서 webhook 엔드포인트는 TLS를 사용해야 합니다 +5. **시크릿 순환**: 대시보드를 통해 주기적으로 webhook 시크릿을 재생성하세요 + +### 통합 예제 + + +```python Python (Flask) - 전체 예제 +from flask import Flask, request, jsonify +import requests +import hmac +import hashlib +import time + +app = Flask(__name__) + +WEBHOOK_SECRET = "whsec_your_signing_secret_here" +MAX_TIMESTAMP_AGE = 300 + +def verify_signature(payload: bytes, signature: str, timestamp: str) -> bool: + try: + ts = int(timestamp) + if abs(time.time() - ts) > MAX_TIMESTAMP_AGE: + return False + except (ValueError, TypeError): + return False + + signature_payload = f"{timestamp}.{payload.decode('utf-8')}" + expected = hmac.new( + WEBHOOK_SECRET.encode('utf-8'), + signature_payload.encode('utf-8'), + hashlib.sha256 + ).hexdigest() + + return hmac.compare_digest(f"sha256={expected}", signature) + +@app.route('/hitl-webhook', methods=['POST']) +def handle_hitl(): + # 먼저 서명 검증 + signature = request.headers.get('X-CrewAI-Signature', '') + timestamp = request.headers.get('X-CrewAI-Timestamp', '') + + if not verify_signature(request.data, signature, timestamp): + return jsonify({'error': '유효하지 않은 서명'}), 401 + + payload = request.json + + # 나중에 검토하기 위해 저장 + store_request(payload) + + # 또는 규칙에 따라 자동 승인 + if should_auto_approve(payload): + response = requests.post( + payload['callback_url'], + json={'feedback': '정책에 의해 자동 승인됨', 'source': 'auto_approver'} + ) + return jsonify({'status': 'auto_approved'}) + + return jsonify({'status': 'queued_for_review'}) +``` + +```javascript Node.js (Express) - 전체 예제 +const express = require('express'); +const crypto = require('crypto'); +const axios = require('axios'); + +const app = express(); +const WEBHOOK_SECRET = 'whsec_your_signing_secret_here'; +const MAX_TIMESTAMP_AGE = 300; + +// 서명 검증을 위해 raw body 캡처 +app.use('/hitl-webhook', express.raw({ type: 'application/json' })); + +function verifySignature(payload, signature, timestamp) { + const ts = parseInt(timestamp, 10); + if (isNaN(ts) || Math.abs(Date.now() / 1000 - ts) > MAX_TIMESTAMP_AGE) { + return false; + } + + const signaturePayload = `${timestamp}.${payload.toString()}`; + const expected = crypto + .createHmac('sha256', WEBHOOK_SECRET) + .update(signaturePayload) + .digest('hex'); + + return crypto.timingSafeEqual( + Buffer.from(`sha256=${expected}`), + Buffer.from(signature) + ); +} + +app.post('/hitl-webhook', async (req, res) => { + const signature = req.headers['x-crewai-signature'] || ''; + const timestamp = req.headers['x-crewai-timestamp'] || ''; + + if (!verifySignature(req.body, signature, timestamp)) { + return res.status(401).json({ error: '유효하지 않은 서명' }); + } + + const { event_type, callback_url, message, output } = JSON.parse(req.body); + + console.log(`수신됨 ${event_type}: ${message}`); + + // Slack, 이메일 등을 통해 팀에 알림 + await notifyTeam(payload); + + // 나중에 누군가가 승인할 때: + // await axios.post(callback_url, { feedback: '승인됨!' }); + + res.json({ received: true }); +}); +``` + + +### Webhook 서명 검증 + +모든 webhook 요청은 HMAC-SHA256을 사용하여 서명됩니다. 요청이 진본이고 변조되지 않았음을 확인하기 위해 서명을 검증해야 합니다. + +#### 서명 헤더 + +각 webhook 요청에는 다음 헤더가 포함됩니다: + +| 헤더 | 설명 | +|------|------| +| `X-CrewAI-Signature` | HMAC-SHA256 서명: `sha256=` | +| `X-CrewAI-Timestamp` | 요청이 서명된 Unix 타임스탬프 | + +#### 검증 알고리즘 + +서명은 다음과 같이 계산됩니다: + +``` +HMAC-SHA256(signing_secret, timestamp + "." + raw_body) +``` + +여기서: +- `signing_secret`은 webhook의 고유 시크릿입니다 (대시보드에 표시) +- `timestamp`는 `X-CrewAI-Timestamp` 헤더의 값입니다 +- `raw_body`는 원시 JSON 요청 본문입니다 (파싱 전) + +#### Python 검증 예제 + +```python +import hmac +import hashlib +import time +from flask import Flask, request, jsonify + +app = Flask(__name__) + +WEBHOOK_SECRET = "whsec_your_signing_secret_here" +MAX_TIMESTAMP_AGE = 300 # 5분 + +def verify_signature(payload: bytes, signature: str, timestamp: str) -> bool: + """Webhook 서명을 검증합니다.""" + # 리플레이 공격 방지를 위한 타임스탬프 확인 + try: + ts = int(timestamp) + if abs(time.time() - ts) > MAX_TIMESTAMP_AGE: + return False + except (ValueError, TypeError): + return False + + # 예상 서명 계산 + signature_payload = f"{timestamp}.{payload.decode('utf-8')}" + expected = hmac.new( + WEBHOOK_SECRET.encode('utf-8'), + signature_payload.encode('utf-8'), + hashlib.sha256 + ).hexdigest() + + expected_header = f"sha256={expected}" + + # 타이밍 공격 방지를 위한 상수 시간 비교 + return hmac.compare_digest(expected_header, signature) + +@app.route('/hitl-webhook', methods=['POST']) +def handle_hitl(): + signature = request.headers.get('X-CrewAI-Signature', '') + timestamp = request.headers.get('X-CrewAI-Timestamp', '') + + if not verify_signature(request.data, signature, timestamp): + return jsonify({'error': '유효하지 않은 서명'}), 401 + + payload = request.json + # 검증된 webhook 처리... + return jsonify({'status': 'received'}) +``` + +#### Node.js 검증 예제 + +```javascript +const express = require('express'); +const crypto = require('crypto'); + +const app = express(); +const WEBHOOK_SECRET = 'whsec_your_signing_secret_here'; +const MAX_TIMESTAMP_AGE = 300; // 5분 + +// 서명 검증을 위해 raw body 사용 +app.use('/hitl-webhook', express.raw({ type: 'application/json' })); + +function verifySignature(payload, signature, timestamp) { + // 타임스탬프 확인 + const ts = parseInt(timestamp, 10); + if (isNaN(ts) || Math.abs(Date.now() / 1000 - ts) > MAX_TIMESTAMP_AGE) { + return false; + } + + // 예상 서명 계산 + const signaturePayload = `${timestamp}.${payload.toString()}`; + const expected = crypto + .createHmac('sha256', WEBHOOK_SECRET) + .update(signaturePayload) + .digest('hex'); + + const expectedHeader = `sha256=${expected}`; + + // 상수 시간 비교 + return crypto.timingSafeEqual( + Buffer.from(expectedHeader), + Buffer.from(signature) + ); +} + +app.post('/hitl-webhook', (req, res) => { + const signature = req.headers['x-crewai-signature'] || ''; + const timestamp = req.headers['x-crewai-timestamp'] || ''; + + if (!verifySignature(req.body, signature, timestamp)) { + return res.status(401).json({ error: '유효하지 않은 서명' }); + } + + const payload = JSON.parse(req.body); + // 검증된 webhook 처리... + res.json({ status: 'received' }); +}); +``` + +#### Ruby 검증 예제 + +```ruby +require 'openssl' +require 'json' + +class HitlWebhookController < ApplicationController + WEBHOOK_SECRET = ENV['CREWAI_WEBHOOK_SECRET'] + MAX_TIMESTAMP_AGE = 300 # 5분 + + skip_before_action :verify_authenticity_token + + def receive + signature = request.headers['X-CrewAI-Signature'] + timestamp = request.headers['X-CrewAI-Timestamp'] + payload = request.raw_post + + unless verify_signature(payload, signature, timestamp) + render json: { error: '유효하지 않은 서명' }, status: :unauthorized + return + end + + data = JSON.parse(payload) + # 검증된 webhook 처리... + render json: { status: 'received' } + end + + private + + def verify_signature(payload, signature, timestamp) + return false if timestamp.blank? || signature.blank? + + # 타임스탬프 최신성 확인 + ts = timestamp.to_i + return false if (Time.now.to_i - ts).abs > MAX_TIMESTAMP_AGE + + # 예상 서명 계산 + signature_payload = "#{timestamp}.#{payload}" + expected = OpenSSL::HMAC.hexdigest('SHA256', WEBHOOK_SECRET, signature_payload) + expected_header = "sha256=#{expected}" + + # 상수 시간 비교 + ActiveSupport::SecurityUtils.secure_compare(expected_header, signature) + end +end +``` + +#### 보안 모범 사례 + +1. **항상 서명 검증** webhook 데이터 처리 전에 서명을 검증하세요 +2. **타임스탬프 최신성 확인** (5분 허용 오차 권장) +3. **상수 시간 비교 사용** 타이밍 공격을 방지합니다 +4. **시크릿 안전 저장** 환경 변수나 시크릿 매니저를 사용하세요 +5. **주기적 시크릿 순환** (대시보드에서 재생성 가능) + +### 오류 처리 + +webhook 엔드포인트는 수신 확인을 위해 2xx 상태 코드를 반환해야 합니다: + +| 응답 | 동작 | +|------|------| +| 2xx | Webhook 성공적으로 전달됨 | +| 4xx/5xx | 실패로 기록됨, 재시도 없음 | +| 타임아웃 (30초) | 실패로 기록됨, 재시도 없음 | + +### 통합 테스트 + + + + 개발 엔드포인트를 가리키는 webhook 추가 + + + 로컬 개발의 경우 [ngrok](https://ngrok.com) 사용: + ```bash + ngrok http 3000 + # HTTPS URL을 webhook 엔드포인트로 사용 + ``` + + + `@human_feedback` 데코레이터가 있는 flow 실행 + + + 엔드포인트가 페이로드를 수신하는지 확인 + + + `callback_url`로 POST하여 flow 완료 + + + +## 기타 통합 옵션 + +### API 접근 + +커스텀 통합을 위한 완전한 프로그래밍 제어: + +```python +# 예: 프로그래밍 방식으로 HITL 상태 확인 +from crewai.enterprise import HITLClient + +client = HITLClient() +pending_reviews = client.get_pending_reviews(flow_id="my-flow") + +for review in pending_reviews: + print(f"검토 {review.id}: {review.status} - 할당된 사람: {review.assignee}") +``` + +### 곧 출시 예정 + +- **Slack 통합**: Slack에서 직접 HITL 요청에 응답 +- **Microsoft Teams**: Teams 네이티브 검토 경험 +- **모바일 앱**: 이동 중 검토 및 승인 + +## 모범 사례 + + +**간단하게 시작**: 기본 승인 게이트로 시작한 다음, 워크플로우가 성숙해지면 라우팅과 SLA를 추가하세요. + + +1. **명확한 검토 기준 정의**: 일관된 결정을 보장하기 위해 검토자가 무엇을 확인해야 하는지 문서화하세요. + +2. **현실적인 SLA 설정**: 지속 가능한 워크플로우를 유지하기 위해 긴급도와 검토자 용량의 균형을 맞추세요. + +3. **에스컬레이션을 현명하게 사용**: 품질을 유지하기 위해 진정으로 중요하지 않은 검토에만 자동 승인을 사용하세요. + +4. **모니터링 및 반복**: 분석을 사용하여 병목 현상을 식별하고 검토자 할당을 최적화하세요. + +5. **팀 교육**: 검토자가 자신의 역할과 사용 가능한 도구를 이해하도록 하세요. + +## 관련 리소스 + + + + `@human_feedback` 데코레이터 구현 가이드 + + + HITL 워크플로우 설정을 위한 단계별 가이드 + + + 조직을 위한 역할 기반 접근 제어 구성 + + + 실시간 이벤트 알림 설정 + + diff --git a/docs/ko/enterprise/guides/human-in-the-loop.mdx b/docs/ko/enterprise/guides/human-in-the-loop.mdx index 36556332d..3ffd2533b 100644 --- a/docs/ko/enterprise/guides/human-in-the-loop.mdx +++ b/docs/ko/enterprise/guides/human-in-the-loop.mdx @@ -5,9 +5,53 @@ icon: "user-check" mode: "wide" --- -인간-중심(Human-In-The-Loop, HITL)은 인공지능과 인간 전문 지식을 결합하여 의사결정을 강화하고 작업 결과를 향상시키는 강력한 접근 방식입니다. 이 가이드는 CrewAI 내에서 HITL을 구현하는 방법을 보여줍니다. +인간-중심(Human-In-The-Loop, HITL)은 인공지능과 인간 전문 지식을 결합하여 의사결정을 강화하고 작업 결과를 향상시키는 강력한 접근 방식입니다. 이 가이드는 CrewAI Enterprise 내에서 HITL을 구현하는 방법을 보여줍니다. -## HITL 워크플로 설정 +## CrewAI의 HITL 접근 방식 + +CrewAI는 human-in-the-loop 워크플로우를 구현하기 위한 두 가지 접근 방식을 제공합니다: + +| 접근 방식 | 적합한 용도 | 버전 | +|----------|----------|---------| +| **Flow 기반** (`@human_feedback` 데코레이터) | Enterprise UI를 사용한 프로덕션, 관리형 워크플로우, 전체 플랫폼 기능 | **1.8.0+** | +| **Webhook 기반** | 커스텀 통합, 외부 시스템 (Slack, Teams 등), 레거시 설정 | 모든 버전 | + +## Enterprise 플랫폼과 Flow 기반 HITL + + +`@human_feedback` 데코레이터는 **CrewAI 버전 1.8.0 이상**이 필요합니다. + + +Flow에서 `@human_feedback` 데코레이터를 사용하면, CrewAI Enterprise는 인간 피드백 워크플로우를 완벽하게 제어할 수 있는 전용 **HITL 관리 UI**를 제공합니다: + + + + Enterprise 대시보드에서 직접 HITL 요청을 검토하고 응답하세요—webhook 설정이 필요 없습니다. + + + 다양한 작업 유형이나 crew에 대해 특정 팀원 또는 그룹을 응답자로 할당하세요. + + + 세분화된 권한 제어로 HITL 요청을 보거나, 응답하거나, 에스컬레이션할 수 있는 사람을 정의하세요. + + + 응답이 지연되거나 상급 검토가 필요할 때 자동 에스컬레이션 규칙을 구성하세요. + + + 응답 시간에 대한 서비스 수준 계약을 설정하고 자동 알림 및 추적을 활성화하세요. + + + 콘텐츠, 우선순위 또는 사용자 정의 규칙을 기반으로 적용 정책과 함께 HITL 요청을 라우팅하세요. + + + + +`@human_feedback` 데코레이터의 구현 세부 사항은 [Flow에서 인간 피드백](/ko/learn/human-feedback-in-flows) 가이드를 참조하세요. + + +## Webhook 기반 HITL 워크플로 설정 + +Slack, Microsoft Teams 또는 자체 애플리케이션과 같은 외부 시스템과의 커스텀 통합을 위해 webhook 기반 접근 방식을 사용할 수 있습니다: @@ -99,3 +143,14 @@ HITL 워크플로우는 특히 다음과 같은 경우에 유용합니다: - 민감하거나 위험도가 높은 작업 - 인간의 판단이 필요한 창의적 작업 - 준수 및 규제 검토 + +## 자세히 알아보기 + + + + 할당, SLA 관리, 에스컬레이션 정책 및 분석을 포함한 전체 Enterprise Flow HITL 플랫폼 기능을 살펴보세요. + + + Flow에서 `@human_feedback` 데코레이터 구현 가이드. + + diff --git a/docs/ko/learn/human-in-the-loop.mdx b/docs/ko/learn/human-in-the-loop.mdx index 9ccdcb231..fe9c1d145 100644 --- a/docs/ko/learn/human-in-the-loop.mdx +++ b/docs/ko/learn/human-in-the-loop.mdx @@ -112,3 +112,9 @@ HITL 워크플로우는 다음과 같은 경우에 특히 유용합니다: - 민감하거나 고위험 작업 - 인간의 판단이 필요한 창의적 과제 - 컴플라이언스 및 규제 검토 + +## Enterprise 기능 + + + CrewAI Enterprise는 플랫폼 내 검토, 응답자 할당, 권한, 에스컬레이션 정책, SLA 관리, 동적 라우팅 및 전체 분석을 갖춘 Flow용 포괄적인 HITL 관리 시스템을 제공합니다. [자세히 알아보기 →](/ko/enterprise/features/flow-hitl-management) + diff --git a/docs/pt-BR/enterprise/features/flow-hitl-management.mdx b/docs/pt-BR/enterprise/features/flow-hitl-management.mdx new file mode 100644 index 000000000..f7673988c --- /dev/null +++ b/docs/pt-BR/enterprise/features/flow-hitl-management.mdx @@ -0,0 +1,910 @@ +--- +title: "Gerenciamento HITL para Flows" +description: "Revisão humana de nível empresarial para Flows com atribuição, gerenciamento de SLA, políticas de escalação e roteamento dinâmico" +icon: "users-gear" +mode: "wide" +--- + + +Os recursos de gerenciamento HITL para Flows requerem o decorador `@human_feedback`, disponível no **CrewAI versão 1.8.0 ou superior**. Estes recursos aplicam-se especificamente a **Flows**, não a Crews. + + +O CrewAI Enterprise oferece um sistema abrangente de gerenciamento Human-in-the-Loop (HITL) para Flows que transforma fluxos de trabalho de IA em processos colaborativos humano-IA. Além de simples portões de aprovação, a plataforma oferece controles de nível empresarial para atribuição, responsabilidade e conformidade. + +## Visão Geral + + + + Revise e responda a solicitações diretamente no dashboard Enterprise + + + Direcione revisões para as pessoas certas com base em regras e expertise + + + Garanta respostas oportunas com políticas de escalação automatizadas + + + +## Configurando Pontos de Revisão Humana em Flows + +Configure checkpoints de revisão humana em seus Flows usando o decorador `@human_feedback`. Quando a execução atinge um ponto de revisão, o sistema pausa e exibe um estado de "aguardando entrada" na UI. + +```python +from crewai.flow.flow import Flow, start, listen +from crewai.flow.human_feedback import human_feedback, HumanFeedbackResult + +class ContentApprovalFlow(Flow): + @start() + def generate_content(self): + # IA gera conteúdo + return "Texto de marketing gerado para campanha Q1..." + + @listen(generate_content) + @human_feedback( + message="Por favor, revise este conteúdo para conformidade com a marca:", + emit=["approved", "rejected", "needs_revision"], + ) + def review_content(self, content): + return content + + @listen("approved") + def publish_content(self, result: HumanFeedbackResult): + print(f"Publicando conteúdo aprovado. Notas do revisor: {result.feedback}") + + @listen("rejected") + def archive_content(self, result: HumanFeedbackResult): + print(f"Conteúdo rejeitado. Motivo: {result.feedback}") + + @listen("needs_revision") + def revise_content(self, result: HumanFeedbackResult): + print(f"Revisão solicitada: {result.feedback}") +``` + +Para detalhes completos de implementação, consulte o guia [Feedback Humano em Flows](/pt-BR/learn/human-feedback-in-flows). + +## Atribuição e Roteamento + +A plataforma Enterprise oferece capacidades sofisticadas de atribuição para garantir que as revisões cheguem aos membros certos da equipe. + +### Atribuição de Respondentes + +Atribua membros específicos da equipe ou grupos como respondentes para diferentes tipos de tarefas: + + + + Vá para as configurações do seu Flow e selecione a seção de configuração "Revisão Humana". + + + Atribua usuários individuais ou grupos como respondentes padrão para solicitações de revisão. + + + Defina respondentes alternativos quando os designados principais não estiverem disponíveis. + + + + + Configurações HITL + + +### Regras de Roteamento Dinâmico + +Configure roteamento inteligente baseado no estado do flow, tipo de conteúdo ou condições personalizadas: + +| Tipo de Regra | Descrição | Exemplo | +|---------------|-----------|---------| +| **Baseado em Conteúdo** | Roteie com base no conteúdo sendo revisado | Conteúdo legal → Equipe jurídica | +| **Baseado em Prioridade** | Atribua revisores com base no nível de urgência | Alta prioridade → Revisores seniores | +| **Baseado em Estado** | Roteie com base em variáveis de estado do flow | `state.amount > 10000` → Diretor financeiro | +| **Round-Robin** | Distribua revisões uniformemente pela equipe | Balanceie carga de trabalho automaticamente | + + + Configuração de Regras de Roteamento HITL + + +### Permissões Baseadas em Função + +Controle quem pode visualizar, responder ou escalar solicitações HITL: + + + + Pode visualizar solicitações HITL e seu status, mas não pode responder ou tomar ações. + + + Pode visualizar e responder a solicitações HITL atribuídas com decisões de aprovar/rejeitar. + + + Pode visualizar todas as solicitações, responder, reatribuir a outros membros da equipe e sobrescrever decisões. + + + Acesso total incluindo configuração de regras de roteamento, SLAs e políticas de escalação. + + + +## Processo de Revisão + +### Interface de Revisão + +A interface de revisão HITL oferece uma experiência limpa e focada para revisores: + +- **Renderização Markdown**: Formatação rica para conteúdo de revisão com destaque de sintaxe +- **Painel de Contexto**: Visualize estado do flow, histórico de execução e informações relacionadas +- **Entrada de Feedback**: Forneça feedback detalhado e comentários com sua decisão +- **Ações Rápidas**: Botões de aprovar/rejeitar com um clique com comentários opcionais + + + Lista de Solicitações HITL Pendentes + + +### Modos de Revisão + +Escolha a abordagem de revisão que se adapta ao seu fluxo de trabalho: + + + + **Bloqueie execução até aprovação** + + O flow pausa completamente até que um humano forneça feedback. Melhor para decisões críticas que não devem prosseguir sem revisão. + + + **Enfileire itens para revisão eficiente** + + Colete múltiplas solicitações de revisão e processe-as em sessões focadas. Ideal para revisões de alto volume e menor urgência. + + + +### Histórico e Trilha de Auditoria + +Toda interação HITL é rastreada com uma linha do tempo completa: + +- Histórico de decisões (aprovar/rejeitar/revisar) +- Identidade do revisor e timestamp +- Feedback e comentários fornecidos +- Mudanças de estado e escalações +- Métricas de tempo de resposta + +## Gerenciamento de SLA e Escalação + +Garanta respostas oportunas com rastreamento automatizado de SLA e políticas de escalação. + +### Configurando SLAs + +Defina expectativas de tempo de resposta para diferentes tipos de revisão: + +| Nível de SLA | Tempo de Resposta | Caso de Uso | +|--------------|-------------------|-------------| +| **Crítico** | 15 minutos | Incidentes de produção, revisões de segurança | +| **Alto** | 1 hora | Conteúdo voltado ao cliente, aprovações urgentes | +| **Padrão** | 4 horas | Revisão regular de conteúdo, aprovações rotineiras | +| **Baixo** | 24 horas | Revisões não bloqueantes, processamento em lote | + +### Regras de Escalação + +Configure escalação automática quando os SLAs estiverem em risco: + + + + Envie notificação de lembrete ao revisor atribuído (ex: em 50% do tempo de SLA). + + + Escale para gerente ou revisor de backup quando o limite de SLA for atingido. + + + Configure comportamento alternativo se não houver resposta após período estendido: + - **Auto-aprovação**: Prossiga com a execução (para revisões não críticas) + - **Auto-rejeição**: Falhe com segurança e notifique stakeholders + - **Re-roteamento**: Atribua a diferente revisor ou equipe + + + +### Notificações + +Alertas automatizados mantêm stakeholders informados durante todo o fluxo de trabalho: + +- **Notificações de Atribuição**: Alerte revisores quando novas solicitações chegarem +- **Avisos de SLA**: Lembre revisores antes dos prazos +- **Alertas de Escalação**: Notifique gerentes quando revisões forem escaladas +- **Atualizações de Conclusão**: Informe solicitantes quando revisões forem concluídas + + +**Integração com Slack**: Notificações diretas do Slack para solicitações HITL em breve. + + +## Análise e Monitoramento + +Acompanhe o desempenho HITL com análises abrangentes. + +### Dashboard de Desempenho + +Monitore métricas-chave em seus fluxos de trabalho HITL: + + + Dashboard de Métricas HITL + + + + + Acompanhe a porcentagem de revisões concluídas dentro dos limites de SLA. + + + Monitore tempos de resposta médios e medianos por revisor, equipe ou flow. + + + Analise padrões de volume de revisão para otimizar capacidade da equipe. + + + Visualize taxas de aprovação/rejeição em diferentes tipos de revisão. + + + +### Métricas Individuais + +Acompanhe o desempenho do revisor para responsabilidade e balanceamento de carga de trabalho: + +- Taxas de aprovação/rejeição por revisor +- Tempo médio de resposta por revisor +- Taxas de conclusão de revisão +- Frequência de escalação + +### Auditoria e Conformidade + +Capacidades de auditoria prontas para empresas para requisitos regulatórios: + +- Histórico completo de decisões com timestamps +- Verificação de identidade do revisor +- Logs de auditoria imutáveis +- Capacidades de exportação para relatórios de conformidade + +## Casos de Uso Comuns + + + + **Caso de Uso**: Automação de questionários de segurança internos com validação humana + + - IA gera respostas para questionários de segurança + - Equipe de segurança revisa e valida precisão + - Respostas aprovadas são compiladas na submissão final + - Trilha de auditoria completa para conformidade + + + + **Caso de Uso**: Conteúdo de marketing que requer revisão legal/marca + + - IA gera texto de marketing ou conteúdo de mídia social + - Roteie para equipe de marca para revisão de voz/tom + - Escale para jurídico para conteúdo sensível a conformidade + - Publicação automática após aprovação + + + + **Caso de Uso**: Relatórios de despesas, termos de contrato, alocações de orçamento + + - IA pré-processa e categoriza solicitações financeiras + - Roteie com base em limites de valor para aprovadores apropriados + - Aplique segregação de funções com acesso baseado em função + - Mantenha trilha de auditoria completa para conformidade financeira + + + + **Caso de Uso**: Revisão regulatória para operações sensíveis + + - IA sinaliza potenciais problemas de conformidade + - Oficiais de conformidade revisam itens sinalizados + - Escale para consultoria jurídica conforme necessário + - Gere relatórios de conformidade com histórico de decisões + + + + **Caso de Uso**: Validação de saída de IA antes da entrega ao cliente + + - IA gera conteúdo ou respostas voltadas ao cliente + - Equipe de QA amostra e revisa qualidade da saída + - Loops de feedback melhoram desempenho da IA ao longo do tempo + - Acompanhe métricas de qualidade em ciclos de revisão + + + +## API de Webhooks Personalizados + +Quando seus Flows pausam para feedback humano, você pode configurar webhooks para enviar dados da solicitação para sua própria aplicação. Isso permite: + +- Construir UIs de aprovação personalizadas +- Integrar com ferramentas internas (Jira, ServiceNow, dashboards personalizados) +- Rotear aprovações para sistemas de terceiros +- Notificações em apps mobile +- Sistemas de decisão automatizados + +### Configurando Webhooks + + + + Vá para **Deployment** → **Settings** → **Human in the Loop** + + + Clique para expandir a configuração de **Webhooks** + + + Digite sua URL de webhook (deve ser HTTPS em produção) + + + Clique em **Salvar Configuração** para ativar + + + +Você pode configurar múltiplos webhooks. Cada webhook ativo recebe todos os eventos HITL. + +### Eventos de Webhook + +Seu endpoint receberá requisições HTTP POST para estes eventos: + +| Tipo de Evento | Quando é Disparado | +|----------------|-------------------| +| `new_request` | Um flow pausa e solicita feedback humano | +| `escalation` | Uma solicitação pendente é escalada devido a timeout de SLA | + +### Payload do Webhook + +Todos os webhooks recebem um payload JSON com esta estrutura: + +```json +{ + "event_type": "new_request", + "id": "550e8400-e29b-41d4-a716-446655440000", + "status": "pending", + "flow_id": "flow_abc123", + "flow_class": "ContentReviewFlow", + "method_name": "review_article", + "message": "Por favor, revise este artigo para publicação.", + "output": "# Título do Artigo\n\nEste é o conteúdo que precisa de revisão...", + "emit": ["approve", "reject", "request_changes"], + "default_outcome": null, + "state": { + "article_id": 12345, + "author": "john@example.com", + "category": "technology" + }, + "metadata": { + "priority": "high", + "source": "cms" + }, + "created_at": "2026-01-12T10:30:00Z", + "callback_url": "https://api.crewai.com/crewai_plus/api/v1/human_feedback_requests/550e8400.../respond?token=abc123...", + "response_token": "abc123def456...", + "deployment_id": 12345, + "deployment_name": "Content Review Crew", + "flow_execution_id": "exec_789", + "trace_batch_id": "trace_456", + "organization_id": "org_123", + "assigned_to": { + "id": 42, + "email": "reviewer@company.com", + "name": "Jane Reviewer" + }, + "assigned_at": "2026-01-12T10:30:05Z", + "escalated_at": null, + "sla_target_minutes": 120, + "triggered_by_user_id": 99, + "routing": { + "effective_responders": [ + {"id": 42, "email": "reviewer@company.com", "name": "Jane Reviewer"}, + {"id": 43, "email": "manager@company.com", "name": "Bob Manager"} + ], + "enforce_routing_rules": true + } +} +``` + +### Referência de Campos + + + + | Campo | Tipo | Descrição | + |-------|------|-----------| + | `event_type` | string | `"new_request"` ou `"escalation"` | + | `id` | UUID | Identificador único para esta solicitação | + | `status` | string | Sempre `"pending"` para solicitações ativas | + | `method_name` | string | O método decorado que solicitou feedback | + | `message` | string | Prompt/pergunta legível para o revisor | + | `output` | string | Conteúdo a revisar (pode conter Markdown) | + | `emit` | array | Opções de resposta válidas do decorador | + | `default_outcome` | string | Resultado padrão se resposta automática for acionada | + | `state` | object | Estado do flow no momento da pausa | + | `metadata` | object | Metadados personalizados do decorador | + | `created_at` | ISO8601 | Quando a solicitação foi criada | + + + + | Campo | Tipo | Descrição | + |-------|------|-----------| + | `callback_url` | string | **Faça POST para esta URL para enviar feedback** (token incluído) | + | `response_token` | string | Token de autenticação de uso único (já em callback_url) | + + + + | Campo | Tipo | Descrição | + |-------|------|-----------| + | `deployment_id` | integer | Identificador do deployment | + | `deployment_name` | string | Nome legível do deployment | + | `flow_execution_id` | UUID | Link para o trace de execução | + | `organization_id` | UUID | Identificador da organização | + | `sla_target_minutes` | integer | Meta de SLA configurada (null se não definida) | + | `triggered_by_user_id` | integer | Usuário que iniciou o flow (se conhecido) | + + + + | Campo | Tipo | Descrição | + |-------|------|-----------| + | `assigned_to` | object | Revisor pré-atribuído (se houver) | + | `assigned_at` | ISO8601 | Quando a atribuição foi feita | + | `escalated_at` | ISO8601 | Quando a solicitação foi escalada (null se não) | + | `routing.effective_responders` | array | Usuários configurados para responder | + | `routing.enforce_routing_rules` | boolean | Se apenas respondentes listados podem responder | + + + +### Respondendo a Solicitações + +Para enviar feedback, **faça POST para a `callback_url`** incluída no payload do webhook. + +```http +POST /crewai_plus/api/v1/human_feedback_requests/{id}/respond?token={token} +Content-Type: application/json + +{ + "feedback": "Aprovado. Ótimo artigo!", + "source": "my_custom_app" +} +``` + +**O token já está incluído na `callback_url`**, então você pode fazer POST diretamente: + +```bash +curl -X POST "${callback_url}" \ + -H "Content-Type: application/json" \ + -d '{"feedback": "Aprovado com pequenas edições"}' +``` + +#### Parâmetros + +| Parâmetro | Obrigatório | Descrição | +|-----------|-------------|-----------| +| `feedback` | Sim | Seu texto de feedback (será passado para o flow) | +| `source` | Não | Identificador do seu app (aparece no histórico) | + +#### Exemplos de Resposta + + +```json Sucesso (200 OK) +{ + "status": "accepted", + "request": { + "id": "550e8400-e29b-41d4-a716-446655440000", + "status": "responded", + "feedback": "Aprovado com pequenas edições", + "outcome": null, + "responded_at": "2026-01-12T11:45:00Z", + "responded_via": "my_custom_app" + } +} +``` + +```json Já Respondido (409 Conflict) +{ + "error": "already_responded", + "message": "Feedback já fornecido via dashboard em 2026-01-12T11:30:00Z" +} +``` + +```json Token Inválido (401 Unauthorized) +{ + "error": "unauthorized", + "message": "Token de resposta inválido" +} +``` + + +### Segurança + + +Todas as requisições de webhook são assinadas criptograficamente usando HMAC-SHA256 para garantir autenticidade e prevenir adulteração. + + +#### Segurança do Webhook + +- **Assinaturas HMAC-SHA256**: Todo webhook inclui uma assinatura criptográfica +- **Secrets por webhook**: Cada webhook tem seu próprio secret de assinatura único +- **Criptografado em repouso**: Os secrets de assinatura são criptografados no nosso banco de dados +- **Verificação de timestamp**: Previne ataques de replay + +#### Segurança do Token de Resposta + +- **Uso único**: Tokens são invalidados após uma resposta bem-sucedida +- **Entropia de 256 bits**: Tokens usam geração aleatória criptograficamente segura +- **Comparação segura contra timing**: Previne ataques de timing + +#### Melhores Práticas + +1. **Verifique assinaturas**: Sempre valide o header `X-CrewAI-Signature` +2. **Verifique timestamps**: Rejeite requisições com mais de 5 minutos +3. **Armazene secrets com segurança**: Trate os secrets de assinatura como senhas +4. **Use HTTPS**: Seu endpoint de webhook deve usar TLS em produção +5. **Rotacione secrets**: Regenere os secrets de webhook periodicamente via dashboard + +### Exemplos de Integração + + +```python Python (Flask) - Exemplo Completo +from flask import Flask, request, jsonify +import requests +import hmac +import hashlib +import time + +app = Flask(__name__) + +WEBHOOK_SECRET = "whsec_your_signing_secret_here" +MAX_TIMESTAMP_AGE = 300 + +def verify_signature(payload: bytes, signature: str, timestamp: str) -> bool: + try: + ts = int(timestamp) + if abs(time.time() - ts) > MAX_TIMESTAMP_AGE: + return False + except (ValueError, TypeError): + return False + + signature_payload = f"{timestamp}.{payload.decode('utf-8')}" + expected = hmac.new( + WEBHOOK_SECRET.encode('utf-8'), + signature_payload.encode('utf-8'), + hashlib.sha256 + ).hexdigest() + + return hmac.compare_digest(f"sha256={expected}", signature) + +@app.route('/hitl-webhook', methods=['POST']) +def handle_hitl(): + # Verifique a assinatura primeiro + signature = request.headers.get('X-CrewAI-Signature', '') + timestamp = request.headers.get('X-CrewAI-Timestamp', '') + + if not verify_signature(request.data, signature, timestamp): + return jsonify({'error': 'Assinatura inválida'}), 401 + + payload = request.json + + # Armazene para revisão posterior + store_request(payload) + + # Ou aprove automaticamente com base em regras + if should_auto_approve(payload): + response = requests.post( + payload['callback_url'], + json={'feedback': 'Aprovado automaticamente por política', 'source': 'auto_approver'} + ) + return jsonify({'status': 'auto_approved'}) + + return jsonify({'status': 'queued_for_review'}) +``` + +```javascript Node.js (Express) - Exemplo Completo +const express = require('express'); +const crypto = require('crypto'); +const axios = require('axios'); + +const app = express(); +const WEBHOOK_SECRET = 'whsec_your_signing_secret_here'; +const MAX_TIMESTAMP_AGE = 300; + +// Capture raw body para verificação de assinatura +app.use('/hitl-webhook', express.raw({ type: 'application/json' })); + +function verifySignature(payload, signature, timestamp) { + const ts = parseInt(timestamp, 10); + if (isNaN(ts) || Math.abs(Date.now() / 1000 - ts) > MAX_TIMESTAMP_AGE) { + return false; + } + + const signaturePayload = `${timestamp}.${payload.toString()}`; + const expected = crypto + .createHmac('sha256', WEBHOOK_SECRET) + .update(signaturePayload) + .digest('hex'); + + return crypto.timingSafeEqual( + Buffer.from(`sha256=${expected}`), + Buffer.from(signature) + ); +} + +app.post('/hitl-webhook', async (req, res) => { + const signature = req.headers['x-crewai-signature'] || ''; + const timestamp = req.headers['x-crewai-timestamp'] || ''; + + if (!verifySignature(req.body, signature, timestamp)) { + return res.status(401).json({ error: 'Assinatura inválida' }); + } + + const { event_type, callback_url, message, output } = JSON.parse(req.body); + + console.log(`Recebido ${event_type}: ${message}`); + + // Notifique sua equipe via Slack, email, etc. + await notifyTeam(payload); + + // Depois, quando alguém aprovar: + // await axios.post(callback_url, { feedback: 'Aprovado!' }); + + res.json({ received: true }); +}); +``` + + +### Verificação de Assinatura de Webhook + +Todas as requisições de webhook são assinadas usando HMAC-SHA256. Você deve verificar a assinatura para garantir que as requisições são autênticas e não foram adulteradas. + +#### Headers de Assinatura + +Cada requisição de webhook inclui estes headers: + +| Header | Descrição | +|--------|-----------| +| `X-CrewAI-Signature` | Assinatura HMAC-SHA256: `sha256=` | +| `X-CrewAI-Timestamp` | Timestamp Unix de quando a requisição foi assinada | + +#### Algoritmo de Verificação + +A assinatura é calculada como: + +``` +HMAC-SHA256(signing_secret, timestamp + "." + raw_body) +``` + +Onde: +- `signing_secret` é o secret único do seu webhook (mostrado no dashboard) +- `timestamp` é o valor do header `X-CrewAI-Timestamp` +- `raw_body` é o corpo da requisição JSON bruto (antes do parsing) + +#### Exemplo de Verificação em Python + +```python +import hmac +import hashlib +import time +from flask import Flask, request, jsonify + +app = Flask(__name__) + +WEBHOOK_SECRET = "whsec_your_signing_secret_here" +MAX_TIMESTAMP_AGE = 300 # 5 minutos + +def verify_signature(payload: bytes, signature: str, timestamp: str) -> bool: + """Verifica a assinatura do webhook.""" + # Verifique timestamp para prevenir ataques de replay + try: + ts = int(timestamp) + if abs(time.time() - ts) > MAX_TIMESTAMP_AGE: + return False + except (ValueError, TypeError): + return False + + # Calcule assinatura esperada + signature_payload = f"{timestamp}.{payload.decode('utf-8')}" + expected = hmac.new( + WEBHOOK_SECRET.encode('utf-8'), + signature_payload.encode('utf-8'), + hashlib.sha256 + ).hexdigest() + + expected_header = f"sha256={expected}" + + # Comparação em tempo constante para prevenir ataques de timing + return hmac.compare_digest(expected_header, signature) + +@app.route('/hitl-webhook', methods=['POST']) +def handle_hitl(): + signature = request.headers.get('X-CrewAI-Signature', '') + timestamp = request.headers.get('X-CrewAI-Timestamp', '') + + if not verify_signature(request.data, signature, timestamp): + return jsonify({'error': 'Assinatura inválida'}), 401 + + payload = request.json + # Processe o webhook verificado... + return jsonify({'status': 'received'}) +``` + +#### Exemplo de Verificação em Node.js + +```javascript +const express = require('express'); +const crypto = require('crypto'); + +const app = express(); +const WEBHOOK_SECRET = 'whsec_your_signing_secret_here'; +const MAX_TIMESTAMP_AGE = 300; // 5 minutos + +// Use raw body para verificação de assinatura +app.use('/hitl-webhook', express.raw({ type: 'application/json' })); + +function verifySignature(payload, signature, timestamp) { + // Verifique timestamp + const ts = parseInt(timestamp, 10); + if (isNaN(ts) || Math.abs(Date.now() / 1000 - ts) > MAX_TIMESTAMP_AGE) { + return false; + } + + // Calcule assinatura esperada + const signaturePayload = `${timestamp}.${payload.toString()}`; + const expected = crypto + .createHmac('sha256', WEBHOOK_SECRET) + .update(signaturePayload) + .digest('hex'); + + const expectedHeader = `sha256=${expected}`; + + // Comparação em tempo constante + return crypto.timingSafeEqual( + Buffer.from(expectedHeader), + Buffer.from(signature) + ); +} + +app.post('/hitl-webhook', (req, res) => { + const signature = req.headers['x-crewai-signature'] || ''; + const timestamp = req.headers['x-crewai-timestamp'] || ''; + + if (!verifySignature(req.body, signature, timestamp)) { + return res.status(401).json({ error: 'Assinatura inválida' }); + } + + const payload = JSON.parse(req.body); + // Processe o webhook verificado... + res.json({ status: 'received' }); +}); +``` + +#### Exemplo de Verificação em Ruby + +```ruby +require 'openssl' +require 'json' + +class HitlWebhookController < ApplicationController + WEBHOOK_SECRET = ENV['CREWAI_WEBHOOK_SECRET'] + MAX_TIMESTAMP_AGE = 300 # 5 minutos + + skip_before_action :verify_authenticity_token + + def receive + signature = request.headers['X-CrewAI-Signature'] + timestamp = request.headers['X-CrewAI-Timestamp'] + payload = request.raw_post + + unless verify_signature(payload, signature, timestamp) + render json: { error: 'Assinatura inválida' }, status: :unauthorized + return + end + + data = JSON.parse(payload) + # Processe o webhook verificado... + render json: { status: 'received' } + end + + private + + def verify_signature(payload, signature, timestamp) + return false if timestamp.blank? || signature.blank? + + # Verifique atualidade do timestamp + ts = timestamp.to_i + return false if (Time.now.to_i - ts).abs > MAX_TIMESTAMP_AGE + + # Calcule assinatura esperada + signature_payload = "#{timestamp}.#{payload}" + expected = OpenSSL::HMAC.hexdigest('SHA256', WEBHOOK_SECRET, signature_payload) + expected_header = "sha256=#{expected}" + + # Comparação em tempo constante + ActiveSupport::SecurityUtils.secure_compare(expected_header, signature) + end +end +``` + +#### Melhores Práticas de Segurança + +1. **Sempre verifique assinaturas** antes de processar dados do webhook +2. **Verifique atualidade do timestamp** (recomendamos tolerância de 5 minutos) +3. **Use comparação em tempo constante** para prevenir ataques de timing +4. **Armazene secrets com segurança** usando variáveis de ambiente ou gerenciadores de secrets +5. **Rotacione secrets periodicamente** (você pode regenerar no dashboard) + +### Tratamento de Erros + +Seu endpoint de webhook deve retornar um código de status 2xx para confirmar o recebimento: + +| Sua Resposta | Nosso Comportamento | +|--------------|---------------------| +| 2xx | Webhook entregue com sucesso | +| 4xx/5xx | Registrado como falha, sem retry | +| Timeout (30s) | Registrado como falha, sem retry | + +### Testando sua Integração + + + + Adicione um webhook apontando para seu endpoint de desenvolvimento + + + Para desenvolvimento local, use [ngrok](https://ngrok.com): + ```bash + ngrok http 3000 + # Use a URL HTTPS como seu endpoint de webhook + ``` + + + Execute um flow com um decorador `@human_feedback` + + + Confirme que seu endpoint recebeu o payload + + + Faça POST para a `callback_url` para completar o flow + + + +## Outras Opções de Integração + +### Acesso via API + +Controle programático completo para integrações personalizadas: + +```python +# Exemplo: Verificar status HITL programaticamente +from crewai.enterprise import HITLClient + +client = HITLClient() +pending_reviews = client.get_pending_reviews(flow_id="my-flow") + +for review in pending_reviews: + print(f"Revisão {review.id}: {review.status} - Atribuída a: {review.assignee}") +``` + +### Em Breve + +- **Integração com Slack**: Responda a solicitações HITL diretamente do Slack +- **Microsoft Teams**: Experiência de revisão nativa do Teams +- **App Mobile**: Revise e aprove em qualquer lugar + +## Melhores Práticas + + +**Comece Simples**: Comece com portões de aprovação básicos, depois adicione roteamento e SLAs conforme seus fluxos de trabalho amadurecem. + + +1. **Defina Critérios de Revisão Claros**: Documente o que os revisores devem procurar para garantir decisões consistentes. + +2. **Defina SLAs Realistas**: Equilibre urgência com capacidade do revisor para manter fluxos de trabalho sustentáveis. + +3. **Use Escalação com Sabedoria**: Reserve auto-aprovação para revisões verdadeiramente não críticas para manter a qualidade. + +4. **Monitore e Itere**: Use análises para identificar gargalos e otimizar atribuições de revisores. + +5. **Treine Sua Equipe**: Garanta que os revisores entendam seu papel e as ferramentas disponíveis para eles. + +## Recursos Relacionados + + + + Guia de implementação para o decorador `@human_feedback` + + + Guia passo a passo para configurar workflows HITL + + + Configure controle de acesso baseado em função para sua organização + + + Configure notificações de eventos em tempo real + + diff --git a/docs/pt-BR/enterprise/guides/human-in-the-loop.mdx b/docs/pt-BR/enterprise/guides/human-in-the-loop.mdx index 298290aef..8834ac44a 100644 --- a/docs/pt-BR/enterprise/guides/human-in-the-loop.mdx +++ b/docs/pt-BR/enterprise/guides/human-in-the-loop.mdx @@ -5,9 +5,53 @@ icon: "user-check" mode: "wide" --- -Human-In-The-Loop (HITL) é uma abordagem poderosa que combina inteligência artificial com expertise humana para aprimorar a tomada de decisão e melhorar os resultados das tarefas. Este guia mostra como implementar HITL dentro do CrewAI. +Human-In-The-Loop (HITL) é uma abordagem poderosa que combina inteligência artificial com expertise humana para aprimorar a tomada de decisão e melhorar os resultados das tarefas. Este guia mostra como implementar HITL dentro do CrewAI Enterprise. -## Configurando Workflows HITL +## Abordagens HITL no CrewAI + +CrewAI oferece duas abordagens para implementar workflows human-in-the-loop: + +| Abordagem | Melhor Para | Versão | +|----------|----------|---------| +| **Baseada em Flow** (decorador `@human_feedback`) | Produção com UI Enterprise, workflows gerenciados, recursos completos da plataforma | **1.8.0+** | +| **Baseada em Webhook** | Integrações customizadas, sistemas externos (Slack, Teams, etc.), configurações legadas | Todas as versões | + +## HITL Baseado em Flow com Plataforma Enterprise + + +O decorador `@human_feedback` requer **CrewAI versão 1.8.0 ou superior**. + + +Ao usar o decorador `@human_feedback` em seus Flows, o CrewAI Enterprise oferece uma **UI de Gerenciamento HITL** dedicada que proporciona controle total sobre os workflows de feedback humano: + + + + Revise e responda a solicitações HITL diretamente no dashboard Enterprise—sem necessidade de configuração de webhook. + + + Atribua membros específicos da equipe ou grupos como respondentes para diferentes tipos de tarefas ou crews. + + + Defina quem pode visualizar, responder ou escalar solicitações HITL com controles de permissão granulares. + + + Configure regras de escalação automática quando as respostas atrasarem ou exigirem revisão sênior. + + + Defina Acordos de Nível de Serviço para tempos de resposta com notificações e rastreamento automáticos. + + + Roteie solicitações HITL com base em conteúdo, prioridade ou regras personalizadas com políticas de aplicação. + + + + +Para detalhes de implementação do decorador `@human_feedback`, consulte o guia [Feedback Humano em Flows](/pt-BR/learn/human-feedback-in-flows). + + +## Configurando Workflows HITL Baseados em Webhook + +Para integrações customizadas com sistemas externos como Slack, Microsoft Teams ou suas próprias aplicações, você pode usar a abordagem baseada em webhook: @@ -99,3 +143,14 @@ Workflows HITL são particularmente valiosos para: - Operações sensíveis ou de alto risco - Tarefas criativas que exigem julgamento humano - Revisões de conformidade e regulatórias + +## Saiba Mais + + + + Explore os recursos completos da plataforma HITL para Flows, incluindo atribuição, gerenciamento de SLA, políticas de escalação e análises. + + + Guia de implementação para o decorador `@human_feedback` em seus Flows. + + diff --git a/docs/pt-BR/learn/human-in-the-loop.mdx b/docs/pt-BR/learn/human-in-the-loop.mdx index 07528027c..d56fa1167 100644 --- a/docs/pt-BR/learn/human-in-the-loop.mdx +++ b/docs/pt-BR/learn/human-in-the-loop.mdx @@ -112,3 +112,9 @@ Workflows HITL são particularmente valiosos para: - Operações sensíveis ou de alto risco - Tarefas criativas que requerem julgamento humano - Revisões de conformidade e regulamentação + +## Recursos Enterprise + + + O CrewAI Enterprise oferece um sistema abrangente de gerenciamento HITL para Flows com revisão na plataforma, atribuição de respondentes, permissões, políticas de escalação, gerenciamento de SLA, roteamento dinâmico e análises completas. [Saiba mais →](/pt-BR/enterprise/features/flow-hitl-management) +