
👉 真正有价值的,从来不是你做了一个 AI 功能,而是你是否把它变成别人也能复用的能力。
我们最初的目标很直接:
利用 AI 实现作业批阅,我们希望借此节省老师的时间,提升批阅质量,让反馈更“像老师”。

初版实现非常典型,仅仅整合了一个 AI 批阅接口:
def generate_feedback(answer: str, question: str) -> str:
prompt = f"""
请批改学生作业:
题目:{question}
学生答案:{answer}
请给出评价和建议:
"""
return llm.generate(prompt)
上线后的问题也很典型:
我们不缺数据(历史作业、错题轨迹、知识点标签),但这些数据存在,却没有参与到 AI 批阅推理中。
在不断优化的过程中,我们意识到:AI 批阅其实不是一个“单点调用模型”的问题,而是一个典型的复杂场景。
我们在内部将其定义为“龙虾场景”:
定义: 一个由多个数据源、多个处理步骤、多个决策点组成的高价值场景,难以通过单次模型调用完成。

它通常具备三个特征:
AI 批阅到底在做什么?
我们把整个链路完整拆解后发现:
1. 拉取学生历史数据
2. 识别与当前题目相关的数据
3. 提取错误模式 / 学习趋势
4. 压缩为模型可接受的上下文
5. 构建带“教学意图”的 Prompt
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)
这种写法导致了三大问题:
我们做了一个“反直觉”的决定:禁止再写“大函数”,必须拆成最小能力单元(Skill)。

Skill 设计原则: 不是封装函数,而是定义能力边界
所有能力必须满足:
核心 Skill 设计示例:
1、数据检索
class GetStudentHistorySkill(Skill):
def __call__(self, student_id: str, question_type: str):
return db.query("SELECT ...") # 获取纯净数据
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]
3、上下文压缩
这是效果提升最大的一个点,不要把数据直接喂给模型,要先“变成知识”
class SummarizeHistorySkill(Skill):
def __call__(self, records):
# 利用 LLM 将长文本压缩为高密度的“学生画像”
prompt = "总结学生历史表现,重点:高频错误、进步趋势..."
return self.llm.generate(prompt)
4、意图构建
class BuildPromptSkill(Skill):
def __call__(self, question, answer, history_summary):
# 注入教学意图
return f"你是一位经验丰富的老师...结合历史表现{history_summary}...评价{answer}"
当 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
为什么 skill.md 是关键?
实战中的坑:
当 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"])
升级之后,系统开始具备“演化能力”:
龙虾场景落地四步法:
反常识的实战经验:
这次我们并不是在“优化一个 AI 功能”,而是在回答一个更基础的问题:
在 AI 时代,系统应该如何组织能力?
我的答案是:用 Skill 作为最小能力单元,用 Flow 组织复杂场景。

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