- opencode (global config) sees marg/fireworks only, no ocp - openlama (OPENCODE_CONFIG=openlama.json) sees ocp only via enabled_providers - Verified: opencode run -m ocp/... → Model not found; openlama run -m ocp/... → OK - openlama launcher sets OPENCODE_CONFIG + NO_PROXY + execs opencode
7.4 KiB
AGENTS.md — ollama-proxy
Контекст
ollama-proxy — Go-прокси для Ollama Cloud (https://ollama.com). Балансирует запросы по нескольким API-ключам с round-robin и failover на 429/5xx. Слушает 127.0.0.1:11435, экспонирует нативный Ollama API (/api/*) и OpenAI-совместимый (/v1/*) passthrough. Деплой — systemd unit ollama-proxy.service. Используется opencode через кастомный провайдер ocp.
Стек
- Go 1.22 (используется
log/slog,net/http,net/http/httputil) - Единственная внешняя зависимость:
golang.org/x/term(prompt без echo вaccounts add) - Go 1.18 из apt НЕ подходит — нужен
~/.local/go/bin/go(Go 1.22.10). Перед сборкой:export PATH="$HOME/.local/go/bin:$PATH" - Сборка:
make build→./ollama-proxy - Тесты:
go test ./...(43 теста, включая integration-тесты сhttptest) - Линт:
go vet ./...,gofmt -l .
Структура
main.go — точка входа, делегирует в cli.Run
internal/config/
accounts.go — Account, AccountsFile, JSON load/save (chmod 0600, atomic)
server.go — ServerConfig (addr, base_url, cooldown, retries, log_level)
internal/log/logger.go — slog JSON logger с configurable level
internal/proxy/
balancer.go — round-robin + per-account cooldown (RWMutex)
handler.go — HTTP handler: reverse-proxy, Authorization подмена, SSE flush
retry.go — документация стриминг-инварианта
internal/cli/
root.go — dispatch подкоманд (serve / accounts / version)
accounts.go — add / list / remove / set-base-url
serve.go — запуск HTTP-сервера с signal handling
systemd/ollama-proxy.service — systemd unit
Конфигурация
- Аккаунты:
~/.config/ollama-proxy/accounts.json(XDG_CONFIG_HOME, chmod 0600, atomic write) - Флаги
serve:--addr,--base-url,--cooldown,--retries,--log-level - Env vars:
OLLAMA_PROXY_ADDR,OLLAMA_PROXY_BASE_URL,OLLAMA_PROXY_COOLDOWN,OLLAMA_PROXY_RETRIES,OLLAMA_PROXY_LOG_LEVEL
Типичные задачи
- Добавить аккаунт:
ollama-proxy accounts add --name <alias>(промпт) или... add <key> --name <alias> - Перезапустить после правки аккаунтов:
sudo systemctl restart ollama-proxy(прокси читает accounts.json при старте; runtime-обновления не поддерживаются) - Посмотреть логи:
journalctl -u ollama-proxy -f— JSON-структурированные (account, account_id, path, status, latency_ms, stream) - Проверить, что прокси жив:
curl http://127.0.0.1:11435/api/version→ должен вернуть JSON от ollama.com - Проверить список моделей:
curl http://127.0.0.1:11435/v1/models | jq '.data | length'(~35 моделей) - Запустить opencode с пулом:
openlama(обёртка в~/.local/bin/openlama, выставляет NO_PROXY и запускает opencode) - Обновить список моделей в opencode-конфиге:
curl -sS http://127.0.0.1:11435/v1/models | jq -r '.data[].id'→ обновитьmodelsблок в~/.config/opencode/opencode.json
Интеграция с opencode
Два отдельных конфига: opencode видит только marg/fireworks, openlama видит только ocp.
~/.config/opencode/opencode.json— глобальный конфиг сmarg+fireworks(безocp)~/.config/opencode/openlama.json— отдельный конфиг сocp+"enabled_providers": ["ocp"]. Содержит те же instructions/mcp/plugins/agent что глобальный, но только провайдерocp.~/.local/bin/openlama— обёртка, выставляетOPENCODE_CONFIG=~/.config/opencode/openlama.json+NO_PROXY=127.0.0.1,localhost,::1+exec opencode "$@"
openlama.json (ключевая часть):
{
"enabled_providers": ["ocp"],
"provider": {
"ocp": {
"npm": "@ai-sdk/openai-compatible",
"name": "Ollama Cloud (pool)",
"options": {
"baseURL": "http://127.0.0.1:11435/v1",
"apiKey": "proxy"
},
"models": {
"gpt-oss:20b": { "name": "gpt-oss:20b" },
"...": { "name": "..." }
}
}
}
}
OPENCODE_CONFIG мерджится с глобальным конфигом, но enabled_providers: ["ocp"] перекрывает глобальный — marg/fireworks скрыты.
Модель не сделана дефолтной — выбирается через /models в TUI.
ВАЖНО: NO_PROXY. Если в окружении установлен HTTP_PROXY/HTTPS_PROXY (например http://127.0.0.1:2080), opencode (Bun runtime) направит запросы к прокси через HTTP-прокси → 502 Bad Gateway. Нужно явно исключить localhost:
# В ~/.config/environment.d/no-proxy-local.conf (systemd/desktop sessions):
NO_PROXY=127.0.0.1,localhost,::1
no_proxy=127.0.0.1,localhost,::1
Или запускать opencode с NO_PROXY=127.0.0.1,localhost opencode ....
Модели в конфиге: opencode НЕ умеет динамически резолвить модели через /v1/models для @ai-sdk/openai-compatible — models: {} даёт ProviderModelNotFoundError. Нужно явно перечислить модели. Обновить список: curl -sS http://127.0.0.1:11435/v1/models | jq -r '.data[].id' → вставить в models блок.
WARN
- Никогда не запускай прокси на
0.0.0.0без auth — он не имеет аутентификации, любой может использовать твои ключи accounts.jsonсодержит ключи в plaintext — файл chmod 0600, не коммить в git- После правки
accounts.jsonнуженsudo systemctl restart ollama-proxy(прокси не перечитывает файл в рантайме) - Если локальная
ollamaзапущена на 11434 — это НЕ конфликтует (прокси на 11435), ноOLLAMA_HOST=127.0.0.1:11435нужно явно указывать - Стриминг-инвариант: после первого flush-а 2xx ответа переключение аккаунта НЕ происходит. Mid-stream ошибки → truncated response клиенту. Это by design (нельзя дублировать вывод)
- 5xx НЕ вызывает cooldown аккаунта (только 429). 5xx → failover на следующий аккаунт, но без penalty
План отката
sudo systemctl stop ollama-proxy && sudo systemctl disable ollama-proxysudo rm /usr/local/bin/ollama-proxy /etc/systemd/system/ollama-proxy.service && sudo systemctl daemon-reload- Убрать блок
ocpиз~/.config/opencode/opencode.json