Dify × Slack Integration: Connecting AI Agents with Lambda
Hi, I’m Dang, an AI engineer at Knowledgelabo, Inc. We provide a service called "Manageboard", which supports our clients in aggregating, analyzing, and managing scattered internal business data. Manageboard is set to enhance its AI capabilities in the future.
In this article, I’ll introduce the challenges we encountered when integrating Slack with Dify via AWS Lambda and how we addressed them.
Background and Architecture
The open-source LLM platform Dify allows you to build AI agents without code and supports Slack integration. However, when the built-in Slack integration doesn’t work, the following structure can be used instead:
Reference: DifyとSlackを連携したSlack Botをつくってみた
Main Challenges and Solutions
When AI agents grow more complex due to features such as file input/output, several challenges arise. It’s important to understand common issues and how to solve them in advance.
File Upload/Download with Slack
Receiving Files
Slack events include file URLs. You can retrieve the files by accessing the URL with a token.
def lambda_handler(event, context):
body = json.loads(event["body"])
event_data = body.get("event", {})
files = event_data.get("files", "")
num_of_files = len(files)
file_contents = []
for idx in range(num_of_files):
file_url = files[idx]["url_private_download"]
file_response = requests.get(
file_url,
headers={
"Authorization": f"Bearer {os.environ.get('SLACK_TOKEN')}"
}
)
file_contents.append(file_response.content)
Sending Files
Since the files.upload API is deprecated, use the following three steps instead:
- Get an upload URL using
files.getUploadURLExternal - Upload the file to that URL
- Complete the upload using
files.completeUploadExternal
# Step 1
url_response = requests.get(
"https://slack.com/api/files.getUploadURLExternal",
headers={
"Authorization": f"Bearer {os.environ.get('SLACK_TOKEN')}",
"Content-Type": "application/x-www-form-urlencoded"
},
params={
"filename": "result.csv",
"length": str(len(content_bytes))
}
)
response_json = url_response.json()
upload_url = response_json["upload_url"]
file_id = response_json["file_id"]
# Step 2
requests.post(
upload_url,
data=content_bytes,
headers={
"Content-Type": "application/octet-stream"
}
)
# Step 3
channel = event_data.get("channel", "")
thread_ts = event_data.get("thread_ts", "")
requests.post(
"https://slack.com/api/files.completeUploadExternal",
headers={
"Authorization": f"Bearer {os.environ.get('SLACK_TOKEN')}",
"Content-Type": "application/json"
},
json={
"channel_id": channel,
"initial_comment": "",
"thread_ts": thread_ts,
"files": [{"id": file_id, "title": "result.csv"}]
}
)
Duplicate Slack Event Triggers
If Slack detects a delay in processing, it may retry the same event. In addition, when specifying the URL for “Event Subscriptions,” a challenge request will occur. To avoid duplicate processing, use pre-checks like this:
def lambda_handler(event, context):
body = json.loads(event["body"])
if (body.get("challenge")):
return {
"statusCode": 200,
"body": "challenge ignored"
}
if (event["headers"].get("x-slack-retry-num")):
return {
"statusCode": 200,
"body": "retry ignored"
}
Reference: Events API
Lambda Library Dependencies
On AWS Lambda, even common libraries like requests need to be added manually.
Option 1: Use Lambda Layers
- Zip the package and register it as a Layer
- Easy and lightweight, but may cause environment-related errors
Reference: Working with layers for Python Lambda functions
Option 2: Use a Container Image (ECR)
- Use Docker to install required packages
- Ensures consistency across development and production environments, though setup is more complex
Reference: Deploy Python Lambda functions with container images
Uploading Files to Dify
The Dify Workflow API does not support direct file sending. You must first upload the file, then pass the file ID to the workflow.
# Upload file
upload_response = requests.post(
upload_url,
headers={
"Authorization": f"Bearer {os.environ.get('DIFY_API_KEY')}"
},
files={
"file": (file_name, file_content, mimetype)
}
)
file_id = upload_response.json().get("id")
# Call workflow
flow_response = requests.post(
workflow_url,
headers={
"Authorization": f"Bearer {os.environ.get('DIFY_API_KEY')}",
"Content-Type": "application/json"
},
json={
"response_mode": "blocking",
"user": user,
"inputs": {
"file": {
"transfer_method": "local_file",
"upload_file_id": file_id,
"type": filetype # e.g., "document", "image"
},
"message": "" # Optional input text
}
}
)
Conclusion
To connect Slack with Dify, no-code tools alone aren’t enough. Intermediary processing using services like Lambda is necessary. By carefully handling file processing and event management, you can build more flexible and stable AI workflows.
Discussion