中文 / EN
Press ↓ to explore

From Low-Code to Pro-Code

How developers wield Dify for LLM apps

Dify x PUPU · Open, observable, extensible intelligent workflows and plugin ecosystem.

Zheng Li · Head of Open Source Ecosystem @ Dify
2025 / Sharing Deck

Agenda

From Low‑Code to Pro‑Code: connect orchestration, engineering guardrails, ecosystem, triggers, and observability into a production loop.

Part Module Focus
01 Breakthrough Pain points · positioning · why now
02 Fusion Visual DSL ↔ Pro‑Code · debugging view · collaboration
03 Extension Plugins & Marketplace · tooling security · reuse
04 Connection Triggers · types & matrix · hands-on cases
05 Observability OpenTelemetry · multi-DB · cost/perf visibility
06 Summary Evolution path · call to action

Breaking the mold · Next-gen LLM app paradigm

Start from pain points; map Dify's role.

Paradigm shift

Community-driven · globally adopted

Top-100 GitHub repo by stars.

Install 1M+ Powered by Dify
Popularity 120K+ GitHub Stars
Reach 150+ Countries
Enterprise 60+ Industries
Contributors 1000+ Open-source contributors
Downloads 550M+ Total downloads

1.0 Demo: RAG + Guardrails

30 mins build: preprocess → retrieve → guardrail → return.

Preprocess 10 min

Chunk + clean, push vectors.

# python node\nchunks = split(doc, size=400)\nstore(chunks)
Retrieve + Guardrail 14 ms

Top-k + safety filter.

RAG → LLM → Regex/blacklist → out
Return & observe Replay

Write back; Trace ID to APM/logs.

Trace: workflow.run
Token: 115 / req
Cost: $0.0017

1.0 Flow animation: Chaos → Clarity

Inputs
  • Raw logs / documents
  • Event payloads
  • Custom features
Normalize → Vectorize → Route
Guardrail + policy check
Outputs
  • Response / callback
  • Metrics: p99, token, cost
  • Trace link to APM/Logs

1.1 Pain points today

The surface is “missing pieces”; the root is “engineering gaps”.

Fragmented interfaces
invoke / bill / monitor
Slow iteration
isolation / canary
Collaboration friction
assets / reuse
Production gaps
audit / retry / quota
Pain points

1.2 Dify's position

One-stop LLM app platform: build, orchestrate, operate.

Orchestration

Workflow / Prompt Studio / RAG pipeline.

Engineering

Retries, branching, quotas, env isolation.

Extension

Plugins & tools to connect external systems.

Observability

Tracing / token / cost visibility keeps prod stable.

Positioning

1.3 Why Now?

The Tipping Point: Compute, Models, and Data align.

2017
Transformer
Attention is all you need
2020
GPT-3
Few-shot learning emerges
2025.2
Dify v1.0
LLM middleware born
2025.11
Pro-Code
Production, Standards, Engineering

1.4 Traditional vs AI-Native

From deterministic programming to probabilistic engineering.

Traditional Dev
  • Core Logic Deterministic
    If-Then-Else control
  • Data Structured (SQL/JSON)
    Schema first
  • Testing Unit Tests (Pass/Fail)
    Coverage metrics
Next Gen
AI-Native Dev
  • Core Logic Probabilistic
    Prompt + Context guided
  • Data Unstructured (Embedding)
    Semantic retrieval
  • Testing Evaluation (Eval)
    Accuracy, Hallucination, Relevance

1.5 Dify Ecosystem Landscape

The "Operating System" for LLM apps, connecting models to business.

End Users
External Systems
Chat Bots
Agent Assistants
Workflow Automation
Dify Core Engine
Orchestration
RAG Pipeline
Plugin Runtime
Observability
LLMs
Vector DBs
Compute

Fusion · Busting the "low-code" stereotype

Visual DSL is an abstraction of pro engineering, not a toy.

Visual DSL

2.1 Visual dialectic

Both camps need visualization, for different reasons:

Low‑Code Pro‑Code
Role of visual Programming language Abstraction + debugging view
Primary goal Lower cognitive load
Explainable, teachable
Understand complex DSLs faster
Comparable, replayable
What it surfaces Runnable logic Engineering facts
(Trace / Tokens / Variables)
See · Compare · Explain · Move fast
Workflow as DSL

2.1 Dual track: DSL ↔ Code node

Same logic, two forms, co-evolving.

Workflow canvas
  • Mapping: retrieve → LLM → branch
  • Visual breakpoints: latency, retries, sampling
  • Business-readable for product/ops
Code node (Python)
def handler(payload):
    country = payload["country"]
    score = risk_model.predict(payload)
    if country == "US" and score < 0.2:
        return {"route": "fast-lane"}
    return {"route": "human-review", "score": score}
