# agent-engine-python **Repository Path**: kong0836/agent-engine-python ## Basic Information - **Project Name**: agent-engine-python - **Description**: Python版本的agent后端 - **Primary Language**: Python - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-18 - **Last Updated**: 2026-09-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # agent-engine-python * 本地 Agent 引擎的 Python 实现:uv workspace 多包工程,基于 FastAPI 构建。**与姊妹仓库 [agent-engine-java](../agent-engine-java) 功能完全一致**——同一套 Agent Loop 架构、同一份 SSE 协议契约、同一组配置项与数据库表,仅技术栈映射为 Python 生态;两仓库的移植映射与差异决策见 [docs/00-技术栈与架构映射](docs/00-技术栈与架构映射.md)。 ## 架构方案 * 与 Java 版同一套"模块化单体"设计:核心是 **Agent Loop(推理循环)**,MVC 只出现在 web 接入包内部。依赖方向遵循**依赖倒置**:`core` 定义 SPI(Protocol)且**零三方依赖**,实现包向上实现接口,`start` 作为组合根(Composition Root)负责整体装配。 ```text 用户输入 → 上下文组装(系统提示+记忆+工具列表) → LLM 推理 ↑ ↓ └── 工具结果回填 ←── 执行工具 ←── 判断需要调用工具? ──否──→ 最终回复(SSE) ``` ## 项目结构 * ```text agent-engine-python/ ├── pyproject.toml ← uv workspace 根:成员登记 + ruff/mypy/pytest 工程门禁 ├── Makefile ← sync/run/test/lint/typecheck/check 常用命令 ├── .env.example ← 配置样例(键名与 Java 版一致,点分→环境变量映射规则见 00-映射 §2.4) ├── .github/workflows/ci.yml ← CI:ruff + mypy + pytest(mock 档) + 红线 1 机械检查 + evals 夜间 job ├── agent-engine-start/ ← 启动装配:app.py(create_app/lifespan 横幅)+ assembly.py(build_* 工厂)+ settings.py │ └── src/agent_engine_start/ ├── agent-engine-core/ ← 领域核心:零三方依赖;messages/tool/spi/loop/loop_result/errors/ │ └── src/agent_engine_core/ locks/cancellation/prompt/window/sanitizer/state/budget/guardrail/ │ └── prompts/ skill/todo/reflect + prompts/(system/summary/reflection/self-check) ├── agent-engine-web/ ← HTTP 接入:agent_controller.py + dto.py + errors.py(ProblemDetail)+ sse.py │ └── src/agent_engine_web/ ├── agent-engine-model/ ← LLM 接入:placeholder(默认)+ openai_sdk(生产)+ openai_httpx(对照)+ protocol/errors │ └── src/agent_engine_model/ ├── agent-engine-tools/ ← 工具体系:registry.py + current_time.py + sandbox.py(骨架) │ └── src/agent_engine_tools/ ├── agent-engine-memory/ ← 会话记忆:store_memory.py(默认)+ sqlalchemy_impl.py(P1 施工落点) │ └── src/agent_engine_memory/ ├── agent-engine-lab/ ← 学习沙盒:stage1_api_basics.py 起,不进 start 装配 │ └── src/agent_engine_lab/ ├── docs/ ← 技术设计文档(与 Java 版逐篇对应,"可直接施工"粒度) └── sql/ddl.sql ← 数据库初始化脚本(与 Java 版同表同列) ``` > 各包均为 src 布局 + `py.typed`;骨架状态:占位链路(占位模型 + 内存存储 + 同步端点 + ProblemDetail 异常 + 启动横幅)已可运行并通过 23 项测试,其余模块以"完整签名 + 设计文档章节引用"的骨架形态就位,施工从 [P0-核心技术设计](docs/P0-核心技术设计.md) §0 的顺序开始。 ## 模块职责与依赖 * | 成员包 | 职责 | 依赖 | |------|------|------| | [agent-engine-start](agent-engine-start/README.md) | 应用入口:创建 FastAPI app、按 Settings 装配各实现(`build_*` 工厂)、启动自检横幅 | web、model、tools、memory | | [agent-engine-core](agent-engine-core/README.md) | `AgentLoop` 推理循环、`ChatMessage`、`ChatModel`/`ToolRegistry`/`MemoryStore` 等 SPI Protocol | **零三方依赖(红线)** | | [agent-engine-web](agent-engine-web/README.md) | `AgentController`(`POST /api/agent/chat`)、SSE 流式端点、全局异常处理 | core、fastapi | | [agent-engine-model](agent-engine-model/README.md) | LLM 统一接入:三 provider 矩阵(placeholder 兜底 / openai 手写对照 / openai-sdk 生产默认),见 [P0-模型接入](docs/P0-模型接入技术设计.md) | core、openai | | [agent-engine-tools](agent-engine-tools/README.md) | `DefaultToolRegistry` + 示例工具 `current_time` | core | | [agent-engine-memory](agent-engine-memory/README.md) | 会话记忆:`MemoryStore` 进程内默认实现,持久化方案见下文 | core、sqlalchemy(可选 extra) | | [agent-engine-lab](agent-engine-lab/README.md) | 学习沙盒:按项目自定的 Agent 学习路线分阶段实验,成果毕业后迁入正式模块 | core、model、openai | 依赖方向:`web/model/tools/memory → core`,`start → 全部`。实现包之间互不依赖,替换 LLM 供应商只需替换 model 包实现;依赖纪律由 uv workspace 的独立 `pyproject.toml` 物理强制(core 的依赖列表永远为空)。 ## 快速启动 * ```bash # 0. 安装 uv(若未安装)与全部依赖 uv sync # 1. 运行(默认端口 8080;骨架已含占位链路,启动横幅打印装配组合) uv run uvicorn agent_engine_start.app:app --port 8080 # 2. 验证 Agent 链路(占位模型返回上下文统计) curl -X POST http://localhost:8080/api/agent/chat \ -H "Content-Type: application/json" \ -d '{"sessionId":"s1","message":"你好"}' ``` ```bash # 2b. 工程门禁(CI 等价:lint + 类型检查 + 测试) make check ``` ```bash # 3. 切换真实模型(provider 三态,配置项总表见下文) # openai-sdk(生产默认): AGENT_MODEL_PROVIDER=openai-sdk + ZHIPU_API_KEY=... # openai(手写对照): AGENT_MODEL_PROVIDER=openai + ZHIPU_API_KEY=... ``` ## 技术设计文档(docs/) * 全部设计已定稿到"可直接施工"粒度(完整代码、编号踩坑点、分步施工顺序),动工前必读。与 Java 版逐篇对应;协议契约、提示词模板、DDL 三份**与 Java 版内容一致**(契约不因语言而变),其余各篇为 Python 生态重写。同步规则:包 README 记「做什么/现状」,设计稿记「怎么做/为什么」,两边出现分歧时以设计稿为准,并在包 README 补映射链接。 | 文档 | 面向 | 核心内容 | Java 对应 | |------|------|------|------| | [00-技术栈与架构映射](docs/00-技术栈与架构映射.md) | 从 Java 版平移过来的开发者 | Spring→Python 逐机制映射表、并发模型差异、红线移植 | —(新增) | | [P0-核心技术设计](docs/P0-核心技术设计.md) | 把"能跑的占位引擎"变成"能打的 Agent" | 真实 LLM 接入、协议转换、工具执行闭环、AgentLoop、滑动窗口、SSE 流式 | 同名 | | [P0-模型接入技术设计](docs/P0-模型接入技术设计.md) | 正式模块按"真实 Agent 项目"标准设计 | 双 Provider 矩阵、openai SDK 生产实现(自持循环)、对 P0 七项的影响矩阵 | P0-SpringAI | | [P0-历史摘要策略技术设计](docs/P0-历史摘要策略技术设计.md) | "对话太长怎么办"的下半场 | 摘要 KV + 覆盖指针、80% 水位触发、失败退化为纯裁剪 | 同名 | | [P1-健壮性技术设计](docs/P1-健壮性技术设计.md) | 接入真实世界之后必然遇到 | SDK 超时重试、工具健壮性、SQLAlchemy 持久化、切换矩阵、CORS/鉴权、Guardrail | 同名 | | [P1-对话中断恢复技术设计](docs/P1-对话中断恢复技术设计.md) | 崩溃/断连/取消之后会话不坏 | 孤儿 toolCall 组装期自愈、SSE 断连行为、用户取消安全终止点、状态拉取端点 | 同名 | | [P2-扩展面技术设计](docs/P2-扩展面技术设计.md) | lab 阶段毕业成果的预置契约 | RAG、MCP、评测、多 Agent 编排、生产化 | 同名 | | [P2-会话管理技术设计](docs/P2-会话管理技术设计.md) | 前端多会话侧栏的后端支撑 | agent_session 元数据表(重命名/收藏/置顶)、分享快照、懒创建、级联删除与 append-only 边界 | 同名 | | [P2-成本与配额治理技术设计](docs/P2-成本与配额治理技术设计.md) | 从"看得到"到"管得住" | 单 run 上限 + 会话日配额、BudgetLedger 两档、429 语义 | 同名 | | [P2-工具安全沙箱技术设计](docs/P2-工具安全沙箱技术设计.md) | 有副作用工具的安全边界 | 威胁模型、白名单 + 根锚定 + 环境隔离、高危人工确认 | 同名 | | [P3-AskUser主动提问技术设计](docs/P3-AskUser主动提问技术设计.md) | 主动提问 + **P3 公共基础**(§1) | SessionStateStore、ToolContext、HTTP 挂起-恢复协议 | 同名 | | [P3-TodoList任务清单技术设计](docs/P3-TodoList任务清单技术设计.md) | 复杂任务的执行治理 | todo_write 全量替换、写入-回注闭环 | 同名 | | [P3-Skill技能系统技术设计](docs/P3-Skill技能系统技术设计.md) | 把"工具"升级为"技能" | 渐进披露、load_skill、组装期工具合并 | 同名 | | [P4-反思与自我修正技术设计](docs/P4-反思与自我修正技术设计.md) | 补齐 Reflective Agent 范式 | 失败复盘教训 KV、终稿自评(默认关)、组装期注入、evals 失败样本回流 | 同名 | | [协议契约-SSE事件与错误码](docs/协议契约-SSE事件与错误码.md) | 前后端契约唯一事实源 | 事件契约全表、端点语义、错误码矩阵、变更规则 | 同名(内容一致) | | [系统提示词模板](docs/系统提示词模板.md) | 提示词即代码 | 模板正文、占位符契约、注入位说明 | 同名(内容一致) | ## 配置项总表 * 配置中心在 start 包(`Settings` 类树,pydantic-settings 消费环境变量/`.env`),各实现经组合根工厂函数消费(切换矩阵详见 [P1 §4](docs/P1-健壮性技术设计.md))。**键名与默认值与 Java 版完全一致**;点分键 → 环境变量映射规则:`agent.model.provider` → `AGENT_MODEL_PROVIDER`(点换下划线、全大写、`AGENT_` 前缀)。 | 配置项 | 默认值 | 说明 | |--------|--------|------| | `agent.model.provider` | `placeholder` | 模型实现切换:placeholder / openai(手写对照,lab 毕业迁入) / openai-sdk(生产默认,见 [P0-模型接入](docs/P0-模型接入技术设计.md)) | | `agent.model.openai.api-key` | — | LLM 密钥,经 `ZHIPU_API_KEY` 环境变量注入,不落配置文件;两个真实 provider(openai/openai-sdk)共用 | | `agent.model.openai.base-url` | — | OpenAI 协议兼容端点(智谱 `https://open.bigmodel.cn/api/paas/v4/`,**尾斜杠必须保留**) | | `agent.model.openai.model` | `glm-4-flash` | 模型名 | | `agent.model.openai.temperature` | `0.7` | 采样温度 | | `agent.model.openai.timeout-seconds` | `60` | 读超时(等模型出字) | | `agent.memory.store` | `in-memory` | 存储切换:in-memory / sqlalchemy;同时控制 `MemoryStore` 与 `SessionStateStore`(P3) | | `agent.memory.max-sessions` | `1000` | 进程内 Store 会话数上限,LRU+TTL 惰性淘汰(P1 §7.2) | | `agent.memory.session-ttl` | `24h` | 会话空闲淘汰阈值,淘汰与并发锁联动(P1 §7.1/7.2) | | `agent.system-prompt` | `pkg:agent_engine_core/prompts/system.md` | 系统提示词模板位置,支持 pkg:/file:/内联(P0 §7.4) | | `agent.context.summary-enabled` | `true` | 历史摘要开关,关闭则行为与纯滑动窗口一致(P0-历史摘要 §3) | | `agent.context.max-tokens` | 模型窗口 × 0.6 | 上下文 token 预算,80% 水位触发摘要(P0-历史摘要 §3) | | `agent.skill.max-active-skills` | `2` | 每会话技能激活数上限(P3-Skill §5,防囤技能) | | `agent.budget.run-tokens` | `100000` | 单 run token 上限,超限循环终止并给阶段性结论(P2-成本与配额 §1) | | `agent.budget.daily-tokens` | `500000` | 会话日配额,超限入口拒绝 429 `QUOTA_EXCEEDED`(ProblemDetail code,契约 §4;P2-成本与配额 §1) | | `agent.budget.global-daily-tokens` | `0` | 全局日配额,`0` 不限,>0 启用(P2-成本与配额 §1) | | `agent.budget.ledger` | `in-memory` | 配额账本切换:in-memory(重启清零,自然日重计)/ sqlalchemy(`agent_usage_daily` 表);与 `agent.memory.store` 解耦 | | `agent.budget.zone` | 系统时区 | 日界时区,跨时区部署时显式配置(P2-成本与配额 CB2) | | `agent.tools.sandbox.root` | 工程工作目录 | 沙箱锚定根,文件/Shell 路径规范化后必须仍在根内(P2-工具安全沙箱 §1) | | `agent.tools.sandbox.allow-commands` | — | Shell 命令白名单(起步 `ls`/`cat`/`grep`/`find`),白名单外拒绝文本回填(P2-工具安全沙箱 §2) | | `agent.web.api-key` | — | HTTP API Key 鉴权(P1 §5.2);`/api/share/**` 在中间件白名单放行(P2-会话管理 SM10) | | `agent.web.cors.allowed-origins` | — | CORS 允许来源列表(P1 §5) | | `agent.guardrail.fail-mode` | `open` | 护栏自身异常时放行/拦截(P1 踩坑 G1;对外服务建议 close) | | `agent.rag.enabled` | `false` | RAG 上下文注入开关(P2-扩展面 §1;关闭时循环零变化) | | `agent.reflection.lessons-enabled` | `true` | 失败复盘开关:失败 run 收尾生成教训写入会话 KV,下条请求组装期注入(P4 §2) | | `agent.reflection.self-check` | `false` | 终稿自评开关:COMPLETED 出口前结构检查,开启后成功路径多一轮调用(P4 §2) | | `agent.reflection.prompt` | `pkg:agent_engine_core/prompts/reflection.md` | 复盘提示词位置,支持 pkg:/file:/内联(P4 附录 A) | > 模型读超时与工具执行超时随各自 Settings 类落地,文档显式给出键名;数据库连接串 `database__url`(`DATABASE__URL`,dev 默认 SQLite 文件库)见 P1 §3。 ## 持久化设计(MemoryStore 落库)* `MemoryStore` 的设计初衷:**数据访问被 SPI 屏蔽**。core 只认 Protocol,web 等消费方拿到的永远是 `ChatMessage`(领域模型);数据库与 SQLAlchemy 是 memory 包的私有实现细节,替换存储不动 core/web。 两类类,角色严格区分: | 类 | 所在包 | 角色 | |------|------|------| | `ChatMessage` | core | 领域模型(frozen dataclass),所有模块共享 | | `MessageRecord`(SQLAlchemy) | memory | 持久化模型,仅 memory 可见,经 `to_chat_message()` / `of()` 与领域模型互转(防腐层) | 落库分两档,按规模演进: 1. **仅会话记忆落库**(推荐起步):memory 包内实现 —— 加 `sqlalchemy[asyncio]` + 驱动(aiosqlite/asyncmy),新增 `models/`、`repositories/` 分层与 `SqlalchemyMemoryStore`;与 `InMemoryMemoryStore` 用 `agent.memory.store` 切换,core 一行不改。 2. **多处落库**(出现工具审计、业务表等):拆 `agent-engine-repository` 基础包,装 engine/session 工厂、事务管理、Alembic 脚本;各包自己的模型仍留在各自包内,不共享。 三条硬约束(与 Java 版一致): 1. **core 永不感知 SQLAlchemy**,依赖方向保持 `memory → core`,不出现反向; 2. **事务收敛在 Store 实现内部**(`async with session.begin()`),`AgentLoop.run()` 不开事务(内含 LLM 秒级网络调用,长事务拖垮连接池); 3. **配置归 start**:`DATABASE__URL` 等写在 start 的 Settings/.env;DDL 脚本放实现包 resources,随包分发;生产建议 Alembic 版本化迁移。 判断规则一句话:**每张表归属唯一包,持久化模型是该包私有实现;其他包要数据走 SPI,不走表。** ## 功能实现待办清单(面试优先级) * > 以**应对面试**为目标排序:优先做面试必问的核心链路,再做真实世界必踩的健壮性,最后补拉开差距的扩展面。清单与 Java 版逐项对应(功能完全一致),高频度标注:☆☆☆ 高频必问 · ☆☆ 中频追问 · ☆ 加分项。 ### P0 · 核心链路(把"能跑的占位引擎"变成"能打的 Agent") * - [ ] **真实 LLM 接入** — model 包基于 openai SDK 实现 `OpenAiSdkChatModel`(替换占位实现;手写 httpx 版为对照,见 [P0-模型接入](docs/P0-模型接入技术设计.md)) ☆☆☆ 面试考法:异步客户端构建、OpenAI 兼容端点(DeepSeek/智谱)切换、temperature 等参数语义; - [ ] **工具调用协议转换** — model 包 `ToolDefinition` ↔ function calling schema/toolCalls 解析 ☆☆☆ 面试考法:Function Calling 完整往返流程(这是 Agent 面试第一题); - [ ] **工具执行闭环** — tools 包 `ToolRegistry` 从"发现"补全到"执行" ☆☆☆ 面试考法:工具 schema 怎么定义、执行结果如何回填; - [ ] **Agentic Loop 补全** — core 包 `AgentLoop`:推理 → 工具意图解析 → 执行 → 回填 → 再推理 ☆☆☆ 面试考法:循环何时终止、最大轮次防失控、多工具并发还是串行; - [ ] **上下文窗口管理** — core + memory:滑动窗口裁剪 / 历史摘要 ☆☆☆ 面试考法:"对话太长超出上下文怎么办"—— 必备追问,滑动窗口与摘要两种策略都要能讲; - [ ] **SSE 流式输出** — web 包流式端点 + core/model 的流式推理链路,含 SSE 心跳注释行防网关空闲掐断(P0 §6 踩坑 F9) ☆☆☆ 面试考法:流式实现原理(`astream` → asyncio.Queue → StreamingResponse → 前端 EventSource); - [ ] **随行小件** — web 参数校验(pydantic)+ 全局异常处理(exception_handler)+ start 类型安全配置(pydantic-settings)+ 系统提示词外置与组装期渲染(P0 §7.4) ☆☆ 工作量小,随核心链路一起完成,构成完整工程闭环; - [ ] **结构化输出 SPI(P0.5)** — model `call_for(model_type)`:schema 约束 + 围栏剥离 + 解析失败修复重试(设计见 [P0 §10](docs/P0-核心技术设计.md)) ☆☆ 面试考法:结构化输出与工具调用为何互斥、prompt 约束 vs `response_format` 在兼容平台的取舍; ### P1 · 健壮性(接入真实世界之后必然遇到) * - [ ] **SDK 级健壮性** — model:超时、重试、异常分层(`RateLimitError` 等按类型降级) ☆☆ 面试考法:LLM 调用超时/限流怎么处理 —— 超时重试熔断的经典变体; - [ ] **工具执行健壮性** — tools:执行超时(线程池 + `asyncio.wait_for`)、异常包装为错误文本回填 ☆☆☆ 面试考法:"工具执行报错会打断 Agent 吗?" —— 答案是回填给 LLM 让其自愈,高频追问; - [ ] **会话并发治理与内存淘汰** — core per-session 循环级串行(asyncio.Lock 排队 30s,超时 409)+ `InMemoryMemoryStore` LRU+TTL 惰性淘汰 + `GET /session/{id}/usage` 用量端点(设计见 [P1 §7](docs/P1-健壮性技术设计.md)) ☆☆ 面试考法:"同会话并发两次请求会怎样"、进程内缓存的有界设计、单实例口径与生产观测的分层; - [ ] **会话记忆持久化** — memory:`SqlalchemyMemoryStore` + `MessageRecord` 防腐层(设计见上文) ☆☆ 面试考法:为什么持久化模型不放 core、事务为什么收敛在 Store 内部(方案已定稿,按图施工); - [ ] **多环境与多实现切换** — start Settings + 组合根工厂切换占位/真实模型、内存/持久化存储 ☆☆ 面试考法:依赖注入与组合根模式、Python 里如何实现"恰好一个"装配不变量; - [ ] **对话中断恢复** — core:`HistorySanitizer` 组装期自愈孤儿 toolCall(崩溃/存储故障截断的会话会被 400 永久拒绝,设计见 [P1-对话中断恢复](docs/P1-对话中断恢复技术设计.md));web:SSE 断连不中止循环、`POST cancel` 用户主动取消(安全终止点,与断连语义相反)+ `GET session state` 端点 ☆☆ 面试考法:"工具执行到一半服务崩了,这个会话还能用吗?" —— 组装期检测孤儿 toolCall 补占位结果,append-only 不撤回;"用户点停止,正在执行的工具要不要强杀?" —— 不强杀,回填后跳过剩余(副作用未知); - [ ] **CORS / 鉴权** — web:浏览器接入配置,API Key 中间件放行流式端点 ☆☆; - [ ] **Guardrail 契约** — core:输入过滤(提示注入检测)与输出审查接口 ☆☆ 面试考法:提示注入攻击与防御(Agent 安全方向热点)。 ### P2 · 扩展面(拉开差距的加分项) * - [ ] **RAG 与向量化记忆** — lab 阶段四毕业,产出 `agent-engine-rag` 包 + 记忆策略落 memory ☆☆☆ 面试高频度其实是最高档(向量检索原理、RAG 全链路),但价值在核心链路之后兑现;可提前在 lab 沙盒启动; - [ ] **MCP 工具生态** — lab 阶段三毕业,产出 `agent-engine-mcp`,本地工具桥接外部 MCP Server ☆☆ 面试考法:MCP 与 Function Calling 的关系、MCP 协议是什么; - [ ] **评测与安全实验** — lab 阶段六:evals 用例集 + 提示注入攻防;evals pytest 化双档进流水线(mock 主流水 + 真模型夜间档,P2 §3.4) ☆☆ 面试考法:"Agent 效果怎么评测" —— 有真实 evals 集是强差异化素材; - [ ] **多会话管理与会话分享** — memory + web:`agent_session` 元数据表(懒创建/重命名/收藏/置顶)、级联删除、`SessionShareStore` 物化快照分享,core 零改动(设计见 [P2-会话管理](docs/P2-会话管理技术设计.md)) ☆☆ 面试考法:"元数据表 vs 聚合消息表"的取舍、PATCH null 语义(部分更新)、分享快照 vs 活链接(隐私与不可变性); - [ ] **成本与配额治理** — core + web:`BudgetLedger` 两档、单 run 上限 + 会话/全局日配额、`LoopResult.BUDGET_EXCEEDED` 四态、429 `QUOTA_EXCEEDED` 与上游限流 503 严格区分(设计见 [P2-成本与配额治理](docs/P2-成本与配额治理技术设计.md)) ☆☆ 面试考法:"Agent 上生产怎么控制成本"——统计只是台账,配额才是治理; - [ ] **工具安全沙箱** — tools:`ToolSandbox`(白名单 + 根锚定 + 环境隔离 + 独立截断)、`confirmed_required` 高危人工确认(复用 P3 挂起-恢复协议,零新协议)、`confirm_required` SSE 事件(设计见 [P2-工具安全沙箱](docs/P2-工具安全沙箱技术设计.md)) ☆☆ 面试考法:"提示注入诱导 Agent 执行危险操作怎么防"——威胁模型 + 纵深防御的具体答案; - [ ] **多 Agent 编排** — core:起步用 Agent-as-Tool(子 Agent 包装为工具,复用 `ToolRegistry`),验证价值后再上规划者-执行者消息传递(P2 §4.0/§4.1) ☆ 面试考法:多 Agent 协作 vs 单 Agent 循环的取舍; - [ ] **生产化收尾** — start:健康检查探针、容器化分层构建、优雅停机、sessionId 链路日志;CI 工作流 / LICENSE / examples 门面(P2 §5.4) ☆ ### P3 · 交互与技能(设计定稿,待施工) * > 三份 P3 设计共用一套公共基础(`SessionStateStore` / `ToolContext` / `SessionEvents` / `LoopResult`,统一定义见 [AskUser 文档 §1](docs/P3-AskUser主动提问技术设计.md));核心原则:**交互原语即工具** —— 循环主流程零改动,全部变化收敛在组装期与工具自身。 - [ ] **P3 公共基础** — core:`SessionStateStore` SPI + memory 双实现 + `Tool` 签名升级为 `execute(tool_context, arguments_json)`(async) ☆☆☆ 三个交互特性共同的前置,先于它们施工(含 `agent_session_state` 表与原子取走语义); - [ ] **AskUser 主动提问** — `ask_user` 工具 + HTTP 挂起-恢复协议 + CLI 阻塞通道 ☆☆☆ 面试考法:Agent 如何处理歧义、跨请求挂起的状态如何恢复(答案 TOOL 角色回填,不是 USER); - [ ] **TodoList 任务清单** — `todo_write` 全量替换语义 + 组装期回注闭环 ☆☆ 面试考法:长任务执行治理、"状态不是消息"的边界、回注防失忆; - [ ] **Skill 技能系统** — `load_skill` 渐进披露 + 组装期工具合并 ☆☆ 面试考法:上下文成本治理(目录常驻 ≈300 token vs 全量 ≈5000+)、与 Claude Skills 的同构设计。 ### P4 · 反思与自我修正(设计定稿,待施工) * - [ ] **失败复盘(lessons)** — 失败 run(MAX_ROUNDS/BUDGET_EXCEEDED)收尾生成 ≤400 字教训写入会话 KV,下条请求组装期注入,成功即清(默认开,见 [P4 §2](docs/P4-反思与自我修正技术设计.md)) ☆ - [ ] **终稿自评(self-check)** — COMPLETED 出口前结构完整性检查,FIX 最多重推一轮(默认关,成本近翻倍) ☆ - [ ] **evals 失败样本回流** — nightly evals 失败 case 归档 + 人工三桶分类 + 转回归用例(依赖 P2 §3.4) ☆ ### 使用方式 * 1. 严格按 P0 → P1 → P2 → P3 → P4 顺序推进;P0 各项存在跨包依赖,按上文列出的先后做;P3 公共基础先于三个交互特性; 2. 每完成一项打勾,并把对应包 README「功能实现优先级清单」同步更新; 3. 每项右侧"面试考法"即自测清单 —— 做完一项,先能不看资料讲清对应问题,再进入下一项; 4. 与 Java 版对照学习:同名设计文档逐节对应,踩坑点编号一致(A/B/C… 系列为 Python 版独立编号,与 Java 版同号不同义时以本文档为准),可双向印证"同一问题在不同运行时的两种解法"。 ## 新增子包 * 1. 在根目录创建成员包目录(标准 `src/` 布局 + `pyproject.toml`,成员声明 `requires-python = ">=3.12"`,不重复锁版本); 2. 在根 `pyproject.toml` 的 `[tool.uv.workspace] members` 登记包名,成员间依赖以 `[project.dependencies]` 声明 `agent-engine-core` 等名字,即可纳入统一构建与依赖纪律检查。 ## 技术栈 * | 项 | 说明 | |------|------| | Python ≥ 3.12 | 根 pyproject 统一声明 `requires-python`,成员包继承 | | FastAPI + uvicorn | web 接入与 ASGI 服务;SSE 用 StreamingResponse(手写 SSE 帧,协议级掌控) | | uv workspace | 根 pyproject 聚合 7 个成员包;单包测试 `uv run --package agent-engine-core pytest` | | openai (Python SDK) ≥ 1.x | 版本经根 pyproject 统一管理,仅 model 包声明(openai-sdk 生产 provider + lab 使用) | | SQLAlchemy 2.0 (async) | 持久化(memory 包,可选 extra `agent-engine-memory[sqlalchemy]`),dev 用 aiosqlite、生产用 MySQL(asyncmy) | | pydantic v2 + pydantic-settings | 请求校验 + 类型安全配置(web/start 包) | | pytest + pytest-asyncio | 测试;evals 双档经 marker 划分(mock 档主流水 / nightly 档真模型) | | ruff + mypy | Lint 与类型检查(工程门禁,CI 强制) | > 三方依赖刻意克制:不引 LangChain/LlamaIndex 等编排框架 —— 循环编排权必须留在自研 `AgentLoop`(与 Java 版"框架只做协议层、`internalToolExecutionEnabled(false)`"同一条红线,见 [P0-模型接入 §0](docs/P0-模型接入技术设计.md))。