Ідея за 30 секунд
Multi-Tenant — це архітектурний підхід, у якому одна агентна система обслуговує багато клієнтів, але кожен tenant (окремий клієнт) ізольований.
Ізоляція має бути не лише в даних. Вона потрібна в усьому ланцюжку:
- контекст Runtime;
- пам'ять і кеш;
- доступи до інструментів;
- ліміти бюджету і rate limits;
- аудит і трейс.
Коли потрібно: коли один сервіс працює для багатьох клієнтів, команд або workspace у спільній інфраструктурі.
LLM не має самостійно визначати tenant-контекст. Tenant має визначатися через auth або routing, а система примусово застосовує його на кожному кроці.
Проблема
Без чіткої multi-tenant ізоляції система працює, але ризики швидко стають критичними.
LLM-агенти збільшують ризик cross-tenant витоків, бо один запит може читати пам'ять, викликати інструменти і писати дані в кілька систем.
Типові збої:
- контекст одного tenant потрапляє у відповідь іншому;
- tool call виконується з чужими credentials;
- пам'ять або кеш змішуються між клієнтами;
- один tenant витрачає весь спільний бюджет (noisy neighbor);
- аудит не дозволяє довести, хто саме ініціював дію.
У production це означає витоки даних, інциденти безпеки і складний комплаєнс.
Рішення
Додати Multi-Tenant як явну межу ізоляції (tenant boundary) між Agent Runtime і всіма станами/діями системи.
Ця межа визначає:
- як ідентифікується tenant;
- які ресурси доступні цьому tenant;
- які ліміти застосовуються саме до нього;
- як фіксується tenant-контекст у логах і трейсах.
Аналогія: як сейфові комірки в банку.
Будівля одна, але доступ до кожної комірки має тільки її власник.
Multi-Tenant так само дозволяє спільну платформу без змішування доступу і даних.
Як працює Multi-Tenant
Multi-Tenant — це керований шар між вхідним запитом і виконанням дій, який примусово ізолює кожен запуск за tenant_id.
Опис повного флоу: Identify → Isolate → Authorize → Execute → Audit
Identify
Система визначає tenant через auth token, org mapping або routing-правила.
Isolate
Runtime, memory, cache і budget-контекст прив'язуються до конкретного tenant_id.
Authorize
Policy-шар перевіряє role, tenant scopes, allowlist і пер-tenant ліміти.
Execute
Виклики інструментів виконуються тільки з tenant-scoped credentials і ресурсами цього tenant.
Audit
Кожен критичний крок логується з tenant_id, actor_id, reason_code, outcome.
Цей цикл дозволяє масштабувати один сервіс на багато клієнтів без cross-tenant змішування.
У коді це виглядає так
class MultiTenantArchitecture:
def __init__(self, auth, runtime, policy, tools, memory, budgets, audit):
self.auth = auth
self.runtime = runtime
self.policy = policy
self.tools = tools
self.memory = memory
self.budgets = budgets
self.audit = audit
def run(self, request, auth_token):
identity = self.auth.resolve(auth_token) or {}
tenant_id = identity.get("tenant_id")
actor_id = identity.get("actor_id")
if not tenant_id:
return {"ok": False, "reason_code": "tenant_missing"}
if not self.budgets.allowed(tenant_id=tenant_id):
return {"ok": False, "reason_code": "tenant_budget_exceeded"}
# Увесь контекст жорстко прив'язаний до tenant.
state = self.runtime.start(request=request, tenant_id=tenant_id)
memory_items = self.memory.retrieve(tenant_id=tenant_id, query=request["text"], top_k=4)
action = self.runtime.decide(state=state, memory_items=memory_items)
gate = self.policy.authorize(
tenant_id=tenant_id,
actor_id=actor_id,
action=action,
)
if not gate["ok"]:
self.audit.log(
tenant_id=tenant_id,
actor_id=actor_id,
action=action.get("name"),
outcome="denied",
reason_code=gate.get("reason_code", "policy_denied"),
)
return {"ok": False, "reason_code": gate.get("reason_code", "policy_denied")}
result = self.tools.execute(
action=action,
tenant_id=tenant_id,
scopes=gate.get("scopes", []),
)
self.audit.log(
tenant_id=tenant_id,
actor_id=actor_id,
action=action.get("name"),
outcome="executed",
reason_code=result.get("reason_code", "ok"),
)
return result
Як це виглядає під час виконання
Запит: "Онови статус замовлення #918 і надішли підтвердження клієнту"
Step 1
Auth + Routing: визначає tenant_id = tenant_acme
Multi-Tenant Boundary: встановлює tenant-контекст і пер-tenant ліміти
Step 2
Agent Runtime: формує action
Policy: перевіряє role + tenant scopes + allowlist
Tool Execution: виконує дію лише з credentials tenant_acme
Step 3
Audit: зберігає tenant_id, actor_id, action, outcome, reason_code
Runtime: повертає результат без змішування з іншими клієнтами
Multi-Tenant не змінює логіку агента. Він робить її передбачуваною і безпечною для багатоклієнтського середовища.
Коли підходить — і коли ні
Multi-Tenant потрібен там, де одна система працює для багатьох клієнтів або команд із різними доступами.
Підходить
| Ситуація | Чому Multi-Tenant підходить | |
|---|---|---|
| ✅ | Один агентний сервіс обслуговує багато клієнтів | Tenant boundary запобігає cross-tenant витокам даних і доступів. |
| ✅ | Потрібні різні бюджети, квоти і policy rules для різних tenant | Пер-tenant ліміти захищають систему від noisy-neighbor ефекту. |
| ✅ | Потрібен аудит для безпеки й комплаєнсу | Логи і трейс фіксують дії з чіткою прив'язкою до tenant. |
Не підходить
| Ситуація | Чому Multi-Tenant не підходить | |
|---|---|---|
| ❌ | Система обслуговує лише одного клієнта без планів масштабування | Повна multi-tenant обв'язка може бути зайвою складністю на старті. |
| ❌ | Дані та доступи вже фізично ізольовані окремими інсталяціями | У такому випадку часто достатньо single-tenant архітектури на кожну інсталяцію. |
У простому single-tenant сценарії інколи достатньо базового контексту:
result = runtime.run(request=request, tenant_id="default")
Типові проблеми та відмови
| Проблема | Що відбувається | Як запобігти |
|---|---|---|
| Credential bleed | Tool call використовує ключі іншого tenant | Tenant-scoped credentials + заборона глобальних клієнтів |
| Cache / memory bleed | Кеш або пам'ять повертають дані іншого tenant | Namespace key із tenant_id, ізоляція store і тест-кейси на витоки |
| Noisy neighbor | Один tenant забирає спільний бюджет і деградує сервіс для інших | Per-tenant budgets, rate limits, квоти і пріоритети |
| Підміна tenant-контексту | Система приймає tenant_id з prompt або payload без перевірки auth | Tenant визначається лише з auth/routing, а не з тексту запиту моделі |
| Неповний аудит | Неможливо довести, який tenant ініціював ризикову дію | Обов'язкові поля аудиту: tenant_id, actor_id, action, reason_code, outcome |
| Повторні write-операції | Retry дублює запис або списання в межах tenant | Idempotency keys і дедуплікація для mutation-дій |
Більшість multi-tenant інцидентів виникає не в моделі, а в слабкій межі між контекстом і виконанням.
Як поєднується з іншими патернами
Multi-Tenant — це поперечний архітектурний шар, який підсилює безпеку та стабільність усієї системи.
- Agent Runtime — Runtime виконує кроки, а Multi-Tenant задає межі tenant-контексту на кожному кроці.
- Tool Execution Layer — кожен
tool_callмає виконуватись із tenant-scoped доступами. - Memory Layer — пам'ять і кеш мають бути ізольовані за
tenant_id. - Policy Boundaries — policy rules застосовуються з урахуванням tenant, role і scopes.
- Orchestration Topologies — у multi-agent флоу tenant-контекст має передаватися між усіма гілками.
- Hybrid Workflow Agent — workflow-коміти мають лишатися в межах ресурсів конкретного tenant.
- Human-in-the-Loop Architecture — approval-кроки також повинні мати tenant-bound аудит і доступи.
- Containerizing Agents — контейнери дають стабільне середовище, але tenant-ізоляцію забезпечує саме Multi-Tenant межа.
Інакше кажучи:
- Multi-Tenant визначає чия це дія і чий це контекст
- Інші архітектурні шари визначають як ця дія виконується
Коротко
Multi-Tenant:
- ізолює дані, доступи і state між клієнтами
- застосовує пер-tenant ліміти бюджету і rate limits
- примусово прив'язує tool calls до tenant-scoped credentials
- робить аудит прозорим через tenant_id + reason_code
FAQ
Q: Чи достатньо просто додати tenant_id у запит?
A: Ні. tenant_id має примусово проходити через Runtime, policy, tools, memory, cache і audit.
Q: Де найчастіше стаються cross-tenant витоки?
A: Найчастіше в кешах, пам'яті і глобальних клієнтах для зовнішніх API.
Q: Як безпечно перейти з single-tenant на multi-tenant?
A: Почати з tenant_id в auth/routing, далі ізолювати memory/cache/tools, додати пер-tenant ліміти й аудит, і лише потім мігрувати дані поетапно.
Q: Що важливіше спочатку: пер-tenant бюджети чи пер-tenant policy?
A: Обидва важливі. Policy захищає доступи, бюджети захищають від noisy-neighbor і вибуху витрат.
Що далі
Multi-tenant архітектура починається з ізоляції, але не закінчується на ній. Далі подивіться, як утримати стабільність під реальним навантаженням:
- Memory Layer — як будувати tenant-scoped пам'ять без витоків між клієнтами.
- Containerizing Agents — як забезпечити відтворюване виконання для кожного tenant.
- Policy Boundaries — як розвести доступи, ролі й ризикові дії.
- Production Stack — як зібрати це в керовану production-модель.