---
tags: [eino, go, ai-agent, rag, tool-calling, project-theme]
create time: 2026-05-05 14:30
---

# EiNO 项目实战：个人知识助手

## 概述

基于字节跳动 EINO 框架（Go 语言），从零构建一个**个人知识助手 Agent**。该项目深度融合 **RAG（检索增强生成）** 与 **Tool Calling（工具调用）** 两大核心能力，采用 Supervisor 多 Agent 编排模式，帮助用户高效检索笔记、整理知识、发现关联。场景聚焦日常知识管理，不依赖外部基础设施，是入门 EINO 框架的理想项目。

## 正文

### 1. 项目背景

> [!question] 思考：当你积累了上千篇笔记，某天想找一篇"半年前记过的 Go 并发模式"，只记得大概内容却忘了标题——你会怎么办？

传统做法：逐个翻文件夹 → 搜关键词 → 翻了几分钟还是没找到。而一个智能知识助手可以：

1. **听懂模糊描述**："那个讲 goroutine 泄漏排查的文章"→ 语义检索精准定位
2. **整理碎片知识**："把最近关于 EINO 的笔记汇总成一篇综述"
3. **发现隐藏关联**："这篇 RAG 笔记和那篇向量数据库笔记其实在讲同一件事"

这个场景**天然适合 AI Agent**：检索知识库（RAG）+ 操作笔记（Tool Calling）+ 多步骤任务（ReAct）。

**用 EINO 的原因**：
- Go 原生协程，本地跑也轻量
- 编译时类型检查，工具定义清晰、不易出错
- ADK 内置 Supervisor / Plan-Execute / Interrupt 等模式，开箱即用

---

### 2. 系统架构总览

```mermaid
graph TD
    U["用户提问"] --> S["Supervisor Agent<br/>知识总管家"]

    S --> R["Retrieval Agent<br/>知识检索专家"]
    S --> W["Writer Agent<br/>内容处理专家"]
    S --> O["Organizer Agent<br/>知识整理专家"]

    R --> VDB["向量数据库<br/>笔记内容索引"]
    R --> T1["Tool: 语义搜索<br/>相似笔记召回"]
    R --> T2["Tool: 关键词搜索<br/>精确匹配"]

    W --> T3["Tool: 创建笔记<br/>写入 Markdown"]
    W --> T4["Tool: 摘要提取<br/>生成笔记摘要"]
    W --> T5["Tool: 标签推荐<br/>自动打标签"]

    O --> T6["Tool: 关联发现<br/>Wiki-link 推荐"]
    O --> T7["Tool: 知识图谱<br/>关联关系查询"]

    style S fill:#4A90D9,color:#fff
    style VDB fill:#27AE60,color:#fff
```

> **Supervisor 模式**：Supervisor Agent 接收用户指令，根据意图路由——搜索类交给 Retrieval Agent、写作类交给 Writer Agent、整理类交给 Organizer Agent，最终汇总结果返回。

---

### 3. RAG 模块设计

RAG 负责从用户的笔记库中检索相关内容，让 Agent "读懂你的知识库"。

#### 3.1 笔记索引管道

```mermaid
flowchart LR
    A["Markdown 笔记库"] --> B["Document Loader<br/>按段落分块"]
    B --> C["Embedding<br/>文本向量化"]
    C --> D["Indexer<br/>写入向量库"]
    D --> E["Hybrid Retriever<br/>混合检索"]
    E --> F["Agent<br/>上下文注入"]
```

#### 3.2 核心代码：混合检索器

