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

feat(backend): refactor how inference providers are added and configured #475

Conversation

AgustinRamiroDiaz
Copy link
Contributor

@AgustinRamiroDiaz AgustinRamiroDiaz commented Sep 5, 2024

Fixes #359

What

Added configuration for LLM providers
We now have a schema defined in https://json-schema.org/, which checks that LLM provider configurations are compliant.

Expected flow for new providers

  1. Extend the JSON schema to add their providers
  2. If not compatible with other plugins, add a plugin to llms.py
  3. add a migration to load these new providers into the database

Step 3 seems to be the hardest for newcomers, since it would require a guide to use Alembic and SQLAlchemy to fill the database. Also, step 3 could not be desired since we'd be modifying provider configurations that users could've tuned and maybe don't want to change.
I'm open to ideas

Why

To allow new OpenAI compliant providers to come in and add their own by self registering

Testing done

  • Created e2e tests and unit tests

Decisions made

  • Decided to use json schema since
    • it's a big standard with an ecosystem of tools
    • JSON is widely adopted, like in our JSON-rpc
  • I've made a lot of extras along the way with the intent of improving the codebase as I was passing by

Checks

  • I have tested this code
  • I have reviewed my own PR
  • I have created an issue for this PR
  • I have set a descriptive PR title compliant with conventional commits

Reviewing tips

  • Don't check git history
  • review in order:
    1. json-schema
    2. tests
    3. code

User facing release notes

  • Refactored inference providers: now LLM providers and models can be extended and configured easily, opening the door for new providers to register.
  • Added new OpenAI o1-mini and o1-preview models
  • Added plugin to allow using Anthropic (Claude)

@AgustinRamiroDiaz AgustinRamiroDiaz force-pushed the 359-sim-refactor-how-inference-providers-are-added-and-configured branch from 5e6824c to b012247 Compare September 6, 2024 22:28
@AgustinRamiroDiaz AgustinRamiroDiaz changed the title 359 sim refactor how inference providers are added and configured feat(backend): refactor how inference providers are added and configured Sep 6, 2024
@@ -13,7 +13,7 @@ repos:
hooks:
- id: backend-unit-pytest
name: backend unit tests with pytest
entry: python3 -m pytest backend
entry: pytest tests/unit
Copy link
Contributor Author

Choose a reason for hiding this comment

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

extra: moved unit tests

