Skip to content

Commit

Permalink
Merge pull request #7 from hemajv/oc-templates
Browse files Browse the repository at this point in the history
Add openshift deployment files for react agent,streamlit
  • Loading branch information
hemajv authored Nov 6, 2024
2 parents 808e9bc + dc218e6 commit b7571c6
Show file tree
Hide file tree
Showing 19 changed files with 416 additions and 10 deletions.
10 changes: 10 additions & 0 deletions agent-starter.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
set -x

# Check if the config.yaml file exists and copy it
if [ -f /opt/app-root/config/config.yaml ]; then
cp /opt/app-root/config/config.yaml /opt/app-root/src/config.yaml
fi

# Start the agent server
${POETRY_HOME}/bin/poetry run python react_agent/api.py
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ version = "0.1.0"
description = ""
readme = "README.md"
authors = ["Red Hat"]
packages = [{include = "llm_agents"}]

[tool.poetry.dependencies]
python = ">=3.10,<4.0"
Expand Down Expand Up @@ -50,4 +49,4 @@ per-file-ignores = { "tests/*" = ["D"] }

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
build-backend = "poetry.core.masonry.api"
66 changes: 66 additions & 0 deletions react-agent-Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Builder image to install dependencies from pyproject and lock file
FROM quay.io/fedora/python-310:latest AS builder
USER root
ENV POETRY_HOME=/opt/poetry \
POETRY_VERSION=1.8.2

# Install Poetry
RUN wget -P /tmp/ https://certs.corp.redhat.com/certs/Current-IT-Root-CAs.pem && \
curl -sSL https://install.python-poetry.org | python - && \
${POETRY_HOME}/bin/poetry config virtualenvs.in-project true && \
${POETRY_HOME}/bin/poetry config certificates.de-cop-nexus.cert /tmp/Current-IT-Root-CAs.pem

# Copy the source code and install dependencies
COPY . /opt/app-root/src/
WORKDIR /opt/app-root/src/
RUN ${POETRY_HOME}/bin/poetry install --only main

# Final image
FROM quay.io/fedora/python-310:latest
LABEL maintainer="et@redhat.com" \
io.k8s.description="ReAct Agent" \
io.k8s.display-name="react_agent" \
io.openshift.tags="et"

USER root

# Update OS and install necessary packages
RUN dnf -y update && \
dnf -y install java-17-openjdk tini wget && \
dnf -y autoremove && \
dnf -y clean all && \
wget -P /etc/pki/ca-trust/source/anchors https://certs.corp.redhat.com/certs/Current-IT-Root-CAs.pem && \
keytool -import -noprompt -keystore /etc/pki/java/cacerts -file /etc/pki/ca-trust/source/anchors/Current-IT-Root-CAs.pem -alias RH-IT-Root-CA -storepass changeit && \
update-ca-trust enable && \
update-ca-trust extract

# Install Poetry in the final stage
ENV POETRY_HOME=/opt/poetry \
PATH="/opt/poetry/bin:$PATH"
RUN curl -sSL https://install.python-poetry.org | python -

# Copy the source code and set up the environment
COPY . /opt/app-root/src/
WORKDIR /opt/app-root/src/
RUN fix-permissions /opt/app-root/src -P && \
echo "" > /opt/app-root/bin/activate

# Copy virtual environment from the builder stage
COPY --from=builder --chown=1001:0 /opt/app-root/src/.venv /opt/app-root/src/.venv

# Install streamlit directly
RUN /opt/app-root/src/.venv/bin/pip install streamlit

# Copy the starter.sh script and set permissions
COPY agent-starter.sh /opt/app-root/src/
RUN chmod +x /opt/app-root/src/agent-starter.sh

USER 1001

EXPOSE 2113 8501

# Ensure the virtual environment is included in the PATH
ENV PATH="/opt/app-root/src/.venv/bin:$PATH"

# Start the API server using agent-starter.sh
CMD ["/opt/app-root/src/agent-starter.sh"]
2 changes: 1 addition & 1 deletion react_agent/agent/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ def react_agent():
response_format = "agent"
tools = import_tools(common_tools_kwargs={"response_format": response_format})
prompt = PromptTemplate.from_template(REACT_PROMPT)
agent = create_react_agent(completion_llm, tools, prompt)
agent = create_react_agent(completion_llm, tools, prompt, stop_sequence=["Observation:"])
agent_executor = AgentExecutor(name="ReActAgent", agent=agent, tools=tools, handle_parsing_errors=True)
return agent_executor
18 changes: 12 additions & 6 deletions react_agent/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,28 @@
import logging
from contextlib import asynccontextmanager

