LangChainGo: подключение Go-приложения к OpenAI-совместимому API

Библиотека langchaingo принимает любой OpenAI-совместимый адрес. Показываем клиент, запрос, стриминг и цепочку с шаблоном на Go и считаем стоимость вызовов.

5 мин · · разработка · API-ключи

LangChain для Go, он же langchaingo, ходит в модели через тот же протокол, что и официальный OpenAI SDK. Поэтому его можно направить на любой OpenAI-совместимый шлюз, поменяв адрес, ключ и имя модели. Ниже настройка langchain go по шагам: клиент, простой запрос, сообщения с системной ролью, стриминг и цепочка с шаблоном. В конце считаем, сколько стоят такие вызовы.

Код сверен с исходниками библиотеки github.com/tmc/langchaingo на 18 октября 2026. API библиотеки развивается, поэтому перед началом сверьтесь со своей версией на pkg.go.dev. В go.mod библиотеки на момент проверки указан Go 1.26, убедитесь, что ваш тулчейн подходит.

Установка и ключ

bash
go get github.com/tmc/langchaingo

Ключ fetch_... создаётся в кабинете Zukko. Полный ключ показывается один раз, сохраните его и передавайте приложению через переменную окружения:

bash
export ZUKKO_API_KEY=fetch_ваш_ключ

Клиент: base URL, ключ и модель

Пакет llms/openai создаёт клиента функцией openai.New с опциями. Три нужные нам: WithBaseURL, WithToken и WithModel.

bash
package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/tmc/langchaingo/llms"
	"github.com/tmc/langchaingo/llms/openai"
)

