feat(modelprovider): 完善模型调用与RAG召回支撑

This commit is contained in:
2026-05-31 23:56:31 +08:00
parent 1e004f1a83
commit ab9b099e9b
9 changed files with 295 additions and 58 deletions

View File

@@ -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. 文档用途说明

View File

@@ -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)
## 参考资料

View File

@@ -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 适配层、工作流编排和前端管理台。

View File

@@ -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 '更新者';

View File

@@ -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 主线:
### 里程碑 3Agent 最小运行时
- 支持一个可配置 Agent、一个会话、一次模型调用、一次工具调用
- 已完成:支持一个可配置 Agent、一次模型调用与 RAG 召回调试链路
- 待完成:会话持久化、工具调用与任务编排。
### 里程碑 4平台管理化

View File

@@ -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)

View File

@@ -13,6 +13,10 @@ public interface OpenAiCompatibleModelClient {
* 方法 embeddings用于定义接口能力契约。
*/
List<List<Double>> embeddings(ModelProvider provider, ModelConfig model, List<String> texts, Integer expectedDimension);
/**
* 方法 chatCompletions用于定义接口能力契约。
*/
OpenAiChatCompletionResult chatCompletions(ModelProvider provider, ModelConfig model, List<OpenAiChatMessage> messages);
/**
* 方法 health用于定义接口能力契约。
*/

View File

@@ -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<OpenAiChatMessage> messages) {
if (messages == null || messages.isEmpty()) {
throw new IllegalArgumentException("聊天消息不能为空");
}
RestClient client = RestClient.builder().baseUrl(provider.getBaseUrl()).build();
List<Map<String, String>> payloadMessages = new ArrayList<>();
for (OpenAiChatMessage message : messages) {
if (message == null || !StringUtils.hasText(message.getContent())) {
continue;
}
Map<String, String> 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<String, Object> 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<String, Object> 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));
}
}

View File

@@ -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<RagChunkEmbedding> {
@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<RagChunkRecallResponse> queryTopKByStore(@Param("storeId") Long storeId,
@Param("queryVector") String queryVector,
@Param("topK") int topK);
}