Midnight's blog

Back

一、Hello Agent#

先认识一下 Agent:它不是「更会聊天的模型」,而是能带着目标连续干活的程序。

核心就一件事——循环:

想下一步 → 调用工具 → 观察结果 → 再想 → 再调用…直到完成或停下。

和普通对话模型的区别很直接:后者问一句答一句就结束,Agent 会围着目标转好几圈,中间可能读文件、跑命令、查信息,再根据结果调整。这个圈一般叫 Agent Loop。

while not done:
    think()   # 推理
    act()     # 调 Tool
    observe() # 看结果
python

所以学 Agent,不必一上来堆概念:先记住它是个循环;Tool、Hooks、ToDo、Subagent、Skills等都是后来挂在这个循环上的能力与约束。

二、工具#

2.1 Tool#

“LLM 决策,Tool 落地”

从聊天对框到终端干活,第一个重要一步就是Tool,读文件、改代码、跑命令从此开始有了动手能力。模型通过 Tool Calling / Function Calling 选出工具并传入参数,由运行时真正执行,再把结果回传给模型,形成 [ 推理 → 调用 → 观察 → 再推理 ] 的循环。

2.2 Hooks#

“管理边界能力”

有了 Tool,Agent 能读改文件、执行命令,能力明显变强;随之而来的是风险:路径搞错、误执行破坏性操作、越权访问敏感资源。

很多人会想:用提示词写清不许删文件、不许乱改行不行?提示词只能做 软约束——模型仍是概率生成,同一句话不能保证每次都遵守。

要把尽量别乱来变成违规就拦住,需要挂在工具调用前后的硬约束机制,这就是 Hooks(钩子):在执行前审计/拦截,在执行后记录或补救,把不确定的生成行为收进可强制执行的边界里。

三、规划与协作#

3.1 ToDo#

“按清单推进,而不是想到哪做到哪”

举个例子:你说”帮我推荐一件衣服”。

没有 ToDo 时,Agent 多半只能靠已有知识顺着你说——听起来很会聊,其实像在哄人,缺少推销员那种主动采集信息、对比筛选的过程,推荐也容易飘、容易空。

有了 ToDo,它会先把路径摊开:了解喜好 → 结合季节 → 确认体态/尺码 → 检索候选 → 清洗筛选 → 给出推荐;若你觉得步骤不对,还可以改清单。每一步可追踪,结果才更靠谱。

人和 Agent 不一样:人可以边想边做;Agent 没有真正的自主意识,长链路里更容易跑偏。所以在 Agent 开发里,规划不是加分项,而是把能力收成可控流程的关键一步——ToDo 做的,就是把模糊目标拆成可执行、可修正的清单。

3.2 Subagent#

“主 Agent 编排,Subagent 干活”

还是买衣服:你要的不只是推荐一件,还要比价、看评价、盯库存。

没Subagent ,全压在一个 Agent 身上——边聊边搜边比,上下文越堆越乱,最后可能记混了,推荐也糊。

有Subagent,主Agent 像店长:一个小弟专搜款式,一个专比价格,一个专看评价;各自干完交结果,店长再汇总给你。人可以一个人干到底;Agent 不行,单会话塞太多容易懵。所以复杂任务要拆出去、并行干、再汇总——这就是 Subagent。

# 主 Agent 派活,Subagent 专项执行后交回结果
task = "推荐一件春季外套"
# 并行委派(示意)
results = {
    "style":  subagent_explore("搜春季外套款式"),   # 翻资料
    "price":  subagent_shell("比价脚本"),            # 跑工具
    "review": subagent_general("总结口碑"),          # 综合分析
}
# 主 Agent 只负责编排 + 最终答复
answer = synthesize(task, results)
python

3.3 Skills#

“把会做,变成按标准做”

还是买衣服:老销售心里有套固定流程——先问预算、再看场合、再给三档选择。新人全靠临场发挥,今天一套说辞明天一套。

没有 Skills 时,Agent 每次都靠临场发挥,同一类活质量忽高忽低。

有了 Skills,等于给它一本标准作业书:什么场景触发、先问什么、输出长什么样。人可以凭经验自由发挥;Agent 没有真正经验,要把经验写成可复用规范,它才能稳定复现——这就是 Skills。

# Skill = 可复用的标准(触发条件 + 步骤 + 输出要求)
skill = {
    "name": "recommend-clothes",
    "when": "用户要推荐衣服",           # 何时启用
    "steps": [
        "确认预算与场合",
        "结合季节缩小范围",
        "给出高中低三档推荐并说明理由",
    ],
    "output": "列表 + 理由,不要空洞夸奖",
}
# 命中场景就按手册走,而不是纯靠临场发挥
if match(user_query, skill["when"]):
    follow(skill["steps"], skill["output"])
python

3.4 System prompt#

“按需组装”

很多人以为 System Prompt 就是开头硬编码一大段你是谁、你要怎样。能跑,但不灵活:任务变了、Skill 变了、记忆变了,整段都得改。

更常见的做法是组装(Assembly):运行前把几块拼起来,再塞进系统位。

  • 角色与边界(你是谁、不能干什么)
  • 当前任务说明
  • Skills / 规范片段(命中才挂上)
  • 记忆摘要 / 索引(见下文)
  • 输出格式要求
# System Prompt = 拼装,不是写死
system_prompt = "\n\n".join([
    role_rules,           # 角色与边界
    task_brief,           # 本次任务
    skill_snippets,       # 命中的 Skill
    memory_index,         # 相关记忆索引
    output_format,        # 输出要求
])
python

四、记忆#

4.1 context#

“窗口信息”

Context 就是塞进模型里的东西(可重复的):系统提示、对话内容(有用的)、Tool结果…Agent多跑几轮,文件内容、命令输出全堆在message里,窗口一满,服务就停止了。

所以要压缩(Compaction):裁减无关旧对话、把Tool结果总结、输出落库成文只能预览,还不够再让Agent做一轮摘要。原则很简单——便宜的先做(不设计Agent的能用代码搞定的),贵的后做。

代价也清楚:压缩是为了继续跑,细节会丢。用户偏好、关键约束一旦挤掉,下一圈可能就忘了——这就连到 Memory。

# 每轮调用前:先腾地方,再问模型
context = cheap_compact(context)   # 裁剪 / 占位 / 文件落库
if too_long(context):
    context = summarize(context)   # 贵:LLM
python

4.2 memory#

“压缩会丢细节,重要的是持久化”

简单落地:

  1. 用 Markdown 文件持久化,按固定格式写(类型、内容、时间、适用范围)
  2. 维护一份索引 md,只记有哪些记忆、大概讲什么
  3. 组装 System Prompt 时注入索引(或相关条目),而不是整库硬塞进 Context
  4. 分类:这类记忆该给谁——主 Agent、某个 Skill、某类任务、还是仅本会话
Agent基础概念扫盲
Author Midnight
Published at 2026年7月15日