func main() {
	ctx := context.Background()

Адрес для OpenAI-формата всегда с /v1: https://api.zukko.pro/v1. Библиотека сама добавит путь /chat/completions.

То же без кода: по исходникам клиент читает переменные окружения OPENAI_BASE_URL, OPENAI_API_KEY и OPENAI_MODEL, если опции не заданы. Тогда в программе достаточно openai.New(), а адрес, ключ и модель переключаются снаружи.

Сообщения, системная роль и расход токенов

Для диалога с системной инструкцией используйте GenerateContent:

bash
messages := []llms.MessageContent{
	llms.TextParts(llms.ChatMessageTypeSystem, "Ты помощник Go-разработчика. Отвечай кратко."),
	llms.TextParts(llms.ChatMessageTypeHuman, "Чем context.WithTimeout отличается от context.WithDeadline?"),
}

resp, err := llm.GenerateContent(ctx, messages, llms.WithTemperature(0.2))
if err != nil {
	log.Fatal(err)
}

choice := resp.Choices[0]
fmt.Println(choice.Content)
fmt.Println("вход:", choice.GenerationInfo["PromptTokens"],
	"выход:", choice.GenerationInfo["CompletionTokens"],
	"из кэша:", choice.GenerationInfo["PromptCachedTokens"])

В GenerationInfo библиотека складывает данные об использовании токенов: PromptTokens, CompletionTokens, TotalTokens, а также PromptCachedTokens. У моделей GPT шлюз видит чтение кэша, и оно приходит в prompt_tokens_details.cached_tokens, откуда библиотека берёт это поле. Эти числа удобно писать в лог: они позволяют свериться со списаниями в кабинете.

Про llms.WithMaxTokens: по исходникам библиотека отправляет его как max_completion_tokens. Если конкретная модель или маршрут отвечают 400 на этот параметр, уберите опцию, проверьте запрос через curl и сверьтесь с документацией langchaingo о режиме старого поля max_tokens.

Стриминг

bash
_, err = llm.GenerateContent(ctx, messages,
	llms.WithStreamingFunc(func(ctx context.Context, chunk []byte) error {
		fmt.Print(string(chunk))
		return nil
	}),
)

Сервер Zukko в потоке OpenAI-формата всегда присылает последний чанк с usage и пустым списком choices. Если писать разбор потока самому, проверяйте, что choices не пуст, прежде чем читать первый элемент. В langchaingo такой чанк обрабатывается: библиотека пропускает его как текстовый кусок и берёт из него статистику использования.

Цепочка с шаблоном

В langchaingo шаблон запроса и модель связывает LLMChain. Шаблон в актуальной версии записывается в синтаксисе Go template:

bash
import (
	"github.com/tmc/langchaingo/chains"
	"github.com/tmc/langchaingo/prompts"
)

prompt := prompts.NewPromptTemplate(
	"Предложи три названия для сервиса, который {{.description}}. Ответ списком.",
	[]string{"description"},
)

chain := chains.NewLLMChain(llm, prompt)

out, err := chains.Run(ctx, chain, "переводит голосовые сообщения в текст")
if err != nil {
	log.Fatal(err)
}
fmt.Println(out)

chains.Run подходит, когда у цепочки один входной параметр и один выход. Для нескольких параметров используйте chains.Call и передавайте map[string]any. Если вы переносите примеры из старых статей, проверьте синтаксис подстановки: фигурные скобки с одним именем без точки могут не сработать.

Официальный SDK openai-go

Если LangChain вам не нужен, а нужен просто клиент OpenAI-формата на Go, подойдёт официальная библиотека github.com/openai/openai-go/v3. По её README адрес меняется опцией option.WithBaseURL:

bash
client := openai.NewClient(
	option.WithBaseURL("https://api.zukko.pro/v1"),
	option.WithAPIKey(os.Getenv("ZUKKO_API_KEY")),
)

resp, err := client.Chat.Completions.New(ctx, openai.ChatCompletionNewParams{
	Messages: []openai.ChatCompletionMessageParamUnion{
		openai.UserMessage("Привет! Ответь одним словом."),
	},
	Model: "deepseek-v4.1-flash",
})
if err != nil {
	log.Fatal(err)
}
fmt.Println(resp.Choices[0].Message.Content)

Пакеты openai и option импортируются из github.com/openai/openai-go/v3 и github.com/openai/openai-go/v3/option. В README этой библиотеки на момент проверки указан Go 1.26 или новее. Если нужен низкоуровневый вариант с net/http и разбором SSE, см. Claude API в Go.

Сколько это стоит

Цены на 18 октября 2026, доллары за 1M токенов. Пример: сервис обрабатывает 1 000 запросов, в каждом 400 токенов входа и 150 токенов выхода. Это 0.4M токенов входа и 0.15M выхода.

МодельВход / выходФормулаИтого
deepseek-v4.1-flash0.013 / 0.0380.4 × 0.013 + 0.15 × 0.038$0.0109
gpt-6.1-sol0.27 / 1.320.4 × 0.27 + 0.15 × 1.32$0.306
claude-sonnet-5-50.4 / 20.4 × 0.4 + 0.15 × 2$0.46

Для Claude через langchaingo и формат chat/completions весь вход идёт по цене входа, а скидка за кэш работает в Anthropic-формате. У GPT чтение кэша видно в обоих форматах. Актуальный список моделей и цен — GET https://api.zukko.pro/v1/models, подробности о форматах — в справочнике chat/completions. Чтобы тестовый цикл не потратил лишнего, заведите отдельный ключ с дневным лимитом.

Если что-то не работает

Ошибки приходят из библиотеки как обычный error с текстом ответа сервера. Ориентируйтесь на смысл:

  • 401: неверный ключ. Проверьте префикс fetch_ и что переменная окружения задана в том процессе, который запускает программу.
  • 402: не хватает баланса.
  • 403 model_not_allowed_for_key: модели нет в списке разрешённых у ключа.
  • 404 model_not_found: неверное имя модели, сверьтесь с GET /v1/models. Если ошибка 404 приходит на каждый запрос, проверьте адрес: он должен заканчиваться на /v1.
  • 503 model_disabled: модель выключена, переключитесь на другую из списка.

Доступ из России — через шлюз, оплата СБП (платёжная страница добавляет 8,5% сверху), картой MasterCard или криптой. Разбор ошибок — в статье 401, 402, model not found.

Частые вопросы

Можно ли в langchaingo использовать Claude или DeepSeek, а не только GPT?

Да. Шлюз принимает любую свою модель в OpenAI-формате, поэтому достаточно поменять строку в WithModel. Перед сменой проверьте, что нужная вам функция (инструменты, JSON-режим) работает с выбранной моделью.

Нужно ли писать /v1 в адресе?

Да, для OpenAI-формата адрес https://api.zukko.pro/v1. Без /v1 запросы уйдут на неверный путь.

Как узнать, сколько токенов потратил запрос?

Читайте GenerationInfo в ответе: поля PromptTokens, CompletionTokens и PromptCachedTokens. Историю расходов смотрите в кабинете в разделе «Использование» или через GET /v1/usage.

Есть ли у langchaingo готовый агент с инструментами?

В библиотеке есть агенты и инструменты, но их состав и API менялись, поэтому смотрите примеры в репозитории в папке examples под вашу версию.

zukko

Платите в 25×
меньше

за Claude Code & ChatGPT

Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.