-
Notifications
You must be signed in to change notification settings - Fork 10
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
feat(backend): refactor how inference providers are added and configured #475
Conversation
5e6824c
to
b012247
Compare
@@ -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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra: moved unit tests
"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" | ||
} | ||
} |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needed for imports
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() | ||
] |
There was a problem hiding this comment.
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?"
provider: Mapped[str] = mapped_column(String(255)) | ||
model: Mapped[str] = mapped_column(String(255)) |
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
?
@@ -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} |
There was a problem hiding this comment.
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
13dca11
to
4d0ba72
Compare
There was a problem hiding this 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(): |
There was a problem hiding this comment.
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?
LLMProvider( | ||
provider=provider, | ||
model=model, | ||
config=config, |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added!
first_default_provider = default_providers[0] | ||
last_provider_id = default_providers[-1]["id"] | ||
|
||
# Create a new provider |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
4d0ba72
to
36ed535
Compare
Codecov ReportAttention: Patch coverage is
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. |
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]>
978c463
to
f778e7c
Compare
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, |
There was a problem hiding this comment.
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]>
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]>
@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 |
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
There was a problem hiding this 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?
Signed-off-by: Agustín Ramiro Díaz <[email protected]>
@cristiam86 you were right! Fixed in my last commit by adding a cache + running it at startup 👍 |
🎉 This PR is included in version 0.8.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
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
llms.py
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
Decisions made
Checks
Reviewing tips
User facing release notes