flare-agent Bài 7: Áp dụng vào edu-ai-platform — End-to-end

Kết hợp tất cả packages của flare-agent để xây dựng edu-ai-platform hoàn chỉnh — vocabulary learning agent với quiz workflow, RAG memory và SSE streaming trên Cloudflare.

6 phút đọc
Tập này đang được chuẩn bị, quay lại sau nhé.

flare-agent Bài 7: Áp dụng vào edu-ai-platform

Series: Build Your Own AI Agent Framework trên Cloudflare Bài: 7 / 7 — End-to-end


Tổng kết những gì đã build

Package Vai trò
@flare-agent/types Interfaces — hợp đồng giữa các layer
@flare-agent/providers LLM Router — Groq, WorkersAI, Ollama
@flare-agent/memory KV + D1 + Vectorize adapters
@flare-agent/core Agent Loop + Tool Registry
@flare-agent/workflow Graph-based Workflow Engine

Bài này kết nối tất cả vào edu-ai-platform thực tế.


Kiến trúc edu-ai-platform

React/Vite (Cloudflare Pages)
  ↓ POST /api/chat
  ↓ GET  /api/quiz/start
Hono Worker
  ├── /api/chat     → VocabularyAgent (Agent Loop)
  ├── /api/quiz/*   → QuizWorkflow (Workflow Engine)
  └── /api/recall   → RAG query
Durable Object (session state)
  └── AgentSession
Storage
  ├── KV  → conversation history
  ├── D1  → vocabulary, progress, users
  └── Vectorize → semantic word search

Project Structure

edu-ai-platform/
├── apps/
│   ├── web/                    # React + Vite
│   │   └── src/
│   │       ├── hooks/
│   │       │   └── useChat.ts  # SSE consumer
│   │       └── components/
│   │           └── ChatBox.tsx
│   └── worker/                 # Hono Worker
│       └── src/
│           ├── index.ts        # routes
│           ├── agents/
│           │   └── vocabulary.ts
│           ├── workflows/
│           │   └── quiz.ts
│           └── tools/
│               ├── vocabulary.ts
│               └── progress.ts
└── packages/                   # flare-agent packages
    ├── types/
    ├── providers/
    ├── memory/
    ├── core/
    └── workflow/

Tools

// apps/worker/src/tools/vocabulary.ts
import { tool } from '@flare-agent/core';

export const getVocabulary = tool({
  schema: {
    name: 'get_vocabulary',
    description: 'Lấy danh sách từ vựng theo chủ đề và level',
    parameters: {
      type: 'object',
      properties: {
        topic: { type: 'string', description: 'Chủ đề (business, travel, ...)' },
        level: {
          type: 'string',
          enum: ['beginner', 'intermediate', 'advanced'],
        },
        limit: { type: 'number', default: 5 },
      },
      required: ['topic'],
    },
  },
  execute: async ({ topic, level, limit }, ctx) => {
    const db = ctx.env.DB as D1Database;
    const { results } = await db
      .prepare(
        `SELECT word, definition, example
         FROM vocabulary
         WHERE topic = ? AND level = ?
         ORDER BY RANDOM() LIMIT ?`
      )
      .bind(topic, level ?? 'beginner', limit ?? 5)
      .all();
    return results;
  },
});

export const saveProgress = tool({
  schema: {
    name: 'save_progress',
    description: 'Lưu tiến độ học của user',
    parameters: {
      type: 'object',
      properties: {
        wordId: { type: 'string' },
        status: { type: 'string', enum: ['learned', 'reviewing', 'skipped'] },
        score: { type: 'number' },
      },
      required: ['wordId', 'status'],
    },
  },
  execute: async ({ wordId, status, score }, ctx) => {
    const db = ctx.env.DB as D1Database;
    await db
      .prepare(
        `INSERT OR REPLACE INTO progress (user_id, word_id, status, score, updated_at)
         VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP)`
      )
      .bind(ctx.userId, wordId, status, score ?? 0)
      .run();
    return { success: true };
  },
});

Vocabulary Agent

// apps/worker/src/agents/vocabulary.ts
import { Agent } from '@flare-agent/core';
import { getVocabulary, saveProgress } from '../tools/vocabulary';

export const vocabularyAgent = new Agent({
  name: 'vocabulary-tutor',
  model: { provider: 'groq', model: 'llama-3.3-70b-versatile' },
  memory: 'd1',
  maxIterations: 8,
  systemPrompt: (ctx) =>
    `Bạn là trợ lý học từ vựng tiếng Anh thân thiện.
     Hỗ trợ người dùng ${ctx.userId ?? 'ẩn danh'} học từ vựng hiệu quả.
     Luôn giải thích bằng tiếng Việt, ví dụ bằng tiếng Anh.
     Khuyến khích và động viên khi user trả lời đúng.`,
})
.use(getVocabulary, saveProgress);

Hono Routes

// apps/worker/src/index.ts
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { createSSEResponse } from '@flare-agent/core';
import { vocabularyAgent } from './agents/vocabulary';
import { QuizWorkflow } from './workflows/quiz';
import { MemoryManager, KVMemoryAdapter, D1MemoryAdapter, VectorizeAdapter } from '@flare-agent/memory';

const app = new Hono<{ Bindings: Env }>();

app.use('*', cors());

// Chat endpoint — stream response
app.post('/api/chat/stream', async (c) => {
  const { input, sessionId, userId } = await c.req.json();

  const ctx = {
    sessionId,
    userId,
    env: c.env as any,
  };

  const provider = /* resolve từ config */;
  const stream = provider.stream(
    [{ role: 'user', content: input }]
  );

  return createSSEResponse(stream);
});

