| name | feishu-kb-search |
| display_name | 飞书知识库检索 |
| description | 检索飞书(Lark)知识库 / 企业内部 Wiki 来回答问题,实时查、永远最新;这通常是本智能体唯一的知识库,判得宽、判得快。**判断要点:用户抛出一个待回答的问题,且默认你了解他/她公司·部门·团队·项目·服务器的具体情况,而答案不在通用常识或联网搜索里、只可能写在他们自家内部文档——就用本技能去飞书知识库检索作答。**哪怕只字未提"飞书/知识库"也要触发,例如:某服务器怎么连/账号是什么、项目怎么部署、镜像怎么构建、环境怎么配;某项目进展到哪步、团队今年定了哪些目标计划;周报里学/写了啥、提示词或设计文档怎么写、手册纪要、报销请假等制度、内部台账表格;以及"我们公司/部门/项目的 X""内部文档里有没有 X""查下知识库里的 X"。**关键区分(避免和邻近技能抢):用户给的是"待回答的问题"、没给文档链接或 token → 走本技能(先帮他找到含答案的文档);"打开/读/改/删某个指定文档(带 URL 或 token)"→ 走 lark-doc;"管理知识库空间/节点结构"→ 走 lark-wiki。**宁可多触发也别漏——内部专属信息答错或编造的代价远大于多查一次。不触发:通用百科 / 时事 / 公开技术常识(走联网搜索)、纯闲聊。 |
| version | 1.0.0 |
| tags | feishu,lark,knowledge-base,wiki,retrieval |
| allowed_tools | bash |
飞书知识库检索
实时检索飞书(Lark)知识库(Wiki)回答问题。不建本地索引、不做向量化——每次直接查飞书,所以永远是最新内容。
底层全靠沙箱里的 lark-cli。飞书知识空间是用户资源,所以所有 lark-cli 调用都必须带 --as user(bot 身份看不到用户的知识空间)。
何时使用(触发判断)
很多部署里,飞书知识库就是这个智能体唯一的知识库(内置库为空),所以"用户是不是在查知识库"要判断得宽、判得快。一个可靠的启发式:
问题问的是不是"组织内部专属、且模型无法从通用训练或联网搜索得知"的事实? 是 → 用本技能。
- ✅ 该触发:内部制度(报销/请假标准)、内部流程与配置(服务器怎么连、项目怎么部署)、项目进展、团队周报/手册/纪要、内部台账表格、"我们公司/部门/项目的 X"、以及直接说"查知识库""内部文档里有没有 X"——无论有没有提"飞书"二字。
- ❌ 不该触发:通用百科 / 时事 / 公开常识(走联网搜索)、对方明确要操作(新建/改/删)飞书文档(走 lark-doc 等)、纯闲聊。
判断不准时倾向于触发:内部问题答错或凭空编造的代价,远大于多检索一次。检索后若确实没有,如实说"没找到"即可(见第 4 步)。
核心思路:把知识库目录当索引来导航
先理解原理,后面的步骤才不是死记硬背。
这套检索仿照 LLM Wiki(Karpathy)模式:不靠 embedding 向量相似度去召回,而是把知识库的**目录(节点树:每篇文档的标题 + 层级)**当成一份"索引",由你(模型)读这份索引、用推理判断哪些文档跟问题相关,然后直接去读那几篇正文作答。对几十到一两百篇规模的知识库,目录 + 上下文窗口足够你做出准确的相关性判断,不需要任何向量库基础设施。
这么做有两个好处:判断相关性的是你的语义理解(而不是关键词是否字面命中),所以"问法和文档用词不一致"也能判断对;同时零基础设施、永远最新。
飞书原生搜索(drive +search)是关键词匹配,作为兜底补充:当目录只有标题、信息不足以判断某文档是否相关时,用关键词搜正文来补召回。它不是主力。
工作流程
第 0 步:选定知识空间(首次必做,会话内记住)
lark-cli wiki spaces list --as user --format json
- 把每个空间的
name / space_id /(如有)description 列给用户,让用户选一个或多个。
- 列表为空或报权限错 → 多半是用户尚未授权或应用通讯录可见性不足,如实告知用户去完成飞书授权,不要自己瞎猜
space_id,也不要降级到 bot 身份。
- 选定后把
space_id 记住,本轮会话后续提问直接复用,不要每次都让用户重选。用户说"换个知识库""换库"时才重新走本步。
第 1 步:拉取索引(知识库目录 / 节点树)
把选定空间的节点树拉出来——这就是导航用的"索引地图"。只取标题与层级,不拉正文,很便宜:
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 篇)。判断依据是标题语义 + 层级位置(比如"报销"问题优先看"财务制度"分章下的文档)。
如果仅凭标题难以判断(标题太泛、或问题涉及正文细节),补一步关键词搜索兜底,把命中的文档并入候选:
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 步格式)。
- 检索不到时:明确的"未找到"说明 + 可能原因 + 调整建议(此时无「相关文件」清单)。