切换日光/暗黑模式
103. 技能后端、缓存与读取接口
学习目标
这一节开始为 Vibe 系统补齐技能管理的后端能力,让 AI 能先看到技能简介,再按需读取技能详情。
学完后,你应该能理解:
- 技能为什么要拆成简介和详情;
- 为什么每轮对话都要把技能简介放进系统提示词;
- 技能详情为什么要通过工具按需读取;
- 技能表如何建模;
- Redis 缓存为什么适合保存技能提示词;
- 新增、更新、删除技能后为什么要刷新缓存。
技能的作用
技能不是普通文档。
它的作用是约束 AI 按项目规则做事。
例如系统里有几类任务:
- 编辑模块配置;
- 编辑前端代码;
- 编辑后端接口;
- 生成建表语句;
- 覆盖默认接口;
- 调用通用表格组件。
每类任务都有自己的规范。AI 只有先读到这些规范,才知道应该按什么格式输出代码。
这和本地 AGENTS.md、CLAUDE.md 或 Codex 技能文件的思路类似:模型不是凭空知道项目约定,而是通过上下文读取规则。
简介和详情分开
技能表里主要保存两个字段:
summary:技能简介;detail:技能详情。
简介会放进系统提示词,让 AI 知道“有哪些技能可以用”。
详情不会每次都全部塞进上下文,而是通过工具按需读取。
这样做有两个好处:
- 系统提示词不会无限膨胀;
- AI 可以根据当前任务选择真正需要的技能。
如果每次都把所有技能详情全部发给模型,随着技能越来越多,上下文会变长,成本和出错率都会上升。
技能表建模
课程里为技能建立了独立模型。
它和前面用户、模块等模型类似,都继承基础模型,并声明真实数据表名。
技能表不只按 id 使用。
很多时候系统真正拿到的是技能简介 summary,所以缓存和查询更适合用 summary 作为 key。
这和用户缓存用 username 类似:中间件解析 token 时拿到的是用户名,而不是数据库主键。
缓存单条技能
技能详情会被频繁读取。
例如 AI 判断当前任务需要“前端页面开发规范”,就会调用读取技能详情的工具。这个动作可能在多轮对话中重复出现。
所以单条技能详情适合放进 Redis。
读取流程可以理解成:
- 先按技能简介从 Redis 查;
- 查不到再访问数据库;
- 数据库查到后写回 Redis;
- 下次直接从缓存返回。
这样可以减少数据库访问,也能让工具调用更快。
缓存全部技能简介
除了单条技能详情,系统还需要频繁读取“所有技能简介”。
因为每轮大模型对话开始时,系统提示词都要告诉模型:
你可以使用哪些技能。
所以全部技能简介也需要缓存。
课程里为它单独设计缓存 key,并通过 Redis 保存拼接后的简介文本。
如果缓存为空,就从数据库读取所有技能,把每条 summary 用换行拼起来,再写回缓存。
缓存击穿和分布式锁
当缓存失效时,可能有多个请求同时发现缓存为空。
如果它们一起查数据库、一起写缓存,就会造成缓存击穿。
课程里继续使用分布式锁来处理:
- 先查一次缓存;
- 如果没有缓存,尝试拿锁;
- 拿到锁后再查一次缓存;
- 仍然没有,再访问数据库;
- 写入缓存后释放锁。
这和前面用户缓存、模块缓存的思路一致。
对 JS 开发者来说,可以把它类比成“多个异步请求同时初始化同一份全局数据”时,需要避免重复初始化。
技能接口
后端提供两类接口:
- 查询全部技能简介;
- 按技能简介查询单条技能详情。
前端工具调用时,先把全部简介放进提示词。
当 AI 需要某个技能详情时,再调用工具读取对应 detail。
这样技能系统就从“数据库里的文档”变成了“AI 可主动读取的开发规范”。
修改技能后的缓存刷新
技能是可以编辑的。
当新增、更新或删除技能时,缓存必须刷新。
否则数据库里已经改了,AI 仍然读到旧规则。
课程里通过拦截器处理这些变化:
- 更新单条技能缓存;
- 刷新全部技能简介缓存;
- 删除技能时清掉对应缓存;
- 多个刷新任务可以并发执行。
这让技能管理页面和 AI 对话上下文保持一致。
阶段重点
这一节的核心不是 Redis 语法。
核心是理解技能系统的架构:
简介负责“让 AI 发现能力”,详情负责“让 AI 学会规则”,缓存负责“让读取足够快”。
有了这套后端能力,后面前端聊天组件才能把技能真正接入工具调用流程。