Outputs auto-bind to downstream nodes

2.2 Best practice: high-density development

Let visual DSL handle 80% glue logic; use pro-code for the 20% heavy lifting.

Visual orchestration

Branches, loops, RAG pipelines—align fast with biz needs.

Code nodes

Embed Python/Node scripts for data cleaning and math.

Feedback loop

Trace IDs stitch logs; iterate prompts + code from evidence.

2.3 Debug view: vars + logs

Variable snapshot

Node-level input/output diff with highlights.

user_id: 91283 → 91283
country: CN → US (flag)
Tokens & cost
  • Prompt Tokens: 320
  • Completion Tokens: 88
  • Cost: $0.0009 / req
Logs & trace

Follow Trace ID to Jaeger / SLS.

trace_id=wf-1827 span=llm.call status=ok p95=180ms

2.4 Prompt Engineering as Code

Manage Prompts like Code: Versioning and Diffing.

prompts/customer_service.yaml v2.1.0
system_prompt: |
You are a helpful assistant.
# Context variables
Current User: {{ user_name }}
History: {{ conversation_history }}
parameters:
temperature: 0.7
model: gpt-4-turbo
Version Diff
- model: gpt-3.5-turbo
+ model: gpt-4-turbo
Updated by @zhengli 2 hours ago

2.5 Team Collaboration

Breaking silos between Prompt Engineers and Developers.

Admin

Infrastructure

  • • Model Provider Config
  • • API Key Management
  • • Vector DB Ops
Builder

App Developer

  • • Prompt Debugging
  • • Workflow Design
  • • Release & Versioning
Operator

Business Ops

  • • Log Review & Annotation
  • • Performance Feedback
  • • Knowledge Base Uploads

2.6 Complex Logic Orchestration

Beyond linear flows: Loops, Iterations, and Conditionals.

Start
Input Check
Iteration Node
Item A
LLM Process
Result
If / Else
Pass Fail

Extension · Build your arsenal

Marketplace & plugins make Dify platform-ready.

Plugin market

3.1 Dify plugin architecture

Standard APIs, auth, and multi-language runtimes.

Runtime

Isolated execution with timeout and retry control.

Auth

API Key / OAuth / internal credentials.

Billing

Pluggable quotas and metering.

Packaging

Marketplace publishing and versioning.

Plugin architecture

3.1 Call example: Slack bot plugin

Request (cURL)
curl -X POST https://api.dify.ai/plugins/slack_bot \\
  -H "Authorization: Bearer <token>" \\
  -d '{
    "channel_id": "ops-alert",
    "text": "Build passed ✅",
    "bot_token": "******"
  }'
Response & observability
  • status: success
  • message_ts: 171103.23
  • trace_id: plugin-9821 (jump to logs)
180ms
p95
0.0003
Cost $
99.9%
Success

3.2 Release pipeline · 4 steps

1
Define

manifest + schema

2
Build

code node / runtime

3
Verify

local + sandbox

4
Ship

Marketplace / internal

3.2 Example: Slack bot tool

"Definition is development": manifest + simple code.

🗂️ Manifest (YAML): Describe metadata and parameters (bot_token, channel_id).
💻 Implementation (Python): Extend Tool, send message via Slack SDK in _invoke.
Ship: Test locally, then publish to Dify Marketplace.
manifest.yaml
main.py
identity:
name: slack_bot
label: { en_US: Slack Bot }
parameters:
# Inputs: token + channel
- name: bot_token
type: secret-input
- name: channel_id
type: string
- name: text
type: string
// main.py preview
class SlackBotTool(Tool):
def _invoke(self, params: dict):
# get credentials
token = params.get('bot_token')
client = WebClient(token=token)
# call SDK
res = client.chat_postMessage(
channel=params.get('channel_id'),
text=params.get('text')
)
return { "result": res.data }

3.3 Tool Security & Sandboxing

Trust no code. Isolation is key for platform stability.

Unsafe Zone

3rd-party Plugin Code
Arbitrary Network Calls
High Resource Usage

gRPC / Socket

Safe Sandbox

Namespace Isolation
Resource Quotas
Network Whitelist

3.4 Advanced: Tools calling Workflows

Agentic Behavior: Plugins are not just executors, but deciders.

# plugin_logic.py: Plugin decides to call another workflow

def _invoke(self, params):
    user_intent = analyze_intent(params['input'])
    
    if user_intent == 'complex_task':
        # Reverse call back to Dify API
        response = dify_client.run_workflow(
            workflow_id="wf-sub-task-001",
            inputs={"query": params['input']},
            user_id=params['user_id']
        )
        return {"result": response['data'], "delegated": True}
        
    return {"result": simple_process(params), "delegated": False}
                            