// Chat endpoint — full response
app.post('/api/chat', async (c) => {
  const { input, sessionId, userId } = await c.req.json();

  const result = await vocabularyAgent.run(input, {
    sessionId,
    userId,
    env: c.env as any,
  });

  return c.json(result);
});

// Quiz workflow
app.post('/api/quiz/answer', async (c) => {
  const { answer, sessionId, userId } = await c.req.json();

  const workflow = new QuizWorkflow(c.env);
  const result = await workflow.run(answer, {
    sessionId,
    userId,
    env: c.env as any,
  });

  return c.json(result);
});

// RAG — tìm từ theo nghĩa
app.get('/api/recall', async (c) => {
  const query = c.req.query('q') ?? '';

  const memory = new MemoryManager({
    vector: new VectorizeAdapter(c.env.VECTORIZE, c.env.AI),
  });

  const results = await memory.recall(query, 5);
  return c.json({ results });
});

export const AgentSession = vocabularyAgent.toDurableObject();
export default app;

React Hook — SSE Consumer

// apps/web/src/hooks/useChat.ts
import { useState, useCallback } from 'react';

export function useChat() {
  const [messages, setMessages] = useState<Array<{
    role: 'user' | 'assistant';
    content: string;
  }>>([]);
  const [streaming, setStreaming] = useState('');
  const [loading, setLoading] = useState(false);

  const send = useCallback(async (input: string, sessionId: string) => {
    setLoading(true);
    setMessages((prev) => [...prev, { role: 'user', content: input }]);

    const res = await fetch('/api/chat/stream', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ input, sessionId }),
    });

    const reader = res.body!.getReader();
    const decoder = new TextDecoder();
    let fullText = '';

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      const lines = decoder.decode(value).split('\n');
      for (const line of lines) {
        if (!line.startsWith('data: ')) continue;
        const data = line.slice(6);
        if (data === '[DONE]') break;
        try {
          const { text } = JSON.parse(data);
          fullText += text;
          setStreaming(fullText);
        } catch { /* skip */ }
      }
    }

    setMessages((prev) => [...prev, { role: 'assistant', content: fullText }]);
    setStreaming('');
    setLoading(false);
  }, []);

  return { messages, streaming, loading, send };
}

wrangler.toml

name = "edu-ai-worker"
main = "src/index.ts"
compatibility_date = "2025-01-01"

[[durable_objects.bindings]]
name = "AGENT_SESSION"
class_name = "AgentSession"

[[migrations]]
tag = "v1"
new_classes = ["AgentSession"]

[[kv_namespaces]]
binding = "KV"
id = "YOUR_KV_ID"

[[d1_databases]]
binding = "DB"
database_name = "edu-ai"
database_id = "YOUR_D1_ID"

[[vectorize]]
binding = "VECTORIZE"
index_name = "edu-vocabulary"

[ai]
binding = "AI"

[vars]
OLLAMA_BASE_URL = "https://your-oracle-vm/ollama"

[secrets]
GROQ_API_KEY = ""

Kết quả

Sau 7 bài, bạn có:

  1. Framework ~800 lines TypeScript — hiểu 100% internals
  2. Zero lock-in — swap provider, memory, runtime bằng 1 dòng
  3. edu-ai-platform chạy native trên Cloudflare
  4. Tái sử dụng được cho bất kỳ project nào khác

Bước tiếp theo

  • Extract framework thành npm packages khi cần dùng cho project thứ 2
  • Thêm Observability / Tracing (OpenTelemetry)
  • Thêm Multi-agent support
  • Viết tests cho từng package

Series hoàn tất. Nếu bài viết hữu ích, hãy star repo và chia sẻ với cộng đồng developer Việt Nam! 🇻🇳