38 KiB
个人任务 Agent 设计方案 v2
一个面向"写汇报 PPT、写科研申报书、写代码"三类任务的轻量级 agent 框架。 完全自实现,综合 nanobot / CoreCoder / better-claw / smolagents 的优点,模型自由,为模型持续升级做了演化性设计。
v2 更新要点(2026-05):
- 模型策略基于 DeepSeek V4 实际能力(2026-04-24 发布)重新设计
- Skill 系统对齐 Anthropic 开放标准(2025-12 发布,行业已成共识)
- 工具范式改为 Hybrid:JSON tool call + run_python 混合
- 新增第 6 章「演化性设计」—— 让 agent 跟着模型升级而升级
- 新增 Eval Suite 框架,作为模型升级的决策依据
1. 设计目标与边界
1.1 要做什么
构建一个本地运行的任务型 agent,能稳定完成三类工作:
| 任务模式 | 输入示例 | 输出 | 主要能力 |
|---|---|---|---|
| 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 能力随之升级,不需要大改架构
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/<name>/scripts/*.py │
└──────────────────────────────────────────────┘
↓
┌──────────────────────────────────────────────┐
│ LLM 层(LiteLLM + Model Profile) │
│ - 默认:DeepSeek V4-Flash │
│ - 升级:DeepSeek V4-Pro / Claude Opus 4.7 │
│ - Profile 化配置,新模型 5 分钟接入 │
└──────────────────────────────────────────────┘
3.2 目录结构
your_agent/
├── 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 行
├── 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
├── 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
总代码量预估:1300-1600 行 Python(比 v1 多 ~200 行,因为加了 capabilities 和 run_python)
4. 核心组件设计
4.1 Agent Loop(core/loop.py)
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 "[已达到最大迭代次数]"
4.2 Model Profile + Capabilities(core/capabilities.py)⭐ 新增
核心思想:每个模型有自己的能力档案,agent 行为根据档案动态调整。新模型出来,加一个 yaml 即可。
@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
"""
...
模型档案示例 (config/models/deepseek_v4.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):
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 为例):
# 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)
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):
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:
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/<task_id>/.
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 工具粒度原则 ⭐ 新增
工具切分按"原子操作"原则,不做高级封装:
# ❌ 反模式:工具做太多,模型用不灵活
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 标准格式
---
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/<task_id>/`:
- `project.md` - 课题信息卡片
- `sections/<section_name>.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 文件 | 视情况 |
具体实现:
# 启动时: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 官方 + 行业经验)
- Description 是关键 —— 决定模型能否触发,要明确具体
- SKILL.md 主体不超过 5000 tokens / 500 行 —— 超过就拆 references/
- 写 WHY+WHAT,不写 HOW —— 描述目标和资源,不写步骤
- 代码即工具又是文档 —— scripts/ 里的脚本可以执行,也可以读到 context 当文档
- 保持 Skill 数 ≤ 20,工具数 ≤ 10 同时可见(超过后准确率下降)
4.6 Context 管理(简化版)
V4 时代 long context 性能好了很多,大部分任务不再需要复杂压缩。但保留三层兜底:
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 当主力
# 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 成本预估
| 任务 | V4-Flash | V4-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 |
结论:99% 任务 V4-Flash 已够用,关键终稿可升级 Pro,Claude 仅作 fallback。
6. 演化性设计 ⭐ 新增章节
核心问题:模型每 3-6 个月迭代一次,agent 怎么不被甩在后面?
6.1 设计哲学
Less Scaffolding, More Trust(少脚手架,多信任)
老 agent 框架(LangChain 早期、AutoGPT)失败的核心原因:给 LLM 太多脚手架,模型升级后这些脚手架成了枷锁。
参考反例:
- 强制 ReAct 三段式输出 —— GPT-4 出来后这种格式反而降智
- PydanticOutputParser 死磕格式 —— Structured Output 内置后成了多此一举
- Prompt 里详细教"应该怎么思考" —— 强模型不需要被教
正确做法:把 LLM 当一个会持续变强的同事对待,告诉它目标,不告诉它步骤。
6.2 七条具体原则
原则 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(启动时探测)
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
模型升级时:
- 写一个新版本 prompt(更精简、更信任模型)
- 在 eval suite 上对比 v1 vs v2
- 数据说话,切换 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 任务):
# 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 任务):
# 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
# 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 出来时,按这个流程:
## 模型升级 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 核心代码。
7. 关键工程细节
7.1 任务状态(tasks/<task_id>/state.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 天)
core/llm.py+ Model Profile 雏形core/loop.py- 主循环core/session.pytools/base.py+tools/fs.py+tools/shell.pycli.py- 基础 REPLconfig/agent.yaml+config/models/deepseek_v4.yaml
验收:python cli.py chat 能让 V4-Flash 修一个简单 Python bug。
Phase 2:Skill 系统(标准格式)+ 三个 skill(2 天)
tools/skill_tool.py(LoadSkill)- 三个 skill 目录,对齐 Anthropic 格式
- 任务模式路由
验收:三种模式都能进入,渐进披露正常工作。
Phase 3:Hybrid 范式(1-2 天)
tools/run_python.py- subprocess 沙盒版- PPT/Word 通过 run_python 生成(不再做高级 API 封装)
- PDF / 文献检索脚本到 skills/proposal/scripts/
验收:能产出 .pptx 和 .docx,文献检索真实。
Phase 4:演化性能力(1-2 天)⭐ 新增
core/capabilities.py- Model Profile 加载- Capability Probing 启动检测
- 版本化 prompts/ 目录结构
- 配置热重载
验收:能切换 V4-Flash 和 V4-Pro 不用改代码,只改 config。
Phase 5:Eval Suite(2 天)⭐ 新增
evals/runner.py- 每种任务 3-5 个测试 case
- LLM-as-judge 评分
- 报告输出(score / cost / latency)
验收:python evals/runner.py --model deepseek-v4-flash 能跑完所有任务并出报告。
Phase 6:长任务工程化(2-3 天)
core/context.py- 三层压缩(兜底用)core/memory.py- 双层记忆- 任务恢复机制
验收:写完整一份申报书不崩,中断后能恢复。
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 已知风险
| 风险 | 缓解 |
|---|---|
| run_python 沙盒安全(subprocess 不够强) | 限制工作目录 + 环境变量过滤;后期升级 Docker |
| V4 在某些复杂任务上仍不如 Claude | Eval suite 帮判断;fallback 机制 |
| Skill description 不够好 → 触发不准 | 用 V4-Pro 优化 description;eval 测触发率 |
| Long context 退化 | Capability probe 探测 reliable_context;不要依赖宣称值 |
| Prompt 改了一次就不敢动 | 版本化 + eval 让改动有数据支撑 |
10.2 取舍说明
为什么改用 Anthropic Skill 标准而不是自创:
- 行业标准已成,跨平台兼容
- 直接拿到 Anthropic skills repo 的现成资源
- 未来想换底层 SDK 不用改 skill
为什么用 Hybrid 范式而不是纯 CodeAgent:
- DeepSeek V4 在 JSON tool calling 已足够稳定
- 沙盒成本更低(只在需要时执行代码)
- 可以兼容 thinking 模式(纯 CodeAgent 跟 thinking 不太合)
为什么花精力做 Eval Suite:
- 没有 eval,模型升级决策只能凭感觉
- 一次性投入,长期复用
- 跑 eval 的成本(~$10)远低于因为没 eval 选错模型的成本
为什么不做 subagent:
- 用户明确不需要
- 加了之后状态管理复杂度爆炸
- 单 agent + skill 已能覆盖 95% 场景
11. 与 v1 方案的差异
| 维度 | 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 开始落地:
- 起项目骨架
- 写
core/llm.py+core/capabilities.py - 写
config/models/deepseek_v4.yaml - 跑通最小 REPL
- 用 V4-Flash 跑一个简单任务
Phase 1 预计 2 天完成,跑通后能立即用。
附录 A:Anthropic Skill 标准参考
官方资源:
- Agent Skills 文档
- Anthropic 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
- 三种推理模式: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 范式 / 演化性设计