Lokalne llm w automatycznym generowaniu kodu
Czy LLMy potrafią skutecznie generować kod? Obecnie bez wątpienia. Jednak pytanie czy jesteśmy skazani na używanie publicznych API, które są płatne? czy możemy również generować kod własnym sprzętem?
Przeprowadzony eksperyment pokazuje próby rozwiązania prostego problemu pakowania z kilkoma dodakowymi przeszkodami. Do testów używałem rozszerzenia Cline jako że daje możliwość modelom uruchamianie aplikacji, interpretację wyników i poprawę własnego kodu.
Zadanie wyglądało tak:
#main.py
from random import randint
import solution
def generate_items():
"""
Generate a list of random items with lengths between 4 to 20.
"""
length = randint(4, 20)
return [randint(4, 20) for _ in range(length)]
def calculate_cost(package_list):
"""
Calculate the total cost of packaging based on the packages.
"""
cost = 0
for package in package_list:
size = 0
for layer in package:
if size < sum(layer):
size = sum(layer)
cost += size
return cost
def check_rolues(package_list, items):
"""
Check various roles and constraints of the packaging.
"""
max_weight_package = 40
total_weight = 0
for package in package_list:
single_element_layer = 0
weight = 0
#find the largest item in each package
for layer in package:
if len(layer) == 1 and layer[0] > single_element_layer:
single_element_layer = layer[0]
#the largest item does not define the size of the package
for layer in package:
if sum(layer) > single_element_layer:
print("The biggest item is not define the size of the package")
return False
#check weight of each package to be less than 40
for layer in package:
weight += sum(layer)
total_weight += weight
if weight > max_weight_package:
print("Weight is more than 40")
return False
#check total weight to be equal to sum of all item
if total_weight != sum(items):
print("The items have been changed")
return False
return True
if __name__ == "__main__":
# Generate a list of random items
items = generate_items()
print("Generated items:", items)
# Pack the items into packages using LLM
package_list = solution.packing(items)
# Calculate the cost of packaging if checks pass
print("Cost of Packaging:")
cost = None
if check_rolues(package_list, items):
for package in package_list:
print(package)
cost = calculate_cost(package_list)
print("Packing Cost:", cost)
Modele które udało się przetestować to deepcoder:14b, deepseek-r1:14b, gemma3:12b, qwen3:14b. Użytkowanie tych modeli nie jest plug and play. Potrafiły się one zapętlać, bądź zmieniać sam plik main.py Generowana logika potrafiła zmieniać się np jeśli nazwę zmiennej zawierającą wygenerowane dane zmieniłem z numers na items, lub gdy we wcześniejszych wersjach rozpisałem check_rolues dla kilku modeli.
Ten ostatni przypadek jest szczególnie ciekawy gdyż wydawało się że modele zaczynają rozumieć że dochodzi do rywalizacji, a generowane rozwiązania były lepsze.
Koniec końców wszystkie funkcje nie są wyszukane, nie ma zaawansowanych heurystyk czy generowania całej przestrzeni rozwiązań. Wszystkie okazały się dość leniwe, co więcej tylko gemma wykorzystała inny algorytm który w dodatku jest gorszy od pozostałych. Wszsytkie modele obrały strategię by nie pchać kilku elementów do warstwy w paczce a optymalizować rozmiary każdej z nich, sortując te elementy. Należy także brać pod uwagę że może być to efekt niezamierzony lub intuicja(?). Poniżej przedstawiam przykładowe wyniki
Generated items: [15, 15, 18, 11, 14, 7, 16, 9, 12, 8, 9, 18, 20, 6, 8, 18, 4, 9]
Cost of Packaging:
[[20], [18]]
[[18], [18], [4]]
[[16], [15], [9]]
[[15], [14], [11]]
[[12], [9], [9], [8]]
[[8], [7], [6]]
Deepcoder Cost: 89
[[20], [18]]
[[18], [18], [4]]
[[16], [15], [9]]
[[15], [14], [11]]
[[12], [9], [9], [8]]
[[8], [7], [6]]
Deepseek Cost: 89
[[15], [15]]
[[18], [11]]
[[14], [7], [16]]
[[9], [12], [8], [9]]
[[18], [20]]
[[6], [8], [18], [4]]
[[9]]
Gemma Cost: 108
[[20], [18]]
[[18], [18], [4]]
[[16], [15], [9]]
[[15], [14], [11]]
[[12], [9], [9], [8]]
[[8], [7], [6]]
Qwen3 Cost: 89
Dodatkowo zamieszczam najlepsze rozwiązania każdego z modelu:
Deepcoder:14b
def packing(numbers):
"""
Pack numbers into packages following the constraints:
- Each package's total weight must not exceed 40
- The largest element in each package must equal the sum of its layers
- Minimize the number of packages and their total cost
Returns a list of packages, where each package is a list of layers.
"""
# Sort numbers in descending order to prioritize larger elements first
sorted_numbers = sorted(numbers, reverse=True)
# List to hold the packages
packages = []
for number in sorted_numbers:
placed = False
# Try to place the number into an existing package
for i in range(len(packages)):
current_package = packages[i]
# Calculate the sum of all elements in the package
total_sum = sum(sum(layer) for layer in current_package)
# Check if adding this number would exceed the weight limit
if (total_sum + number) > 40:
continue
# Create a new layer with just this number (single element)
new_layer = [number]
# Add the layer to the package
current_package.append(new_layer)
placed = True
break
if not placed:
# Start a new package with this number as the first layer
new_package = [[number]]
packages.append(new_package)
return packages
Deepseek-r1:14b
def packing(items):
"""
Pack items into separate packages while optimizing for minimal cost.
Returns a list of packages, where each package contains layers of items
that meet the constraints from check_rolues().
"""
def calculate_layer_sum(layer):
return sum(layer)
def can_add_to_package(package, item):
# Check if adding this item as a new layer would violate constraints
current_max = max(sum(l) for l in package)
proposed_layer = [item]
# Check size constraint (max layer sum must be at least the largest single element)
if item > current_max:
return False
# Check weight constraint (sum of all layers in package <= 40)
total_weight = sum(calculate_layer_sum(l) for l in package) + item
if total_weight > 40:
return False
return True
packages = []
# Start with the largest items first to optimize packing
sorted_items = sorted(items, reverse=True)
for item in sorted_items:
placed = False
# Try placing in an existing package
for package in packages:
if can_add_to_package(package, item):
package.append([item])
placed = True
break
if not placed:
# Start new package
packages.append([[item]])
return packages
Gemma3:12b
from typing import List
def packing(numbers: List[int]) -> List[List[List[int]]]:
"""
Packs the given numbers into packages, minimizing cost.
"""
packages = []
current_package = []
current_weight = 0
for number in numbers:
if current_weight + number <= 40:
current_package.append([number])
current_weight += number
else:
packages.append(current_package)
current_package = [[number]]
current_weight = number
if current_package:
packages.append(current_package)
return packages
Qwen3:14b
def packing(items):
items_sorted = sorted(items, reverse=True)
packages = []
for item in items_sorted:
placed = False
for package in packages:
# Check if adding the item is possible
if sum(package['items']) + item <= 40 and item <= package['max_item']:
package['items'].append(item)
placed = True
break
if not placed:
new_package = {
'items': [item],
'max_item': item
}
packages.append(new_package)
# Function to arrange items into layers
def arrange_layers(items, max_item):
layers = []
remaining = items.copy()
while remaining:
layer = []
current_sum = 0
i = 0
while i < len(remaining):
if current_sum + remaining[i] <= max_item:
layer.append(remaining[i])
current_sum += remaining[i]
i += 1
else:
break
layers.append(layer)
remaining = remaining[i:]
return layers
# Arrange items into layers for each package
for package in packages:
package['layers'] = arrange_layers(package['items'], package['max_item'])
# Return the list of packages as a list of layers
result = []
for package in packages:
result.append(package['layers'])
return result