Transformer课程 业务对话机器人Rasa 3.x 持续集成 和持续部署
Continuous Integration and Continuous Deployment
即使开发上下文助手不同于开发传统软件,您仍然应该遵循软件开发最佳实践。设置持续集成 和持续部署 管道可确保对bot的增量更新能够改善它,而不会损害它。
Overview
持续集成是频繁合并代码更改并在提交更改时自动测试更改的实践。连续部署意味着自动将集成的更改部署到暂存或生产环境。它们使您能够更频繁地改进助手,并有效地测试和部署这些更改。
本指南将涵盖特定于Rasa项目的持续集成、持续部署管道中应包含的内容。 建议选择一个与您使用的任何Git存储库集成的工具。
Continuous Integration
改进助手的最佳方法是经常进行增量更新。无论变化有多小,您都要确保它不会带来新问题或对助理的绩效产生负面影响。
通常最好在合并/拉取请求或提交时运行检查。大多数测试都足够快,可以在每次更改时运行。但是,仅当某些文件已更改或存在其他指示器时,才可以选择运行资源密集型测试。例如,如果您的代码托管在Github上,则只有在拉取请求具有特定标签(例如“需要NLU测试”)的情况下,才能进行测试运行。
Continuous Integration Pipeline Overview
持续集成管道应包括模型训练和测试,作为简化部署过程的步骤。保存新训练数据后的第一步是启动管道。这可以手动启动,也可以在创建或更新请求时启动。
接下来,您需要运行各种测试集,以查看更改的影响。这包括为数据验证、NLU交叉验证和故事测试运行测试。有关测试的更多信息,请参阅测试助手。
最后一步是检查测试结果,如果测试成功,则推动更改。一旦新模型经过训练和测试,就可以使用连续部署管道自动部署它。
GitHub Actions CI Pipeline
您可以在持续集成管道中使用Rasa Train Test Github操作自动执行数据验证、训练和测试。
使用Github操作的持续集成管道示例如下所示:
jobs:
training-testing:
name: Training and Testing
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Rasa Train and Test GitHub Action
uses: RasaHQ/rasa-train-test-gha@main
with:
requirements_file: requirements.txt
data_validate: true
rasa_train: true
cross_validation: true
rasa_test: true
test_type: all
publish_summary: true
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Upload model
if: github.ref == 'refs/heads/main'
uses: actions/upload-artifact@master
with:
name: model
path: models
在此管道中,Rasa Train Test Github操作在第一步执行数据验证、模型训练和故事测试,在第二步将模型文件 上传。
存储库的自述文件中提供了Rasa Train Test Github操作的完整可配置参数列表。
当publish_summary设置为true时,此操作将自动将模型的测试结果作为注释发布到关联的Pull请求:
可以根据评估结果批准或拒绝拉取请求,并且在许多情况下,如果所有 检查都通过,您将希望自动化模型的部署。您可以继续到下一节,以了解有关连续部署的更多信息。
Continuous Deployment
要经常向用户提供改进,您需要尽可能多地自动化部署过程。
一旦 检查成功,持续部署步骤通常在推送或合并到某个分支时运行。
Deploying Your Rasa Model
如果您在持续集成管道中运行了测试故事,那么您已经拥有了一个经过训练的模型。如果持续集成结果令人满意,您可以设置持续部署管道,将经过训练的模型上载到Rasa服务器。例如,要将模型上载到Rasa X:
curl -k -F "model=@models/my_model.tar.gz" "https://example.rasa.com/api/projects/default/models?api_token={your_api_token}"
如果您使用的是Rasa X,则还可以将上载的模型标记为生产(或使用多个部署环境时要标记的任何部署):
curl -X PUT "https://example.rasa.com/api/projects/default/models/my_model/tags/production"
行动守则的更新
如果更新包括对模型和操作代码的更改,并且这些更改以任何方式相互依赖,则不应自动将模型标记为生产。您首先需要构建和部署更新的操作服务器,以便新模型不会调用更新前操作服务器中不存在的操作。
Deploying Your Action Server
对于操作代码的每次更新,您都可以自动为操作服务器构建新映像并将其上载到映像存储库。如上所述,如果操作服务器与当前生产模型不兼容,请小心在生产中自动部署新的映像标记。
作为示例,请参见Rara Rasa助手以及Carbon Bot。两者都将Github操作用作持续集成 和持续部署工具。
这些例子只是许多可能性中的两个。如果您有自己喜欢的持续集成 和持续部署设置,请与论坛上的Rasa社区共享。
https://github.com/RasaHQ/carbon-bot/blob/master/.github/workflows/model_ci.yml
name: Model CI
on:
push:
branches:
- 'master'
pull_request:
types: [opened, synchronize, reopened]
env:
DOMAIN: 'carbon.rasa.com'
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_NAME: carbon-assistant
NAMESPACE: carbon-assistant
RASA_X_IMAGE_NAME: ${{ secrets.RASA_X_IMAGE_NAME }}
RASA_X_USERNAME: admin
RASA_X_PASSWORD: ${{ secrets.RASA_X_ADMIN_PASSWORD }}
jobs:
build-model:
name: Build, test, and upload model
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install dependencies
run: |
python -m pip install --upgrade "pip<20"
pip install -r requirements.txt
- name: Check stories are consistent
run: |
rasa data validate stories --max-history 5 --fail-on-warning
- name: Train model
run: |
rasa train
- name: Run Through Test Stories
run: |
rasa test core --stories test_stories/stories.yml --fail-on-prediction-errors
- name: Cross-validate NLU model
id: cvnlu
if: github.event_name == 'pull_request'
run: |
rasa test nlu -f 2 --cross-validation
python format_results.py
- name: Upload Cross Validation Results
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v2
with:
name: cross-validation-result
path: results.md
- name: Upload model
if: github.event_name == 'push' && (startsWith(github.event.ref, 'refs/tags') || github.ref == 'refs/heads/master')
uses: actions/upload-artifact@v2
with:
name: model
path: models
- name: Post cross-val results to PR
if: steps.cvnlu.outcome == 'success'
uses: samsucik/comment-on-pr@comment-file-contents
continue-on-error: true
with:
msg: results.md
build-images:
name: Build and Push Images
runs-on: ubuntu-latest
env:
IS_PUSH_EVENT: ${{ github.event_name == 'push' }}
steps:
- uses: actions/checkout@v2
- name: Set image tag
run: |
if [[ $IS_PUSH_EVENT == "false" ]]
then
IMAGE_TAG=${{ github.head_ref }}
else
IMAGE_TAG=$(basename ${{ github.ref }})
fi
echo "IMAGE_TAG=${IMAGE_TAG}-${{ github.sha }}" >> $GITHUB_ENV
# Setup gcloud CLI
- uses: google-github-actions/setup-gcloud@v0.2.1
name: Google Auth
with:
service_account_key: ${{ secrets.GKE_SA_KEY }}
project_id: ${{ secrets.GKE_PROJECT }}
# Configure docker to use the gcloud command-line tool as a credential helper
- run: |-
gcloud --quiet auth configure-docker
- name: Build and push the Docker image
run: |
# Read and export variables from .env file
set -o allexport; source .env; set +o allexport
docker build . \
--build-arg RASA_SDK_IMAGE=rasa/rasa-sdk:${RASA_SDK_VERSION} \
--tag gcr.io/${{ secrets.GKE_PROJECT }}/carbon-bot-actions:$IMAGE_TAG
docker push gcr.io/${{ secrets.GKE_PROJECT }}/carbon-bot-actions:$IMAGE_TAG
deploy-to-cluster:
name: Re-deploy the cluster with the latest action server
runs-on: ubuntu-latest
needs:
- build-images
if: github.event_name == 'push' && (startsWith(github.event.ref, 'refs/tags') || github.ref == 'refs/heads/master')
steps:
# Checkout repository because we need the content of the `.env` file later
- uses: actions/checkout@v2
- name: Set image tag
env:
IS_PUSH_EVENT: ${{ github.event_name == 'push' }}
run: |
if [[ $IS_PUSH_EVENT == "false" ]]
then
IMAGE_TAG=${{ github.head_ref }}
else
IMAGE_TAG=$(basename ${{ github.ref }})
fi
echo "IMAGE_TAG=${IMAGE_TAG}-${{ github.sha }}" >> $GITHUB_ENV
# Setup gcloud CLI
- uses: google-github-actions/setup-gcloud@v0.2.1
name: Google Auth
with:
service_account_key: ${{ secrets.GKE_SA_KEY }}
project_id: ${{ secrets.GKE_PROJECT }}
# Configure docker to use the gcloud command-line tool as a credential helper
- run: |-
gcloud --quiet auth configure-docker
# Get the GKE credentials so we can deploy to the cluster
- uses: google-github-actions/get-gke-credentials@v0.2.1
with:
cluster_name: ${{ secrets.GKE_CLUSTER }}
location: ${{ secrets.GKE_ZONE }}
credentials: ${{ secrets.GKE_SA_KEY }}
- name: Install Helm and helmfile ⛑
run: |
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
sudo curl -fsSL https://github.com/roboll/helmfile/releases/download/v0.138.7/helmfile_linux_amd64 --output /usr/local/bin/helmfile
sudo chmod +x /usr/local/bin/helmfile
- name: Install Chart
env:
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
RASA_TOKEN: ${{ secrets.RASA_TOKEN }}
RASA_X_TOKEN: ${{ secrets.RASA_X_TOKEN }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
PASSWORD_SALT: ${{ secrets.PASSWORD_SALT }}
REDIS_PASSWORD: ${{ secrets.REDIS_PASSWORD }}
RABBITMQ_PASSWORD: ${{ secrets.RABBITMQ_PASSWORD }}
RASA_X_ADMIN_PASSWORD: ${{ secrets.RASA_X_ADMIN_PASSWORD }}
GKE_PROJECT: ${{ secrets.GKE_PROJECT }}
FACEBOOK_VERIFY_TOKEN: ${{ secrets.FACEBOOK_VERIFY_TOKEN }}
FACEBOOK_APP_SECRET: ${{ secrets.FACEBOOK_APP_SECRET }}
FACEBOOK_PAGE_ACCESS_TOKEN: ${{ secrets.FACEBOOK_PAGE_ACCESS_TOKEN }}
CLIMATIQ_API_KEY: ${{ secrets.CLIMATIQ_API_KEY }}
run: |
# Install helm v3
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
# Read and export variables from .env file
set -o allexport; source .env; set +o allexport
kubectl create ns ${NAMESPACE} || true
cd .github/deployments; helmfile sync
cat <<EOF | kubectl apply --namespace ${NAMESPACE} -f -
apiVersion: networking.gke.io/v1beta1
kind: ManagedCertificate
metadata:
generation: 1
name: rasa-bots-certificate
spec:
domains:
- ${{ env.DOMAIN }}
EOF
upload-model:
name: Upload the trained model to Rasa X
needs:
- deploy-to-cluster
- build-model
env:
MODEL_DIRECTORY: "models"
if: github.event_name == 'push' && (startsWith(github.event.ref, 'refs/tags') || github.ref == 'refs/heads/master')
runs-on: ubuntu-latest
steps:
- name: Download Model
uses: actions/download-artifact@v2
with:
name: model
path: ${{ env.MODEL_DIRECTORY }}
- name: Get path to model
run: |
ls -R
echo "MODELNAME=${{ env.MODEL_DIRECTORY }}/$(ls ${{ env.MODEL_DIRECTORY }})" >> $GITHUB_ENV
- name: Upload Model to Rasa
run: |
# Get token
RASA_X_TOKEN=$(curl -s --header "Content-Type: application/json" \
--request POST \
--data "{\"username\":\"${RASA_X_USERNAME}\",\"password\":\"${RASA_X_PASSWORD}\"}" \
https://${{ env.DOMAIN }}/api/auth | jq -r .access_token)
# Upload model
curl -k --fail -H "Authorization: Bearer ${RASA_X_TOKEN}" -F "model=@${MODELNAME}" https://${{ env.DOMAIN }}/api/projects/default/models
# ensure model is ready and tag as production
sleep 5
export MODEL=$(basename ${MODELNAME} .tar.gz)
curl --fail -XPUT -H "Authorization: Bearer ${RASA_X_TOKEN}" https://${{ env.DOMAIN }}/api/projects/default/models/${MODEL}/tags/production
https://github.com/RasaHQ/rasa-demo/blob/main/.github/workflows/continuous_integration.yml
name: Continuous Integration
on: [pull_request]
env:
GDRIVE_CREDENTIALS: ${{ secrets.GDRIVE_CREDENTIALS }}
MAILCHIMP_LIST: ${{ secrets.MAILCHIMP_LIST }}
MAILCHIMP_API_KEY: ${{ secrets.MAILCHIMP_API_KEY }}
ALGOLIA_APP_ID: ${{ secrets.ALGOLIA_APP_ID }}
ALGOLIA_SEARCH_KEY: ${{ secrets.ALGOLIA_SEARCH_KEY }}
ALGOLIA_DOCS_INDEX: ${{ secrets.ALGOLIA_DOCS_INDEX }}
RASA_X_HOST: ${{ secrets.RASA_X_DOMAIN }}
RASA_X_PASSWORD: ${{ secrets.RASA_X_PASSWORD }}
RASA_X_USERNAME: ${{ secrets.RASA_X_USERNAME }}
RASA_X_HOST_SCHEMA: ${{ secrets.RASA_X_HOST_SCHEMA }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TRACKER_DB_URL: ${{ secrets.TRACKER_DB_URL }}
# Due to the issue with openssl library for Google Cloud SDK (gcloud)
# (https://github.com/GoogleCloudPlatform/github-actions/issues/128)
# we use 297.0.01 version
GCLOUD_VERSION: "297.0.1"
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
check_changed_files:
name: Check for file changes
runs-on: ubuntu-20.04
outputs:
nlu: ${{ steps.changed-files.outputs.nlu }}
core: ${{ steps.changed-files.outputs.core }}
training: ${{ steps.changed-files.outputs.training }}
actions: ${{ steps.changed-files.outputs.actions }}
steps:
# Due to an issue with checking out a wrong commit, we make sure
# to checkout HEAD commit for a pull request.
# More details: https://github.com/actions/checkout/issues/299
- name: Checkout pull request HEAD commit instead of merge commit
uses: actions/checkout@v2
if: github.event_name == 'pull_request'
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Checkout git repository
uses: actions/checkout@v2
if: github.event_name != 'pull_request'
- uses: RasaHQ/pr-changed-files-filter@c4f7116a04b8a4596313469429e2ad235f59d9c4
id: changed-files
with:
token: ${{ secrets.GITHUB_TOKEN }}
filters: .github/change_filters.yml
base: ${{ github.ref }}
lint-testing:
name: Code Formatting Tests
runs-on: ubuntu-latest
steps:
- name: Checkout pull request HEAD commit instead of merge commit
uses: actions/checkout@v2
if: github.event_name == 'pull_request'
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Checkout git repository
uses: actions/checkout@v2
if: github.event_name != 'pull_request'
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install dependencies
run: |
python -m pip install --upgrade "pip<20"
pip install -r requirements-dev.txt
- name: Code Formatting Tests
run: |
echo "------------------------------------"
echo "/usr/bin/git log -1 --format='%H'"
/usr/bin/git log -1 --format='%H'
echo "------------------------------------"
make lint
type-testing:
name: Type Tests
runs-on: ubuntu-latest
steps:
- name: Checkout pull request HEAD commit instead of merge commit
uses: actions/checkout@v2
if: github.event_name == 'pull_request'
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Checkout git repository
uses: actions/checkout@v2
if: github.event_name != 'pull_request'
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install dependencies
run: |
python -m pip install --upgrade "pip<20"
pip install -r requirements-dev.txt
- name: Type Checking
run: |
pip list
make types
action-unit-tests:
needs:
- lint-testing
- type-testing
name: Custom Action Unit Tests
runs-on: ubuntu-latest
steps:
- name: Checkout pull request HEAD commit instead of merge commit
uses: actions/checkout@v2
if: github.event_name == 'pull_request'
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Checkout git repository
uses: actions/checkout@v2
if: github.event_name != 'pull_request'
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install dependencies
run: |
make install-dev
- name: Unit Tests
run: |
make test-actions
data-validation:
name: Data Validation
runs-on: ubuntu-latest
steps:
- name: Checkout pull request HEAD commit instead of merge commit
uses: actions/checkout@v2
if: github.event_name == 'pull_request'
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Checkout git repository
uses: actions/checkout@v2
if: github.event_name != 'pull_request'
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install dependencies
run: |
python -m pip install --upgrade "pip<20"
pip install -r requirements-dev.txt
- name: Rasa Data Validation
run: |
rasa data validate --debug
training-testing:
name: Test Model
runs-on: ubuntu-latest
needs:
- data-validation
- check_changed_files
if: ${{ needs.check_changed_files.outputs.training == 'true' }}
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.8.0
with:
access_token: ${{ github.token }}
- name: Checkout pull request HEAD commit instead of merge commit
uses: actions/checkout@v2
if: github.event_name == 'pull_request'
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Checkout git repository
uses: actions/checkout@v2
if: github.event_name != 'pull_request'
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install dependencies
run: |
python -m pip install --upgrade "pip<20"
pip install -r requirements-dev.txt
rasa --version
- name: Cross-validate NLU model
id: cvnlu
if: contains( github.event.pull_request.labels.*.name, 'nlu_testing_required' )
run: |
rasa --version
rasa test nlu -f 3 --cross-validation --config config_nlu_testing.yml
python .github/workflows/format_results.py
- name: post cross-val results to PR
if: steps.cvnlu.outcome == 'success'
uses: amn41/comment-on-pr@comment-file-contents
continue-on-error: true
with:
msg: results.md
- name: Train Model
run: |
rasa --version
rasa train
- name: Test End 2 End Stories
if: ${{ needs.check_changed_files.outputs.core == 'true' }}
run: |
rasa --version
rasa test core --stories tests/test_conversations.yml --fail-on-prediction-errors
- name: Wait for the conclusion of all other workflow runs
# upload model from PR
if: github.event_name == 'pull_request'
id: check-runs-conclusion
env:
WAIT_INTERVAL_SECS: 10
timeout-minutes: 20
run: |
while true; do
# Get a list of checks information, excluding training-testing and build-images
CHECKS_LIST=$(gh api /repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }}/check-runs --jq '.check_runs.[] | select(.name != "Test Model" and .name != "Build Action Server Image")')
# Get the status and conclusion of echo jobs
STATUS_LIST=$(echo $CHECKS_LIST | jq -r '.status')
CONCLUSION_LIST=$(echo $CHECKS_LIST | jq -r '.conclusion')
# Make sure all other check runs are completed
if [[ "$(echo $STATUS_LIST | tr ' ' '\n' | sort | uniq)" == "completed" ]]; then
# Check the conclusion of all other check runs
# Fail the step if there is any failture
if [[ "$(echo CONCLUSION_LIST | tr ' ' '\n' | sort | uniq)" =~ "failure" ]]; then
echo "::error:: Some check runs failed. Skip uploading model."
exit 1
else
echo "All other check runs are successed."
echo "::set-output name=upload-model::true"
exit 0
fi
fi
sleep $WAIT_INTERVAL_SECS
echo "Wait for $WAIT_INTERVAL_SECS seconds..."
done
- name: Set model name from Rasa version
if: |
github.event_name == 'pull_request' &&
steps.check-runs-conclusion.outputs.upload-model == 'true'
run: |
python -c "import rasa; open('rasaversion.txt','w+').write(rasa.__version__)"
rasa_version=`cat rasaversion.txt`
model_path=`ls models/*.tar.gz | head -n 1`
model_timestamp=$(basename "$model_path" .tar.gz)
model_name="$model_timestamp"_rasa"$rasa_version"
renamed_model_path=models/"$model_name".tar.gz
mv $model_path $renamed_model_path
echo "MODEL_NAME=${model_name}" >> $GITHUB_ENV
echo "MODEL_PATH=${renamed_model_path}" >> $GITHUB_ENV
- uses: google-github-actions/setup-gcloud@master
if: |
(github.event_name == 'pull_request' &&
contains( github.event.pull_request.labels.*.name, 'upload_model' )) ||
steps.check-runs-conclusion.outputs.upload-model == 'true'
name: Authenticate with gcloud ????
with:
version: "${{ env.GCLOUD_VERSION }}"
service_account_email: ${{ secrets.SARA_GKE_SERVICE_ACCOUNT_NAME }}
service_account_key: ${{ secrets.SARA_GKE_SERVICE_ACCOUNT_KEY }}
- name: Upload model to storage bucket
if: |
(github.event_name == 'pull_request' &&
contains( github.event.pull_request.labels.*.name, 'upload_model' )) ||
steps.check-runs-conclusion.outputs.upload-model == 'true'
run: gsutil cp "${MODEL_PATH}" ${{ secrets.STORAGE_BUCKET_URL }}/rasa_demo_models
build-images:
name: Build Action Server Image
needs:
- lint-testing
- type-testing
- training-testing
- check_changed_files
if: ${{ needs.check_changed_files.outputs.actions == 'true' }}
runs-on: ubuntu-latest
steps:
- name: Checkout pull request HEAD commit instead of merge commit
uses: actions/checkout@v2
if: github.event_name == 'pull_request'
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Checkout git repository
uses: actions/checkout@v2
if: github.event_name != 'pull_request'
- name: Authenticate with gcloud ????
uses: google-github-actions/setup-gcloud@daadedc81d5f9d3c06d2c92f49202a3cc2b919ba
with:
version: ${{ env.GCLOUD_VERSION }}
service_account_key: ${{ secrets.GCLOUD_AUTH }}
- name: Configure Docker to use Google Cloud Platform
run: |
gcloud auth configure-docker
- name: Pull Latest Image
run: |
docker pull gcr.io/replicated-test/rasa-demo:latest || true
- name: Build Image
run: |
docker build --cache-from gcr.io/replicated-test/rasa-demo:latest .
https://github.com/features/actions