3.5 Marketplace Economy

Connecting developers and enterprises for shared value.

👩‍💻

Creators

Build high-quality tools
Publish to Marketplace
Revenue share

🚀

Platform

Distribution channel
Billing & Settlement
Security review

🏢

Consumers

One-click install
SaaS Subscription
Solve business pain

Connection · Event-driven automation

Triggers move apps from passive Q&A to proactive execution.

Event automation

4.1 What triggers change

  • Passive response: wait for user questions; context + timeliness missing.
  • Active execution: events fire workflows to take action.
Trigger flow

4.1 Animation: event → workflow

Event sources
  • Webhook: /orders/created
  • Plugin: GitHub PR
  • Schedule: cron(0/10 * * *)
Event → var mapping → branch
LLM routing + retries
Callback / DB / notify
Observability
  • Trace ID: trig-2039
  • p95: 420ms
  • Rules: version v2.1

4.2 Demo flow

Webhook → Dify parses payload → LLM routes → action out.

Webhook

Receive external event, verify signature.

LLM routing

Choose model/path based on context.

Action

Call plugins/tools, write output.

Observe

Tracing + token/cost.

Trigger workflow

4.3 Why triggers matter

Bring “when to start” back to the orchestration layer.

Without triggers With triggers
Scattered entrypoints: buttons / cron / direct calls Unified entry: event source → mapping → routing
Hard to govern: no trace, hard to debug Governable: replayable, observable, auditable
Start conditions live in scripts/code Start conditions live in the workflow canvas
Trigger logic hard to reuse One canvas: branch first, merge later

4.4 Trigger types (v1.10.0)

Covers schedules, third-party events, and in-house systems.

Schedule Trigger

Run at fixed cadence: reports, cleanup, health checks.

Plugin Trigger

Third-party events: PR updates, ticket changes, docs edits. One subscription can drive multiple workflows.

Webhook Trigger

For your systems. Unique URL per trigger; query/header/body map to variables; optional callback with workflow result.

4.4 Use-case matrix

Real-time
High complexity
Batch
Standardized
Alerting
Prom → Trigger → Slack
Code review
PR → plugin trigger → summary
RAG replay
KB update → rerun → diff
CRM automation
Lead → workflow → email/ticket
Content safety
Webhook → multimodal → ban
E-commerce
Order → LLM route → fulfillment

4.5 Example: GitHub PR auto-review

Plugin trigger + LLM = automated code review loop.

🛰️ Subscribe
GitHub trigger, non-draft PRs to main.
t0
📥 Variables
Payload → action/pull_request/repo/sender.
t0+30ms
🤖 LLM review
Summarize diff; auto-comment / request changes / trigger CI.
t0+180ms

4.6 Tech Deep Dive: High Concurrency Event Bus

Ensuring zero event loss and non-blocking execution.

External Sources
API Gateway
Validation & Auth
MQ
Redis Broker
FIFO Queue
Celery Worker
Workflow Execution

4.7 Real-world Case: Smart Support Routing

From email ingress to auto-classification and human loop.

1

Email Trigger

Customer emails support@company.com → Webhook fires Dify.

2

Intent Classification (LLM)

Analyze content: "Refund", "Technical Issue", or "General"?

Refund
Call Stripe Plugin to check status
Technical
Retrieve RAG KB for solutions
3

Human-in-the-loop

Draft reply → Send to Slack for approval → Click to send.

Observability · Open-source rigor

Transparent, traceable, portable engineering.

Open insight

5.1 OTEL End-to-End Tracing

Not just logs—one trace across LLM + infra.

Trace Link
Workflow App
Trace ID: T-1001
HTTP Header
Propagation
API / Worker
● Monkey Patch
Plugin Daemon
● Compile Probe
Redis PostgreSQL VectorDB

Tech Deep Dive: Non-invasive Probes

Dify ships fast—so probes must be non-invasive.

Approach

  • API / Worker (Python): Monkey patch Flask/Celery entry to inject trace context.
  • Plugin daemon (Go): Compile-time instrumentation in Dockerfile.
  • Trace link: Propagate TraceID via HTTP headers; stitch app + infra.
entrypoint.sh
# Python bootstrap
if [ "$DEBUG" = "true" ]; then
exec flask run ...
else
# inject aliyun-instrument
exec aliyun-instrument gunicorn \
--bind ... \
--workers ... \
app:app
fi
// Go Dockerfile instrumentation
RUN wget .../instgo-linux-amd64 -O instgo
RUN ./instgo go build -o main cmd/server/main.go

5.1 Deep Dive: Python Monkey Patch

aliyun-instrument uses wrapt to hook into Dify's core methods at runtime.

