别烧钱了, 大模型语义缓存产品来了
本期播客
别烧钱了, 你和大模型直接需要一层语义缓存, 它来了
别再傻傻匹配字符串了!PostgreSQL语义缓存一招让LLM调用成本狂降70%
我的第一反应是, 信你个鬼, 不过看完下面的介绍, 我知道了, 确实非常适合企业内使用, 当企业内、客服系统冲刺着大量语义相似的提问时. 效果很好.
说白了就是向量数据库的另一种应用, 在讲上下文发给大模型之前先搜一下有没有语义极度相似的, 也许可以给你省一笔钱.
本质上和确定性搜索场景的缓存用法类似, 例如redis , ...
https://www.pgedge.com/blog/semantic-caching-in-postgresql-a-hands-on-guide-to-pg_semantic_cache
你的AI聊天机器人,每天可能被问同样的问题几十遍,只是换了个说法。它却傻乎乎地每次都去调用昂贵的大模型,既烧钱又慢得像蜗牛。这就是传统缓存的死穴——只认死理,非得字一模一样才算命中。今天教你用PostgreSQL官方扩展pg_semantic_cache,让数据库“听懂人话”,轻松实现语义缓存,把LLM调用成本砍掉一大半。
一、传统缓存为啥不顶用?
假如用户问:
“我们第四季度收入是多少?” “给我上个季度的销售数字” “2024年Q4营收数据”
在传统缓存眼里,这是三个完全不同的字符串,于是三次都去问大模型。但实际上它们问的是同一件事。研究显示,AI应用里40%到70%的查询都是这种“语义重复”——换汤不换药。结果就是:API调用次数翻倍,延迟翻倍,云账单也翻倍。
二、语义缓存怎么破?
语义缓存不看你用的词,而是看你表达的意思。它会把问题和答案转换成“向量”(可以想象成一组坐标),然后通过计算向量之间的距离来判断两个问题是不是“一伙的”。距离越近,意思越像。超过设定的相似度阈值(比如95%),就直接返回缓存的结果,根本不用再去麻烦大模型。
pg_semantic_cache就是PostgreSQL官方推出的一个扩展,把这种能力直接集成到数据库里。下面我们就动手搭一个环境,亲眼看看它是怎么工作的。
三、动手实践:30分钟跑通语义缓存
1. 用Docker一键拉起环境
创建一个 Dockerfile,内容如下(基于Rocky Linux 9,安装pgEdge Enterprise Postgres 17,自带向量插件pgvector):
FROM rockylinux:9
RUN dnf install -y epel-release && \
dnf config-manager --set-enabled crb && \
dnf install -y gcc make git redhat-rpm-config
RUN dnf install -y https://dnf.pgedge.com/reporpm/pgedge-release-latest.noarch.rpm && \
dnf install -y pgedge-enterprise-postgres_17 pgedge-pgvector_17 pgedge-postgresql17-devel
ENV PATH="/usr/pgsql-17/bin:${PATH}"
ENV PG_CONFIG="/usr/pgsql-17/bin/pg_config"
RUN git clone https://github.com/pgedge/pg_semantic_cache.git /tmp/pg_semantic_cache && \
cd /tmp/pg_semantic_cache && \
make PG_CONFIG=/usr/pgsql-17/bin/pg_config && \
make PG_CONFIG=/usr/pgsql-17/bin/pg_config install && \
rm -rf /tmp/pg_semantic_cache
USER postgres
RUN /usr/pgsql-17/bin/initdb -D /var/lib/pgsql/17/data
RUNecho"host all all 0.0.0.0/0 trust" >> /var/lib/pgsql/17/data/pg_hba.conf && \
echo "listen_addresses = '*'" >> /var/lib/pgsql/17/data/postgresql.conf
EXPOSE5432
CMD ["/usr/pgsql-17/bin/postgres", "-D", "/var/lib/pgsql/17/data"]
构建并运行容器:
docker build -t pg-semantic-cache .
docker run -d --name semcache -p 5432:5432 pg-semantic-cache
稍等几秒,等数据库启动后,进入容器连接PostgreSQL:
docker exec -it semcache psql -U postgres
2. 创建数据库并启用扩展
CREATEDATABASE semcache_demo;
\c semcache_demo
CREATE EXTENSION IFNOTEXISTS vector; -- pgvector(自带)
CREATE EXTENSION IFNOTEXISTS pg_semantic_cache; -- 语义缓存扩展
检查一下缓存是否为空:
SELECT * FROM semantic_cache.cache_stats();
应该看到 total_entries = 0,一切就绪。
3. 配置向量维度(演示用8维,方便理解)
SELECT semantic_cache.set_vector_dimension(8);
SELECT semantic_cache.rebuild_index(); -- 应用更改,会清空缓存
4. 模拟存入三条问答(问题 + 向量 + 答案)
假设三个用户分别问了关于PostgreSQL的问题,大模型给出了答案,我们把结果存进缓存:
-- 事务问题
SELECT semantic_cache.cache_query(
'How does PostgreSQL handle transactions?',
'[0.12,0.85,0.44,0.31,0.67,0.22,0.91,0.15]',
'{"answer": "PostgreSQL implements MVCC for transaction management..."}'::jsonb,
7200,
ARRAY['postgres', 'concepts']
);
-- 索引问题
SELECT semantic_cache.cache_query(
'What types of indexes does PostgreSQL support?',
'[0.33,0.18,0.72,0.55,0.11,0.88,0.29,0.64]',
'{"answer": "PostgreSQL supports B-tree, Hash, GiST, GIN, BRIN..."}'::jsonb,
7200,
ARRAY['postgres', 'indexing']
);
-- 复制问题
SELECT semantic_cache.cache_query(
'How do I set up replication in PostgreSQL?',
'[0.78,0.42,0.15,0.93,0.37,0.56,0.08,0.71]',
'{"answer": "PostgreSQL supports streaming replication and logical replication..."}'::jsonb,
7200,
ARRAY['postgres', 'replication']
);
现在缓存里有3条记录了。
5. 模拟一个新用户提问:“Explain ACID and transactions in Postgres”
这个问题跟第一条(事务)语义非常接近,假设嵌入模型给出的向量是 [0.13,0.83,0.46,0.29,0.65,0.24,0.89,0.17](和第一条的向量非常接近)。我们查询缓存:
SELECT * FROM semantic_cache.get_cached_result(
'[0.13,0.83,0.46,0.29,0.65,0.24,0.89,0.17]',
0.95-- 相似度阈值95%
);
结果:found = t,相似度0.9991,直接返回了第一条的答案!整个过程毫秒级,根本没去调用大模型。
6. 再试一个完全不相关的问题
向量是 [0.95,0.05,0.10,0.02,0.88,0.03,0.50,0.40]:
SELECT * FROM semantic_cache.get_cached_result(
'[0.95,0.05,0.10,0.02,0.88,0.03,0.50,0.40]',
0.95
);
结果:found = f,相似度只有0.6821,没命中。
7. 查看缓存统计
SELECT * FROM semantic_cache.cache_stats();
你会看到 total_entries 还是3(因为没命中那次虽然没返回结果,但默认不自动插入新条目,实际应用中需要应用自己决定是否插入新结果),hits=1, misses=1,命中率50%。
四、原理一句话:向量相似度计算
每个问题和结果存成一个向量(由嵌入模型生成)。 新查询来了,用它的向量跟缓存里所有向量比一遍,找余弦距离最近的。 如果最近的距离超过阈值(比如0.95,意味着95%相似),就返回对应的缓存结果。 否则就是没命中,应用再去调LLM,得到新结果后再存进缓存。
相似度分数大致可以这样理解:
0.98以上:几乎一样的意思(比如“重置密码”和“密码重置”) 0.93~0.97:同一意图,表达不同(“Q4营收” vs “上个季度销售额”) 0.85~0.92:相关但不完全相同 0.85以下:基本不相关
五、真金白银的效果:命中率从20%飙到80%
传统缓存(精确匹配)在AI应用里命中率通常只有15%~25%。而语义缓存能把命中率提高到60%~80%!这意味着:
65%~75%的LLM调用被省掉了,API费用同比例下降。 缓存命中时,响应时间从大模型的几百毫秒甚至几秒,降到2~3毫秒,用户体验飞升。 对于RAG(检索增强生成)应用,节省的不仅是LLM调用,还跳过了向量检索和生成过程,成本进一步降低。
生成一次嵌入的成本极低(约0.01~0.03。省掉LLM调用,就是省掉了大头。
六、接下来还能玩什么?
缓存不是一存了之。下篇我们会深入聊:
如何用标签(tags)组织缓存条目 缓存失效策略(比如按时间、按标签) 淘汰策略(LRU、TTL等) 成本跟踪和调优 针对百万级缓存使用HNSW索引 完整的Python集成示例
pg_semantic_cache是开源的,遵循PostgreSQL许可证。想自己动手的,直接去GitHub拉代码:
🔗 github.com/pgedge/pg_semantic_cache
一句话总结:让你的数据库学会“意会”,别再让LLM为同义反复买单。