avatar

一条在知识海洋的咸鱼

这个家伙很懒,啥也没有留下😋

  • 首页
  • Linux
  • OCJP
  • Java核心技术卷
  • J2EE相关标准
  • 深入理解Java虚拟机
  • NIO与SOcket编程技术指南
  • Java多线程编程核心技术
  • Redis开发与运维
  • Spring Cloud Alibaba 微服务原理与实践
  • DevOps
  • Docker
  • MySQL必知必会
  • AI自学路线
  • Spring Boot 编程思想(核心篇)
主页 21 Embedding 向量化
文章

21 Embedding 向量化

发表于 2026-06-14 更新于 2026-06- 15
作者 Administrator
78~101 分钟 阅读

向量入库:把 Embedding 稳定写入 PostgreSQL + pgvector

向量入库的核心不是简单执行一次 UPDATE,而是保证 chunk、向量、模型信息和文档状态一致,并且在失败时能够完整回滚、重新执行和排查问题。

[TOC]

1. 本节要解决什么

前面的流程已经得到每个 chunk 对应的 1024 维向量:

chunkId  
chunkIndex  
vector  
inputHash  
embedding metadata  

本节负责把这些数据可靠地写入 PostgreSQL:

向量 -> rag_chunk.embedding模型信息 -> rag_chunk.metadata.embedding完成状态 -> rag_document.status失败原因 -> rag_document.error_message  

完成本节后,应能够理解:

pgvector 字段如何创建和校验  
Java 如何把浮点数组写入 vector 字段  
为什么使用 JDBC batch向量和 metadata 如何保持一致  
为什么写入必须使用事务  
重复执行是否会产生重复数据  
失败后数据库会处于什么状态  
如何验收整篇文档是否入库完整  
HNSW 索引什么时候生效  
生产环境还可以做哪些改进  

本文示例采用以下配置:

Embedding 模型:text-embedding-v4  
向量维度:1024  
向量数据库:PostgreSQL + pgvector  
距离度量:cosine distance  
向量字段:rag_chunk.embedding  
模型血缘:rag_chunk.metadata.embedding  

2. 向量入库整体流程

graph TD;  
 A["收到当前文档的全部向量"] --> B["校验向量数量和维度"];  
 B --> C["打开数据库连接"];  
 C --> D["关闭自动提交"];  
 D --> E["JDBC batch 更新 rag_chunk"]; E --> F["检查每个 chunk 是否成功更新"];  
 F --> G["更新 rag_document.status = EMBEDDED"]; G --> H["提交事务"];  
 E -- "失败" --> I["回滚事务"];  
 F -- "chunk 不存在" --> I;  
 G -- "文档不存在" --> I;  

模型调用和数据库写入应该分开:先得到完整向量结果,再把向量交给入库服务统一持久化。


3. pgvector 数据库准备

3.1 启用 vector 扩展

CREATE EXTENSION IF NOT EXISTS vector;  

检查扩展:

SELECT extname, extversion  
FROM pg_extension  
WHERE extname = 'vector';  

如果没有查询结果,说明当前 database 没有启用扩展。

注意:

pgvector 必须先安装到 PostgreSQL 服务  
CREATE EXTENSION 需要在当前使用的 database 中执行  
不同 database 的扩展启用状态相互独立  
应用账号可能没有创建扩展的权限  

3.2 创建向量字段

本文示例使用:

ALTER TABLE rag_chunk  
 ADD COLUMN IF NOT EXISTS embedding vector(1024);  

vector(1024) 表示:

每条向量必须包含1024个浮点数  
不能写入1023维或1536维向量  
NULL表示这个chunk尚未完成向量化  

维度必须在所有位置保持一致:

EMBEDDING_DIMENSION=1024  
Python请求 dimensions=1024Python返回向量长度=1024  
Java响应校验=1024  
PostgreSQL字段 vector(1024)  

3.3 检查字段实际维度

