图片
当你这样设计系统之后,数据 API 不再只是“提供数据”,AI 也不再只是“调用模型”。它们之间,多了一层真正有价值的东西:可组合、可调度、可演化的能力层。

👉 真正有价值的,从来不是你做了一个 AI 功能,而是你是否把它变成别人也能复用的能力。

 

一、起点:一个看似简单的问题

我们最初的目标很直接:

利用 AI 实现作业批阅,我们希望借此节省老师的时间,提升批阅质量,让反馈更“像老师”。

初版实现非常典型,仅仅整合了一个 AI 批阅接口:

def generate_feedback(answer: str, question: str) -> str:
    prompt = f"""
    请批改学生作业:
    题目:{question}
    学生答案:{answer}
    请给出评价和建议:
    """
    return llm.generate(prompt)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

上线后的问题也很典型:

  • 评价“正确但没用”:泛泛而谈,没有针对性。
  • 缺乏个性化:没有结合学生个人情况。
  • 无视历史:多次错误没有被识别。
  • 割裂感强:完全不像“连续教学”。

我们不缺数据(历史作业、错题轨迹、知识点标签),但这些数据存在,却没有参与到 AI 批阅推理中。

 

二、识别“龙虾场景”:复杂度的觉醒

在不断优化的过程中,我们意识到:AI 批阅其实不是一个“单点调用模型”的问题,而是一个典型的复杂场景。

我们在内部将其定义为“龙虾场景”:

定义: 一个由多个数据源、多个处理步骤、多个决策点组成的高价值场景,难以通过单次模型调用完成。

图片图片

 

它通常具备三个特征:

  • 多跳(Multi-step):不是一次调用能完成
  • 多源(Multi-source):依赖多个数据系统
  • 高价值(High-impact):直接影响核心体验

 

三、拆解“龙虾场景”:从 Prompt 工程到数据编排

AI 批阅到底在做什么?

我们把整个链路完整拆解后发现:

1. 拉取学生历史数据
2. 识别与当前题目相关的数据
3. 提取错误模式 / 学习趋势
4. 压缩为模型可接受的上下文
5. 构建带“教学意图”的 Prompt
6. 调用模型生成反馈
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

这里有一个关键认知转变:

这不是一个“Prompt 优化问题”,而是一个“数据处理 + 推理编排问题”

 

复盘初版代码的“大泥球”架构:

def generate_feedback(student_id, question, answer):
    # 逻辑耦合:数据获取、过滤、压缩、Prompt 混在一起
    history = db.get_history(student_id)
    relevant = [h for h in history if h["kp"] in question]
    history_text = "\n".join([h["content"] for h in relevant[:10]])
    prompt = f"""
    历史表现:{history_text}
    当前题目:{question}
    学生答案:{answer}
    请评价:
    """
    return llm.generate(prompt)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

图片图片

这种写法导致了三大问题:

  • 逻辑耦合: 无法复用任何一段逻辑
  • 不可扩展: 换个场景(如学情分析)就要重写一遍
  • 不可调试: 很难定位是过滤有问题,还是 Prompt 有问题

 

四、关键转折:能力拆解与 Skill 化

我们做了一个“反直觉”的决定:禁止再写“大函数”,必须拆成最小能力单元(Skill)。

图片

Skill 设计原则: 不是封装函数,而是定义能力边界

所有能力必须满足:

  • 输入明确(不隐式依赖上下文)
  • 输出稳定(结构化)
  • 无副作用(可复用)

 

核心 Skill 设计示例:

1.数据检索

class GetStudentHistorySkill(Skill):
    def __call__(self, student_id: str, question_type: str):
        return db.query("SELECT ...") # 获取纯净数据
  • 1.
  • 2.
  • 3.

2.相关性过滤

class FilterRelevantRecordsSkill(Skill):
    def __call__(self, records, question):
        # 实战经验:规则过滤 + 结构化标签远比 Embedding 稳定
        kp_set = extract_kp(question)
        return [r for r in records if r["knowledge_point"] in kp_set]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

3.上下文压缩

这是效果提升最大的一个点,不要把数据直接喂给模型,要先“变成知识”

