405 lines
21 KiB
Markdown
405 lines
21 KiB
Markdown
# 设计文档
|
||
|
||
> 一个本地运行的个人任务 agent。覆盖三类工作:写汇报 PPT、写科研申报书、写代码。
|
||
> 模型自由(LiteLLM 接 OpenAI-compatible),代码可控(目标 1500-2000 行 Python,自己读得懂)。
|
||
|
||
---
|
||
|
||
## 1. 边界
|
||
|
||
### 做什么
|
||
- **PPT**:文本 / 会议纪要 → `.pptx`(用 `python-pptx`)
|
||
- **科研申报**:课题信息 → 分章节 `.docx`(用 `python-docx`)
|
||
- **编码**:文件编辑、shell 执行、迭代验证
|
||
|
||
### 不做什么
|
||
- 子 agent / IM 渠道 / 多用户 / Web UI(初期 CLI 即可)/ 自定义 RAG / 锁定 Anthropic
|
||
- **Eval Suite**:个人工具用 dogfooding 判断模型升级,造作 case 没区分度
|
||
|
||
### 关键约束
|
||
- 模型自由:LiteLLM 接 OpenAI-compatible 任意 provider(默认 DeepSeek V4)
|
||
- 任务持久化:任意时刻关机,下次能恢复
|
||
- 演化性:模型升级时 agent 跟着升级,不需要大改架构
|
||
|
||
---
|
||
|
||
## 2. 架构
|
||
|
||
### 目录树(实际)
|
||
|
||
```
|
||
zcbot/
|
||
├── core/
|
||
│ ├── capabilities.py # ModelCapabilities,从 yaml 加载
|
||
│ ├── llm.py # LiteLLM 封装,按 capabilities 自动启用 features
|
||
│ ├── loop.py # ReAct 主循环
|
||
│ ├── probe.py # 真实探测对账 yaml 声称的能力
|
||
│ ├── session.py # 消息列表 + meta + 落盘 messages.json
|
||
│ ├── skills.py # SkillRegistry (Anthropic 渐进披露格式)
|
||
│ └── task.py # TaskState (mode/desc/status/tokens/timestamps)
|
||
├── tools/
|
||
│ ├── base.py # Tool 基类 + _resolve 路径
|
||
│ ├── fs.py # read / write / edit (唯一匹配) / glob / grep
|
||
│ ├── shell.py # subprocess + 黑名单
|
||
│ ├── run_python.py # tmp .py + subprocess,过滤敏感 env
|
||
│ └── skill_tool.py # load_skill
|
||
├── skills/
|
||
│ ├── coding/ # SKILL.md
|
||
│ ├── ppt/ # SKILL.md + references/ + scripts/ + assets/
|
||
│ └── proposal/ # SKILL.md
|
||
├── prompts/system/
|
||
│ └── general_v1.md
|
||
├── config/
|
||
│ ├── agent.yaml
|
||
│ └── models/
|
||
│ └── deepseek_v4.yaml # flash + pro 两档
|
||
├── workspace/
|
||
│ └── tasks/<task_id>/
|
||
│ ├── state.json # TaskState
|
||
│ ├── messages.json # Session
|
||
│ ├── spec_lock.md # skill 阶段一产物 (proposal/ppt)
|
||
│ ├── source/ # proposal 用户素材 (PDF / 团队介绍)
|
||
│ ├── source.md # ppt 转过的素材
|
||
│ ├── sections/ # proposal 逐章 md (01_summary.md ... 12_appendix.md)
|
||
│ ├── slides/ # ppt 中间素材 (chart_p?.png)
|
||
│ └── <topic>.docx / .pptx # 最终产物
|
||
├── main.py # 装配 (build_agent)
|
||
└── cli.py # CLI: chat / tasks / probe
|
||
```
|
||
|
||
**task_dir = `workspace/tasks/<task_id>/`,所有 skill 产物都写到这里**。task_dir 绝对路径在 system prompt 里显式给 agent,SKILL.md 的 `<task_dir>` 占位符指向它。如果 agent 写错位置(写到 cwd / `skills/` / repo 根),git status 会立刻报红 —— `.gitignore` 不再用无锚通配规则盖住污染。
|
||
|
||
### 启动时拼装顺序
|
||
1. 读 `config/agent.yaml` 拿 default_model
|
||
2. `ModelCapabilities.load("deepseek_v4.flash", config/models/)` 拿能力档案
|
||
3. `LLM(caps)` 构造,从 env 读 API key
|
||
4. 解析 task_dir(新建 or resume)
|
||
5. 拼 system prompt:`prompts/system/general_v1.md` + `SkillRegistry.discovery_block()`(skill 列表)+ cwd + **task_dir 绝对路径**(产物根)
|
||
6. 装配工具集(fs / shell / load_skill / run_python)
|
||
7. 启动 REPL —— **新建路径不预占文件**(懒创建,见 §3.6)
|
||
|
||
---
|
||
|
||
## 3. 核心组件
|
||
|
||
### 3.1 主循环(`core/loop.py`)
|
||
ReAct 风格:LLM → 若有 tool_calls 就执行 → 把结果塞回消息列表 → 再调 LLM。无 tool_call 即返回。
|
||
- 工具结果对模型截断到 16K 字符,对用户预览 400 字符
|
||
- thinking spinner 由后台 daemon 线程每 100ms 刷新文本:`thinking... 1.3s ctx 12,345 tok`(累计 token 反映上下文大小)
|
||
- 每轮 LLM 返回追加 dim 一行 `[in N out N t Xs]` —— 留痕本轮成本
|
||
- assistant 文字走 `rich.markdown.Markdown` 渲染,粗体/列表/表格/代码块正常展示(非流式,整段渲染)
|
||
- `max_iterations` 从 capabilities 读,不同模型不同
|
||
|
||
### 3.2 Model Profile(`core/capabilities.py` + `config/models/*.yaml`)
|
||
**核心思想**:每个模型一份 yaml 档案,agent 行为按档案动态调整。新模型 5 分钟接入,不改代码。
|
||
|
||
`ModelCapabilities` 字段:max/reliable_context、max_output、parallel_tools、tool_calling_quality、thinking_mode、reasoning_effort_levels、code_quality、enable_run_python、max_iterations、optimal_temperature、prompt_caching、extended_thinking、api_base、api_key_env。
|
||
|
||
`LLM.chat` 按 capabilities 自动启 `parallel_tool_calls` / `reasoning_effort` / Anthropic prompt-caching header。
|
||
|
||
### 3.3 Capability Probing(`core/probe.py` + `cli.py probe`)
|
||
yaml 是手填的,可能错。`probe` 用真实 LLM 调用对账:
|
||
- `basic_chat`:连通性
|
||
- `parallel_tools`:给两个独立工具,看 single response 是否 ≥2 个 tool_calls
|
||
- `thinking_mode`:对 declared=True 的模型试 reasoning_effort,看 API 是否接受 + 是否产 reasoning_content
|
||
- `long_context`:needle-in-haystack 简化版(opt-in,默认关)
|
||
|
||
不修改 yaml,只输出 rich Table 报告。退出码 0/2/3 区分 ok / mismatch / error。**显式触发,不进启动路径**(每次启动跑会烧 API)。
|
||
|
||
### 3.4 工具系统(Hybrid 范式)
|
||
|
||
**两类工具并存**:
|
||
- **JSON tool call**(`tools/`):read / write / edit / glob / grep / shell / run_python / load_skill —— 处理离散操作
|
||
- **Code execution**(`run_python`):tmp `.py` + subprocess + 工作目录限制 + 敏感 env 过滤(`*API_KEY *TOKEN *SECRET *PASSWORD *PRIVATE_KEY`)—— 处理批处理 / 算数据 / 生成文档
|
||
|
||
**关键设计**:
|
||
- `edit` 用 **唯一匹配**约束(CoreCoder 风格):old_str 必须只出现一次,否则报错。防 LLM 改错地方。
|
||
- 工具按**原子操作**切分,不做高级封装。`make_pptx()` ❌,`run_python(code)` 调 `python-pptx` ✅。粒度太粗会接收不到模型升级红利。
|
||
|
||
### 3.5 Skill 系统(Anthropic 渐进披露标准)
|
||
对齐 Anthropic 2025-12 开放标准,跨平台兼容(Claude Code / Codex CLI / Gemini CLI 都用)。
|
||
|
||
**三层加载**:
|
||
| 层 | 时机 | 内容 | Token |
|
||
|---|------|------|------|
|
||
| Discovery | agent 启动 | 仅 `name + description`,所有 skill 都读 | 几百 |
|
||
| Activation | `load_skill(name)` | 完整 SKILL.md | 1000-5000 |
|
||
| Execution | SKILL.md 指 `references/xxx` | 单个 reference 文件 | 视情况 |
|
||
|
||
**Skill 设计原则**:写 WHY+WHAT,不写 Step 1/2/3。让模型自己规划。description 要明确具体——决定模型能否触发。
|
||
|
||
### 3.6 Session 与 Task
|
||
|
||
**Session**(`core/session.py`)= 消息列表 + meta + 落 `messages.json`。
|
||
|
||
**Task**(`core/task.py`)= Session 的上层概念,含 mode / description / status (active/completed/abandoned) / model / reasoning_effort / cwd / created_at / updated_at / tokens_prompt / tokens_completion。落 `state.json`。
|
||
|
||
存储:`workspace/tasks/<task_id>/{state.json, messages.json}`。每轮 `agent.run` 后调 `sync_task_tokens` 把 LLM 累计 tokens 写回。
|
||
|
||
**懒创建** —— `build_agent` 新建分支不立刻 save,task_dir 在第一条 user 消息触发 `Session.append → save()` 时才物化(`Session.save` / `TaskState.save` 都 `mkdir(parents=True)`)。启动 REPL 后立刻 `/exit` 磁盘无痕,跨进程也安全(没有"另一个 REPL 刚 build_agent 还没说话就被这个进程当空 task 删掉"的窗口)。
|
||
|
||
**REPL 内 task 切换** —— `/new` 开新 task,`/resume [last|<id>]` 切到已有 task(无参数列最近 10 个表格让用户选),`/done /abandon` 改状态,`/desc` 改描述。切走前 `_cleanup_if_empty` 守门:三条都满足才删 task_dir —— ① session 没 user 消息 ② 目录在磁盘上 ③ 目录里只剩 `messages.json`(state.json 存在 = `/done /abandon /desc` 留下的显式痕迹,要保)。
|
||
|
||
CLI:`chat --mode coding --desc "..." [--resume last|<id>]`;`tasks [--status active|completed|abandoned]` 列任务。
|
||
|
||
---
|
||
|
||
## 4. 模型路由
|
||
|
||
### 默认配置(`config/agent.yaml`)
|
||
```yaml
|
||
default_model: deepseek_v4.flash
|
||
```
|
||
|
||
设计上的分模式路由(后续要做)思路:
|
||
| 模式 | 模型 | 理由 |
|
||
|-----|-----|------|
|
||
| 通用 / 编码 / PPT / 提案初稿 | flash | flash SWE-Bench 80.6,够用 |
|
||
| 复杂 bug / 提案终稿 | pro + reasoning_effort=max | 关键产出值得花 |
|
||
| fallback | claude_4_7.opus | V4 不行时手动切 |
|
||
|
||
### 成本量级
|
||
| 任务 | flash | pro-max | Claude Opus 4.7 |
|
||
|-----|------|--------|------|
|
||
| 修一个 bug(~10 轮) | $0.01 | $0.05 | $0.30 |
|
||
| 5 页汇报 PPT | $0.05 | $0.20 | $1.50 |
|
||
| 完整申报书 | $0.30 | $1.50 | $10-15 |
|
||
|
||
99% 任务 flash 够用,关键终稿升级 Pro。
|
||
|
||
---
|
||
|
||
## 5. 设计哲学
|
||
|
||
### 核心原则:Less Scaffolding, More Trust
|
||
老 agent 框架(早期 LangChain、AutoGPT)失败的核心:给 LLM 太多脚手架,模型升级后这些脚手架成枷锁。
|
||
|
||
**正确做法**:把 LLM 当一个**会持续变强的同事**对待,告诉它目标,不告诉它步骤。
|
||
|
||
### 七条具体原则
|
||
1. **Prompt 用 WHY+WHAT,不用 HOW** —— 详细教"应该怎么思考"会降智强模型
|
||
2. **Skill 渐进披露,不写完整流程** —— 对齐 Anthropic 标准
|
||
3. **工具按原子操作切分,不做高级封装** —— 留出组合空间给模型
|
||
4. **Model Profile 化,不硬编码** —— 新模型 5 分钟接入
|
||
5. **Capability Probing** —— yaml 是手填的,跑探测对账实际行为
|
||
6. **版本化 Prompt** —— `prompts/system/active.md` 软链接(尚未做,等真要切版本时再做)
|
||
7. **eval 评估** —— 设计阶段曾认为是关键,落地后判断:个人工具 dogfooding 更有效;**已删**
|
||
|
||
### 借鉴自(简版)
|
||
| 来源 | 借鉴 |
|
||
|-----|------|
|
||
| CoreCoder | 主循环简洁实现 + Edit 唯一匹配约束 |
|
||
| Anthropic Agent Skills | SKILL.md + 渐进披露标准 |
|
||
| nanobot | Workspace + 任务隔离 |
|
||
| smolagents | LiteLLM 做模型层 + CodeAct 范式启发 run_python |
|
||
|
||
---
|
||
|
||
## 6. 风险与取舍
|
||
|
||
### 已知风险
|
||
| 风险 | 缓解 |
|
||
|-----|------|
|
||
| run_python subprocess 沙盒不够强 | 限制工作目录 + 敏感 env 过滤;后续可升级 Docker |
|
||
| V4 在某些复杂任务不如 Claude | dogfooding 判断,fallback 手动切 |
|
||
| Skill description 不够好 → 触发不准 | 用 Pro 优化 description,实战观察 |
|
||
| Long context 退化 | `probe --long-context` 探测可靠 ceiling,不依赖宣称值 |
|
||
| `Session.save()` 不原子,异常会留 0 字节文件 | 后续改 tmp + rename(已记 PROGRESS) |
|
||
|
||
### 取舍说明
|
||
**为什么用 Hybrid 范式而不是纯 CodeAgent**:V4 JSON tool call 已稳定;沙盒成本只在需要时付;兼容 thinking 模式。
|
||
|
||
**为什么用 Anthropic Skill 标准而不是自创**:行业标准已成,跨 SDK 兼容;直接拿 Anthropic 现成 skills repo。
|
||
|
||
**为什么不做 subagent**:状态管理复杂度爆炸;单 agent + skill 已覆盖 95% 场景。
|
||
|
||
**为什么不做 Eval Suite**:DESIGN 旧版按团队/产品场景设计;个人单用户场景里,跑两个真实任务的 dogfooding 比造作 case 信号更强,probe 已覆盖健康检查。
|
||
|
||
---
|
||
|
||
## 7. Core / Platform 切分(草案,status=design,2026-05-09)
|
||
|
||
> §1-§6 是 **personal-tool track**;本节是 **platform track**,目标把 core 包成多租户 SaaS。两者共享同一 core 代码,部署形态不同。本节落地前 §1-§6 路线照走,不阻塞 dogfood。
|
||
|
||
### 7.1 总原则
|
||
|
||
| | 形态 | 数据归属 | 接口 |
|
||
|---|---|---|---|
|
||
| Core(自己做) | 独立 **HTTP/SSE service** + sandbox 进程组 | 对话 / 文件 / 产物 / tokens / 用量 | `/v1/*` REST + SSE |
|
||
| Platform(团队做) | BFF + Web/Mobile UI + Auth + Billing | 终端用户 / 订阅 / 发票 | 调用 core `/v1/*` |
|
||
|
||
CLI 也是 core 的一个客户端 —— 走同一 `/v1`,本地起 core 跑 localhost。dogfood 和平台走同一份代码路径,bug 先在自己身上发现。
|
||
|
||
参考蓝本:**OpenAI Assistants API** 形态(stateful agent service:`/threads /messages /files /runs`)。
|
||
|
||
### 7.2 资源模型与接口(/v1)
|
||
|
||
```
|
||
POST /v1/tasks 创建 task(mode/desc/model)
|
||
GET /v1/tasks 列表
|
||
GET /v1/tasks/{id} 详情
|
||
PATCH /v1/tasks/{id} 改 mode/desc/status
|
||
DELETE /v1/tasks/{id} 删 task(连带 messages/files/产物)
|
||
|
||
POST /v1/tasks/{id}/files 上传(multipart,入 task_dir/source/)
|
||
GET /v1/tasks/{id}/files 列表
|
||
GET /v1/tasks/{id}/files/{name} 下载(产物也走这里)
|
||
DELETE /v1/tasks/{id}/files/{name}
|
||
|
||
POST /v1/tasks/{id}/messages 发消息,返回 {run_id}
|
||
GET /v1/tasks/{id}/messages 历史
|
||
GET /v1/tasks/{id}/runs/{run_id}/events SSE 事件流
|
||
POST /v1/tasks/{id}/runs/{run_id}/cancel
|
||
|
||
GET /v1/skills 可用 skill 列表
|
||
GET /v1/models 可用 model profile
|
||
POST /v1/probe (admin) 跑 capability probe
|
||
|
||
GET /v1/usage tokens/cost/quota 状态(by tenant)
|
||
```
|
||
|
||
**SSE 事件格式**:
|
||
```json
|
||
{"type":"tool_call","run_id":"...","name":"read","args":{...},"ts":"..."}
|
||
{"type":"tool_result","run_id":"...","name":"read","preview":"...","truncated":false}
|
||
{"type":"text","run_id":"...","delta":"..."} ← LLM 流式 token
|
||
{"type":"usage","run_id":"...","prompt":1234,"completion":567,"cost_usd":0.012}
|
||
{"type":"done","run_id":"..."}
|
||
```
|
||
|
||
**版本化**:`/v1` 半年内 minor 向后兼容,major 6 个月 deprecation 窗口。
|
||
|
||
### 7.3 认证模型
|
||
|
||
Core 只信平台,**不直接对终端用户**。
|
||
|
||
```
|
||
Authorization: Bearer <platform_api_key> ← 绑死平台租户
|
||
X-Tenant-Id: <tenant_uuid> ← 平台 sign 的 JWT claim
|
||
X-User-Id: <user_uuid> ← 同上
|
||
X-Request-Id: <uuid> ← 跨服务 trace
|
||
```
|
||
|
||
平台对终端用户做 OIDC/Clerk auth,把租户/用户 ID 签进 JWT 给 core 验签 —— 平台**无法伪造租户 ID**。多租户隔离在 core 这一层强制,平台 bug 不会泄露跨租户数据。
|
||
|
||
### 7.4 存储:Postgres + 本地文件系统
|
||
|
||
**结构化数据走 Postgres**(service 形态多 worker 必须):
|
||
|
||
```
|
||
tenants(id, name, api_key_hash, plan, created_at, status)
|
||
tasks(id, tenant_id, user_id, mode, description, status, model_profile,
|
||
tokens_prompt, tokens_completion, cost_usd, created_at, updated_at)
|
||
messages(id, task_id, role, content, tool_calls, tool_call_id,
|
||
reasoning_content, created_at)
|
||
runs(id, task_id, status, started_at, finished_at, error, tokens_p, tokens_c, cost_usd)
|
||
files(id, task_id, name, path, size, content_type, uploaded_at, kind)
|
||
← kind: source / intermediate / artifact
|
||
usage_events(id, tenant_id, task_id, run_id, kind, value, ts)
|
||
← 计费/审计明细,append-only
|
||
quotas(tenant_id, max_concurrent_runs, max_tokens_month, max_storage_bytes, ...)
|
||
```
|
||
|
||
**文件走本地磁盘**:
|
||
|
||
```
|
||
<storage_root>/
|
||
tenants/{tenant_id}/
|
||
tasks/{task_id}/
|
||
source/ ← 用户上传(PDF / 团队介绍等)
|
||
intermediate/← 中间产物(spec_lock.md / sections / slides)
|
||
artifact/ ← 最终产物(.docx / .pptx)
|
||
```
|
||
|
||
`files.path` 存相对 `<storage_root>` 的路径。`<storage_root>` 由部署配置决定(单机 = 一个目录,多 worker = 共享挂载点)。
|
||
|
||
为什么本地而不 S3:简化首版部署,运维门槛低;访问延迟低;tasks 文件总量 100GB 级别本地盘够用。规模真起来后,**files 表 + storage 抽象层只需换 backend,接口不动**。
|
||
|
||
### 7.5 沙盒:Per-task 容器 + Per-run exec
|
||
|
||
| 选择 | 理由 |
|
||
|---|---|
|
||
| 每 task 一个长驻容器 | 起容器 ~300ms 太慢;一个 task 多轮 tool call 共享容器才划算 |
|
||
| 每 run 一次 `docker exec` | 进容器跑 run_python/shell;exec 级 timeout/资源限制 |
|
||
| 容器空闲 N 分钟回收 | 不浪费;下次 resume 重新拉起 |
|
||
| `task_dir` 直接 bind mount 进容器 | 宿主 `<storage_root>/.../tasks/{id}/` 挂到容器 `/workspace`,无同步开销 |
|
||
|
||
**资源限制**:cgroup CPU/mem 上限、磁盘配额、网络 egress allowlist(只能出 LLM API 和 PyPI 镜像)、root 文件系统 read-only、no-new-privileges、drop ALL caps。
|
||
|
||
**选型**:Phase 起步用 **Docker**(运维门槛低);流量起来后视情况换 gVisor / Firecracker / e2b。Executor Protocol 抽象后切换成本低。
|
||
|
||
### 7.6 Core 代码改造(按依赖顺序)
|
||
|
||
| # | 改造 | 影响文件 | 估时 |
|
||
|---|---|---|---|
|
||
| 1 | **事件流化 `loop.py`** —— `console.print` 改成 `yield Event`;CLI 接 console sink,API 接 SSE sink | `core/loop.py` `cli.py` | 半天 |
|
||
| 2 | **Storage 层** —— `Session/TaskState` 落 Postgres;`files` 走 `<storage_root>` | `core/session.py` `core/task.py` `main.py` 新增 `core/storage/` | 2 天 |
|
||
| 3 | **Executor 抽象** —— `run_python`/`shell` 走 `Executor.run(code, timeout, env)`;实现 = `docker exec` 到 per-task 容器 | `tools/run_python.py` `tools/shell.py` 新增 `core/executor/` | 2 天 |
|
||
| 4 | **Config + 多租户上下文** —— 每次请求带 `(tenant_id, user_id)`,所有 storage/executor 调用都 scoped | `main.py` `cli.py` 全链路 | 1 天 |
|
||
| 5 | **`api_key_env` 退役** —— 改 `KeyProvider`,运行时从 vault 取(平台 BYO 模式则逐请求注入) | `core/capabilities.py` `core/llm.py` | 半天 |
|
||
| 6 | **HTTP 外壳** —— FastAPI app,把上面五层包成 `/v1/*` + SSE | 新增 `core/api/` | 3-4 天 |
|
||
|
||
代码量增量预估:**+800~1200 行**(API 层 + storage 层 + executor 层 + 配套测试)。
|
||
|
||
### 7.7 职责矩阵
|
||
|
||
| 事项 | Core | Platform | 备注 |
|
||
|---|---|---|---|
|
||
| 终端用户 auth | – | ✅ | OIDC/Clerk |
|
||
| 平台↔core 鉴权 | ✅ 验签 | ✅ 签发 | Bearer + JWT |
|
||
| 多租户数据隔离 | ✅ enforce | – | platform bug 不能跨租户 |
|
||
| Prompt injection 防护 | ✅ | – | 只有 core 看得见 LLM I/O |
|
||
| 敏感数据出站审计 | ✅ 产事件 | ✅ 消费转 SIEM | 双层 |
|
||
| 配额超限拒绝 | ✅ 计数 + 拒绝 | ✅ 展示给用户 | core 不能信平台传值 |
|
||
| 文件病毒扫描 | ✅ 入库再扫一次 | ✅ pre-upload 扫 | 双层 |
|
||
| GDPR 删除 | ✅ 提供 `DELETE` | ✅ 触发 | 数据在 core 这边 |
|
||
| LLM API key(BYO) | 运行时注入,**不持久化明文** | ✅ 加密存,逐请求传 | 降攻击面 |
|
||
| 计费 | ✅ 产 usage 事件 | ✅ 汇总 + Stripe | core 不碰钱 |
|
||
| 监控 / SLO | ✅ 自己负责 | – | 独立服务 |
|
||
|
||
### 7.8 分阶段落地
|
||
|
||
| 阶段 | 目标 | 工作量 | 验收 |
|
||
|---|---|---|---|
|
||
| **A** 改造 §7.6 #1(事件流化) | CLI 不变,但 loop yield event;为后续铺路 | 半天 | CLI 走 event sink 跑通 dogfood |
|
||
| **B** 改造 #2-#5(storage / executor / DI / key)| 单进程仍可跑;接口齐备 | 1 周 | CLI 接 Postgres 跑通本地多 task |
|
||
| **C** 改造 #6(HTTP 外壳)| `/v1/*` 跑通,docker compose 起完整栈(core api + sandbox + PG) | 4 天 | curl / Postman 跑通主流程 |
|
||
| **D** 多租户 + Auth + Quota + Audit | 平台接得上 | 1 周 | 平台 demo 跑通 |
|
||
| **E** 上线打磨(限流/监控/告警/HA) | 可承接平台真实流量 | 持续 | SLO 99.5% |
|
||
|
||
**A** 立刻可做,独立有价值。**B-D** 等平台团队 kickoff 时间锁定后开。**E** 上线后持续投入。
|
||
|
||
### 7.9 已知风险
|
||
|
||
| 风险 | 缓解 |
|
||
|---|---|
|
||
| 过早抽象违背 §5 哲学 | A 阶段单独有价值(支持 Web UI);B-E 等平台到位再做 |
|
||
| `/v1` 冻死后核心演化变慢 | minor 向后兼容窗口,major 6 个月 deprecation;内部加 `/v1internal` 用于实验 |
|
||
| Sandbox 网络出站限制不当 | Egress allowlist 起步只放 LLM endpoint + PyPI 镜像;skill 需要新出站靠申请 |
|
||
| Per-task 容器 ID 泄漏到对话 | tool 结果 sanitize,容器内 hostname/IP 不暴露 |
|
||
| 平台 bug 把 core 冲垮 | 平台维度限流(rate limit by Bearer key)+ 租户维度并发上限 |
|
||
| 文件计费/存储滥用 | 上传大小上限、月度配额、保留期(过期自动清) |
|
||
| LLM 成本失控 | BYO key 默认;平台代付要 per-tenant 月预算硬上限 |
|
||
| 本地盘容量瓶颈 | files 表 + storage 抽象层,换 backend 接口不动;LRU 清理冷 task |
|
||
| 多 worker 共享本地盘 | 起步单机部署即可;需要扩 worker 时上 NFS 或换对象存储 |
|
||
|
||
### 7.10 取舍说明
|
||
|
||
**为什么 Docker 起步而不直接上 Firecracker/gVisor**:Docker 运维门槛最低,Executor Protocol 抽象后可平滑切换。提前上 microVM 是过度工程。
|
||
|
||
**为什么不复用 K8s Job per run**:Job 启停成本高(秒级),agent loop 一轮 tool call 才几百毫秒。Per-task 长驻容器 + per-run exec 是性能/隔离的最佳折中。
|
||
|
||
**为什么本地文件而不 S3**:首版部署/运维门槛低,访问延迟低,100GB 级别单机够用。storage 抽象层留好,真要切对象存储改 backend 不改接口。
|
||
|
||
**为什么 Postgres 而不 SQLite**:service 形态下 API + sandbox + 后续 worker 都要读写状态,SQLite 单写锁会成为瓶颈。Postgres 起步成本可接受。
|
||
|
||
---
|
||
|
||
## 附录:DeepSeek V4 关键事实(2026-04-24)
|
||
|
||
- **V4-Pro**:1.6T 总 / 49B 激活,1M context,SWE-Bench 80.6 / Terminal-Bench 67.9 / MCPAtlas 73.6
|
||
- **V4-Flash**:284B 总 / 13B 激活,1M context
|
||
- 三种推理模式:non-thinking / thinking / thinking-max
|
||
- 价格:输入 ~$0.145/M,输出 ~$1.74/M(约 Claude Opus 1/6 ~ 1/7)
|
||
- `deepseek-chat` / `deepseek-reasoner` 在 2026-07-24 后下线 → 必须迁 `deepseek-v4-flash` / `deepseek-v4-pro`
|