--- title: "AgentKit 门户平台整体演进路线" type: feat date: 2026-06-24 origin: docs/brainstorms/2026-06-24-portal-platform-evolution-requirements.md deepened: 2026-06-24 --- # AgentKit 门户平台整体演进路线 ## Summary 按优先级串行推进 AgentKit 门户平台演进:P1 用 LlamaIndex 构建工业级 RAG 管道 + TaskIQ 异步任务基础;P2 扩展多端消息接入与 MCP Server 认证发布;P3 用 LiteLLM/langchain-mcp-adapters 替换 commodity 层降本。差异化能力(Agent 引擎/专家团队/自进化/终端安全)保持自研,不在本计划范围内。 ## Problem Frame AgentKit 定位为企业级统一 AI Agent 门户平台。对标 MaxKB 后发现四方面差距:RAG 管道是开发者级组件非工业级产品(上传端点从未调用向量化,KB 存储仅内存);平台触达仅有 RAG 数据源适配器无消息适配器;MCP Server 零认证且未支持 Skill/专家团队发布;commodity 层大量自研维护成本高。 本次演进为预防性演进 + 必备功能补齐。目标是补齐门户平台应有的能力,使 AgentKit 在企业级 AI Agent 平台赛道具备完整竞争力。 ## Requirements ### RAG 工业级管道(P1) R1. 企业用户可上传文档到知识库,文档经 LlamaIndex 管道处理(解析→分段→预览→向量化→索引)后可被检索。现有 `memory/local_rag.py` 的 `LocalRAGService` 对 KB 场景废弃,Agent 记忆(WorkingMemory/EpisodicMemory/SemanticMemory)保留不动。 R2. 知识库支持双索引检索:pgvector 语义检索 + PostgreSQL 全文检索(jieba 中文分词),提供 embedding/keywords/blend 三种模式。检索模式由企业用户按知识库配置默认值,Agent 运行时可按查询特征覆盖。 R3. 文档分段支持智能分段与高级分段(LlamaIndex IngestionPipeline),企业用户可在向量化前预览分段结果(只读预览,编辑能力延后)。 R4. 系统为文档段落自动生成相关问题(LLM-based,参考现有 `memory/contextual_retrieval.py` 的 ContextualChunker 模式),提升检索召回率。 R5. 系统支持术语表(Termbase),通过 jieba 自定义词典增强中文分词,提升领域术语检索准确率。 R6. 知识库支持命中处理模式:模型优化模式(LLM 基于检索结果生成回答)与直接回答模式(直接返回匹配段落),按 KB 配置默认模式,Agent 可按查询场景覆盖。 R7. 检索结果经 rerank 模型重排后返回(API-based reranker,可配置 Cohere Rerank 或 BGE-Reranker)。 R8. 知识库实施 per-KB 访问控制(owner/authorized-users),文档上传验证文件类型(白名单)、强制大小限制、索引前净化解析内容(markdown sanitize、PDF 解析安全)。Agent 检索限定于调用用户授权的知识库。 R9. 知识库元数据持久化到 PostgreSQL(KB 源、文档记录、ACL),重启不丢失。现有内存 `KnowledgeSourceStore` 替换为 PG 后端。 R10. 文档向量化通过 TaskIQ 异步执行(复用现有 Redis 作为 broker),提供进度展示、失败通知与重试、任务历史。文档状态模型:pending → parsing → segmenting → vectorizing → indexed | failed(含 error_message)。 ### 平台触达扩展(P2) R11. 系统支持企微/钉钉/飞书/Slack 消息接入。各适配器验证平台签名/token(飞书 encrypt_key、钉钉 token、企微 EncodingAESKey)后处理消息,拒绝未认证请求。 R12. 平台凭证存储于加密 DB 列(master key 来自环境变量),定义轮换策略与访问审计。现有明文 `ProviderConfig.api_key` 同步迁移。 R13. MCP Server 合并至主 FastAPI app(`/api/v1/mcp/` 路由),所有端点要求认证与授权(复用 `require_permission` + API Key)。现有独立 `mcp/server.py` 重构为路由工厂。 R14. 企业用户/开发者可将 Skill/专家团队发布为 MCP 工具(配置:工具名称、描述、输入 schema、鉴权方式、速率限制),发布需管理员级授权。外部 AI 系统通过 MCP 协议认证调用。 ### 生态替换降本(P3) R15. LLM Provider 底层替换为 LiteLLM:6 个直接 API provider(OpenAI/Anthropic/Gemini/Doubao/Wenxin/Yuanbao)走 LiteLLM 统一接口。上层网关逻辑(fallback/用量追踪/部门级配额)保留自研。`RemoteLLMProvider`(客户端→服务端代理)保留不动。 R16. MCP 客户端替换为 `langchain-mcp-adapters`:跟进行业协议演进,降低自研 3 传输层(Stdio/HTTP/SSE)维护成本。 R17. 自研语义缓存替换为 LiteLLM 内置 Redis Semantic Cache。阈值调优(默认 0.87,约 13% 误命中风险)。现有 `llm/cache.py` 废弃。 ## Key Technical Decisions **KTD1: LlamaIndex 作为 RAG 管道框架。** 外部研究确认 LlamaIndex 2026 原生覆盖所有所需能力(双索引/智能分段/rerank/问题生成),pgvector 一等支持。相比从零构建避免重复造轮子;相比集成 MaxKB 独立服务避免引入 Django + 独立 PG 的运维复杂度。风险:LlamaIndex 频繁 breaking changes → 通过版本锁定 + 集成测试缓解。 **KTD2: TaskIQ 替代 Celery 作为异步任务队列。** 外部研究确认 Celery 对 asyncio 原生栈过度设计(引入 broker + worker + beat = 3 个新运维组件)。TaskIQ 提供一等 FastAPI 集成、Redis broker 支持、asyncio 原生。R10 提前至 P1 解决文档向量化阻塞事件循环的优先级依赖冲突。ARQ 已废弃不采用。 **KTD3: KB 元数据持久化到 PostgreSQL。** 遵循 `memory/episodic.py` 的 EpisodicMemory 模式(SQLAlchemy async session + PG)。KB 源、文档记录、ACL 存关系表,embedding 存 pgvector。替换现有内存 `KnowledgeSourceStore`。 **KTD4: MCP Server 合并至主 FastAPI app。** 现有 `mcp/server.py` 独立 app 零认证是 RCE 面(终端工具存在)。合并为 `/api/v1/mcp/` 子路由,复用 `require_permission` + `APIKeyHeader` 认证。独立 `MCPServer` 类重构为路由工厂。 **KTD5: Per-KB ACL 通过新 `kb_acl` 表实现。** 遵循现有 `filter_kb_sources_by_department` 模式,新增 `kb_acl` 表(kb_id, user_id, role: owner/viewer)。`kb_acl` 表定义于 `rag_platform/store.py`(PostgreSQL,与 KB 元数据同库)以保证事务边界一致 — 不放在 `server/auth/models.py`。`kb_acl.kb_id` 外键 → KB 表 `id` ON DELETE CASCADE。Agent 检索时通过 `filter_kb_by_user_acl()` 过滤,与部门级过滤并行。ACL 变更必须触发检索缓存失效。 **KTD6: 应用层 jieba 分词实现中文全文检索。** PostgreSQL 内置 `tsvector` 不支持中文分词。在 Python 层用 jieba 分词后写入 `tsvector`,避免安装 PG 扩展(pg_jieba/zhparser)的运维复杂度,也避免引入 Elasticsearch 外部搜索引擎。术语表通过 jieba 自定义词典实现。 **KTD7: LiteLLM 替换直接 provider,RemoteLLMProvider 保留。** LiteLLM 原生支持 Volcengine/Doubao;Wenxin/Yuanbao 通过 OpenAI 兼容端点。`RemoteLLMProvider` 是客户端→服务端代理(架构上不同于直接 API provider),LiteLLM 无法替代。fallback/用量追踪保留自研上层逻辑,底层 provider 适配走 LiteLLM。语义缓存在 P3(U17)由自研替换为 LiteLLM 内置 Redis Semantic Cache — KTD7 保留自研指的是 P1/P2 阶段,P3 完成后自研缓存废弃。 **KTD8: 加密 DB 列存储平台凭证。** 单部署企业场景下,加密 DB 列 + master key 足够。避免引入 HashiCorp Vault 外部依赖。加密算法强制 AES-256-GCM(非泛指 "AES-256"),每行使用随机 96-bit nonce 与密文一同存储。采用 envelope encryption(master key 包裹 per-row data key)或 HKDF with per-row salt 派生 per-row 密钥。生产环境 master key 必须存储于云 KMS(AWS KMS / 阿里云 KMS),应用启动 guard 在生产模式下若仅检测到环境变量 key 则拒绝启动;环境变量仅作为开发环境 fallback。凭证轮换通过 API 触发 re-encrypt。访问审计记录到现有审计日志。Master key 轮换采用双密钥窗口策略:新 key 与旧 key 同时有效(DB 列存储 key_id 标识),后台批量 re-encrypt 旧密钥数据到新密钥,完成后旧 key 失效。Master key 泄露恢复流程从 Deferred 提升至 Risks(见 Risks & Dependencies)。 **KTD9: 新建 `src/agentkit/rag_platform/` 顶层模块。** 与 `memory/` 职责分离:`rag_platform/` 服务企业知识库场景,`memory/` 服务 Agent 运行时记忆。`LocalRAGService` 对 KB 场景废弃,Agent 记忆(EpisodicMemory)保留使用。明确决策:`rag_platform/` 定义自己的检索模型;现有 `memory/knowledge_base.py` 中的 `KnowledgeBase` protocol 对 KB 用途废弃。`MemoryRetriever` 将在新的单元中重新接线,直接调用 `rag_platform/retrieval.py`。由于当前无外部代码 import `LocalRAGService`,"代码重复"顾虑不再成立 — 真正的问题是 protocol 复用,答案是:新 protocol、清晰边界、`MemoryRetriever` 内置 adapter。 **KTD10: 成功标准从"MaxKB 功能对等"重构为"用户结果导向"。** MaxKB 是 RAG 知识库产品,AgentKit 是 Agent 平台。对标不同产品类别的功能对等可能构建不服务于实际用户的能力。成功标准改为:企业用户可上传文档、配置检索、测试召回、通过多端使用 Agent 检索知识库。 **KTD11: RetrievalPrincipal 用于非交互路径的 ACL 强制执行。** 定义 `RetrievalPrincipal` 概念,封装用户身份用于 ACL 过滤。WebSocket chat:principal = JWT 用户。MCP 工具调用:principal = per-client API Key 绑定的身份(要求 per-client keys,非全局 key)。TaskIQ worker:principal 序列化进任务 payload 并在 worker 内 re-hydrate。多端 webhook:IM 用户 → AgentKit 用户映射步骤。没有此机制,非交互路径的 ACL 会被静默绕过。 ## High-Level Technical Design ```mermaid flowchart TB subgraph P1["P1: RAG 工业级管道 + 异步任务"] U1[U1 RAG 平台骨架] --> U2[U2 KB 持久化 + ACL] U2 --> U3[U3 文档处理管道] U3 --> U4[U4 双索引检索] U4 --> U5[U5 Rerank/问题生成/术语表] U5 --> U6[U6 命中处理 + KB 设置] U3 --> U7[U7 上传安全 + 净化] U3 --> U8[U8 TaskIQ 异步任务] U6 --> U9[U9 前端 KB 管理] U8 --> U9 end subgraph P2["P2: 平台触达扩展"] U10[U10 适配器骨架 + secrets] --> U11[U11 飞书 IM] U11 --> U12[U12 钉钉/企微/Slack] U13[U13 MCP 认证 + 合并] U13 --> U14[U14 Skill/团队 MCP 发布] end subgraph P3["P3: 生态替换降本"] U15[U15 LiteLLM Provider] --> U17[U17 LiteLLM 语义缓存] U16[U16 langchain-mcp-adapters] end P1 --> P2 --> P3 ``` ### 文档处理管道状态机 ```mermaid stateDiagram-v2 [*] --> pending: 上传 pending --> parsing: TaskIQ 接收 parsing --> segmenting: 解析成功 parsing --> failed: 解析失败 segmenting --> vectorizing: 预览确认/自动 segmenting --> failed: 分段失败 vectorizing --> indexed: 向量化+索引成功 vectorizing --> failed: 向量化失败 failed --> pending: 用户重试 indexed --> [*] ``` ### 检索流程 ```mermaid flowchart LR Q[Agent 查询] --> ACL{Per-KB ACL 过滤} ACL -->|授权| Mode{检索模式} Mode -->|embedding| Sem[pgvector 语义] Mode -->|keywords| FT[PG 全文 jieba] Mode -->|blend| Both[双索引合并] Sem --> Rerank[rerank 模型] FT --> Rerank Both --> Rerank Rerank --> Hit{命中处理} Hit -->|model_opt| LLM[LLM 生成回答] Hit -->|direct| Return[返回匹配段落] LLM --> Result[检索结果] Return --> Result ``` ## Implementation Units ### P1: RAG 工业级管道 + 异步任务基础 --- ### U1. RAG 平台模块骨架 + LlamaIndex 集成 - **Goal:** 创建 `src/agentkit/rag_platform/` 模块,集成 LlamaIndex 作为管道框架,连接现有 pgvector。 - **Files:** - `src/agentkit/rag_platform/__init__.py` — 模块入口 - `src/agentkit/rag_platform/models.py` — Pydantic 数据模型(KB、Document、Chunk、QueryResult) - `src/agentkit/rag_platform/pipeline.py` — LlamaIndex IngestionPipeline 封装 - `src/agentkit/rag_platform/indexing.py` — pgvector 索引管理(LlamaIndex PGVectorStore) - **Patterns:** 遵循现有模块结构(cf. `memory/__init__.py`, `mcp/__init__.py`);LlamaIndex `PGVectorStore` 连接现有 PostgreSQL。 - **pgvector Schema Isolation:** LlamaIndex `PGVectorStore` 必须使用显式表名(如 `rag_platform_kb_chunks`),不可使用默认 `data_`。确认 `create_if_not_exists` 不会触碰 `episodic_memory` 或任何 `memory/` 所属表。KB chunk 表(含 `search_vector`)与 LlamaIndex 向量表应统一为单表(同时含两列)或通过 FK 关联并维持同步不变式:每个 chunk 行恰好对应一个 embedding 行。 - **Test scenarios:** - LlamaIndex PGVectorStore 连接现有 pgvector 扩展 - 基础 ingest(文档 → chunk → embedding → pgvector INSERT)端到端工作 - 基础 query(query → embedding → pgvector cosine 检索)返回结果 - **Verification:** `pytest tests/unit/rag_platform/test_pipeline.py` --- ### U2. KB 持久化存储 + Per-KB 访问控制 - **Goal:** 替换内存 `KnowledgeSourceStore` 为 PostgreSQL 持久化,实现 per-KB ACL。 - **Files:** - `src/agentkit/rag_platform/store.py` — KB/Document 持久化(SQLAlchemy async)+ `kb_acl` 表定义 - `src/agentkit/rag_platform/models.py` — ORM 模型(SQLAlchemy 2 `DeclarativeBase` + `Mapped`) - `src/agentkit/rag_platform/acl.py` — per-KB ACL 逻辑 - `src/agentkit/server/routes/kb_management.py` — 替换 `KnowledgeSourceStore` 调用 - **Patterns:** 遵循 `memory/episodic.py` 的 EpisodicMemory PG 模式(async session);遵循 `filter_kb_sources_by_department` 模式实现 `filter_kb_by_user_acl()`。使用 SQLAlchemy 2 ORM(`DeclarativeBase` + `Mapped`)而非原始 SQL — 便于 Alembic 迁移演进 schema。Alembic 迁移在本单元范围内。 - **Migration note:** 现有内存 `KnowledgeSourceStore` 数据是 ephemeral 的;首次 PG 后端启动时,若内存 store 非空,记录 warning 日志以便运维重新注册 KB。这对未在 config 中捕获的 KB 状态是破坏性变更。 - **Invariant:** ACL 条目与 KB 元数据共享事务边界(同一 PG DB)。`kb_acl.kb_id` FK → KB 表 `id` ON DELETE CASCADE。 - **Test scenarios:** - KB 元数据写入 PG,重启后仍存在 - owner 用户可查询自己的 KB - 非 authorized 用户查询 KB 被拒绝 - Agent 检索时 ACL 过滤生效(仅返回授权 KB 的结果) - **Verification:** `pytest tests/unit/rag_platform/test_store.py tests/unit/rag_platform/test_acl.py` --- ### U3. 文档处理管道(LlamaIndex 分段 + 预览 + 向量化) - **Goal:** 连接上传→解析→分段→预览→向量化→索引管道,使用 LlamaIndex IngestionPipeline。 - **Files:** - `src/agentkit/rag_platform/document_processor.py` — 文档处理管道 - `src/agentkit/rag_platform/preview.py` — 分段预览 API - `src/agentkit/server/routes/kb_management.py` — 重写 `upload_document()` 端点 - **Patterns:** LlamaIndex `IngestionPipeline`(jieba-aware 自定义 SentenceSplitter + MetadataExtractor);现有 `memory/document_loader.py` 的 `DocumentLoader` 用于解析;文档状态模型(pending→parsing→segmenting→vectorizing→indexed|failed)。LlamaIndex 默认 `SentenceSplitter` 按英文标点/空格切分,中文场景需自定义 splitter(基于 jieba 分词边界切分)以保证分段质量。分段预览端点必须复用 `require_permission` + per-KB ACL 校验(owner/viewer 可预览,其他拒绝)。 - **Failure & Retry Semantics:** 向量化是 all-or-nothing(单个 PG 事务包裹所有 chunk+embedding INSERT)。失败时部分工作回滚。`segmenting` 阶段产生的孤儿 chunks 标记为 `orphaned` 并从检索中排除。重试从 `pending` 重新处理,按 document hash + chunk hash 去重。不变式:检索永不返回来自非 `indexed` 文档的 chunk。 - **Test scenarios:** - 上传 PDF → 解析 → 分段 → 返回预览(只读) - 确认预览 → 向量化 → 索引 → 可检索 - 解析失败 → 状态 failed + error_message - 向量化失败 → 状态 failed + error_message - 重复上传同一文档 → 拒绝或更新(非创建重复) - **Verification:** `pytest tests/unit/rag_platform/test_document_processor.py` --- ### U4. 双索引检索(pgvector 语义 + PG 全文检索 with jieba) - **Goal:** 实现双索引检索,支持 embedding/keywords/blend 三种模式。 - **Files:** - `src/agentkit/rag_platform/retrieval.py` — 检索逻辑(三模式) - `src/agentkit/rag_platform/fulltext.py` — jieba 分词 + tsvector 写入/查询 - `src/agentkit/rag_platform/models.py` — 新增 `RetrievalRequest` 模型(含可选 `retrieval_mode` 与 `hit_processing_mode` 覆盖字段,默认值为 KB 配置值) - **Patterns:** LlamaIndex hybrid retriever(VectorStoreRetriever + NLSQLRetriever 或自定义);jieba 在 Python 层分词后写入 `search_vector` 列。集成机制:Python 层调用 `jieba.cut(text)` 得到 token 列表,用空格连接后写入 `tsvector` 列(`to_tsvector('simple', space_joined_tokens)`),查询时同样用 jieba 分词后构造 tsquery。避免依赖 PG 扩展(pg_jieba/zhparser)。 - **Agent access:** Agent 通过 `MemoryRetriever` 参数访问(隐式,按 session 配置)— 不是单独的 Tool。Chat handler 通过 Agent context 传播 per-query 覆盖。 - **Test scenarios:** - embedding 模式:语义检索返回相关结果 - keywords 模式:中文全文检索返回包含关键词的结果 - blend 模式:合并语义+全文结果,去重排序 - 查询无结果时返回空列表(非报错) - **Verification:** `pytest tests/unit/rag_platform/test_retrieval.py tests/unit/rag_platform/test_fulltext.py` --- ### U5. Rerank + 问题生成 + 术语表 - **Goal:** 添加 rerank 模型重排、问题自动生成、术语表支持。 - **Files:** - `src/agentkit/rag_platform/rerank.py` — rerank 模型集成(Cohere/BGE-Reranker 可配置) - `src/agentkit/rag_platform/question_gen.py` — LLM-based 问题生成 - `src/agentkit/rag_platform/termbase.py` — 术语表管理 + jieba 自定义词典 - **Patterns:** LlamaIndex rerankers(`CohereRerank` 或 `SentenceTransformerRerank`);参考 `memory/contextual_retrieval.py` 的 ContextualChunker 模式生成问题;jieba `load_userdict()` 加载术语表。Rerank API 调用将文档 chunks 发送到第三方(Cohere 等),需在 KB 设置中标注数据出境风险并提供本地部署选项(BGE-Reranker via Xinference)作为敏感数据 KB 的默认。 - **Test scenarios:** - rerank 后结果相关性顺序改善 - 问题生成产生与段落内容相关的问题 - 术语表中的领域术语被正确分词 - 术语表增强后检索召回率提升 - **Verification:** `pytest tests/unit/rag_platform/test_rerank.py tests/unit/rag_platform/test_question_gen.py tests/unit/rag_platform/test_termbase.py` --- ### U6. 命中处理模式 + KB 设置 - **Goal:** 实现命中处理模式(模型优化/直接回答)+ KB 级别设置。 - **Files:** - `src/agentkit/rag_platform/hit_processing.py` — 命中处理逻辑 - `src/agentkit/rag_platform/settings.py` — KB 设置模型(检索模式默认/命中处理默认/授权用户) - `src/agentkit/server/routes/kb_management.py` — KB 设置端点 - **Patterns:** 模型优化模式调用现有 LLM Gateway;直接回答模式返回匹配段落;KB 设置存 PG。KB 设置端点必须复用 `require_permission` + per-KB ACL 校验(仅 owner 可修改设置,viewer 只读)。 - **Test scenarios:** - model_opt 模式:LLM 基于检索结果生成回答 - direct 模式:直接返回匹配段落 - KB 设置默认模式生效 - Agent 运行时覆盖默认模式 - **Verification:** `pytest tests/unit/rag_platform/test_hit_processing.py tests/unit/rag_platform/test_settings.py` --- ### U7. 文件上传安全 + 内容净化 - **Goal:** 后端文件类型白名单 + 内容净化。 - **Depends on:** U3(U7 重写 `upload_document()` 端点,U3 也重写同一端点 — 两者必须协同实施,U7 的白名单/净化逻辑嵌入 U3 的上传管道) - **Files:** - `src/agentkit/rag_platform/sanitize.py` — 内容净化(markdown sanitize + PDF 安全) - `src/agentkit/server/routes/kb_management.py` — 上传端点增加白名单验证 - **Patterns:** `memory/document_loader.py` 的模块级函数 `_detect_format()`(注意:是模块级函数,非 `DocumentLoader` 方法)映射作为白名单源;`bleach` 或 `markdown` 库净化 HTML/markdown;PDF 解析限制页面数/大小。 - **Expanded attack surface:** - (a) ZIP 类格式(`.docx/.xlsx/.pptx`)的解压比率限制 — 比率 > 100:1 或解压后 > N MB 时拒绝(防 zip bomb)。 - (b) XML parser 加固 — 对 XML-based 格式禁用 ENTITY 解析、外部 DTD、XInclude(防 XXE)。 - (c) URL egress 过滤 — deny by default(allowlist 模式)。Blocked ranges 必须包含:127.0.0.0/8(loopback)、10.0.0.0/8、172.16.0.0/12、192.168.0.0/16(RFC1918)、169.254.0.0/16(link-local + cloud metadata)、::1(IPv6 loopback)、fc00::/7(IPv6 ULA)、fe80::/10(IPv6 link-local)。优先使用 egress allowlist(resolve target,仅允许 public IP)以覆盖未来内部范围。 - (d) 嵌入图片的像素数上限(防 image bomb)。 - (e) 若使用 LlamaParse 托管服务,添加与 U5 rerank note 相同的数据出境警告 + per-KB opt-in。 - **Test scenarios:** - 白名单外文件类型被拒绝(.exe, .sh 等) - 超大小限制文件被拒绝 - markdown 中 `