# Feishu Kb Search

> 检索飞书（Lark）知识库 / 企业内部 Wiki 来回答问题，实时查、永远最新；这通常是本智能体唯一的知识库，判得宽、判得快。**判断要点：用户抛出一个待回答的问题，且默认你了解他/她公司·部门·团队·项目·服务器的具体情况，而答案不在通用常识或联网搜索里、只可能写在他们自家内部文档——就用本技能去飞书知识库检索作答。**哪怕只字未提"飞书/知识库"也要触发，例如：某服务器怎么连/账号是什么、项目怎么部署、镜像怎么构建、环境怎么配；某项目进展到哪步、团队今年定了哪些目标计划；周报里学/写了啥、提示词或设计文档怎么写、手册纪要、报销请假等制度、内部台账表格；以及"我们公司/部门/项目的 X""内部文档里有没有 X""查下知识库里的 X"。**关键区分（避免和邻近技能抢）：用户给的是"待回答的问题"、没给文档链接或 token → 走本技能（先帮他找到含答案的文档）；"打开/读/改/删某个指定文档（带 URL 或 token）"→ 走 lark-doc；"管理知识库空间/节点结构"→ 走 lark-wiki。**宁可多触发也别漏——内部专属信息答错或编造的代价远大于多查一次。不触发：通用百科 / 时事 / 公开技术常识（走联网搜索）、纯闲聊。

