第 2 课 第一个自己的 Agent:写定义、配人设
复制内置客服写出图书馆助手「小图」的定义,亲手验证 YAML 投喂口与数据库存储的分工、init 幂等的版本化行为,学会用 export 导出定义,建立「Agent 是配置不是代码」的心智。
第 2 课:第一个自己的 Agent——从 YAML 到对话
学完本课你能:独立写出一份 Agent 定义并让它出现在工作台;解释「定义落库 + 版本化」比「Prompt 写在代码里」好在哪;亲手验证改 YAML → 重跑 init → 版本号 +1 的完整链路 | 预计耗时 30 分钟 | 前置:第 1 课(环境就绪、服务能起) | 难度 ★☆☆
这一课你要造自己的第一个 Agent:图书馆借阅助手「小图」。它会陪我们走完剩下的所有课——第 4 课给它写查借阅和挂失工具,第 5 课给它喂馆藏规章,第 6 课给它配评测,第 7 课给它上流程和团队,第 8 课把它部署上线。
先说实话:这一课结束时小图还不会真的用你的人设说话——它的大脑还是第 1 课那个只会一句台词的 FakeLLM。这一课造的是身体:定义、版本、导入链路。第 3 课换上真大脑的那一刻,你会回来问它"你是谁",那时候人设才真正活过来。身体和大脑分开造,恰好让你看清这个框架最重要的一条设计:Agent 是配置,不是代码。
当然,图书馆只是我们的主线。你完全可以换成奶茶店点单助手、社团招新答疑——所有步骤同构,教程末尾 reference/ 目录只维护图书馆版,保证教程可验证。
1. 学习目标
- 写出一份最小可用的 Agent YAML 并导入生效
- 解释 YAML(投喂口)和数据库(存储)的分工,以及为什么改 YAML 必须重跑
luban init - 验证版本化行为:内容变化 → 版本 +1;内容不变 → 不追加
- 用
luban export导出定义并理解往返无损
2. 概念讲解:Agent 是配置,不是代码
回想一下传统做法:一个 AI 助手的人设(系统 Prompt)、它能用什么工具、守什么规矩,都写死在代码里。改一句人设 = 改代码 = 走一遍提交、评审、构建、发版。人设这种一天要调三次的东西,凭什么要走发版流程?
LubanAgent 的回答:Agent 的一切要素是一份定义(definition),存在数据库里,带版本号。改人设 = 改一条库记录 = 立即生效,不发版。每次修改产生一个不可变的历史版本——出了问题可以回滚,评测时可以钉住某个版本对比(第 6 课)。
那 YAML 是干什么的?投喂口。仓库自带的 app/agents/*.yaml 是定义的"源文件草稿",luban init 把它们灌进数据库。之后系统运行读的是库,不是 YAML——所以改了 YAML 必须重跑 luban init 才生效。这个分工你上一课已经听过一遍,这一课亲手验证它。
一份最小定义只有两个必填项:name(即 Agent 的 key)和 instruction(系统 Prompt)。其余字段都是渐进增强——本课只用 greeting(进会话的问候语)、brain(逻辑槽位,下一课细讲)、memory(记忆策略)、limits(治理限额:步数/Token 预算/超时)。工具、知识、技能这些以后再挂。完整字段表别背,用户手册 §1 是字典,用到再查。
3. 动手:主线步骤
步骤 1:从内置客服复制一份起点
cp app/agents/customer_service.yaml app/agents/my_lib_assistant.yaml然后打开 app/agents/my_lib_assistant.yaml,整个文件替换为下面这份(不是改几行——把客服的工具、知识、技能段全删掉,那些第 4、5 课再加;留下的字段都是你现在认识的最小集):
name: my-lib-assistant
description: 图书馆借阅助手:查借阅记录、校园卡挂失、馆藏规章咨询
greeting: 你好,我是图书馆助手「小图」~借阅查询、挂失补办、规章咨询都可以找我。
instruction: |
你是「小图」,学校图书馆的借阅服务助手。
服务范围:借阅记录查询、校园卡挂失、馆藏规章咨询。
边界:不处理图书采购建议、不提供文献代查,超出范围如实说明并建议到馆咨询前台。
brain: smart
memory: session
limits: { max_steps: 12, budget_tokens: 50000, timeout_sec: 120 }
io_contract: { input: text, output: text }✅ 检查点:文件保存后,grep name app/agents/my_lib_assistant.yaml 输出 name: my-lib-assistant——注意 name 就是 Agent 的 key,横线命名。
步骤 2:导入落库
.venv/bin/luban init✅ 你应该看到:输出列表多了一行 my-lib-assistant@1(首次导入,版本 1),其余 9 个内置 Agent 都是 (unchanged)。
步骤 3:工作台确认
刷新工作台 Agents 页。
✅ 你应该看到:my-lib-assistant 出现在列表里,版本 1。点进去能看到你写的人设全文——注意你现在看到的内容来自数据库,不是 YAML 文件。做个实验:把 YAML 文件里的 description 随便改一个字,刷新工作台——没有任何变化。数据库里存的还是老版本。这就是"投喂口 vs 存储"。
步骤 4:验证版本化——改一次,重导一次
把 YAML 里 instruction 的第一句改成:
你是「小图」,学校图书馆的借阅服务助手,语气亲切像个耐心的学姐。然后:
.venv/bin/luban init
.venv/bin/luban init # 紧接着再跑一遍✅ 你应该看到:第一次输出 my-lib-assistant@2(内容变了 → 追加新版本);第二次输出 my-lib-assistant@2 (unchanged)(内容没变 → 不追加)。工作台刷新后小图的版本变成 2,点版本历史能看到 v1 和 v2 两个快照。
这个行为比你想象的更重要:部署脚本反复跑 init 是安全的——不会无限膨胀版本号,也不会把你在线上调过的东西改回 YAML 的状态(那个更深的坑第 3 课会专门验证)。
步骤 5:导出——定义随时能带走
.venv/bin/luban export my-lib-assistant✅ 你应该看到:stdout 打出一份 YAML,字段与你最后保存的版本一致(export 导出的是数据库里的当前版,不是你手上的 YAML 文件——如果两者不一致,以这个输出为准,说明你忘了 init)。加 --output x.yaml --version 1 可以导出历史版本快照。
定义存库、随时导出成文件、文件又能 init 回库——这条往返链路就是你将来迁移环境(开发库 → 生产库)的通道。
步骤 6:跟小图说句话(诚实的部分)
调试台选 my-lib-assistant,说"你是谁"。
✅ 你应该看到:回复还是那句 你好,我是 LubanAgent。——FakeLLM 不读人设,它的剧本只有一句台词。小图的身体(定义、版本、导入链路)已经就位,大脑还没换。这不是失败,是这一课和下一课的分界线。
4. 完成自检清单
-
luban init后输出my-lib-assistant@1,工作台可见 - 改 YAML 不 init → 工作台无变化(投喂口实验)
- 改 YAML + init → 版本 +1;再跑 init →
(unchanged) -
luban export my-lib-assistant输出与库中当前版一致 - 理解了为什么调试台里小图还是固定台词(身体 vs 大脑)
5. 常见坑
改了 YAML,工作台没变化。 最高频问题。YAML 是投喂口不是存储——重跑 luban init。判断你看到的是不是库里的内容:luban export <key> 导出的永远是库。
init 报 未知键 一类校验错误。 YAML 里出现了不认识的字段(多半是从客服 YAML 复制时带了没删干净的段,或者手滑打错字段名)。错误信息会指出是哪个键,删掉或改对即可——字段白名单在 lubanagent/cli/yaml_io.py,字典在用户手册 §1。
name 里有下划线或大写。 key 的惯用命名是横线小写(my-lib-assistant)。下划线能过校验,但和仓库内置 Agent 的风格不一致,工作台里看着也别扭。
版本号比我改的次数多。 检查是不是 YAML 里有多余的空格/换行变化——init 的对比是内容深度相等,格式变化也算内容变化。用编辑器的"去掉行尾空格"功能对齐一下。
6. 练习
练习 A(模仿):给小图换一个你自己写的 greeting,走完 init → 工作台确认 → export 验证的完整链路。
练习 B(变式,重要):把 instruction 整段删到只剩一句"你是图书馆助手",init 后导出看一眼。然后想:第 3 课接上真模型后,这个人设会产出什么样的回复?先写下你的预判,第 3 课结束回来对照——这个练习是让你提前体感"人设的详细程度直接决定回复质量",比任何解释都管用。
练习 C(综合):用你自己的场景(奶茶店/社团/实验室)从零写一份新定义(不复制客服,从空文件开始),只准看字段名不许抄内容。写完 init,确认导入成功。从下一课起你可以两条线并行:跟着教程走图书馆主线,同时用自己的 Agent 做每课练习的变体。
7. 小结与下一课预告
小图有了身体:一份入库的、版本化的定义,以及一条你已经亲手验证过的"改 YAML → init → 版本 +1"链路。你也有了"投喂口 vs 存储"的实感——这个心智模型后面每一课都会用到。
下一课换大脑:注册 DeepSeek(或任一 OpenAI 兼容模型),绑到 smart 槽位。然后你会回来问小图"你是谁"——它终于开口说出"我是小图"的那一刻,前面两课的铺垫全部兑现。顺便你会看清"换模型不改代码"不是口号:改一条库里的映射,同一个 Agent 立刻换脑。
延伸阅读:用户手册 §1(Agent 定义与版本化——全部字段字典)、§9(工程基座) | 参考产出:reference/02-lib-assistant.yaml | 涉及源码:lubanagent/cli/yaml_io.py(YAML 解析与字段白名单)