import mlflow
import uvicorn
from fastapi import FastAPI

import mlflow
from react_agent.agent import react_agent
from react_agent.apispec import ReActRequest, ReActResponse
from react_agent.constants import APP_HOST, APP_PORT

from react_agent.constants import APP_HOST, APP_PORT, MLFLOW_EXPERIMENT_NAME, MLFLOW_TRACKING_URI, MLFLOW_TRACKING_TOKEN
logger = logging.getLogger(__name__)

# Connect to a hosted mlflow
mlflow.set_tracking_uri(MLFLOW_TRACKING_URI)
if not mlflow.get_experiment_by_name(MLFLOW_EXPERIMENT_NAME):
mlflow.create_experiment(name=MLFLOW_EXPERIMENT_NAME)

experiment = mlflow.get_experiment_by_name(MLFLOW_EXPERIMENT_NAME)
experiment_id = experiment.experiment_id

# Start logging
mlflow.langchain.autolog(log_traces=True)
with mlflow.start_run(experiment_id=experiment_id):
mlflow.langchain.autolog(log_traces=True)

agents = {}


@asynccontextmanager
async def lifespan(app: FastAPI):
"""Run startup sequence."""
Expand Down
3 changes: 3 additions & 0 deletions react_agent/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
OPENAI_URI = os.environ.get("OPENAI_URI", "http://localhost:11434/v1")
OPENAI_MODEL = os.environ.get("OPENAI_MODEL", "mistral")
OPENAI_IGNORE_SSL = os.environ.get("OPENAI_IGNORE_SSL", False)
MLFLOW_TRACKING_URI = os.environ.get("MLFLOW_TRACKING_URI")
MLFLOW_TRACKING_TOKEN = os.environ.get("MLFLOW_TRACKING_TOKEN")
MLFLOW_EXPERIMENT_NAME = os.environ.get("MLFLOW_EXPERIMENT_NAME")

ERROR_MESSAGE = "Unable to process request, please try again later."

Expand Down
42 changes: 42 additions & 0 deletions react_agent/openshift/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# OpenShift Deployment Instructions

To deploy the ReAct agent on an OpenShift cluster, you can follow the below instructions.

## Prerequisites

- OpenShift CLI (`oc`) installed and configured
- (**Optional**) `kubectl` and `kustomize` installed and configured

## Deployment Instructions

### Step 1: Clone the Repository

```sh
git clone git@github.com:redhat-et/llm-agents.git
cd llm-agents/react_agent
```

### Step 2: Deploy the ReAct Agent API Server

The agent API server is responsible for handling requests and interacting with the LLM. It exposes endpoints for different functionalities of the tool-based agent. The API server processes incoming requests, sends them to the appropriate tools or models, and returns the results to the clients. This deployment step sets up the necessary backend infrastructure for the ReAct agent.


```sh
oc apply -f openshift/deployment.yaml
```

```sh
oc apply -f openshift/service.yaml
```

```sh
oc apply -f openshift/route.yaml
```

```sh
oc apply -f openshift/configmap.yaml
```

### Containerfile