- Skill: `zju-real/feishu-kb-search` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add zju-real/feishu-kb-search`
- Raw SKILL.md: https://api.skillmd.com/api/skills/zju-real/feishu-kb-search/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: ZJU-REAL (https://skillmd.com/u/zju-real)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/zju-real/feishu-kb-search

---


# 飞书知识库检索

实时检索飞书（Lark）知识库（Wiki）回答问题。**不建本地索引、不做向量化**——每次直接查飞书，所以永远是最新内容。

底层全靠沙箱里的 `lark-cli`。飞书知识空间是**用户资源**，所以所有 `lark-cli` 调用都必须带 `--as user`（bot 身份看不到用户的知识空间）。

## 何时使用（触发判断）

很多部署里，飞书知识库就是这个智能体**唯一**的知识库（内置库为空），所以"用户是不是在查知识库"要判断得宽、判得快。一个可靠的启发式：

> **问题问的是不是"组织内部专属、且模型无法从通用训练或联网搜索得知"的事实？** 是 → 用本技能。

- ✅ 该触发：内部制度（报销/请假标准）、内部流程与配置（服务器怎么连、项目怎么部署）、项目进展、团队周报/手册/纪要、内部台账表格、"我们公司/部门/项目的 X"、以及直接说"查知识库""内部文档里有没有 X"——**无论有没有提"飞书"二字**。
- ❌ 不该触发：通用百科 / 时事 / 公开常识（走联网搜索）、对方明确要操作（新建/改/删）飞书文档（走 lark-doc 等）、纯闲聊。

判断不准时**倾向于触发**：内部问题答错或凭空编造的代价，远大于多检索一次。检索后若确实没有，如实说"没找到"即可（见第 4 步）。

## 核心思路：把知识库目录当索引来导航

先理解原理，后面的步骤才不是死记硬背。

这套检索仿照 **LLM Wiki（Karpathy）模式**：不靠 embedding 向量相似度去召回，而是把知识库的**目录（节点树：每篇文档的标题 + 层级）**当成一份"索引"，**由你（模型）读这份索引、用推理判断哪些文档跟问题相关，然后直接去读那几篇正文作答**。对几十到一两百篇规模的知识库，目录 + 上下文窗口足够你做出准确的相关性判断，不需要任何向量库基础设施。

这么做有两个好处：判断相关性的是你的语义理解（而不是关键词是否字面命中），所以"问法和文档用词不一致"也能判断对；同时零基础设施、永远最新。

飞书原生搜索（`drive +search`）是**关键词匹配**，作为**兜底补充**：当目录只有标题、信息不足以判断某文档是否相关时，用关键词搜正文来补召回。它不是主力。

## 工作流程

### 第 0 步：选定知识空间（首次必做，会话内记住）

```bash
lark-cli wiki spaces list --as user --format json
```

- 把每个空间的 `name` / `space_id` /（如有）`description` 列给用户，让用户选一个或多个。
- 列表为空或报权限错 → 多半是用户**尚未授权**或应用通讯录可见性不足，**如实告知用户去完成飞书授权**，不要自己瞎猜 `space_id`，也不要降级到 bot 身份。
- 选定后把 `space_id` 记住，本轮会话后续提问直接复用，不要每次都让用户重选。用户说"换个知识库""换库"时才重新走本步。

### 第 1 步：拉取索引（知识库目录 / 节点树）

把选定空间的节点树拉出来——这就是导航用的"索引地图"。**只取标题与层级，不拉正文**，很便宜：

```bash
lark-cli wiki nodes list --space-id <space_id> --as user --format json
```

节点分层。对 `has_child=true` 的节点递归展开：`nodes list --space-id <space_id> --parent-node-token <node_token>`。**注意递归用的是 `node_token`，不是 `obj_token`**（`obj_token` 是用来读正文的，传给 `--parent-node-token` 会失败）。整理成一份带层级缩进的目录，每个节点同时记下 `title` / `node_token` / `obj_token` / `obj_type` / `has_child`，便于你通读和后续下钻。

**保留所有类型的节点**（`docx` / `sheet` / `bitable` / `board` 画板 …），不要在索引阶段就丢掉非 docx——表格、多维表格里常装着项目进展、配置清单等关键信息。不同类型在第 3 步用不同方式读取（见该步的"按类型读取"表）。

### 第 2 步：读索引，导航选文档（核心）

通读第 1 步的目录，结合用户问题，**用推理选出最可能含答案的文档**（3-8 篇）。判断依据是标题语义 + 层级位置（比如"报销"问题优先看"财务制度"分章下的文档）。

如果**仅凭标题难以判断**（标题太泛、或问题涉及正文细节），补一步关键词搜索兜底，把命中的文档并入候选：

```bash
lark-cli drive +search --query "<关键词>" --space-ids <space_id> --doc-types docx,sheet,bitable --as user --format json
```

（关键词可对问题做同义/术语扩展，并可用飞书高级语法 `intitle:`、`"短语"`、`A OR B`、`A -B`。`--doc-types` 视需要纳入 sheet/bitable。）

### 第 3 步：读取候选内容（按类型路由）

候选节点是什么 `obj_type`，就用对应方式读：

| obj_type | 读取方式 |
|---|---|
| `docx` | `lark-cli docs +fetch --doc <obj_token> --doc-format markdown --as user`（正文 Markdown） |
| `sheet` | 用 lark-sheets 能力读：`lark-cli sheets ...` 读取工作表数据 / 在表中查找内容 |
| `bitable` | 用 lark-base 能力读：`lark-cli base ...` 搜索 / 读取多维表格记录 |
| `board`（画板） | 用 lark-whiteboard 能力导出节点结构 / 预览图；画板是视觉内容，文本召回有限（同图片型文档，见边界） |

具体子命令的参数以各 lark 技能（lark-sheets / lark-base / lark-whiteboard）为准，不确定时先查对应技能的用法，不要硬猜 flag。

**docx 正文**在返回 JSON 的 `data.document.content`。正文不长可直接读；多篇或较长时落到沙箱文件（如 `/workspace/.feishu_kb/doc_<obj_token>.md`）再通读。`--doc` 传 token、`--doc-format markdown` 指定内容格式（别把 token 当位置参数，`--format` 是输出封装格式不是内容格式）。

**省 token（可选）**：长文档可先用 `--scope outline` 拉标题大纲定位，再用 `--scope keyword --keyword "<词>"` 只取命中段落，不必整篇拉。

（fetch 语法、token 用法、父空壳下钻等易错点，见文末"避坑清单"。）

### 第 4 步：作答 + 末尾附「相关文件」

基于读到的正文作答。正文里关键结论可顺带点出处；但**无论如何，回答的最下方必须有一个固定的「相关文件」清单**——把本次检索用到的、与回答相关的飞书文档逐条列出（标题 + 可点击链接），方便用户点回飞书核对原文。这是本技能回答的标准收尾。

固定格式（正文之后）：

```
（……回答正文……）

