diff --git a/DESIGN.md b/DESIGN.md index 20e90f5..9ebbd63 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -1,1140 +1,212 @@ -# 个人任务 Agent 设计方案 v2 +# 设计文档 -> 一个面向"写汇报 PPT、写科研申报书、写代码"三类任务的轻量级 agent 框架。 -> 完全自实现,综合 nanobot / CoreCoder / better-claw / smolagents 的优点,模型自由,**为模型持续升级做了演化性设计**。 - -> **v2 更新要点(2026-05)**: -> 1. 模型策略基于 DeepSeek V4 实际能力(2026-04-24 发布)重新设计 -> 2. Skill 系统对齐 Anthropic 开放标准(2025-12 发布,行业已成共识) -> 3. 工具范式改为 Hybrid:JSON tool call + run_python 混合 -> 4. 新增第 6 章「演化性设计」—— 让 agent 跟着模型升级而升级 -> 5. 新增 Eval Suite 框架,作为模型升级的决策依据 +> 一个本地运行的个人任务 agent。覆盖三类工作:写汇报 PPT、写科研申报书、写代码。 +> 模型自由(LiteLLM 接 OpenAI-compatible),代码可控(目标 1500-2000 行 Python,自己读得懂)。 --- -## 1. 设计目标与边界 +## 1. 边界 -### 1.1 要做什么 +### 做什么 +- **PPT**:文本 / 会议纪要 → `.pptx`(用 `python-pptx`) +- **科研申报**:课题信息 → 分章节 `.docx`(用 `python-docx`) +- **编码**:文件编辑、shell 执行、迭代验证 -构建一个本地运行的任务型 agent,能稳定完成三类工作: +### 不做什么 +- 子 agent / IM 渠道 / 多用户 / Web UI(初期 CLI 即可)/ 自定义 RAG / 锁定 Anthropic +- **Eval Suite**:个人工具用 dogfooding 判断模型升级,造作 case 没区分度 -| 任务模式 | 输入示例 | 输出 | 主要能力 | -|---------|---------|------|---------| -| **PPT 模式** | "把这份会议纪要做成 5 页汇报 PPT" | `.pptx` 文件 | 大纲提炼、版式设计、图表生成 | -| **科研申报模式** | "写一份国自然青年基金的立项依据" | `.docx` 文件(分章节) | 长文写作、文献检索、格式套模板 | -| **编码模式** | "修这个文件的 bug" / "实现这个函数" | 修改后的代码 | 文件编辑、shell 执行、迭代验证 | - -### 1.2 明确不做什么 - -- ❌ 子 agent / subagent -- ❌ IM 渠道(Telegram / WeChat / Discord 等) -- ❌ 多用户系统 -- ❌ Web UI(初期 CLI 即可) -- ❌ 自定义 RAG / 向量检索 -- ❌ Anthropic 锁定(必须模型自由) - -### 1.3 关键约束 - -- **模型自由**:支持 DeepSeek V4 / Kimi / Qwen / GPT / Claude 等任意 OpenAI-compatible API -- **代码可控**:总代码量 1100-1500 行,自己能完全读懂 -- **任务持久化**:任意时刻关机,下次能恢复 -- **长任务稳定**:单任务可跑数小时不崩 -- **演化性**:模型升级时 agent 能力随之升级,不需要大改架构 +### 关键约束 +- 模型自由:LiteLLM 接 OpenAI-compatible 任意 provider(默认 DeepSeek V4) +- 任务持久化:任意时刻关机,下次能恢复 +- 演化性:模型升级时 agent 跟着升级,不需要大改架构 --- -## 2. 各家方案借鉴清单 +## 2. 架构 -| 借鉴自 | 借鉴的设计 | 为什么抄 | -|--------|-----------|---------| -| **CoreCoder** | 主 agent loop 简洁实现 | ~150 行写完核心,可读性极高 | -| **CoreCoder** | Edit 工具的"唯一匹配"约束 | 防止 LLM 改错地方,业界最佳实践 | -| **CoreCoder** | 三层 context 压缩(简化版,V4 时代不太用) | 兜底方案 | -| **Anthropic Agent Skills** | **SKILL.md + 渐进披露 标准** | 行业标准,2025-12 开放,跨平台兼容 | -| **nanobot** | Workspace + 任务隔离的目录结构 | 多任务并行不互相污染 | -| **nanobot** | 双层记忆(core + extended) | core 注入 prompt,extended 按需读 | -| **better-claw** | Mid-query 轮转 + carryover | 长任务工程兜底 | -| **better-claw** | 任务状态持久化(state.json) | 支持中断恢复 | -| **smolagents** | LiteLLM 做模型层 | 一行切换 25+ provider | -| **smolagents** | `@tool` 装饰器风格 | 工具定义最简洁 | -| **smolagents** | **CodeAgent 思路(部分采用)** | 通过 `run_python` 工具实现 hybrid 范式 | -| **CodeAct 论文** | 代码作为 action 的范式 | 在数据/计算/批处理任务上比 JSON 强 20% | - ---- - -## 3. 整体架构 - -### 3.1 分层结构 +### 目录树(实际) ``` -┌──────────────────────────────────────────────┐ -│ 入口层 │ -│ - CLI(初期):interactive REPL │ -│ - 后期可加:Streamlit / Gradio Web UI │ -└──────────────────────────────────────────────┘ - ↓ -┌──────────────────────────────────────────────┐ -│ 任务路由层 │ -│ - /ppt → PPT 模式 + ppt skill │ -│ - /doc → 科研写作模式 + proposal skill │ -│ - /code → 编码模式 + coding skill │ -│ - 默认 → 通用模式 │ -└──────────────────────────────────────────────┘ - ↓ -┌──────────────────────────────────────────────┐ -│ Agent 核心 │ -│ - Loop:ReAct 循环(LLM ↔ Tool) │ -│ - Capability Manager:模型能力探测与适配 │ -│ - Context Manager:三层压缩(必要时) │ -│ - Session:对话历史持久化 │ -│ - Memory:双层记忆系统 │ -└──────────────────────────────────────────────┘ - ↓ -┌──────────────────────────────────────────────┐ -│ 工具层(Hybrid 范式) │ -│ 通用工具(JSON tool call): │ -│ - read / write / edit / glob / grep / shell │ -│ - web_search / web_fetch │ -│ - load_skill │ -│ - run_python(沙盒执行,Hybrid 关键) │ -│ │ -│ Skill 提供的工具(标准格式): │ -│ - skills//scripts/*.py │ -└──────────────────────────────────────────────┘ - ↓ -┌──────────────────────────────────────────────┐ -│ LLM 层(LiteLLM + Model Profile) │ -│ - 默认:DeepSeek V4-Flash │ -│ - 升级:DeepSeek V4-Pro / Claude Opus 4.7 │ -│ - Profile 化配置,新模型 5 分钟接入 │ -└──────────────────────────────────────────────┘ -``` - -### 3.2 目录结构 - -``` -your_agent/ +zcbot/ ├── core/ -│ ├── __init__.py -│ ├── loop.py # 主 agent loop ~150 行 -│ ├── llm.py # LiteLLM 封装 ~120 行 -│ ├── capabilities.py # 模型能力探测与适配 ~100 行 ⭐新增 -│ ├── context.py # 三层 context 压缩 ~150 行 -│ ├── session.py # 会话持久化 ~100 行 -│ └── memory.py # 双层记忆 ~80 行 +│ ├── 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/ -│ ├── __init__.py -│ ├── base.py # Tool 基类 ~50 行 -│ ├── fs.py # read/write/edit/glob/grep ~250 行 -│ ├── shell.py # bash 执行 + 安全检查 ~80 行 -│ ├── web.py # web_search + fetch ~80 行 -│ ├── run_python.py # 沙盒 Python 执行器 ~100 行 ⭐新增 -│ └── skill_tool.py # load_skill 工具 ~60 行 -├── skills/ # ⭐ 标准 Anthropic Agent Skills 格式 -│ ├── ppt/ -│ │ ├── SKILL.md # 主指引(短) -│ │ ├── references/ # 详细资料(按需读) -│ │ ├── scripts/ # 可执行脚本 -│ │ └── assets/ # 模板等资源 -│ ├── proposal/ -│ │ ├── SKILL.md -│ │ ├── references/ -│ │ ├── scripts/ -│ │ └── assets/ -│ └── coding/ -│ ├── SKILL.md -│ └── references/ -├── prompts/ # ⭐ 版本化系统提示词 -│ ├── system/ -│ │ ├── general_v1.md -│ │ └── general_active.md → general_v1.md -│ └── modes/ -│ ├── ppt.md -│ ├── proposal.md -│ └── coding.md +│ ├── 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/ # ⭐ 模型档案库 -│ ├── _template.yaml -│ ├── deepseek_v4.yaml -│ ├── claude_4_7.yaml -│ └── gpt_5.yaml -├── evals/ # ⭐ 评估任务集 -│ ├── coding/ -│ ├── ppt/ -│ ├── proposal/ -│ └── runner.py # eval 执行器 -├── workspace/ # 用户数据(gitignore) -│ ├── tasks/ -│ ├── memory/ -│ │ ├── core.md -│ │ └── extended/ -│ └── logs/ -├── cli.py # CLI 入口 ~150 行 -├── main.py # 装配 + 启动 ~50 行 -├── requirements.txt -└── README.md +│ ├── agent.yaml +│ └── models/ +│ └── deepseek_v4.yaml # flash + pro 两档 +├── workspace/ +│ └── tasks// +│ ├── state.json # TaskState +│ └── messages.json # Session +├── main.py # 装配 (build_agent) +└── cli.py # CLI: chat / tasks / probe ``` -**总代码量预估:1300-1600 行 Python**(比 v1 多 ~200 行,因为加了 capabilities 和 run_python) +### 启动时拼装顺序 +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 +6. 装配工具集(fs / shell / load_skill / run_python) +7. 写初始 `state.json` + `messages.json`,启动 REPL --- -## 4. 核心组件设计 +## 3. 核心组件 -### 4.1 Agent Loop(`core/loop.py`) +### 3.1 主循环(`core/loop.py`) +ReAct 风格:LLM → 若有 tool_calls 就执行 → 把结果塞回消息列表 → 再调 LLM。无 tool_call 即返回。 +- 工具结果对模型截断到 16K 字符,对用户预览 400 字符 +- 用 `console.status("thinking...")` 转圈点,所有日志走 `rich` +- `max_iterations` 从 capabilities 读,不同模型不同 -```python -class AgentLoop: - def __init__(self, llm, tools, capabilities, context_manager, session, - max_iterations=None): - self.llm = llm - self.tools = tools - self.caps = capabilities # ⭐ 模型能力档案 - self.ctx = context_manager - self.session = session - # 迭代次数从 capabilities 读取,不同模型不同 - self.max_iterations = max_iterations or self.caps.max_iterations - - def run(self, user_message: str) -> str: - self.session.append({"role": "user", "content": user_message}) - - for iteration in range(self.max_iterations): - messages = self.ctx.check_and_compress(self.session.messages) - - response = self.llm.chat( - messages=messages, - tools=[t.schema for t in self.tools.values()], - # ⭐ 高级特性按 capabilities 启用 - parallel_tool_calls=self.caps.parallel_tools, - reasoning_effort=self.caps.default_reasoning_effort - ) - msg = response.choices[0].message - self.session.append(msg) - - if not msg.tool_calls: - return msg.content - - # ⭐ 并行 vs 串行执行根据能力决定 - if self.caps.parallel_tools and len(msg.tool_calls) > 1: - results = self._execute_tools_parallel(msg.tool_calls) - else: - results = self._execute_tools_serial(msg.tool_calls) - - for tool_call, result in results: - self.session.append({ - "role": "tool", - "tool_call_id": tool_call.id, - "content": result - }) - - return "[已达到最大迭代次数]" -``` +### 3.2 Model Profile(`core/capabilities.py` + `config/models/*.yaml`) +**核心思想**:每个模型一份 yaml 档案,agent 行为按档案动态调整。新模型 5 分钟接入,不改代码。 -### 4.2 Model Profile + Capabilities(`core/capabilities.py`)⭐ 新增 +`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。 -**核心思想**:每个模型有自己的能力档案,agent 行为根据档案动态调整。新模型出来,加一个 yaml 即可。 +`LLM.chat` 按 capabilities 自动启 `parallel_tool_calls` / `reasoning_effort` / Anthropic prompt-caching header。 -```python -@dataclass -class ModelCapabilities: - """模型能力档案""" - model_id: str - - # 基础能力 - max_context: int # 最大上下文(tokens) - reliable_context: int # 实测可靠上下文 - max_output: int # 最大输出 - - # Tool calling - parallel_tools: bool # 是否支持并行 tool call - tool_calling_quality: str # "excellent" / "good" / "fair" - - # 思考模式 - thinking_mode: bool # 是否支持思考模式 - reasoning_effort_levels: list # ["low","medium","high","max"] - default_reasoning_effort: str - - # 推理与代码 - code_quality: str # CodeAct 范式适配度 - enable_run_python: bool # 是否启用 run_python 工具 - - # 工程参数 - max_iterations: int # 最大迭代次数 - optimal_temperature: float - - # 特殊功能 - prompt_caching: bool # Anthropic 特有 - extended_thinking: bool # Claude 4.x 特有 - - @classmethod - def from_yaml(cls, path: Path) -> "ModelCapabilities": - """从 config/models/*.yaml 加载""" - ... - - @classmethod - def detect(cls, model_id: str) -> "ModelCapabilities": - """根据 model_id 自动找到对应档案 - deepseek-v4-flash → config/models/deepseek_v4.yaml (variant=flash) - claude-opus-4-7 → config/models/claude_4_7.yaml - """ - ... -``` +### 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,默认关) -**模型档案示例** (`config/models/deepseek_v4.yaml`): +不修改 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//{state.json, messages.json}`。每轮 `agent.run` 后调 `sync_task_tokens` 把 LLM 累计 tokens 写回。 + +CLI:`chat --mode coding --desc "..."`;REPL `/status /done /abandon /desc`;`tasks [--status active|completed|abandoned]` 列任务。 + +--- + +## 4. 模型路由 + +### 默认配置(`config/agent.yaml`) ```yaml -family: deepseek_v4 -variants: - flash: - model_id: deepseek/deepseek-v4-flash - max_context: 1048576 - reliable_context: 262144 - max_output: 384000 - parallel_tools: true - tool_calling_quality: good - thinking_mode: true - reasoning_effort_levels: [non_thinking, thinking] - default_reasoning_effort: non_thinking - code_quality: good - enable_run_python: true - max_iterations: 50 - optimal_temperature: 0.3 - prompt_caching: false - extended_thinking: false - - pro: - model_id: deepseek/deepseek-v4-pro - max_context: 1048576 - reliable_context: 524288 - max_output: 384000 - parallel_tools: true - tool_calling_quality: excellent - thinking_mode: true - reasoning_effort_levels: [low, medium, high, max] - default_reasoning_effort: medium - code_quality: excellent - enable_run_python: true - max_iterations: 100 - optimal_temperature: 0.2 - prompt_caching: false - extended_thinking: false -``` - -**Claude 4.7 档案** (`config/models/claude_4_7.yaml`): - -```yaml -family: claude_4_7 -variants: - opus: - model_id: anthropic/claude-opus-4-7 - max_context: 200000 - reliable_context: 200000 - max_output: 8192 - parallel_tools: true - tool_calling_quality: excellent - thinking_mode: true - reasoning_effort_levels: [low, medium, high] - default_reasoning_effort: medium - code_quality: excellent - enable_run_python: true - max_iterations: 100 - optimal_temperature: 0.2 - prompt_caching: true # Claude 特有 - extended_thinking: true -``` - -**新模型怎么加(以未来 V5 为例)**: - -```bash -# 1. 复制模板 -cp config/models/_template.yaml config/models/deepseek_v5.yaml - -# 2. 填能力(从模型发布博客 + 跑一次 capability probe) -vim config/models/deepseek_v5.yaml - -# 3. 跑 eval suite 验证 -python evals/runner.py --model deepseek-v5-pro - -# 4. 切换默认模型 -vim config/agent.yaml # default_model: deepseek-v5-pro -``` - -整个流程不需要改任何 agent 核心代码。 - -### 4.3 LLM 封装(`core/llm.py`) - -```python -class LLM: - def __init__(self, capabilities: ModelCapabilities, api_key: str, base_url: str = None): - self.caps = capabilities - self.api_key = api_key - self.base_url = base_url - self.token_counter = TokenCounter() - - def chat(self, messages, tools=None, parallel_tool_calls=None, - reasoning_effort=None, max_retries=3): - # 用 capabilities 自动填充默认值 - kwargs = { - "model": self.caps.model_id, - "messages": messages, - "tools": tools, - "temperature": self.caps.optimal_temperature, - "api_key": self.api_key, - "base_url": self.base_url, - } - - # 按能力启用 - if self.caps.parallel_tools and parallel_tool_calls is not False: - kwargs["parallel_tool_calls"] = True - if self.caps.thinking_mode and reasoning_effort: - kwargs["reasoning_effort"] = reasoning_effort - if self.caps.prompt_caching: - kwargs["extra_headers"] = {"anthropic-beta": "prompt-caching-2024-07-31"} - - for attempt in range(max_retries): - try: - response = litellm.completion(**kwargs) - self.token_counter.add(response.usage, self.caps.model_id) - return response - except (RateLimitError, APIConnectionError): - if attempt == max_retries - 1: - raise - time.sleep(2 ** attempt) -``` - -### 4.4 工具系统(Hybrid 范式) - -#### 4.4.1 通用工具(JSON tool call) - -文件操作工具的核心仍然是 **Edit 工具的"唯一匹配"约束**(借鉴 CoreCoder): - -```python -class EditTool(Tool): - name = "edit" - description = "Replace a unique string in a file with another string." - - def execute(self, path: str, old_str: str, new_str: str) -> str: - content = Path(path).read_text() - count = content.count(old_str) - if count == 0: - return f"[Error] old_str not found in {path}" - if count > 1: - return f"[Error] old_str appears {count} times, must be unique" - Path(path).write_text(content.replace(old_str, new_str)) - return self._make_diff(content, ...) -``` - -#### 4.4.2 `run_python` 工具 ⭐ 新增 - -**Hybrid 范式的关键**:agent 主要用 JSON tool call,但需要时可以写代码作为 action: - -```python -class RunPythonTool(Tool): - name = "run_python" - description = """Execute Python code in a sandboxed environment. - - Use for: - - Data analysis, statistics, calculations - - Batch file operations (process many files) - - Document generation (PPT, Word, charts) - - Tasks where code is more natural than tool composition - - Available libraries: pandas, numpy, matplotlib, python-pptx, python-docx, - arxiv, requests, pypdf, pdfplumber. - - Working directory is the current task's tasks//. - Files created here are automatically available to the user. - """ - - def execute(self, code: str, timeout: int = 60) -> str: - # 阶段 1(本地用):subprocess + venv + 工作目录限制 - # 阶段 2(更安全):Docker container - # 阶段 3(公开服务):E2B / Modal - - with tempfile.NamedTemporaryFile(suffix=".py", mode="w", delete=False) as f: - f.write(code) - script_path = f.name - - try: - result = subprocess.run( - [sys.executable, script_path], - cwd=self.task_dir, # 限制工作目录 - capture_output=True, - timeout=timeout, - env=self._safe_env() # 过滤敏感环境变量 - ) - return self._format_result(result) - finally: - os.unlink(script_path) -``` - -**为什么这是关键设计**: -- **JSON tool call 处理离散操作**(读文件、跑命令、查文献) -- **Code execution 处理连续逻辑**(算数据、批处理、生成文档) -- 模型自己决定什么时候用什么,不是你硬编码 - -#### 4.4.3 工具粒度原则 ⭐ 新增 - -工具切分按"原子操作"原则,不做高级封装: - -```python -# ❌ 反模式:工具做太多,模型用不灵活 -class GenerateProposalTool: - def execute(self, topic): - # 内部硬编码 8 章节流程 - -# ✅ 正模式:原子操作,组合策略给模型 -class WriteSectionTool: # 写一节 -class CompileDocxTool: # 合并成 docx -class SearchPapersTool: # 查文献 -class FormatBibtexTool: # BibTeX 格式化 -``` - -**理由**:模型变强后会有更好的组合策略。封装太死接收不到模型升级的红利。 - -### 4.5 Skill 系统(对齐 Anthropic 开放标准)⭐ 重大调整 - -#### 4.5.1 标准目录结构 - -每个 skill 是一个目录,包含: - -``` -skills/proposal/ -├── SKILL.md # 主指引(短,~3000 tokens 内) -├── references/ # 详细资料(按需加载) -│ ├── nsfc_format.md -│ ├── citation_style.md -│ └── section_examples.md -├── scripts/ # 可执行脚本(可作为工具) -│ ├── search_papers.py -│ ├── format_bibtex.py -│ └── compile_docx.py -└── assets/ # 模板、字体等 - └── templates/ - ├── nsfc_youth.docx - ├── nsfc_general.docx - └── nsfc_key.docx -``` - -#### 4.5.2 SKILL.md 标准格式 - -```markdown ---- -name: proposal -description: 撰写科研申报书(国自然/省基金/横向项目)。当用户需要写课题申请、立项依据、项目书时使用。 ---- - -# 科研申报书 - -## 资源 -- `references/nsfc_format.md`:国自然格式细节 -- `references/citation_style.md`:引文规范 -- `references/section_examples.md`:各章节范例 -- `scripts/search_papers.py`:可执行,文献检索 -- `scripts/compile_docx.py`:可执行,合并章节为 docx -- `assets/templates/`:不同基金类型的 docx 模板 - -## 原则 -- 文献必须真实(用 search_papers,绝不编造) -- 分章节写,不一次性生成全文 -- 先与用户对齐课题信息卡片 - -## 工作目录 -所有产出在 `tasks//`: -- `project.md` - 课题信息卡片 -- `sections/.md` - 各章节草稿 -- `proposal.docx` - 最终输出 - -## 字数参考 -立项依据 5000-8000 字,研究内容 3000-5000 字。 -具体格式参见 references/nsfc_format.md。 -``` - -注意:**不再写"Step 1/2/3"流程**,只写资源、原则、目标。让模型自己规划。 - -#### 4.5.3 Progressive Disclosure(渐进披露)的三层加载 - -按 Anthropic 标准: - -| 层 | 时机 | 内容 | Token 占用 | -|---|------|------|----------| -| **Discovery** | Agent 启动 | 仅 `name + description`,所有 skill 都加载 | 几百 tokens | -| **Activation** | 任务匹配某个 skill | 完整 SKILL.md 主体 | 1000-5000 tokens | -| **Execution** | SKILL.md 引用某个 reference 时 | 单个 reference 文件 | 视情况 | - -具体实现: - -```python -# 启动时:Discovery -def build_initial_system_prompt(skills) -> str: - skill_descriptions = [] - for name, skill in skills.items(): - meta = parse_frontmatter(skill["SKILL.md"]) - skill_descriptions.append(f"- {name}: {meta['description']}") - - return f""" -You are a task agent. Available skills: -{chr(10).join(skill_descriptions)} - -Use `load_skill(name)` to load full instructions when relevant. -""" - -# Agent 调用 load_skill 后:Activation -class LoadSkillTool(Tool): - def execute(self, name: str) -> str: - return (skills_dir / name / "SKILL.md").read_text() - -# Agent 在 SKILL.md 里看到 references/xxx.md,主动调 read_file:Execution -# 这一层不需要专门工具,就是普通 read 工具 -``` - -#### 4.5.4 Skill 设计原则(基于 Anthropic 官方 + 行业经验) - -1. **Description 是关键** —— 决定模型能否触发,要明确具体 -2. **SKILL.md 主体不超过 5000 tokens / 500 行** —— 超过就拆 references/ -3. **写 WHY+WHAT,不写 HOW** —— 描述目标和资源,不写步骤 -4. **代码即工具又是文档** —— scripts/ 里的脚本可以执行,也可以读到 context 当文档 -5. **保持 Skill 数 ≤ 20**,工具数 ≤ 10 同时可见(超过后准确率下降) - -### 4.6 Context 管理(简化版) - -V4 时代 long context 性能好了很多,**大部分任务不再需要复杂压缩**。但保留三层兜底: - -```python -class ContextManager: - def __init__(self, capabilities, llm): - # ⭐ 阈值从 capabilities 读取,不同模型不同 - self.max_tokens = capabilities.reliable_context - self.soft = self.max_tokens * 0.6 # V4 长 context 强,提高阈值 - self.force = self.max_tokens * 0.85 - self.collapse = self.max_tokens * 0.95 - self.llm = llm - - def check_and_compress(self, messages): - tokens = count_tokens(messages) - if tokens < self.soft: - return messages - if tokens < self.force: - return self._snip_old_tool_results(messages) - if tokens < self.collapse: - return self._microcompact(messages) - return self._collapse(messages, llm=self.llm) -``` - -**实测预期**:DeepSeek V4-Pro 在 256K 内基本不触发任何压缩,写一份完整申报书(7-8 万 token)用 V4-Flash 也只触发到 soft 层。 - -### 4.7 Session 与 Memory - -(沿用 v1 设计,无重大变化) - ---- - -## 5. 模型路由策略(基于 V4 实际能力)⭐ 重大调整 - -### 5.1 默认配置:V4-Flash 当主力 - -```yaml -# config/agent.yaml default_model: deepseek_v4.flash - -# 模式覆盖 -by_mode: - general: deepseek_v4.flash - - coding: deepseek_v4.flash # SWE-Bench 80.6,Flash 已够用 - coding_hard: deepseek_v4.pro # 复杂 bug、架构设计 - - ppt: deepseek_v4.flash # PPT 生成不需要顶级模型 - - proposal_draft: deepseek_v4.flash - proposal_final: - profile: deepseek_v4.pro - reasoning_effort: max # 终稿用最强模式 - -# 工具用模型(便宜) -utility: - summarize: deepseek_v4.flash - title: deepseek_v4.flash - -# 紧急升级路径(V4 不行时手动切) -fallback: - - claude_4_7.opus # 国基终稿如果质量不够,临时切 Claude ``` -### 5.2 成本预估 +设计上的分模式路由(后续要做)思路: +| 模式 | 模型 | 理由 | +|-----|-----|------| +| 通用 / 编码 / PPT / 提案初稿 | flash | flash SWE-Bench 80.6,够用 | +| 复杂 bug / 提案终稿 | pro + reasoning_effort=max | 关键产出值得花 | +| fallback | claude_4_7.opus | V4 不行时手动切 | -| 任务 | V4-Flash | V4-Pro-Max | Claude Opus 4.7 | -|-----|---------|-----------|------------------| +### 成本量级 +| 任务 | flash | pro-max | Claude Opus 4.7 | +|-----|------|--------|------| | 修一个 bug(~10 轮) | $0.01 | $0.05 | $0.30 | | 5 页汇报 PPT | $0.05 | $0.20 | $1.50 | -| 一份完整申报书(2-3 小时) | $0.30 | $1.50 | $10-15 | +| 完整申报书 | $0.30 | $1.50 | $10-15 | -**结论**:99% 任务 V4-Flash 已够用,关键终稿可升级 Pro,Claude 仅作 fallback。 +99% 任务 flash 够用,关键终稿升级 Pro。 --- -## 6. 演化性设计 ⭐ 新增章节 +## 5. 设计哲学 -> **核心问题**:模型每 3-6 个月迭代一次,agent 怎么不被甩在后面? - -### 6.1 设计哲学 - -**Less Scaffolding, More Trust**(少脚手架,多信任) - -老 agent 框架(LangChain 早期、AutoGPT)失败的核心原因:**给 LLM 太多脚手架,模型升级后这些脚手架成了枷锁**。 - -参考反例: -- 强制 ReAct 三段式输出 —— GPT-4 出来后这种格式反而降智 -- PydanticOutputParser 死磕格式 —— Structured Output 内置后成了多此一举 -- Prompt 里详细教"应该怎么思考" —— 强模型不需要被教 +### 核心原则:Less Scaffolding, More Trust +老 agent 框架(早期 LangChain、AutoGPT)失败的核心:给 LLM 太多脚手架,模型升级后这些脚手架成枷锁。 **正确做法**:把 LLM 当一个**会持续变强的同事**对待,告诉它目标,不告诉它步骤。 -### 6.2 七条具体原则 +### 七条具体原则 +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 更有效;**已删** -#### 原则 1:Prompt 用 WHY+WHAT,不用 HOW - -``` -❌ HOW 型: -"修 bug 时: -1. 先用 read 工具读文件 -2. 再用 grep 找相关位置 -3. 然后用 edit 工具替换 -4. 最后跑测试..." - -✅ WHY+WHAT 型: -"目标:修复用户报告的 bug,做最小可逆修改。 -工具:read, edit, grep, run, ... -原则:验证后再改、最小变更、有测试就跑。" -``` - -#### 原则 2:Skill 用渐进披露,不写完整流程 - -直接对齐 Anthropic 开放标准。Discovery 层只放 description,模型理解能力越强触发越准 —— 你不用回头给老 description 加 trigger 词。 - -#### 原则 3:工具按原子操作切分,不做高级封装 - -详见 4.4.3。粒度太粗,模型升级后没有施展空间。 - -#### 原则 4:Model Profile 化,不硬编码 - -详见 4.2。所有模型相关参数都在 yaml 里,新模型 5 分钟接入。 - -#### 原则 5:Capability Probing(启动时探测) - -```python -def probe_capabilities(llm) -> dict: - """启动时跑几个小测试,验证 yaml 里声称的能力""" - results = {} - - # 测试 1:并行 tool call 是否真的工作 - response = llm.chat([...], tools=[...test_tools]) - results["parallel_tools_actual"] = len(response.tool_calls) > 1 - - # 测试 2:thinking mode 输出是否符合预期 - response = llm.chat([...], reasoning_effort="medium") - results["thinking_works"] = hasattr(response.choices[0].message, "reasoning_content") - - # 测试 3:long context recall(简化版 needle in haystack) - needle = f"The secret code is {random_code()}." - haystack = make_long_context(needle, target_tokens=100_000) - response = llm.chat([{"role": "user", "content": haystack + "\nWhat is the secret code?"}]) - results["long_context_100k"] = random_code() in response.choices[0].message.content - - return results -``` - -发现实际能力跟 yaml 不符 → 警告并自动调整。 - -#### 原则 6:版本化 Prompt,支持 A/B 切换 - -``` -prompts/system/ -├── coding_v1.md # 老模型用的详细版 -├── coding_v2.md # 新模型用的精简版 -└── coding_active.md → coding_v2.md -``` - -模型升级时: -1. 写一个新版本 prompt(更精简、更信任模型) -2. 在 eval suite 上对比 v1 vs v2 -3. 数据说话,切换 active 软链接 - -#### 原则 7:Eval Suite —— 模型升级的决策基础 - -**最关键的一条**。没有 eval,你升级模型只能"凭感觉"。 - -详见下一节。 - -### 6.3 Eval Suite 框架 - -#### 6.3.1 目录结构 - -``` -evals/ -├── coding/ -│ ├── fix_import_bug/ -│ │ ├── input/ # 输入文件 -│ │ │ └── main.py -│ │ ├── prompt.txt # 给 agent 的指令 -│ │ ├── expected/ # 期望输出 -│ │ │ └── main.py -│ │ └── rubric.yaml # 评分标准 -│ ├── implement_function/ -│ └── refactor/ -├── ppt/ -│ ├── meeting_to_slides/ -│ │ ├── input/ -│ │ │ └── notes.md -│ │ ├── prompt.txt -│ │ └── rubric.yaml # 主观评分(LLM-as-judge) -│ └── ... -├── proposal/ -│ ├── write_intro_section/ -│ ├── search_and_cite/ -│ └── ... -└── runner.py # 执行器 -``` - -#### 6.3.2 Rubric 示例 - -**客观评分**(coding 任务): -```yaml -# evals/coding/fix_import_bug/rubric.yaml -type: deterministic -checks: - - type: file_diff - path: main.py - expected_path: expected/main.py - - type: run_command - command: python -c "import main" - expect_exit_code: 0 - - type: run_tests - command: pytest tests/ -``` - -**主观评分**(ppt/proposal 任务): -```yaml -# evals/ppt/meeting_to_slides/rubric.yaml -type: llm_judge -judge_model: claude-opus-4-7 # 用强模型当裁判 -criteria: - - "幻灯片数是否符合要求(5 页)" - - "每页 bullet 是否 ≤ 5 条" - - "信息密度是否合理" - - "是否有图表(如果数据 ≥ 3 个点)" -score_threshold: 7 # 满分 10 -``` - -#### 6.3.3 Runner - -```python -# evals/runner.py -def run_eval_suite(model_id: str, suite: str = "all"): - results = [] - for case_dir in find_cases(suite): - # 起一个干净的 agent 实例 - agent = build_agent(model=model_id, workspace=tmp_workspace()) - - # 跑测试 - prompt = (case_dir / "prompt.txt").read_text() - result = agent.run(prompt) - - # 评分 - rubric = load_rubric(case_dir / "rubric.yaml") - score = grade(rubric, agent.workspace, result) - - results.append({ - "case": case_dir.name, - "score": score, - "tokens": agent.token_counter.total, - "cost": agent.token_counter.cost_usd, - "duration": agent.duration_seconds - }) - - return summarize(results) - -if __name__ == "__main__": - # 模型升级时,跑这个 - print(run_eval_suite("deepseek-v4-flash")) - print(run_eval_suite("deepseek-v4-pro")) - # 对比看哪个性价比最高 -``` - -#### 6.3.4 Eval 的真实用途 - -每次模型升级,你能用数据回答这些问题: - -> Q1:V5-Flash 出来了,值得升级吗? -> A:跑 eval suite,对比 V4-Flash vs V5-Flash 的 score 和 cost。 - -> Q2:Claude Opus 5.0 出来了,要不要换主力? -> A:跑 eval。如果 score 提升 < 10% 但 cost 涨 10x,继续用 DeepSeek。 - -> Q3:某个 prompt 改了之后,效果是好是坏? -> A:跑 eval。 - -**没有 eval suite,你的"升级"全靠想象。** - -### 6.4 实操:模型升级 checklist - -未来 V5、Opus 5、GPT-6 出来时,按这个流程: - -```markdown -## 模型升级 Checklist - -- [ ] 1. 写新模型档案 yaml (5 分钟,从 _template 起) -- [ ] 2. 跑 capability probe 验证 yaml(10 分钟) -- [ ] 3. 跑完整 eval suite 测试新模型(30 分钟,看任务量) -- [ ] 4. 对比 score / cost / latency,判断是否升级 -- [ ] 5. 如果升级: - - [ ] 在 config 里调整 default_model - - [ ] 检查现有 prompt 是否可以精简(强模型不需要那么多脚手架) - - [ ] 跑 eval 回归一遍 -- [ ] 6. 部分模式按需升级(比如只把 proposal_final 升级到新 Pro) -``` - -整个流程**不需要改 agent 核心代码**。 +### 借鉴自(简版) +| 来源 | 借鉴 | +|-----|------| +| CoreCoder | 主循环简洁实现 + Edit 唯一匹配约束 | +| Anthropic Agent Skills | SKILL.md + 渐进披露标准 | +| nanobot | Workspace + 任务隔离 | +| smolagents | LiteLLM 做模型层 + CodeAct 范式启发 run_python | --- -## 7. 关键工程细节 - -### 7.1 任务状态(`tasks//state.json`) - -```json -{ - "task_id": "proposal_20260102_1430", - "mode": "proposal", - "description": "国自然青年基金 - LLM agent 在医疗问诊", - "status": "active", - "model_used": "deepseek-v4-pro", - "reasoning_effort": "max", - "created_at": 1735800000, - "tokens_used": {"prompt": 145000, "completion": 38000}, - "cost_usd": 0.42 -} -``` - -### 7.2 中断恢复 / 成本控制 / 安全约束 - -(沿用 v1 设计,无重大变化) - ---- - -## 8. 实施路线图 - -### Phase 1:最小可用骨架(2 天) - -- [x] `core/llm.py` + Model Profile 雏形 -- [x] `core/loop.py` - 主循环 -- [x] `core/session.py` -- [x] `tools/base.py` + `tools/fs.py` + `tools/shell.py` -- [x] `cli.py` - 基础 REPL -- [x] `config/agent.yaml` + `config/models/deepseek_v4.yaml` - -**验收**:`python cli.py chat` 能让 V4-Flash 修一个简单 Python bug。 - -### Phase 2:Skill 系统(标准格式)+ 三个 skill(2 天) - -- [x] `tools/skill_tool.py`(LoadSkill) -- [x] 三个 skill 目录,对齐 Anthropic 格式 -- [x] 任务模式路由 - -**验收**:三种模式都能进入,渐进披露正常工作。 - -### Phase 3:Hybrid 范式(1-2 天) - -- [x] `tools/run_python.py` - subprocess 沙盒版 -- [x] PPT/Word 通过 run_python 生成(不再做高级 API 封装) -- [x] PDF / 文献检索脚本到 skills/proposal/scripts/ - -**验收**:能产出 .pptx 和 .docx,文献检索真实。 - -### Phase 4:演化性能力(1-2 天)⭐ 新增 - -- [x] `core/capabilities.py` - Model Profile 加载 -- [x] Capability Probing 启动检测 -- [x] 版本化 prompts/ 目录结构 -- [x] 配置热重载 - -**验收**:能切换 V4-Flash 和 V4-Pro 不用改代码,只改 config。 - -### Phase 5:Eval Suite(2 天)⭐ 新增 - -- [x] `evals/runner.py` -- [x] 每种任务 3-5 个测试 case -- [x] LLM-as-judge 评分 -- [x] 报告输出(score / cost / latency) - -**验收**:`python evals/runner.py --model deepseek-v4-flash` 能跑完所有任务并出报告。 - -### Phase 6:长任务工程化(2-3 天) - -- [x] `core/context.py` - 三层压缩(兜底用) -- [x] `core/memory.py` - 双层记忆 -- [x] 任务恢复机制 - -**验收**:写完整一份申报书不崩,中断后能恢复。 - -### Phase 7:打磨(持续) - -- 双层记忆系统完善 -- 更多 skill -- Web UI(可选) -- Docker 沙盒(替代 subprocess) -- 更多模型档案(Claude / GPT / Kimi 等) - ---- - -## 9. 技术栈清单 - -``` -# requirements.txt(核心) - -# LLM -litellm>=1.50.0 -tiktoken>=0.7.0 - -# 文档(给 run_python 用) -python-pptx>=0.6.21 -python-docx>=1.1.0 -pypdf>=3.17.0 -pdfplumber>=0.10.0 -matplotlib>=3.8.0 -pandas>=2.0.0 - -# 文献 -arxiv>=2.1.0 -requests>=2.31.0 - -# CLI / 配置 -click>=8.1.0 -rich>=13.7.0 -pydantic>=2.5.0 -pyyaml>=6.0 -python-frontmatter>=1.0.0 - -# Eval -deepdiff>=6.0 # 文件 diff 比对 - -# 开发 -pytest>=7.4.0 -ruff>=0.1.0 -``` - ---- - -## 10. 风险与权衡 - -### 10.1 已知风险 +## 6. 风险与取舍 +### 已知风险 | 风险 | 缓解 | |-----|------| -| run_python 沙盒安全(subprocess 不够强) | 限制工作目录 + 环境变量过滤;后期升级 Docker | -| V4 在某些复杂任务上仍不如 Claude | Eval suite 帮判断;fallback 机制 | -| Skill description 不够好 → 触发不准 | 用 V4-Pro 优化 description;eval 测触发率 | -| Long context 退化 | Capability probe 探测 reliable_context;不要依赖宣称值 | -| Prompt 改了一次就不敢动 | 版本化 + eval 让改动有数据支撑 | +| 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) | -### 10.2 取舍说明 +### 取舍说明 +**为什么用 Hybrid 范式而不是纯 CodeAgent**:V4 JSON tool call 已稳定;沙盒成本只在需要时付;兼容 thinking 模式。 -**为什么改用 Anthropic Skill 标准而不是自创**: -- 行业标准已成,跨平台兼容 -- 直接拿到 Anthropic skills repo 的现成资源 -- 未来想换底层 SDK 不用改 skill +**为什么用 Anthropic Skill 标准而不是自创**:行业标准已成,跨 SDK 兼容;直接拿 Anthropic 现成 skills repo。 -**为什么用 Hybrid 范式而不是纯 CodeAgent**: -- DeepSeek V4 在 JSON tool calling 已足够稳定 -- 沙盒成本更低(只在需要时执行代码) -- 可以兼容 thinking 模式(纯 CodeAgent 跟 thinking 不太合) +**为什么不做 subagent**:状态管理复杂度爆炸;单 agent + skill 已覆盖 95% 场景。 -**为什么花精力做 Eval Suite**: -- 没有 eval,模型升级决策只能凭感觉 -- 一次性投入,长期复用 -- 跑 eval 的成本(~$10)远低于因为没 eval 选错模型的成本 - -**为什么不做 subagent**: -- 用户明确不需要 -- 加了之后状态管理复杂度爆炸 -- 单 agent + skill 已能覆盖 95% 场景 +**为什么不做 Eval Suite**:DESIGN 旧版按团队/产品场景设计;个人单用户场景里,跑两个真实任务的 dogfooding 比造作 case 信号更强,probe 已覆盖健康检查。 --- -## 11. 与 v1 方案的差异 +## 附录:DeepSeek V4 关键事实(2026-04-24) -| 维度 | v1 | v2 | -|-----|----|----| -| 默认模型 | deepseek-chat (V3.2) | deepseek-v4-flash | -| Context 阈值 | 65K, 0.5/0.7/0.85 | 256K, 0.6/0.85/0.95 | -| 工具范式 | 纯 JSON tool call | **Hybrid:JSON + run_python** | -| Skill 格式 | 自创 | **Anthropic 开放标准** | -| Skill 描述风格 | "Step 1/2/3" 流程 | **WHY+WHAT 风格** | -| 模型配置 | 散在 config 里 | **Model Profile 化** | -| 升级机制 | 无 | **Capability Probing + Eval Suite** | -| Prompt 管理 | 散在代码里 | **版本化 + active 软链接** | -| 工具粒度 | 部分高级封装(如 make_pptx) | **原子化(用 run_python 调 python-pptx)** | -| 代码量 | 1100-1300 行 | 1300-1600 行 | - ---- - -## 12. 下一步 - -确认方案后,从 Phase 1 开始落地: - -1. 起项目骨架 -2. 写 `core/llm.py` + `core/capabilities.py` -3. 写 `config/models/deepseek_v4.yaml` -4. 跑通最小 REPL -5. 用 V4-Flash 跑一个简单任务 - -Phase 1 预计 2 天完成,跑通后能立即用。 - ---- - -## 附录 A:Anthropic Skill 标准参考 - -官方资源: -- [Agent Skills 文档](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview) -- [Anthropic skills 仓库](https://github.com/anthropics/skills)(开源,可直接抄) -- 现成可用的 skill:pdf-processing、xlsx、docx、pptx、claude-api 等 - -行业落地: -- Claude Code: `~/.claude/skills/` -- OpenAI Codex CLI: `.agents/skills/` -- Google Gemini CLI: `.gemini/skills/` -- GitHub Copilot: 同日跟进 -- **格式完全统一**,只是路径不同 - -## 附录 B:DeepSeek V4 关键事实(2026-04-24) - -模型: -- V4-Pro:1.6T 总 / 49B 激活,1M context -- V4-Flash:284B 总 / 13B 激活,1M context +- **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 - -Agent 能力(V4-Pro-Max): -- SWE-Bench Verified: 80.6%(对标 Claude Opus 4.6 的 80.8%) -- Terminal-Bench 2.0: 67.9%(超过 Claude 4.6 的 64.3%) -- MCPAtlas: 73.6%(对标 Claude 4.6 的 73.8%) - -价格: -- 输入约 $0.145 / M tokens(Claude Opus 的 1/7) -- 输出约 $1.74 / M tokens(Claude Opus 的 1/6) - -迁移: -- `deepseek-chat` / `deepseek-reasoner` 在 2026-07-24 后下线 -- 必须迁到 `deepseek-v4-flash` / `deepseek-v4-pro` - -## 附录 C:演化性设计的灵感来源 - -- **Anthropic "Equipping agents for the real world"** —— Skill 渐进披露的设计哲学 -- **CodeAct 论文(Wang et al. 2024)** —— Code as action 范式 -- **LangChain 早期教训** —— 过度脚手架的反例 -- **Karpathy 的 nanoGPT 哲学** —— "可读性优先于功能完备" - ---- - -*Last updated: 2026-05-02* -*v2 changes: DeepSeek V4 / Anthropic Skill 标准 / Hybrid 范式 / 演化性设计* +- 价格:输入 ~$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` diff --git a/PROGRESS.md b/PROGRESS.md index 51c5718..686f51f 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -1,113 +1,38 @@ # 实施进度 -> 配合 `DESIGN.md` 阅读。本文件记录已完成的事、关键决策、与原设计的偏差。 +> 配合 `DESIGN.md` 阅读。本文件只记录 phase 状态、决策偏差、文件量、下一步。 -最后更新: 2026-05-06 (Phase 4 + Phase 6 task/state.json 落地;移除 legacy session 兼容;Phase 5 evals 决定不做) +最后更新:2026-05-06(Phase 4 + Phase 6 task/state.json 落地;Phase 5 evals 决定不做) --- -## 总体状态 +## 状态 | Phase | 标题 | 状态 | 备注 | |------|-----|-----|------| -| 1 | 最小可用骨架 | ✅ 完成 | 全部验收点过 | -| 2 | Skill 系统 + 三个 skill | ✅ 完成 | Anthropic 格式;coding/ppt/proposal | -| 3 | Hybrid 范式 (run_python) | ✅ 完成 | subprocess + 敏感 env 过滤 | -| 4 | 演化性能力 | 🟡 部分 | Model Profile 已就位;capability probing ✅;版本化 prompts 未做 | -| 5 | Eval Suite | ⏸ 不做 | 个人工具,造作 case 没区分度;真换模型用 dogfooding 判断 | -| 6 | 长任务工程化 | 🟡 部分 | task + state.json ✅;session 中断恢复 ✅;context 压缩、双层记忆未做 | -| 7 | 打磨 | ❌ 未开始 | Docker 沙盒 / 更多 skill / Web UI | +| 1 | 最小可用骨架 | ✅ | 全部验收点过 | +| 2 | Skill 系统 + 三个 skill | ✅ | Anthropic 格式;coding/ppt/proposal | +| 3 | Hybrid 范式 (run_python) | ✅ | subprocess + 敏感 env 过滤 | +| 4 | 演化性能力 | 🟡 | Model Profile + Capability Probing ✅;版本化 prompts 未做 | +| 5 | Eval Suite | ⏸ 不做 | 个人工具用 dogfooding 替代,probe 覆盖健康检查 | +| 6 | 长任务工程化 | 🟡 | task + state.json + 中断恢复 ✅;context 压缩、双层记忆未做 | +| 7 | 打磨 | ❌ | Docker 沙盒 / 更多 skill / Web UI | --- -## 已完成清单 +## 已完成关键能力 -### 1. 项目骨架 -- 目录: `core/ tools/ skills/ prompts/ config/ workspace/` -- 入口: `cli.py` (REPL) + `main.py` (装配) -- 依赖: `requirements.txt` (litellm / pyyaml / click / rich / python-pptx / python-docx / matplotlib) -- 本地虚拟环境: `.venv/`(Python 3.10.9) +**Phase 1-3**(2026 早期):骨架 + skill 系统 + run_python。所有工具基目录是用户当前 cwd(不是 zcbot 仓库本身),agent 操作的是用户项目。`tools/fs.py` 的 `edit` 用 CoreCoder 风格唯一匹配。`tools/run_python.py` 过滤 `*API_KEY *TOKEN *SECRET *PASSWORD *PRIVATE_KEY` 环境变量。三个 skill 中 `ppt/` 最完整(v3:商务红硬约束 + apply_brand 品牌条 + Iconify 图标库 + scripts:fetch_icon / quality_check / source_to_md / render_icon)。 -### 2. 模型层 -- `core/capabilities.py`: `ModelCapabilities` 数据类,从 `config/models/.yaml` 加载 -- `core/llm.py`: LiteLLM 封装,自动按 capabilities 启用 parallel_tools / reasoning_effort / prompt_caching / thinking_mode;指数退避重试 -- `config/models/deepseek_v4.yaml`: flash 和 pro 两档 -- 缺 `DEEPSEEK_API_KEY` 时报清晰错误,不崩 +**Phase 4**(2026-05-06): +- `core/probe.py` + `cli.py probe` —— basic_chat / parallel_tools / thinking_mode / long_context 四项探测 +- 真实 probe 跑通,**flash mismatch 发现**:yaml `parallel_tools: false` 但实测能并发(暂不自动改 yaml,需更多场景观察) +- pro 全 ok -### 3. 会话与持久化 -- `core/session.py`: 内存消息列表 + 元数据 + 落盘 JSON,文件格式 - ```json - {"meta": {"id","created_at","cwd","model","model_profile"}, "messages": [...]} - ``` - 老格式(纯 list)向后兼容 -- 每次 `cli.py chat` 启动一个新 session,文件名 `workspace/sessions/.json` -- 支持: `--resume last` / `--resume `;resume 时若当前 cwd 与记录不同会警告 -- REPL 命令: `/exit /reset /new /id` -- `cli.py sessions` 列表显示 id / msgs / cwd / 第一条用户消息预览 - -### 4. ReAct 主循环 -- `core/loop.py`: LLM ↔ tool 循环,无 tool_calls 即返回 -- LLM 调用包了 `console.status("thinking...", spinner="dots")` 转圈点 -- 工具结果对模型截断到 16K 字符,对用户预览 400 字符 -- 所有日志走 `rich.Console`,彩色 - -### 5. 通用工具 -- `tools/base.py`: `Tool` 基类 + `_resolve` 路径解析 -- `tools/fs.py`: - - `read` —— 带行号,支持 offset/limit - - `write` —— 自动建父目录,覆写 - - `edit` —— old_str **唯一匹配**约束(CoreCoder 风格) - - `glob` —— `**/*.py` 等模式 - - `grep` —— Python 正则,自动跳过 `.git node_modules __pycache__ .venv venv dist build` -- `tools/shell.py`: subprocess 执行,黑名单拦 `rm -rf /` 等;默认 60s 超时 -- `tools/run_python.py`: subprocess 跑临时 .py 文件,过滤 `*API_KEY *TOKEN *SECRET *PASSWORD *PRIVATE_KEY` 环境变量 - -### 6. Skill 系统(Anthropic 渐进披露标准) -- `core/skills.py`: `SkillRegistry` 扫描 `skills//`,只读 SKILL.md frontmatter 做 discovery -- `tools/skill_tool.py`: `load_skill(name)` 工具返回完整 SKILL.md 给模型 -- 三个 skill,均按 WHY+WHAT 风格写,不写 Step 1/2/3: - - `skills/coding/SKILL.md` - - `skills/ppt/` —— 完整渐进披露结构(借鉴 hugohe3/ppt-master 的两阶段 + spec lock 思路): - - `SKILL.md`(两阶段工作流 + ⛔ blocking 八条对齐 + 红色硬约束 + 强制封面/尾页 + 反模式) - - `references/design_principles.md`(§0 画布 + §1-9 字号/配色/留白/字数预算/图表) - - `references/layouts.md`(9 种版式 + `apply_brand(slide, kind)` 品牌条覆盖每页 + assert_inside) - - `references/icons.md`(业务图标两层:Iconify / unicode 兜底;MSO_SHAPE 退为 layouts.md helper 内部几何原语) - - `assets/icons/INDEX.md`(本地图标库索引 + 推荐清单) - - `scripts/fetch_icon.py`(Iconify CDN 拉个性化 SVG/PNG,主题色染色,缓存本地) - - `scripts/quality_check.py`(页数/标题/bullet/字号/配色 + shape 越界 + 文本溢出估算) - - `scripts/source_to_md.py`(PDF/DOCX/PPTX/URL → Markdown) - - `scripts/render_icon.py`(unicode 字形 → 透明 PNG,兜底) - - **配色**:商务红 PRIMARY `#C00000` / SECONDARY `#E15554` / ACCENT `#FFC107` —— v3 改为硬约束,模型不能基于"场景判断"自行换色 - - **品牌条**:v3 加 `apply_brand(slide, kind)`,所有版式起手必调,4 种模式 (cover/inner/section/end) 覆盖左竖条 + 浅底,不再裸白纸 - - **图标**:v3 加 Iconify CDN 拉取链路 (tabler/lucide/heroicons/material-symbols 等 150+ 集),本地缓存复用 - - `skills/proposal/SKILL.md`(含工作目录约定 + 字数表 + python-docx 合并模板) - -### 7. System Prompt -- `prompts/system/general_v1.md`(无版本化软链接,直接引用 v1) -- 启动时拼接顺序: 通用指引 → discovery 块(skill 列表) → 当前工作目录 - -### 8. Capability Probing(Phase 4) -- `core/probe.py`:四项探测 + ProbeReport - - `probe_basic_chat` —— 连通性,失败则跳过其余 - - `probe_parallel_tools` —— 给两个独立工具,看 single response 里 tool_calls 数 ≥2 - - `probe_thinking_mode` —— 对 declared=True 的模型传 reasoning_effort,看 API 接受 + 是否产出 reasoning_content/thinking - - `probe_long_context` —— needle-in-haystack 简化版,默认 reliable_context * 4 / 8 字符,上限 200K(opt-in,需 `--long-context`) -- `cli.py probe [--model X] [--long-context]`:rich Table 输出;退出码 0=全 ok / 2=有 mismatch / 3=有 error -- 不修改 yaml,只报告差异——是否调档案由用户决定 -- 不进启动路径(每次启动跑会烧 API),用户显式触发 - -### 9. Task 概念 + state.json(Phase 6) -- `core/task.py`:`TaskState` dataclass(对齐 DESIGN.md §7.1) - - 字段:task_id / mode / description / status (active/completed/abandoned) / model / model_profile / reasoning_effort / cwd / created_at / updated_at / tokens_prompt / tokens_completion / cost_usd - - `save(task_dir)` / `load(task_dir)`,加载时容忍未知字段(schema 演化) -- 存储布局:`workspace/tasks//{state.json, messages.json}` -- `main.build_agent` 返回 5 元组 `(agent, session, sid, task_state, task_dir)` -- `main.sync_task_tokens(state, dir, llm)`:每轮 agent.run 后调,把 LLM 累计 tokens 写回 state.json -- CLI: - - `chat --mode coding --desc "修一处 bug"`(可选元数据) - - REPL:`/status` 看 state、`/done` 标完成、`/abandon` 标弃、`/desc <文本>` 改描述 - - `cli.py tasks [--status active|completed|abandoned]`:列任务,显示 mode/model/msgs/tokens/desc -- 已知小坑:`Session.save()` 不原子,write_text 抛错(如 stdin 注入了 UTF-8 surrogate 半字符)会留下 0 字节文件——交互使用没问题,后续可加 tmp+rename +**Phase 6 部分**(2026-05-06): +- `core/task.py` + `workspace/tasks//{state.json, messages.json}` —— TaskState 跟 mode/desc/status/tokens/timestamps;`build_agent` 返 5 元组;`sync_task_tokens` 每轮后写回 +- CLI 新增 `tasks` 子命令 + REPL `/status /done /abandon /desc`;`chat` 加 `--mode --desc` 选项 +- 移除 legacy `workspace/sessions/` 兼容(单一布局) --- @@ -115,71 +40,43 @@ | 项 | 决策 | 与设计差异 | |---|------|-----------| -| 工具基目录 | 用户当前 cwd,不是 workspace/ | 设计未明说;选 cwd 是因为 agent 该操作用户的项目 | -| Workspace 用途 | `tasks//{state.json, messages.json}`;memory/ 待 Phase 6 双层记忆 | 设计含 `tasks/ memory/ logs/`,部分落地 | -| Session 粒度 | 一个目录一个 task,含 state.json | Phase 6 落地;DESIGN.md §7.1 字段对齐 | -| Eval Suite | 决定不做 | DESIGN.md §6.3 设计为团队/产品场景;个人工具用 dogfooding 替代,probe 覆盖健康检查 | -| 版本化 prompt | 直接 general_v1.md,无 active.md 软链接 | Windows 软链接麻烦;后续要切版本时再做 | -| run_python 沙盒 | subprocess + env 过滤 | 设计阶段 1 就是这套,未升级 Docker | -| 工具数 | 8 个 (read/write/edit/glob/grep/shell/run_python/load_skill) | 设计上限 ≤10 同时可见,目前刚好 | - ---- - -## 验收过的测试 - -- 全项目 `ast.parse` 语法 OK -- yaml 配置可解析 -- 所有 import 链路在 venv 中跑通 -- `cli.py --help` / `cli.py chat --help` / `cli.py tasks --help` / `cli.py probe --help` 正常 -- `SkillRegistry` 识别出 3 个 skill,discovery 块拼装正确 -- 缺 `DEEPSEEK_API_KEY` 时报清晰错误 -- 实测 DeepSeek API 接通,`flash` 和 `pro` 两档都能调通 -- **真实 probe 结果**(2026-05-06): - - `deepseek_v4.flash`:basic_chat ok / **parallel_tools mismatch**(yaml=false, observed=true,2 个 tool_calls)/ thinking_mode skip(declared false) - - `deepseek_v4.pro`:basic_chat ok / parallel_tools ok / thinking_mode ok(reasoning_content 返回) - - flash 的 mismatch 暂不自动改 yaml —— `parallel_tools=true` 会影响所有实际调用,需更多场景观察后再决定 - ---- - -## 已知遗留 / 下一步候选 - -按性价比排序: - -1. **Phase 6 双层记忆**(~半天)—— `workspace/memory/core.md` 注 prompt + `extended/` 按需读 -2. **Phase 6 context 三层压缩**(~1 天)—— 兜底用,V4 长上下文一般用不到 -3. **小修打磨**(~半小时)—— `Session.save()` 改原子写(tmp + rename),防 surrogate 等异常 truncate -4. **Phase 7 Docker 沙盒**(~1 天)—— 替换 subprocess,run_python 安全升级 -5. **Phase 7 更多 skill / 模型档案**(持续) +| 工具基目录 | 用户当前 cwd | 设计未明说;agent 该操作用户项目 | +| Workspace 用途 | `tasks//{state.json, messages.json}` | memory/ 待 Phase 6 双层记忆 | +| Eval Suite | 不做 | 设计为团队场景;个人工具 dogfooding 替代 | +| 版本化 prompt | 直接 `general_v1.md`,无 active.md 软链接 | Windows 软链接麻烦,真要切版本时再做 | +| run_python 沙盒 | subprocess + env 过滤 | 阶段 1 设计如此;Docker 待 Phase 7 | --- ## 文件清单(代码量) ``` -core/capabilities.py 71 行 -core/llm.py 89 行 -core/loop.py 99 行 -core/probe.py 243 行 ← Phase 4 -core/session.py 77 行 -core/skills.py 81 行 -core/task.py 63 行 ← Phase 6 -tools/base.py 34 行 -tools/fs.py 182 行 -tools/shell.py 63 行 -tools/run_python.py 84 行 -tools/skill_tool.py 45 行 -main.py 175 行 ← +tasks 布局 / TaskState 装配 -cli.py 265 行 ← +probe / +tasks 子命令 +core/capabilities.py 71 +core/llm.py 89 +core/loop.py 99 +core/probe.py 243 ← Phase 4 +core/session.py 77 +core/skills.py 81 +core/task.py 63 ← Phase 6 +tools/base.py 34 +tools/fs.py 182 +tools/shell.py 63 +tools/run_python.py 84 +tools/skill_tool.py 45 +main.py 175 ← Phase 6 task 装配 +cli.py 265 ← +probe / +tasks 子命令 ───────────────────────────────── -合计 Python ~1571 行 - -prompts/system/general_v1.md -skills/coding/SKILL.md -skills/ppt/SKILL.md -skills/proposal/SKILL.md -config/agent.yaml -config/models/deepseek_v4.yaml -requirements.txt +Python 合计 ~1571 行 ``` -设计预估 Phase 1-3 大约 800-1000 行,实际 1083 行,加上 Phase 4 + Phase 6 约 1571 行 Python。 +加上 skills/ppt 下的脚本(~600 行)、SKILL.md / references / config / prompts,总仓库约 2500 行可读源码。 + +--- + +## 下一步候选(性价比排序) + +1. **Phase 6 双层记忆**(~半天)—— `workspace/memory/core.md` 注 prompt,`extended/.md` 按需读 +2. **Phase 6 context 三层压缩**(~1 天)—— 兜底用,V4 长上下文一般用不到 +3. **小修打磨**(~半小时)—— `Session.save()` 改原子写(tmp + rename),防 surrogate 等异常 truncate +4. **Phase 7 Docker 沙盒**(~1 天)—— 替换 subprocess,run_python 安全升级 +5. **Phase 7 更多 skill / 模型档案**(持续)