mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-02-20 03:00:31 -05:00
updating docs
This commit is contained in:
909
docs/en/enterprise/features/flow-hitl-management.mdx
Normal file
909
docs/en/enterprise/features/flow-hitl-management.mdx
Normal file
@@ -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"
|
||||
---
|
||||
|
||||
<Note>
|
||||
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.
|
||||
</Note>
|
||||
|
||||
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
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="In-Platform Review" icon="desktop">
|
||||
Review and respond to requests directly in the Enterprise dashboard
|
||||
</Card>
|
||||
<Card title="Smart Assignment" icon="user-check">
|
||||
Route reviews to the right people based on rules and expertise
|
||||
</Card>
|
||||
<Card title="SLA & Escalation" icon="clock">
|
||||
Ensure timely responses with automated escalation policies
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## 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:
|
||||
|
||||
<Steps>
|
||||
<Step title="Navigate to HITL Settings">
|
||||
Go to your Flow settings and select the "Human Review" configuration section.
|
||||
</Step>
|
||||
<Step title="Configure Responders">
|
||||
Assign individual users or groups as default responders for review requests.
|
||||
</Step>
|
||||
<Step title="Set Backup Responders">
|
||||
Define fallback responders when primary assignees are unavailable.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/hitl-settings-1.png" alt="HITL Configuration Settings" />
|
||||
</Frame>
|
||||
|
||||
### 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 |
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/hitl-settings-2.png" alt="HITL Routing Rules Configuration" />
|
||||
</Frame>
|
||||
|
||||
### Role-Based Permissions
|
||||
|
||||
Control who can view, respond to, or escalate HITL requests:
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Viewer" icon="eye">
|
||||
Can view HITL requests and their status but cannot respond or take action.
|
||||
</Accordion>
|
||||
<Accordion title="Responder" icon="reply">
|
||||
Can view and respond to assigned HITL requests with approve/reject decisions.
|
||||
</Accordion>
|
||||
<Accordion title="Manager" icon="user-tie">
|
||||
Can view all requests, respond, reassign to other team members, and override decisions.
|
||||
</Accordion>
|
||||
<Accordion title="Admin" icon="shield">
|
||||
Full access including configuration of routing rules, SLAs, and escalation policies.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## 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
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/hitl-list-pending-feedbacks.png" alt="HITL Pending Requests List" />
|
||||
</Frame>
|
||||
|
||||
### Review Modes
|
||||
|
||||
Choose the review approach that fits your workflow:
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Immediate Gating" icon="hand">
|
||||
**Block execution until approval**
|
||||
|
||||
Flow pauses completely until a human provides feedback. Best for critical decisions that must not proceed without review.
|
||||
</Card>
|
||||
<Card title="Batch Processing" icon="layer-group">
|
||||
**Queue items for efficient review**
|
||||
|
||||
Collect multiple review requests and process them in focused sessions. Ideal for high-volume, lower-urgency reviews.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
### 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:
|
||||
|
||||
<Steps>
|
||||
<Step title="Warning Threshold">
|
||||
Send reminder notification to assigned reviewer (e.g., at 50% of SLA time).
|
||||
</Step>
|
||||
<Step title="Escalation Trigger">
|
||||
Escalate to manager or backup reviewer when SLA threshold is reached.
|
||||
</Step>
|
||||
<Step title="Auto-Action">
|
||||
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
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
### 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
|
||||
|
||||
<Note>
|
||||
**Slack Integration**: Direct Slack notifications for HITL requests coming soon.
|
||||
</Note>
|
||||
|
||||
## Analytics & Monitoring
|
||||
|
||||
Track HITL performance with comprehensive analytics.
|
||||
|
||||
### Performance Dashboard
|
||||
|
||||
Monitor key metrics across your HITL workflows:
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/hitl-metrics.png" alt="HITL Metrics Dashboard" />
|
||||
</Frame>
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="SLA Compliance" icon="chart-line">
|
||||
Track percentage of reviews completed within SLA thresholds.
|
||||
</Card>
|
||||
<Card title="Response Times" icon="stopwatch">
|
||||
Monitor average and median response times by reviewer, team, or flow.
|
||||
</Card>
|
||||
<Card title="Volume Trends" icon="chart-bar">
|
||||
Analyze review volume patterns to optimize team capacity.
|
||||
</Card>
|
||||
<Card title="Decision Distribution" icon="chart-pie">
|
||||
View approval/rejection rates across different review types.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
### 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
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Security Reviews" icon="shield-halved">
|
||||
**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
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Content Approval" icon="file-lines">
|
||||
**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
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Financial Approvals" icon="money-bill">
|
||||
**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
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Compliance Checks" icon="clipboard-check">
|
||||
**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
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Quality Assurance" icon="magnifying-glass">
|
||||
**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
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## 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
|
||||
|
||||
<Steps>
|
||||
<Step title="Navigate to Settings">
|
||||
Go to your **Deployment** → **Settings** → **Human in the Loop**
|
||||
</Step>
|
||||
<Step title="Expand Webhooks Section">
|
||||
Click to expand the **Webhooks** configuration
|
||||
</Step>
|
||||
<Step title="Add Your Webhook URL">
|
||||
Enter your webhook URL (must be HTTPS in production)
|
||||
</Step>
|
||||
<Step title="Save Configuration">
|
||||
Click **Save Configuration** to activate
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
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
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Core Fields" icon="circle-info">
|
||||
| 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 |
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Response Fields" icon="reply">
|
||||
| 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) |
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Context Fields" icon="layer-group">
|
||||
| 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) |
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Assignment & Routing Fields" icon="route">
|
||||
| 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 |
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
### 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
|
||||
|
||||
<CodeGroup>
|
||||
```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"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Security
|
||||
|
||||
<Info>
|
||||
All webhook requests are cryptographically signed using HMAC-SHA256 to ensure authenticity and prevent tampering.
|
||||
</Info>
|
||||
|
||||
#### 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
|
||||
|
||||
<CodeGroup>
|
||||
```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 });
|
||||
});
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### 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=<hex_digest>` |
|
||||
| `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
|
||||
|
||||
<Steps>
|
||||
<Step title="Configure Webhook">
|
||||
Add a webhook pointing to your dev endpoint
|
||||
</Step>
|
||||
<Step title="Use a Tunnel for Local Dev">
|
||||
For local development, use [ngrok](https://ngrok.com):
|
||||
```bash
|
||||
ngrok http 3000
|
||||
# Use the HTTPS URL as your webhook endpoint
|
||||
```
|
||||
</Step>
|
||||
<Step title="Trigger a Flow">
|
||||
Run a flow with a `@human_feedback` decorator
|
||||
</Step>
|
||||
<Step title="Verify Receipt">
|
||||
Check that your endpoint receives the payload
|
||||
</Step>
|
||||
<Step title="Submit Response">
|
||||
POST to the `callback_url` to complete the flow
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## 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
|
||||
|
||||
<Tip>
|
||||
**Start Simple**: Begin with basic approval gates, then add routing and SLAs as your workflows mature.
|
||||
</Tip>
|
||||
|
||||
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
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Human Feedback in Flows" icon="code" href="/en/learn/human-feedback-in-flows">
|
||||
Implementation guide for the `@human_feedback` decorator
|
||||
</Card>
|
||||
<Card title="Flow HITL Workflow Guide" icon="route" href="/en/enterprise/guides/human-in-the-loop">
|
||||
Step-by-step guide for setting up HITL workflows
|
||||
</Card>
|
||||
<Card title="RBAC Configuration" icon="shield-check" href="/en/enterprise/features/rbac">
|
||||
Configure role-based access control for your organization
|
||||
</Card>
|
||||
<Card title="Webhook Streaming" icon="bolt" href="/en/enterprise/features/webhook-streaming">
|
||||
Set up real-time event notifications
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -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
|
||||
|
||||
<Note>
|
||||
The `@human_feedback` decorator requires **CrewAI version 1.8.0 or higher**.
|
||||
</Note>
|
||||
|
||||
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:
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="In-Platform Response" icon="reply">
|
||||
Review and respond to HITL requests directly within the Enterprise dashboard—no webhook setup required.
|
||||
</Card>
|
||||
<Card title="Responder Assignment" icon="user-plus">
|
||||
Assign specific team members or groups as responders for different task types or crews.
|
||||
</Card>
|
||||
<Card title="Permissions & Access Control" icon="shield-check">
|
||||
Define who can view, respond to, or escalate HITL requests with granular permission controls.
|
||||
</Card>
|
||||
<Card title="Escalation Policies" icon="arrow-up-right">
|
||||
Configure automatic escalation rules when responses are delayed or require senior review.
|
||||
</Card>
|
||||
<Card title="SLA Management" icon="clock">
|
||||
Set Service Level Agreements for response times with automatic notifications and tracking.
|
||||
</Card>
|
||||
<Card title="Dynamic Routing" icon="route">
|
||||
Route HITL requests based on content, priority, or custom rules with enforcement policies.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Tip>
|
||||
For implementation details on the `@human_feedback` decorator, see the [Human Feedback in Flows](/en/learn/human-feedback-in-flows) guide.
|
||||
</Tip>
|
||||
|
||||
## 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:
|
||||
|
||||
<Steps>
|
||||
<Step title="Configure Your Task">
|
||||
@@ -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
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Flow HITL Management" icon="users-gear" href="/en/enterprise/features/flow-hitl-management">
|
||||
Explore the full Enterprise Flow HITL platform capabilities including assignment, SLA management, escalation policies, and analytics.
|
||||
</Card>
|
||||
<Card title="Human Feedback in Flows" icon="code" href="/en/learn/human-feedback-in-flows">
|
||||
Implementation guide for the `@human_feedback` decorator in your Flows.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -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
|
||||
|
||||
<Card title="Flow HITL Management Platform" icon="users-gear" href="/en/enterprise/features/flow-hitl-management">
|
||||
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)
|
||||
</Card>
|
||||
|
||||
BIN
docs/images/enterprise/hitl-list-pending-feedbacks.png
Normal file
BIN
docs/images/enterprise/hitl-list-pending-feedbacks.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 251 KiB |
BIN
docs/images/enterprise/hitl-metrics.png
Normal file
BIN
docs/images/enterprise/hitl-metrics.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 263 KiB |
BIN
docs/images/enterprise/hitl-settings-1.png
Normal file
BIN
docs/images/enterprise/hitl-settings-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 224 KiB |
BIN
docs/images/enterprise/hitl-settings-2.png
Normal file
BIN
docs/images/enterprise/hitl-settings-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 154 KiB |
910
docs/ko/enterprise/features/flow-hitl-management.mdx
Normal file
910
docs/ko/enterprise/features/flow-hitl-management.mdx
Normal file
@@ -0,0 +1,910 @@
|
||||
---
|
||||
title: "Flow HITL 관리"
|
||||
description: "할당, SLA 관리, 에스컬레이션 정책 및 동적 라우팅을 갖춘 Flow용 엔터프라이즈급 인간 검토"
|
||||
icon: "users-gear"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Note>
|
||||
Flow HITL 관리 기능은 `@human_feedback` 데코레이터가 필요하며, **CrewAI 버전 1.8.0 이상**에서 사용할 수 있습니다. 이 기능은 Crew가 아닌 **Flow**에만 적용됩니다.
|
||||
</Note>
|
||||
|
||||
CrewAI Enterprise는 AI 워크플로우를 협업적인 인간-AI 프로세스로 전환하는 Flow용 포괄적인 Human-in-the-Loop(HITL) 관리 시스템을 제공합니다. 단순한 승인 게이트를 넘어, 플랫폼은 할당, 책임, 규정 준수를 위한 엔터프라이즈급 제어를 제공합니다.
|
||||
|
||||
## 개요
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="플랫폼 내 검토" icon="desktop">
|
||||
Enterprise 대시보드에서 직접 요청을 검토하고 응답
|
||||
</Card>
|
||||
<Card title="스마트 할당" icon="user-check">
|
||||
규칙과 전문성에 따라 적합한 담당자에게 검토 라우팅
|
||||
</Card>
|
||||
<Card title="SLA 및 에스컬레이션" icon="clock">
|
||||
자동화된 에스컬레이션 정책으로 적시 응답 보장
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## 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 플랫폼은 검토가 적합한 팀원에게 전달되도록 정교한 할당 기능을 제공합니다.
|
||||
|
||||
### 응답자 할당
|
||||
|
||||
다양한 작업 유형에 대해 특정 팀원 또는 그룹을 응답자로 할당합니다:
|
||||
|
||||
<Steps>
|
||||
<Step title="HITL 설정으로 이동">
|
||||
Flow 설정으로 이동하여 "인간 검토" 구성 섹션을 선택합니다.
|
||||
</Step>
|
||||
<Step title="응답자 구성">
|
||||
검토 요청에 대한 기본 응답자로 개별 사용자 또는 그룹을 할당합니다.
|
||||
</Step>
|
||||
<Step title="백업 응답자 설정">
|
||||
주 담당자가 부재 시 대체 응답자를 정의합니다.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/hitl-settings-1.png" alt="HITL 구성 설정" />
|
||||
</Frame>
|
||||
|
||||
### 동적 라우팅 규칙
|
||||
|
||||
Flow 상태, 콘텐츠 유형 또는 사용자 정의 조건에 따라 지능형 라우팅을 설정합니다:
|
||||
|
||||
| 규칙 유형 | 설명 | 예시 |
|
||||
|-----------|------|------|
|
||||
| **콘텐츠 기반** | 검토 대상 콘텐츠에 따라 라우팅 | 법률 콘텐츠 → 법무팀 |
|
||||
| **우선순위 기반** | 긴급도에 따라 검토자 할당 | 높은 우선순위 → 시니어 검토자 |
|
||||
| **상태 기반** | Flow 상태 변수에 따라 라우팅 | `state.amount > 10000` → 재무 이사 |
|
||||
| **라운드 로빈** | 팀 전체에 검토를 균등 분배 | 워크로드 자동 균형 |
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/hitl-settings-2.png" alt="HITL 라우팅 규칙 구성" />
|
||||
</Frame>
|
||||
|
||||
### 역할 기반 권한
|
||||
|
||||
HITL 요청을 보거나, 응답하거나, 에스컬레이션할 수 있는 사람을 제어합니다:
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="뷰어" icon="eye">
|
||||
HITL 요청과 상태를 볼 수 있지만 응답하거나 조치를 취할 수 없습니다.
|
||||
</Accordion>
|
||||
<Accordion title="응답자" icon="reply">
|
||||
할당된 HITL 요청을 보고 승인/거부 결정으로 응답할 수 있습니다.
|
||||
</Accordion>
|
||||
<Accordion title="관리자" icon="user-tie">
|
||||
모든 요청을 보고, 응답하고, 다른 팀원에게 재할당하고, 결정을 재정의할 수 있습니다.
|
||||
</Accordion>
|
||||
<Accordion title="어드민" icon="shield">
|
||||
라우팅 규칙, SLA 및 에스컬레이션 정책 구성을 포함한 전체 접근 권한.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## 검토 프로세스
|
||||
|
||||
### 검토 인터페이스
|
||||
|
||||
HITL 검토 인터페이스는 검토자에게 깔끔하고 집중된 경험을 제공합니다:
|
||||
|
||||
- **마크다운 렌더링**: 구문 강조가 포함된 풍부한 형식의 검토 콘텐츠
|
||||
- **컨텍스트 패널**: Flow 상태, 실행 기록 및 관련 정보 보기
|
||||
- **피드백 입력**: 결정과 함께 상세한 피드백 및 코멘트 제공
|
||||
- **빠른 작업**: 선택적 코멘트가 있는 원클릭 승인/거부 버튼
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/hitl-list-pending-feedbacks.png" alt="HITL 대기 중인 요청 목록" />
|
||||
</Frame>
|
||||
|
||||
### 검토 모드
|
||||
|
||||
워크플로우에 맞는 검토 방식을 선택합니다:
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="즉시 게이팅" icon="hand">
|
||||
**승인까지 실행 차단**
|
||||
|
||||
인간이 피드백을 제공할 때까지 Flow가 완전히 일시 중지됩니다. 검토 없이 진행해서는 안 되는 중요한 결정에 적합합니다.
|
||||
</Card>
|
||||
<Card title="배치 처리" icon="layer-group">
|
||||
**효율적인 검토를 위해 항목 대기열에 추가**
|
||||
|
||||
여러 검토 요청을 수집하고 집중 세션에서 처리합니다. 대량이지만 긴급도가 낮은 검토에 이상적입니다.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
### 기록 및 감사 추적
|
||||
|
||||
모든 HITL 상호작용은 완전한 타임라인으로 추적됩니다:
|
||||
|
||||
- 결정 기록 (승인/거부/수정)
|
||||
- 검토자 신원 및 타임스탬프
|
||||
- 제공된 피드백 및 코멘트
|
||||
- 상태 변경 및 에스컬레이션
|
||||
- 응답 시간 메트릭
|
||||
|
||||
## SLA 관리 및 에스컬레이션
|
||||
|
||||
자동화된 SLA 추적 및 에스컬레이션 정책으로 적시 응답을 보장합니다.
|
||||
|
||||
### SLA 구성
|
||||
|
||||
다양한 검토 유형에 대한 응답 시간 기대치를 설정합니다:
|
||||
|
||||
| SLA 레벨 | 응답 시간 | 사용 사례 |
|
||||
|----------|----------|----------|
|
||||
| **긴급** | 15분 | 프로덕션 인시던트, 보안 검토 |
|
||||
| **높음** | 1시간 | 고객 대면 콘텐츠, 긴급 승인 |
|
||||
| **표준** | 4시간 | 일반 콘텐츠 검토, 일상적인 승인 |
|
||||
| **낮음** | 24시간 | 비차단 검토, 배치 처리 |
|
||||
|
||||
### 에스컬레이션 규칙
|
||||
|
||||
SLA가 위험에 처할 때 자동 에스컬레이션을 구성합니다:
|
||||
|
||||
<Steps>
|
||||
<Step title="경고 임계값">
|
||||
할당된 검토자에게 알림 전송 (예: SLA 시간의 50% 도달 시).
|
||||
</Step>
|
||||
<Step title="에스컬레이션 트리거">
|
||||
SLA 임계값에 도달하면 관리자 또는 백업 검토자에게 에스컬레이션.
|
||||
</Step>
|
||||
<Step title="자동 조치">
|
||||
연장된 기간 후에도 응답이 없을 경우 대체 동작 구성:
|
||||
- **자동 승인**: 실행 진행 (중요하지 않은 검토의 경우)
|
||||
- **자동 거부**: 안전하게 실패하고 이해관계자에게 알림
|
||||
- **재라우팅**: 다른 검토자 또는 팀에 할당
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
### 알림
|
||||
|
||||
자동화된 알림이 워크플로우 전반에 걸쳐 이해관계자에게 정보를 제공합니다:
|
||||
|
||||
- **할당 알림**: 새 요청이 도착하면 검토자에게 알림
|
||||
- **SLA 경고**: 마감 전 검토자에게 리마인더
|
||||
- **에스컬레이션 알림**: 검토가 에스컬레이션되면 관리자에게 알림
|
||||
- **완료 업데이트**: 검토가 완료되면 요청자에게 알림
|
||||
|
||||
<Note>
|
||||
**Slack 통합**: HITL 요청에 대한 직접 Slack 알림이 곧 제공됩니다.
|
||||
</Note>
|
||||
|
||||
## 분석 및 모니터링
|
||||
|
||||
포괄적인 분석으로 HITL 성능을 추적합니다.
|
||||
|
||||
### 성능 대시보드
|
||||
|
||||
HITL 워크플로우 전반의 주요 메트릭을 모니터링합니다:
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/hitl-metrics.png" alt="HITL 메트릭 대시보드" />
|
||||
</Frame>
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="SLA 준수" icon="chart-line">
|
||||
SLA 임계값 내에 완료된 검토 비율 추적.
|
||||
</Card>
|
||||
<Card title="응답 시간" icon="stopwatch">
|
||||
검토자, 팀 또는 Flow별 평균 및 중앙값 응답 시간 모니터링.
|
||||
</Card>
|
||||
<Card title="볼륨 트렌드" icon="chart-bar">
|
||||
팀 용량 최적화를 위한 검토 볼륨 패턴 분석.
|
||||
</Card>
|
||||
<Card title="결정 분포" icon="chart-pie">
|
||||
다양한 검토 유형에 대한 승인/거부 비율 보기.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
### 개별 메트릭
|
||||
|
||||
책임 추적 및 워크로드 균형을 위한 검토자 성과 추적:
|
||||
|
||||
- 검토자별 승인/거부 비율
|
||||
- 검토자별 평균 응답 시간
|
||||
- 검토 완료율
|
||||
- 에스컬레이션 빈도
|
||||
|
||||
### 감사 및 규정 준수
|
||||
|
||||
규제 요구 사항을 위한 엔터프라이즈급 감사 기능:
|
||||
|
||||
- 타임스탬프가 있는 완전한 결정 기록
|
||||
- 검토자 신원 확인
|
||||
- 불변 감사 로그
|
||||
- 규정 준수 보고를 위한 내보내기 기능
|
||||
|
||||
## 일반적인 사용 사례
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="보안 검토" icon="shield-halved">
|
||||
**사용 사례**: 인간 검증이 포함된 내부 보안 설문지 자동화
|
||||
|
||||
- AI가 보안 설문지에 대한 응답 생성
|
||||
- 보안팀이 정확성 검토 및 검증
|
||||
- 승인된 응답이 최종 제출물로 편집
|
||||
- 규정 준수를 위한 완전한 감사 추적
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="콘텐츠 승인" icon="file-lines">
|
||||
**사용 사례**: 법무/브랜드 검토가 필요한 마케팅 콘텐츠
|
||||
|
||||
- AI가 마케팅 카피 또는 소셜 미디어 콘텐츠 생성
|
||||
- 브랜드팀에 목소리/톤 검토를 위해 라우팅
|
||||
- 규정 준수에 민감한 콘텐츠는 법무팀으로 에스컬레이션
|
||||
- 승인 시 자동 게시
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="재무 승인" icon="money-bill">
|
||||
**사용 사례**: 경비 보고서, 계약 조건, 예산 배분
|
||||
|
||||
- AI가 재무 요청을 사전 처리하고 분류
|
||||
- 금액 임계값에 따라 적절한 승인자에게 라우팅
|
||||
- 역할 기반 접근으로 직무 분리 시행
|
||||
- 재무 규정 준수를 위한 완전한 감사 추적 유지
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="규정 준수 검사" icon="clipboard-check">
|
||||
**사용 사례**: 민감한 작업에 대한 규제 검토
|
||||
|
||||
- AI가 잠재적 규정 준수 문제 플래그
|
||||
- 규정 준수 담당자가 플래그된 항목 검토
|
||||
- 필요에 따라 법률 고문에게 에스컬레이션
|
||||
- 결정 기록이 포함된 규정 준수 보고서 생성
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="품질 보증" icon="magnifying-glass">
|
||||
**사용 사례**: 고객 전달 전 AI 출력 검증
|
||||
|
||||
- AI가 고객 대면 콘텐츠 또는 응답 생성
|
||||
- QA팀이 출력 품질 샘플링 및 검토
|
||||
- 피드백 루프가 시간이 지남에 따라 AI 성능 개선
|
||||
- 검토 주기 전반의 품질 메트릭 추적
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## 커스텀 Webhook API
|
||||
|
||||
Flow가 인간 피드백을 위해 일시 중지되면, 요청 데이터를 자체 애플리케이션으로 보내도록 webhook을 구성할 수 있습니다. 이를 통해 다음이 가능합니다:
|
||||
|
||||
- 커스텀 승인 UI 구축
|
||||
- 내부 도구와 통합 (Jira, ServiceNow, 커스텀 대시보드)
|
||||
- 타사 시스템으로 승인 라우팅
|
||||
- 모바일 앱 알림
|
||||
- 자동화된 결정 시스템
|
||||
|
||||
### Webhook 구성
|
||||
|
||||
<Steps>
|
||||
<Step title="설정으로 이동">
|
||||
**배포** → **설정** → **Human in the Loop**으로 이동
|
||||
</Step>
|
||||
<Step title="Webhook 섹션 확장">
|
||||
**Webhooks** 구성을 클릭하여 확장
|
||||
</Step>
|
||||
<Step title="Webhook URL 추가">
|
||||
webhook URL 입력 (프로덕션에서는 HTTPS 필수)
|
||||
</Step>
|
||||
<Step title="구성 저장">
|
||||
**구성 저장**을 클릭하여 활성화
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
여러 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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 필드 참조
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="핵심 필드" icon="circle-info">
|
||||
| 필드 | 유형 | 설명 |
|
||||
|------|------|------|
|
||||
| `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 | 요청 생성 시간 |
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="응답 필드" icon="reply">
|
||||
| 필드 | 유형 | 설명 |
|
||||
|------|------|------|
|
||||
| `callback_url` | string | **피드백 제출을 위해 이 URL로 POST** (토큰 포함) |
|
||||
| `response_token` | string | 일회용 인증 토큰 (이미 callback_url에 포함) |
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="컨텍스트 필드" icon="layer-group">
|
||||
| 필드 | 유형 | 설명 |
|
||||
|------|------|------|
|
||||
| `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를 시작한 사용자 (알려진 경우) |
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="할당 및 라우팅 필드" icon="route">
|
||||
| 필드 | 유형 | 설명 |
|
||||
|------|------|------|
|
||||
| `assigned_to` | object | 사전 할당된 검토자 (있는 경우) |
|
||||
| `assigned_at` | ISO8601 | 할당된 시간 |
|
||||
| `escalated_at` | ISO8601 | 요청이 에스컬레이션된 시간 (아닌 경우 null) |
|
||||
| `routing.effective_responders` | array | 응답하도록 구성된 사용자 |
|
||||
| `routing.enforce_routing_rules` | boolean | 나열된 응답자만 응답할 수 있는지 여부 |
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
### 요청에 응답하기
|
||||
|
||||
피드백을 제출하려면 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` | 아니오 | 앱 식별자 (기록에 표시) |
|
||||
|
||||
#### 응답 예시
|
||||
|
||||
<CodeGroup>
|
||||
```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": "유효하지 않은 응답 토큰"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### 보안
|
||||
|
||||
<Info>
|
||||
모든 webhook 요청은 HMAC-SHA256을 사용하여 암호화 서명되어 진위성을 보장하고 변조를 방지합니다.
|
||||
</Info>
|
||||
|
||||
#### Webhook 보안
|
||||
|
||||
- **HMAC-SHA256 서명**: 모든 webhook에 암호화 서명이 포함됨
|
||||
- **Webhook별 시크릿**: 각 webhook은 고유한 서명 시크릿을 가짐
|
||||
- **저장 시 암호화**: 서명 시크릿은 데이터베이스에서 암호화됨
|
||||
- **타임스탬프 검증**: 리플레이 공격 방지
|
||||
|
||||
#### 응답 토큰 보안
|
||||
|
||||
- **일회용**: 토큰은 성공적인 응답 후 무효화됨
|
||||
- **256비트 엔트로피**: 토큰은 암호학적으로 안전한 랜덤 생성 사용
|
||||
- **타이밍 안전 비교**: 타이밍 공격 방지
|
||||
|
||||
#### 모범 사례
|
||||
|
||||
1. **서명 검증**: 항상 `X-CrewAI-Signature` 헤더를 검증하세요
|
||||
2. **타임스탬프 확인**: 5분 이상 된 요청은 거부하세요
|
||||
3. **시크릿 안전 저장**: 서명 시크릿을 비밀번호처럼 취급하세요
|
||||
4. **HTTPS 사용**: 프로덕션에서 webhook 엔드포인트는 TLS를 사용해야 합니다
|
||||
5. **시크릿 순환**: 대시보드를 통해 주기적으로 webhook 시크릿을 재생성하세요
|
||||
|
||||
### 통합 예제
|
||||
|
||||
<CodeGroup>
|
||||
```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 });
|
||||
});
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Webhook 서명 검증
|
||||
|
||||
모든 webhook 요청은 HMAC-SHA256을 사용하여 서명됩니다. 요청이 진본이고 변조되지 않았음을 확인하기 위해 서명을 검증해야 합니다.
|
||||
|
||||
#### 서명 헤더
|
||||
|
||||
각 webhook 요청에는 다음 헤더가 포함됩니다:
|
||||
|
||||
| 헤더 | 설명 |
|
||||
|------|------|
|
||||
| `X-CrewAI-Signature` | HMAC-SHA256 서명: `sha256=<hex_digest>` |
|
||||
| `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초) | 실패로 기록됨, 재시도 없음 |
|
||||
|
||||
### 통합 테스트
|
||||
|
||||
<Steps>
|
||||
<Step title="Webhook 구성">
|
||||
개발 엔드포인트를 가리키는 webhook 추가
|
||||
</Step>
|
||||
<Step title="로컬 개발용 터널 사용">
|
||||
로컬 개발의 경우 [ngrok](https://ngrok.com) 사용:
|
||||
```bash
|
||||
ngrok http 3000
|
||||
# HTTPS URL을 webhook 엔드포인트로 사용
|
||||
```
|
||||
</Step>
|
||||
<Step title="Flow 트리거">
|
||||
`@human_feedback` 데코레이터가 있는 flow 실행
|
||||
</Step>
|
||||
<Step title="수신 확인">
|
||||
엔드포인트가 페이로드를 수신하는지 확인
|
||||
</Step>
|
||||
<Step title="응답 제출">
|
||||
`callback_url`로 POST하여 flow 완료
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## 기타 통합 옵션
|
||||
|
||||
### 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 네이티브 검토 경험
|
||||
- **모바일 앱**: 이동 중 검토 및 승인
|
||||
|
||||
## 모범 사례
|
||||
|
||||
<Tip>
|
||||
**간단하게 시작**: 기본 승인 게이트로 시작한 다음, 워크플로우가 성숙해지면 라우팅과 SLA를 추가하세요.
|
||||
</Tip>
|
||||
|
||||
1. **명확한 검토 기준 정의**: 일관된 결정을 보장하기 위해 검토자가 무엇을 확인해야 하는지 문서화하세요.
|
||||
|
||||
2. **현실적인 SLA 설정**: 지속 가능한 워크플로우를 유지하기 위해 긴급도와 검토자 용량의 균형을 맞추세요.
|
||||
|
||||
3. **에스컬레이션을 현명하게 사용**: 품질을 유지하기 위해 진정으로 중요하지 않은 검토에만 자동 승인을 사용하세요.
|
||||
|
||||
4. **모니터링 및 반복**: 분석을 사용하여 병목 현상을 식별하고 검토자 할당을 최적화하세요.
|
||||
|
||||
5. **팀 교육**: 검토자가 자신의 역할과 사용 가능한 도구를 이해하도록 하세요.
|
||||
|
||||
## 관련 리소스
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Flow에서 인간 피드백" icon="code" href="/ko/learn/human-feedback-in-flows">
|
||||
`@human_feedback` 데코레이터 구현 가이드
|
||||
</Card>
|
||||
<Card title="Flow HITL 워크플로우 가이드" icon="route" href="/ko/enterprise/guides/human-in-the-loop">
|
||||
HITL 워크플로우 설정을 위한 단계별 가이드
|
||||
</Card>
|
||||
<Card title="RBAC 구성" icon="shield-check" href="/ko/enterprise/features/rbac">
|
||||
조직을 위한 역할 기반 접근 제어 구성
|
||||
</Card>
|
||||
<Card title="Webhook 스트리밍" icon="bolt" href="/ko/enterprise/features/webhook-streaming">
|
||||
실시간 이벤트 알림 설정
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -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
|
||||
|
||||
<Note>
|
||||
`@human_feedback` 데코레이터는 **CrewAI 버전 1.8.0 이상**이 필요합니다.
|
||||
</Note>
|
||||
|
||||
Flow에서 `@human_feedback` 데코레이터를 사용하면, CrewAI Enterprise는 인간 피드백 워크플로우를 완벽하게 제어할 수 있는 전용 **HITL 관리 UI**를 제공합니다:
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="플랫폼 내 응답" icon="reply">
|
||||
Enterprise 대시보드에서 직접 HITL 요청을 검토하고 응답하세요—webhook 설정이 필요 없습니다.
|
||||
</Card>
|
||||
<Card title="응답자 할당" icon="user-plus">
|
||||
다양한 작업 유형이나 crew에 대해 특정 팀원 또는 그룹을 응답자로 할당하세요.
|
||||
</Card>
|
||||
<Card title="권한 및 접근 제어" icon="shield-check">
|
||||
세분화된 권한 제어로 HITL 요청을 보거나, 응답하거나, 에스컬레이션할 수 있는 사람을 정의하세요.
|
||||
</Card>
|
||||
<Card title="에스컬레이션 정책" icon="arrow-up-right">
|
||||
응답이 지연되거나 상급 검토가 필요할 때 자동 에스컬레이션 규칙을 구성하세요.
|
||||
</Card>
|
||||
<Card title="SLA 관리" icon="clock">
|
||||
응답 시간에 대한 서비스 수준 계약을 설정하고 자동 알림 및 추적을 활성화하세요.
|
||||
</Card>
|
||||
<Card title="동적 라우팅" icon="route">
|
||||
콘텐츠, 우선순위 또는 사용자 정의 규칙을 기반으로 적용 정책과 함께 HITL 요청을 라우팅하세요.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Tip>
|
||||
`@human_feedback` 데코레이터의 구현 세부 사항은 [Flow에서 인간 피드백](/ko/learn/human-feedback-in-flows) 가이드를 참조하세요.
|
||||
</Tip>
|
||||
|
||||
## Webhook 기반 HITL 워크플로 설정
|
||||
|
||||
Slack, Microsoft Teams 또는 자체 애플리케이션과 같은 외부 시스템과의 커스텀 통합을 위해 webhook 기반 접근 방식을 사용할 수 있습니다:
|
||||
|
||||
<Steps>
|
||||
<Step title="작업 구성">
|
||||
@@ -99,3 +143,14 @@ HITL 워크플로우는 특히 다음과 같은 경우에 유용합니다:
|
||||
- 민감하거나 위험도가 높은 작업
|
||||
- 인간의 판단이 필요한 창의적 작업
|
||||
- 준수 및 규제 검토
|
||||
|
||||
## 자세히 알아보기
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Flow HITL 관리" icon="users-gear" href="/ko/enterprise/features/flow-hitl-management">
|
||||
할당, SLA 관리, 에스컬레이션 정책 및 분석을 포함한 전체 Enterprise Flow HITL 플랫폼 기능을 살펴보세요.
|
||||
</Card>
|
||||
<Card title="Flow에서 인간 피드백" icon="code" href="/ko/learn/human-feedback-in-flows">
|
||||
Flow에서 `@human_feedback` 데코레이터 구현 가이드.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -112,3 +112,9 @@ HITL 워크플로우는 다음과 같은 경우에 특히 유용합니다:
|
||||
- 민감하거나 고위험 작업
|
||||
- 인간의 판단이 필요한 창의적 과제
|
||||
- 컴플라이언스 및 규제 검토
|
||||
|
||||
## Enterprise 기능
|
||||
|
||||
<Card title="Flow HITL 관리 플랫폼" icon="users-gear" href="/ko/enterprise/features/flow-hitl-management">
|
||||
CrewAI Enterprise는 플랫폼 내 검토, 응답자 할당, 권한, 에스컬레이션 정책, SLA 관리, 동적 라우팅 및 전체 분석을 갖춘 Flow용 포괄적인 HITL 관리 시스템을 제공합니다. [자세히 알아보기 →](/ko/enterprise/features/flow-hitl-management)
|
||||
</Card>
|
||||
|
||||
910
docs/pt-BR/enterprise/features/flow-hitl-management.mdx
Normal file
910
docs/pt-BR/enterprise/features/flow-hitl-management.mdx
Normal file
@@ -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"
|
||||
---
|
||||
|
||||
<Note>
|
||||
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.
|
||||
</Note>
|
||||
|
||||
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
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="Revisão na Plataforma" icon="desktop">
|
||||
Revise e responda a solicitações diretamente no dashboard Enterprise
|
||||
</Card>
|
||||
<Card title="Atribuição Inteligente" icon="user-check">
|
||||
Direcione revisões para as pessoas certas com base em regras e expertise
|
||||
</Card>
|
||||
<Card title="SLA e Escalação" icon="clock">
|
||||
Garanta respostas oportunas com políticas de escalação automatizadas
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## 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:
|
||||
|
||||
<Steps>
|
||||
<Step title="Navegue até Configurações HITL">
|
||||
Vá para as configurações do seu Flow e selecione a seção de configuração "Revisão Humana".
|
||||
</Step>
|
||||
<Step title="Configure Respondentes">
|
||||
Atribua usuários individuais ou grupos como respondentes padrão para solicitações de revisão.
|
||||
</Step>
|
||||
<Step title="Defina Respondentes de Backup">
|
||||
Defina respondentes alternativos quando os designados principais não estiverem disponíveis.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/hitl-settings-1.png" alt="Configurações HITL" />
|
||||
</Frame>
|
||||
|
||||
### 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 |
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/hitl-settings-2.png" alt="Configuração de Regras de Roteamento HITL" />
|
||||
</Frame>
|
||||
|
||||
### Permissões Baseadas em Função
|
||||
|
||||
Controle quem pode visualizar, responder ou escalar solicitações HITL:
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Visualizador" icon="eye">
|
||||
Pode visualizar solicitações HITL e seu status, mas não pode responder ou tomar ações.
|
||||
</Accordion>
|
||||
<Accordion title="Respondente" icon="reply">
|
||||
Pode visualizar e responder a solicitações HITL atribuídas com decisões de aprovar/rejeitar.
|
||||
</Accordion>
|
||||
<Accordion title="Gerente" icon="user-tie">
|
||||
Pode visualizar todas as solicitações, responder, reatribuir a outros membros da equipe e sobrescrever decisões.
|
||||
</Accordion>
|
||||
<Accordion title="Admin" icon="shield">
|
||||
Acesso total incluindo configuração de regras de roteamento, SLAs e políticas de escalação.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## 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
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/hitl-list-pending-feedbacks.png" alt="Lista de Solicitações HITL Pendentes" />
|
||||
</Frame>
|
||||
|
||||
### Modos de Revisão
|
||||
|
||||
Escolha a abordagem de revisão que se adapta ao seu fluxo de trabalho:
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Bloqueio Imediato" icon="hand">
|
||||
**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.
|
||||
</Card>
|
||||
<Card title="Processamento em Lote" icon="layer-group">
|
||||
**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.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
### 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:
|
||||
|
||||
<Steps>
|
||||
<Step title="Limite de Aviso">
|
||||
Envie notificação de lembrete ao revisor atribuído (ex: em 50% do tempo de SLA).
|
||||
</Step>
|
||||
<Step title="Gatilho de Escalação">
|
||||
Escale para gerente ou revisor de backup quando o limite de SLA for atingido.
|
||||
</Step>
|
||||
<Step title="Ação Automática">
|
||||
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
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
### 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
|
||||
|
||||
<Note>
|
||||
**Integração com Slack**: Notificações diretas do Slack para solicitações HITL em breve.
|
||||
</Note>
|
||||
|
||||
## 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:
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/hitl-metrics.png" alt="Dashboard de Métricas HITL" />
|
||||
</Frame>
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Conformidade com SLA" icon="chart-line">
|
||||
Acompanhe a porcentagem de revisões concluídas dentro dos limites de SLA.
|
||||
</Card>
|
||||
<Card title="Tempos de Resposta" icon="stopwatch">
|
||||
Monitore tempos de resposta médios e medianos por revisor, equipe ou flow.
|
||||
</Card>
|
||||
<Card title="Tendências de Volume" icon="chart-bar">
|
||||
Analise padrões de volume de revisão para otimizar capacidade da equipe.
|
||||
</Card>
|
||||
<Card title="Distribuição de Decisões" icon="chart-pie">
|
||||
Visualize taxas de aprovação/rejeição em diferentes tipos de revisão.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
### 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
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Revisões de Segurança" icon="shield-halved">
|
||||
**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
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Aprovação de Conteúdo" icon="file-lines">
|
||||
**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
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Aprovações Financeiras" icon="money-bill">
|
||||
**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
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Verificações de Conformidade" icon="clipboard-check">
|
||||
**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
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Garantia de Qualidade" icon="magnifying-glass">
|
||||
**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
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## 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
|
||||
|
||||
<Steps>
|
||||
<Step title="Navegue até Configurações">
|
||||
Vá para **Deployment** → **Settings** → **Human in the Loop**
|
||||
</Step>
|
||||
<Step title="Expanda a Seção Webhooks">
|
||||
Clique para expandir a configuração de **Webhooks**
|
||||
</Step>
|
||||
<Step title="Adicione sua URL de Webhook">
|
||||
Digite sua URL de webhook (deve ser HTTPS em produção)
|
||||
</Step>
|
||||
<Step title="Salve a Configuração">
|
||||
Clique em **Salvar Configuração** para ativar
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
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
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Campos Principais" icon="circle-info">
|
||||
| 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 |
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Campos de Resposta" icon="reply">
|
||||
| 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) |
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Campos de Contexto" icon="layer-group">
|
||||
| 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) |
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Campos de Atribuição e Roteamento" icon="route">
|
||||
| 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 |
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
### 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
|
||||
|
||||
<CodeGroup>
|
||||
```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"
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Segurança
|
||||
|
||||
<Info>
|
||||
Todas as requisições de webhook são assinadas criptograficamente usando HMAC-SHA256 para garantir autenticidade e prevenir adulteração.
|
||||
</Info>
|
||||
|
||||
#### 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
|
||||
|
||||
<CodeGroup>
|
||||
```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 });
|
||||
});
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### 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=<hex_digest>` |
|
||||
| `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
|
||||
|
||||
<Steps>
|
||||
<Step title="Configure o Webhook">
|
||||
Adicione um webhook apontando para seu endpoint de desenvolvimento
|
||||
</Step>
|
||||
<Step title="Use um Túnel para Dev Local">
|
||||
Para desenvolvimento local, use [ngrok](https://ngrok.com):
|
||||
```bash
|
||||
ngrok http 3000
|
||||
# Use a URL HTTPS como seu endpoint de webhook
|
||||
```
|
||||
</Step>
|
||||
<Step title="Dispare um Flow">
|
||||
Execute um flow com um decorador `@human_feedback`
|
||||
</Step>
|
||||
<Step title="Verifique o Recebimento">
|
||||
Confirme que seu endpoint recebeu o payload
|
||||
</Step>
|
||||
<Step title="Envie a Resposta">
|
||||
Faça POST para a `callback_url` para completar o flow
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## 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
|
||||
|
||||
<Tip>
|
||||
**Comece Simples**: Comece com portões de aprovação básicos, depois adicione roteamento e SLAs conforme seus fluxos de trabalho amadurecem.
|
||||
</Tip>
|
||||
|
||||
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
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Feedback Humano em Flows" icon="code" href="/pt-BR/learn/human-feedback-in-flows">
|
||||
Guia de implementação para o decorador `@human_feedback`
|
||||
</Card>
|
||||
<Card title="Guia de Workflow HITL para Flows" icon="route" href="/pt-BR/enterprise/guides/human-in-the-loop">
|
||||
Guia passo a passo para configurar workflows HITL
|
||||
</Card>
|
||||
<Card title="Configuração RBAC" icon="shield-check" href="/pt-BR/enterprise/features/rbac">
|
||||
Configure controle de acesso baseado em função para sua organização
|
||||
</Card>
|
||||
<Card title="Streaming de Webhook" icon="bolt" href="/pt-BR/enterprise/features/webhook-streaming">
|
||||
Configure notificações de eventos em tempo real
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -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
|
||||
|
||||
<Note>
|
||||
O decorador `@human_feedback` requer **CrewAI versão 1.8.0 ou superior**.
|
||||
</Note>
|
||||
|
||||
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:
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Resposta na Plataforma" icon="reply">
|
||||
Revise e responda a solicitações HITL diretamente no dashboard Enterprise—sem necessidade de configuração de webhook.
|
||||
</Card>
|
||||
<Card title="Atribuição de Respondentes" icon="user-plus">
|
||||
Atribua membros específicos da equipe ou grupos como respondentes para diferentes tipos de tarefas ou crews.
|
||||
</Card>
|
||||
<Card title="Permissões e Controle de Acesso" icon="shield-check">
|
||||
Defina quem pode visualizar, responder ou escalar solicitações HITL com controles de permissão granulares.
|
||||
</Card>
|
||||
<Card title="Políticas de Escalação" icon="arrow-up-right">
|
||||
Configure regras de escalação automática quando as respostas atrasarem ou exigirem revisão sênior.
|
||||
</Card>
|
||||
<Card title="Gerenciamento de SLA" icon="clock">
|
||||
Defina Acordos de Nível de Serviço para tempos de resposta com notificações e rastreamento automáticos.
|
||||
</Card>
|
||||
<Card title="Roteamento Dinâmico" icon="route">
|
||||
Roteie solicitações HITL com base em conteúdo, prioridade ou regras personalizadas com políticas de aplicação.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Tip>
|
||||
Para detalhes de implementação do decorador `@human_feedback`, consulte o guia [Feedback Humano em Flows](/pt-BR/learn/human-feedback-in-flows).
|
||||
</Tip>
|
||||
|
||||
## 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:
|
||||
|
||||
<Steps>
|
||||
<Step title="Configure Sua Tarefa">
|
||||
@@ -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
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Gerenciamento HITL para Flows" icon="users-gear" href="/pt-BR/enterprise/features/flow-hitl-management">
|
||||
Explore os recursos completos da plataforma HITL para Flows, incluindo atribuição, gerenciamento de SLA, políticas de escalação e análises.
|
||||
</Card>
|
||||
<Card title="Feedback Humano em Flows" icon="code" href="/pt-BR/learn/human-feedback-in-flows">
|
||||
Guia de implementação para o decorador `@human_feedback` em seus Flows.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -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
|
||||
|
||||
<Card title="Plataforma de Gerenciamento HITL para Flows" icon="users-gear" href="/pt-BR/enterprise/features/flow-hitl-management">
|
||||
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)
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user