llm-to-agent/docs/design.md
2026-08-21 16:33:06 +08:00

6.6 KiB
Raw Blame History

llm-to-agent 设计文档

架构设计

核心理念:微内核 + 事件驱动

Agent 的本质是一个循环:用户输入 → LLM 思考 → 工具调用 → LLM 再思考 → 最终回复

本项目的答案是:内核只做一件事——驱动这个循环。LLM 调用、工具执行、日志输出等一切能力全部通过事件总线交给外部插件。

三层架构

┌──────────────────────────────────────────┐
│  Route 层       CLI / Desktop / Web       │  ← 只决定 I/O 方式
├──────────────────────────────────────────┤
│  Plugin 层      provider / tool / hook    │  ← 可替换的能力单元
├──────────────────────────────────────────┤
│  Core 层        Scheduler + HookBus       │  ← 只做循环 + 事件路由
└──────────────────────────────────────────┘

事件总线

内核循环的每一步都通过 HookBus 发出事件,插件注册响应,形成“事件驱动 + 插件化”的架构。

插件类型

类型 职责 响应的事件
provider LLM 提供商适配 llm:calltool:select
tool 工具能力 tool:schematool:execute
hook 生命周期副作用 tool:beforetool:afterrun:end
prompt 系统提示词 通过配置注入,不响应事件

每个插件通过 manifest.json 声明元信息(名称、类型、提供的能力、适用平台),由 PluginManager 统一加载。

三条产品线

                    ┌── @llm-to-agent/core ──┐
                    │  MicroKernel + HookBus  │
                    └────────────────────────┘
                              │
            ┌─────────────────┼─────────────────┐
            ▼                 ▼                 ▼
          CLI              Desktop            Web
       (readline)        (Electron)      (Browser HTTP)
            │                 │                 │
    ┌───────┴────────┐ ┌──────┴───────┐ ┌──────┴───────┐
    │ 本地工具全部   │ │ 同 CLI       │ │ 仅远程工具   │
    │ console 日志   │ │ IPC 日志     │ │ SSE 日志     │
    └────────────────┘ └──────────────┘ └──────────────┘

CLI 与 Desktop 共享本地工具文件读写、Shell 执行Web 端通过 platforms 字段自动跳过本地工具。


项目目录设计

Monorepo 结构pnpm workspace

llm-to-agent/
├── pnpm-workspace.yaml
├── package.json                 ← 根private统一 dev/test 脚本)
├── tsconfig.json
│
├── docs/                        ← 设计文档
│   └── design.md
│
├── packages/
│   │
│   ├── types/                   ← @llm-to-agent/types
│   │   └── src/index.ts         ← 所有共享类型Message/ToolDef/PluginManifest/...
│   │
│   ├── core/                    ← @llm-to-agent/core
│   │   └── src/
│   │       ├── hook-bus.ts      ← 事件总线on/emit/request/collect
│   │       ├── scheduler.ts     ← Agent 循环think→tool→think
│   │       ├── context.ts       ← 消息上下文管理器
│   │       ├── plugin-manager.ts← 插件加载 + 生命周期
│   │       └── kernel.ts        ← MicroKernel 入口(组合以上模块)
│   │
│   ├── plugins-builtin/         ← @llm-to-agent/plugins-builtin
│   │   └── [xxxxx]/ ← 内置插件
│   │
│   ├── cli/                     ← @llm-to-agent/cli终端入口
│   │   └── src/index.ts         ← readline 循环 + kernel.init([...])
│   │
│   ├── desktop/                 ← @llm-to-agent/desktop桌面入口
│   │   └── src/main.ts          ← Electron 主进程
│   │
│   ├── server/                  ← @llm-to-agent/serverWeb 后端)
│   │   └── src/index.ts         ← Express + SSE
│   │
│   ├── web/                     ← @llm-to-agent/webWeb 前端)
│   │   └── index.html           ← 待实现 React 聊天界面
│   │
│   ├── tests/                   ← @llm-to-agent/tests
│   │   └── src/                 ← *.test.tsNode 原生 test runner
│   │
│   └── old/                     ← @llm-to-agent/old旧代码归档
│       └── src/                 ← 重构前的 Agent 实现

包依赖关系

@llm-to-agent/types           ← 零依赖,纯类型
    ↑           ↑
   core    plugins-builtin
    ↑           ↑
    ├───────────┴────────────┐
    ↓           ↓            ↓
   cli      desktop      server
                            ↑
                           web

插件清单规范

每个插件目录包含 manifest.json

{
  "name": "@agent/tool-file",
  "version": "1.0.0",
  "type": "tool",
  "provides": ["file-read", "file-write"],
  "entry": "./index.ts",
  "platforms": ["cli", "desktop"]
}
字段 说明
type provider / tool / hook / prompt
provides 提供的能力标识
entry 入口文件,默认导出 register(bus: HookBus)
platforms 可用平台PluginManager 加载时自动过滤

关键类型

// 消息
interface Message {
  role: 'system' | 'user' | 'assistant' | 'tool';
  content: string;
  tool_calls?: ToolCall[];
  tool_call_id?: string;
}

// 工具定义OpenAI 兼容)
interface ToolDef {
  type: 'function';
  function: {
    name: string;
    description: string;
    parameters: Record<string, unknown>;
  };
}

// 插件清单
interface PluginManifest {
  name: string;
  version: string;
  type: 'provider' | 'tool' | 'hook' | 'prompt';
  provides: string | string[];
  entry: string;
  platforms?: ('cli' | 'desktop' | 'web')[];
}

// 事件总线
type EventName = string;
type Listener = (data: any) => any | Promise<any>;