14 KiB
14 KiB
11 — LLM Integration Guide (MicroDAO)
Інтеграція ChatGPT / OpenAI / інших моделей у агентську систему MicroDAO
Цей документ описує:
-
де і як підключити LLM,
-
як організувати backend-виклики,
-
як звʼязати агента з моделлю,
-
як працює agent-first онбординг,
-
як працює агентський чат,
-
як працює еволюційна модель на основі LLM.
Документ орієнтований на Cursor + Node/TS backend.
1. Принцип інтеграції
Усі виклики до LLM здійснюються на бекенді, не з фронтенду.
Причини:
-
безпека (ключ не світиться),
-
стабільність,
-
контроль ціни,
-
можливість додавати кэшинг, rate-limits,
-
можливість підміняти провайдерів (OpenAI → Anthropic → локальні моделі).
2. Високорівнева архітектура
Frontend (React SPA)
|
| POST /agents/{id}/chat
↓
Backend
├── agentsController.ts
├── llm/
│ ├── openaiClient.ts
│ ├── modelRouter.ts
│ └── prompts/
│ ├── system_agent.txt
│ └── system_onboarding.txt
|
↓
OpenAI API (або інша модель)
```text
---
## 3. Структура директорій для LLM
Додайте на бекенд:
```text
src/
llm/
openaiClient.ts
modelRouter.ts
prompts/
system_agent.txt
system_onboarding.txt
system_evolution.txt
```text
- `openaiClient.ts` — клієнт OpenAI / GPT.
- `modelRouter.ts` — місце, де ти можеш вирішити, яку модель використовувати (gpt-4.1-mini, o3, claude тощо).
- `prompts/*.txt` — системні промпти для:
- Agent Chat
- Onboarding Guide Agent
- Evolution Meta-Agent
---
## 4. Реалізація базового клієнта OpenAI
**Файл: `src/llm/openaiClient.ts`**
```ts
import OpenAI from "openai";
export const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY!,
});
export async function callLLM(messages: any[], model = "gpt-4.1-mini") {
const res = await openai.chat.completions.create({
model,
messages,
temperature: 0.2,
});
return res.choices[0]?.message?.content ?? "";
}
```text
---
## 5. Model Router
**Файл: `src/llm/modelRouter.ts`**
```ts
export function pickModel(agentProfile: string) {
switch (agentProfile) {
case "technical":
return "gpt-4.1";
case "business":
return "gpt-4.1-mini";
case "creative":
return "gpt-4o-mini";
default:
return "gpt-4.1-mini";
}
}
```text
У майбутньому це місце для:
- локальних моделей (Ollama, vLLM),
- кластеру DAGI,
- автоматичного підбору моделі.
---
## 6. Запит до LLM для агентського чату
**Файл: `src/controllers/agentsController.ts`**
```ts
import { callLLM } from "../llm/openaiClient";
import { pickModel } from "../llm/modelRouter";
import systemAgent from "../llm/prompts/system_agent.txt";
export async function chatWithAgent(req, res) {
const { agentId } = req.params;
const { messages } = req.body;
const agent = await db.agent.find(agentId);
const model = pickModel(agent.role);
const llmMessages = [
{ role: "system", content: systemAgent },
...messages
];
const reply = await callLLM(llmMessages, model);
// зберегти останнє повідомлення як agent message
await db.agentMessages.insert({
agent_id: agentId,
role: "assistant",
body: reply
});
res.json({ reply });
}
```text
---
## 7. Інтеграція з Agent Chat у фронтенді
**Файл: `api/agents.ts`**
```ts
export async function agentChat(agentId: string, messages: ChatMessage[]) {
return api.post(`/agents/${agentId}/chat`, { messages });
}
```text
**У `AgentChatWindow.tsx`:**
```ts
const onSend = async (text: string) => {
addMessage({ role: "user", content: text });
const response = await agentChat(agentId, [
...history,
{ role: "user", content: text }
]);
addMessage({ role: "assistant", content: response.reply });
};
```text
---
## 8. Agent-First Onboarding Integration
Використовує той самий LLM-клієнт, але з іншим системним промптом:
**`prompts/system_onboarding.txt`:**
```text
You are MicroDAO Guide Agent.
Your job is to ask the user questions one-by-one to configure their microDAO.
NEVER skip steps. NEVER jump too far.
Be friendly, minimalistic and precise.
```text
У онбордингу:
```ts
const reply = await callLLM([
{ role: "system", content: onboardingSystemPrompt },
...conversation
]);
```text
Але state-machine керує реальними діями (API), LLM — тільки текстом.
---
## 9. Integration with Evolutionary Agent (09_evolutionary_agent.md)
Meta-Agent (self-review) використовує **ще один промпт**:
`prompts/system_evolution.txt`:
```text
You are Meta-Agent responsible for analyzing logs of conversations.
Find mistakes, weak answers, missing rules, and propose improvements.
Always output JSON with `["type", "value", "explanation"]`.
```text
Self-review:
```ts
const improvements = await callLLM([
{ role: "system", content: evolutionPrompt },
{ role: "user", content: JSON.stringify(conversationLog) }
]);
```text
---
## 10. Як передавати пам'ять агента в LLM
У LLM-запит можна додати:
- `short-term memory` (останні X повідомлень)
- `long-term memory` (витяг з Co-Memory)
- `agent profile`
- інструкції агента (структура з DB)
Приклад у messages:
```ts
const llmMessages = [
{ role: "system", content: systemPrompt },
{ role: "assistant", content: "AGENT_PROFILE:" + JSON.stringify(agentProfile) },
{ role: "assistant", content: "MEMORY:" + JSON.stringify(memories) },
...history,
{ role: "user", content: question }
];
```text
---
## 11. Безпека
- API key зберігати у `.env` на сервері.
- Ніколи не відправляти ключ у фронтенд.
- Додавати rate limit.
- Додавати аудит використання агента.
---
## 12. Кешування та оптимізація
## 12.1. Кешування відповідей
Для однакових запитів можна кешувати відповіді:
```ts
const cacheKey = hash(messages);
const cached = await cache.get(cacheKey);
if (cached) return cached;
const reply = await callLLM(messages);
await cache.set(cacheKey, reply, { ttl: 3600 });
return reply;
```text
## 12.2. Streaming відповідей
Для кращого UX можна використовувати streaming:
```ts
const stream = await openai.chat.completions.create({
model,
messages,
stream: true,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content;
if (content) {
res.write(content);
}
}
```text
## 12.3. Rate Limiting
Обмеження кількості запитів:
```ts
import rateLimit from "express-rate-limit";
const agentLimiter = rateLimit({
windowMs: 60 * 1000, // 1 хвилина
max: 10, // 10 запитів на хвилину
keyGenerator: (req) => req.user.id,
});
```text
---
## 13. Альтернативні провайдери
## 13.1. Anthropic Claude
```ts
import Anthropic from "@anthropic-ai/sdk";
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY!,
});
export async function callClaude(messages: any[]) {
const response = await anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 1024,
messages,
});
return response.content[0].text;
}
```text
## 13.2. Локальні моделі (Ollama)
```ts
export async function callOllama(messages: any[], model = "llama2") {
const response = await fetch("http://localhost:11434/api/chat", {
method: "POST",
body: JSON.stringify({
model,
messages,
}),
});
const data = await response.json();
return data.message.content;
}
```text
## 13.3. Уніфікований інтерфейс
```ts
interface LLMProvider {
call(messages: any[], options?: any): Promise<string>;
}
class OpenAIProvider implements LLMProvider {
async call(messages: any[], options?: any) {
return callLLM(messages, options?.model);
}
}
class AnthropicProvider implements LLMProvider {
async call(messages: any[], options?: any) {
return callClaude(messages);
}
}
export function getLLMProvider(provider: string): LLMProvider {
switch (provider) {
case "openai":
return new OpenAIProvider();
case "anthropic":
return new AnthropicProvider();
case "ollama":
return new OllamaProvider();
default:
return new OpenAIProvider();
}
}
```text
---
## 14. Обробка помилок
## 14.1. Retry Logic
```ts
async function callLLMWithRetry(
messages: any[],
model: string,
maxRetries = 3
): Promise<string> {
for (let i = 0; i < maxRetries; i++) {
try {
return await callLLM(messages, model);
} catch (error) {
if (i === maxRetries - 1) throw error;
await sleep(1000 * (i + 1)); // exponential backoff
}
}
throw new Error("LLM call failed after retries");
}
```text
## 14.2. Fallback моделі
```ts
async function callLLMWithFallback(messages: any[], primaryModel: string) {
try {
return await callLLM(messages, primaryModel);
} catch (error) {
console.warn(`Primary model failed, using fallback`);
return await callLLM(messages, "gpt-3.5-turbo");
}
}
```text
---
## 15. Моніторинг та логування
## 15.1. Логування викликів
```ts
async function callLLM(messages: any[], model: string) {
const startTime = Date.now();
try {
const reply = await openai.chat.completions.create({
model,
messages,
temperature: 0.2,
});
const duration = Date.now() - startTime;
const tokens = reply.usage?.total_tokens || 0;
logger.info("LLM call", {
model,
duration,
tokens,
cost: calculateCost(model, tokens),
});
return reply.choices[0]?.message?.content ?? "";
} catch (error) {
logger.error("LLM call failed", { model, error });
throw error;
}
}
```text
## 15.2. Метрики
Відстежувати:
- кількість викликів на агента
- середній час відповіді
- витрати на токени
- частота помилок
- популярні моделі
---
## 16. Завдання для Cursor
```text
You are a senior backend + frontend engineer.
Integrate OpenAI LLM into the MicroDAO Agents system using:
- 11_llm_integration.md
- 03_api_core_snapshot.md
- 05_coding_standards.md
Tasks:
1. Create openaiClient.ts
2. Create modelRouter.ts
3. Add AgentChat endpoint
4. Connect AgentChatWindow to backend
5. Add LLM to AgentOnboardingChat
6. Add LLM to EvolutionMetaAgent (stub)
Output:
- list of modified files
- diff
- summary
```text
---
## 17. Типи та інтерфейси
## 17.1. ChatMessage
```ts
interface ChatMessage {
role: "system" | "user" | "assistant";
content: string;
timestamp?: string;
}
```text
## 17.2. LLMResponse
```ts
interface LLMResponse {
content: string;
model: string;
tokens?: {
prompt: number;
completion: number;
total: number;
};
finishReason?: string;
}
```text
## 17.3. AgentChatRequest
```ts
interface AgentChatRequest {
messages: ChatMessage[];
context?: {
channelId?: string;
threadId?: string;
userId?: string;
};
options?: {
temperature?: number;
maxTokens?: number;
stream?: boolean;
};
}
```text
---
## 18. Тестування
## 18.1. Unit Tests
```ts
describe("openaiClient", () => {
it("should call LLM with correct messages", async () => {
const messages = [
{ role: "system", content: "You are a helpful assistant" },
{ role: "user", content: "Hello" },
];
const response = await callLLM(messages);
expect(response).toBeDefined();
expect(typeof response).toBe("string");
});
});
```text
## 18.2. Integration Tests
```ts
describe("Agent Chat Integration", () => {
it("should handle full chat flow", async () => {
const agentId = "test-agent";
const messages = [
{ role: "user", content: "Hello" },
];
const response = await agentChat(agentId, messages);
expect(response.reply).toBeDefined();
});
});
```text
---
## 19. Результат
Після інтеграції:
- будь-який агент microDAO працює на GPT/LLM,
- онбординг веде агент-гіда,
- Team Assistant відповідає у чаті,
- Meta-Agent генерує покращення,
- вся система стає справжньою OS на базі ШІ.
---
## 20. Наступні кроки
Після базової інтеграції можна додати:
- Streaming відповідей для кращого UX
- Кешування для оптимізації витрат
- Підтримку альтернативних провайдерів
- Fine-tuning моделей для конкретних спільнот
- Інтеграцію з DAGI для колективного навчання
---
**Готово.**
Це **повна специфікація інтеграції LLM**, готова до використання в Cursor.