Core Mechanism

  • Dynamic Replacement: When modules load, target functions (e.g. WorkflowRunner.run) are swapped with a wrapper.
  • Transparent Context: wrapt ensures metadata (like __name__) is preserved, keeping it invisible to business logic.
  • Exception Passthrough: Errors are captured as Span Events and then re-raised.
# Pseudo-code: Dify Instrumentation Logic
import wrapt
from opentelemetry import trace

def _instrument(self, **kwargs):
# 1. Locate and hook target
wrapt.wrap_function_wrapper(
"dify.core.workflow.runner", # Module
"WorkflowRunner.run", # Method
self._trace_wrapper # Hook
)

def _trace_wrapper(self, wrapped, instance, args, kwargs):
tracer = trace.get_tracer("aliyun.dify")
# 2. Start Span
with tracer.start_as_current_span("workflow.run") as span:
# 3. Record inputs
span.set_attribute("user_id", kwargs.get("user_id"))

# 4. Execute original logic
result = wrapped(*args, **kwargs)

# 5. Return result
return result

5.1 Sampling & throttling

Dynamic sampling

Per-span rates: LLM 20%, vector search 50%, critical transactions 100%.

Token-aware throttling

Adjust prompt length + concurrency by queue depth and TPS.

Escalate on errors

Error >1% → sample 100% and enable debug logs.

5.2 Troubleshooting story: the "ghost" error

Frontend looks fine but RAG returns empty; no app logs.

Spot the symptom

Workflow trace shows retriever runs fast and returns empty string.

Follow the link

Click "infrastructure link" on span to open SLS/Jaeger with TraceID.

Root cause

One shard of vector DB timed out; retry policy missing. Add retry + fallback and redeploy.

5.2 Database Flexibility: Architecture Decoupling

  • DB_TYPE Support: DatabaseConfig adds PostgreSQL, MySQL, OceanBase.
  • Dynamic Engine: SQLAlchemy URI and Engine Options adjust automatically.
  • Config Update: Removed OceanBase specific vector configs; unified management.

Example (.env)

# Select Database Type
DB_TYPE=mysql
# MySQL Configuration
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_USER=dify_user
Dify API / Worker
SQLAlchemy Engine Factory
Postgres
MySQL
OceanBase

5.2 Performance dashboard

410 ms
p95 latency
0.0021
$/Request
incl. RAG + LLM
99.96%
Success
last 7d
Hot spans
  • workflow.run → 35%
  • retriever.query → 22%
  • llm.call → 18%
Actions
  • Shard vector DB to cut tail latency
  • Prompt cache hit +12%
  • Async callbacks reduce API blocking

5.3 Quality Assurance: Matrix CI/CD

To ensure Schema compatibility across dialects, we introduced independent migration tests for MySQL.

  • GitHub Actions Refactor: Separate Postgres & MySQL services.
  • Migration Test Job: Run full Alembic migrations on MySQL to catch syntax errors.
  • Compatibility Redline: Schema changes must pass on both DBs.
Pull Request
Matrix Strategy
Job: test-api (Postgres)
Job: migration-test (MySQL)

5.4 Code Refactoring: SQL Abstraction

Replacing dialect-specific Raw SQL with Python Helpers & ORM.

Portable Date Functions

convert_datetime_to_date wraps truncation logic (Postgres date_trunc vs MySQL date_format).

# api/controllers/console/app/statistic.py
def convert_datetime_to_date(column):
if db.engine.name == 'postgresql':
return func.date_trunc('day', column)
return func.date(column)

Metadata Filter Standardization

dataset_retrieval.py removes Raw SQL, using SQLAlchemy JSON methods for type safety.

- sql += f"meta->>'{key}' = '{value}'"
+ filter_conditions.append(
+ Dataset.meta[key].as_string() == value
+ )

5.5 Cost Analysis & Optimization

Granular operations: Know where every penny goes.

Total Cost $4,281
LLM Inference
GPT-4, Claude 3 (60%)
$2,568
Vector DB
Storage & Indexing (25%)
$1,070
Embedding
Text-to-Vector (15%)
$643

Summary · LLM app evolution

Unified orchestration + guardrails + ecosystem + triggers → observable, evolvable production AI.

Phase 1 · Paradigm shift
Visual DSL + code nodes shrink idea-to-ship.
Week 1
Phase 2 · Guardrails
Retries, branches, quotas, observability keep it safe.
Week 2
Phase 3 · Ecosystem & triggers
Marketplace / plugins / triggers open external power.
Week 3
Phase 4 · Data & evolution
OTEL + multi-DB abstraction; tune cost/perf continuously.
Ongoing

Thank you

Call for action: Share your use case, contribute plugins/cases, build the ecosystem together.
banana@dify.ai
Xiaohongshu QR
Xiaohongshu
Bilibili QR
Bilibili