使用渐进式,逐步实现一个 AI 服务的关键点。 使用 React+NodeJS实现。

1、接口设计

A. 任务启动接口 (Producer Side)

前端通过此接口发送问题,后端初始化 Agent 并返回票据。

  • POST /api/v1/agent/chat
  • 请求体: { sessionId: string, prompt: string }
  • 响应体: { agentId: string, status: "created" }

B. SSE 订阅接口 (Consumer Side)

前端拿到 agentId 后,立即建立长连接。

  • GET /api/v1/events/subscribe/:agentId
  • Header: Connection: keep-alive, Content-Type: text/event-stream

2、核心模块设计

模块一:Connection Manager (SSE 枢纽)

这是你微服务的核心。它像一个“交换机”,负责维护 agentId 到多个 Response 对象的映射。

  • 数据结构: Map<string, Set<Response>>
  • 职责:
    • 管理连接的生命周期(连接、断开、清理)。
    • 实现心跳包,防止网关超时。
    • 封装 send(agentId, data) 方法,实现一对多广播。

模块二:Agent Engine (执行引擎)

负责与 AI 模型(如 OpenAI)交互。

  • 职责:
    • 实例化 Agent 逻辑。
    • 将 AI 返回的 Stream 碎片包装成标准的 AgentEvent 格式。
    • 每次产生新碎片时,调用 Connection Manager 的发送方法。

模块三:Session Store (可选)

  • 职责: 记录 sessionIdagentId 的历史关系,确保对话上下文的连续性。

1、V0.1 可跑通过的 DEMO

feature:

  1. AI 模型分发,可以选择使用哪个模型。
  2. 实现对话框上,AI 返回逐字添加的效果

方案:

1、AI 模型分发的简单版本:

// 通过规则,来选择使用哪个 Model
function agentDispatcher(prompt) {
  // 简单的关键词路由:如果包含 "代码"、"函数"、"code",则路由给 Coder Agent
  if (prompt.match(/(代码|函数|code|script)/i)) {
    console.log(`[Router] Dispatching to Coder Agent: ${prompt}`);
    return coderModel(prompt);
  }
  console.log(`[Router] Dispatching to Chat Agent: ${prompt}`);
  return chatModel(prompt);
}

2、实现流式推送(逐字效果)

  1. ❌ 前端轮训:性能问题,也不现实。
  2. ❌ WebSocket:太重了。
  3. ✅ Chunked Transfer(http 分块传输)
  4. ✅ SSE(Server-Sent Events)

最佳方案,一般是 **SSE + Chunked。**这里v0.1版本,先只用chunked实现。

// server
app.post("/api/chat", async (req, res) => {
  const { prompt } = req.body;
 
  // 关键头信息:开启流式传输
  res.setHeader("Content-Type", "text/html; charset=utf-8");
  res.setHeader("Transfer-Encoding", "chunked");
 
  try {
    // 获取对应的 Generator
    const stream = agentDispatcher(prompt);
 
    // 循环推送数据块
    for await (const chunk of stream) {
      res.write(chunk);
    }
  } catch (err) {
    console.error(err);
  } finally {
    res.end(); // 结束响应
  }
});
 
// client
 const response = await fetch("http://localhost:3001/api/chat", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ prompt: currentPrompt }),
      });
 
      const reader = response.body.getReader();
      const decoder = new TextDecoder();
 
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
 
        const textChunk = decoder.decode(value, { stream: true });
 
        // 实时更新最后一条消息(即 AI 的回复)
        setMessages((prev) =>
          prev.map((msg, idx) =>
            idx === prev.length - 1
              ? {
                  ...msg,
                  content: msg.content + textChunk,
                }
              : msg
          )
        );
      }