diff --git a/README.md b/README.md index 829a752..ea6ad8d 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Skill = SkillConfig + 绑定 Tools。一个 Skill 代表一个可执行技能, ### 4. 意图路由 -两级路由:Level 1 关键词匹配(零成本,~0ms),Level 2 LLM 分类(回退方案,~200 tokens)。自动将用户输入路由到最佳匹配的 Skill。 +请求预处理(`RequestPreprocessor`,详见第 7 节)按前缀分流:`@skill:xxx` 显式选技能、琐碎输入走 `DIRECT_CHAT`、其余走 `REACT`。旧的 3 层 `CostAwareRouter`(含 `RegexRules` / `HeuristicClassifier` / `SemanticRouter` / `Vickrey Auction`)已被 `RequestPreprocessor` 替换;`IntentRouter`(`router/intent.py`)存在但未接入 chat 流程。 ### 5. 记忆系统 @@ -70,28 +70,21 @@ Skill = SkillConfig + 绑定 Tools。一个 Skill 代表一个可执行技能, - **Prompt 优化** -- 遗传算法 + A/B 测试自动优化 Prompt - **路径优化** -- 分析工具调用路径,推荐更优执行策略 -### 7. 三层意图路由 +### 7. 请求预处理(RequestPreprocessor) -CostAwareRouter 三层路由,从零成本到高成本逐层升级: +`RequestPreprocessor`(`chat/request_preprocessor.py`)按前缀分流,零成本路由: -| Layer | 方法 | 延迟 | Token 消耗 | 说明 | -|-------|------|------|-----------|------| -| 0 | 正则规则 | ~0ms | 0 | 问候/简单对话/@team/@skill 前缀直接回复 | -| 1 | 启发式分类 | ~0ms | 0 | 关键词 + 模式匹配 + 复杂度评估 | -| 1.5 | 语义路由 | ~0ms | 0 | 向量相似度匹配(可选) | -| 2 | LLM 分类 | ~500ms | ~200 | 回退方案,LLM 判断意图 | +| Layer | 触发条件 | 延迟 | Token | 路由结果 | +|-------|---------|------|-------|---------| +| 0 | `@skill:xxx` 前缀 | ~0ms | 0 | 显式技能选择(`SKILL_REACT` 或技能配置的模式) | +| 1 | 琐碎输入正则(问候/身份/事实/数学/翻译) | ~0ms | 0 | `DIRECT_CHAT`(由 `_TOOL_CONTEXT_RE` 守护) | +| 默认 | 其他输入 | ~0ms | 0 | `REACT`(LLM 在 agent 循环中自主决定工具使用) | -路由结果携带 `ExecutionMode` 枚举(`DIRECT_CHAT` / `REACT` / `SKILL_REACT` / `TEAM_COLLAB`),作为路由层与执行层的架构契约,杜绝硬编码。 +`@board` 前缀走 `BoardRouter`(多轮讨论),`@team` 前缀走 `ExpertTeamRouter`(流水线协作),均在 `RequestPreprocessor` 之前分流。 -### 8. 语义路由 +路由结果携带 `ExecutionMode` 枚举(`DIRECT_CHAT` / `REACT` / `SKILL_REACT` / `REWOO` / `REFLEXION` / `PLAN_EXEC` / `TEAM_COLLAB`),作为路由层与执行层的架构契约,杜绝硬编码。 -基于向量相似度的意图路由,作为关键词匹配的补充: - -- **SemanticRouter** -- 将用户输入和 Skill 描述向量化,通过余弦相似度匹配 -- **缓存友好** -- 向量缓存避免重复计算 -- **平滑降级** -- 语义路由失败时自动回退到启发式/LLM 分类 - -### 9. LLM 响应缓存 +### 8. LLM 响应缓存 语义相似度缓存,减少重复 LLM 调用: @@ -99,7 +92,7 @@ CostAwareRouter 三层路由,从零成本到高成本逐层升级: - **语义匹配** -- 相似 prompt 命中缓存,避免重复调用 - **TTL 管理** -- 缓存条目自动过期,支持手动失效 -### 10. 级联检测与状态持久化 +### 9. 级联检测与状态持久化 生产级故障防护: @@ -108,15 +101,15 @@ CostAwareRouter 三层路由,从零成本到高成本逐层升级: - **session_ttl** -- 可配置的会话 TTL,自动清理过期状态 - **优雅降级** -- Redis 不可用时自动降级到 InMemory,保持服务可用 -### 11. 产出质量管理 +### 10. 产出质量管理 四维质量检查:必填字段、最低字数、JSON Schema 校验、自定义验证器。检查不通过时自动重试(可配置 max_retries),重试时携带质量反馈信息。 -### 12. 标准化输出 +### 11. 标准化输出 Schema 验证 + 字段类型归一化(str -> int/float/bool)+ 元数据附加(version、produced_at、quality_score)。所有 Skill 产出统一为 StandardOutput 格式。 -### 13. 内置工具集 +### 12. 内置工具集 开箱即用的工具插件,覆盖常见 Agent 需求: @@ -136,7 +129,7 @@ Schema 验证 + 字段类型归一化(str -> int/float/bool)+ 元数据附 工具组合:`SequentialChain`(顺序链)、`ParallelFanOut`(并行扇出)、`DynamicSelector`(动态选择)。 -### 14. Pipeline 编排 +### 13. Pipeline 编排 多 Agent 协同编排,支持复杂工作流: @@ -146,7 +139,7 @@ Schema 验证 + 字段类型归一化(str -> int/float/bool)+ 元数据附 - **PipelineReflector** -- 执行反思与重规划 - **HandoffManager** -- Agent 间任务移交 -### 15. Expert Team Mode +### 14. Expert Team Mode 多专家协作执行复杂任务,B+C 混合模式(结构化协作计划 + 去中心化执行),前端以多角色对话流呈现: @@ -217,7 +210,7 @@ result = await orchestrator.execute_plan(plan) 用户也可在聊天中通过 `@team:researcher,writer,reviewer 任务描述` 前缀触发团队模式。 -### 16. 企业级客户端-服务端架构 +### 15. 企业级客户端-服务端架构 将 AgentKit 从纯本地运行架构演进为企业级客户端+服务端架构。客户端(Tauri 桌面端)作为 AI 工作台本地执行 Agent/终端/文件操作,服务端作为企业平台提供 LLM 网关(统一 Key 管理)、用户权限、审计日志、知识库共享能力。 @@ -298,7 +291,7 @@ provider = RemoteLLMProvider( response = await provider.chat(request) ``` -### 17. 文档处理能力 +### 16. 文档处理能力 Agent 内置文档生成与读取能力,Agent 通过 `DocumentTool` 自主创建 Word/Excel/PDF 文档、填充 Word 模板、读取多格式文档,无需用户手动操作 Office 软件。 @@ -402,15 +395,16 @@ result = await tool.execute( │ portal.py · chat.py · evolution.py · workflows.py │ │ auth.py · terminal_server.py · terminal_whitelist.py │ │ llm_gateway.py · config_sync.py · system.py · ... │ - │ 22个路由模块 · Agent Pool · Expert Team · Memory Store │ + │ 28个路由模块 · Agent Pool · Expert Team · Memory Store │ └──────────────────────────┼───────────────────────────────────┘ │ ┌──────────────┼──────────────┐ - │ CostAwareRouter │ - │ Layer 0: 正则规则 (0ms) │ - │ Layer 1: 启发式分类 (0ms) │ - │ Layer 1.5: 语义路由 (可选) │ - │ Layer 2: LLM分类 (~500ms) │ + │ RequestPreprocessor │ + │ @board → BoardRouter │ + │ @team → ExpertTeamRouter │ + │ Layer 0: @skill:xxx 前缀 │ + │ Layer 1: 琐碎输入正则 (0ms) │ + │ 默认: REACT (LLM 自主决策) │ │ → ExecutionMode 枚举契约 │ └──────┬───────────────┬───────┘ │ │ @@ -1220,26 +1214,19 @@ ReActEngine 实现 Think -> Act -> Observe 循环: 危险工具确认流:非白名单命令触发 `needs_confirmation`,用户确认后以 `_skip_dangerous_check=True` 重新执行,避免无限循环。 -### chat/skill_routing -- CostAwareRouter 三层路由 +### chat/request_preprocessor -- 请求预处理 -三层路由从零成本到高成本逐层升级: +按前缀分流的零成本路由: -| Layer | 组件 | 延迟 | Token | -|-------|------|------|-------| -| 0 | `RegexRules` | ~0ms | 0 | -| 1 | `HeuristicClassifier` | ~0ms | 0 | -| 1.5 | `SemanticRouter` | ~0ms | 0 | -| 2 | `LLMClassifier` | ~500ms | ~200 | +| Layer | 触发条件 | 延迟 | Token | 路由结果 | +|-------|---------|------|-------|---------| +| 0 | `@skill:xxx` 前缀 | ~0ms | 0 | 显式技能选择(`SKILL_REACT` 或技能配置的模式) | +| 1 | 琐碎输入正则 | ~0ms | 0 | `DIRECT_CHAT`(由 `_TOOL_CONTEXT_RE` 守护) | +| 默认 | 其他输入 | ~0ms | 0 | `REACT`(LLM 自主决策) | -路由结果包含 `ExecutionMode` 枚举(`DIRECT_CHAT` / `REACT` / `SKILL_REACT` / `TEAM_COLLAB`),作为路由层与执行层的架构契约。`complexity` 评分使用 `if is not None` 判断,避免 `0.0 or default` 误覆盖。`@team:expert1,expert2` 前缀直接路由到 `TEAM_COLLAB` 模式。 +路由结果包含 `ExecutionMode` 枚举(`DIRECT_CHAT` / `REACT` / `SKILL_REACT` / `REWOO` / `REFLEXION` / `PLAN_EXEC` / `TEAM_COLLAB`),作为路由层与执行层的架构契约。`@team:expert1,expert2` 前缀直接路由到 `TEAM_COLLAB` 模式(由 `ExpertTeamRouter` 处理),`@board` 前缀走 `BoardRouter`(多轮讨论)。 -### chat/semantic_router -- 语义路由 - -基于向量相似度的意图路由,作为关键词匹配的补充: - -- **SemanticRouter** -- 将用户输入和 Skill 描述向量化,通过余弦相似度匹配 -- **缓存友好** -- 向量缓存避免重复计算 -- **平滑降级** -- 语义路由失败时自动回退到启发式/LLM 分类 +旧的 3 层 `CostAwareRouter`(含 `RegexRules` / `HeuristicClassifier` / `SemanticRouter` / `Vickrey Auction`)已被 `RequestPreprocessor` 替换;`IntentRouter`(`router/intent.py`)存在但未接入 chat 流程;`AuctionHouse`(Vickrey 拍卖)位于 `marketplace/auction.py`(属于 marketplace 子系统,非路由)。 ### llm/gateway -- LLM Gateway @@ -1280,9 +1267,9 @@ SkillRegistry 管理 Skill 的注册、发现、更新。 团队生命周期:FORMING -> PLANNING -> EXECUTING -> SYNTHESIZING -> COMPLETED。失败时自动回退到单 Agent 模式(lead 或首个活跃专家)。 -### router/intent -- 意图路由(已升级为 chat/skill_routing) +### router/intent -- 意图路由(未接入 chat 流程) -原两级路由已升级为 CostAwareRouter 三层路由(详见 chat/skill_routing 模块详解)。 +`IntentRouter` 存在但未接入 chat 流程;当前 chat 请求由 `RequestPreprocessor`(详见 `chat/request_preprocessor` 模块详解)处理。本模块保留供未来扩展。 ### quality/gate -- 产出质量管理 @@ -1613,7 +1600,7 @@ async def generate_content(keyword: str, brand: str) -> dict: fischer-agentkit/ ├── src/agentkit/ # Python 后端 │ ├── bus/ # 消息总线(MemoryBus + RedisBus) -│ ├── chat/ # 聊天路由(CostAwareRouter + ExecutionMode) +│ ├── chat/ # 聊天路由(RequestPreprocessor + ExecutionMode) │ ├── cli/ # CLI 命令(Typer) │ ├── client/ # 客户端 SDK(ConfigSync + RemoteLLMProvider 集成) │ ├── core/ # 核心引擎(ReAct/Reflexion/ReWOO/ConfigDriven + HandoffTransport) diff --git a/src/agentkit/server/app.py b/src/agentkit/server/app.py index deaf64c..e02c393 100644 --- a/src/agentkit/server/app.py +++ b/src/agentkit/server/app.py @@ -800,7 +800,17 @@ def create_app( # that login (signing), whoami (verifying), and the middleware all use # the same secret. Without this, get_or_create_jwt_secret() would mint # a different random secret on every call and tokens could never verify. - jwt_secret = get_jwt_secret() or get_or_create_jwt_secret() + # + # ponytail: ephemeral secret is for token-signing only — passing it to + # AuthMiddleware would activate JWT verification in dev mode, breaking + # _is_dev_mode() and rejecting unauthenticated requests with 401 (root + # cause of test_portal_routes 17 failures). Only explicit AGENTKIT_JWT_SECRET + # activates middleware JWT verification; ephemeral stays on app.state for + # signing routes (auth.py). Ceiling: dev tokens signed with ephemeral + # secret still verify if a client somehow obtains them, but ephemeral + # secret is non-persistent and invalidated on restart by design. + explicit_jwt_secret = get_jwt_secret() # None when AGENTKIT_JWT_SECRET unset + jwt_secret = explicit_jwt_secret or get_or_create_jwt_secret() # for signing client_keys: dict[str, str] = {} try: from agentkit.server.middleware import _load_client_keys @@ -811,7 +821,7 @@ def create_app( app.add_middleware( AuthMiddleware, - jwt_secret=jwt_secret or "", + jwt_secret=explicit_jwt_secret or "", # only explicit secret activates JWT verify api_key=effective_api_key, client_keys=client_keys, )