上一篇我们做出了一个最小版博客选题助手:输入一个写作方向,输出 5 个结构化选题,再把结果保存成 Markdown 文件。
它能跑,也能验收。但如果诚实一点评价,它还更像一个「一次性脚本」,而不是一个「项目」。
差别在哪?你明天再打开它,它不记得你是谁、写过什么、喜欢什么风格;它的材料只能靠你当场手敲;上次生成的结果躺在 outputs/ 里,它自己并不会去看;想改个偏好还得去改代码。
这一篇就往前走一步:把「能跑一次的小脚本」推进成「明天打开还能继续用的东西」。我们会沿着同一个博客选题助手,加上四样东西:工具、记忆、文件读写,以及一个很简单的界面。最后再正式聊一聊上一篇预告过的 MCP。
先分清:脚本和项目的差别
很多人一听「做成项目」,就想到复杂架构、分层目录、配置文件、部署脚本。那是成熟工程的样子,不是现在的目标。
我们现在说的「像项目」,其实只是这几种变化:
| 一次性脚本 | 像项目的东西 |
|---|---|
| 每次运行都是全新的开始 | 记得你的偏好和做过的事 |
| 材料只能当场手敲 | 能自己读文件夹里的资料 |
| 结果是聊天窗口里的一段字 | 结果落成一个个可回看、可复用的文件 |
| 所有逻辑挤在一个文件里 | 几块各司其职的东西,出问题时能定位 |
| 改个偏好要去改代码 | 改一下配置或让助手自己更新记忆 |
把这张表浓缩一下,核心就是三点:它能动手(工具)、它记得住(记忆)、它留下东西(文件读写)。
界面其实排在这三点后面。界面让项目更好用,但不会自动让它更有用。这个顺序后面还会再提一次,因为它是最容易踩反的地方。
工具:让 Agent 不只是嘴上说说
其实上一篇最后加的「保存结果到文件」,已经是这个助手的第一个工具了。
工具的意思很简单:模型负责判断「现在该做什么」,真正动手的是程序。模型说「我想看看你以前写过什么」,然后由一段代码去读文件,把内容拿回来,模型再基于真实内容思考。
对博客选题助手来说,值得加的工具大概有这几个:
- 读已写选题:读一份已发布文章的标题清单,避免又推荐一个写过的题目;
- 读零散想法:读
notes/里随手记的方向,让选题从你的真实积累里长出来,而不是凭空生成; - 保存生成结果:把这次的 5 个选题写进
outputs/,并附上使用到的输入; - 记录采用情况:你选了哪个题目,回写进历史里,下次就知道这一路受欢迎。
生活中的比喻是:这位新同事以前只能听你口述,现在拿到了文件柜的钥匙,能自己翻资料了。
每个工具都要说清四件事
新手最容易犯的错,是只对 coding agent 说「帮我加一个读文件的功能」。这句话太松,AI 会自由发挥。
更好的方式是,让每个工具先说清四件事:
| 要说明的 | 举例:读已写选题 |
|---|---|
| 名字 | read_published_topics |
| 用途 | 读取已发布文章的标题和标签,用于避免重复选题 |
| 输入 | 无参数,固定读 data/published-topics.md |
| 边界 | 只读,不修改任何文件;文件不存在时返回空列表,不报错 |
「边界」这一栏最容易被忽略,也最重要。你可以按危险程度给工具分个类:
- 只读工具:读文件、列目录、查资料。风险最低,先做这类。
- 写入工具:写新文件、追加记录。要限制写在哪个目录里。
- 破坏性工具:覆盖、删除、发消息、改线上数据。新手项目里默认不要有;真需要,就让它先问你一句再动手。
一条很好用的底线是:工具的活动范围限制在项目文件夹内。不要让一个刚学会读文件的助手,拥有扫你整个硬盘的权限。
可以这样对 coding agent 说:
请给项目加两个工具,先只做只读的。
1. read_published_topics:
读取 data/published-topics.md,返回其中的文章标题列表。
只读取,不修改任何文件。
文件不存在时返回空列表,并在终端提示"还没有已发布记录"。
2. read_ideas:
读取 notes/ideas.md,返回里面记录的写作想法。
同样只读。
要求:
- 两个工具都只能访问项目目录内的文件,禁止访问项目外的路径。
- 请先告诉我你准备修改哪些文件、新增哪些函数,再开始改代码。
- 暂时不要让模型自动调用删除或覆盖操作。
最后那句「先说准备改哪些文件」是老规矩了,但它真的能省掉很多返工。
记忆:让它别每次从零开始
工具解决的是「能动手」,记忆解决的是「别每次重新认识你」。
对选题助手来说,值得记的东西大概分两类。
第一类是偏好,也就是长期稳定、不怎么变的东西:
{
"blog_positioning": "写给想用 AI 做项目、但还不会完整写代码的新手",
"preferred_length": "1500-2500 字",
"tone": "口语化,少术语,多举例子",
"avoid": ["标题党", "纯工具测评", "没有具体步骤的鸡汤"]
}
第二类是历史,也就是一次次运行积累下来的东西:
{
"generated": [
{ "date": "2026-08-20", "direction": "AI 工具入门", "adopted": "第一次做 Agent 项目,应该从哪里开始" },
{ "date": "2026-08-24", "direction": "Prompt 技巧", "adopted": null }
]
}
有了这两份东西,助手的行为会明显不一样。它会知道你不是要写给资深工程师看的,会避免再推一个上个月刚写过的题目,也会发现「偏实战步骤」这类角度你采用得更多。
生活里的比喻是:偏好像贴在显示器边上的便利贴,历史像一本翻旧的笔记本。前者每次都看,后者需要时翻一翻。
可以这样要求 coding agent:
请加一个最简单的记忆功能,用文件保存,不要引入数据库。
1. data/memory.json 保存两部分:preferences(偏好)和 history(历史)。
2. 程序启动时读取它,把 preferences 注入 prompt。
3. 每次生成结束后,把这次的方向和时间追加到 history。
4. 提供 update_preferences 这类最小修改方式,让我能改偏好而不用改代码。
要求:
- 记忆文件必须是人能直接打开看懂的格式。
- 不要保存 API Key、密码或任何敏感信息。
- 如果 memory.json 损坏或格式不对,给出友好提示并备份原文件,不要直接覆盖。
这里有几条经验值得记住。
记忆要少而准。 把所有聊天记录都塞进去,不是记忆变强了,是噪音变多了。只留真正会影响下次判断的东西。
记忆要能被你查看和修改。 如果你看不懂、改不动,它就会慢慢变成一堆没人敢碰的垃圾。用 JSON 或 Markdown,别用只有程序读得懂的格式。
记忆要能被删掉。 出现过时的偏好是很正常的,能一键清空或回滚,你才敢让它一直记。
顺便说一句:当「已写文章」越积越多,你会发现把整份清单都塞给模型很浪费。那时候更好的做法是「先找出相关的几篇,再一起交给模型」。做到这一步,其实就已经摸到第一篇讲过的 RAG 了。所以记忆和 RAG 不是对立关系,它们经常是同一条路上的前后两段。
文件读写:给项目一块地面
工具和记忆最后都要落到文件上。文件读写看起来最土,却是最能让项目「站住」的部分。
上一篇的目录是这样的:
blog-topic-agent/
README.md
.gitignore
.env.example
requirements.txt
outputs/
src/
main.py
加完工具、记忆和资料之后,可以慢慢长成这样:
blog-topic-agent/
README.md # 怎么跑、怎么验收
.gitignore # .env、outputs 不该进仓库
.env.example
src/
main.py # 主流程
tools.py # 文件读写工具
memory.py # 记忆读写
data/
memory.json # 偏好和历史
published-topics.md # 已写过的选题
notes/
ideas.md # 你随手记的方向
outputs/ # 每次生成的结果
不需要照抄,关键是三条约定。
第一,输入和输出分开。 你提供的资料放 data/ 和 notes/,程序生成的东西放 outputs/。混在一起的话,过两周你就分不清哪个是自己写的、哪个是 AI 生成的。
第二,路径要相对,不要写死。 让 coding agent 用相对项目根目录的路径,而不是 C:\Users\你的名字\... 这种。写死的路径换个电脑、换个目录就全线崩溃。
请把所有文件读写改成基于项目根目录的相对路径。
不要在代码中出现任何绝对路径。
请检查一遍并告诉我改了哪些地方。
第三,动手前先报计划。 尤其是写操作,让它在终端先打印「准备写入:outputs/2026-08-29-ai-tools.md」,再真的写。这样你一眼就能发现它要写错地方了。
安全上有三条底线值得写在 README 里:
- 只允许读写项目目录内的文件;
.env必须进.gitignore,绝不提交;outputs/也建议忽略,或者至少别把带敏感信息的结果提交上去。
这一阶段可以这样验收,非常具体:
1. 在 data/published-topics.md 里放 3 个你写过的标题。
2. 运行助手,输入一个和它们相近的方向。
3. 检查输出的 5 个选题里,没有和已写标题明显重复的。
4. 检查 outputs/ 里多了一个新文件。
5. 检查 data/memory.json 里多了一条今天的记录。
6. 再运行一次,确认这次会参考上一次的历史。
跑通这六条,你的助手就已经从「聊天工具」变成「会看资料、会记账的小助手」了。
简单界面:先命令行菜单,再网页
功能稳定之后,界面才值得做。
但其实在网页之前,还有一个很划算的中间步骤:命令行菜单。它几乎不增加复杂度,却让使用体验好很多。
比如运行 python src/main.py 之后出现:
博客选题助手
1. 生成新选题
2. 查看历史记录
3. 修改我的偏好
4. 查看已写过的选题
0. 退出
请输入编号:
这个菜单的价值不只是好看。它把「能用」变成了「知道能用哪些」:你不用再记命令参数,也不会忘了自己还有偏好可以设置。
可以这样要求:
请给命令行加一个最简单的菜单。
要求:
1. 启动后显示 4 个选项:生成新选题、查看历史、修改偏好、查看已写选题。
2. 每个选项只调用已有函数,不要重写逻辑。
3. 输入非法编号时提示并重新显示菜单。
4. 任何会写入文件的操作,执行前先打印"准备写入:文件路径"。
5. 不要引入新的依赖。
如果这个菜单用起来顺手,再考虑做一个很轻的网页:一个输入框、一个「生成」按钮、一个结果区域,也许再加一个历史列表。Python 生态里 Streamlit、Gradio 这类工具能让这件事变得很快;也可以用最简单的 HTML 表单加一个本地小服务。
给 coding agent 的提示大概是这样:
我想加一个最简单的网页界面,只做输入方向和查看结果。
要求:
1. 页面上只有一个输入框、一个按钮和一个结果展示区。
2. 复用现有的生成函数和记忆逻辑,不要重写。
3. 不要做登录、用户系统、数据库和部署。
4. 先只在本地运行,告诉我访问哪个地址。
5. 请说明新增了哪些文件、安装了哪些依赖。
还是那句提醒:核心输出不稳定之前,别急着做界面。 一个简单的判断标准是——同一组输入连跑三次,如果结果差别很大,说明要调的是 prompt 和输入,不是页面。把不稳定的东西装进漂亮的页面里,只会让你更难发现问题。
MCP:工具多了之后的统一插口
第一篇讲 Tool 时我们提过一句:工具多了,会遇到 MCP 这类帮助 AI 应用连接外部工具和资源的协议。现在正是讲它的时候。
MCP 是 Model Context Protocol。先说清楚一件事:它不提供任何新能力。 它能读文件,你的脚本也能读文件;它能查数据库,你写代码也能查。MCP 解决的不是「能不能做」,而是「怎么连」。
生活里的比喻是插口和转接头。
如果你的助手只能读本地文件,你写几行代码就够了。但当它还要连网盘、连笔记软件、连代码仓库、连日历、连内部系统时,麻烦就来了:每接一个,你都要写一套专属的连接代码,换一个客户端又得重来一遍。这就像每个设备都自带一根形状奇特的线。
MCP 想做的是把这件事统一起来:工具和数据按同一套规则对外说明「我是谁、我能做什么、需要什么参数」,AI 应用这一边也按同一套规则去发现和调用。于是同一套工具可以在不同客户端里复用,别人写好的连接你也能直接拿来用。
那什么时候该用它?
适合的时候:
- 你要接的外部系统越来越多,专属代码开始重复;
- 你想用别人已经写好的连接,比如现成的网盘或代码仓库接入;
- 你希望同一套工具能在不同的 AI 客户端里使用;
- 你的项目开始从「一个人的小工具」走向「要给别人用」。
暂时不需要的时候:
- 项目只有一个脚本、两三个本地工具;
- 工具都是你自己写的,也不会在别处复用;
- 你还没搞清楚工具本身该怎么设计。
第二种情况其实才是新手现在的位置。对博客选题助手来说,读文件、写文件、记偏好,直接写成几个函数最简单,也最好懂。这时候引入 MCP,只会让一个原本清楚的小项目突然多出一层你暂时用不上的抽象。
所以对新手最诚实的建议是:知道 MCP 是什么、解决什么问题,就够了。 等哪天你真的开始重复写第三套连接代码,或者想接一个别人已经做好的数据源,再回来认真学它。那时候你会学得很快,因为你已经知道没有它的时候有多麻烦。
一个稳妥的推进顺序
把上面这些排一下序,可以得到一条对新手比较友好的路线:
| 步骤 | 加什么 | 怎么验收 | 这一步先别做 |
|---|---|---|---|
| 1 | 只读工具:读已写选题、读零散想法 | 生成的选题不再和已写内容重复 | 任何写操作 |
| 2 | 偏好记忆 | 改一次偏好,输出风格随之变化 | 历史记录 |
| 3 | 历史记忆 | 连续跑两次,第二次会参考第一次 | 复杂数据库 |
| 4 | 整理目录结构 | 每类文件都在该在的位置 | 大重构 |
| 5 | 命令行菜单 | 不用看 README 也能用完全部功能 | 网页界面 |
| 6 | 轻量网页 | 在浏览器里完成一次完整流程 | 登录、部署 |
| 7 | 评估要不要用 MCP | 是否出现重复的外部连接代码 | 为了用而用 |
重点不是这张表本身,而是一次只加一个,跑通验收再加下一个。
这是 Vibe Coding 里最反直觉、也最有用的一条经验。你看着 AI 几分钟就能生成一大堆功能,很容易想着「干脆一次全做了」。但一次加五个功能,出问题时你不知道是哪一个新的坏了;一次加一个,出问题立刻知道就是它。
这一版可以停下来的自检清单
做到下面这些,就可以先提交一个版本,喘口气:
- 助手能读取项目里的资料,而不是只靠当场手敲;
- 至少有一个只读工具,并且明确限制了访问范围;
- 偏好存在文件里,改偏好不用改代码;
- 历史记录会累积,下一次运行会参考上一次;
- 输入资料、生成结果、记忆数据分门别类放好;
- 所有路径都是相对路径,没有写死的绝对路径;
- 会写入文件的操作,执行前都会告诉你准备写哪里;
- 有一个命令行菜单,不查 README 也能用;
.env已经进.gitignore,没有被提交;- README 里写清楚了怎么运行、怎么验收、哪些目录是干什么的。
如果这些大部分都做到了,这个小工具就已经脱离玩具阶段了。它可能还很简单,但它是可继续的:往上加能力不会推倒重来,换台电脑也能跑,过两个月回来你还能看懂。
结尾
从「能跑的脚本」到「像样的项目」,真正的分界线不是代码变多了,而是它开始有了三样东西:能动手的工具、能延续的记忆、能沉淀的文件。
界面让这套东西更好用,MCP 让它在工具变多时更好接,但它们都是后面的事。先把工具、记忆和文件这三块地基铺好,后面每一步都会轻松很多。
还有一个提醒值得再说一次:这一篇里所有东西都可以一件一件加。你不需要一个下午就把工具、记忆、菜单和网页全做完。挑一件,加进去,跑通,验收,提交。这个节奏看起来慢,实际上是最快的那一种。
下一篇是这个系列的第六篇,也是我觉得对新手最有用的一篇:《从能跑到好用:怎么调 prompt、看错误、让 AI 帮你修 bug》。我们会聊怎么判断问题是出在 prompt、输入、代码还是环境,怎么把报错完整地贴给 AI,怎么要求它只做最小修改,以及怎么用几组真实样例把 Agent 一点点调稳。
本系列目录
这是「AI / Vibe Coding 新手系列」的第 5 篇,全系列共六篇:
- 先听懂:AI、LLM、Prompt、Agent、RAG、Tool、Memory 到底是什么
- Vibe Coding 是什么:不会完整写代码,也能把想法变成项目
- 做第一个 Agent 前,要准备哪些东西
- 实战:用 Vibe Coding 做一个最小 Agent
- 让 Agent 更像项目:工具、记忆、文件读写和简单界面(当前篇)
- 从能跑到好用:怎么调 prompt、看错误、让 AI 帮你修 bug
延伸阅读(比本系列更偏工程化,建议跑通第一个 Agent 后再看):从 Demo 到可交付:如何做一个 Agent 项目
