# 文件搜索 Agent

本机全文检索 + 自然语言问答的文件搜索工具。**零第三方依赖**（只用 Python 标准库 +
环境里已有的 Office 解析库），不需要联网安装任何东西。

> 本工作区里有**两份**产物，别搞混：
>
> | 目录 | 是什么 | 怎么跑 |
> | --- | --- | --- |
> | `backend/` + `frontend/` | **独立版**：自带 HTTP 服务与网页界面，可单独运行 | `run.cmd` → <http://127.0.0.1:8765/> |
> | `graphscholar-addon/` | **集成版**：把同一个搜索引擎做进你的「智研成理 GraphScholar」工程（FastAPI + Obsidian 暗紫前端），零新增 pip 依赖 | 见 [集成指南](graphscholar-addon/集成指南.md)，一条 `merge_into_project.py` 命令 |
>
> 两者共用同一套检索内核（SQLite FTS5 + trigram 中文子串检索）。

- 设计思路：[docs/DESIGN.md](docs/DESIGN.md)
- 接口契约：[docs/API.md](docs/API.md)
- GraphScholar 集成：[graphscholar-addon/集成指南.md](graphscholar-addon/集成指南.md)

## 快速开始

```bat
run.cmd
```

然后打开 <http://127.0.0.1:8765/>，第一次使用点右上角 **索引** 建立索引。

也可以直接指定解释器与端口：

```bat
python backend\server.py --port 8899
```

> Windows 上如果 `python` 是 Microsoft Store 的占位程序（提示 "Python was not found"），
> 请安装真正的 Python 3.10+，或直接用 `run.cmd`（它会自动寻找可用解释器）。

## 功能

- **全文检索**：基于 SQLite FTS5 + `trigram` 分词器，中文/英文都支持**子串**匹配；
  BM25 相关度排序，文件名命中权重是正文的 8 倍。
- **语义混合检索**：关键词 + 向量两路，**RRF 融合**（`mode=hybrid|keyword|semantic`）。
  默认走**离线向量兜底**：纯 numpy、零新增依赖、断网可用，做词序/近似/拼写容错
  （查询 `中文子串匹配靠分词器` 能找回原文 `中文检索靠 FTS5 的 trigram 分词器实现子串匹配`）；
  在设置里填入嵌入接口地址（如硅基流动 `BAAI/bge-m3`）即升级为**真语义**。
  详见 [docs/SEMANTIC.md](docs/SEMANTIC.md)。
- **查询语法**：`ext:md,py`、`path:docs/`、`size:>2MB`、`mtime:<30d`、`"精确短语"`、`-排除`。
- **内容抽取**：纯文本/代码（自动识别 UTF-8 / GB18030 / UTF-16 编码）、Markdown、JSON、
  CSV、HTML（去标签）、Word(.docx)、Excel(.xlsx)、PowerPoint(.pptx)、PDF（尽力而为）。
- **增量索引**：以 `size + mtime_ns` 判断是否变化，只重抽变化的文件；删除的文件自动清理。
- **Agent 问答**：用自然语言提问，Agent 自己调用 `search_files` / `read_file` /
  `list_dir` / `stats` 工具，回答里带 `[1]` 式引用。未配置模型时自动降级为**本地规则引擎**，
  功能仍然可用。

## 目录结构

```
backend/    server.py(HTTP/路由/SSE) config.py db.py extract.py indexer.py
            search.py(关键词+RRF 融合) semantic.py(向量通道) content.py agent.py llm.py
frontend/   index.html styles.css app.js   零构建原生 ESM
docs/       DESIGN.md(思路) API.md(接口契约) SEMANTIC.md(语义混合检索)
data/       config.json index.db           运行时生成
run.cmd     一键启动
```

## 配置

在界面右上角「设置」里改，或直接编辑 `data/config.json`：

| 键 | 说明 |
| --- | --- |
| `port` / `host` | 监听地址，默认 `127.0.0.1:8765`（仅回环） |
| `default_roots` | 首次启动自动加入的索引根目录 |
| `ignore_dirs` / `ignore_globs` | 跳过的目录名与文件名通配 |
| `max_file_bytes` | 超过该大小只登记元数据、不抽取内容 |
| `chunk_chars` / `chunk_overlap` | 分块大小与重叠字符数 |
| `llm.enabled` / `llm.api_key` / `llm.model` / `llm.base_url` | 模型接入（OpenAI 兼容接口，默认 DeepSeek） |
| `semantic.enabled` / `semantic.backend` / `semantic.base_url` / `semantic.model` | 语义通道：`backend=auto` 时**填了 base_url 就用远端嵌入，否则用离线兜底**；`min_score` 是相似度下限 |

`api_key` 只写入不读出：`GET /api/config` 永远只返回 `api_key_set: true/false`。

## 安全边界

- 服务默认只监听 `127.0.0.1`，局域网内其它机器访问不到。
- 只提供**读**接口，没有写入/删除文件的接口。
- `/api/file/raw` 与 `/api/open` 都要求目标路径位于已登记的索引根目录内，防目录穿越。

## 已知限制

- 扫描件 PDF、图片内文字不支持（需要 OCR，属于后续计划）。
- 索引根目录如果在当前沙箱授权目录之外，服务可能读不到（见下）。
- 索引本机大目录时首次建立索引会比较耗时；建议先只加需要的目录。