ADD COLUMN IF NOT EXISTS 只能保证字段存在,不能保证已有字段维度正确。

可以使用下面的系统表查询字段类型:

SELECT format_type(attribute.atttypid, attribute.atttypmod) AS column_type  
FROM pg_attribute attribute  
JOIN pg_class table_info  
 ON table_info.oid = attribute.attrelidWHERE table_info.relname = 'rag_chunk'  
 AND attribute.attname = 'embedding' AND attribute.attnum > 0 AND NOT attribute.attisdropped;```  
  
本文示例的期望结果:  
  
```text  
vector(1024)  

如果数据库是 vector(1536),配置却是 1024,应用会拒绝继续启动,避免把错误留到入库阶段。

3.4 创建 HNSW 索引

CREATE INDEX IF NOT EXISTS rag_chunk_embedding_hnsw_idx  
ON rag_chunk  
USING hnsw (embedding vector_cosine_ops);  

这里的 vector_cosine_ops 表示索引用于 cosine distance。

后续查询应使用匹配的运算符:

ORDER BY embedding <=> :query_embedding  
LIMIT :top_k;  

4. 入库数据结构

Java 可以使用一个简单的 record 表示待入库向量:

public record EmbeddingWriteItem(  
 UUID chunkId, int chunkIndex, List<Double> vector, String inputHash, String embeddingMetadataJson) {  
}  

字段含义:

字段 作用
chunkId 定位 rag_chunk.id
chunkIndex 表示 chunk 在文档中的顺序
vector 1024 维 Embedding 数组
inputHash 最终向量化输入文本的 SHA-256
embeddingMetadataJson 模型、维度、版本、时间等血缘信息

4.1 为什么需要 chunkId

向量必须与生成它的文本严格一一对应:

rag_chunk.id = chunkId  
rag_chunk.content = 生成该向量的正文  
rag_chunk.embedding = 该正文对应的向量  

如果向量顺序错位,数据库仍可能写入成功,但后续检索会返回错误文本。这类错误比 SQL 报错更危险。

因此不能只依赖列表位置,必须携带稳定的 chunkId。

4.2 inputHash 的作用

向量化输入可能由标题和正文共同组成:

标题路径:产品手册 > 上传限制  
正文:单个文件最大20MB。  

Python 对最终输入计算 SHA-256:

inputHash = sha256(最终输入文本)  

它可以用于:

确认向量对应的是哪一版文本  
发现标题或正文是否发生变化  
排查旧向量是否已经失效  
以后实现未变化chunk跳过向量化  

5. 向量写入 SQL

每个 chunk 使用下面的 SQL 更新:

UPDATE rag_chunk  
SET embedding = CAST(? AS vector),  
 metadata = metadata || jsonb_build_object( 'embedding', CAST(? AS jsonb) ), updated_at = now()WHERE id = ?  
 AND document_id = ?;  

四个参数依次是:

1. 向量文本  
2. Embedding metadata JSON  
3. chunkId  
4. documentId  

5.1 为什么同时使用 chunkId 和 documentId

只按 chunkId 更新虽然也能找到数据,但无法验证该 chunk 是否属于当前文档。

推荐条件:

WHERE id = ? AND document_id = ?  

可以阻止下面这种错误:

当前任务处理文档A  
请求数据中却混入文档B的chunkId  

如果更新行数为 0,入库服务应认为 chunk 已不存在或归属不正确,并回滚整个事务。

5.2 Java 如何写入 vector

一种简单做法是先把 List<Double> 转成 pgvector 支持的文本格式:

[0.012,-0.035,0.087,...]  

然后使用参数化 SQL:

chunkStatement.setString(1, vectorText(embedding.vector()));  

数据库端转换:

CAST(? AS vector)  

这样做的优点:

实现简单  
仍然使用PreparedStatement参数绑定  
不会把完整向量直接拼接进SQL语句  
不需要额外的pgvector JDBC类型  

