File size: 6,525 Bytes
1556404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233

# 🧩 Integrating Local LLMs into **ShinkaEvolve**

## 🧠 Overview

The original **ShinkaEvolve** code does **not** include built-in support for running **local LLMs**.
To enable this functionality, parts of the codebase can be modified to integrate locally hosted models.

---

## 🏗️ Code Organization

**ShinkaEvolve** uses a **modular architecture** that supports multiple **LLM providers**.
The relevant code for LLM interaction is located in the **`LLM/`** folder, which manages all model communications.
ShinkaEvolve distinguishes between two LLM types:

* **Regular LLMs**
* **Embedding LLMs**

---

## ⚙️ Adding a Regular LLM

To add support for a **regular LLM**, follow these steps. They will show an example of adding support for gpt-oss models running with unsloth, which provides an API compatible with OpenAI API (v1/completions).
This LLM can then be specified in the configuration variables:

```yaml
llm_models:
meta_llm_models:
```

---

### 🔧 Step 1: Modify the Client

The file **`client.py`** is responsible for creating clients that interact with LLMs.
Each client instance is later used to query a specific model.

To add a local model, introduce a new client configuration.
The API URL is extracted from the model name, which follows this format:

```
local-gptoss-unsloth-url
```

#### Example

```python
elif "local-gptoss-unsloth" in model_name:
    # Extract URL from model name
    pattern = r"https?://"
    match = re.search(pattern, model_name)
    if match:
        start_index = match.start()
        url = model_name[start_index:]
    else:
        raise ValueError(f"Invalid URL in model name: {model_name}")
    
    # Create OpenAI-compatible client
    client = openai.OpenAI(
        api_key="filler",
        base_url=url
    )

    # Structured output mode (if required)
    if structured_output:
        client = instructor.from_openai(
            client,
            mode=instructor.Mode.JSON,
        )
```

---

### 📁 Step 2: Create the Local Query Function

Inside the **`models/`** folder, create a new subfolder to store the query functions for your local models:

```
LLM/models/local/
```

> Don’t forget to include an empty `__init__.py` file.

This folder should contain a **custom query function** for the local model. I called my file local_gptoss_unsloth.py.
It should follow the same structure as other functions in `LLM/models/`, but with small adjustments.

#### My Key Adjustments

* Replace `max_output_tokens` with **`max_tokens`** to match the local API.
* Extract additional response metadata such as:

  * `total_tokens`
  * `thinking_tokens` (if your model includes reasoning traces)

This function is later imported and registered in **`query.py`**.

---

### 🧩 Step 3: Update `__init__.py`

Configure **`__init__.py`** to include and expose the new local query function, so it can be imported elsewhere.

```
from .local.local_gptoss_unsloth import query_local_gptoss_unsloth            # ADDED THIS LINE
from .result import QueryResult

__all__ = [
    "query_anthropic",
    "query_openai",
    "query_deepseek",
    "query_gemini",
    "query_local_gptoss_unsloth",              # ADDED THIS LINE
    "QueryResult",
]
```

---

### 📬 Step 4: Update `query.py`

Import and register the new local query function in query.py.

#### Imports

```python
from .models import (
    query_anthropic,
    query_openai,
    query_deepseek,
    query_gemini,
    query_local_gptoss_unsloth,  # ADDED THIS LINE
    QueryResult,
)
```

#### Model Selection Logic

```python
elif "local-gptoss-unsloth" in model_name:  # ADDED THIS LINE
    query_fn = query_local_gptoss_unsloth
```

---

### 🧠 Step 5: Other Observations

The file **`query.py`** also defines functions such as:

* `sample_model_kwargs`
* `sample_batch_kwargs`

However, these are **not referenced anywhere else** in the repository, so no modifications are required here for now.

---

### ✅ Summary

| Step | File                                         | Change               | Description                                              |
| ---- | -------------------------------------------- | -------------------- | -------------------------------------------------------- |
| 1    | `client.py`                                  | Add new client block | Create OpenAI-compatible client for local LLM            |
| 2    | `models/local/query_local_gptoss_unsloth.py` | New function         | Query local model, adjust tokens, extract reasoning info |
| 3    | `__init__.py`                                | Add import           | Expose new query function                                |
| 4    | `query.py`                                   | Register model       | Add conditional for local LLM                            |
| 5    | —                                            | Review only          | Ignored unused functions                                 |

---

## 🧬 Adding a Local Embedding Model

For embedding models, you can use **Ollama**, which follows the **OpenAI API** format.
The only relevant file is **`embedding.py`**.

### Code Addition

```python
elif model_name.startswith("local-"):
    # Pattern: local-(model-name)-(http or https url)
    match = re.match(r"local-(.+?)-(https?://.+)", model_name)
    if match:
        model_to_use = match.group(1)
        url = match.group(2)
    else:
        raise ValueError(f"Invalid local model format: {model_name}")

    client = openai.OpenAI(
        base_url=url,
        api_key="filler"
    )
```

#### Notes

* Compatible with **any Ollama model**.
* The model name must follow this convention:

  ```
  local-model-name-url
  ```
* The code extracts both `model-name` and `url`, and uses them to query Ollama.

---

### Query Logic

The existing line in **`embedding.py`** remains unchanged:

```python
response = self.client.embeddings.create(
    model=self.model,
    input=code,
    encoding_format="float"
)
```

For local embedding models, `self.model` corresponds to the extracted model name.
The only addition to the **Embedding Client** class:

```python
elif self.model_name.startswith("local-"):
    cost = 0.0
```

---

## 🚀 Result

ShinkaEvolve can now connect to **locally hosted LLMs** and **embedding models** through **OpenAI-compatible APIs**.
This setup supports **Ollama** and other frameworks such as **gpt-oss** under **Unsloth**.

If your model has different requirements, follow the same pattern with a distinct model identifier and your own custom logic.