gRPC结合FAISS构建AI助手语义缓存模块(一):设计

一、背景简介

原AI聊天助手项目中,每次提问(Prompt)都需要调用公有LLM API来获取大模型的回答(Answer),然而,有些时候用户会向聊天助手询问同样的问题,我们将KV存储集成到聊天助手当中,初步实现了一个Prompt对应一个Answer的缓存功能。

但是有时候,用户向聊天助手询问的问题并不是一字不差,同样的语义,由于prompt字面的不同,原先的缓存功能就失效,现在的问题是如何实现语义级别的缓存功能

二、组件依赖

2.1 高性能中间件 - 自研KV存储

Github - KVstore

支持命令

命令 语法 说明
SET SET 写入键值对,key 已存在则覆盖
GET GET 读取键值,不存在返回 $-1
DEL DEL 删除键,返回删除数量
EXISTS EXISTS 检查键是否存在,返回 0 / 1
MOD MOD 仅当键存在时更新值
SAVE SAVE 手动触发 RDB 快照保存
PING PING message 连通性探测,返回 PONG 或回显 message

2.2 高效向量搜索 - FAISS

语义级别的识别,首先想到的方案是结合FAISS来做,(Facebook AI Similarity Search),这是由 Meta(原 Facebook)开源的一个高效向量搜索库。

FAISS向量搜索具体的内部实现是一个比较复杂的问题,这里只粗浅介绍一下:

原始的prompt,比如"我饿了"、"我想吃饭",被模型编码成为高维向量:

复制代码
文本输入                    高维向量空间
"我饿了"    → 模型编码 → [0.12, -0.34, 0.56, ..., 0.78]  (768维)
"我想吃饭"  → 模型编码 → [0.11, -0.32, 0.55, ..., 0.79]  (768维)
                           ↑ 两个向量方向几乎相同 ↑

内存结构:

隐式ID 向量数据 (768个float32) 对应的文本
0 [0.0123, -0.0456, 0.0789, ...] "我饿了"
1 [0.0115, -0.0412, 0.0765, ...] "我想吃饭"
2 [-0.0891, 0.1234, -0.0056, ...] "今天天气不错"
  • FAISS 只存数字,不知道prompt的文本是什么
  • ID 自动生成(从0开始,每次调用add自增)
  • prompt文本存在KV存储里,用 ID 关联

检索时暴力遍历,通过余弦相似度衡量向量方向的相似性,给定阈值,判断是否命中。当然了,检索算法有内置的优化实现。

我们faiss模块中使用到的核心接口如下:

分类 接口 一句话作用
创建索引 IndexFlatIP 建一个用内积算相似度的索引
写入 add 把向量存进索引
检索 search 找最相似的 Top-K 个向量
保存 write_index 把内存索引存成文件
加载 read_index 从文件恢复索引到内存
取数量 ntotal 看索引里存了多少条
取维度 d 看向量是几维的

2.3 通信底座 - gRPC

gRPC(Google Remote Procedure Call)是由谷歌公司开发的远程调用框架。什么叫远程调用?

如下图所示,这是一个多语言多平台的系统,不同语言和平台之间的对象本不能直接相互调用,gRPC就是为了解决这个问题出现的:

通过Protobuf 协议(一种语言无关、平台无关且便于传输的序列化协议),server端对需要共享的对象进行序列化,接收端进行反序列化,并且client端通过stub封装从而实现直接调用 (无需关系底层实现),这篇博客介绍了你所需要的Protobuf相关内容

三、模块架构

Go后端作为gRPC的client,通过stub收发proto消息,由Python实现的faiss语义层为gRPCserver,他们之间的通信消息和服务由Proto文件给定,proto文件中定义三个接口函数:

伪代码 复制代码
GetCache(prompt)
PutCache(prompt)
DeleteCache(prompt)

prompt进faiss层被编码为相似度+ID,ID与KV中的answer绑定,faiss层通过GET ID、SET ID Answer等命令与KV存储交互。

整体模块架构总结如下:

复制代码
┌────────────────────────────────────────────────────────┐
│               业务客户端层 (Go Web 后端)               │
└───────────────────────────┬────────────────────────────┘
                            │ gRPC 通信 (50051)
┌───────────────────────────▼────────────────────────────┐
│ 1. 网关层 (main.py) - 流量拦截与服务生命周期管理        │
└───────────────────────────┬────────────────────────────┘
                            │ 本地方法调度
┌───────────────────────────▼────────────────────────────┐
│ 2. 核心算法层 (engine.py)                              │
│    ├── [模块 A] 语义编码 (SentenceTransformer)          │
│    ├── [模块 B] 几何正规化 ($L_2$ Normalization)       │
│    └── [模块 C] 容错自愈 (维度探测器)                   │
└───────────────────────────┬────────────────────────────┘
                            │ 双向读写
┌───────────────────────────▼────────────────────────────┐
│ 3. 存储与索引层 (持久化)                                │
│    ├── [模块 D] 内存阵列检索 (FAISS) ──> 负责"控门"   │
│    └── [模块 E] KV缓存 (自研KV)  ──> 负责"管账"   │
└────────────────────────────────────────────────────────┘
相关推荐
火云牌神4 分钟前
分层整洁架构:标准化工程目录结构,防范 AI 越界调用
人工智能·架构·ai编程·分层架构·vibecoding
新知图书13 分钟前
8.1 智能体的心跳执行模式:以定时器为核心(智能体工程)
人工智能·agent·ai agent·智能体
墨心@15 分钟前
阶段 4:事件总线
人工智能·语言模型·大语言模型·agent·codex·harness
AbrahamCS15 分钟前
从角色协同到可运行图:Graph Engineer 与多智能体编排
前端·人工智能·智能体
MacroZheng18 分钟前
几行代码给项目集成AI功能,Spring AI 2.0太香了!
java·人工智能·spring boot
zed_2320 分钟前
给接口加把锁:Bearer Token 鉴权(附冒烟验收)
人工智能
u01030552730 分钟前
昇腾Model Agent模型适配指南
人工智能
Neptune2331 分钟前
Agent死循环6小时:从“相信LLM判断”到“焊死硬件条件止
人工智能
用户5487754316033 分钟前
DeepSeek Harness 与 xAgent:两种 Agent Harness 架构路线怎么选
人工智能·deepseek
安逸sgr36 分钟前
卷积神经网络 CNN 是什么?为什么适合处理图像?
人工智能·ai·大模型·agent·智能体