class SummarizeHistorySkill(Skill):
    def __call__(self, records):
        # 利用 LLM 将长文本压缩为高密度的“学生画像”
        prompt = "总结学生历史表现,重点:高频错误、进步趋势..."
        return self.llm.generate(prompt)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

4.意图构建

class BuildPromptSkill(Skill):
    def __call__(self, question, answer, history_summary):
        # 注入教学意图
        return f"你是一位经验丰富的老师...结合历史表现{history_summary}...评价{answer}"
  • 1.
  • 2.
  • 3.
  • 4.

五、Skill 升级:从“代码封装”到“Agent 可理解”

当 Skill 化设计完成后,我们遇到了新问题:Skill 虽然拆出来了,但只有人能看懂,Agent 看不懂。

函数代码对工程师很清晰,但对 Agent 来说是不可感知的黑盒。

解决方案:引入 Skill 描述规范

我们为每一个 Skill 增加了一份结构化描述文件(skill.md),实现“代码 + 描述”的双结构。

# skill.md
name: filter_relevant_records
description: |
  从学生历史记录中筛选与当前题目相关的记录,
  基于知识点匹配进行过滤
inputs:
  - name: records
    type: List[Record]
    description: 学生历史记录列表
  - name: question
    type: String
    description: 当前题目内容
dependencies:
  - get_student_history
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

为什么 skill.md 是关键?

  • 没有它: Skill 只是代码,必须人来写流程,Agent 无法参与。
  • 有了它: Agent 可以根据 description 理解能力,根据 inputs 自动补参数,根据 dependencies 构建调用链。

 

实战中的坑:

  • 描述太技术: 要写给模型看,而不是写给工程师看。
  • 粒度过大: 导致 Agent 无法拆解,其他流程无法复用。
  • 忽略依赖: 导致 Agent 不知道调用顺序。

 

六、Skill Flow:让系统“跑起来”

当 Skill 标准化后,我们并没有写死流程,而是做了一层编排:

def run_pipeline(ctx):
    # 1. 获取
    ctx["history"] = GetStudentHistorySkill()(ctx["student_id"])
    # 2. 过滤
    ctx["filtered"] = FilterRelevantRecordsSkill()(ctx["history"], ctx["question"])
    # 3. 压缩
    ctx["summary"] = SummarizeHistorySkill()(ctx["filtered"])
    # 4. 构建
    ctx["prompt"] = BuildPromptSkill()(ctx["question"], ctx["answer"], ctx["summary"])
    # 5. 生成
    return GenerateFeedbackSkill()(ctx["prompt"])
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

图片

升级之后,系统开始具备“演化能力”:

  • 新场景极速上线: 从“重写”变成“组合”。学情分析复用 70%,学习报告复用 80%。
  • 优化路径清晰: 调整过滤策略、调整压缩方式,每一步都可独立优化,不再是“玄学调参”。
  • Agent 自然接入: Agent 不再是空壳,而是可以基于 Skill 描述进行规划和调用。

 

七、落地经验总结

龙虾场景落地四步法:

  1. 识别: 找高价值、高复杂、高频的场景
  2. 拆解: 强制拆解到数据获取、处理、压缩、意图构建、生成
  3. Skill 化: 单一职责,输入输出明确
  4. Flow 编排: 先固定流程,再逐步放开动态决策

 

反常识的实战经验:

  • 不要一上来就做向量检索: 成本高、不稳定。结构化数据 + 规则过滤更可靠
  • 上下文压缩比 Prompt 更重要: 80% 的效果来自数据质量,而不是 Prompt 的花样
  • Agent 是“放大器”,不是“起点”: 没有 Skill,Agent 是空壳;有了 Skill,Agent 才有意义

 

结语

这次我们并不是在“优化一个 AI 功能”,而是在回答一个更基础的问题:

在 AI 时代,系统应该如何组织能力?

我的答案是:用 Skill 作为最小能力单元,用 Flow 组织复杂场景。

当你这样设计系统之后,数据 API 不再只是“提供数据”,AI 也不再只是“调用模型”。它们之间,多了一层真正有价值的东西:可组合、可调度、可演化的能力层。

而这,才是复杂业务在 AI 时代真正的解法。

文章来自:51CTO

Loading

作者 yinhua

发表回复