```go
// RetrieverService 混合检索：语义匹配 + 标签过滤
type RetrieverService struct {
    client   milvus.Client
    embedder embedding.Embedder
}

func (s *RetrieverService) Retrieve(ctx context.Context, query string, tags []string) ([]*schema.Document, error) {
    // 1. 将用户查询转为向量
    vector, err := s.embedder.Embed(ctx, query)
    if err != nil {
        return nil, fmt.Errorf("embed query: %w", err)
    }

    // 2. 构建标量过滤：限定标签范围
    //    例如: "tag in ['go', 'concurrency', 'eino']"
    expr := buildTagFilterExpr(tags)

    // 3. 混合检索：Top-K=5
    results, err := s.client.Search(ctx, "notes_collection",
        nil, expr,
        []string{"content", "title", "tags"},
        vector,
        milvus.NewTopKMetricType(milvus.L2, 5),
        milvus.NewSearchParam(16),
    )
    // ... 转换为 EINO Document 格式
    return s.convertToDocs(results), nil
}
```

> [!tip] 设计要点
> 混合检索 = **语义相似度**（"我记得大概意思"） + **标签过滤**（"应该是 Go 相关的"）。相比纯关键词搜索，它能找到表述不同但意思相近的笔记——这正是知识管理中最常见的场景。

---

### 4. Tool Calling 模块设计

Agent 通过工具与笔记系统交互：搜索、创建、整理、发现关联。

#### 4.1 工具清单

| 工具 | 类型 | 描述 |
|------|------|------|
| `semantic_search` | 查询 | 语义搜索笔记，支持模糊自然语言描述 |
| `keyword_search` | 查询 | 精确关键词 + 标签搜索 |
| `create_note` | 写入 | 创建新笔记（Markdown + YAML frontmatter） |
| `generate_summary` | 处理 | 为指定笔记生成摘要 |
| `suggest_tags` | 处理 | 根据内容自动推荐标签 |
| `find_related` | 查询 | 发现关联笔记，推荐 Wiki-link |

#### 4.2 核心代码：定义工具

```go
// === 写笔记工具 ===
type CreateNoteParams struct {
    Title   string   `json:"title" desc:"笔记标题"`
    Content string   `json:"content" desc:"Markdown 格式正文"`
    Tags    []string `json:"tags" desc:"标签列表，如 ['go', 'eino']"`
}

func CreateNoteTool(vaultPath string) componenttool.BaseTool {
    return &componenttool.Tool{
        Name: "create_note",
        Desc: "在知识库中创建一篇新的 Markdown 笔记",
        Func: func(ctx context.Context, params *CreateNoteParams) (string, error) {
            fullPath := filepath.Join(vaultPath, params.Title+".md")
            content := buildMarkdownWithFrontmatter(params)
            if err := os.WriteFile(fullPath, []byte(content), 0o644); err != nil {
                return "", fmt.Errorf("write note: %w", err)
            }
            return fmt.Sprintf("笔记已创建: %s", fullPath), nil
        },
    }
}

// === 关联发现工具 ===
type FindRelatedParams struct {
    NoteTitle string `json:"note_title" desc:"目标笔记标题"`
}

func FindRelatedTool(retriever *RetrieverService) componenttool.BaseTool {
    return &componenttool.Tool{
        Name: "find_related",
        Desc: "根据笔记内容，从知识库中发现与之关联的其他笔记，推荐 Wiki-link",
        Func: func(ctx context.Context, params *FindRelatedParams) (string, error) {
            noteContent := readNote(params.NoteTitle)
            related, _ := retriever.Retrieve(ctx, noteContent, nil)
            return formatWikiLinkSuggestions(related), nil
        },
    }
}
```

> [!question] 思考：如果用户说"帮我把最近一周关于 EINO 的笔记整理成一篇综述"，Agent 需要依次调用哪些工具？顺序能否调换？

---

### 5. Multi-Agent 编排：Supervisor 模式

