Skip to content

Commit 1182ba3

Browse files
committed
copy docs
1 parent 0a92ad1 commit 1182ba3

196 files changed

Lines changed: 3357 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/.DS_Store

10 KB
Binary file not shown.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Running and Testing Agents Locally
2+
3+
You can run the Python function for your agent itself by writing a `main()` function, or you can call the [`testbench_prompts.py`](https://github.com/lambda-feedback/lambda-chat/blob/main/src/agents/utils/testbench_prompts.py) script that runs a similar pipeline to the `module.py`.
4+
5+
```bash
6+
python src/agents/utils/testbench_prompts.py
7+
```
8+
9+
You can also use the `test_prompts.py` script to test the agents with example inputs from Lambda Feedback questions and synthetic conversations.
10+
```bash
11+
python src/agents/utils/test_prompts.py
12+
```
13+
14+
## Testing using the Docker Image [:material-docker:](https://www.docker.com/)
15+
16+
You can also build and run the docker pipeline for the agents. The chatbot agents are deployed onto a AWS Lambda serverless cloud function using the docker image. Hence, for final testing of your chatbots, we recommend completing those steps.
17+
18+
#### Build the Docker Image
19+
20+
To build the Docker image, run the following command in the root folder of the project (where the Dockerfile is located):
21+
22+
```bash
23+
docker build -t llm_chat .
24+
```
25+
26+
### Running the Docker Image
27+
28+
To run the Docker image, use the following command:
29+
30+
#### Without .env file:
31+
32+
```bash
33+
docker run -e OPENAI_API_KEY={your key} -e OPENAI_MODEL={your LLM chosen model name} -p 8080:8080 llm_chat
34+
```
35+
36+
#### With container name (for interaction, e.g. copying file from inside the docker container):
37+
38+
```bash
39+
docker run --env-file .env -it --name my-lambda-container -p 8080:8080 llm_chat
40+
```
41+
42+
This will start the evaluation function and expose it on port `8080` and it will be open to be curl:
43+
44+
```bash
45+
curl --location 'http://localhost:8080/2015-03-31/functions/function/invocations' --header 'Content-Type: application/json' --data '{"message":"hi","params":{"conversation_id":"12345Test","conversation_history": [{"type":"user","content":"hi"}]}}'
46+
```
47+
48+
### Call Docker Container From Postman
49+
50+
POST URL:
51+
52+
```bash
53+
http://localhost:8080/2015-03-31/functions/function/invocations
54+
```
55+
56+
Body:
57+
58+
```JSON
59+
{
60+
"message":"hi",
61+
"params":{
62+
"conversation_id":"12345Test",
63+
"conversation_history": [{"type":"user","content":"hi"}]
64+
}
65+
}
66+
```
67+
68+
Body with optional Params:
69+
```JSON
70+
{
71+
"message":"hi",
72+
"params":{
73+
"conversation_id":"12345Test",
74+
"conversation_history":[{"type":"user","content":"hi"}],
75+
"summary":" ",
76+
"conversational_style":" ",
77+
"question_response_details": "",
78+
"include_test_data": true,
79+
"agent_type": {agent_name}
80+
}
81+
}
82+
```
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Developing Chat Agents: Getting Started
2+
3+
## What is a Chat Agent?
4+
5+
It's a function which calls Large Language Models (LLMs) to respond to the student's messages given contxtual data:
6+
7+
- question data
8+
- user data such as past responses to the problem
9+
Chatbot Agents capture and automate the process of assisting students during their learning process when outside of classroom.
10+
11+
## Getting Setup for Development
12+
13+
1. Get the code on your local machine (Using github desktop or the `git` cli)
14+
15+
- For new functions: clone the main repo for [lambda-chat](https://github.com/lambda-feedback/lambda-chat) and create a new branch. Then go under `scr/agents` and copy the `base_agent` folder.
16+
17+
- For existing functions: please make your changes on a new separate branch
18+
19+
2. _If you are creating a new chatbot agent_, you'll need to set it's name as the folder name in `scr/agents` and its corresponding files.
20+
3. You are now ready to start making changes and implementing features by editing each of the three main function-logic files:
21+
22+
1. **`scr/agents/{base_agent}/{base}_agent.py`**: This file contains the main LLM pipeline using [LangGraph](https://langchain-ai.github.io/langgraph/) and [LangChain](https://python.langchain.com/docs/introduction/).
23+
24+
- the agent expects the following inputs when it being called:
25+
26+
Body with necessary Params:
27+
28+
```JSON
29+
{
30+
"message":"hi",
31+
"params":{
32+
"conversation_id":"12345Test",
33+
"conversation_history": [{"type":"user","content":"hi"}]
34+
}
35+
}
36+
```
37+
38+
Body with optional Params:
39+
40+
```JSON
41+
{
42+
"message":"hi",
43+
"params":{
44+
"conversation_id":"12345Test",
45+
"conversation_history":[{"type":"user","content":"hi"}],
46+
"summary":" ",
47+
"conversational_style":" ",
48+
"question_response_details": "",
49+
"include_test_data": true,
50+
"agent_type": {agent_name}
51+
}
52+
}
53+
```
54+
55+
2. **`scr/agents/{base_agent}/{base}_prompts.py`**: This is where you can write the system prompts that describe how your AI Assistant should behave and respond to the user.
56+
57+
3. Make sure to add your agent `invoke()` function to the `module.py` file.
58+
59+
4. Please add a `README.md` file to describe the use and behaviour of your agent.
60+
61+
4. Changes can be tested locally by running the pipeline tests using:
62+
```bash
63+
pytest src/module_test.py
64+
```
65+
[Running and Testing Agents Locally](local.md){ .md-button }
66+
67+
68+
5. Merge commits into any branch (except main) will trigger the `dev.yml` workflow, which will build the docker image, push it to a shared `dev` ECR repository to make the function available from the `dev` and `localhost` client app.
69+
70+
6. In order to make your new chatbot available on the LambdaFeedback platform, you will have to get in contact with the ADMINS on the platform.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Alternate Evaluation Function Languages
2+
---
3+
4+
## Lambda-Compatible Images
5+
### Extending a pre-built Lambda image
6+
- Available for: Node.js, Python, Java, .NET, Go, Ruby
7+
- [Docs](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-images.html#runtimes-images-lp)
8+
- [Repo](https://github.com/aws/aws-lambda-base-images)
9+
- These base images are regularly updated, and the most widely used (more docs)
10+
- They also come with pre-packaged runtime interface clients - a HTTP interface for runtimes to receive invocation events and respond
11+
- Good for local development
12+
13+
### Creating custom base images
14+
- Using the [lambda/provided](https://gallery.ecr.aws/lambda/provided) image
15+
- This "contains all the required components to run functions packaged as container images on Lambda"
16+
- Building a custom runtime from scratch
17+
- [Custom AWS Lambda runtimes](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html#runtimes-custom-build)
18+
- [Runtimes walkthrough tutorial](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-walkthrough.html)
19+
- Emulate execution locally?
20+
> Lambda provides a runtime interface emulator (RIE) for you to test your function locally. The AWS base images for Lambda and base images for custom runtimes include the RIE. For other base images, you can download the [Runtime interface emulator](https://github.com/aws/aws-lambda-runtime-interface-emulator) from the AWS GitHub repository.
21+
22+
### Misc Notes/Sources
23+
- [The Lambda Execution Environment](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtime-environment.html)
24+
- [Create Images from Alternative base images](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html#images-create-from-alt)
25+
26+
## Development Philosophy
27+
Ultimately we want to call a function made by a user in any language. Two ways to do this:
28+
29+
- We write and provide runtime in all the different languages. This means that all the logic happens in that language. We write the code that actually receives the requests from lambda function events. In this case, the user function can be imported from those handlers.
30+
- Writing handlers in each of those languages requires time and extensive knowledge (in order to write robust code)
31+
- Handler code needs to:
32+
- Have clean and reliable error catching
33+
34+
- We write a global runtime, which makes a call to their function via a sub-process. We call their script, which must recieve the payload as a commandline argument.
35+
- User has to write more code
36+
- For allowing cmdline arguments, and parsing of inputs
37+
- Might be slower than in other languages. Since another script has to be executed.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Base Layer Feedback Implementation
2+
3+
Input structure:
4+
5+
```json
6+
{
7+
"response": "user input",
8+
"answer": "original answer",
9+
"params": {
10+
"cases": [
11+
{
12+
"answer": "same shape as original answer",
13+
"feedback": "feedback string",
14+
"params": {...} # Any parameters to set or override
15+
},
16+
...
17+
]
18+
}
19+
}
20+
```
21+
22+
## Execution Logic for the `eval` command
23+
1. First `evaluation_function` is called using the response, answer and params
24+
3. If evaluation threw an error, then return the error message
25+
2. If evaluation was successful, check for matching cases
26+
1. If "params" contains a non-empty list of "cases", determine the correct feedback, add it to the result and return the block (Logic for this is described in the next section)
27+
2. If "params" doesn't contain a list of cases, simply return the result
28+
29+
## Determining the correct feedback case
30+
1. Iterate through each case in the list of `cases`:
31+
1. Validate the case has an 'answer' and 'feedback'
32+
2. If the case contains 'params', then merge them with the original 'params', overwriting values if they already exist
33+
3. Call `evaluation_function` with the student "response", case "answer" and merged "params"
34+
1. If the function returns "is_correct: true", we have a match, store case and feedback returned from the evaluation function
35+
2. If the function returns an error, catch it and add it to a list of warnings
36+
2. If no matches were found, don't return any feedback
37+
3. If exactly one match was found, check if `override_eval_feedback` is in parameters
38+
1. If `override_eval_feedback` is set to true, return the case feedback
39+
2. If `override_eval_feedback` is not set or set to false, append the evaluation function feedback to the case feedback, separated by a linebreak and the return the result
40+
4. If more than one matches were found, return the first one (using the same procedure as if only one match was found) and add a warning explaining which cases matched, and why only the first was selected.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Deployed Evaluation Functions
2+
3+
Documentation for each of the functions registered to the LambdaFeedback platform are pulled in this section automatically. This is done using a custom MkDocs plugin [EvalDocsLoader](https://github.com/lambda-feedback/EvalDocsLoader).
4+
5+
If you can't see any documentation files as subsections here, please contact an admin.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Running and Testing Functions Locally
2+
3+
## Simple
4+
5+
6+
## Using Docker [:material-docker:](https://www.docker.com/)
7+
This method builds and runs evaluation functions in the same way they are deployed on AWS as Lambda functions. Extending a pre-built and AWS-maintained [base python image](https://docs.aws.amazon.com/lambda/latest/dg/python-image.html#python-image-base), the container contains a HTTP client which can be used to locally simulate Lambda execution events.
8+
9+
Note that this is different from the [simple](#simple) method proposed, in that it gives access to all the functionality provided by the base layer. This means that commands such as `docs` and `healthcheck` can be tested.
10+
11+
1. Install [Docker](https://docs.docker.com/get-docker/) on your machine
12+
13+
2. Navigate to the root directory of your function
14+
15+
3. Build the image. This will pull our base image from Dockerhub, extend it with files specific to your evaluation function and name it `eval-tmp`.
16+
```bash
17+
docker image build -t eval-tmp app
18+
```
19+
20+
4. Spin up a container using the image built in the previous step.
21+
```bash
22+
docker run --rm -d --name eval-function -p 9000:8080 eval-tmp
23+
```
24+
25+
5. You can now simulate requests to the function using any request client (like [Insomnia](https://insomnia.rest/) or [Postman](https://www.postman.com/)). By default, the url you can hit is:
26+
```url
27+
http://localhost:9000/2015-03-31/functions/function/invocations
28+
```
29+
30+
???+ warning
31+
*When deployed, our Lambda functions are triggered by calls made through an AWS [API Gateway](https://aws.amazon.com/api-gateway/). This means that when testing locally, events sent should follow the structure of events triggered by that resource. That is, if you want to simulate what it would be like to make web requests to the deployed function.*
32+
33+
Specifically, this means structuring requests in the following way:
34+
```json
35+
{
36+
"headers": {
37+
"command": "eval"
38+
},
39+
"body": {
40+
"response": "a",
41+
"answer": "a",
42+
"params": {
43+
"garlic": "moreish"
44+
}
45+
}
46+
}
47+
```
48+
49+
The main difference is that `headers` and `body` are sent as keys in the main body of the local request. When hitting the deployed function through the API Gateway, the `command` field would instead be passed in the actual HTTP headers of the request - and the actual request body would only contain the `response`, `answer` and `params` fields.
50+
51+
6. *(Optional)* The `run` command specifies the **-d** flag, which spins up the container in detached mode. If you want to inspect the logs of the function, you can run:
52+
```bash
53+
docker container logs -f eval-function
54+
```
55+
56+
??? note "Tip"
57+
You will very rarely need this, but you can peek into the running container by opening a shell within it using:
58+
59+
```bash
60+
docker exec -it eval-function bash
61+
```
62+
63+
## Useful Links
64+
65+
-
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# evaluation-function-utils Package
2+
3+
- Error Reporting
4+
- Schema validation
5+
- Local testing
6+
7+
## Errors
8+
Submodule containing custom error and exception classes, which can be properly caught by the base evaluation layer, and return more detailed and appropriate errors.
9+
10+
### class `EvaluationException`
11+
This class extends the usual python `Exception`, with additional functionality. It can be used to package additional fields and values to errors thrown and returned by evaluation functions.
12+
13+
!!! example
14+
If at some point in the execution of the [`evaluation_function`](specification.md#the-evaluationfunction), an error is thrown:
15+
16+
```python
17+
from evaluation_function_utils.errors import EvaluationException
18+
19+
if isinstance(input, str):
20+
raise EvaluationException(
21+
"The input must not be a string",
22+
valid_types=["int", "float", "array"],
23+
)
24+
```
25+
26+
Then the output generated by the lambda function will look like:
27+
28+
```python
29+
{
30+
"command": "eval",
31+
"error": {
32+
"message": "The input must not be a string",
33+
"valid_types": [
34+
"int", "float", "array"
35+
]
36+
}
37+
}
38+
```
39+
40+
This class contains an error_dict property, which packages the additional arguments given to the Exception instance into a JSON-serializable object. It does so in an error-safe way, also reporting serialization errors if they occur.
41+
42+
## Client
43+
This submodule contains a custom `EvaluationFunctionClient`, which can be used to call other deployed evaluation functions.
44+
45+
### class `EvaluationFunctionClient`
46+
Client wrapped around the botocore.client.Lambda, for invoking deployed evaluation functions. On initialisation, it fetches credentials from environment variables "INVOKER_KEY", "INVOKER_ID" and "INVOKER_REGION", or from an optional environment file prescrived by `env_path`.
47+
48+
!!! example
49+
50+
```python
51+
from evaluation_function_utils.client import EvaluationFunctionClient
52+
client = EvaluationFunctionClient()
53+
54+
def evaluation_function(response, answer, params):
55+
return client.invoke('isExactEqual', response, answer, params)
56+
```
57+
58+
In this example, the evaluation_function completely offloads grading to the deployed 'isExactEqual' function.
59+
60+
*Note:* The `EvaluationFunctionClient.invoke` method was designed to behave exactly as if the [`evaluation_function`](specification.md#the-evaluationfunction) function defined in the targeted deployed function was called directly. This means that if errors are encountered an `EvaluationException` is raised.

0 commit comments

Comments
 (0)