From ab9b099e9b1a0d133dca63d7a599398b6ab4624f Mon Sep 17 00:00:00 2001 From: bruce Date: Sun, 31 May 2026 23:56:31 +0800 Subject: [PATCH] =?UTF-8?q?feat(modelprovider):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E8=B0=83=E7=94=A8=E4=B8=8ERAG=E5=8F=AC?= =?UTF-8?q?=E5=9B=9E=E6=94=AF=E6=92=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENT.md | 40 +++++---- README.md | 49 ++++++---- docs/ARCHITECTURE.md | 58 ++++++++++-- docs/MODEL_PROVIDER_SCHEMA.sql | 39 ++++++++ docs/ROADMAP.md | 39 ++++---- rag-store-page-apis.md | 11 +++ .../client/OpenAiCompatibleModelClient.java | 4 + .../OpenAiCompatibleModelClientImpl.java | 90 ++++++++++++++++++- .../rag/mapper/RagChunkEmbeddingMapper.java | 23 +++++ 9 files changed, 295 insertions(+), 58 deletions(-) diff --git a/AGENT.md b/AGENT.md index 8c5caab..22b8dc7 100644 --- a/AGENT.md +++ b/AGENT.md @@ -11,8 +11,8 @@ - 文件上传与附件管理 - 前后端统一的管理控制台 -当前阶段已经完成平台骨架、公共接口规范、知识库/知识文档管理、文档上传、文档解析、解析快照与手动切片入口。 -后续重点从"文档可切片"推进到"向量可检索"、"模型可路由"和"Agent 可运行"。 +当前阶段已经完成平台骨架、公共接口规范、知识库/知识文档管理、文档上传、文档解析、解析快照、手动切片入口、模型平台基础配置与 Agent 定义管理/调试入口。 +后续重点从"文档可切片"推进到"向量可检索"、"模型可路由"和"Agent 运行时可编排"。 ## 2. 总体设计思路 @@ -74,18 +74,24 @@ ### 3.3 Agent 运行模块 -后续平台重点能力,建议逐步补齐: +当前已落地最小可用能力: -- Agent 定义 -- Prompt 模板 -- 工具注册与调用 -- 会话上下文与记忆 -- 执行日志与任务状态 +- `agent_definition`:Agent 定义管理(CRUD、编码唯一校验、知识库绑定校验) +- Agent 管理接口:`/api/agents/list`、`/api/agents/query`、`/api/agents/detail`、`/api/agents/save`、`/api/agents/delete` +- Agent 调试接口:`POST /api/agents/{agentId}/chat`,支持普通对话与 RAG 对话两种模式 +- Agent 调试链路:用户问题向量化 -> `rag_chunk_embedding` 相似度召回 -> 组装上下文 -> Chat 模型回答 -> 返回引用切片 +- 统一模型调用日志:通过 `ChatModelGateway` 与 `model_call_log` 记录请求 ID、模型、耗时与 token 信息 + +后续平台重点能力: + +- Prompt 模板管理 +- 会话上下文持久化与记忆 +- 工具注册与调用协议 +- 执行任务状态与日志 - 多步骤编排 -建议未来增加的核心对象: +建议后续补齐的核心对象: -- `agent_definition` - `agent_session` - `agent_message` - `agent_task` @@ -104,6 +110,8 @@ - 知识库管理页(完整 CRUD + 概览卡片 + 双栏详情 + 批量上传入口) - 知识文档页(条件查询 + 批量上传 + 解析重试 + 批量切片 + 编辑/启停用/删除) - 切片任务页(解析成功/失败文档概览与切片入口) +- Agent 管理页(Agent 定义管理与知识库绑定) +- Agent 调试页(普通对话 / RAG 对话切换、引用切片回显) 前端技术要点: @@ -125,7 +133,7 @@ - 附件管理页面前端联调 - RAG 检索配置、向量索引任务和最近任务页面联调 - 模型服务商、模型配置、路由规则和调用日志管理 -- Agent 调试页 +- Agent 会话历史与运行日志页 - 执行日志查看 ## 4. 当前接口设计原则 @@ -219,7 +227,7 @@ 5. ~~接入切片生成与切片持久化~~(已完成定长/分隔符切片与手动切片入口) 6. 建设模型服务商配置与模型路由层 7. 接入 Embedding / Chat 模型并完成向量写入 -8. 建立 Agent 运行时骨架 +8. 完善 Agent 运行时骨架(会话、工具、任务) 9. ~~补前端控制台基础骨架~~(已完成,部分高级页面待联调) 剩余重点: @@ -227,17 +235,17 @@ - 完成模型服务商配置、模型配置、路由规则和调用日志基础能力 - 接入 Embedding,生成并保存 `rag_chunk_embedding` - 补齐索引任务、重试、重建索引和最近任务接口 -- 接入 OpenAI-compatible / Spring AI 适配层并实现最小模型调用链路 +- 扩展 Agent 会话、工具调用与任务编排能力 ## 7. 下一步建议 结合当前代码状态,接下来建议重点做: -- 实现模型服务商和模型配置表:支持 Ollama、硅基流动、百炼等 OpenAI-compatible 来源 -- 实现 Embedding 网关:对已落库切片调用 Embedding 模型并写入 `rag_chunk_embedding` +- 完成 RAG 全量向量化链路,确保知识库可稳定召回 +- 为 Agent 调试链路补齐会话持久化与多轮上下文管理 +- 建立 Agent 工具注册与调用协议,沉淀最小工具集 - 把 `indexStatus` 从手工字段推进为真实状态流转 - 补齐重建索引、失败重试、最近任务接口和前端展示 -- 接入模型路由,实现本地小模型与云端大模型的成本优先调用链路 ## 8. 文档用途说明 diff --git a/README.md b/README.md index aa680bb..b508677 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ Common Agent 是一个规划中的通用 Agent 平台,技术路线基于 Java、Spring Boot 和 Spring AI。 项目目标是建设一套完整的前后端系统,支持 Agent 编排、工具调用、会话管理、RAG 知识库和平台管理能力。 -当前项目已经完成基础工程、公共模块、RAG 元数据管理、文档上传、文档解析入口、解析快照、手动切片入口、前端知识库与知识文档管理页面。 -Agent 运行时、RAG 向量化、检索问答、模型服务商配置与更多平台管理能力会在后续阶段逐步实现。 +当前项目已经完成基础工程、公共模块、RAG 元数据管理、文档上传、文档解析入口、解析快照、手动切片入口、模型服务商配置基础能力、Agent 定义管理与调试页面。 +会话持久化、工具调用编排、RAG 全量向量化与检索问答能力会在后续阶段逐步完善。 ## 项目愿景 @@ -13,7 +13,7 @@ Common Agent 希望成为一个可复用的企业级 AI 应用基础平台: - Agent 运行时:支持对话、工具调用、记忆、任务执行和流程编排。 - RAG 知识库:支持文档导入、解析、切片、向量化、检索和基于上下文的回答生成。 - 模型抽象:通过 Spring AI 统一接入聊天模型、Embedding 模型和重排序模型。 -- 管理控制台:提供会话、Agent、知识库、文档、提示词和系统配置的 Web 管理界面。 +- 管理控制台:提供 Agent、知识库、文档、模型配置和系统配置的 Web 管理界面。 - 多环境部署:支持本地开发、测试环境和生产环境的配置隔离。 ## 当前技术栈 @@ -36,7 +36,7 @@ common_agent │ ├── src/ │ │ ├── api/ # Axios 封装与各模块 API │ │ ├── layouts/ # AdminLayout 管理后台布局 -│ │ ├── pages/ # 业务页面(工作台、枚举、附件、知识库、文档) +│ │ ├── pages/ # 业务页面(系统、RAG、Agent) │ │ ├── router/ # Vue Router 配置 │ │ ├── stores/ # Pinia 状态管理 │ │ ├── styles/ # 全局样式 @@ -59,14 +59,16 @@ common_agent │ │ │ ├── handler/ # GlobalExceptionHandler │ │ │ ├── mapper/ # SysAttachmentMapper, SysEnumMapper │ │ │ └── service/ # 接口与实现 -│ │ └── rag/ # RAG 知识库模块 -│ │ ├── constant/ # RagSystemConstants -│ │ ├── controller/ # RagStoreController, RagDocumentController -│ │ ├── dto/ # 请求/响应 DTO -│ │ ├── entity/ # RagStore, RagDocument, RagChunk, RagChunkEmbedding -│ │ ├── enums/ # RagParseStatusEnum, RagIndexStatusEnum, RagChunkStrategyEnum -│ │ ├── mapper/ # RagDocumentMapper, RagStoreMapper -│ │ └── service/ # 接口与实现 +│ │ ├── rag/ # RAG 知识库模块 +│ │ │ ├── constant/ # RagSystemConstants +│ │ │ ├── controller/ # RagStoreController, RagDocumentController +│ │ │ ├── dto/ # 请求/响应 DTO +│ │ │ ├── entity/ # RagStore, RagDocument, RagChunk, RagChunkEmbedding +│ │ │ ├── enums/ # RagParseStatusEnum, RagIndexStatusEnum, RagChunkStrategyEnum +│ │ │ ├── mapper/ # RagDocumentMapper, RagStoreMapper +│ │ │ └── service/ # 接口与实现 +│ │ ├── modelprovider/ # 模型服务商、模型配置、路由、网关与调用日志 +│ │ └── agent/ # Agent 定义管理与调试链路 │ ├── main/resources/ │ │ ├── application.yaml # 环境选择 │ │ ├── application-dev.yaml # 开发环境配置 @@ -74,8 +76,12 @@ common_agent │ └── test/java/ # 单元测试(结构稳定性测试 + 前端 API 测试) ├── docs/ │ ├── ARCHITECTURE.md # 架构说明 -│ └── ROADMAP.md # 开发路线图 +│ ├── ROADMAP.md # 开发路线图 +│ ├── MODEL_PROVIDER_REQUIREMENTS.md # 模型服务商配置与路由需求 +│ ├── MODEL_PROVIDER_DESIGN.md # 模型服务商配置与路由设计 +│ └── MODEL_PROVIDER_SCHEMA.sql # 模型平台与Agent核心表结构 ├── AGENT.md # 平台设计草案 +├── agent-page-apis.md # Agent页面后端接口清单 ├── pom.xml └── README.md ``` @@ -152,6 +158,8 @@ npm run build | 知识库 | 完整 CRUD + 双栏详情 | | 知识文档 | 条件查询 + 批量上传 + 解析重试 + 批量切片 + 编辑/启停用/删除 | | 切片任务 | 解析成功/失败文档概览 + 切片入口 | +| Agent管理 | Agent 定义 CRUD + 知识库绑定 | +| Agent调试 | 普通对话 / RAG 对话切换 + 引用切片回显 | 当前 UI 规范: @@ -171,16 +179,24 @@ npm run build ## RAG 当前能力边界 -当前 RAG 已经从元数据管理推进到"上传 + 解析 + 手动切片"阶段: +当前 RAG 已经从元数据管理推进到"上传 + 解析 + 手动切片 + Agent 调试召回"阶段: - 知识库:支持列表、条件查询、详情、总览、单库文档概览、新增、编辑、删除。 - 知识文档:支持列表、条件查询、详情、新增/编辑、删除、批量上传。 - 文档解析:基于 Apache Tika 支持 TXT/Markdown/LOG、PDF、Word、Excel 文本抽取,解析时更新 `parseStatus` 并保存解析快照。 - 文档切片:支持按解析快照进行手动异步切片,已落地定长切片和分隔符切片,写入 `rag_chunk`。 -- 向量表:`rag_chunk_embedding` 实体、Mapper、Service 已有结构,向量写入、检索召回和重排序仍待接入。 -- 模型配置:已补充模型服务商配置与路由需求/设计文档,后续用于统一接入 Ollama、硅基流动、百炼等来源。 +- 向量表:`rag_chunk_embedding` 实体、Mapper、Service 已有结构,向量写入与召回 SQL 已用于 Agent 调试链路,RAG 检索问答接口仍待补齐。 +- 模型配置:模型服务商、模型配置、路由规则、调用日志基础能力已落地,Embedding/Chat 网关可用于 RAG 与 Agent 调试调用。 - 前端:知识库页、知识文档页、RAG 工作台和切片任务页已经接入当前接口,检索配置、最近任务、重建索引仍是后续能力。 +## Agent 当前能力边界 + +- Agent 定义:支持 `agent_definition` 的列表、查询、详情、新增/更新、删除。 +- Agent 对话:支持 `POST /api/agents/{agentId}/chat`,`ragEnabled=true` 时走 RAG 召回,`false` 时走普通对话。 +- RAG 对话流程:用户问题向量化 -> 按知识库召回 TopK 切片 -> 组装系统提示词与上下文 -> Chat 模型回答。 +- 调试回显:返回答案、请求 ID 和引用切片,便于前端页面展示与排障。 +- 当前限制:尚未持久化 `agent_session/agent_message`,工具调用和任务编排仍在规划中。 + ## 规划模块 - `agent-core`:Agent 执行模型、工具注册、记忆和编排能力。 @@ -197,6 +213,7 @@ npm run build - [模型服务商配置与路由需求](docs/MODEL_PROVIDER_REQUIREMENTS.md) - [模型服务商配置与路由设计](docs/MODEL_PROVIDER_DESIGN.md) - [平台设计草案](AGENT.md) +- [Agent 页面接口清单](agent-page-apis.md) ## 参考资料 diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 28e599b..be12836 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -135,8 +135,50 @@ - 知识库 CRUD、文档 CRUD、批量上传、Tika 文本解析、解析快照和状态流转已完成。 - `rag_chunk` 已支持基于解析快照的手动异步切片,当前已落地定长切片和分隔符切片。 -- `rag_chunk_embedding` 的结构层已就绪,尚未实现模型调用、向量化、索引任务和检索问答。 -- 模型服务商配置与路由已有需求/设计文档,后续会作为 Embedding、Chat 和 Rerank 的统一接入层。 +- `rag_chunk_embedding` 已支持按知识库向量相似度召回 TopK,用于 Agent 调试链路引用回显。 +- RAG 对外检索问答接口、索引任务化和重排序能力仍在后续建设中。 + +### 3.3 Agent 模块 + +包路径:`com.bruce.agent` + +职责: + +- 维护 Agent 定义主数据(CRUD + 编码唯一性 + 绑定知识库校验)。 +- 提供 Agent 调试对话接口,支持普通对话与 RAG 对话模式切换。 +- 在 RAG 对话模式下,完成“问题向量化 -> 切片召回 -> 上下文组装 -> Chat 模型回答”的最小链路。 +- 返回引用切片和请求 ID,便于前端调试与调用追踪。 + +关键类: + +| 类 | 路径 | +|----|------| +| AgentDefinition | `agent/entity/AgentDefinition.java` | +| AgentDefinitionController | `agent/controller/AgentDefinitionController.java` | +| AgentDefinitionServiceImpl | `agent/service/impl/AgentDefinitionServiceImpl.java` | +| AgentDefinitionResponse | `agent/dto/response/AgentDefinitionResponse.java` | +| AgentChatResponse | `agent/dto/response/AgentChatResponse.java` | +| ChatModelGateway | `modelprovider/gateway/ChatModelGateway.java` | +| ChatModelGatewayImpl | `modelprovider/gateway/ChatModelGatewayImpl.java` | +| ChatRequest | `modelprovider/gateway/ChatRequest.java` | +| ChatResult | `modelprovider/gateway/ChatResult.java` | + +接口列表: + +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | `/api/agents/list` | 查询全部 Agent | +| POST | `/api/agents/query` | Agent 条件查询 | +| GET | `/api/agents/detail` | 获取 Agent 详情 | +| POST | `/api/agents/save` | 新增/更新 Agent | +| POST | `/api/agents/delete` | 删除 Agent | +| POST | `/api/agents/{agentId}/chat` | Agent 调试对话 | + +当前边界: + +- `agent_definition` 与前端 Agent 管理页已完成联调。 +- 对话入口已支持 `ragEnabled` 开关,`true` 走 RAG 召回,`false` 走普通对话。 +- 尚未落地会话持久化(`agent_session` / `agent_message`)和工具调用编排。 ## 4. 数据模型关系 @@ -150,8 +192,9 @@ | `rag_document` | 知识库文档表 | 关联 `rag_store.id` 和 `sys_attachment.id` | | `rag_chunk` | 知识切片表 | 关联 `rag_store.id` 和 `rag_document.id` | | `rag_chunk_embedding` | 切片向量表 | 关联 `rag_store.id`、`rag_document.id` 和 `rag_chunk.id` | +| `agent_definition` | Agent 定义表 | 关联 `rag_store.id` | -`rag_document` 是 RAG 模块与附件模块的连接点,`rag_chunk` 和 `rag_chunk_embedding` 是下一步检索链路的核心落点。 +`rag_document` 是 RAG 模块与附件模块的连接点,`rag_chunk` 和 `rag_chunk_embedding` 是检索链路核心落点,`agent_definition` 负责把 Agent 与知识库绑定到同一调用链路。 ## 5. 配置与运行 @@ -183,16 +226,15 @@ ## 7. 当前不足 -- RAG 尚未进入"可检索链路",当前完成上传、解析和手动切片,但未完成向量化和召回。 -- 模型服务商配置、模型路由和调用日志尚未落地代码。 -- Agent 运行时相关模型与服务尚未开始建设。 +- RAG 尚未形成独立检索问答接口,当前召回能力主要用于 Agent 调试链路。 +- Agent 运行时尚未持久化会话,工具调用与任务编排仍未落地。 - 前端部分页面(附件管理、检索配置、最近任务)为占位或后续能力提示。 - 缺少鉴权、租户、操作日志。 ## 8. 建议演进方向 1. 补 RAG 最小检索闭环:解析文本 → 生成切片 → 生成向量 → 检索召回。 -2. 建设模型服务商配置与路由层,统一接入 Ollama、硅基流动、百炼等 OpenAI-compatible 来源。 -3. 建设 Agent 域模型:Agent、Session、Message、Tool、Task。 +2. 把当前 Agent 调试链路升级为会话化运行:沉淀 Session、Message 和上下文裁剪策略。 +3. 建设 Agent 工具注册与调用协议,补齐任务状态与执行日志。 4. 补齐索引任务、重试、重建索引和前端任务视图。 5. 衔接模型供应商、Spring AI 适配层、工作流编排和前端管理台。 diff --git a/docs/MODEL_PROVIDER_SCHEMA.sql b/docs/MODEL_PROVIDER_SCHEMA.sql index e4b586c..f0bc5a3 100644 --- a/docs/MODEL_PROVIDER_SCHEMA.sql +++ b/docs/MODEL_PROVIDER_SCHEMA.sql @@ -94,6 +94,23 @@ CREATE TABLE IF NOT EXISTS rag_store_model_config ( CONSTRAINT fk_rag_store_model_config_embedding_model_id FOREIGN KEY (embedding_model_id) REFERENCES model_config (id) ); +CREATE TABLE IF NOT EXISTS agent_definition ( + id BIGSERIAL PRIMARY KEY, + agent_code VARCHAR(100) NOT NULL, + agent_name VARCHAR(200) NOT NULL, + system_prompt TEXT, + store_id BIGINT NOT NULL, + status VARCHAR(50) NOT NULL DEFAULT 'ENABLED', + version INTEGER NOT NULL DEFAULT 1, + create_time TIMESTAMP, + update_time TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + create_by VARCHAR(64), + update_by VARCHAR(64), + CONSTRAINT uk_agent_definition_code UNIQUE (agent_code), + CONSTRAINT fk_agent_definition_store_id FOREIGN KEY (store_id) REFERENCES rag_store (id) +); + CREATE TABLE IF NOT EXISTS model_call_log ( id BIGSERIAL PRIMARY KEY, request_id VARCHAR(64) NOT NULL, @@ -112,8 +129,12 @@ CREATE TABLE IF NOT EXISTS model_call_log ( request_hash VARCHAR(64), error_code VARCHAR(100), error_message VARCHAR(1000), + version INTEGER NOT NULL DEFAULT 1, create_time TIMESTAMP, + update_time TIMESTAMP, remark VARCHAR(500) DEFAULT '', + create_by VARCHAR(64), + update_by VARCHAR(64), CONSTRAINT uk_model_call_log_request_id UNIQUE (request_id) ); @@ -200,6 +221,20 @@ COMMENT ON COLUMN rag_store_model_config.remark IS '备注'; COMMENT ON COLUMN rag_store_model_config.create_by IS '创建者'; COMMENT ON COLUMN rag_store_model_config.update_by IS '更新者'; +COMMENT ON TABLE agent_definition IS 'Agent定义表'; +COMMENT ON COLUMN agent_definition.id IS 'ID'; +COMMENT ON COLUMN agent_definition.agent_code IS 'Agent编码'; +COMMENT ON COLUMN agent_definition.agent_name IS 'Agent名称'; +COMMENT ON COLUMN agent_definition.system_prompt IS '系统提示词'; +COMMENT ON COLUMN agent_definition.store_id IS '绑定知识库ID'; +COMMENT ON COLUMN agent_definition.status IS '状态'; +COMMENT ON COLUMN agent_definition.version IS '版本'; +COMMENT ON COLUMN agent_definition.create_time IS '创建时间'; +COMMENT ON COLUMN agent_definition.update_time IS '更新时间'; +COMMENT ON COLUMN agent_definition.remark IS '备注'; +COMMENT ON COLUMN agent_definition.create_by IS '创建者'; +COMMENT ON COLUMN agent_definition.update_by IS '更新者'; + COMMENT ON TABLE model_call_log IS '模型调用日志表'; COMMENT ON COLUMN model_call_log.id IS 'ID'; COMMENT ON COLUMN model_call_log.request_id IS '请求唯一ID'; @@ -218,5 +253,9 @@ COMMENT ON COLUMN model_call_log.duration_ms IS '耗时(毫秒)'; COMMENT ON COLUMN model_call_log.request_hash IS '请求哈希'; COMMENT ON COLUMN model_call_log.error_code IS '错误码'; COMMENT ON COLUMN model_call_log.error_message IS '错误信息摘要'; +COMMENT ON COLUMN model_call_log.version IS '版本'; COMMENT ON COLUMN model_call_log.create_time IS '创建时间'; +COMMENT ON COLUMN model_call_log.update_time IS '更新时间'; COMMENT ON COLUMN model_call_log.remark IS '备注'; +COMMENT ON COLUMN model_call_log.create_by IS '创建者'; +COMMENT ON COLUMN model_call_log.update_by IS '更新者'; diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index d1d858d..4d86d9d 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -1,6 +1,6 @@ # Common Agent 开发路线图 -本文档基于 2026-05-25 当前分支代码整理,用来区分"已经完成""建议优先做""中期建设项"。 +本文档基于 2026-05-27 当前分支代码整理,用来区分"已经完成""建议优先做""中期建设项"。 ## 已完成 @@ -52,30 +52,34 @@ - 知识文档管理页:条件查询 + 批量上传 + 解析重试 + 批量切片入口 + 编辑/启停用/删除。 - RAG 工作台与切片任务页:展示文档解析/切片概览并提供切片入口。 - RAG 文档批量上传组件:支持锁定知识库或选择知识库上传。 +- Agent 管理页:支持 Agent 定义新增、编辑、删除、状态管理和知识库绑定。 +- Agent 调试页:支持普通对话 / RAG 对话切换、请求 ID 与引用切片回显。 - API 层:Axios 封装 + Long 类型安全解析 + 统一错误拦截。 - 单元测试:Vitest + @vue/test-utils,覆盖路由、布局、页面和 API。 -### 模型平台设计 +### 模型平台与 Agent 最小链路 -- 已新增模型服务商配置与路由需求文档:`docs/MODEL_PROVIDER_REQUIREMENTS.md`。 -- 已新增模型服务商配置与路由设计文档:`docs/MODEL_PROVIDER_DESIGN.md`。 -- 已明确后续通过模型网关统一接入 Ollama、硅基流动、百炼等 OpenAI-compatible 来源。 +- 模型服务商、模型配置、路由规则、知识库模型绑定、调用日志核心表结构已落地(`docs/MODEL_PROVIDER_SCHEMA.sql`)。 +- `EmbeddingModelGateway` 和 `ChatModelGateway` 已落地,统一走 OpenAI-compatible 协议调用上游模型。 +- `AgentDefinitionController` 与 `AgentDefinitionServiceImpl` 已提供 Agent CRUD 与调试对话接口。 +- Agent 调试链路已接入:问题向量化 -> `rag_chunk_embedding` 召回 -> 组装上下文 -> Chat 回答 -> 返回引用切片。 ### 质量保障 - 后端结构稳定性单元测试。 - 前端组件与 API 单元测试。 +- Agent 结构与服务单元测试(`AgentComponentStructureTests`、`AgentDefinitionServiceImplTests`)。 ## 短期优先级 建议优先完成下面几项,把 RAG 上传解析切片链路升级为可检索链路: -1. 模型服务商配置:新增服务商、模型、路由规则和调用日志基础表。 -2. Embedding 网关:优先支持 OpenAI-compatible 接口,接入硅基流动或 Ollama Embedding。 -3. 向量写入:对 `rag_chunk` 调用 Embedding 模型并保存 `rag_chunk_embedding`。 -4. 索引任务入口:把文档或知识库的 `indexStatus` 推进为真实状态流转。 -5. 补齐重建索引、失败重试、最近任务接口。 -6. 前端接入模型配置、检索配置、最近任务和重建索引动作。 +1. 打通文档切片后的全量向量写入,确保 `rag_chunk_embedding` 可持续更新。 +2. 新增独立 RAG 检索问答接口,避免仅依赖 Agent 调试入口消费召回能力。 +3. 索引任务入口:把文档或知识库的 `indexStatus` 推进为真实状态流转。 +4. 补齐重建索引、失败重试、最近任务接口。 +5. 落地 Agent 会话持久化(`agent_session`、`agent_message`)与多轮上下文管理。 +6. 补齐 Agent 工具注册、工具调用协议和任务执行日志。 ## RAG 最小闭环 @@ -84,14 +88,14 @@ 1. ~~批量上传文件,自动创建 `sys_attachment` 与 `rag_document`。~~ 2. ~~调用解析入口,使用 Tika 抽取文本并更新 `parseStatus`。~~ 3. ~~根据切片策略生成 `rag_chunk`。~~ -4. 调用 Embedding 模型生成向量并写入 `rag_chunk_embedding`。 -5. 提供检索接口,按 query 向量召回切片并返回引用元数据。 +4. 调用 Embedding 模型生成向量并写入 `rag_chunk_embedding`(已被 Agent 调试链路消费)。 +5. 提供独立检索接口,按 query 向量召回切片并返回引用元数据。 ## Agent 核心能力 -RAG 数据链路稳定后,再进入 Agent 主线: +Agent 主线能力按以下顺序继续推进: -1. Agent 定义管理。 +1. ~~Agent 定义管理。~~ 2. 会话与消息模型。 3. 工具注册与工具调用协议。 4. Prompt 模板管理。 @@ -120,6 +124,8 @@ RAG 数据链路稳定后,再进入 Agent 主线: - RAG 文档批量上传接口:POST `/api/rag/documents/batchUpload`。 - RAG 文档解析接口:POST `/api/rag/documents/parse`,当前同步解析、保存解析快照并返回解析元数据。 - RAG 文档切片接口:POST `/api/rag/documents/chunk`,当前异步生成并替换 `rag_chunk`。 +- Agent 管理接口:`/api/agents/list`、`/api/agents/query`、`/api/agents/detail`、`/api/agents/save`、`/api/agents/delete`。 +- Agent 调试接口:POST `/api/agents/{agentId}/chat`,支持 `ragEnabled` 开关。 - 大整数 ID 通过 `@JsonSerialize(ToStringSerializer.class)` 输出为字符串。 ## 里程碑 @@ -137,7 +143,8 @@ RAG 数据链路稳定后,再进入 Agent 主线: ### 里程碑 3:Agent 最小运行时 -- 支持一个可配置 Agent、一个会话、一次模型调用、一次工具调用。 +- 已完成:支持一个可配置 Agent、一次模型调用与 RAG 召回调试链路。 +- 待完成:会话持久化、工具调用与任务编排。 ### 里程碑 4:平台管理化 diff --git a/rag-store-page-apis.md b/rag-store-page-apis.md index d85cfce..eed6ede 100644 --- a/rag-store-page-apis.md +++ b/rag-store-page-apis.md @@ -436,3 +436,14 @@ - 模型服务商与 Embedding 模型配置 - 检索配置 - 检索测试/召回预览 + +## 7. 与 Agent 调试链路的关联 + +当前 RAG 切片与向量数据已经被 Agent 调试页直接消费: + +- Agent 调试接口 `POST /api/agents/{agentId}/chat` 在 `ragEnabled=true` 时会读取 `rag_chunk_embedding` 进行 TopK 召回。 +- 若未完成切片向量化,Agent 调试会返回“未召回到可用知识切片”。 + +关联文档: + +- [Agent 页面后端接口清单](agent-page-apis.md) diff --git a/src/main/java/com/bruce/modelprovider/client/OpenAiCompatibleModelClient.java b/src/main/java/com/bruce/modelprovider/client/OpenAiCompatibleModelClient.java index c2d7ff4..60f44ef 100644 --- a/src/main/java/com/bruce/modelprovider/client/OpenAiCompatibleModelClient.java +++ b/src/main/java/com/bruce/modelprovider/client/OpenAiCompatibleModelClient.java @@ -13,6 +13,10 @@ public interface OpenAiCompatibleModelClient { * 方法 embeddings,用于定义接口能力契约。 */ List> embeddings(ModelProvider provider, ModelConfig model, List texts, Integer expectedDimension); + /** + * 方法 chatCompletions,用于定义接口能力契约。 + */ + OpenAiChatCompletionResult chatCompletions(ModelProvider provider, ModelConfig model, List messages); /** * 方法 health,用于定义接口能力契约。 */ diff --git a/src/main/java/com/bruce/modelprovider/client/OpenAiCompatibleModelClientImpl.java b/src/main/java/com/bruce/modelprovider/client/OpenAiCompatibleModelClientImpl.java index b1e5afb..d736651 100644 --- a/src/main/java/com/bruce/modelprovider/client/OpenAiCompatibleModelClientImpl.java +++ b/src/main/java/com/bruce/modelprovider/client/OpenAiCompatibleModelClientImpl.java @@ -1,10 +1,13 @@ package com.bruce.modelprovider.client; +import com.bruce.modelprovider.config.AiSecretProperties; import com.bruce.modelprovider.entity.ModelConfig; import com.bruce.modelprovider.entity.ModelProvider; +import lombok.RequiredArgsConstructor; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; import org.springframework.web.client.RestClient; import java.util.ArrayList; @@ -22,11 +25,17 @@ import java.util.Map; * 4. API Key 从 `secretRef` 对应环境变量读取,不在代码中硬编码。 */ @Component +@RequiredArgsConstructor /** * OpenAiCompatibleModelClientImpl,负责模型平台对应层的职责。 */ public class OpenAiCompatibleModelClientImpl implements OpenAiCompatibleModelClient { + /** + * 统一读取独立 AI 配置文件中的密钥映射。 + */ + private final AiSecretProperties aiSecretProperties; + /** * 调用上游 Embedding 接口并解析向量数组。 */ @@ -74,6 +83,63 @@ public class OpenAiCompatibleModelClientImpl implements OpenAiCompatibleModelCli return vectors; } + @Override + @SuppressWarnings("unchecked") + public OpenAiChatCompletionResult chatCompletions(ModelProvider provider, ModelConfig model, List messages) { + if (messages == null || messages.isEmpty()) { + throw new IllegalArgumentException("聊天消息不能为空"); + } + RestClient client = RestClient.builder().baseUrl(provider.getBaseUrl()).build(); + + List> payloadMessages = new ArrayList<>(); + for (OpenAiChatMessage message : messages) { + if (message == null || !StringUtils.hasText(message.getContent())) { + continue; + } + Map item = new HashMap<>(); + item.put("role", StringUtils.hasText(message.getRole()) ? message.getRole().trim() : "user"); + item.put("content", message.getContent()); + payloadMessages.add(item); + } + if (payloadMessages.isEmpty()) { + throw new IllegalArgumentException("聊天消息内容不能为空"); + } + + Map body = new HashMap<>(); + body.put("model", model.getUpstreamModel()); + body.put("messages", payloadMessages); + + RestClient.RequestBodySpec request = client.post().uri("/chat/completions") + .contentType(MediaType.APPLICATION_JSON) + .body(body); + String apiKey = resolveApiKey(provider); + if (apiKey != null) { + request = request.header(HttpHeaders.AUTHORIZATION, "Bearer " + apiKey); + } + + Map response = request.retrieve().body(Map.class); + if (response == null || !(response.get("choices") instanceof List choices) || choices.isEmpty()) { + throw new IllegalStateException("上游Chat响应缺少choices字段"); + } + Object first = choices.getFirst(); + if (!(first instanceof Map firstChoice) + || !(firstChoice.get("message") instanceof Map message) + || !(message.get("content") instanceof String content) + || !StringUtils.hasText(content)) { + throw new IllegalStateException("上游Chat响应缺少message.content"); + } + + OpenAiChatCompletionResult result = new OpenAiChatCompletionResult(); + result.setUpstreamRequestId(String.valueOf(response.get("id"))); + result.setContent(content); + if (response.get("usage") instanceof Map usage) { + result.setPromptTokens(toInteger(usage.get("prompt_tokens"))); + result.setCompletionTokens(toInteger(usage.get("completion_tokens"))); + result.setTotalTokens(toInteger(usage.get("total_tokens"))); + } + return result; + } + /** * 调用 `/models` 做健康探测:成功返回 true,异常返回 false。 */ @@ -98,14 +164,34 @@ public class OpenAiCompatibleModelClientImpl implements OpenAiCompatibleModelCli /** * 读取服务商密钥: - * 有 secretRef 时从环境变量读取;首期不使用数据库密钥明文。 + * 1) 优先读取 Spring AI 独立配置文件(ai-config.ini); + * 2) 再读取环境变量,兼容原有部署方式; + * 3) 最后回退数据库密文/占位字段(兼容历史数据)。 */ private String resolveApiKey(ModelProvider provider) { if (provider.getSecretRef() != null && !provider.getSecretRef().isBlank()) { - return System.getenv(provider.getSecretRef().trim()); + String secretRef = provider.getSecretRef().trim(); + String fromSpringConfig = aiSecretProperties.getApiKeyBySecretRef(secretRef); + if (StringUtils.hasText(fromSpringConfig)) { + return fromSpringConfig; + } + String fromEnv = System.getenv(secretRef); + if (StringUtils.hasText(fromEnv)) { + return fromEnv.trim(); + } + } + if (StringUtils.hasText(provider.getApiKeyCipher())) { + return provider.getApiKeyCipher().trim(); } return null; } + + private Integer toInteger(Object value) { + if (value == null) { + return null; + } + return Integer.valueOf(String.valueOf(value)); + } } diff --git a/src/main/java/com/bruce/rag/mapper/RagChunkEmbeddingMapper.java b/src/main/java/com/bruce/rag/mapper/RagChunkEmbeddingMapper.java index a8b03ab..d3d138e 100644 --- a/src/main/java/com/bruce/rag/mapper/RagChunkEmbeddingMapper.java +++ b/src/main/java/com/bruce/rag/mapper/RagChunkEmbeddingMapper.java @@ -1,9 +1,32 @@ package com.bruce.rag.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.bruce.rag.dto.response.RagChunkRecallResponse; import com.bruce.rag.entity.RagChunkEmbedding; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; @Mapper public interface RagChunkEmbeddingMapper extends BaseMapper { + + @Select(""" + SELECT + e.chunk_id AS chunkId, + e.document_id AS documentId, + c.chunk_content AS chunkContent, + 1 - (e.embedding <=> CAST(#{queryVector} AS vector)) AS score + FROM rag_chunk_embedding e + INNER JOIN rag_chunk c ON c.id = e.chunk_id + WHERE e.store_id = #{storeId} + AND e.enabled = TRUE + AND c.enabled = TRUE + ORDER BY e.embedding <=> CAST(#{queryVector} AS vector) + LIMIT #{topK} + """) + List queryTopKByStore(@Param("storeId") Long storeId, + @Param("queryVector") String queryVector, + @Param("topK") int topK); }