Dify is a good environment for building LLM applications, but assembling a non-trivial workflow by hand takes time. I wanted to see whether LangChain and LangGraph could generate Dify’s workflow DSL, validate it, and loop back for another attempt when the result was not good enough.
This was an experiment, not an autonomous software factory. That distinction becomes important around the moment your YAML generator develops opinions.
Model the generator as a state machine #
The useful part of LangGraph here is not “agents” as a magic word. It is explicit control flow. The graph has three nodes:
workflow_generatorproduces a Dify workflow.checkevaluates the generated workflow.ask_operatorlets a human approve the result or send it back with feedback.
If the check passes, the graph ends. If it fails, an operator reviews it. Approval ends the run; rejection returns the state to the generator. That gives us a generation → validation → feedback loop without hiding the transitions in a heroic prompt.
def create_workflow_graph(generator: WorkflowGenerator) -> StateGraph:
workflow = StateGraph(State)
workflow.add_node("workflow_generator", generator.generate_workflow)
workflow.add_node("check", generator.check_workflow)
workflow.add_node("ask_operator", ask_operator)
workflow.set_entry_point("workflow_generator")
workflow.add_edge("workflow_generator", "check")
workflow.add_conditional_edges(
"check",
lambda state: state.current_judge,
{True: END, False: "ask_operator"},
)
workflow.add_conditional_edges(
"ask_operator",
lambda state: state.operator_approved,
{True: END, False: "workflow_generator"},
)
return workflow.compile()Compared with calling the Anthropic API directly, the graph makes retries, quality checks, and error handling easier to see and reason about. The costs are equally unsurprising: more setup, and another abstraction for the team to learn. A state machine is wonderful when you have state. For a single request, it is just furniture.
Run the experiment #
The source is available in the DifyWorkFlowGenerator repository:
git clone https://github.com/Tomatio13/DifyWorkFlowGenerator.git
cd DifyWorkFlowGenerator
pip install langchain langchain-anthropic langgraph pydantic pyyaml
export ANTHROPIC_API_KEY="your-api-key"
python difyDslGenCheck.pyPlace workflow_generator_prompt.yml at the project root before running the script.
The prompt did not become elegantly small #
The original plan was to compose several short prompts: generate one part, check it, then continue. That fits LangGraph’s shape and sounds pleasantly architectural on a whiteboard.
In practice, Dify’s complete DSL specification had to remain in context or the model produced invalid output. The implementation therefore depends on one large prompt and Claude 3 Sonnet’s context window. Attempts to make the process more granular made the output worse, so I stopped. This is worth saying plainly: “we tried the elegant design and it failed” is engineering data, not an apology.
The project still delivered the important learning. Treat generation, validation, and human approval as distinct states. Make retries visible. Keep an escape hatch for an operator. Even if the prompt remains chunky, the system around it does not have to be.