ember
Библиотека для простой интеграции с LLM-провайдерами и создания собственных агентов. Предоставляет простой и единообразный интерфейс для работы с языковыми моделями, чтобы вы могли сосредоточиться на логике своих агентов, а не на деталях API.
Возможности
- Единый интерфейс для различных LLM-провайдеров
- Простой способ создавать и конфигурировать собственных агентов
- Инструменты/функции для модели (tool calling)
- Подключение внешних инструментов по MCP (Model Context Protocol)
- Персистентная память агента: диалоги между сессиями и кросс-сессионный recall
- Минимальное количество кода для старта
⚠️ Проект на ранней стадии разработки. API активно меняется.
Установка
На PyPI пакет публикуется под именем emberio-labs-ember (импорт в коде — ember):
pip install "emberio-labs-ember[openai]" # с поддержкой OpenAI
pip install "emberio-labs-ember[mcp]" # с поддержкой MCP-клиента
pip install emberio-labs-ember # ядро (без провайдеров)
Для разработки (из репозитория) проект управляется через Poetry:
poetry install
Быстрый старт
Без ключей: MockProvider
Работает без сети и API-ключей — удобно для экспериментов:
from ember import Agent, MockProvider
agent = Agent(provider=MockProvider(response_text="Привет! Я мок-провайдер."))
print(agent.run("Привет!"))
# Привет! Я мок-провайдер.
С OpenAI: OpenAIProvider
API-ключ передаётся явно (провайдер сам не читает окружение):
import os
from ember import Agent, OpenAIProvider
agent = Agent(
provider=OpenAIProvider(api_key=os.environ["OPENAI_API_KEY"]),
model="gpt-4o-mini",
)
print(agent.run("Расскажи о себе в одном предложении."))
Полный исполняемый пример — в examples/quickstart.py.
OpenAI-совместимые API (base_url)
Chat Completions — де-факто индустриальный стандарт: его поддерживают
облачные провайдеры (OpenRouter, Groq, DeepSeek, Mistral, Perplexity)
и локальные/self-hosted серверы (LM Studio, vLLM, LocalAI). Тот же
OpenAIProvider подключается к любому из них через base_url:
import os
from ember import Agent, OpenAIProvider
# облачный провайдер (пример: Groq)
agent = Agent(
provider=OpenAIProvider(
api_key=os.environ["GROQ_API_KEY"],
base_url="https://api.groq.com/openai/v1",
model="llama-3.1-8b-instant",
),
)
# локальный сервер (пример: LM Studio) — ключ не требуется, передайте заглушку
provider = OpenAIProvider(
api_key="sk-local",
base_url="http://localhost:1234/v1",
model="local-model",
)
base_url — это полный URL до версии API: SDK сам добавит
/chat/completions, а /v1 дописывать за вас никто не будет. Ключ
остаётся обязательным параметром конструктора; локальные серверы обычно
игнорируют его значение.
История диалога
Agent сам накапливает историю: сообщения пользователя и ответы модели
добавляются в agent.messages. Сбросить диалог можно через agent.reset().
Системный промпт задаётся в конструкторе:
agent = Agent(
provider=MockProvider(),
system_prompt="Ты краткий и полезный помощник.",
)
Память агента: персистентные сессии и recall
По умолчанию история диалога живёт в памяти агента и исчезает вместе с ним.
Подключив хранилище — интерфейс Memory с реализацией по умолчанию
FileMemory — вы получите диалоги, переживающие перезапуск приложения,
и кросс-сессионный recall: агент «вспоминает» релевантное из прошлых разговоров.
from ember import Agent, FileMemory, MockProvider
memory = FileMemory("/tmp/ember-memory") # директория создаётся сама
agent = Agent(
provider=MockProvider(response_text="Привет, Алекс!"),
memory=memory,
session_id="user-42", # новая беседа = новый session_id
)
agent.run("Привет, меня зовут Алекс")
# «Перезапуск приложения»: тот же session_id — диалог продолжается
restored = Agent(
provider=MockProvider(response_text="Привет, Алекс!"),
memory=memory,
session_id="user-42",
)
print([m.content for m in restored.messages])
# ['Привет, меня зовут Алекс', 'Привет, Алекс!']
Как это работает:
memoryиsession_idзадаются вместе: безsession_idдиалог некуда сохранять.FileMemoryхранит каждую сессию в отдельном JSONL-файле<directory>/<session_id>.json.- При создании агент загружает историю сессии и продолжает диалог с неё. В хранилище пишется только «разговорная» часть (user/assistant/tool) — system-промпт остаётся конфигурацией агента и ставится первым при создании.
- Сохранение происходит после каждого
run()/stream_run(), в том числе при завершении с исключением: накопленная часть диалога не теряется. reset()начинает текущую сессию заново (и очищает её в хранилище); сессии с другимиsession_idне трогаются.- Recall: в
run()/stream_run()агент ищет по тексту запроса релевантные сообщения в других сессиях (bag-of-words overlap, без LLM) и добавляет их в запрос отдельным system-сообщением «Из прошлых сессий: ...». История и хранилище при этом не изменяются.
Своё хранилище (Redis, Postgres, SQLite...) подключить просто: реализуйте
Memory — load_session/save_session/search/delete_session — и передайте
в Agent. Полный исполняемый пример — examples/memory.py.
Инструменты (tool calling)
Модель можно научить вызывать функции. Опишите инструмент через Tool
и передайте список в запрос:
from ember import ChatRequest, Message, Tool
tools = [
Tool(
name="get_weather",
description="Погода в городе",
parameters={
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
)
]
# provider — любой Provider, например OpenAIProvider(api_key=...)
response = provider.complete(
ChatRequest(
messages=[Message(role="user", content="Какая погода в Москве?")],
model="gpt-4o-mini",
tools=tools,
)
)
# Если модель решила вызвать инструмент, вызовы будут в response.message.tool_calls
if response.message.tool_calls:
for call in response.message.tool_calls:
print(call.name, call.arguments)
Результат выполнения возвращается модели сообщением с ролью tool
и идентификатором вызова:
Message(role="tool", content="+15C", tool_call_id=call.id)
MCP: внешние инструменты (Model Context Protocol)
MCP — открытый стандарт интеграции
инструментов с LLM-агентами. ember умеет подключаться к MCP-серверам
(клиентская часть) и использовать их инструменты наряду с локальными
FunctionTool. Сервер при этом может быть как вашим процессом, так
и сторонним сервисом.
Подключение к серверу — через MCPClient:
from ember import Agent, MCPClient
# stdio: сервер запускается как дочерний процесс
with MCPClient.stdio(command="python", args=["server.py"]) as mcp:
agent = Agent(provider=provider, tools=mcp.list_tools())
print(agent.run("Проверь доступность сервиса."))
MCPClient.list_tools() выполняет tools/list и возвращает обычные
FunctionTool: JSON Schema параметров сохраняется, а func проксирует
вызов на сервер (tools/call). Для агента такие инструменты ничем не
отличаются от локальных — они исполняются в цикле agent.run(),
результаты возвращаются модели сообщениями role=tool, а в одном агенте
можно смешивать MCP-инструменты и локальные функции.
Поддерживается и streamable HTTP транспорт — передайте URL endpoint:
from ember import Agent, MCPClient
with MCPClient.http("http://127.0.0.1:8000/mcp") as mcp:
agent = Agent(provider=provider, tools=mcp.list_tools())
print(agent.run("Проверь доступность сервиса."))
Если сервер требует аутентификацию или другие HTTP-заголовки, передайте
их словарём в headers= — заголовки уходят с каждым запросом:
with MCPClient.http(
"https://mcp.example.com/mcp",
headers={"Authorization": "Bearer YOUR_TOKEN"},
) as mcp:
tools = mcp.list_tools()
Ошибки транспорта и сервера (падение процесса, таймаут, сбой tools/call,
отказ HTTP-сервера) оборачиваются в MCPError — понятное исключение
по образцу ProviderError. Требуется пакет mcp (extra ember[mcp]).
Полный исполняемый пример — examples/mcp_client.py:
он запускает MCP-сервер с инструментом ping и исполняет его агентом
без API-ключей:
python examples/mcp_client.py
Разработка
# Установка зависимостей (включая dev)
poetry install --with dev
# Запуск тестов
poetry run pytest
# Линтинг
poetry run ruff check .
poetry run ruff format --check .
# Проверка типов
poetry run mypy ember
CI (GitHub Actions) автоматически прогоняет линтинг, проверку типов и тесты на Python 3.10–3.12 для каждого pull request.
Релиз
Публикация новой версии на PyPI автоматизирована через GitHub Actions
(workflow .github/workflows/publish.yml):
-
Поднимите версию в
pyproject.toml(version = "0.1.0") и закоммитьте изменение, например:chore: bump version to 0.1.0 -
Создайте и запушьте git-тег, совпадающий с версией:
git tag v0.1.0 git push origin v0.1.0
-
Workflow соберёт wheel и sdist (
poetry build) и опубликует их на PyPI. Веткаmainпри этом не нужна — достаточно тега.
Публикация использует Trusted Publishing (OIDC): секреты в GitHub не хранятся. Для этого владельцу нужно один раз настроить publisher на PyPI (и, опционально, на TestPyPI для проверок):
- PyPI: https://pypi.org/manage/account/publishing/
- TestPyPI: https://test.pypi.org/manage/account/publishing/
Поля формы одинаковы для PyPI и TestPyPI:
| Поле | Значение |
|---|---|
| Project name | emberio-labs-ember |
| GitHub owner | emberio-labs |
| GitHub repository | ember |
| Workflow name | publish.yml |
| Environment | (пусто) |
После настройки публикацию можно проверить вручную на TestPyPI:
GitHub → Actions → Publish → Run workflow. На боевой PyPI пакет уходит
только по git-тегу v*.
Лицензия
Проект распространяется под лицензией MIT.
© 2026 Emberio Labs
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file emberio_labs_ember-0.4.0.tar.gz.
File metadata
- Download URL: emberio_labs_ember-0.4.0.tar.gz
- Upload date:
- Size: 28.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4656d17c05ac757070c68979a7ea74996bfa37c26aaa5af7cfc20483b0a73c1f
|
|
| MD5 |
a35c0b7d6cb37620317b7880243ac1a7
|
|
| BLAKE2b-256 |
b8a76dffa3651f29fb32d6207190c430b6bb4e3a77ae25849d6d1d0175a9c655
|
Provenance
The following attestation bundles were made for emberio_labs_ember-0.4.0.tar.gz:
Publisher:
publish.yml on emberio-labs/ember
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
emberio_labs_ember-0.4.0.tar.gz -
Subject digest:
4656d17c05ac757070c68979a7ea74996bfa37c26aaa5af7cfc20483b0a73c1f - Sigstore transparency entry: 2736539307
- Sigstore integration time:
-
Permalink:
emberio-labs/ember@8466e82d32b2121a91b9f25ff8594c196e62f864 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/emberio-labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8466e82d32b2121a91b9f25ff8594c196e62f864 -
Trigger Event:
push
-
Statement type:
File details
Details for the file emberio_labs_ember-0.4.0-py3-none-any.whl.
File metadata
- Download URL: emberio_labs_ember-0.4.0-py3-none-any.whl
- Upload date:
- Size: 32.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a7f08e45aa9f9ac15f65ffd88f29e434be7af3ca16fc55d5ebe9b748f44296ae
|
|
| MD5 |
d12d8c7cfb4de65c90e91e06455b5862
|
|
| BLAKE2b-256 |
4b891baa7e523f0cf74ccb98b474ecf44c6a1b20021d91ccb483d567eb27f478
|
Provenance
The following attestation bundles were made for emberio_labs_ember-0.4.0-py3-none-any.whl:
Publisher:
publish.yml on emberio-labs/ember
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
emberio_labs_ember-0.4.0-py3-none-any.whl -
Subject digest:
a7f08e45aa9f9ac15f65ffd88f29e434be7af3ca16fc55d5ebe9b748f44296ae - Sigstore transparency entry: 2736540122
- Sigstore integration time:
-
Permalink:
emberio-labs/ember@8466e82d32b2121a91b9f25ff8594c196e62f864 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/emberio-labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8466e82d32b2121a91b9f25ff8594c196e62f864 -
Trigger Event:
push
-
Statement type: