给 AI Agent 装个"项目知识大脑":ProjQA 技能开发笔记

文档散落各处、排障靠口口相传、新人问完老人再问——这些场景每个技术团队都不陌生。本文记录了 ProjQA 技能从零到开源的完整开发过程:一个 Python 脚本 + LLM,不部署任何后端,不引入向量模型,让 AI Agent 直接基于本地项目文档回答运维问题。

一、谁都遇到过的困境

如果你在一个有几十个微服务的技术团队待过,以下场景大概率不陌生:

  • 某个服务线上报错,翻遍 wiki、共享盘、个人电脑,找不到对应的排障文档
  • 上周刚解决过同样的问题,但当时是群里口述处理的,没人记下来
  • 某服务的部署文档存在某个离职同事的电脑里,他走了,知识也走了
  • 新人入职,同样的部署流程、同样的注意事项,每来一波人就要讲一遍
  • 知道有篇文档讲过这个问题的解决方案,但就是想不起来在哪个目录、叫什么名字

文档不是没有,而是散落在各处、没有统一检索入口、无法快速抵达

很多人第一反应是上 RAG:搞个 Embedding 模型 + 向量数据库 + 检索后端。但真动手会发现——国内网络拉模型镜像慢、依赖安装各种报错、向量库还要单独部署维护。更关键的是,团队的文档量可能也就几十到上百个文件,用整套向量检索方案杀鸡用牛刀了。

于是问题变成了:能不能让 AI Agent 直接读本地文档回答问题,不部署任何后端,不引入向量模型?

这就是 ProjQA 的起点。

二、核心设计原则:三个"零"

动手之前,先定下三条原则,它们贯穿了整个开发过程:

原则一:零后端

不部署任何服务。不需要数据库,不需要 API 网关。一个 Python 脚本 + LLM 自身能力,就够了。

这不是偏执,而是务实。我们要的不是一个知识库"系统",而是一个即插即用的"技能"——把它丢给 Agent,它就能干活。不需要运维同学帮忙部署,不需要申请服务器资源,不需要担心某天服务挂了知识库就不可用。

原则二:零向量模型

不用 Embedding,不用向量数据库,不用相似度计算。

传统 RAG 的检索链路是:文档 → 切块 → Embedding → 向量存储 → Query Embedding → 向量相似度 → 取 Top-K。这条链路需要模型、需要数据库、需要 API 调用。

替代方案是:文件系统索引 + LLM 语义匹配。脚本扫描文件生成索引(关键词、简述、提问摘要由 LLM 补充),检索时 LLM 直接读索引匹配候选文档,再读文档内容回答。

你可能会问:在上下文里塞关键词做匹配,精度能比向量检索?

对于中小规模文档库(百级以下),LLM 的语义理解能力远超向量相似度。向量检索只能算"词面相近",而 LLM 能理解"订单服务"和 order-service 是同一个东西(配合别名映射),能理解"起不来"等于"启动失败"。这是质的区别。

原则三:智能体即 LLM

所有需要"理解"和"判断"的环节都由 LLM 完成,脚本只做确定性操作。

环节执行者为什么
文件扫描与增量比对Python 脚本确定性操作,比 mtime/size,不需要理解力
关键词/简述/提问摘要生成LLM需要理解文档内容才能生成
别名映射LLM需要理解用户意图和映射关系
候选文档匹配LLM需要语义理解能力
回答生成LLM核心价值所在

脚本不做任何"智能"判断,只管文件系统的脏活累活。LLM 不碰文件系统细节,只管理解、匹配、回答。分工清晰,各自做最擅长的事。

三、第一版:跑通最小闭环

第一版只做了三件事:

1. 一个目录结构——按项目分类组织文档:

projqa-docs/
├── 电商平台/
│   ├── FAQ/              # 常见问题与解决方案
│   ├── 运维手册/          # 部署、运维、排障流程
│   ├── 服务资料/          # 单个服务的信息档案
│   ├── 架构设计/          # 系统架构、技术方案
│   └── 会议纪要/          # 决策记录
├── _index.md             # 索引文件(脚本自动维护)
└── _aliases.md           # 别名映射表(人工维护)

2. 一个扫描脚本scan_projqa.py)——递归扫描文档目录,比对文件 mtime/size 做增量更新,生成索引文件。索引条目格式:

