<!--
---
title: Arabica Sprint3 开发指南：意图驱动路由与高可用容错架构
description: 基于 Sprint 3 架构设计，指导开发者搭建全自然语言意图驱动的 MCP Server，实现学术文献检索、本地知识库无缝对接，并在底层构建抗死循环与强容错机制。
type: Development Guide
version: v1.0.0 (Arabica) - Sprint 3
file: arabica-sprint3-development-specification.md
author: Gitconomy Research-郭晧
date: 2026-03-11
tags:
  - Project Caffeine
  - MCP Server
  - Sprint 3
  - Intent-Driven
  - Fault Tolerance
  - arXiv API
  - Node.js
license: CC BY-SA 4.0
status: Active
---
-->
# Arabica Sprint 3 开发指南

## 1. 模块概览与架构设计

Sprint 3 的核心是完成系统的“智能升维”：不再采用向客户端 UI 暴露的 Prompts 原语，将大模型升级为拥有完整上下文的高级智能体（Agent）。通过意图识别，系统自动路由至对应的工具（Tools），并在底层彻底解决大模型长文本转义崩溃与工具死循环问题。

整体架构精简为高度内聚的三层模型：

- **接入层**：`app.ts` 负责初始化 MCP 服务器，注册 5 大核心工具，并放宽参数类型（`z.any()`）以承接畸形负载。
- **控制层（核心大脑）**：`toolsController.ts` 充当路由网关与防火墙，处理参数兜底序列化、JSON 框架外壳剥离及强指令注入。
- **服务层**：`arxivService.ts`（学术网关）与 `resourceService.ts`（本地存储网关）处理具体的外部/内部 I/O。

<br>

下图展示了模块间的静态关系：

