Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
HotPotQA environment implemented with aviary, allowing agents to perform multi-hop question answering on the HotPotQA dataset.
[1] Yang et al. HotpotQA: A Dataset for Diverse, Explainable Multi-Hop Question Answering. EMNLP, 2018.
[2] Yao et al., ReAct: Synergizing Reasoning and Acting in Language Models. In The Eleventh International Conference on Learning Representations. 2023
To install the HotPotQA environment, run the following command:
An environment designed to utilize PaperQA for answering questions from the LFRQATaskDataset. Long-form RobustQA (LFRQA) is a human-annotated dataset introduced in the RAG-QA-Arena, featuring over 1400 questions from various categories, including science.
To install the LFRQA environment, run:
Refer to this tutorial for instructions on how to run the environment.
[1] RAG-QA Arena (https://arxiv.org/pdf/2407.13998)
GSM8k environment implemented with aviary, allowing agents to solve math word problems from the GSM8k dataset.
The citation for GSM8k is given below:
[1] Cobbe, K., Kosaraju, V., Bavarian, M., Chen, M., Jun, H., Kaiser, L., Plappert, M., Tworek, J., Hilton, J., Nakano, R. and Hesse, C., 2021. Training verifiers to solve math word problems. arXiv preprint arXiv:2110.14168.
To install the GSM8k environment, run the following command:
aviary is a monorepo using .
Git clone this repo
Install the project manager uv
: https://docs.astral.sh/uv/getting-started/installation/
Run uv sync
This will editably install the full monorepo in your local environment.
To run tests, please just run pytest
in the repo root.
Note you will need OpenAI and Anthropic API keys configured.
LitQA2 environment implemented with aviary, allowing agents to perform question answering on the LitQA dataset.
LitQA (now legacy) is a dataset composed from 50 multiple-choice questions from recent literature. It is designed to test the LLM's the ability to retrieve information outside of the pre-training corpus. To ensure the questions are not in the pre-training corpus, the questions were collected from scientific papers published after September 2021 -- cut-off date of GPT-4's training data.
LitQA2 is part of the LAB-Bench dataset. LitQA2 contains 248 multiple-choice questions from the literature and was created ensuring that the questions cannot be answered by recalling from the pre-training corpus only. It considered scientific paper published within 36 months from the data of its publication. Therefore, LitQA2 is considered a scientific RAG dataset.
To install the LitQA environment, run:
In litqa/env.py
, you will find:
GradablePaperQAEnvironment
: an environment that can grade answers given an evaluation function.
And in litqa/task.py
, you will find:
LitQAv2TaskDataset
: a task dataset designed to pull LitQA v2 from Hugging Face, and create one GradablePaperQAEnvironment
per question
Here is an example of how to use them:
[1] Lála et al. PaperQA: Retrieval-Augmented Generative Agent for Scientific Research. ArXiv:2312.07559, 2023.
[2] Skarlinski et al. Language agents achieve superhuman synthesis of scientific knowledge. ArXiv:2409.13740, 2024.
[3] Laurent et al. LAB-Bench: Measuring Capabilities of Language Models for Biology Research. ArXiv:2407.10362, 2024.
Gymnasium framework for training language model agents on constructive tasks.
To install aviary (note fh
stands for FutureHouse):
To install aviary with the bundled environments, please see the Environments section below.
As of 10/25/2024, unfortunately Google Colab does not yet support Python 3.11 or 3.12 (issue).
Thus, as a workaround, you will need to install Python 3.11 into your notebook. Here is a sample notebook showing how to do this: https://colab.research.google.com/drive/1mejZ5cxgKZrMpYEe0iRoanaGGQ0Cr6WI?usp=sharing
Also, note that async
code works in Google Colab.
For local development, please see the CONTRIBUTING.md.
Communication between the agent and environment is done through messages. Messages have two attributes:
The content
is a string with a text, a JSON serializable list of dict
s, or a null value. A list of dicts is used to encode multi-modal content. The method create_message
can be used to create a message with images:
create_message
supports images as numpy array or base64 encoded images. In this case, content
will be a list of dictionaries with the keys text
and image_url
.
We follow the structure adopted by OpenAI.
For the meaning of role, see the table below. You can change around roles as desired, except for tool
which has a special meaning in aviary.
assistant
Agent
A tool selector agent's tool selection message
system
Agent system prompt
"You are an agent."
user
Environment system prompt or emitted observation
HotPotQA problem to solve, or details of an internal env failure
tool
Result of tool run in the environment
Some number crunching program's output
Message
is extended in ToolRequestMessage
and ToolResponseMessage
to include the relevant tool name and arguments.
An environment should have two functions:
where messages are how communication is passed. The action_msg
should be ToolRequestMessage
which is 1 or more calls to tools provided by the reset
. The obs_msgs
returned from the environment are ToolResponseMessage
or other general messages that are observations. The reward
is a scalar value. The done
is a boolean value. The truncated
is a boolean value.
The easiest way to create an environment is using the functional interface, which just uses functions and decorators to define environments. First, let's define what the environment looks like by defining its start
function:
Note that the decorator is a call (start()
). The start
decorator starts the definition of an environment. The function, my_env
, can take whatever you would like and should return a tuple containing the first observation and anything you would like to store about the state of the environment (used to persist/share things between tools). The state will always automatically have an optional reward
and a boolean done
that indicates if the environment is complete.
Now we can define some tools:
The tools will be converted into things visible for LLMs using the type hints and the variable descriptions. Thus, the type hinting can be valuable for the agent using it correctly. The docstrings are also passed to the LLM, and is the primary way (along with function name) for communicating about intended tool usage.
You can access the state
variable in tools, which will have any fields you passed in the return tuple of start()
. For example, if you returned {'foo': 'bar'}
, then you could access state.foo
in the tools.
Stop an environment or set a reward via the state
variable as shown the second tool. If the reward is not set, it is treated as zero.
Now we can use our environment:
If you need more control over Environments and tools, you'll want to subclass the Environment
First we define an environment by subclassing the Environment
and defining a state
. The state
is all variables that change per step and we want to keep together. It will be accessible in your tools, so you can use it to store information that you want to persist between steps and between tools.
We do not have other variables aside from state
for this environment. We could have things like configuration, a name, tasks, etc. attached to it.
We expose a simple interface to some commonly-used environments that are included in the aviary codebase. You can instantiate one by referring to its name and passing keyword arguments:
Included with some environments are collections of problems that define training or evaluation datasets. We refer to these as TaskDataset
s, and expose them with a similar interface:
Now let's define our functions that will make up our tools. We'll just have one tool. Tools can optionally have their last argument be state
which is the environment state. This is how you can access the state. This argument will not be exposed to the agent as a possible parameter and will be injected by the environment (if part of the function signature).
There is special syntax we use for defining a tool. The tool is built from the following parts of the function: its name, its arguments names, the arguments types, and the docstring. The docstring is parsed to get a description of the function and its arguments, so match the syntax carefully.
Setting the state.done = True
is how we indicate completion. This example terminates immediately. You can use other ways to decide to terminate.
You can make the function async
- the environment will account for that when the tool is called.
We support more sophisticated signatures, for those who want to use them:
Multiline docstrings
Non-primitive type hints (e.g. type unions)
Default values
Exclusion of info below \f
(see below)
If you have summary-level information that belongs in the docstring, but you don't want it part of the Tool.info.description
, add a r
prefix to the docstring and inject \f
before the summary information to exclude. This convention was created by FastAPI (docs).
reset
methodNow we'll define the reset
function which should set-up the tools, and return one or more initial observations and the tools. The reset
function is async
to allow for database interactions or HTTP requests.
step
methodNow we can define the step
function which should take an action and return the next observation, reward, done, and if the episode was truncated.
You will probably often use this specific syntax for calling the tools - calling exec_tool_calls
with the action.
export_frame
methodOptionally, we can define a function to export a snapshot of the environment and its state for visualization or debugging purposes.
If an environment can be instantiated without anything other than a task (i.e., it implements from_task
), you can start a server to view its tools:
This will start a server that allows you to view the tools and call them, viewing the descriptions/types and output that an agent would see when using the tools.
Here are a few environments implemented with aviary:
GSM8k
fhaviary[gsm8k]
HotPotQA
fhaviary[hotpotqa]
LitQA
fhaviary[litqa]
LFRQA
fhaviary[lfrqa]