Skip to content

Commit

Permalink
Add dependancy injection (#609)
Browse files Browse the repository at this point in the history
* refactoring

* wip

* Fix typing and update test

* Initial example wit code injection implemented

* Skip docs_src.user_guide.code_injection in test_import

* Rename the main.py to mesop_main.py

* wip: code injection docs

* wip: code injection docs

* Update code injectionn user guide

* Update code injectionn user guide

* Update code injection docs

* Update tests

* Update tests

* Update code injection docs to use cookiecutter

* Update tests

* Update code injection docs

* Rename Code Injection to Dependency Injection

* Generate cookiecutter my_bank_app in build_docs

* Update docs

* Update docs

---------

Co-authored-by: Davor Runje <[email protected]>
  • Loading branch information
rjambrecic and davorrunje authored Nov 29, 2024
1 parent fcc375f commit e0ce500
Show file tree
Hide file tree
Showing 72 changed files with 1,581 additions and 64 deletions.
9 changes: 6 additions & 3 deletions docs/docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ search:
- [FastAPI + Nats.io](user-guide/adapters/fastapi_nats/index.md)
- [FastAPI Security](user-guide/adapters/fastapi/security.md)
- [API-s](user-guide/api/index.md)
- [Dependency Injection](user-guide/api/dependency_injection/index.md)
- [OpenAPI](user-guide/api/openapi/index.md)
- [Security](user-guide/api/security.md)
- [Testing](user-guide/testing/index.md)
Expand Down Expand Up @@ -59,14 +60,16 @@ search:
- [NatsAdapter](api/fastagency/adapters/nats/base/NatsAdapter.md)
- [NatsProvider](api/fastagency/adapters/nats/base/NatsProvider.md)
- api
- dependency_injection
- [inject_params](api/fastagency/api/dependency_injection/inject_params.md)
- openapi
- [OpenAPI](api/fastagency/api/openapi/OpenAPI.md)
- client
- [OpenAPI](api/fastagency/api/openapi/client/OpenAPI.md)
- [add_to_globals](api/fastagency/api/openapi/client/add_to_globals.md)
- fastapi_code_generator_helpers
- [ArgumentWithDescription](api/fastagency/api/openapi/fastapi_code_generator_helpers/ArgumentWithDescription.md)
- [patch_get_parameter_type](api/fastagency/api/openapi/fastapi_code_generator_helpers/patch_get_parameter_type.md)
- openapi
- [OpenAPI](api/fastagency/api/openapi/openapi/OpenAPI.md)
- [add_to_globals](api/fastagency/api/openapi/openapi/add_to_globals.md)
- patch_datamodel_code_generator
- [patch_apply_discriminator_type](api/fastagency/api/openapi/patch_datamodel_code_generator/patch_apply_discriminator_type.md)
- patch_fastapi_code_generator
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
# 0.5 - API
# 2 - Release
# 3 - Contributing
# 5 - Template Page
# 10 - Default
search:
boost: 0.5
---

::: fastagency.api.dependency_injection.inject_params
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ search:
boost: 0.5
---

::: fastagency.api.openapi.client.OpenAPI
::: fastagency.api.openapi.openapi.OpenAPI
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ search:
boost: 0.5
---

::: fastagency.api.openapi.client.add_to_globals
::: fastagency.api.openapi.openapi.add_to_globals
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
141 changes: 141 additions & 0 deletions docs/docs/en/user-guide/api/dependency_injection/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Dependency Injection

[Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection){target="_blank"} is a secure way to connect external functions to agents in `AutoGen` without exposing sensitive data such as passwords, tokens, or personal information. This approach ensures that sensitive information remains protected while still allowing agents to perform their tasks effectively, even when working with large language models (LLMs).

In this guide, we’ll explore how to use `FastAgency` to build secure workflows that handle sensitive data safely.

As an example, we’ll create a banking agent that retrieves a user's account balance. The best part is that sensitive data like username and password are never shared with the language model. Instead, it’s securely injected directly into the function at runtime, keeping it safe while maintaining seamless functionality.

Let’s get started!


## Why Use Dependency Injection?

When working with large language models (LLMs), **security is paramount**. There are several types of sensitive information that we want to keep out of the LLM’s reach:

- **Passwords or tokens**: These could be exposed through [prompt injection attacks](https://en.wikipedia.org/wiki/Prompt_injection){target="_blank"}.
- **Personal information**: Access to this data might fall under strict regulations, such as the [EU AI Act](https://www.europarl.europa.eu/topics/en/article/20230601STO93804/eu-ai-act-first-regulation-on-artificial-intelligence){target="_blank"}.

Dependency injection offers a robust solution by isolating sensitive data while enabling your agents to function effectively.

## Why Dependency Injection Is Essential

Here’s why dependency injection is a game-changer for secure LLM workflows:

- **Enhanced Security**: Your sensitive data is never directly exposed to the LLM.
- **Simplified Development**: Secure data can be seamlessly accessed by functions without requiring complex configurations.
- **Unmatched Flexibility**: It supports safe integration of diverse workflows, allowing you to scale and adapt with ease.

In this guide, we’ll explore how to set up dependency injection, build secure workflows, and create a protected application step-by-step. Let’s dive in!

---

## Install

We will use [**Cookiecutter**](../../../user-guide/cookiecutter/index.md) for setting up the project. Cookiecutter creates the project folder structure, default workflow, automatically installs all the necessary requirements, and creates a [devcontainer](https://code.visualstudio.com/docs/devcontainers/containers){target="_blank"} that can be used with [Visual Studio Code](https://code.visualstudio.com/){target="_blank"}.

You can setup the project using Cookiecutter by following the [**project setup guide**](../../../user-guide/cookiecutter/index.md).

In this example, we’ll create a **Mesop** application **without authentication**. The generated project will have the following files:

```console
{! docs_src/user_guide/dependency_injection/mesop/folder_structure.txt !}
```

## Complete Workflow Code
The only file you need to modify to run the application is `my_bank_app/my_bank_app/workflow.py`. Simply copy and paste the following content into the file:

<details>
<summary>workflow.py</summary>
```python
{! docs_src/user_guide/dependency_injection/workflow.py !}
```
</details>

## Step-by-Step Guide

### Imports
These imports are similar to the imports section we have already covered, with the only difference being the additional imports of the [**`inject_params`**](../../../api/fastagency/api/dependency_injection/inject_params.md) function:

```python hl_lines="7"
{! docs_src/user_guide/dependency_injection/workflow.py [ln:1-8] !}
```

### Define the Bank Savings Function

The `get_balance` function is central to this workflow. It retrieves the user's balance based on the provided **username** and **password**.

The key consideration here is that both username and password should **NEVER** be exposed to the LLM. Instead, they will be securely injected into the `get_balance` function later in the workflow using the [**`inject_params`**](../../../api/fastagency/api/dependency_injection/inject_params.md) mechanism, ensuring that sensitive information remains confidential while still allowing the function to access the required data.

```python
{! docs_src/user_guide/dependency_injection/workflow.py [ln:10-23] !}
```


### Configure the Language Model (LLM)
Here, the large language model is configured to use the `gpt-4o-mini` model, and the API key is retrieved from the environment. This setup ensures that both the user and weather agents can interact effectively.

```python
{! docs_src/user_guide/dependency_injection/workflow.py [ln:26-34] !}
```

### Define the Workflow and Agents

The `bank_workflow` handles user interaction and integrates agents to retrieve balance securely.


1. **User Input Collection**:
- At the beginning of the workflow, the user is prompted to provide:
- **Username**: The workflow asks, *"Enter your username:"*.
- **Password**: The workflow then asks, *"Enter your password:"*.

2. **Agent Setup**:
- Two agents are created to handle the workflow:
- **UserProxyAgent**: Simulates the user's perspective, facilitating secure communication.
- **ConversableAgent**: Acts as the banker agent, retrieving the user's balance.

```python
{! docs_src/user_guide/dependency_injection/workflow.py [ln:36-63] !}
```

### Dependency Injection
Username and password provided by the user are stored securely in a **context dictionary (`ctx`)**.
These parameters are **never shared with the LLM** and they are only used internally within the workflow.

Using [**`inject_params`**](../../../api/fastagency/api/dependency_injection/inject_params.md), the sensitive parameters from the `ctx` dictionary are injected into the `get_balance` function.

```python
{! docs_src/user_guide/dependency_injection/workflow.py [ln:65-69] !}
```

### Register Function with the Agents
In this step, we register the `get_balance_with_params`
```python
{! docs_src/user_guide/dependency_injection/workflow.py [ln:70-75] !}
```

### Enable Agent Interaction and Chat
Here, the user agent initiates a chat with the banker agent, which retrieves the user's balance. The conversation is summarized using a method provided by the LLM.

```python
{! docs_src/user_guide/dependency_injection/workflow.py [ln:77-84] !}
```

## Run Application

You can run this chapter's FastAgency application using the following command:

```console
gunicorn my_bank_app.deployment.main:app
```

## Output
At the beginning, the user is asked to provide the **username** and **password**.

![User Input](./images/user_input.png)

Once the user provide them, the agent executes the `get_balance` function with both parameters securely injected into the function using the [**`inject_params`**](../../../api/fastagency/api/dependency_injection/inject_params.md) mechanism, ensuring these parameters are not exposed to the LLM.

The agent processes the request, retrieves the user's balance, and provides a summary of the results without compromising sensitive data.

![Result](./images/result.png)
10 changes: 8 additions & 2 deletions docs/docs/en/user-guide/api/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,18 @@ Currently, FastAgency supports importing API functionality from [**OpenAPI**](ht

## API Features in FastAgency

### 1. **[OpenAPI Import](./openapi/index.md)**
### 1. **[Dependency Injection](./dependency_injection/index.md)**
FastAgency offers a secure way to manage sensitive data using dependency injection. With the [**`inject_params`**](../../api/fastagency/api/dependency_injection/inject_params.md) function, sensitive information, such as tokens, is injected directly into functions without being exposed to the LLM. This ensures that sensitive data remains private while allowing agents to perform the required tasks. The process helps maintain data security and confidentiality while still enabling the proper execution of functions within the workflow.

[Learn more about Dependency Injection →](./dependency_injection/index.md)


### 2. **[OpenAPI Import](./openapi/index.md)**
FastAgency can automatically generate API functions from OpenAPI specifications, streamlining the process of connecting agents to external services. With just a few lines of code, you can import an API specification, and FastAgency will handle the function generation and LLM integration, making it simple for agents to call external APIs.

[Learn more about OpenAPI Import →](./openapi/index.md)

### 2. **[API Security](./security.md)**
### 3. **[API Security](./security.md)**
FastAgency supports different types of security for REST APIs, including OAuth, API keys, and more. This ensures that your API integrations are secure and can handle sensitive data. Our API security mechanisms are flexible, allowing you to configure and manage secure communication between your agents and external APIs.

[Learn more about API Security →](./security.md)
Expand Down
1 change: 1 addition & 0 deletions docs/docs/navigation_template.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ search:
- [FastAPI + Nats.io](user-guide/adapters/fastapi_nats/index.md)
- [FastAPI Security](user-guide/adapters/fastapi/security.md)
- [API-s](user-guide/api/index.md)
- [Dependency Injection](user-guide/api/dependency_injection/index.md)
- [OpenAPI](user-guide/api/openapi/index.md)
- [Security](user-guide/api/security.md)
- [Testing](user-guide/testing/index.md)
Expand Down
2 changes: 1 addition & 1 deletion docs/docs_src/tutorials/giphy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from autogen.agentchat import ConversableAgent

from fastagency import UI
from fastagency.api.openapi.client import OpenAPI
from fastagency.api.openapi import OpenAPI
from fastagency.api.openapi.security import APIKeyQuery
from fastagency.runtimes.autogen.agents.websurfer import WebSurferAgent
from fastagency.runtimes.autogen import AutoGenWorkflows
Expand Down
2 changes: 1 addition & 1 deletion docs/docs_src/tutorials/giphy/simple_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from autogen import ConversableAgent, UserProxyAgent

from fastagency import UI, FastAgency
from fastagency.api.openapi.client import OpenAPI
from fastagency.api.openapi import OpenAPI
from fastagency.api.openapi.security import APIKeyQuery
from fastagency.runtimes.autogen import AutoGenWorkflows
from fastagency.ui.mesop import MesopUI
Expand Down
2 changes: 1 addition & 1 deletion docs/docs_src/tutorials/whatsapp/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from autogen.agentchat import ConversableAgent

from fastagency import UI
from fastagency.api.openapi.client import OpenAPI
from fastagency.api.openapi import OpenAPI
from fastagency.api.openapi.security import APIKeyHeader
from fastagency.runtimes.autogen import AutoGenWorkflows
from fastagency.runtimes.autogen.agents.websurfer import WebSurferAgent
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
my_bank_app
├── docker
│   ├── content
│   │   ├── nginx.conf.template
│   │   └── run_fastagency.sh
│   └── Dockerfile
├── my_bank_app
│   ├── deployment
│   │   ├── __init__.py
│   │   └── main.py
│   ├── local
│   │   ├── __init__.py
│   │   ├── main_console.py
│   │   └── main_mesop.py
│   ├── __init__.py
│   └── workflow.py
├── scripts
│   ├── build_docker.sh
│   ├── check-registered-app-pre-commit.sh
│   ├── check-registered-app.sh
│   ├── deploy_to_fly_io.sh
│   ├── lint-pre-commit.sh
│   ├── lint.sh
│   ├── register_to_fly_io.sh
│   ├── run_docker.sh
│   ├── run_mesop_locally.sh
│   ├── static-analysis.sh
│   └── static-pre-commit.sh
├── tests
│   ├── __init__.py
│   ├── conftest.py
│   └── test_workflow.py
├── README.md
├── fly.toml
└── pyproject.toml
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CONTAINER_PREFIX=${USER}

# LLM keys
# Set atleast one of the following keys
OPENAI_API_KEY=${OPENAI_API_KEY}
TOGETHER_API_KEY=${TOGETHER_API_KEY}
ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"name": "python-3.12",
"dockerComposeFile": [
"./docker-compose.yml"
],
"service": "python-3.12-my_bank_app",

"secrets": {
"OPENAI_API_KEY": {
"description": "This key is optional and only needed if you are working on OpenAI-related code. Leave it blank if not required. You can always set it later as an environment variable in the codespace terminal."
},
"TOGETHER_API_KEY": {
"description": "This key is optional and only needed if you are working with Together API-related code. Leave it blank if not required. You can always set it later as an environment variable in the codespace terminal."
},
"ANTHROPIC_API_KEY": {
"description": "This key is optional and only needed if you are working with Anthropic API-related code. Leave it blank if not required. You can always set it later as an environment variable in the codespace terminal."
}
},
"shutdownAction": "stopCompose",
"workspaceFolder": "/workspaces/my_bank_app",
// "runArgs": [],
"remoteEnv": {},
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {
"installZsh": true,
"installOhMyZsh": true,
"configureZshAsDefaultShell": true,
"username": "vscode",
"userUid": "1000",
"userGid": "1000"
// "upgradePackages": "true"
},
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/git-lfs:1": {},
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
},
"updateContentCommand": "bash .devcontainer/setup.sh",
"postCreateCommand": [],
"customizations": {
"vscode": {
"settings": {
"python.linting.enabled": true,
"python.testing.pytestEnabled": true,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "always"
},
"[python]": {
"editor.defaultFormatter": "ms-python.vscode-pylance"
},
"editor.rulers": [
80
]
},
"extensions": [
"ms-python.python",
"ms-toolsai.jupyter",
"ms-toolsai.vscode-jupyter-cell-tags",
"ms-toolsai.jupyter-keymap",
"ms-toolsai.jupyter-renderers",
"ms-toolsai.vscode-jupyter-slideshow",
"ms-python.vscode-pylance"
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version: '3'

services:
# nosemgrep: yaml.docker-compose.security.writable-filesystem-service.writable-filesystem-service
python-3.12-my_bank_app:
image: mcr.microsoft.com/devcontainers/python:3.12
container_name: my_bank_app-${USER}-python-3.12
volumes:
- ../:/workspaces/my_bank_app:cached
command: sleep infinity

env_file:
- ./devcontainer.env
security_opt:
- no-new-privileges:true
networks:
- my_bank_app-network

networks:
my_bank_app-network:
name: my_bank_app-${USER}-network
Loading

0 comments on commit e0ce500

Please sign in to comment.