```go
// === 构建 Supervisor，编排三个 Specialist Agent ===
func BuildKnowledgeSupervisor(ctx context.Context) (*adk.Supervisor, error) {
    // Retrieval Agent: 负责搜索和检索
    retrievalAgent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        Name:        "RetrievalAgent",
        Instruction: "你是知识检索专家，擅长从笔记库中找到最相关的内容...",
        Model:       model,
        ToolsConfig: adk.ToolsConfig{
            ToolsNodeConfig: compose.ToolsNodeConfig{
                Tools: []componenttool.BaseTool{
                    SemanticSearchTool(retriever),
                    KeywordSearchTool(),
                    FindRelatedTool(retriever),
                },
            },
        },
        MaxIterations: 10,
    })

    // Writer Agent: 负责创建和整理内容
    writerAgent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        Name:    "WriterAgent",
        Model:   model,
        ToolsConfig: adk.ToolsConfig{
            ToolsNodeConfig: compose.ToolsNodeConfig{
                Tools: []componenttool.BaseTool{
                    CreateNoteTool(vaultPath),
                    SummaryTool(model),
                    SuggestTagsTool(model),
                },
            },
        },
        MaxIterations: 8,
    })

    // Organizer Agent: 负责关联发现和知识图谱
    organizerAgent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
        // ... 配置 FindRelated 等整理工具
        MaxIterations: 8,
    })

    return adk.NewSupervisor(ctx, &adk.SupervisorConfig{
        Name:      "KnowledgeSupervisor",
        Model:     model,
        Instruction: "你是知识总管。根据用户意图路由任务...",
        SubAgents: []adk.Agent{retrievalAgent, writerAgent, organizerAgent},
    })
}
```

```mermaid
sequenceDiagram
    participant U as 用户
    participant S as Supervisor
    participant R as Retrieval Agent
    participant W as Writer Agent

    U->>S: "帮我整理最近关于 EINO 的笔记，<br/>写一篇学习综述"

    S->>S: 意图分类 → 检索 + 写作（复合任务）

    S->>R: 委派检索任务
    R->>R: Tool: semantic_search("EINO") → 找到 5 篇
    R->>R: Tool: find_related → 发现 3 篇关联笔记
    R->>S: 返回 8 篇笔记及其内容

    S->>W: 委派写作任务（附检索结果）
    W->>W: 基于 8 篇笔记撰写综述草稿
    W->>W: Tool: suggest_tags → ["eino", "agent", "go"]
    W->>S: 返回综述 + 推荐标签

    S->>U: 📝 综述全文 + 🏷️ 推荐标签 + 🔗 关联笔记
```

---

### 6. 进阶拓展方向

> [!info] 掌握了基础架构后，可以探索这些方向

1. **会话式检索**：支持多轮追问——"上次那篇关于 goroutine 的"→"不是那篇，是讲泄漏排查的"→ Agent 结合上下文逐步缩小范围，像和人对话一样自然。

2. **定时知识回顾**：用 Cron 触发 Agent，每周自动检索本周新增笔记 → 生成"本周知识地图"→ 推送回顾通知。类似间隔重复，但由 AI 驱动。

3. **跨源增强**：当本地笔记不足时，Agent 可调用 `web_search` 工具获取外部信息作为补充，生成"本地知识 + 外部参考"的混合回答，并标注来源。

4. **知识冲突检测**：当新笔记与已有笔记表述矛盾（如某篇写"Go defer 是栈顺序"，另一篇写"是队列顺序"），Agent 自动标记冲突，提醒用户核实。

5. **MCP 集成**：将工具标准化为 MCP Server，让其他 AI 客户端（如 Claude Desktop、VS Code 插件）也能直接调用你的知识助手。

---

### 7. 关键 EINO 概念速查

| EINO 概念 | 本项目对应 |
|-----------|-----------|
| `ChatModelAgent` | RetrievalAgent / WriterAgent / OrganizerAgent |
| `Supervisor` | KnowledgeSupervisor（多 Agent 总调度） |
| `Tool / ToolsNode` | 语义搜索、创建笔记、摘要、标签、关联发现 |
| `Retriever` | 混合检索器（语义 + 标签过滤） |
| `Embedding` | 文本向量化 |
| `Indexer` | 笔记内容写入向量库 |
| `Document Loader` | Markdown 笔记按段落分块加载 |
| `ChatTemplate` | System Prompt + 检索结果注入 |
| `Interrupt / Resume` | 删改操作前的确认拦截（进阶） |
| `Graph / Compile` | 编排所有节点、编译成可执行图 |

---

## 关联笔记

- [[EINO ADK 深入]]

