-
Notifications
You must be signed in to change notification settings - Fork 237
feat(llm): extract BaseAnthropicLLM, add base_url, export extension points #566
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
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
8bb597f
anthropic-kwargs-bugfix-task-003: add sync/async http_client routing …
matteomedioli 94a2551
Extract BaseAnthropicLLM to hold shared Anthropic message-building an…
matteomedioli 6a47af1
Add explicit base_url parameter to AnthropicLLM
matteomedioli 8b6355f
Export BaseAnthropicLLM and BaseOpenAILLM as public extension points
matteomedioli 6f11a5d
Add test coverage for BaseAnthropicLLM extraction and base_url support
matteomedioli dd085e0
Document the http_client/base_url extension contract for LLM base cla…
matteomedioli 5c93f8b
Document BaseAnthropicLLM extraction and base_url support in changelog
matteomedioli 5d539da
Fix missing blank line after module docstring for ruff format
matteomedioli a758561
docs(examples): show base_url usage in AnthropicLLM example
matteomedioli c2a8c40
docs+api(llm): precise base_url/http_client contract, export split_ht…
matteomedioli 7615841
feat(llm): add explicit base_url parameter to OpenAILLM
matteomedioli c9a9df4
fix(llm): warn on http_client base_url, address review feedback
matteomedioli 91d1b2d
add: missing :class: cross-references for base classes
matteomedioli File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| .. _llm-page: | ||
|
|
||
| *********************************************** | ||
| LLMs | ||
| *********************************************** | ||
|
|
||
| This page gathers LLM-related documentation: configuring the built-in | ||
| providers and extending them to reach custom endpoints. | ||
|
|
||
| .. _llm-extensibility: | ||
|
|
||
| Extending LLMs: BaseAnthropicLLM/BaseOpenAILLM | ||
| ============================================== | ||
|
|
||
| :class:`~neo4j_graphrag.llm.anthropic_llm.BaseAnthropicLLM` and | ||
| :class:`~neo4j_graphrag.llm.openai_llm.BaseOpenAILLM` are the shared base classes behind | ||
| :class:`~neo4j_graphrag.llm.anthropic_llm.AnthropicLLM` and | ||
| :class:`~neo4j_graphrag.llm.openai_llm.OpenAILLM` respectively. They hold all | ||
| the provider-agnostic logic (message building, schema conversion, response | ||
| parsing, structured output handling) and leave SDK client construction to | ||
| their subclasses. This page documents the ``http_client``/``base_url`` | ||
| injection contract they expose, so you can point either provider at a custom | ||
| or self-hosted, API-compatible endpoint. | ||
|
|
||
| Both ``AnthropicLLM`` and ``OpenAILLM`` accept two related, independent | ||
| constructor settings: | ||
|
|
||
| - ``base_url`` (``Optional[str]``): an explicit constructor parameter on both | ||
| classes that overrides the default API endpoint. Passed through to both the | ||
| sync and async SDK clients (``anthropic.Anthropic`` / | ||
| ``anthropic.AsyncAnthropic`` for Anthropic, and the equivalent OpenAI SDK | ||
| clients for OpenAI). | ||
| - ``http_client`` (``Optional[httpx.Client | httpx.AsyncClient]``): an | ||
| already-configured ``httpx`` client to use for requests, e.g. to add custom | ||
| TLS settings, proxies, or timeouts. Accepted through ``**kwargs`` by both | ||
| classes. The concrete class inspects the type of the object you pass: an | ||
| ``httpx.Client`` is routed to the sync SDK client, and an | ||
| ``httpx.AsyncClient`` is routed to the async SDK client. Passing something | ||
| else emits a ``UserWarning`` (via ``warnings.warn``) and falls back to the | ||
| SDK's default client. | ||
|
|
||
| Both settings can be used together: ``base_url`` changes where requests go, | ||
| while ``http_client`` changes how they're sent. Note that a single | ||
| ``http_client`` only customizes one direction: calling the other one (e.g. | ||
| ``ainvoke`` after passing a sync ``httpx.Client``) still works and targets | ||
| ``base_url``, but through the SDK's default transport. | ||
|
|
||
| .. note:: | ||
|
|
||
| A ``base_url`` configured on the ``httpx`` client itself is ignored (a | ||
| ``UserWarning`` is emitted when one is detected): both | ||
| SDKs build absolute request URLs from their own ``base_url`` and only use | ||
| the ``httpx`` client as transport. To change the endpoint, always use the | ||
| ``base_url`` constructor parameter: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| # IGNORED -- the httpx base_url is never used; requests still go to | ||
| # the SDK's default endpoint | ||
| AnthropicLLM( | ||
| model_name="...", | ||
| http_client=httpx.Client(base_url="https://my-endpoint"), | ||
| ) | ||
|
|
||
| # WORKS -- requests go to the custom endpoint, with the custom transport | ||
| AnthropicLLM( | ||
| model_name="...", | ||
| base_url="https://my-endpoint", | ||
| http_client=httpx.Client(proxy="http://my-proxy:8080"), | ||
| ) | ||
|
|
||
| The sync/async routing is implemented by | ||
| :func:`neo4j_graphrag.llm.utils.split_http_client_kwargs`, which is exported | ||
| for exactly one reason: a custom subclass that constructs its own SDK clients | ||
| should call it too, so it preserves the same routing contract instead of | ||
| reintroducing the type-mismatch bug the helper fixes. | ||
|
|
||
| Subclassing example | ||
| ------------------- | ||
|
|
||
| Because :class:`~neo4j_graphrag.llm.anthropic_llm.BaseAnthropicLLM` / | ||
| :class:`~neo4j_graphrag.llm.openai_llm.BaseOpenAILLM` only require the concrete | ||
| subclass to assign ``self.client``/``self.async_client``, you can build your | ||
| own thin subclass to reach a custom Anthropic-compatible endpoint with | ||
| different defaults or credential handling than the built-in ``AnthropicLLM``: | ||
|
|
||
| .. code:: python | ||
|
|
||
| from typing import Any, Optional | ||
|
|
||
| import anthropic | ||
|
|
||
| from neo4j_graphrag.llm import BaseAnthropicLLM | ||
| from neo4j_graphrag.llm.utils import split_http_client_kwargs | ||
|
|
||
|
|
||
| class MyCustomAnthropicLLM(BaseAnthropicLLM): | ||
| """Talks to a self-hosted, Anthropic-compatible endpoint.""" | ||
|
|
||
| DEFAULT_ENDPOINT = "https://my-custom-endpoint.example.com" | ||
|
|
||
| def __init__( | ||
| self, | ||
| model_name: str, | ||
| model_params: Optional[dict[str, Any]] = None, | ||
| **kwargs: Any, | ||
| ): | ||
| super().__init__(model_name=model_name, model_params=model_params, **kwargs) | ||
| # Route an optional http_client kwarg to the matching sync/async | ||
| # client, exactly as the built-in AnthropicLLM does. | ||
| sync_params, async_params = split_http_client_kwargs(kwargs) | ||
| sync_params.setdefault("base_url", self.DEFAULT_ENDPOINT) | ||
| async_params.setdefault("base_url", self.DEFAULT_ENDPOINT) | ||
| self.client = anthropic.Anthropic(**sync_params) | ||
| self.async_client = anthropic.AsyncAnthropic(**async_params) | ||
|
|
||
|
|
||
| llm = MyCustomAnthropicLLM(model_name="claude-3-opus-20240229") | ||
| llm.invoke("Who is the mother of Paul Atreides?") | ||
|
|
||
| All of ``invoke``/``ainvoke``, structured-output handling, and message | ||
| building are inherited from :class:`~neo4j_graphrag.llm.anthropic_llm.BaseAnthropicLLM` unchanged; the subclass only | ||
| needs to decide how ``client``/``async_client`` get constructed. | ||
|
|
||
| The same pattern applies to :class:`~neo4j_graphrag.llm.openai_llm.BaseOpenAILLM` | ||
| for OpenAI-compatible endpoints. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.