Skip to content

Commit 0f9bcdb

Browse files
JoshuaL3000pre-commit-ci[bot]xiguiwchensuyueZePan110
authored andcommitted
Workflow executor example workflow API (opea-project#1102)
Signed-off-by: JoshuaL3000 <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: xiguiw <[email protected]> Co-authored-by: chen, suyue <[email protected]> Co-authored-by: ZePan110 <[email protected]> Signed-off-by: alexsin368 <[email protected]>
1 parent 2826158 commit 0f9bcdb

20 files changed

+594
-50
lines changed

WorkflowExecAgent/README.md

Lines changed: 88 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,51 @@
11
# Workflow Executor Agent
22

3+
## Quick Start: Key Configuration Variables
4+
5+
Before proceeding, here are some key configuration variables needed for the workflow executor agent.
6+
7+
- **SDK_BASE_URL**: The URL to your platform workflow serving API.
8+
9+
Example: `http://<your-server-ip>:5000/`
10+
11+
This is where the agent will send workflow execution requests.
12+
13+
- **SERVING_TOKEN**: The authentication bearer token which is used in the `RequestHandler` class as `api_key`. This is used for authenticating API requests. 3rd party platforms can design their serving workflow API this way for user authentication.
14+
15+
More details can be found in the code [handle_requests.py](tools/utils/handle_requests.py#L23)
16+
17+
> **How to get these values:**
18+
>
19+
> - If you are using the provided example workflow API, refer to the test [README.md](tests/README.md)
20+
> - For your own platform, refer to your API documentation or administrator for the correct values. If you are a platform provider you may refer to [Workflow Building Platform](#workflow-building-platform) section for prerequisites on setting up a serving workflow.
21+
22+
For more info on using these variables, refer to the [Microservice Setup](#microservice-setup) section below on using the [Example Workflow API](tests/example_workflow/) for a working example.
23+
24+
Set these variables in your environment before starting the service.
25+
326
## Overview
427

528
GenAI Workflow Executor Example showcases the capability to handle data/AI workflow operations via LangChain agents to execute custom-defined workflow-based tools. These workflow tools can be interfaced from any 3rd-party tools in the market (no-code/low-code/IDE) such as Alteryx, RapidMiner, Power BI, Intel Data Insight Automation which allows users to create complex data/AI workflow operations for different use-cases.
629

30+
### Definitions
31+
32+
Before we begin, here are the definitions to some terms for clarity:
33+
34+
- servable/serving workflow - A workflow made ready to be executed through API. It should be able to accept parameter injection for workflow scheduling and have a way to retrieve the final output data. It should also have a unique workflow ID for referencing. For platform providers guide to create their own servable workflows compatible with this example, refer to [Workflow Building Platform](#workflow-building-platform)
35+
36+
- SDK Class - Performs requests to interface with a 3rd-party API to perform workflow operations on the servable workflow. Found in `tools/sdk.py`.
37+
38+
- workflow ID - A unique ID for the servable workflow.
39+
40+
- workflow instance - An instance created from the servable workflow. It is represented as a `Workflow` class created using `DataInsightAutomationSDK.create_workflow()` under `tools/sdk.py`. Contains methods to `start`, `get_status` and `get_results` from the workflow.
41+
742
### Workflow Executor
843

9-
This example demonstrates a single React-LangGraph with a `Workflow Executor` tool to ingest a user prompt to execute workflows and return an agent reasoning response based on the workflow output data.
44+
Strategy - This example demonstrates a single React-LangGraph with a `Workflow Executor` tool to ingest a user prompt to execute workflows and return an agent reasoning response based on the workflow output data.
1045

1146
First the LLM extracts the relevant information from the user query based on the schema of the tool in `tools/tools.yaml`. Then the agent sends this `AgentState` to the `Workflow Executor` tool.
1247

13-
`Workflow Executor` tool uses `EasyDataSDK` class as seen under `tools/sdk.py` to interface with several high-level API's. There are 3 steps to this tool implementation:
48+
`Workflow Executor` tool requires a SDK class to call the servable workflow API. In the code, `DataInsightAutomationSDK` is the example class as seen under `tools/sdk.py` to interface with several high-level API's. There are 3 steps to this tool implementation:
1449

1550
1. Starts the workflow with workflow parameters and workflow id extracted from the user query.
1651

@@ -26,37 +61,50 @@ Below shows an illustration of this flow:
2661

2762
### Workflow Serving for Agent
2863

64+
#### Workflow Building Platform
65+
66+
The first step is to prepare a servable workflow using a platform with the capabilities to do so.
67+
2968
As an example, here we have a Churn Prediction use-case workflow as the serving workflow for the agent execution. It is created through Intel Data Insight Automation platform. The image below shows a snapshot of the Churn Prediction workflow.
3069

3170
![image](https://github.com/user-attachments/assets/c067f8b3-86cf-4abc-a8bd-51a98de8172d)
3271

33-
The workflow contains 2 paths which can be seen in the workflow illustrated, the top path and bottom path.
72+
The workflow contains 2 paths which can be seen in the workflow illustrated, the top and bottom paths.
3473

35-
1. Top path - The training path which ends at the random forest classifier node is the training path. The data is cleaned through a series of nodes and used to train a random forest model for prediction.
74+
1. Top path (Training path) - Ends at the random forest classifier node is the training path. The data is cleaned through a series of nodes and used to train a random forest model for prediction.
3675

37-
2. Bottom path - The inference path where trained random forest model is used for inferencing based on input parameter.
76+
2. Bottom path (Inference path) - where trained random forest model is used for inferencing based on input parameter.
3877

3978
For this agent workflow execution, the inferencing path is executed to yield the final output result of the `Model Predictor` node. The same output is returned to the `Workflow Executor` tool through the `Langchain API Serving` node.
4079

41-
There are `Serving Parameters` in the workflow, which are the tool input variables used to start a workflow instance obtained from `params` the LLM extracts from the user query. Below shows the parameter configuration option for the Intel Data Insight Automation workflow UI.
80+
There are `Serving Parameters` in the workflow, which are the tool input variables used to start a workflow instance at runtime obtained from `params` the LLM extracts from the user query. Below shows the parameter configuration option for the Intel Data Insight Automation workflow UI.
4281

43-
![image](https://github.com/user-attachments/assets/ce8ef01a-56ff-4278-b84d-b6e4592b28c6)
82+
<img src="https://github.com/user-attachments/assets/ce8ef01a-56ff-4278-b84d-b6e4592b28c6" alt="image" width="500"/>
4483

4584
Manually running the workflow yields the tabular data output as shown below:
4685

4786
![image](https://github.com/user-attachments/assets/241c1aba-2a24-48da-8005-ec7bfe657179)
4887

4988
In the workflow serving for agent, this output will be returned to the `Workflow Executor` tool. The LLM can then answer the user's original question based on this output.
5089

51-
To start prompting the agent microservice, we will use the following command for this use case:
90+
When the workflow is configured as desired, transform this into a servable workflow. We turn this workflow into a servable workflow format so that it can be called through API to perform operations on it. Data Insight Automation has tools to do this for its own workflows.
91+
92+
> [!NOTE]
93+
> Remember to create a unique workflow ID along with the servable workflow.
94+
95+
#### Using Servable Workflow
96+
97+
Once we have our servable workflow ready, the serving workflow API can be prepared to accept requests from the SDK class. Refer to [Start Agent Microservice](#start-agent-microservice) on how to do this.
98+
99+
To start prompting the agent microservice, we will use the following command for this churn prediction use-case:
52100

53101
```sh
54102
curl http://${ip_address}:9090/v1/chat/completions -X POST -H "Content-Type: application/json" -d '{
55103
"query": "I have a data with gender Female, tenure 55, MonthlyAvgCharges 103.7. Predict if this entry will churn. My workflow id is '${workflow_id}'."
56104
}'
57105
```
58106

59-
The user has to provide a `workflow_id` and workflow `params` in the query. `workflow_id` a unique id used for serving the workflow to the microservice. Notice that the `query` string includes all the workflow `params` which the user has defined in the workflow. The LLM will extract these parameters into a dictionary format for the workflow `Serving Parameters` as shown below:
107+
The user has to provide a `workflow_id` and workflow `params` in the query. Notice that the `query` string includes all the workflow `params` which the user has defined in the workflow. The LLM will extract these parameters into a dictionary format for the workflow `Serving Parameters` as shown below:
60108

61109
```python
62110
params = {"gender": "Female", "tenure": 55, "MonthlyAvgCharges": 103.7}
@@ -72,6 +120,16 @@ And finally here are the results from the microservice logs:
72120

73121
### Start Agent Microservice
74122

123+
For an out-of-box experience there is an example workflow serving API service prepared for users under [Example Workflow API](tests/example_workflow/) to interface with the SDK. This section will guide users on setting up this service as well. Users may modify the logic, add your own database etc for your own use-case.
124+
125+
There are 3 services needed for the setup:
126+
127+
1. Agent microservice
128+
129+
2. LLM inference service - specified as `llm_endpoint_url`.
130+
131+
3. workflow serving API service - specified as `SDK_BASE_URL`
132+
75133
Workflow Executor will have a single docker image. First, build the agent docker image.
76134

77135
```sh
@@ -83,20 +141,23 @@ docker compose -f build.yaml build --no-cache
83141
Configure `GenAIExamples/WorkflowExecAgent/docker_compose/.env` file with the following. Replace the variables according to your usecase.
84142

85143
```sh
86-
export SDK_BASE_URL=${SDK_BASE_URL}
87-
export SERVING_TOKEN=${SERVING_TOKEN}
144+
export wf_api_port=5000 # workflow serving API port to use
145+
export SDK_BASE_URL=http://$(hostname -I | awk '{print $1}'):${wf_api_port}/ # The workflow server will use this example workflow API url
146+
export SERVING_TOKEN=${SERVING_TOKEN} # Authentication token. For example_workflow test, can be empty as no authentication required.
147+
export ip_address=$(hostname -I | awk '{print $1}')
88148
export HF_TOKEN=${HF_TOKEN}
89149
export llm_engine=${llm_engine}
90150
export llm_endpoint_url=${llm_endpoint_url}
91-
export ip_address=$(hostname -I | awk '{print $1}')
92-
export model="mistralai/Mistral-7B-Instruct-v0.3"
93-
export recursion_limit=${recursion_limit}
94-
export temperature=0
95-
export max_new_tokens=1000
96151
export WORKDIR=${WORKDIR}
97152
export TOOLSET_PATH=$WORKDIR/GenAIExamples/WorkflowExecAgent/tools/
98153
export http_proxy=${http_proxy}
99154
export https_proxy=${https_proxy}
155+
156+
# LLM variables
157+
export model="mistralai/Mistral-7B-Instruct-v0.3"
158+
export recursion_limit=${recursion_limit}
159+
export temperature=0
160+
export max_new_tokens=1000
100161
```
101162

102163
Launch service by running the docker compose command.
@@ -106,9 +167,18 @@ cd $WORKDIR/GenAIExamples/WorkflowExecAgent/docker_compose
106167
docker compose -f compose.yaml up -d
107168
```
108169

170+
To launch the example workflow API server, open a new terminal and run the following:
171+
172+
```sh
173+
cd $WORKDIR/GenAIExamples/WorkflowExecAgent/tests/example_workflow
174+
. launch_workflow_service.sh
175+
```
176+
177+
`launch_workflow_service.sh` will setup all the packages locally and launch the uvicorn server to host the API on port 5000. For a Dockerfile method, please refer to `Dockerfile.example_workflow_api` file.
178+
109179
### Validate service
110180

111-
The microservice logs can be viewed using:
181+
The agent microservice logs can be viewed using:
112182

113183
```sh
114184
docker logs workflowexec-agent-endpoint
@@ -120,7 +190,7 @@ You can validate the service using the following command:
120190

121191
```sh
122192
curl http://${ip_address}:9090/v1/chat/completions -X POST -H "Content-Type: application/json" -d '{
123-
"query": "I have a data with gender Female, tenure 55, MonthlyAvgCharges 103.7. Predict if this entry will churn. My workflow id is '${workflow_id}'."
193+
"query": "I have a data with gender Female, tenure 55, MonthlyCharges 103.7, TotalCharges 1840.75. Predict if this entry will churn. My workflow id is '${workflow_id}'."
124194
}'
125195
```
126196

WorkflowExecAgent/docker_compose/intel/cpu/xeon/compose_vllm.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ services:
99
- ${WORKDIR}/GenAIComps/comps/agent/src/:/home/user/comps/agent/src/
1010
- ${TOOLSET_PATH}:/home/user/tools/
1111
ports:
12-
- "9090:9090"
12+
- "9091:9090"
1313
ipc: host
1414
environment:
1515
ip_address: ${ip_address}

WorkflowExecAgent/tests/2_start_vllm_service.sh

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function build_vllm_docker_image() {
2626
else
2727
cd ./vllm
2828
fi
29-
docker build -f Dockerfile.cpu -t vllm-cpu-env --shm-size=100g .
29+
docker build -f docker/Dockerfile.cpu -t vllm-cpu-env --shm-size=100g .
3030
if [ $? -ne 0 ]; then
3131
echo "opea/vllm:cpu failed"
3232
exit 1
@@ -37,15 +37,20 @@ function build_vllm_docker_image() {
3737

3838
function start_vllm_service() {
3939
echo "start vllm service"
40+
export VLLM_SKIP_WARMUP=true
4041
docker run -d -p ${vllm_port}:${vllm_port} --rm --network=host --name test-comps-vllm-service -v ~/.cache/huggingface:/root/.cache/huggingface -v ${WORKPATH}/tests/tool_chat_template_mistral_custom.jinja:/root/tool_chat_template_mistral_custom.jinja -e HF_TOKEN=$HF_TOKEN -e http_proxy=$http_proxy -e https_proxy=$https_proxy -it vllm-cpu-env --model ${model} --port ${vllm_port} --chat-template /root/tool_chat_template_mistral_custom.jinja --enable-auto-tool-choice --tool-call-parser mistral
4142
echo ${LOG_PATH}/vllm-service.log
42-
sleep 5s
43+
sleep 10s
4344
echo "Waiting vllm ready"
4445
n=0
4546
until [[ "$n" -ge 100 ]] || [[ $ready == true ]]; do
47+
docker logs test-comps-vllm-service
48+
if docker logs test-comps-vllm-service| grep "Error response from daemon: No such container:"; then
49+
exit 1
50+
fi
4651
docker logs test-comps-vllm-service &> ${LOG_PATH}/vllm-service.log
4752
n=$((n+1))
48-
if grep -q "Uvicorn running on" ${LOG_PATH}/vllm-service.log; then
53+
if grep -q "Application startup complete." ${LOG_PATH}/vllm-service.log; then
4954
break
5055
fi
5156
if grep -q "No such container" ${LOG_PATH}/vllm-service.log; then
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/bin/bash
2+
# Copyright (C) 2024 Intel Corporation
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
set -e
6+
7+
WORKPATH=$(dirname "$PWD")
8+
vllm_port=${vllm_port}
9+
[[ -z "$vllm_port" ]] && vllm_port=8084
10+
export WORKDIR=$WORKPATH/../../
11+
echo "WORKDIR=${WORKDIR}"
12+
export SDK_BASE_URL=$1
13+
echo "SDK_BASE_URL=$1"
14+
export SERVING_TOKEN=${SERVING_TOKEN}
15+
export HF_TOKEN=${HUGGINGFACEHUB_API_TOKEN}
16+
export llm_engine=vllm
17+
export ip_address=$(hostname -I | awk '{print $1}')
18+
export llm_endpoint_url=http://${ip_address}:${vllm_port}
19+
export model=mistralai/Mistral-7B-Instruct-v0.3
20+
export recursion_limit=25
21+
export temperature=0
22+
export max_new_tokens=1000
23+
export TOOLSET_PATH=$WORKDIR/GenAIExamples/WorkflowExecAgent/tools/
24+
25+
function start_agent() {
26+
echo "Starting Agent services"
27+
cd $WORKDIR/GenAIExamples/WorkflowExecAgent/docker_compose/intel/cpu/xeon
28+
WORKDIR=$WORKPATH/docker_image_build/ docker compose -f compose_vllm.yaml up -d
29+
echo "Waiting agent service ready"
30+
sleep 10s
31+
}
32+
33+
function main() {
34+
echo "==================== Start agent service ===================="
35+
start_agent
36+
echo "==================== Agent service started ===================="
37+
}
38+
39+
main
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/bin/bash
2+
# Copyright (C) 2024 Intel Corporation
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
set -e
6+
7+
wf_api_port=${wf_api_port}
8+
[[ -z "$wf_api_port" ]] && wf_api_port=5005
9+
WORKPATH=$(dirname "$PWD")
10+
LOG_PATH="$WORKPATH/tests/example_workflow"
11+
export WORKDIR=$WORKPATH/../../
12+
echo "WORKDIR=${WORKDIR}"
13+
14+
function start_example_workflow_api() {
15+
echo "Starting example workflow API"
16+
cd $WORKDIR/GenAIExamples/WorkflowExecAgent/tests/example_workflow
17+
docker build -f Dockerfile.example_workflow_api -t example-workflow-service .
18+
docker run -d -p ${wf_api_port}:${wf_api_port} --rm --network=host --name example-workflow-service -it example-workflow-service
19+
echo "Waiting example workflow API ready"
20+
until [[ "$n" -ge 100 ]] || [[ $ready == true ]]; do
21+
docker logs example-workflow-service &> ${LOG_PATH}/example-workflow-service.log
22+
n=$((n+1))
23+
if grep -q "Uvicorn running on" ${LOG_PATH}/example-workflow-service.log; then
24+
break
25+
fi
26+
if grep -q "No such container" ${LOG_PATH}/example-workflow-service.log; then
27+
echo "container example-workflow-service not found"
28+
exit 1
29+
fi
30+
sleep 5s
31+
done
32+
}
33+
34+
function main() {
35+
echo "==================== Start example workflow API ===================="
36+
start_example_workflow_api
37+
echo "==================== Example workflow API started ===================="
38+
}
39+
40+
main
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/bin/bash
2+
# Copyright (C) 2024 Intel Corporation
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
set -e
6+
7+
WORKPATH=$(dirname "$PWD")
8+
export WORKDIR=$WORKPATH/../../
9+
echo "WORKDIR=${WORKDIR}"
10+
export ip_address=$(hostname -I | awk '{print $1}')
11+
query=$1
12+
validate_result=$2
13+
14+
function validate() {
15+
local CONTENT="$1"
16+
local EXPECTED_RESULT="$2"
17+
local SERVICE_NAME="$3"
18+
19+
if echo "$CONTENT" | grep -q "$EXPECTED_RESULT"; then
20+
echo "[ $SERVICE_NAME ] Content is as expected: $CONTENT"
21+
echo "[TEST INFO]: Workflow Executor agent service PASSED"
22+
else
23+
echo "[ $SERVICE_NAME ] Content does not match the expected result: $CONTENT"
24+
echo "[TEST INFO]: Workflow Executor agent service FAILED"
25+
fi
26+
}
27+
28+
function validate_agent_service() {
29+
echo "----------------Test agent ----------------"
30+
local CONTENT=$(curl http://${ip_address}:9091/v1/chat/completions -X POST -H "Content-Type: application/json" -d '{
31+
"messages": "'"${query}"'"
32+
}')
33+
validate "$CONTENT" "$validate_result" "workflowexec-agent-endpoint"
34+
docker logs workflowexec-agent-endpoint
35+
}
36+
37+
function main() {
38+
echo "==================== Validate agent service ===================="
39+
validate_agent_service
40+
echo "==================== Agent service validated ===================="
41+
}
42+
43+
main

0 commit comments

Comments
 (0)