From ebe4a58f90bf207bd3732d066717910cfd1548e0 Mon Sep 17 00:00:00 2001 From: KIMB-technologies Date: Wed, 30 Oct 2024 22:12:51 +0100 Subject: [PATCH] Einstieg Doku --- .gitignore | 12 +++- agent-extract/Dockerfile => Dockerfile | 0 Example.md | 3 + Implement.md | 3 + Readme.md | 61 +++++++++++++++---- agent-extract/src/agent.py | 37 ----------- agent-solve/Dockerfile | 15 ----- agent-solve/src/agent.py | 59 ------------------ docker-compose.yml | 60 ++++++++++++------ .../src => src/extract}/__init__.py | 0 src/extract/agent.py | 41 +++++++++++++ {agent-solve/src => src/solve}/__init__.py | 0 src/solve/agent.py | 30 +++++++++ src/validate/__init__.py | 0 src/validate/agent.py | 27 ++++++++ 15 files changed, 204 insertions(+), 144 deletions(-) rename agent-extract/Dockerfile => Dockerfile (100%) create mode 100644 Example.md create mode 100644 Implement.md delete mode 100644 agent-extract/src/agent.py delete mode 100644 agent-solve/Dockerfile delete mode 100644 agent-solve/src/agent.py rename {agent-extract/src => src/extract}/__init__.py (100%) create mode 100644 src/extract/agent.py rename {agent-solve/src => src/solve}/__init__.py (100%) create mode 100644 src/solve/agent.py create mode 100644 src/validate/__init__.py create mode 100644 src/validate/agent.py diff --git a/.gitignore b/.gitignore index bdac0ef..1c8f9a2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,14 @@ +.DS_Store +__pycache__ +# data of containers /data/ +!/data/share/example/*.txt -.DS_Store \ No newline at end of file +# ignore local venv +/bin/ +/lib/ +/include/ +/pyvenv.cfg +# ignore ums source +/ums/ \ No newline at end of file diff --git a/agent-extract/Dockerfile b/Dockerfile similarity index 100% rename from agent-extract/Dockerfile rename to Dockerfile diff --git a/Example.md b/Example.md new file mode 100644 index 0000000..2bda8d2 --- /dev/null +++ b/Example.md @@ -0,0 +1,3 @@ +# Beispiel: Rätsel & Agent + +TODO \ No newline at end of file diff --git a/Implement.md b/Implement.md new file mode 100644 index 0000000..ef677b0 --- /dev/null +++ b/Implement.md @@ -0,0 +1,3 @@ +# Implementierung + +TODO \ No newline at end of file diff --git a/Readme.md b/Readme.md index ca23c59..6b2655c 100644 --- a/Readme.md +++ b/Readme.md @@ -1,4 +1,51 @@ -# Template für ein Agentensystem +# Template für das Agentensystem + +## Einstieg +0. Rechner vorbereiten + 1. Docker Desktop installieren + 2. Editor (IDE) installieren (freie Auswahl, Beispiele für ) +1. Repository einrichten + 1. Template laden `git clone -o UHH https://git.chai.uni-hamburg.de/UMS-Agenten/Agenten-Plattform.git` + 2. *Eigenes* Repository hinzufügen `git remote add UMS https://git.uni-muenster.de/example/my-group.git` + 3. In *eigenes* Repository pushen `git push UMS master` + 4. Später dann auch immer `git push UMS ...`, `git pull UMS ...` + 5. Updates vom Template `git pull UHH master` (Achtung: Merge-Konflikt) +2. Lokale Umgebung (kann übersprungen werden, mach aber das Entwickeln netter; nur für VS Code) + - Python-Paket `src`: Eigene Implementierung + - Python-Paket `ums`: Agenten-Plattform ([Quelle](https://git.chai.uni-hamburg.de/UMS-Agenten/Agenten-Plattform/src/branch/master/ums)) + - VS Code kann leider kein Autocomplete/ IntelliSense im Docker Container anbieten, daher müssen die Quellen auch auf dem Host verfügbar sein. + - VS Code erkennt das Verzeichnis `./src/` als Paket `src` + - Wir brauchen zusätzlich ein paar Abhängigkeiten und `ums` + 1. Virtuelles Env. erstellen `python3 -m venv .` + 2. Virtuelles Env. aktivieren `source ./bin/activate` + 3. Pakete installieren `pip install requests fastapi pdoc` (evtl. später weitere, damit diese auch IntelliSense unterstützen) + 4. In VS Code (in einer Python-Datei unten rechts) das Virtuelle Env. auswählen (`./bin/...`) + 5. Verzeichnis `ums` aus dem Docker Container extrahieren: + ```bash + docker create --name "management" "git.chai.uni-hamburg.de/ums-agenten/management:arm64" # oder :amd64 + docker cp "management:/ums-agenten/plattform/ums/" ./ums/ + docker rm "management" + ``` + - Virtuelles Env. und das Verzeichnis `./ums` werden von git ignoriert (siehe `./.gitignore`) +3. Agenten und Management starten + - Die Konfiguration des Managements und er verschiedenen Agenten erfolgt über die Datei `docker-compose.yml` + - Es ist sehr sinnvoll die Datei einmal durchzugehen und die Kommentare dort anzusehen. + 1. Für jeden Container/ Service die Images prüfen und anpassen (`:arm64` or `:amd64`, siehe [↓](#docker-images)) + 2. `docker compose up` startet alle Container wie in der `docker-compose.yml` angegeben + - Anschließend hängt das Terminal an der Ausgabe der verschiedenen Container + - Fehler erscheinen dort im Terminal oder/ und in `./data/persist-*/ums.log` + 3. Das Management kann über erreicht werden, es bietet: + - Dokumentation: + - Übersicht der Nachrichten zwischen Agenten und Management: + - Senden von Nachrichten/ Erstellen von Rätseln: + - Web API: (siehe auch ) +4. Im Ordner `src` ist ein sehr einfaches Agentensystem implementiert [→ Beispiel: Rätsel & Agent](./Example.md) +5. Die Implementierung kann auf dem Beispiel aufbauen [→ Implementierung](./Implement.md) + +> **Generell gilt:** +> Die Images sind größtenteils neu. +> Auch das Management und Agenten-Framework wurde neu entworfen, d.h., es können (und werden) noch ein paar Käfer irgendwo lauern. +> Bugs also bitte melden und bei Problemen mit dem System nachfragen (magnus.bender@uni-hamburg.de). ## Docker Images Es gibt unter viele verschiedene Docker Images. @@ -24,18 +71,6 @@ Folgende Images sind verfügbar: - Dieses Repository bildet einen einfachen und beispielhaften Agenten ab und soll als Basis dienen. -> **Generell gilt:** -> Die Images sind größtenteils neu. -> Auch das Management und Agenten-Framework wurde neu entworfen, d.h., es können (und werden) noch ein paar Käfer irgendwo lauern. -> Bugs also bitte melden und bei Problemen mit dem System nachfragen (magnus.bender@uni-hamburg.de). - Es wird im Laufe der Zeit sicherlich Updates der verschiedenen Images geben. Aus diesem Grund gibt bei den Tags Suffixe wie z.B. `2024-10-04` mit dem Datum des Build eines Images. Somit bleiben auch alte Versionen erreichbar, auch wenn am Ende die aktuelle Version ohne Suffix genutzt werden soll. - -## Struktur einen Agenten -> Dieses Repository ist so konzipiert, dass es geclont werden kann und dann zu einem Angenten *umgebaut* wird. - -... - -TODO \ No newline at end of file diff --git a/agent-extract/src/agent.py b/agent-extract/src/agent.py deleted file mode 100644 index b8f1c20..0000000 --- a/agent-extract/src/agent.py +++ /dev/null @@ -1,37 +0,0 @@ -# Agenten Plattform -# -# (c) 2024 Magnus Bender -# Institute of Humanities-Centered Artificial Intelligence (CHAI) -# Universitaet Hamburg -# https://www.chai.uni-hamburg.de/~bender -# -# source code released under the terms of GNU Public License Version 3 -# https://www.gnu.org/licenses/gpl-3.0.txt - -from ums.agent import ExtractAudioAgent, ExtractImageAgent - -from ums.utils.types import RiddleData - -""" - Examples for simple agents. - - Each agent is represented by its own class. The handling of tasks is done by `handle()` in each agent. - - Finally `AGENT_CLASSES` contains the classes of the agents in a list. Via environmental variables this list is specified to the ums.agent system. -""" - -class MyExtractAudioAgent(ExtractAudioAgent): - - def handle(self, data: RiddleData) -> RiddleData: - print("Audio Process:", data.file_plain) - return data - -class MyExtractImageAgent(ExtractImageAgent): - - def handle(self, data: RiddleData) -> RiddleData: - print("Image Process:", data.file_plain) - return data - -AGENT_CLASSES = [ - MyExtractAudioAgent, MyExtractImageAgent -] \ No newline at end of file diff --git a/agent-solve/Dockerfile b/agent-solve/Dockerfile deleted file mode 100644 index adc6384..0000000 --- a/agent-solve/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -ARG IMAGE_FROM -FROM $IMAGE_FROM - -# become root -USER root - -# do somthing as root, e.g. install packages, set up things ... -# RUN ... - -# copy the source of the agent in this repo -COPY --chown=user:user ./src/ /ums-agenten/project/src/ -# fix permissions -RUN chown -R user:user /ums-agenten -# switch back to user -USER user \ No newline at end of file diff --git a/agent-solve/src/agent.py b/agent-solve/src/agent.py deleted file mode 100644 index 281a8d8..0000000 --- a/agent-solve/src/agent.py +++ /dev/null @@ -1,59 +0,0 @@ -# Agenten Plattform -# -# (c) 2024 Magnus Bender -# Institute of Humanities-Centered Artificial Intelligence (CHAI) -# Universitaet Hamburg -# https://www.chai.uni-hamburg.de/~bender -# -# source code released under the terms of GNU Public License Version 3 -# https://www.gnu.org/licenses/gpl-3.0.txt - -from typing import Callable -from ums.agent import ExtractTextAgent, SolveAgent, GatekeeperAgent - -from ums.utils.types import AgentMessage, Riddle, RiddleData, RiddleSolution, RiddleStatus - -""" - Examples for simple agents. - - Each agent is represented by its own class. The handling of tasks is done by `handle()` in each agent. - - Finally `AGENT_CLASSES` contains the classes of the agents in a list. Via environmental variables this list is specified to the ums.agent system. -""" - -class MyExtractTextAgent(ExtractTextAgent): - - def before_response(self, response: AgentMessage, send_it: Callable[[], None]) -> bool: - print("The response will be:", response) - return True - - def handle(self, data: RiddleData) -> RiddleData: - print("Text Process:", data.file_plain) - return data - - -class MySolveAgent(SolveAgent): - - def handle(self, riddle: Riddle, data: RiddleData) -> RiddleSolution: - - if self.message().id == "test": - status = RiddleStatus() - status.extract.required = False - self.sub_riddle(riddle=Riddle(context="Haha", question="Blubber"), status=status) - - return RiddleSolution(solution="Huii", explanation="Blubb") - - -class MyGatekeeperAgent(GatekeeperAgent): - - def handle(self, solution: RiddleSolution, riddle: Riddle) -> RiddleSolution: - solution.accepted = True - solution.review = "Ok" - - return solution - -AGENT_CLASSES = [ - MyExtractTextAgent, - MySolveAgent, - MyGatekeeperAgent -] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 8dda606..6c33628 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,8 @@ services: + + # first the management + management: # select the correct one base on platform this is running on image: git.chai.uni-hamburg.de/ums-agenten/management:arm64 @@ -11,12 +14,16 @@ services: environment: # limit number of trials for solving a riddle - SOLUTION_MAX_TRIALS=5 + # limit to prevent messages in never ending cycles + - MESSAGE_MAX_CONTACTS=100 # how to access management (the host name is the name of the service in this file) - MANAGEMENT_URL=http://management # *register* the agents to the management - - AGENTS_PROCESS=http://agent_extract_1:8000,http://agent_extract_2:8000 + - AGENTS_PROCESS=http://agent_extract:8000 - AGENTS_SOLVE=http://agent_solve:8000 - AGENTS_GATEKEEPER=http://agent_gatekeeper:8000 + # divide multiple agents of same type by comma + #- AGENTS_PROCESS=http://agent_extract_1:8000,http://agent_extract_2:8000 volumes: # all data is bind-mounted from ./data on the host into the containers # the folder *share* is shared with all agents, it can be used to pass the data via files @@ -24,10 +31,12 @@ services: # the folder *persist* is different for each container and is used to store data permanently - ./data/persist-management/:/ums-agenten/persist/ - agent_solve: + # afterwards the agents + + agent_extract: # this allow to do installs etc. in the docker image (a new image will be built on top of the provided one) build: - context: ./agent-solve + context: . dockerfile: Dockerfile args: # select the correct one base on platform this is running on @@ -39,28 +48,20 @@ services: - 8081:8000 environment: # python package:variable_name of the list of agents implemeted here - - AGENTS_LIST=src.agent:AGENT_CLASSES + - AGENTS_LIST=src.extract.agent:AGENT_CLASSES # tell the agent where the management is accessible - MANAGEMENT_URL=http://management volumes: - ./data/share/:/ums-agenten/share/ - - ./data/persist-solve/:/ums-agenten/persist/ + - ./data/persist-extract/:/ums-agenten/persist/ # this is for development (s.t. the changes in ./src/ are directly applied) - - ./agent-solve/src/:/ums-agenten/project/src/:ro + - ./src/:/ums-agenten/project/src/:ro # for development: will detect file changes and reload server with new source entrypoint: bash -c "SERVE=true uvicorn ums.agent.main:app --host 0.0.0.0 --port 8000 --reload --reload-dir /ums-agenten/project/src/" - networks: - # this is a trick: we add multiple host names to the same container - # later, each agent will get its own container, but for testing, by this - # one container can become *all* agents - default: - aliases: - - agent_extract_2 - - agent_gatekeeper - agent_extract_1: + agent_solve: build: - context: ./agent-extract + context: . dockerfile: Dockerfile args: - IMAGE_FROM=git.chai.uni-hamburg.de/ums-agenten/base-agent:cpu-arm64 @@ -69,9 +70,30 @@ services: ports: - 8082:8000 environment: - - AGENTS_LIST=src.agent:AGENT_CLASSES + - AGENTS_LIST=src.solve.agent:AGENT_CLASSES - MANAGEMENT_URL=http://management volumes: - ./data/share/:/ums-agenten/share/ - - ./data/persist-extract/:/ums-agenten/persist/ - - ./agent-extract/src/:/ums-agenten/project/src/:ro \ No newline at end of file + - ./data/persist-solve/:/ums-agenten/persist/ + - ./src/:/ums-agenten/project/src/:ro + entrypoint: bash -c "SERVE=true uvicorn ums.agent.main:app --host 0.0.0.0 --port 8000 --reload --reload-dir /ums-agenten/project/src/" + + agent_gatekeeper: + build: + context: . + dockerfile: Dockerfile + args: + - IMAGE_FROM=git.chai.uni-hamburg.de/ums-agenten/base-agent:cpu-arm64 + #- IMAGE_FROM=git.chai.uni-hamburg.de/ums-agenten/base-agent:cpu-amd64 + #- IMAGE_FROM=git.chai.uni-hamburg.de/ums-agenten/base-agent:gpu-amd64 + ports: + - 8083:8000 + environment: + - AGENTS_LIST=src.validate.agent:AGENT_CLASSES + - MANAGEMENT_URL=http://management + volumes: + - ./data/share/:/ums-agenten/share/ + - ./data/persist-validate/:/ums-agenten/persist/ + - ./src/:/ums-agenten/project/src/:ro + entrypoint: bash -c "SERVE=true uvicorn ums.agent.main:app --host 0.0.0.0 --port 8000 --reload --reload-dir /ums-agenten/project/src/" + \ No newline at end of file diff --git a/agent-extract/src/__init__.py b/src/extract/__init__.py similarity index 100% rename from agent-extract/src/__init__.py rename to src/extract/__init__.py diff --git a/src/extract/agent.py b/src/extract/agent.py new file mode 100644 index 0000000..3c36ba2 --- /dev/null +++ b/src/extract/agent.py @@ -0,0 +1,41 @@ +# Agenten Plattform +# +# (c) 2024 Magnus Bender +# Institute of Humanities-Centered Artificial Intelligence (CHAI) +# Universitaet Hamburg +# https://www.chai.uni-hamburg.de/~bender +# +# source code released under the terms of GNU Public License Version 3 +# https://www.gnu.org/licenses/gpl-3.0.txt + +from typing import Callable + +from ums.agent import ExtractAudioAgent, ExtractImageAgent, ExtractTextAgent +from ums.utils.types import RiddleData, AgentMessage + + +class SimpleExtractAudioAgent(ExtractAudioAgent): + + def handle(self, data: RiddleData) -> RiddleData: + print("Audio Process:", data.file_plain) + return data + +class SimpleExtractImageAgent(ExtractImageAgent): + + def handle(self, data: RiddleData) -> RiddleData: + print("Image Process:", data.file_plain) + return data + +class SimpleExtractTextAgent(ExtractTextAgent): + + def before_response(self, response: AgentMessage, send_it: Callable[[], None]) -> bool: + print("The response will be:", response) + return True + + def handle(self, data: RiddleData) -> RiddleData: + print("Text Process:", data.file_plain) + return data + +AGENT_CLASSES = [ + SimpleExtractAudioAgent, SimpleExtractImageAgent, SimpleExtractTextAgent +] \ No newline at end of file diff --git a/agent-solve/src/__init__.py b/src/solve/__init__.py similarity index 100% rename from agent-solve/src/__init__.py rename to src/solve/__init__.py diff --git a/src/solve/agent.py b/src/solve/agent.py new file mode 100644 index 0000000..716e1b9 --- /dev/null +++ b/src/solve/agent.py @@ -0,0 +1,30 @@ +# Agenten Plattform +# +# (c) 2024 Magnus Bender +# Institute of Humanities-Centered Artificial Intelligence (CHAI) +# Universitaet Hamburg +# https://www.chai.uni-hamburg.de/~bender +# +# source code released under the terms of GNU Public License Version 3 +# https://www.gnu.org/licenses/gpl-3.0.txt + + +from ums.agent import SolveAgent + +from ums.utils.types import Riddle, RiddleData, RiddleSolution, RiddleStatus + +class SimpleSolveAgent(SolveAgent): + + def handle(self, riddle: Riddle, data: RiddleData) -> RiddleSolution: + + if self.message().id == "test": + status = RiddleStatus() + status.extract.required = False + self.sub_riddle(riddle=Riddle(context="Haha", question="Blubber"), status=status) + + return RiddleSolution(solution="Huii", explanation="Blubb") + + +AGENT_CLASSES = [ + SimpleSolveAgent +] \ No newline at end of file diff --git a/src/validate/__init__.py b/src/validate/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/validate/agent.py b/src/validate/agent.py new file mode 100644 index 0000000..781878d --- /dev/null +++ b/src/validate/agent.py @@ -0,0 +1,27 @@ +# Agenten Plattform +# +# (c) 2024 Magnus Bender +# Institute of Humanities-Centered Artificial Intelligence (CHAI) +# Universitaet Hamburg +# https://www.chai.uni-hamburg.de/~bender +# +# source code released under the terms of GNU Public License Version 3 +# https://www.gnu.org/licenses/gpl-3.0.txt + + +from ums.agent import GatekeeperAgent + +from ums.utils.types import Riddle, RiddleSolution + + +class SimpleSolveAgent(GatekeeperAgent): + + def handle(self, solution: RiddleSolution, riddle: Riddle) -> RiddleSolution: + solution.accepted = True + solution.review = "Ok" + + return solution + +AGENT_CLASSES = [ + SimpleSolveAgent +] \ No newline at end of file