---
**相关文件**
- [文档标题1](飞书链接1)
- [文档标题2](飞书链接2)
```

- **只列真正用到/相关的文档**，没参考到的候选不要放；多篇时按相关度排序。
- **链接从哪来**：优先用 `drive +search` 结果里的 `url` 字段；纯靠目录导航命中、手头没有 url 的，用飞书 wiki 链接格式 `https://<本知识库域名>/wiki/<node_token>`（域名沿用搜索结果或其它已知文档链接里的）。
- 内容来自截图 / 画板等读不全的文档时，仍把它列进「相关文件」并提示用户点链接看原图。

**可迭代回路**：读完发现选错文档或信息不足，回到第 2 步重选（或调整关键词再搜），不要硬用不相关内容凑答案。

如果目录导航 + 关键词兜底都找不到相关内容，**如实告诉用户"在该知识库里没检索到相关文档"**并说明可能原因（库选错 / 确实没有 / 问法与文档差异大可换说法再试），不要编造——这种情况自然没有「相关文件」清单。

## 避坑清单（实测验证，照做省返工）

下面几条是实跑 lark-cli 踩过、验证过的非显而易见点。命令的完整参数仍以各 lark 技能为准，但这几处最容易栽跟头：

- **读正文用 `--doc` 传 token**：`docs +fetch --doc <obj_token> --doc-format markdown --as user`。别把 token 当位置参数（会报 "positional arguments not supported"）；`--format` 是输出封装格式（json/pretty），`--doc-format` 才是内容格式（markdown）。正文落在返回 JSON 的 `data.document.content`。
- **递归子节点用 `node_token`，不是 `obj_token`**：`nodes list --parent-node-token <node_token>`。`obj_token` 是读正文用的，传给 `--parent-node-token` 会失败。所以第 1 步拉目录时，两个 token 都要记下。
- **父节点常是空壳**：`has_child=true` 的节点往往只有标题、正文寥寥几字（它是分类目录，真内容在子节点）。fetch 回来正文极短**不等于没内容**——下钻读它的子文档，别急着放弃。
- **多维表格用 `--base-token`，不是 `--app-token`**：先 `base +table-list --base-token <obj_token>` 取 `data.tables[].id`，再 `base +record-list --base-token <obj_token> --table-id <id>` 读记录。
- **全程带 `--as user`**：知识空间是用户资源，漏了会以 bot 身份跑、看不到用户的库（返回空或报权限）。

## 关键边界（如实告知用户）

- **规模上限**：目录导航适合几十到一两百篇规模的知识库。文档数特别多（目录本身就超出上下文）时，先用 `drive +search` 把范围缩小再导航；超大库（上千文档、跨库）下本方案会吃力，那时才需要考虑建索引的方案。
- **标题质量决定导航效果**：标题起得清晰，导航就准；标题很泛（如全是"XX年总结"）时更依赖第 2 步的关键词兜底。
- **图片型文档答不全**：很多飞书文档正文其实是截图（操作步骤、配置项都在图里），Markdown 导出只拿得到图片占位符、拿不到图里的文字。这种文档你能导航命中，但只能基于文档里的纯文本作答，截图内容看不到——**遇到时要如实告诉用户"该文档关键内容在截图中，建议点链接查看原图"**，不要假装读到了。
- **画板（board）文本召回有限**：画板是视觉内容（架构图/流程图），导出能拿到节点文字但拿不全图意，命中后要如实说明"画板内容以图形为主，建议点链接查看"。电子表格 / 多维表格则可正常读取作答。
- **权限/授权**：未完成飞书用户授权时第 0 步就会失败，应引导用户先授权。

## Inputs

- 用户的自然语言问题（关于飞书知识库 / 公司内部文档的内容）。
- （可选）用户指定的知识空间；未指定则走第 0 步让用户选。

## Outputs

- 回答正文 + **末尾固定的「相关文件」清单**：把本次用到的飞书文档以 `- [标题](链接)` 列在最下方（见第 4 步格式）。
- 检索不到时：明确的"未找到"说明 + 可能原因 + 调整建议（此时无「相关文件」清单）。

