|
1 | | -# llm‑router-LIB — Python client library |
2 | | - |
3 | | -**llm‑router** is a lightweight Python client for interacting with the LLM‑Router API. |
4 | | -It provides typed request models, convenient service wrappers, and robust error handling so you can focus on building |
5 | | -LLM‑driven applications rather than dealing with raw HTTP calls. |
6 | | - |
7 | | ---- |
| 1 | +# llm_router_lib |
8 | 2 |
|
9 | 3 | ## Overview |
10 | 4 |
|
11 | | -`llm_router_lib` is the official Python SDK for the **LLM‑Router** |
12 | | -project <https://github.com/radlab-dev-group/llm-router>. |
13 | | - |
14 | | -It abstracts the HTTP layer behind a small, well‑typed API: |
15 | | - |
16 | | -* **Typed payloads** built with *pydantic* (e.g., `GenerativeConversationModel`). |
17 | | -* **Service objects** that know the endpoint URL and the model class they expect. |
18 | | -* **Automatic token handling**, request retries, and exponential back‑off. |
19 | | -* **Rich exception hierarchy** (`LLMRouterError`, `AuthenticationError`, `RateLimitError`, `ValidationError`). |
20 | | - |
21 | | ---- |
| 5 | +`llm_router_lib` is ** a collection of data‑model definitions**. |
| 6 | +It supplies the **foundation** for request/response structures used by the |
| 7 | +`llm_router_api` package **and** provides a **thin, opinionated client wrapper** |
| 8 | +that makes interacting with the LLM Router service straightforward. |
22 | 9 |
|
23 | | -## Features |
| 10 | +Key components: |
24 | 11 |
|
25 | | -| Feature | Description | |
26 | | -|------------------------------------|--------------------------------------------------------------------------------| |
27 | | -| **Typed request/response models** | Guarantees payload correctness at runtime using Pydantic. | |
28 | | -| **Built‑in conversation services** | Simple `conversation_with_model` and `extended_conversation_with_model` calls. | |
29 | | -| **Retry & timeout** | Configurable request timeout and automatic retries with exponential back‑off. | |
30 | | -| **Authentication** | Bearer‑token support; raises `AuthenticationError` on 401/403. | |
31 | | -| **Rate‑limit handling** | Detects HTTP 429 and raises `RateLimitError`. | |
32 | | -| **Extensible** | Add custom services or models by extending the base classes. | |
33 | | -| **Test suite** | Ready‑to‑run unit tests in `llm_router_lib/tests`. | |
| 12 | +| Package | Purpose | |
| 13 | +|---------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |
| 14 | +| **`data_models`** | `pydantic` models that define the shape of payloads sent to the router (e.g. `GenerativeConversationModel`, `ExtendedGenerativeConversationModel`, utility models for question generation, translation, etc.). These models are shared with the API side, ensuring both client and server speak the same contract. | |
| 15 | +| **`client.py`** | `LLMRouterClient` – a lightweight wrapper around the router’s HTTP API. It offers high‑level methods (`conversation_with_model`, `extended_conversation_with_model`) that accept either plain dictionaries **or** the aforementioned data‑model instances. The client handles payload validation, provider selection, error mapping, and response parsing. | |
| 16 | +| **`services`** | Low‑level service classes (`ConversationService`, `ExtendedConversationService`) that perform the actual HTTP calls via `HttpRequester`. They are used internally by the client but can be reused directly if finer‑grained control is needed. | |
| 17 | +| **`exceptions.py`** | Custom exception hierarchy (`LLMRouterError`, `AuthenticationError`, `RateLimitError`, `ValidationError`) that mirrors the router’s error semantics, making error handling in user code clean and explicit. | |
| 18 | +| **`utils/http.py`** | `HttpRequester` – a small wrapper around `requests` providing retries, time‑outs and logging. It is the networking backbone for the client wrapper. | |
34 | 19 |
|
35 | | ---- |
| 20 | +In short, `llm_router_lib` provides **both** the data contract (the “schema”) **and** a convenient Pythonic client to |
| 21 | +consume the router service. |
36 | 22 |
|
37 | 23 | ## Installation |
38 | 24 |
|
39 | | -The library is pure Python and works with **Python 3.10+**. |
| 25 | +The library targets **Python 3.10.6** and uses a `virtualenv`. Install it in editable mode for development: |
40 | 26 |
|
41 | | -```shell script |
42 | | -# Create a virtualenv (recommended) |
43 | | -python -m venv .venv |
| 27 | +``` bash |
| 28 | +# Clone the repository (if you haven't already) |
| 29 | +git clone https://github.com/radlab-dev-group/llm-router.git |
| 30 | +cd llm-router/llm_router_lib |
| 31 | + |
| 32 | +# Create and activate a virtual environment |
| 33 | +python3 -m venv .venv |
44 | 34 | source .venv/bin/activate |
45 | 35 |
|
46 | | -# Install from the repository (editable mode) |
| 36 | +# Install the package and its dependencies |
47 | 37 | pip install -e . |
48 | 38 | ``` |
49 | 39 |
|
50 | | -If you prefer a regular installation from a wheel or source distribution, use: |
51 | | - |
52 | | -```shell script |
53 | | -pip install . |
54 | | -``` |
55 | | - |
56 | | -> **Note** – The project relies only on the packages listed in the repository’s `requirements.txt` |
57 | | -> (pydantic, requests, etc.), all of which are installed automatically by `pip`. |
58 | | -
|
59 | | ---- |
| 40 | +All runtime dependencies (`requests`, `pydantic`, `rdl_ml_utils`) are declared in the project’s `requirements.txt`. |
60 | 41 |
|
61 | 42 | ## Quick start |
62 | 43 |
|
63 | | -```python |
64 | | -from llm_router_lib.client import LLMRouterClient |
65 | | -from llm_router_lib.data_models.builtin_chat import GenerativeConversationModel |
| 44 | +``` python |
| 45 | +from llm_router_lib import LLMRouterClient |
66 | 46 |
|
67 | | -# Initialise the client (replace with your own endpoint and token) |
| 47 | +# Initialise the client – point it at the router’s base URL |
68 | 48 | client = LLMRouterClient( |
69 | | - api="https://api.your-llm-router.com", |
70 | | - token="YOUR_ACCESS_TOKEN" |
| 49 | + api="http://localhost:8080/api", # router base URL |
| 50 | + token="YOUR_ROUTER_TOKEN", # optional, if router requires auth |
71 | 51 | ) |
72 | 52 |
|
73 | | -# Build a request payload |
74 | | -payload = GenerativeConversationModel( |
75 | | - model_name="google/gemma-3-12b-it", |
76 | | - user_last_statement="Hello, how are you?", |
77 | | - historical_messages=[{"user": "Hi"}], |
78 | | - temperature=0.7, |
79 | | - max_new_tokens=128, |
80 | | -) |
| 53 | +# Build a payload using the provided data model (validation is automatic) |
| 54 | +payload = { |
| 55 | + "model_name": "google/gemma-3-12b-it", |
| 56 | + "user_last_statement": "Hello, how are you?", |
| 57 | + "temperature": 0.7, |
| 58 | + "max_new_tokens": 128, |
| 59 | +} |
81 | 60 |
|
82 | | -# Call the API |
| 61 | +# Call the standard conversation endpoint |
83 | 62 | response = client.conversation_with_model(payload) |
84 | 63 |
|
85 | | -print(response) # → dict with the model's answer and metadata |
| 64 | +print(response) # → {'status': True, 'body': {...}} |
86 | 65 | ``` |
87 | 66 |
|
88 | | -### Extended conversation |
| 67 | +You can also pass a `pydantic` model instance directly: |
89 | 68 |
|
90 | | -```python |
91 | | -from llm_router_lib.data_models.builtin_chat import ExtendedGenerativeConversationModel |
| 69 | +``` |
| 70 | +python |
| 71 | +from llm_router_lib.data_models.builtin_chat import GenerativeConversationModel |
92 | 72 |
|
93 | | -payload = ExtendedGenerativeConversationModel( |
| 73 | +model = GenerativeConversationModel( |
94 | 74 | model_name="google/gemma-3-12b-it", |
95 | | - user_last_statement="Explain quantum entanglement.", |
96 | | - system_prompt="Answer as a friendly professor.", |
97 | | - temperature=0.6, |
98 | | - max_new_tokens=256, |
| 75 | + user_last_statement="Hello, how are you?", |
| 76 | + temperature=0.7, |
| 77 | + max_new_tokens=128, |
99 | 78 | ) |
100 | 79 |
|
101 | | -response = client.extended_conversation_with_model(payload) |
102 | | -print(response) |
| 80 | +response = client.conversation_with_model(model) |
103 | 81 | ``` |
104 | 82 |
|
105 | | ---- |
106 | | - |
107 | | -## Core concepts |
108 | | - |
109 | | -### Client |
110 | | - |
111 | | -`LLMRouterClient` is the entry point. It handles: |
112 | | - |
113 | | -* Base URL normalization. |
114 | | -* Optional bearer token injection. |
115 | | -* Construction of the internal `HttpRequester`. |
| 83 | +## Data models |
116 | 84 |
|
117 | | -All public methods accept either a **dict** or a **pydantic model**; models are automatically serialized with |
118 | | -`.model_dump()`. |
| 85 | +All request payloads are defined in `llm_router_lib/data_models`. |
| 86 | +Common base: |
119 | 87 |
|
120 | | -### Data models |
121 | | - |
122 | | -Located in `llm_router_lib/data_models/`. |
123 | | -Key models: |
124 | | - |
125 | | -| Model | Purpose | |
126 | | -|----------------------------------------------|-------------------------------------------------------------------| |
127 | | -| `GenerativeConversationModel` | Simple chat payload (model name, user message, optional history). | |
128 | | -| `ExtendedGenerativeConversationModel` | Same as above, plus a `system_prompt`. | |
129 | | -| `GenerateQuestionFromTextsModel` | Generate questions from a list of texts. | |
130 | | -| `TranslateTextModel`, `SimplifyTextModel`, … | Various utility models for text transformation. | |
131 | | -| `OpenAIChatModel` | Payload for direct OpenAI‑compatible chat calls. | |
132 | | - |
133 | | -All models inherit from a common `_GenerativeOptions` base that defines temperature, token limits, language, etc. |
134 | | - |
135 | | -### Services |
136 | | - |
137 | | -Implemented in `llm_router_lib/services/`. |
138 | | -Each service extends `_BaseConversationService` and defines: |
139 | | - |
140 | | -* `endpoint` – the API path (e.g., `/api/conversation_with_model`). |
141 | | -* `model_cls` – the Pydantic model class used for validation. |
142 | | - |
143 | | -The service’s `call()` method performs the HTTP POST and returns a parsed JSON dictionary, raising `LLMRouterError` on |
144 | | -malformed responses. |
| 88 | +``` python |
| 89 | +class BaseModelOptions(BaseModel): |
| 90 | + """Options shared across many endpoint models.""" |
| 91 | + mask_payload: bool = False |
| 92 | + masker_pipeline: Optional[List[str]] = None |
| 93 | +``` |
145 | 94 |
|
146 | | -### Utilities |
| 95 | +### Conversation models |
147 | 96 |
|
148 | | -* `llm_router_lib/utils/http.py` – thin wrapper around `requests` with retry logic, response validation, and logging. |
149 | | -* Logging is integrated via the standard library `logging` module; you can inject your own logger when constructing the |
150 | | - client. |
| 97 | +| Model | Required fields | Optional / extra fields | |
| 98 | +|---------------------------------------|-------------------------------------|-----------------------------------------------------------| |
| 99 | +| `GenerativeConversationModel` | `model_name`, `user_last_statement` | `temperature`, `max_new_tokens`, `historical_messages`, … | |
| 100 | +| `ExtendedGenerativeConversationModel` | All of the above + `system_prompt` | – | |
151 | 101 |
|
152 | | -### Error handling |
| 102 | +Utility models for other built‑in endpoints (question generation, translation, |
| 103 | +article creation, context‑based answering, etc.) follow the same pattern and |
| 104 | +inherit from `BaseModelOptions`. |
153 | 105 |
|
154 | | -| Exception | When raised | |
155 | | -|-----------------------|-----------------------------------------------------------| |
156 | | -| `LLMRouterError` | Generic SDK‑level error (e.g., non‑JSON response). | |
157 | | -| `AuthenticationError` | HTTP 401/403 – missing or invalid token. | |
158 | | -| `RateLimitError` | HTTP 429 – the server throttled the request. | |
159 | | -| `ValidationError` | HTTP 400 – request payload failed server‑side validation. | |
| 106 | +## Thin client wrapper (`LLMRouterClient`) |
160 | 107 |
|
161 | | -All exceptions inherit from `LLMRouterError`, allowing a single `except LLMRouterError:` clause to catch any SDK‑related |
162 | | -problem. |
| 108 | +`LLMRouterClient` offers a **high‑level API** that abstracts away the low‑level |
| 109 | +HTTP details: |
163 | 110 |
|
164 | | ---- |
| 111 | +| Method | Description | |
| 112 | +|---------------------------------------------|----------------------------------------------------------------------------------------------------------------| |
| 113 | +| `conversation_with_model(payload)` | Calls `/api/conversation_with_model`. Accepts a dict **or** a `GenerativeConversationModel`. | |
| 114 | +| `extended_conversation_with_model(payload)` | Calls `/api/extended_conversation_with_model`. Accepts a dict **or** an `ExtendedGenerativeConversationModel`. | |
165 | 115 |
|
166 | | -## License |
| 116 | +Internally the client: |
167 | 117 |
|
168 | | -`llm_router_lib` is released under the **MIT License**. See the `LICENSE` file for details. |
| 118 | +1. **Validates** the payload (via the corresponding `pydantic` model if a model instance is supplied). |
| 119 | +2. **Selects** an appropriate provider using the router’s load‑balancing |
0 commit comments