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

Upgrade OpenAI SDK to v1 #1017

Merged
merged 37 commits into from
Dec 4, 2023
Merged

Conversation

tonybaloney
Copy link
Contributor

@tonybaloney tonybaloney commented Nov 29, 2023

Summary of changes

  • Open AI SDK v1 uses a client object, however it doesn't accept a deployment name as the parameter to the chat completions or embeddings methods, so we still need to create two clients. I've raised an issue with the Open AI team about this. In the meantime, it removed a lot of code to store state in global variables
  • I've implemented both Azure OpenAI clients using a token provider instead of a runtime token, this means it will fetch a token for each session call and removed a lot of workaround code to refresh tokens
  • The return types in the new SDK are Pydantic models. I've converted them back into dictionaries at the exit-point for the approach classes so it shouldn't leak too much of the abstraction
  • The new Pydantic models have required fields that we didn't bother to mock/patch in the original test code. I wanted to make the mocked responses as realistic as possible (within reason), so I've included them and that meant updating all the snapshots
  • I've changed the two mock fixtures for the chat completions and embeddings API to be fixture-factories that patch the method of the live client object instead of mocking the underlying OpenAI methods. This should make them more robust if OpenAI refactor their code

TODO List

  • Update dependencies
  • Update prepdocs lib
  • Update backend service API
  • Update Chat Retrieve Read
  • Update Retrieve then Read
  • Test

Reviewers : please test as many bits of functionality as you can. I've tested this locally and deployed it to test in a production instance, but many hands find more bugs :-)

@pamelafox
Copy link
Collaborator

Re tests- they did post some example mocks:
openai/openai-python#715 (comment)
It might be useful to compare our approach to theirs. (I haven't had time yet myself)

@tonybaloney
Copy link
Contributor Author

Re tests- they did post some example mocks: openai/openai-python#715 (comment) It might be useful to compare our approach to theirs. (I haven't had time yet myself)

thanks, I've done something very similar. Most of the remaining work is because the old SDK used to return dictionaries and the new one returns typed pydantic models

@tonybaloney tonybaloney marked this pull request as ready for review November 29, 2023 09:12
Copy link
Collaborator

@pamelafox pamelafox left a comment

Choose a reason for hiding this comment

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

Krista says that we should use model to specify deployment, so you can use a single client, which I think is better for code complexity.

@pamelafox
Copy link
Collaborator

@tonybaloney I tested it and discovered an issue with follow-up questions. Previously, an event choice would either have a content string or have no content property at all, but now it can have "content": None. I've adjusted the code and test fixture to account for that.

@pamelafox
Copy link
Collaborator

I tested it with non-Azure OpenAI with an existing environment and there's an issue due to this new logic in the approaches:

chatgpt_model = self.chatgpt_deployment if self.chatgpt_deployment else self.chatgpt_model

The problem is that AZURE_OPENAI_CHATGPT_DEPLOYMENT has a value even if you're using non-Azure OpenAI (defaults to "chat").

One way around that is to clear out the relevant variables in app.py, before they get passed into the approaches. This change worked for me:

    AZURE_OPENAI_CHATGPT_DEPLOYMENT = OPENAI_HOST == "azure" and os.getenv("AZURE_OPENAI_CHATGPT_DEPLOYMENT")
    AZURE_OPENAI_EMB_DEPLOYMENT = OPENAI_HOST == "azure" and os.getenv("AZURE_OPENAI_EMB_DEPLOYMENT")

The error can't be replicated in test, by the way, as it's an error from the server that the model "chat" cannot be found.

@tonybaloney
Copy link
Contributor Author

@tonybaloney I tested it and discovered an issue with follow-up questions. Previously, an event choice would either have a content string or have no content property at all, but now it can have "content": None. I've adjusted the code and test fixture to account for that.

I added the and content on this line because I saw a bug where it would crash with follow up questions, but maybe I introduced another bug in the process? c2d20f2#diff-a346ba4129613c27f42a9a4de5439423af8ab6df6eb79eaf555204da3d588001R302 could this be simplified if we removed the and content in the if statement?

@pamelafox
Copy link
Collaborator

@tonybaloney You could remove "and content" now, since my line takes care of that (so that in operator works). But we'd need to keep the line that turns it into an empty string.
I think this is just an effect of the move to Pydantic models with model_dump

@tonybaloney
Copy link
Contributor Author

I tested it with non-Azure OpenAI with an existing environment and there's an issue due to this new logic in the approaches:

chatgpt_model = self.chatgpt_deployment if self.chatgpt_deployment else self.chatgpt_model

The problem is that AZURE_OPENAI_CHATGPT_DEPLOYMENT has a value even if you're using non-Azure OpenAI (defaults to "chat").

One way around that is to clear out the relevant variables in app.py, before they get passed into the approaches. This change worked for me:

    AZURE_OPENAI_CHATGPT_DEPLOYMENT = OPENAI_HOST == "azure" and os.getenv("AZURE_OPENAI_CHATGPT_DEPLOYMENT")
    AZURE_OPENAI_EMB_DEPLOYMENT = OPENAI_HOST == "azure" and os.getenv("AZURE_OPENAI_EMB_DEPLOYMENT")

The error can't be replicated in test, by the way, as it's an error from the server that the model "chat" cannot be found.

Good spot. Fixed

app/backend/app.py Outdated Show resolved Hide resolved
scripts/requirements.in Outdated Show resolved Hide resolved
Copy link
Collaborator

@pamelafox pamelafox left a comment

Choose a reason for hiding this comment

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

Done with my deploy tests and code review. No big items, just minor comments.

Copy link
Collaborator

@mattgotteiner mattgotteiner left a comment

Choose a reason for hiding this comment

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

LGTM

@pamelafox pamelafox merged commit aa02563 into Azure-Samples:main Dec 4, 2023
8 checks passed
HughRunyan pushed a commit to RMI/RMI_chatbot that referenced this pull request Mar 26, 2024
* Update version ranges for 1.3.5 openai lib

* Update the embeddings library in scripts to use OpenAI 1.3.5 remove some redundant methods

* Update the embedding response to use a typed model

* Rewrite test_prepdocs to patch out OpenAI v1 models and responses

* Update approaches to use new APIs

* Update backend service and read approaches to use new SDK

* Fix get_search_query. Update RRR approach tests

* Update search manager tests

* Change patching for app tests

* Use deployment ID only in the constructor of the Azure OpenAI Client object and remove it from the approach constructors (and all the logic that went with it)

* Explicitly include aiohttp in prepdocs requirements

* Use two clients because the new SDK doesn't support a deployment name in the chat or embeddings methods

* Ruff ruff

* Simplify typing constructor

* Update types for message history

* Convert RRR to dict before returning

* Bend the rules of physics to get mypy to pass

* Run black over scripts again

* Fix content filtering, update snapshot tests, implement pydantic models for streaming responses.

* Update the snapshots with the new required fields for chunked completions. Update the iterator to pass pydantic model validation

* Force keyword arguments as the list of arguments is long and complicated

* Refactor to have a single client object

* Drop argument

* Type the chat message builder with pydantic

* Rebuild requirements from merge conflicts

* Update formatting

* Fix issue with follow-up questions

* Simplify content check

* Don't use deployment field for non azure

* Update requirements.in

* Remove upper bound

* Remove dependabot constraint

* Merge the clients again

* Fix test_app client name

* Inline the ternary statement to pick either a model or deployment name for the OpenAI SDK calls

---------

Co-authored-by: Pamela Fox <pamela.fox@gmail.com>
Co-authored-by: Pamela Fox <pamelafox@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants