内容提要
本文介绍 Koog 1.3 的知识增强设施:Embeddings 模块通过 LLMEmbedder 生成向量,但 DeepSeek 客户端不支持嵌入,需搭配 Ollama 或云端服务;rag-base 定义存储抽象,rag-vector 提供文档向量化与检索原型,仅适合本地测试;检索可作为工具供 agent 按需调用,实现 agentic RAG;LongTermMemory 将检索与入库功能化,支持自动或手动模式,需注意分桶、去重与持久化限制;生产环境应基于 rag-base 自研向量库适配器。
延伸解读
嵌入与聊天可分离,但需注意客户端限制
Koog 的 LLMEmbedder 依赖具体客户端的嵌入端点,而 DeepSeek 客户端会直接抛出 UnsupportedOperationException,因为 DeepSeek API 本身不提供嵌入。因此,聊天用 DeepSeek 时,嵌入必须换用 Ollama、OpenAI 或 Bedrock 等支持嵌入的服务。文章示例选择跳过向量嵌入,改用不依赖嵌入的本地存储检索,这也是一种可行组合。
内置检索存储适合原型,生产需自研适配器
rag-vector 的 EmbeddingStorage 和 InMemoryRecordStorage 都是本地原型:只支持相似度检索、没有分块、元数据建模有限,且不集成 Pinecone、pgvector 等生产向量库。官方建议从 rag-base 的 SearchStorage 和 WriteStorage 接口入手,自研后端适配器。文章也强调,实现时要明确支持的请求类型、分数度量、分页、过滤和 namespace 授权。
Agentic RAG 灵活但非可靠保证
把检索暴露为工具让模型按需调用,适合只有部分请求需要查库的场景。但文章实测发现,即使 system prompt 要求“必须先调用”,模型仍可能补充知识库没有的细节。工具调用是模型指令而非程序控制;若业务要求每次政策回答都先查库,应把检索放进固定策略节点,并校验输出中的政策与引用。
LongTermMemory 的分桶与持久化需自行设计
LongTermMemory 的 retrieval 和 ingestion 可独立配置,但 sessionId 不会自动分桶,需显式设置 namespace;共享默认 namespace 会导致跨会话检索。自动 ingestion 在 agent 完成点触发,存储批量写入未必有事务性,失败时不会自动回滚。配合 ChatMemory 时还可能重复收录旧历史,需自行去重并设置保留策略。
Q&A
Koog 的 DeepSeek 客户端能用来生成文本嵌入向量吗?
不能。Koog 的 DeepSeek 客户端中嵌入方法无条件抛出 UnsupportedOperationException,因为 DeepSeek API 本身没有嵌入端点。因此不能将 DeepSeek 客户端直接接入 LLMEmbedder 来生成向量。但聊天使用 DeepSeek 不妨碍嵌入使用其他实现,例如 Ollama 本地模型或 OpenAI/Bedrock 云端服务。
Koog 的 rag-vector 模块适合直接用于生产环境的 RAG 吗?
不适合。rag-vector 是本地原型,只支持相似度检索,没有内置 chunking(长文档不会自动切块),记录元数据建模有限,也没有 Pinecone/Weaviate/pgvector/Milvus 等生产向量库集成。生产化路径是基于 rag-base 抽象自研后端适配器,实现 SearchStorage 和 WriteStorage 接口,将检索与写入翻译成向量库调用。
如何让 agent 在需要时主动检索知识库,而不是每次都预先检索?
可以把检索暴露成工具,让模型自己决定何时查、查什么,这就是 agentic RAG。具体做法是定义一个检索工具(如 searchFaq),在工具描述中说明用途,并将工具注册到 agent 的 ToolRegistry 中。这样对只有部分请求需要查知识库的场景更合适,也复用了 Koog 的工具体系。
LongTermMemory 的自动检索和自动入库如何配置?
在 AIAgent 安装块中通过 install(LongTermMemory) 配置 retrieval 和 ingestion 两个独立块。每个块内部 storage 是必填项,整块可以不配置以只启用另一侧。retrieval 可配置 searchStrategy(如 SimilaritySearchStrategy(topK=3))和 promptAugmenter;ingestion 配置 storage 即可。两个开关 enableAutomaticRetrieval 和 enableAutomaticIngestion 默认开启,可组合出全自动、纯手动或混合模式。
使用 LongTermMemory 时,sessionId 能自动实现用户记忆隔离吗?
不能。LongTermMemory 不会根据 run(input, sessionId) 的 sessionId 自动分桶,而是将独立配置的 namespace 传给后端。检索和入库两侧应分别配置成同一业务分桶;共享默认 namespace 会允许跨 session 检索,不能当作用户私有记忆。namespace 或 sessionId 都不是授权机制,需要明确写入范围、去重与隐私边界。
ChatMemory 和 LongTermMemory 有什么区别?可以同时使用吗?
ChatMemory 存对话历史(本轮消息序列,按 sessionId 分桶,每轮读写),回答“上次聊到哪了”;LongTermMemory 存知识(跨会话、按 namespace 隔离、检索式读取),在接入持久化存储、正确分桶并设置保留策略后,才有条件检索更早的事实。两者可以同时安装,但并非完全互不影响:ChatMemory 恢复的历史可能再次进入 LTM ingestion,增强后的文本也可能进入历史存储,需要明确写入范围、去重与隐私边界。
在 Koog 中如何为生产环境自研向量库适配器?
实现 rag-base 的 SearchStorage 和 WriteStorage 接口,将 search、add、update 操作翻译成后端向量库调用。需要明确支持哪些请求类型、分数度量、分页、metadata 过滤和 namespace,并在服务端执行用户授权。嵌入部分可以继续用 LLMEmbedder,也可以在适配器内部调向量库自带的嵌入服务。LongTermMemory 的配置结构不变,只需将 retrieval/ingestion 的 storage 换成自研实现。