feat(modelprovider): 完善模型调用与RAG召回支撑
This commit is contained in:
40
AGENT.md
40
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. 文档用途说明
|
||||
|
||||
|
||||
49
README.md
49
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)
|
||||
|
||||
## 参考资料
|
||||
|
||||
|
||||
@@ -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 适配层、工作流编排和前端管理台。
|
||||
|
||||
@@ -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 '更新者';
|
||||
|
||||
@@ -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:平台管理化
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,用于定义接口能力契约。
|
||||
*/
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user