DEV Community

llimage
llimage

Posted on

一个任务的奇幻漂流:同一个Agent任务,在FROST和FROST-SOP中分别长什么样?

一个任务的奇幻漂流:同一个Agent任务,在FROST和FROST-SOP中分别长什么样?

作者:神通说

日期:2026-07-08

主题:双项目联动 | 周三轮换

阅读时间:8分钟


一个问题

你可能听过这样的故事:

"这个框架很好,但我不知道怎么用到真实项目里。"

FROST 社区里也收到过类似的反馈——

"500行代码确实让我理解了Agent的本质,但理解完之后呢?怎么从'看懂'到'会用'?"

今天这篇文章,就用同一个真实任务,分别展示它在 FROST 和 FROST-SOP 中的样子。你会发现:它们不是两个不同的东西,而是同一个东西的不同分辨率


今天的任务:自动写日报

假设你是一个独立开发者,想让Agent每天自动帮你写工作日报。需求很简单:

  1. 收集今天完成的任务
  2. 用LLM生成日报摘要
  3. 发送邮件给自己

就这么三步。让我们看看它在两个项目中分别怎么实现。


第一站: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测试用例、写推广文章
Enter fullscreen mode Exit fullscreen mode

这段代码做了什么?

  • 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"}
Enter fullscreen mode Exit fullscreen mode

注意区别:

特性 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
Enter fullscreen mode Exit fullscreen mode

这个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/ 目录下
    # 每一天的执行记录都可以回溯
Enter fullscreen mode Exit fullscreen mode

执行完成后,你会得到一个完整的报告:

{
  "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"
}
Enter fullscreen mode Exit fullscreen mode

这就是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 + 审计日志
Enter fullscreen mode Exit fullscreen mode

你不需要"忘掉FROST再学FROST-SOP"——你需要做的是把FROST的概念升级为工程组件

就像你知道汽车引擎的原理(FROST),然后去学怎么造一辆真正的汽车(FROST-SOP)。引擎原理不会因为你造真车就失效——它是一切的基础。


学习路径:从看懂到会用

基于今天的双项目之旅,我建议这样的学习路径:

阶段一:用FROST建立直觉(1-2天)

  1. 克隆 FROST 仓库
  2. 运行 197 个测试用例,理解每个原子的行为
  3. 自己写3个Skill,用 agent.run() 执行
git clone https://gitee.com/liao_liang_7514/frost.git
cd frost
pip install -r requirements.txt
pytest tests/ -v
Enter fullscreen mode Exit fullscreen mode

目标: 看到 StoreSkillAgentSOP 四个词时,脑子里能浮现出它们的运作画面。

阶段二:用FROST-SOP构建真实系统(3-5天)

  1. 克隆 FROST-SOP 仓库
  2. 配置LLM API Key
  3. 用已有的19个Skill搭建一个你自己的SOP
  4. 注册你自己的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
Enter fullscreen mode Exit fullscreen mode

目标: 拥有一个你自己搭建的、可以在生产环境运行的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 是思想源头,FROST-SOP 是思想开花结果。


本文是 FROST 双项目每日推广系列的第 15 篇。每周三固定为"双项目联动"主题,用同一个场景串联两个项目,帮助读者建立从概念到工程的完整认知。

如果觉得有用,给项目一个 Star ⭐,就是最好的鼓励!

Top comments (0)