```mermaid
graph TD
    A[app.ts 接入层] --> B[toolsController 核心路由]
    A --> C[resource 资源注册]

    B --> D[arxivService 学术检索]
    B --> E[resourceService 本地文件操作]
    B --> F[本地 frameworks JSON]

    D --> G[arXiv API]
    E --> H[本地 Markdown 知识库]
    C --> E
````

---

## 2. 函数列表和调用逻辑关系

## 2.1 完成函数列表

以下是 Sprint 3 项目中所有显式定义的核心函数，按文件分组。_(注：Sprint 2 中的 `intentService.ts`、`promptsController.ts` 和 `promptService.ts` 已在本次迭代中删除)_

#### 1. `app.ts`（入口文件）

|**函数名**|**参数**|**描述**|**异步**|
|---|---|---|---|
|`start`|无|初始化 MCP 服务器，连接 STDIO 传输层|✅|

#### 2. `toolsController.ts`（工具控制器 & 路由大脑）

|**函数名**|**参数**|**描述**|**异步**|
|---|---|---|---|
|`handleToolCall`|`toolName: string, params: any`|统一入口，根据工具名分发到具体处理函数|✅|
|`handleSearchArxiv`|`params: any`|处理 `search_arxiv`，调用外部 API 并格式化结果|✅|
|`handleFetchFramework`|`params: any`|处理 `fetch_framework_template`，剥离 JSON 注入刹车指令|✅|
|`handleSaveNote`|`params: any`|处理 `save_note`，执行 JSON 对象容错与序列化|✅|
|`handleListLocalNotes`|无|处理 `list_local_notes`，返回本地笔记清单|✅|
|`handleReadLocalNote`|`params: any`|处理 `read_local_note`，读取具体笔记|✅|

#### 3. `arxivService.ts`（学术检索服务）

|**函数名**|**参数**|**描述**|**异步**|
|---|---|---|---|
|`searchArxiv`|`query: string, maxResults: number`|发起 HTTP 请求，解析 arXiv XML 返回标准化文献数组|✅|

#### 4. `resourceService.ts`（资源服务 - 维持 S2 核心）

|**函数名**|**参数**|**描述**|**异步**|
|---|---|---|---|
|`listObsidianNotes`|无|列出知识库目录下所有 `.md` 文件|✅|
|`readObsidianNote`|`filename: string`|读取指定笔记文件内容，含路径防穿越校验|✅|
|`saveNote`|`filename: string, content: string`|将内容安全写入本地知识库|✅|

## 2.2 整体函数调用关系图

代码段

```mermaid
graph TD
    subgraph "接入层 app.ts"
        A1["server.tool (search_arxiv)"] -->|分发| B1[handleToolCall]
        A2["server.tool (fetch_framework)"] -->|分发| B1
        A3["server.tool (save_note)"] -->|分发| B1
        A4["server.resource (local-notes)"] -->|list/read 回调| C1[resourceService]
    end

    subgraph "控制器 (防火墙与路由) toolsController"
        B1 -->|匹配意图 1| D1[handleSearchArxiv]
        B1 -->|匹配意图 2| D2[handleFetchFramework]
        B1 -->|匹配意图 3| D3[handleSaveNote]
    end

    subgraph "服务层"
        D1 -->|发起网络请求| E1[arxivService.searchArxiv]
        D2 -->|读取本地配置| E2[(frameworks/*.json)]
        D3 -->|容错兜底后写盘| E3[resourceService.saveNote]
    end
```

---

## 3. 核心业务代码实现

## 3.1 接入层 (`app.ts`)

#### 3.1.1 模块职责与设计目标

- **类型收敛与编译修复**：通过显式断言 `type: "text" as const`，解决 TypeScript 无法推断 MCP 严格字面量类型的编译报错。

- **宽容参数输入**：将容易引发大模型转义崩溃的长文本参数（如 `user_input`、`content`）从 `z.string()` 放宽至 `z.any()`，将容错权下放给 Controller 层。


#### 3.1.2 核心代码解析

```typescript
// ==========================================
// 意图 3: 保存笔记工具 (高容错版)
// ==========================================
server.tool(
  'save_note',
  {
    filename: z.string().describe('生成的文件名，必须以 .md 结尾'),
    // 💡 关键容错：放宽校验，接纳大模型误传的 JSON Object
    content: z.any().describe('需要保存的完整内容文本，支持传入JSON对象。')
  },
  async (args) => {
    const result = await handleToolCall('save_note', args);
    return {
      isError: result.isError,
      // 💡 显式字面量断言，修复 TS 报错
      content: result.content.map((item: any) => ({ type: "text" as const, text: item.text }))
    };
  }
);
```

## 3.2 控制层 (`toolsController.ts`)

#### 3.2.1 模块职责与设计目标

控制层在 Sprint 3 中化身为**“智能体的大脑与护栏”**。

1. **抗死循环（Anti-Loop）**：处理 `fetch_framework_template` 时，拦截原始 JSON 结构，提取纯文本，并强行拼接业务指令阻断模型乱调工具。

2. **长文本容错（Fallback Serialization）**：处理 `save_note` 时，拦截畸形的 JSON 入参并自动序列化，确保平滑写盘。


#### 3.2.2 核心逻辑流程与代码

##### 3.2.2.1 `handleFetchFramework` (抗死循环剥离器)

1. **调用序列图**

```mermaid
sequenceDiagram
    participant LLM as 大模型
    participant Ctrl as toolsController
    participant FS as 本地文件系统

    LLM->>Ctrl: 请求工具 fetch_framework (SWOT)
    Ctrl->>FS: 读取 swot.json
    FS-->>Ctrl: 原始 JSON 字符串
    Ctrl->>Ctrl: JSON.parse() 提取 system / user prompt
    Ctrl->>Ctrl: 组装纯文本，并在头部拼接【🛑立即停止调用工具】
    Ctrl-->>LLM: 返回纯文本强指令
    LLM->>LLM: 遵守指令，停止工具调用，开始输出分析文本
```

2. **核心代码**

```typescript
async function handleFetchFramework(params: any) {
    const name = params.framework_name?.toLowerCase();
    // ... 校验框架有效性并读取 JSON 文件 ...
    const parsedData = JSON.parse(fileContent);

    // 提取出真正的 Prompt 文本，绝对不给大模型看 JSON 壳子
    const sysMsg = parsedData.messages?.find((m: any) => m.role === 'system')?.content?.text || '';
    const userMsg = parsedData.messages?.filter((m: any) => m.role === 'user').pop()?.content?.text || '';

    // 组装极强约束的系统指令，强制大模型刹车
    const returnText = `【🛑 最高优先级的底层执行指令 🛑】
你已经成功获取了 ${name.toUpperCase()} 框架的模板。现在，请你**立即停止调用任何工具**！绝对不要重复调用 fetch_framework_template！

请直接在聊天框中为用户输出最终的分析报告。
【系统设定】：\n${sysMsg}\n
【分析结构要求】：\n${userMsg}\n
⚠️ 最终要求：报告输出完毕后，你必须向用户提问：“分析完毕，是否需要将此分析结果保存成笔记？”`;

    return { content: [{ type: 'text', text: returnText }] };
}
```

##### 3.2.2.2 `handleSaveNote` (兜底序列化)

1. **逻辑流程图**

```mermaid
graph TD
    A[接收参数 params.content] --> B{typeof content === string?}
    B -- 是 --> C[直接将 content 传给 resourceService]
    B -- 否(是个对象) --> D["执行 JSON.stringify]
    D --> C
    C --> E[写入 Markdown 文件]
    E --> F[返回操作成功]
```

2. **核心代码**

```typescript
async function handleSaveNote(params: any) {
    if (!params.filename || !params.content) {
      throw new Error("保存失败：缺少 filename 或 content 参数");
    }

    // 💡 核心容错逻辑：帮大模型擦屁股处理奇葩格式
    let contentToSave = '';
    if (typeof params.content === 'string') {
      contentToSave = params.content;
    } else {
      // 若大模型传了深度嵌套的对象，在底层帮它转成带缩进的字符串
      contentToSave = JSON.stringify(params.content, null, 2);
    }

    const message = await saveNote(params.filename, contentToSave);
    return { content: [{ type: 'text', text: message }] };
}
```

## 3.3 服务层 (`arxivService.ts`)

#### 3.3.1 模块职责

专注于与 arXiv 官方 API 通信。其核心使命是将原本极其复杂的学术 XML 标签（包含海量对大模型无用的元数据）**清洗、降维**为大模型能够轻松理解的极简 Markdown 列表。

#### 3.3.2 核心逻辑流

```mermaid
sequenceDiagram
    participant Ctrl as toolsController
    participant Svc as arxivService
    participant API as arXiv API

    Ctrl->>Svc: searchArxiv('quantum', 5)
    Svc->>API: fetch('[http://export.arxiv.org/api/query?search_query=all:quantum&max_results=5](http://export.arxiv.org/api/query?search_query=all:quantum&max_results=5)')
    API-->>Svc: XML 格式的学术数据
    Svc->>Svc: 解析 XML，提取 entry (title, id, summary)
    Svc->>Svc: 清洗换行符，映射为统一的 Literature Object
    Svc-->>Ctrl: 返回极简对象数组
```

---

## 4. 测试与质量保障 (Testing & QA)

Sprint 3 引入了 Jest 自动化测试套件，重点关注工具控制层的路由与容错能力：

1. **网络拦截与 Mock**：在 `arxivService.test.ts` 中，必须通过 `global.fetch = jest.fn()` 拦截真实网络请求，确保测试在离线环境下秒级通过。

2. **容错机制断言**：在 `toolsController.test.ts` 中，编写专门针对 `save_note` 传入 JSON Object 的断言（Assertion），验证 `resourceService.saveNote` 被调用时接收到的是否为序列化后的字符串。

3. **刹车指令探针**：测试 `fetch_framework_template` 时，断言返回的 `content.text` 必须 `toContain('立即停止调用任何工具')`，确保防死锁底座生效。

---

## 许可声明

本文档采用 **知识共享署名-相同方式共享 4.0 国际许可协议 (CC BY-SA 4.0)** 进行许可，© 2025-2026 Gitconomy Research.
