一个任务的奇幻漂流:同一个Agent任务,在FROST和FROST-SOP中分别长什么样?
作者:神通说
日期:2026-07-08
主题:双项目联动 | 周三轮换
阅读时间:8分钟
一个问题
你可能听过这样的故事:
"这个框架很好,但我不知道怎么用到真实项目里。"
FROST 社区里也收到过类似的反馈——
"500行代码确实让我理解了Agent的本质,但理解完之后呢?怎么从'看懂'到'会用'?"
今天这篇文章,就用同一个真实任务,分别展示它在 FROST 和 FROST-SOP 中的样子。你会发现:它们不是两个不同的东西,而是同一个东西的不同分辨率。
今天的任务:自动写日报
假设你是一个独立开发者,想让Agent每天自动帮你写工作日报。需求很简单:
- 收集今天完成的任务
- 用LLM生成日报摘要
- 发送邮件给自己
就这么三步。让我们看看它在两个项目中分别怎么实现。
第一站:FROST——用最少的代码理解本质
FROST 的哲学是:先用500行代码告诉你Agent的底层逻辑,剩下的你自然就会了。
在FROST中,一个Agent的运作只需要四个原子:
from core import Store, Agent, skill_set, skill_get
# 1. 创建记忆容器
store = Store()
# 2. 定义能力(Skill = 纯函数)
def collect_tasks(context):
"""收集今日任务"""
tasks = ["完成FROST v5.0文档", "修复Skill测试用例", "写推广文章"]
context["tasks"] = tasks
return context
def generate_summary(context):
"""生成日报摘要(简化版,实际调用LLM)"""
tasks = context.get("tasks", [])
context["summary"] = f"今日完成{len(tasks)}项任务:" + "、".join(tasks)
return context
def send_report(context):
"""发送日报"""
context["sent"] = True
print(f"[日报已发送] {context['summary']}")
return context
# 3. 组装Agent
agent = Agent("daily_reporter", store, skills={
"collect": collect_tasks,
"summarize": generate_summary,
"send": send_report
})
# 4. 用SOP编排执行顺序
result = agent.run(
sop_steps=["collect", "summarize", "send"],
initial_context={}
)
# 输出:[日报已发送] 今日完成3项任务:完成FROST v5.0文档、修复Skill测试用例、写推广文章
这段代码做了什么?
-
Store是记忆——Agent的工作空间,所有中间结果存在这里 -
Agent是细胞——拥有记忆和能力的最小执行单元 -
sop_steps是宪法——定义执行顺序,Agent不会自作主张改变流程
就这么简单。没有配置文件,没有YAML,没有复杂的初始化。30行Python代码,一个完整的Agent就跑起来了。
这就是FROST的价值——它不帮你"做"什么,它帮你看懂Agent到底是什么。
问题来了
上面的代码能跑,但如果你真的想把它用在生产环境,你会遇到一堆问题:
- 发邮件的能力怎么写? FROST不管——它只告诉你Skill是纯函数,具体实现你自己来
- LLM调用怎么复用? 每次写日报都要调LLM,总不能每次都重写一遍
- 任务失败了怎么办? 发邮件失败了,要不要重试?重试几次?
- 执行日志在哪? 老板问"今天日报发了吗",你怎么知道发没发?
- 多个Agent协作呢? 一个人有好几个项目,每个项目一个Agent,怎么协调?
FROST对这些问题的回答是:这些问题不是我该回答的。
但它的兄弟——FROST-SOP——就是专门回答这些问题的。
第二站:FROST-SOP——让同一个任务跑在生产环境
FROST-SOP 的哲学是:把FROST教你的每一个概念,都变成生产级的工程组件。
同样的"自动写日报"任务,在FROST-SOP中长这样:
Step 1:定义能力(Skill)
在FROST中,Skill是一个普通Python函数。在FROST-SOP中,Skill是一个标准化的类——有Schema、有验证、有异步支持:
from skills.base import BaseSkill
from typing import Any, Dict
class LLMGenerateSkill(BaseSkill):
"""调用LLM生成文本"""
@property
def name(self) -> str:
return "llm_generate"
@property
def description(self) -> str:
return "调用大语言模型生成文本内容"
@property
def parameters(self) -> Dict[str, Any]:
return {
"type": "object",
"properties": {
"prompt": {"type": "string", "description": "提示词"},
"model": {"type": "string", "default": "deepseek-chat"},
"max_tokens": {"type": "integer", "default": 2000}
},
"required": ["prompt"]
}
async def execute(self, prompt: str, model: str = "deepseek-chat",
max_tokens: int = 2000) -> Dict[str, Any]:
# 调用LLM API
response = await self.llm_client.chat(
model=model,
messages=[{"role": "user", "content": prompt}],
max_tokens=max_tokens
)
return {
"success": True,
"content": response.choices[0].message.content,
"tokens_used": response.usage.total_tokens
}
class EmailSendSkill(BaseSkill):
"""发送邮件"""
@property
def name(self) -> str:
return "email_send"
@property
def description(self) -> str:
return "发送邮件给指定收件人"
@property
def parameters(self) -> Dict[str, Any]:
return {
"type": "object",
"properties": {
"to": {"type": "string", "description": "收件人邮箱"},
"subject": {"type": "string", "description": "邮件主题"},
"body": {"type": "string", "description": "邮件正文"}
},
"required": ["to", "subject", "body"]
}
async def execute(self, to: str, subject: str,
body: str) -> Dict[str, Any]:
# 发送邮件(带重试)
for attempt in range(3):
try:
await self.smtp_client.sendmail(to, subject, body)
return {"success": True, "attempt": attempt + 1}
except Exception as e:
if attempt == 2:
return {"success": False, "error": str(e)}
return {"success": False, "error": "Max retries exceeded"}
注意区别:
| 特性 | FROST Skill | FROST-SOP Skill |
|---|---|---|
| 定义方式 | 普通函数 | 标准化类 |
| 参数验证 | 无 | JSON Schema自动验证 |
| 异步支持 | 同步 | 原生async |
| 错误处理 | 自行处理 | 标准化返回格式 |
| 可复用性 | 项目内 | 跨项目注册 |
FROST-SOP 的 Skill 是可注册、可发现、可复用的。写好一个 email_send Skill,所有SOP都可以直接用,不需要重复实现。
Step 2:用声明式SOP定义流程
在FROST中,SOP是一个字符串列表 ["collect", "summarize", "send"]。在FROST-SOP中,SOP是一个完整的声明式定义:
# sops/daily_report.yaml
name: "daily_report"
description: "自动生成并发送每日工作日报"
version: "1.0"
trigger:
type: "cron"
schedule: "0 18 * * *" # 每天18:00执行
steps:
- name: "collect_tasks"
skill: "task_collector"
parameters:
source: "memory_store"
date: "${context.today}"
halt_on_error: true
- name: "generate_summary"
skill: "llm_generate"
parameters:
prompt: "请根据以下任务列表生成一份简洁的工作日报:${collect_tasks.tasks}"
model: "deepseek-chat"
max_tokens: 1000
halt_on_error: true
- name: "send_email"
skill: "email_send"
parameters:
to: "${context.user_email}"
subject: "工作日报 - ${context.today}"
body: "${generate_summary.content}"
halt_on_error: false # 发送失败不影响整体状态
error_handling:
on_failure: "notify_admin"
retry_count: 2
这个YAML定义比FROST的 sop_steps 列表多了什么?
- 触发条件:定时执行,不需要手动触发
-
参数引用:
${collect_tasks.tasks}让上一步的输出自动流入下一步 - 错误处理:每一步可以独立配置失败策略
- 版本管理:SOP有版本号,可以回溯和对比
但核心思想完全一样——有序步骤列表。FROST-SOP只是把这个概念做得更工程化了。
Step 3:运行并观测
在FROST中,运行结果就是一个返回值。在FROST-SOP中,运行结果是一个完整的审计报告:
import asyncio
from core.event_bus import get_async_event_bus, Event, EventType
from engine.sop_engine import SOPEngine
async def run_daily_report():
engine = SOPEngine()
bus = get_async_event_bus()
# 发布执行事件
await bus.publish(Event(
event_type=EventType.SOP_EXECUTE_REQUEST,
source="scheduler",
data={
"sop_id": "daily_report",
"context": {
"today": "2026-07-08",
"user_email": "dev@example.com"
}
}
))
# 等待执行完成
result = await engine.wait_for_completion("daily_report")
# 查看执行报告
print(f"执行状态: {result['status']}")
print(f"步骤详情: {result['steps']}")
print(f"耗时: {result['duration_ms']}ms")
print(f"Token消耗: {result['token_usage']}")
# 审计日志自动保存在 logs/ 目录下
# 每一天的执行记录都可以回溯
执行完成后,你会得到一个完整的报告:
{
"sop_id": "daily_report",
"status": "completed",
"steps": {
"collect_tasks": {"status": "success", "duration_ms": 120},
"generate_summary": {"status": "success", "duration_ms": 3200, "tokens": 450},
"send_email": {"status": "success", "duration_ms": 800}
},
"duration_ms": 4120,
"token_usage": 450,
"execution_id": "exec-20260708-180000",
"timestamp": "2026-07-08T18:00:04+08:00"
}
这就是FROST-SOP的可观测性——不是"大概知道跑了",而是"精确知道每一步花了多久、用了多少Token、成功还是失败"。
对比:同一任务的两种分辨率
让我们把两个实现放在一起对比:
| 维度 | FROST版本 | FROST-SOP版本 |
|---|---|---|
| 代码量 | ~30行 | ~100行 + YAML配置 |
| 执行方式 | 手动调用 agent.run()
|
定时触发,自动运行 |
| 错误处理 | 无内置 | 每步独立配置 |
| 执行日志 |
print() 输出 |
结构化审计报告 |
| 能力复用 | 项目内函数 | 全局注册 + Schema |
| LLM集成 | 手写调用 | 标准化Skill |
| 可观测性 | 无 | 完整指标面板 |
| 适合场景 | 学习、验证、原型 | 生产环境、团队协作 |
关键洞察: 两个版本的核心逻辑完全一样——收集→生成→发送。区别只在于"工程化程度"。
FROST 帮你理解这个逻辑。
FROST-SOP 帮你把这个逻辑变成生产级的系统。
它们是如何无缝衔接的?
最妙的是:从FROST到FROST-SOP,你的认知是连续的。
在FROST中学到的概念,在FROST-SOP中一一对应:
FROST 概念 → FROST-SOP 工程实现
─────────────────────────────────────────
Store(记忆) → AssetStore + ContextStore
Skill(纯函数) → BaseSkill + SkillRegistry
Agent(细胞) → Ancestor/Parent/Child Agent
SOP(步骤列表) → YAML SOP定义 + SOPEngine
run()(执行) → AsyncEventBus + 审计日志
你不需要"忘掉FROST再学FROST-SOP"——你需要做的是把FROST的概念升级为工程组件。
就像你知道汽车引擎的原理(FROST),然后去学怎么造一辆真正的汽车(FROST-SOP)。引擎原理不会因为你造真车就失效——它是一切的基础。
学习路径:从看懂到会用
基于今天的双项目之旅,我建议这样的学习路径:
阶段一:用FROST建立直觉(1-2天)
- 克隆 FROST 仓库
- 运行 197 个测试用例,理解每个原子的行为
- 自己写3个Skill,用
agent.run()执行
git clone https://gitee.com/liao_liang_7514/frost.git
cd frost
pip install -r requirements.txt
pytest tests/ -v
目标: 看到 Store、Skill、Agent、SOP 四个词时,脑子里能浮现出它们的运作画面。
阶段二:用FROST-SOP构建真实系统(3-5天)
- 克隆 FROST-SOP 仓库
- 配置LLM API Key
- 用已有的19个Skill搭建一个你自己的SOP
- 注册你自己的Skill,在多个SOP中复用
git clone https://gitee.com/liao_liang_7514/frost-sop.git
cd frost-sop
pip install -r requirements.txt
# 配置 .env 文件
cp .env.example .env
# 运行测试
pytest tests/ -v
# 启动UI
streamlit run ui/streamlit_app.py
目标: 拥有一个你自己搭建的、可以在生产环境运行的Agent系统。
阶段三:双向迭代(持续)
- 在FROST-SOP中遇到设计困惑?回到FROST看本质
- 在FROST中产生新想法?在FROST-SOP中验证工程可行性
这两个项目不是线性的"先A后B",而是螺旋式的"互相滋养"。
结语:同一个灵魂,两种表达
回到开头的问题:
"理解FROST之后,怎么过渡到真实项目?"
答案是:FROST-SOP就是那个过渡。
它不是另一个框架,它是FROST的工程化表达。同一个Agent概念,在FROST中用500行代码讲清楚原理,在FROST-SOP中用5000+行代码把它变成可用的系统。
FROST 是思想源头,FROST-SOP 是思想开花结果。
今天你用30行代码在FROST中理解的"自动写日报",明天就能用FROST-SOP的声明式SOP让它跑在生产环境——而且带完整的日志、重试、监控。
这不是从"玩具"到"产品"的跳跃。这是从"理解"到"构建"的自然演进。
🔗 项目链接
- FROST(教学框架):https://gitee.com/liao_liang_7514/frost
- FROST-SOP(工程平台):https://gitee.com/liao_liang_7514/frost-sop
FROST 是思想源头,FROST-SOP 是思想开花结果。
本文是 FROST 双项目每日推广系列的第 15 篇。每周三固定为"双项目联动"主题,用同一个场景串联两个项目,帮助读者建立从概念到工程的完整认知。
如果觉得有用,给项目一个 Star ⭐,就是最好的鼓励!
Top comments (0)