Define workflows using natural language
When working with Workflows, you have to write code to handle an event in the workflow.
Often, the logic of the handler is not too complex so that it can be expressed using natural language and executed by an LLM.
Besides the instructions, we just need the expected result event of the step, possible tool calls and optionally other events that can be emitted.
Usage
Let's take an example of a workflow that generates a joke, gets a critique for it, and then improves it.
Define the events
First, we define the events for our workflow. We need one for writing the joke, one for critiquing it, and one for the final result:
import { z } from "zod";
import { zodEvent } from "@llamaindex/workflow";
const writeJokeSchema = z.object({
description: z
.string()
.describe("The topic to write a joke or describe the joke to improve."),
writtenJoke: z.optional(z.string()).describe("The written joke."),
retriedTimes: z
.number()
.default(0)
.describe(
"The retried times for writing the joke. Always increase this from the input retriedTimes.",
),
});
const critiqueSchema = z.object({
joke: z.string().describe("The joke to critique"),
retriedTimes: z.number().describe("The retried times for writing the joke."),
});
const finalResultSchema = z.object({
joke: z.string().describe("The joke to critique"),
critique: z.string().describe("The critique of the joke"),
});
const writeJokeEvent = zodEvent(writeJokeSchema, {
debugLabel: "writeJokeEvent",
});
const critiqueEvent = zodEvent(critiqueSchema, {
debugLabel: "critiqueEvent",
});
const finalResultEvent = zodEvent(finalResultSchema, {
debugLabel: "finalResultEvent",
});
Note that your natural language workflows the events need to be created by the zodEvent
function passing the zod schema as an argument. The agent needs the schema of the event data to correctly generate events.
Also, we need a debugLabel
so the LLM can identify the event to emit in the workflow.
Define the workflow
As usual you first create the workflow:
import { agentHandler, createWorkflow } from "@llamaindex/workflow";
const jokeFlow = createWorkflow();
Then you need to handle the events. For the handlers, instead of code, you're now going to use natural language by calling the agentHandler
function.
It only requires two parameters:
instructions
: A prompt to guide the agent how to handle the steps.results
: The output events that the agent should return after handling the step.
Then you will have a simple code to handle the step:
jokeFlow.handle(
[writeJokeEvent],
agentHandler({
instructions: `You are a joke writer. You are given a topic and you need to write a joke about it.`,
results: [critiqueEvent],
}),
);
jokeFlow.handle(
[critiqueEvent],
agentHandler({
instructions: `
You are given a joke and you need to critique it. Follow the following guidelines:
1. You have maximum 3 times to improve the joke.
2. If the joke is not good, increase the retriedTimes, describe how to improve the joke and send a writeJokeEvent.
3. If the joke is good, trigger the finalResultEvent event.
`,
results: [writeJokeEvent, finalResultEvent],
}),
);
For advanced usage, you can add more functionality to agentHandler
by using these parameters:
events
: A list of additional events that the agent can emit to the workflow. E.g., your agent can emit auiEvent
to update the UI during the execution.tools
: A list of tools that the agent can use to handle the step. E.g., your agent can use asearch
tool to search the web.
You can find more code examples in the examples folder.
Last updated on