The Containerfiles used to build the deployment images can be found [here](https://github.com/redhat-et/llm-agents/react-agent-Containerfile)
38 changes: 38 additions & 0 deletions react_agent/openshift/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: react-agent-config
namespace: react-agent-test
data:
APP_HOST: "0.0.0.0"
APP_PORT: "2113"
OPENAI_URI: "<model-endpoint>"
OPENAI_MODEL: "<model-name>"
OPENAI_IGNORE_SSL: "True"
MLFLOW_TRACKING_URI: "<mlflow-url>"
MLFLOW_TRACKING_TOKEN: "<mlflow-token>"
MLFLOW_EXPERIMENT_NAME: "ReAct Agent"
config.yaml: |
tools:
- name: "constitution_tool"
description: "Answers questions about the U.S. Constitution."
url: "https://my.app/v1/completions"
config:
method: 'POST'
headers:
'Content-Type': 'application/json'
'Authorization': 'Basic 12345'
body:
prompt: '{{prompt}}'
responseParser: 'json.answer'
responseMetadata:
- name: 'sources'
loc: 'json.sources'
responseFormat:
agent: '{{response}}'
json:
- "response"
- "sources"
examples:
- "What is the definition of a citizen in the U.S. Constitution?"
- "What article describes the power of the judiciary branch?"
31 changes: 31 additions & 0 deletions react_agent/openshift/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: react-agent-server
namespace: react-agent-test
spec:
replicas: 1
selector:
matchLabels:
app: react-agent-server
template:
metadata:
labels:
app: react-agent-server
spec:
containers:
- name: react-agent-server
image: docker.io/hemaveeradhi/llm-agent:latest
ports:
- containerPort: 2113
envFrom:
- configMapRef:
name: react-agent-config
volumeMounts:
- name: config-volume
mountPath: /opt/app-root/config/config.yaml
subPath: config.yaml
volumes:
- name: config-volume
configMap:
name: react-agent-config
14 changes: 14 additions & 0 deletions react_agent/openshift/route.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: react-agent-route
namespace: react-agent-test
spec:
to:
kind: Service
name: react-agent-server
port:
targetPort: react-agent-port
tls:
termination: edge
wildcardPolicy: None
13 changes: 13 additions & 0 deletions react_agent/openshift/service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: react-agent-server
namespace: react-agent-test
spec:
selector:
app: react-agent-server
ports:
- name: react-agent-port
protocol: TCP
port: 2113
targetPort: 2113
3 changes: 2 additions & 1 deletion sample.env
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ APP_PORT=2113
OPENAI_URI="https://localhost:11434/v1"
OPENAI_MODEL="mistral:latest"
OPENAI_IGNORE_SSL="True"
MLFLOW_TRACKING_URI="http://localhost:5000"
MLFLOW_TRACKING_URI="<mlflow-endpoint>"
MLFLOW_EXPERIMENT_NAME="ReAct Agent"
MLFLOW_TRACKING_TOKEN="<token>"
66 changes: 66 additions & 0 deletions streamlit-Containerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Builder image to install dependencies from pyproject and lock file
FROM quay.io/fedora/python-310:latest AS builder
USER root
ENV POETRY_HOME=/opt/poetry \
POETRY_VERSION=1.8.2

# Install Poetry
RUN wget -P /tmp/ https://certs.corp.redhat.com/certs/Current-IT-Root-CAs.pem && \
curl -sSL https://install.python-poetry.org | python - && \
${POETRY_HOME}/bin/poetry config virtualenvs.in-project true && \
${POETRY_HOME}/bin/poetry config certificates.de-cop-nexus.cert /tmp/Current-IT-Root-CAs.pem

# Copy the source code and install dependencies
COPY . /opt/app-root/src/
WORKDIR /opt/app-root/src/
RUN ${POETRY_HOME}/bin/poetry install --only main

# Final image
FROM quay.io/fedora/python-310:latest
LABEL maintainer="et@redhat.com" \
io.k8s.description="Streamlit" \
io.k8s.display-name="Streamlit" \
io.openshift.tags="et"

USER root

# Update OS and install necessary packages
RUN dnf -y update && \
dnf -y install java-17-openjdk tini wget && \
dnf -y autoremove && \
dnf -y clean all && \
wget -P /etc/pki/ca-trust/source/anchors https://certs.corp.redhat.com/certs/Current-IT-Root-CAs.pem && \
keytool -import -noprompt -keystore /etc/pki/java/cacerts -file /etc/pki/ca-trust/source/anchors/Current-IT-Root-CAs.pem -alias RH-IT-Root-CA -storepass changeit && \
update-ca-trust enable && \
update-ca-trust extract

# Install Poetry in the final stage
ENV POETRY_HOME=/opt/poetry \
PATH="/opt/poetry/bin:$PATH"
RUN curl -sSL https://install.python-poetry.org | python -

# Copy the source code and set up the environment
COPY . /opt/app-root/src/
WORKDIR /opt/app-root/src/
RUN fix-permissions /opt/app-root/src -P && \
echo "" > /opt/app-root/bin/activate

# Copy virtual environment from the builder stage
COPY --from=builder --chown=1001:0 /opt/app-root/src/.venv /opt/app-root/src/.venv

# Install streamlit directly
RUN /opt/app-root/src/.venv/bin/pip install streamlit

# Copy the starter.sh script and set permissions
COPY streamlit-starter.sh /opt/app-root/src/
RUN chmod +x /opt/app-root/src/streamlit-starter.sh

USER 1001

EXPOSE 8501

# Ensure the virtual environment is included in the PATH
ENV PATH="/opt/app-root/src/.venv/bin:$PATH"

# Start the Streamlit app using streamlit-starter.sh
CMD ["/opt/app-root/src/streamlit-starter.sh"]
10 changes: 10 additions & 0 deletions streamlit-starter.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
set -x

# Check if the config.yaml file exists and copy it
if [ -f /opt/app-root/config/config.yaml ]; then
cp /opt/app-root/config/config.yaml /opt/app-root/src/config.yaml
fi

# Start the Streamlit app
${POETRY_HOME}/bin/poetry run streamlit run streamlit/intro.py
Loading

0 comments on commit b7571c6

Please sign in to comment.