生产项目也可以评估 pgvector Java/JDBC 类型或框架提供的 VectorStore 封装。


6. Embedding metadata 如何保存

本文示例没有单独建立以下列:

embedding_model  
embedding_dimension  
embedding_version  
embedded_at  

这些信息保存在 rag_chunk.metadata 的 embedding 对象中。

示例:

{  
 "source": "upload", "fileType": "pdf", "pageStart": 3, "pageEnd": 4, "embedding": { "provider": "dashscope-openai-compatible", "model": "text-embedding-v4", "dimension": 1024, "version": "v1", "normalized": false, "inputHash": "c0f2...", "embeddedAt": "2026-06-15T10:30:00+08:00" }}  

6.1 JSONB 合并行为

写入 SQL:

metadata = metadata || jsonb_build_object(  
 'embedding', CAST(? AS jsonb))  

它的行为是:

保留metadata中已有的source、页码、标题等顶层字段  
新增embedding对象  
如果embedding已经存在,则替换整个embedding对象  

它不是把整个 metadata 清空后重写。

6.2 查询模型信息

查询模型名:

SELECT metadata #>> '{embedding,model}' AS embedding_model  
FROM rag_chunk  
WHERE id = :chunk_id;  

查询维度:

SELECT (metadata #>> '{embedding,dimension}')::int AS embedding_dimension  
FROM rag_chunk  
WHERE id = :chunk_id;  

查询输入摘要:

SELECT metadata #>> '{embedding,inputHash}' AS input_hash  
FROM rag_chunk  
WHERE id = :chunk_id;  

6.3 JSONB 和普通列如何选择

学习项目可以使用 JSONB,便于扩展和减少改表。

如果以后经常按模型、版本或时间过滤,可以考虑拆成普通列:

ALTER TABLE rag_chunk  
 ADD COLUMN embedding_model varchar(128), ADD COLUMN embedding_version varchar(64), ADD COLUMN embedded_at timestamptz;  

选择原则:

经常过滤、排序、索引的字段:普通列  
主要用于追踪和展示的扩展信息:JSONB  

本文后续示例仍以 metadata.embedding 为准。


7. 为什么使用 JDBC batch

如果一篇文档有 200 个 chunk,逐条执行会产生 200 次独立数据库往返。

批量更新可以这样实现:

for (EmbeddingWriteItem embedding : embeddings) {  
 chunkStatement.setString(1, vectorText(embedding.vector())); chunkStatement.setString(2, embedding.embeddingMetadataJson()); chunkStatement.setObject(3, embedding.chunkId()); chunkStatement.setObject(4, documentId); chunkStatement.addBatch();}  
  
int[] updateCounts = chunkStatement.executeBatch();  

优点:

减少数据库网络往返  
统一管理参数  
提高批量更新吞吐  
便于在一个事务中检查结果  

7.1 检查批量更新结果

还应检查 executeBatch() 返回的更新数量:

for (int updateCount : updateCounts) {  
 if (updateCount == 0) { throw new IllegalStateException("写入向量时发现 chunk 已不存在");  
 }}  

目的是防止:

模型调用期间chunk被删除  
documentId和chunkId归属不一致  
上游传入了过期chunk  

发现异常时不会继续把文档标记为 EMBEDDED。


8. 事务设计

向量入库应使用一个数据库事务:

connection.setAutoCommit(false);  
  
// 批量更新全部 chunkchunkStatement.executeBatch();  
  
// 更新文档状态  
documentStatement.executeUpdate();  
  
connection.commit();  

出现异常:

connection.rollback();  

8.1 事务保护什么

事务保证以下操作要么全部成功,要么全部失败:

所有rag_chunk.embedding写入  
所有metadata.embedding写入  
rag_document.status更新为EMBEDDED  
rag_document.error_message清空  

不会出现:

只写入一半chunk,文档却已经是EMBEDDED  
文档状态成功,但向量仍然为空  
向量写入成功,但metadata没有对应模型信息  

8.2 为什么模型调用不放进事务

Embedding API 可能需要数秒甚至更久,还可能发生限流和网络重试。

如果先开启事务再调用模型:

数据库连接会被长时间占用  
事务持续时间过长  
发生锁竞争的概率增加  
外部接口失败会让事务白白等待  

推荐顺序是:

先在事务外生成全部向量  
再打开短数据库事务完成持久化  

8.3 事务粒度

第一版可以把事务粒度设为一整篇文档:

一篇文档的全部chunk -> 一个写入事务  

适合:

学习项目  
普通大小文档  
需要简单一致性保证  
不希望半篇文档进入检索  

大文档或高吞吐生产环境可以采用版本隔离、分批提交和最终切换可见版本,但设计会复杂很多。


9. 文档状态更新

全部 chunk 写入成功后执行:

UPDATE rag_document  
SET status = 'EMBEDDED',  
 error_message = NULL, updated_at = now()WHERE id = ?;  

如果文档不存在,更新行数为 0,事务会回滚。

9.1 第一版可以不增加 chunk 级状态

第一版可以不增加以下 chunk 级状态:

PENDING_EMBED  
EMBEDDING  
EMBEDDED  
EMBED_FAILED  

判断单个 chunk 是否有向量,使用:

embedding IS NOT NULL  

判断整篇文档是否允许参与检索,还要结合:

rag_document.status = 'EMBEDDED'  

推荐检索条件:

WHERE d.status = 'EMBEDDED'  
 AND c.embedding IS NOT NULL  

9.2 为什么两个条件都需要

重新处理一个已经有旧向量的文档时,如果新模型调用失败:

旧embedding可能仍然存在  
文档状态会被标记为FAILED  

如果检索只检查 embedding IS NOT NULL,可能继续召回旧向量。

所以文档状态是控制整篇文档是否对检索可见的重要开关。


10. 幂等和重复执行

本文使用 UPDATE,而不是向量表 INSERT:

UPDATE rag_chunk  
SET embedding = ...  
WHERE id = ? AND document_id = ?;  

重复执行同一个文档时:

不会新增重复chunk  
不会新增第二条向量记录  
原embedding被新embedding覆盖  
原metadata.embedding被新版本替换  
其他metadata顶层字段继续保留  

因此这种数据库写入方式具有覆盖式幂等性。

10.1 模型调用去重

如果每次重新处理都直接请求 Embedding 模型,即使 chunk 文本没有变化,也会产生重复调用。

已经保存的 inputHash 可以用于后续优化:

重新计算当前输入Hash  
读取旧metadata.embedding.inputHash  
比较模型名、版本、维度和Hash  
完全一致则跳过模型调用  

判断条件不能只看 Hash,还要包含:

provider  
model  
dimension  
version  
normalize配置  

文本相同但模型变化,仍然必须重新生成向量。


11. 失败处理

11.1 数据库写入失败

常见原因:

数据库连接失败  
vector扩展不存在  
向量维度不匹配  
metadata不是合法JSON  
chunk已被删除  
文档已被删除  
账号没有UPDATE权限  

发生异常时:

向量写入事务回滚  
不会保留本次部分写入  
上层服务捕获异常  
尝试把rag_document标为FAILED  
error_message记录根异常摘要  

11.2 标记失败 SQL

UPDATE rag_document  
SET status = 'FAILED',  
 error_message = ?, updated_at = now()WHERE id = ?;  

标记失败本身使用新的数据库连接,不属于已经回滚的写入事务。

11.3 错误信息长度

建议限制写入数据库的错误信息长度,避免异常堆栈或远程响应无限增长。

数据库中建议保存:

稳定错误码  
简洁错误摘要  
最后失败时间  
必要的requestId  

完整堆栈放日志系统,不要全部塞进业务字段。


12. 入库状态查询

可以使用下面的 SQL 汇总一篇文档:

SELECT count(*) AS total_count,  
 count(embedding) AS embedded_count, max(metadata #>> '{embedding,model}') AS model, max((metadata #>> '{embedding,dimension}')::int) AS dimension, max(updated_at) FILTER (WHERE embedding IS NOT NULL) AS last_embedded_atFROM rag_chunk  
WHERE document_id = ?;  

返回:

totalChunkCount  
embeddedChunkCount  
model  
dimension  
lastEmbeddedAt  

12.1 如何判断入库完整

最基本条件:

totalChunkCount > 0  
totalChunkCount == embeddedChunkCount  
model == text-embedding-v4  
dimension == 1024  
rag_document.status == EMBEDDED  

不能只判断文档状态,也不能只判断向量数量。

12.2 为什么使用 count(embedding)

PostgreSQL:

count(*)  

统计所有行,而:

count(embedding)  

只统计 embedding IS NOT NULL 的行。

两者差值就是尚未写入向量的 chunk 数量。


13. 向量样本查询

为了调试,可以查询少量向量样本:

SELECT id,  
 chunk_index, content, embedding::text AS vector_text, metadata #>> '{embedding,inputHash}' AS input_hashFROM rag_chunk  
WHERE document_id = ?  
 AND embedding IS NOT NULLORDER BY chunk_index  
LIMIT ?;  

13.1 为什么只返回向量预览

一条向量有 1024 个数字。完整返回多条向量会:

增加接口响应体  
降低前端可读性  
刷满日志  
没有实际展示价值  

接口可以只取前 8 个数字作为预览,用于确认:

向量不是空值  
格式可以解析  
chunk和向量已经关联  

完整向量应保留在数据库中,不应作为普通业务接口数据频繁返回。


14. HNSW 索引与写入的关系

建立 HNSW 后,每次写入或更新 embedding 时,PostgreSQL 还需要维护向量索引。

因此 HNSW 会带来:

更快的近似向量查询  
更多磁盘占用  
更高的写入成本  
更长的初始索引构建时间  

14.1 学习阶段是否必须建索引

不是。

没有 HNSW,下面的查询仍然可以执行精确检索:

SELECT id, content,  
 embedding <=> :query_embedding AS distanceFROM rag_chunk  
WHERE embedding IS NOT NULL  
ORDER BY embedding <=> :query_embedding  
LIMIT 5;  

数据少时,顺序扫描甚至可能更合适。

14.2 大批量导入策略

大量历史数据首次导入时,常见策略是:

先写入全部向量  
再创建HNSW索引  
执行ANALYZE  
测试查询计划和召回质量  

学习项目为了使用方便,可以提前创建索引。

14.3 检查查询计划

EXPLAIN (ANALYZE, BUFFERS)  
SELECT id, content  
FROM rag_chunk  
WHERE embedding IS NOT NULL  
ORDER BY embedding <=> :query_embedding  
LIMIT 5;  

表很小时没有使用 HNSW 不一定是问题,优化器可能认为顺序扫描成本更低。


15. 手动验收 SQL

15.1 检查 vector 扩展

SELECT extname, extversion  
FROM pg_extension  
WHERE extname = 'vector';  

15.2 检查向量字段

SELECT format_type(attribute.atttypid, attribute.atttypmod) AS column_type  
FROM pg_attribute attribute  
JOIN pg_class table_info  
 ON table_info.oid = attribute.attrelidWHERE table_info.relname = 'rag_chunk'  
 AND attribute.attname = 'embedding' AND attribute.attnum > 0 AND NOT attribute.attisdropped;  

期望:

vector(1024)  

15.3 检查索引

SELECT indexname, indexdef  
FROM pg_indexes  
WHERE tablename = 'rag_chunk'  
 AND indexname = 'rag_chunk_embedding_hnsw_idx';  

15.4 检查向量完整度

SELECT  
 document_id, count(*) AS total_chunks, count(embedding) AS embedded_chunks, count(*) - count(embedding) AS missing_embeddingsFROM rag_chunk  
WHERE document_id = :document_id  
GROUP BY document_id;  

15.5 检查实际维度

SELECT  
 chunk_index, vector_dims(embedding) AS dimensionFROM rag_chunk  
WHERE document_id = :document_id  
 AND embedding IS NOT NULLORDER BY chunk_index;  

所有结果都应为:

1024  

15.6 检查模型血缘

SELECT  
 chunk_index, metadata #>> '{embedding,provider}' AS provider, metadata #>> '{embedding,model}' AS model, (metadata #>> '{embedding,dimension}')::int AS dimension, metadata #>> '{embedding,version}' AS version, metadata #>> '{embedding,inputHash}' AS input_hash, metadata #>> '{embedding,embeddedAt}' AS embedded_atFROM rag_chunk  
WHERE document_id = :document_id  
ORDER BY chunk_index;  

15.7 检查文档状态

SELECT  
 id, original_name, status, error_message, updated_atFROM rag_document  
WHERE id = :document_id;  

成功标准:

status = EMBEDDED  
error_message IS NULL  
missing_embeddings = 0  
所有维度 = 1024所有模型 = text-embedding-v4所有inputHash非空  

16. 生产化改进

前面的实现适合学习和普通文档流程。生产环境可以继续增强。

16.1 使用 DataSource 和连接池

基础示例可能直接使用:

DriverManager.getConnection(...)  

生产环境更适合复用 Spring Boot 的:

DataSource  
HikariCP  
JdbcTemplate  
NamedParameterJdbcTemplate  

这样可以获得连接复用、超时控制、连接池指标和统一事务管理。

16.2 使用 Spring 事务

基础 JDBC 示例通常手动控制:

setAutoCommit(false)  
commit  
rollback  

后续可以通过:

@Transactional  

配合 Spring JDBC 管理事务,但要确保外部 Embedding 调用仍然发生在数据库事务之外。

16.3 使用 Flyway 管理 DDL

学习阶段可以在应用启动时检查扩展、字段和索引。

生产环境建议:

V1 创建基础RAG表  
V2 启用vector并增加embedding字段  
V3 创建HNSW索引  

应用启动只做校验,不自动修改数据库结构。

16.4 增量向量化

利用 inputHash、模型和版本信息,只重新处理发生变化的 chunk:

输入Hash相同 + 模型相同 + 维度相同 + 版本相同  
 -> 复用旧向量  
  
任一不同  
 -> 重新生成并覆盖向量  

16.5 向量版本表

如果需要同时保留多个模型或版本,不应继续覆盖一个字段。

可以建立:

CREATE TABLE rag_chunk_embedding (  
 id uuid PRIMARY KEY, chunk_id uuid NOT NULL REFERENCES rag_chunk(id) ON DELETE CASCADE, provider varchar(64) NOT NULL, model varchar(128) NOT NULL, version varchar(64) NOT NULL, dimension integer NOT NULL, embedding vector(1024) NOT NULL, input_hash char(64) NOT NULL, created_at timestamptz NOT NULL DEFAULT now(), UNIQUE (chunk_id, model, version));  

这是多模型版本需求下的设计,不是第一版必须完成的内容。

16.6 大文档分批持久化

整篇文档一次提交比较简单,也容易保证一致性。

超大文档可以考虑:

按批次写入新版本向量  
旧版本继续对外可见  
全部批次完成后原子切换当前版本  
失败时删除未完成的新版本  

不要简单地“每批写一点并立即让它参与检索”,否则用户可能搜到半篇已更新、半篇未更新的数据。


17. 常见问题

17.1 向量入库会再次调用模型吗

入库层本身不负责模型推理。它接收已经生成的向量,完成校验、持久化和状态更新。

业务接口可以连续完成模型调用和向量入库,但入库组件本身仍然只负责存储。

17.2 embedding 为什么允许 NULL

chunk 创建时还没有向量,所以字段需要允许 NULL。

NULL:尚未向量化  
非NULL:已有可用于距离计算的向量  

17.3 为什么不用 INSERT

向量直接属于已有 rag_chunk 时,使用 UPDATE 最简单,并且不会产生重复向量行。

只有需要保留多模型、多版本时,才更适合拆分独立向量表并使用 INSERT。

17.4 metadata 合并会丢失页码吗

不会。示例 SQL 只替换顶层 embedding 键,其他顶层 metadata 保留。

17.5 修改为其他维度后为什么不能写入

模型输出、Java 配置和数据库字段必须完全一致。更换维度需要:

停止旧写入  
迁移或重建embedding字段  
重新生成所有chunk向量  
重建HNSW索引  
确保查询向量使用相同模型和维度  

17.6 为什么不用每个 chunk 一个事务

每条一个事务会增加提交开销,并可能让整篇文档进入部分完成状态。第一版建议整篇文档原子写入,优先保证一致性。

17.7 HNSW 索引创建后为什么查询仍然顺序扫描

可能原因:

表数据量太少  
查询没有ORDER BY距离并LIMIT  
距离运算符与索引operator class不匹配  
统计信息尚未更新  
过滤条件改变了优化器的成本判断  

应使用 EXPLAIN ANALYZE 判断,不要只看索引是否存在。


18. 练习清单

完成以下练习:

执行vector扩展和vector(1024)字段初始化  
查询并确认字段实际维度  
解释List<Double>如何转换并写入pgvector  
解释metadata || jsonb_build_object的合并行为  
写出文档向量完整度检查SQL  
写出模型血缘查询SQL  
解释JDBC batch的作用  
解释事务保护了哪些数据一致性  
说明重复执行为什么不会增加重复行  
说明为什么检索要同时检查文档状态和embedding非空  
使用EXPLAIN ANALYZE观察向量查询计划  

19. 小结

向量入库的完整数据链路:

1024维向量  
 -> 按chunkId定位rag_chunk  
 -> CAST(? AS vector) -> JDBC batch批量更新  
 -> metadata.embedding保存模型血缘  
 -> 检查所有chunk更新结果  
 -> rag_document.status更新为EMBEDDED  
 -> 同一事务提交  

本节最重要的结论:

向量入库不是把一串数字塞进数据库,而是让向量、原文、模型版本、处理状态和事务结果始终保持一致。

20. 参考资料

  • pgvector
  • PostgreSQL JSON Functions and Operators
  • PostgreSQL JDBC
  • PostgreSQL Transactions
AI自学路线
AI
许可协议: 
分享

相关文章

7月 13, 2026

55 异常兜底:工具失败、非法输出、空检索与超时

异常兜底:工具失败、非法输出、空检索与超时 Agent 的可靠性主要体现在失败时。工ࠥ

7月 13, 2026

54 Agent Memory:短期记忆、用户上下文与摘要

Agent Memory:短期记忆、用户上下文与摘要 Memory 的目标是保持任务连续性,不是永久保存所有聊天。记忆Š

7月 13, 2026

53 Human-in-the-loop:让关键动作暂停、确认与恢复

Human-in-the-loop:让关键动作暂停、确认与恢复 HITL 不是弹一个“确定吗”,而是让工作流在关键动作前持久

下一篇

23 向量检索

上一篇

20 文档切片

最近更新

  • 55 异常兜底:工具失败、非法输出、空检索与超时
  • 54 Agent Memory:短期记忆、用户上下文与摘要
  • 53 Human-in-the-loop:让关键动作暂停、确认与恢复
  • 52 工单 Tool:字段校验、创建结果与失败补偿
  • 51 订单 Tool:Mock、鉴权、状态解析与脱敏

热门标签

java基础 微服务 maven Spring Tomcat DDD Linux Linux基础 SQL基础 数据结构算法

目录

©2026 一条在知识海洋的咸鱼. 保留部分权利。

使用 Halo 主题 Chirpy