- [电商平台/服务资料/服务清单.md] | 关键词: 订单, 支付, 库存, K8S, 副本数 | 简述: 全部微服务信息档案 | 提问摘要: 有哪些服务? 某服务几个副本? | mtime: 2026-08-27 10:00:00 | size: 8192

脚本只负责结构维护和增量检测,关键词、简述、提问摘要这些语义字段留空,交给 LLM 在入库时补充。

3. 一份技能指令SKILL.md)——告诉 Agent 怎么用这个知识库:先查别名映射,再扫索引匹配候选,读取文档,生成带来源标注的回答。

第一版跑通了基本闭环:放文档 → 跑脚本 → LLM 补充语义信息 → 用户提问 → Agent 检索回答。但实际用了几天就发现一堆问题。

四、第二轮迭代:从"能用"到"好用"

问题 1:用户说的是"订单服务",索引里写的是 order-service

用户提问不会用标准服务名,他们说"订单服务"“库存”"支付网关"这些业务称呼。直接拿这些词去匹配索引,命中率很低。

以电商中台为例,团队内部讨论用中文名,代码和配置里是英文服务名:

订单服务 -> order-service
库存中心 -> inventory-center
支付网关 -> payment-gateway
商品中心 -> product-center
用户中台 -> user-platform

解法:别名映射表(_aliases.md

建一个人工维护的映射表,检索前必查。这个表格随用随补,发现新的口语称呼就加一条,渐渐的命中率越来越高。

问题 2:文档多了之后,关键词匹配不够用

文档从十几个涨到几十个后,单纯靠关键词匹配开始出现"候选太多、不确定读哪个"的尴尬。

比如有人问"支付服务超时怎么排查",索引里关键词包含"支付"的文档可能有四五篇——支付接入文档、支付网关部署手册、支付超时排障记录、支付对账说明。关键词都能命中,但只有第三篇是真正相关的。

解法:提问摘要字段

入库时除了关键词和简述,再生成 2-3 个"提问式描述":

提问摘要: 支付超时怎么排查? 支付网关连接池怎么调? §排障步骤: 超时链路分析

这种格式直接描述"这篇文档能回答什么问题",检索时 LLM 拿用户提问去匹配这些提问摘要,命中即高度相关。效果立竿见影,候选文档的精准度大幅提升。

问题 3:大文档全文读入太慢

有些运维手册几百行,Agent 一次性全文读取既慢又浪费上下文窗口。

解法:大文档分章节索引

入库时对大文档追加章节定位信息:

提问摘要: §部署步骤: 怎么部署? §环境变量: 需要配置什么? §常见故障: 启动失败/超时/内存溢出怎么处理?

检索时 LLM 先通过提问摘要定位到具体章节,再只读该章节的行号范围。500 行的文档可能只需要读 30 行。

问题 4:重复入库

同一个人写了个新文档放进来,和已有文档内容高度重叠,文件名略有不同。

比如已有 电商平台/FAQ/支付超时.md,又来一个 电商平台/FAQ/支付网关超时排查.md——内容差不多,只是标题不同。

解法:相似检测

扫描脚本增加 --check-similarity 参数,对新增文档与已有文档做文件名相似度比对,相似度 ≥60% 时提醒:

--- 相似文件提醒(可能重复)---
  ~[82%] 电商平台/FAQ/支付网关超时排查.md  <-->  电商平台/FAQ/支付超时.md

最终是否重复仍由 LLM 读内容判断,脚本只做辅助提醒。

问题 5:补录质量不可控

入库流程要求 LLM 补充关键词/简述/提问摘要,但实际操作中有时会遗漏——补了关键词忘了简述,或者提问摘要没写就提交了。索引里出现大量空字段,检索效果直线下滑。

解法:分级待补清单 + 闭环校验

扫描脚本输出分级清单:

--- 待补[P0] 关键词/简述为空: 2 个文件(必须完成)---
  !! 电商平台/FAQ/支付回调.md
  !! 电商平台/运维手册/灰度发布.md

--- 待补[P1] 提问摘要为空: 1 个文件(增强检索)---
  ?  电商平台/服务资料/商品中心.md

P0(关键词/简述为空)必须完成,P1(提问摘要为空)建议完成。补完后重新跑脚本,确认输出"待补清单: 无"才算入库完成。形成了「扫描 → 补录 → 再扫描验证」的闭环。

五、第三轮迭代:多项目组织与开源准备

多项目知识库

最初所有文档混在一个目录里。随着项目增多到两三个,跨项目误命中越来越频繁——搜"用户服务"本意是找中台的用户中心,结果命中了电商平台的用户模块。

于是改为按项目分类:

projqa-docs/
├── 电商平台/
│   ├── FAQ/
│   ├── 服务资料/
│   └── 运维手册/
├── 技术中台/
│   ├── 架构设计/
│   └── 会议纪要/
├── _index.md
└── _aliases.md

第一级是项目名,第二级是分类名。索引统一在一份 _index.md 中,但路径包含项目名前缀,天然隔离。这个改动几乎零成本,但检索准确率提升明显。

从私有到开源

确定开源后,做了三件事:

1. 移除所有平台专有内容

原始版本绑定在特定 Agent 平台上,引用了平台专有技能名。开源版全部改为通用描述——"使用平台的 Word 文档解析能力"而非指定具体技能名,让任何 Agent 平台都能适配。

2. 路径通用化

所有硬编码的绝对路径改为相对路径 ./projqa-docs,并保留环境变量 PROJQA_DOCS_ROOT 覆盖机制。clone 下来就能跑,不依赖特定目录结构。

3. 补齐开源基建

README、CHANGELOG、CONTRIBUTING、架构文档、快速上手教程、索引/别名模板——让新人拿到手就知道怎么用。

六、关键设计决策回顾

回头看,有几个决策对最终效果影响最大:

决策 1:索引是文件系统快照,不是语义存储

索引脚本只比对 mtime/size,不读文件内容。语义信息(关键词/简述/提问摘要)由 LLM 在入库时补充,脚本只负责把结构维护好。

好处是脚本极其轻量和确定——不怕出 bug,不怕性能问题,上千文件也秒级扫描完。坏处是初次入库需要 LLM 参与补充语义信息。但这个 trade-off 是值得的:脚本做的事情越少越可靠,智能判断交给 LLM 越灵活。

决策 2:不引入向量模型,坚持到开源

开发过程中这个决策被反复质疑。“要不要加个 Embedding 做兜底?”"文档多了要不要上向量检索?"最后的答案是:不要。一旦引入向量模型,零后端的设计原则就被打破了,技能的即插即用性也没了。对于百级以下的文档库,LLM 的语义匹配能力完全够用。

决策 3:按项目分类而非按类型分类

最初文档按类型组织(所有 FAQ 在一起、所有运维手册在一起)。改为按项目组织后,跨项目误命中问题自然消失了。改动成本几乎为零(只是多一层目录前缀),但收益很大。

七、最终形态

项目结构:

projqa-skill/
├── SKILL.md                        # 技能主文件(Agent 读取的核心指令)
├── references/
│   └── retrieval-guide.md          # 检索策略详细指南
├── scripts/
│   └── scan_projqa.py              # 索引扫描与增量维护脚本
├── docs/
│   ├── architecture.md             # 架构设计文档
│   └── quick-start.md              # 快速上手教程
├── examples/
│   ├── _index.example.md           # 索引文件模板
│   └── _aliases.example.md         # 别名映射表模板
├── README.md
├── .gitignore
├── CHANGELOG.md
└── CONTRIBUTING.md

核心工作流程:

用户提问
  → 查别名映射(_aliases.md):口语称呼 → 标准服务名
  → 扫描索引(_index.md):关键词/简述/提问摘要 → 候选文档
  → 读取候选文档:按格式选择解析方式
  → LLM 综合内容生成回答 + 来源标注

入库流程:

放文档到目录
  → 运行 scan_projqa.py --check-similarity
  → 根据待补清单补充关键词/简述/提问摘要
  → 再跑脚本确认"待补清单: 无"

八、写在最后

ProjQA 不复杂——一个 Python 脚本、一份技能指令、一份检索策略指南,三个文件就是全部核心。它的价值不在于技术多精妙,而在于找到了一个恰到好处的平衡点:

  • 比人肉翻文档快——几秒内定位到答案
  • 比传统 RAG 轻——零部署、零运维
  • 比口口相传可靠——答案有来源标注,可追溯

它适合的规模是百级以下的文档库,适合的场景是项目运维知识管理。如果你的团队也在被"信息散落、排障靠问人"困扰,ProjQA 可能就是那个最小够用的解。


Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