Comment on lines +5 to 12
"python.testing.pytestArgs": ["tests", "backend"],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
"python.testing.pytestEnabled": true,
"sonarlint.connectedMode.project": {
"connectionId": "YeagerAI",
"projectKey": "yeagerai_genlayer-simulator"
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

extra: pytest and sonar vscode config

@@ -13,7 +13,7 @@ script_location = migration

# sys.path path, will be prepended to sys.path if present.
# defaults to the current working directory.
prepend_sys_path = .
prepend_sys_path = ./backend/database_handler
Copy link
Contributor Author

Choose a reason for hiding this comment

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

needed for imports

Comment on lines 27 to 31
def get_all_dict(self) -> list[dict]:
return [
{
"id": provider.id,
"provider": provider.provider,
"model": provider.model,
"config": provider.config,
}
for provider in self.session.query(LLMProviderDBModel).all()
]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is duplicated since LLMProvider does not have an ID. I think that it's fine for now, but I'm open to opinions on "should the domain models have IDs?"

Comment on lines +120 to +127
provider: Mapped[str] = mapped_column(String(255))
model: Mapped[str] = mapped_column(String(255))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did not add this pair of (provider, model) as a unique key since I feel that we'd be limiting the users. I think that it makes sense that users can create many provider configurations, and then use that pool to draw from

@@ -110,3 +110,22 @@ class Validators(Base):
created_at: Mapped[Optional[datetime.datetime]] = mapped_column(
DateTime(True), server_default=func.current_timestamp(), init=False
)


class LLMProviderDBModel(Base):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

One question that I'm thinking now is that if this should have any relationship with the validators, or if this is a pool to draw configurations with that could live independently?

Copy link
Collaborator

@cristiam86 cristiam86 Sep 10, 2024

Choose a reason for hiding this comment

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

The second one.
Could you please clarify the name? If the providers are called LLMProvider, why isn't this one called LLMProviderModel or just LLMModel?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was trying to come up with a convention around naming for the database models (the ones that are used with SQLAlchemy), so I thought about adding DBModel to it. I now see it's confusing since we also have the model from the llm.

Maybe just LLMProviderDB?

backend/protocol_rpc/endpoints.py Show resolved Hide resolved
@@ -25,7 +25,7 @@ COPY backend $path/backend
FROM base AS debug
RUN pip install --no-cache-dir debugpy watchdog
USER backend-user
CMD watchmedo auto-restart --recursive --pattern="*.py" --ignore-patterns="*.pyc;*__pycache__*" -- python -m debugpy --listen 0.0.0.0:${RPCDEBUGPORT} -m flask run -h 0.0.0.0 -p ${FLASK_SERVER_PORT}
CMD watchmedo auto-restart --no-restart-on-command-exit --recursive --pattern="*.py" --ignore-patterns="*.pyc;*__pycache__*" -- python -m debugpy --listen 0.0.0.0:${RPCDEBUGPORT} -m flask run -h 0.0.0.0 -p ${FLASK_SERVER_PORT}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

extra: doesn't restart when code exits, which most of the time is when there are "compile" errors

@AgustinRamiroDiaz AgustinRamiroDiaz marked this pull request as ready for review September 6, 2024 22:46
@AgustinRamiroDiaz AgustinRamiroDiaz force-pushed the 359-sim-refactor-how-inference-providers-are-added-and-configured branch from 13dca11 to 4d0ba72 Compare September 9, 2024 18:07
cristiam86
cristiam86 previously approved these changes Sep 10, 2024
Copy link
Collaborator

@cristiam86 cristiam86 left a comment

Choose a reason for hiding this comment

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

I like the approach and it is a big improvement from what we have now. Still, we need to try to document and follow the process of adding a new provider and model ourselves to identify some potential problems that anyone could have.
What concerns me more is the fact that a new provider needs to be added in different places because we have the default configs, some enums in the schemas, the database entry, etc.
Maybe the ideal scenario where someone just adds providers and models from the UI is very hard to achieve but we need to try to be closer to that one.


return_value = []

with warnings.catch_warnings():
Copy link
Collaborator

Choose a reason for hiding this comment

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

@AgustinRamiroDiaz could you please add some comments to understand this solution better?

backend/protocol_rpc/endpoints.py Show resolved Hide resolved
LLMProvider(
provider=provider,
model=model,
config=config,
Copy link
Collaborator

Choose a reason for hiding this comment

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

@AgustinRamiroDiaz, should we load the default one if the user sends an empty config?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cristiam86 this comment got moved and it's not pointing to the code you mention. Could you remind me on which function is this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added!

tests/integration/conftest.py Show resolved Hide resolved
first_default_provider = default_providers[0]
last_provider_id = default_providers[-1]["id"]

# Create a new provider
Copy link
Collaborator

Choose a reason for hiding this comment

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

@AgustinRamiroDiaz this seems too complicated and with some intrinsic logic. Could we just add manual hardcoded values?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't wanted to add hardcoded values since they'd be changing with the schema, but you are right. Once we have a stable schema these tests shouldn't change often

I'll create another test (I think this one adds it's own logic so I won't remove it)

@@ -0,0 +1,44 @@
from tests.common.request import payload, post_request_localhost
Copy link
Collaborator

Choose a reason for hiding this comment

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

@AgustinRamiroDiaz shouldn't we add a test for the update_validator?

tests/unit/test_providers.py Show resolved Hide resolved
@AgustinRamiroDiaz AgustinRamiroDiaz force-pushed the 359-sim-refactor-how-inference-providers-are-added-and-configured branch from 4d0ba72 to 36ed535 Compare September 10, 2024 11:03
@AgustinRamiroDiaz AgustinRamiroDiaz marked this pull request as draft September 10, 2024 16:32
@cristiam86 cristiam86 deleted the branch main September 11, 2024 09:57
@cristiam86 cristiam86 closed this Sep 11, 2024
@cristiam86 cristiam86 reopened this Sep 11, 2024
@cristiam86 cristiam86 changed the base branch from staging to main September 11, 2024 10:01
@cristiam86 cristiam86 dismissed their stale review September 11, 2024 10:01

The base branch was changed.

@AgustinRamiroDiaz AgustinRamiroDiaz linked an issue Sep 11, 2024 that may be closed by this pull request
Copy link

codecov bot commented Sep 11, 2024

Codecov Report

Attention: Patch coverage is 65.51724% with 10 lines in your changes missing coverage. Please review.

Project coverage is 17.35%. Comparing base (c4c2d77) to head (a16920c).
Report is 13 commits behind head on main.

Files with missing lines Patch % Lines
frontend/src/stores/node.ts 36.36% 7 Missing ⚠️
frontend/src/services/JsonRpcService.ts 50.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #475      +/-   ##
==========================================
- Coverage   17.90%   17.35%   -0.55%     
==========================================
  Files         111      111              
  Lines        7955     7928      -27     
  Branches      191      189       -2     
==========================================
- Hits         1424     1376      -48     
- Misses       6456     6477      +21     
  Partials       75       75              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
@AgustinRamiroDiaz AgustinRamiroDiaz force-pushed the 359-sim-refactor-how-inference-providers-are-added-and-configured branch from 978c463 to f778e7c Compare September 12, 2024 11:50
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
.values(
plugin=default_provider.plugin,
plugin_config=default_provider.plugin_config,
config=default_provider.config,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note that we are overriding existing configs. This is because the schema has changed and it's the simplest way. Handling the logic of migrating current configs is possible, but would be a lot of work and it's probably not a requirement

Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
@AgustinRamiroDiaz AgustinRamiroDiaz linked an issue Sep 13, 2024 that may be closed by this pull request
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
@AgustinRamiroDiaz AgustinRamiroDiaz linked an issue Sep 13, 2024 that may be closed by this pull request
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
@AgustinRamiroDiaz AgustinRamiroDiaz marked this pull request as ready for review September 13, 2024 15:19
@AgustinRamiroDiaz
Copy link
Contributor Author

@cristiam86 I've finished the PR and it's now ready to be reviewed

Note that I haven't been able to test the Claude Plugin

Copy link
Collaborator

@cristiam86 cristiam86 left a comment

Choose a reason for hiding this comment

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

Good job @AgustinRamiroDiaz. I have one concern about the performance adding/updating validators which now takes ~1 second while before it was instant. Do you happen to know why? Could it be related to the way we load the JSON providers files? could we paralelize that somehow?

@AgustinRamiroDiaz
Copy link
Contributor Author

@cristiam86 you were right! Fixed in my last commit by adding a cache + running it at startup 👍

@AgustinRamiroDiaz AgustinRamiroDiaz merged commit c089b16 into main Sep 17, 2024
18 of 19 checks passed
Copy link
Contributor

🎉 This PR is included in version 0.8.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@cristiam86 cristiam86 deleted the 359-sim-refactor-how-inference-providers-are-added-and-configured branch October 16, 2024 15:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants