Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing a basic AsyncGuard to logically separate out async calls from Guard() into a new client #767

Merged
merged 9 commits into from
May 17, 2024

Conversation

wylansford
Copy link
Contributor

@wylansford wylansford commented May 13, 2024

Replaces async functionality in the Guard() class with a second class that is solely for Async calls. Any async calls found in Guard are now deprecated

@wylansford wylansford added enhancement New feature or request python Pull requests that update Python code labels May 13, 2024
@wylansford wylansford requested a review from zsimjee May 13, 2024 20:46
@wylansford wylansford changed the base branch from main to 0.4.4-dev May 13, 2024 21:01
Copy link
Collaborator

@zsimjee zsimjee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Can we have AsyncGuard inherit guard and only override the call functions?
  2. In AsyncGuard, should all call overloads be Awaitables and marked async on the def?

guardrails/guard.py Outdated Show resolved Hide resolved
guardrails/guard.py Outdated Show resolved Hide resolved
@wylansford
Copy link
Contributor Author

wylansford commented May 16, 2024

  1. Can we have AsyncGuard inherit guard and only override the call functions?

Done & fixed.

  1. In AsyncGuard, should all call overloads be Awaitables and marked async on the def?

I think this is up to where we want to handle the async management. Right now the _call function calls _call_async which sets the entry point there. Anything from the chain down there needs to be async. I think this is correct. Otherwise, If the call function is async it would be a bit awkward to need the user to manage any async functionality from the outside. With the current setup we will never have to call await on our guard because it's managed fully internally

@CalebCourier
Copy link
Collaborator

  1. Can we have AsyncGuard inherit guard and only override the call functions?

Done & fixed.

  1. In AsyncGuard, should all call overloads be Awaitables and marked async on the def?

I think this is up to where we want to handle the async management. Right now the _call function calls _call_async which sets the entry point there. Anything from the chain down there needs to be async. I think this is correct. Otherwise, If the call function is async it would be a bit awkward to need the user to manage any async functionality from the outside. With the current setup we will never have to call await on our guard because it's managed fully internally

My expectation for an AsyncGuard would be to have to always await both guard() and guard.parse(). This makes it async all the way down. Since we're already throwing when the llm_api isn't async I don't see a reason for maintaining a method signature that allows the user to pass in an incorrect value. With these changes it would also imply that the response itself should be awaitable. This would match the behaviour of other libraries the user would be familiar with like OpenAI: https://github.com/openai/openai-python?tab=readme-ov-file#async-usage

@wylansford
Copy link
Contributor Author

  1. Can we have AsyncGuard inherit guard and only override the call functions?

Done & fixed.

  1. In AsyncGuard, should all call overloads be Awaitables and marked async on the def?

I think this is up to where we want to handle the async management. Right now the _call function calls _call_async which sets the entry point there. Anything from the chain down there needs to be async. I think this is correct. Otherwise, If the call function is async it would be a bit awkward to need the user to manage any async functionality from the outside. With the current setup we will never have to call await on our guard because it's managed fully internally

My expectation for an AsyncGuard would be to have to always await both guard() and guard.parse(). This makes it async all the way down. Since we're already throwing when the llm_api isn't async I don't see a reason for maintaining a method signature that allows the user to pass in an incorrect value. With these changes it would also imply that the response itself should be awaitable. This would match the behaviour of other libraries the user would be familiar with like OpenAI: https://github.com/openai/openai-python?tab=readme-ov-file#async-usage

Yeah understood and can agree on that. Conforming to the other llm apis seems good. I just see this as a design preference of abstracting away async or not. Will make this change

@wylansford
Copy link
Contributor Author

  1. Can we have AsyncGuard inherit guard and only override the call functions?

Done & fixed.

  1. In AsyncGuard, should all call overloads be Awaitables and marked async on the def?

I think this is up to where we want to handle the async management. Right now the _call function calls _call_async which sets the entry point there. Anything from the chain down there needs to be async. I think this is correct. Otherwise, If the call function is async it would be a bit awkward to need the user to manage any async functionality from the outside. With the current setup we will never have to call await on our guard because it's managed fully internally

My expectation for an AsyncGuard would be to have to always await both guard() and guard.parse(). This makes it async all the way down. Since we're already throwing when the llm_api isn't async I don't see a reason for maintaining a method signature that allows the user to pass in an incorrect value. With these changes it would also imply that the response itself should be awaitable. This would match the behaviour of other libraries the user would be familiar with like OpenAI: https://github.com/openai/openai-python?tab=readme-ov-file#async-usage

Yeah understood and can agree on that. Conforming to the other llm apis seems good. I just see this as a design preference of abstracting away async or not. Will make this change

Change is made and pushed

@wylansford wylansford self-assigned this May 16, 2024
guardrails/guard.py Outdated Show resolved Hide resolved
@zsimjee zsimjee merged commit 6900497 into 0.4.4-dev May 17, 2024
@zsimjee zsimjee deleted the async_guard branch May 17, 2024 05:53
@zsimjee zsimjee added this to the v0.4.4 release milestone May 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request python Pull requests that update Python code
Projects
Development

Successfully merging this pull request may close these issues.

3 participants