00. Start

「套壳」也是个技术活

这是一个 Vibe Coding 实践专栏,记录我把「编码 Agent」的能力搬进「写作」这个垂直场景时踩过的坑、做过的取舍,以及过程中的一些反思和总结


🪧 先从一次不经意的对谈说起

上个月跟一个好久不见的老朋友吃饭聊天,问起最近在忙啥。我说,正计划做一个 AI 写作助手,能学你的写作风格、越写越懂你。他「哦」了一下,然后随口问道:「这是要套壳吗?」

我愣了一下,竟不知怎么回答。倒不是觉得被冒犯,是因为当时还没真正动手,我自己也说不清楚个一二三

起初我的想法特别朴素:大模型有 API 嘛,把写作的诉求拼进 Prompt,把模型吐出来的字接住、显示在界面上,齐活。还一度天真的 yy 过,难点顶多是前端好不好看、Prompt 调得精不精

等真正上手干起来,我才意识到,自己可能严重低估了「壳」这个字里的水有多深。正因为过去这个月一直泡在这摊水里,我觉得正好可以写一篇序,把「套壳」这个略带调侃的事儿,掰开来好好说一下

🔩 同样是 Claude,为什么它能自己干活,我的不能

先从 Claude Code 聊起

用过的朋友大概都有体感:你在终端里跟它说一句「帮我把这个模块的测试补齐」,它会自己去读代码、理解结构、动手改文件、跑测试、看报错、再改,一路折腾到测试变绿,中间基本不用你插手。它像一个真会「干活」的同事,而不是一个只会「回话」的问答机

奇怪的是,我拿着同一个 Claude 模型,自己写代码裸调 API,却怎么也做不出这种「自己干活」的感觉。拿 API 拼凑出的 demo,只能干一件事:发一段话过去,收一段话回来。即便现在的模型都很聪明了,可它仍然像是被困在一个对话框里,碰不到我的文件,也记不住上一步干到哪了

而这,正是重点:差的不是模型,是模型外面那一层东西

打个我自己觉得比较贴切的比方。同一台发动机,装进一辆能上路的车,和摆在地上空转,是两码事。让发动机变成车的,是变速箱、传动轴、方向盘、刹车、仪表盘这一整套「操控系统」。模型就是那台发动机,聪明、有劲,但它自己不认路、不会刹车,甚至碰不到方向盘

Claude Code 厉害的地方,恰恰是那套操控系统做得极其扎实。它有一个会自转的循环,让模型能连续干很多步;有一套工具,让模型能真的读写文件;有一层权限,拦着它别把你硬盘删了;还有记忆、有压缩、有分工。这些加起来,才达成「自己干活」的水平

这套东西,业内有个词,叫 Harness。我也不知道中文怎么翻译合适,姑且先用原词吧。而一旦你把注意力从「模型多强」挪到「Harness 怎么搭」,事情就开始变得具象而可控了

🧭 归纳为一个公式

如果现在再让我回答朋友那句「这算是套壳吗」,我大概会这样说:

是套了个壳。但这个「壳」,也有技术含量,而且是构建好产品的重要一环

更简单粗暴一点,也可总结为如下公式:

一个 AI Agent 产品 ≠ 大模型 + Prompt 它 = 模型(发动机)+ 一整套 Harness

「套壳」这个说法之所以容易招来轻视,是因为它把那层「壳」想象成一张贴纸、一层皮。可真做下来才会发现,那层壳是一整套传动与操控系统。模型能力再强,如果没有这套 Harness 兜着,它就只能原地空转

沿着这个思路,接下来这个专栏要做的事,就是把 Claude Code 这套广受认可的 Harness 拆开来看,一层一层琢磨该怎么为写作场景重新定制

🛠 做这个事情的起心动念

先简单交代下背景。我在做的产品叫 SmartWriter,一句话说清楚它想干的事:

一个跑在你电脑上的本地写作 Agent,它会学习你的写作风格,你用得越多,它越懂你想怎么写,帮你把脑子里那点想法更快、更贴合地落成文章

我自己特别讨厌所谓的「AI 味儿」,因此它的定位绝不是「替你写」,而是帮你把心里那点想法,更快、更省力地变成成品。这里头有几个 feature 我比较在意:它得学得会你的「文风」,你爱用哪些词、怎么起承转合、有什么忌讳;它得记得住你,一篇一篇地越来越懂;它还得让你随时能打断、能改方向,而不是自顾自地写完一大坨甩给你

这其实提出了很高的要求:不做「又一个通用聊天 Agent 的替身」,而是要把 Claude Code 这套编码 Agent 的能力,整套迁移到写作场景里来

一说到「迁移」便知大事不妙,远不是「换个 Prompt」那么轻巧了。一轮实践下来发现果真如此,几乎每一层都得重新裁一遍,涉及的细节很多,但硬着头皮啃下来,回头看收获也特别大

✍️ 写作这件事,到底对 Agent 提了什么不一样的要求

前面稍稍提了几句我特别在意的事,这里可以再展开讲讲。写代码和写文章,对 Agent 的期待大概差在哪里:

  1. 它得有温度,不能冷冰冰地「执行」。 写代码,要的是准确、可复现,模型语气冷一点无所谓,效率更重要。写文章却不一样,我看重的是「说人话」。一个正确但没有人味儿的句子,在写作里就是失败品。所以不能让它像个只会执行工单的工程师
  2. 它得能被随时打断、改方向。 写代码的任务往往目标明确,一口气跑完最好。写作是反复推敲的过程:你写着写着,突然觉得这段语气太冲、那个例子不如换一个。所以 Agent 不能是「你说完我一路写到底」,它得是那种能随时能喊停、也能在中途陪你发散的协作者
  3. 它得守住「作者的声音」,不能张口就来。 这是比较微妙的一条。代码你让它补全、重构,它能跳出框架、天马行空往往是好事。写作恰恰相反,它最该做的是「帮你把你想说的说得更好」,而不是「把它想说的塞给你」。有时候 AI 给我加一整段「金句」,文笔虽然也不错,但听着就不像是我会说的,那也只能删掉
  4. 它得真的记住你,而不是每次都当新用户。 代码工具你用完即走,问题解决了就散场。写作助手的后劲更大,它的价值在于长期积累:它得记得你上篇文章的调性、你反复纠正过的习惯、你明说过的忌讳,一篇篇攒出一个「越来越懂你」的画像
  5. 它得分清「素材」和「指令」。 你丢给它一篇参考资料、一段手写底稿,那是素材,是拿来参考和加工的;而你在输入框敲的那些话,是这次要干什么的指令。写代码场景里,这个边界没那么要命,可写作里一旦混淆,它有可能会把你随手粘的一段范文,当成「请照这个写」,调性文风就偏了

从这五条来看,其实「编码 Agent 的默认习惯」是不太好拿来就用的。因此在 Harness 层面,也没法照抄,只能一层层地为写作场景做定制

举个直观一点的例子:Claude Code 会给模型一把「万能钥匙」,让它能执行任意 Shell 命令,写代码时,跑脚本、装依赖、调测试都太正常了。但落到写作场景的话,这把钥匙其实是不需要的,不能无脑复制过来。一个写文章的 Agent,要通用 Shell 干嘛呢?留着它,等于给自己开了一扇最大的安全后门。像这种具体问题具体分析的细节斟酌,在产品构建过程会大量重现。后续在专栏各篇章里,会反复 call back

🗺 把这套 Harness 拆开:一张地图

那到底要改哪些层?我把它拆成了 6 个板块、12 个核心机制,再加 2 个「怎么长进业务里」的垂直维度,把看似散落的零部件,尝试串成一条环环相扣的因果链:

全景图
全景图

这条链我是这么理解的,前一环都是后一环的前提:

  1. 先得有个会自转的引擎(Loop),还得让它转久了别被有限的上下文撑爆(Compact)
  2. 光会转不够,它得跨时间记住东西:这次写到哪了(Session),以及你这个人到底怎么写(Memory)
  3. 能记住了,我得能塑造它的行为:给它写作人格(System Prompt)、给它「某类文章怎么写好」的方法论(Skills)、给用户明确的操作契约(Command)
  4. 行为还得安全地落到真实世界:把确定性的活交给工具(Tools)、用权限框住它别乱碰(Permissions)、在关键点插进我自己的逻辑做兜底(Hooks)
  5. 碰上复杂长文,它得会拆解和分工:先谋后动(Plan Mode)、把调研和质检外包给「分身」(Subagent)
  6. 最后,这一整套机制,得包装成一个不懂 Agent 黑话的写作者也能顺手用起来的产品(产品流程 + UI/UX)

这张地图,就是往后所有篇章的骨架。后面可讲的内容实在太多,我尽可能精简地写了又裁,但篇幅还都挺长的。因此在每篇开头我都会标一下「你在这里」,希望能把细节和全景都尽可能表达清楚

🔀 两条贯穿始终的暗线

有一个产品设计的理念,会影响到后续各环节的构建,这里先埋个伏笔:在 SmartWriter 里,所有的输出,最后都会落到两条泾渭分明的通路上

举个具体场景。假设你在 AI 输出的草稿上,继续进行编辑和完善。这时候后台要并行关注两件事:一件是「把你改好的正文,原样保留、展示、存档」,这是给你看的,一个字都不能变形;另一件是「你这次追加的改动,暴露了什么风格偏好,值不值得记进你的画像」,这是给程序算的,它必须能被结构化地判断和入库。同一个动作,牵出两种截然不同的产物,一种要「原汁原味的自由文本」,一种要「能被机器消费的结构」。如果硬把它们塞进同一次模型调用,让它一边写正文一边吐 JSON,两边都会做不好

两条通路,不混在同一次调用里,各自工作、不打架。 这会影响到一些产品决策,比如「为什么写作正文不能套 Schema」「为什么分析你风格的活要放在写作流程之外异步做」,答案都能追回到这两条通路的划分上

📕 这个专栏是什么,以及,不是什么

讲 Agent 的好材料已经不少,我在动手实践之前,反复看了这三份。而这个专栏,正是站在它们的肩膀上,做的一份「实战备注」:

你想搞清楚 该去看 而我这个专栏补的是
Agent 背后的原理和思想 Claude Code Harness Book 把抽象原则,落到一个真实产品的取舍里
Claude Code内部怎么实现 Learn Claude Code(源码解读) 不复述源码,讲基于 SDK 封装后怎么用、我又怎么再造
SDK 有哪些开箱能力、怎么调 Claude Agent SDK 官方文档 补文档里没有的:坑在哪、默认值为什么不够、垂直场景怎么定制

与其说这个专栏是我在「教」怎么建 Agent,不如说这是我把自己当下对 Agent 的理解,以及实战中绕过的路、踩过的坑,尽量客观地记录。有些看似言之凿凿的判断,说不定过一阵随着自我认知迭代我也许会进行更新,但至少,这些坑都是实打实踩过的

一句话总结就是,这个专栏定位是以上三份材料的「实战经验 Plus」,外加一份「垂直场景的落地示范」。读完官方文档,你会知道 SDK「能做什么」;我在这里补充的是:拿它做一个真产品,会遇到什么、过程中是如何决策的

也把「不做什么」说在前头,以免浪费你宝贵的阅读时间:不会讲如何手把手搭环境、逐行讲代码,那些 SDK 文档和示例更合适;也不会翻译搬运 API 文档,那是官方的活,我抢不来。我尽量不堆「Agent 真的很强」这类正确的废话,每一篇,至少覆盖「我踩过这个坑」的一手东西,和一个「我为什么这么选」的判断。配图主要使用架构图和流程图讲结构,只在「一句话说不清、一段代码秒懂」的地方,才放一小段代码点睛

踩坑分享示例:项目启动没多久,我一开始没拿定主意,直接照搬 Claude Code 现成的 System Prompt,想着站在巨人的肩膀上岂不美哉?可是仔细研读官网说明以及实测下来,发现底层那套软件工程指令有时候会压不住,写出来的东西很"生硬",最后还是推倒重来、为写作场景重新定制一份。类似这种「前面不懂 or 想抄近道,最后认栽」的坑,后续章节也会在适当的时机插播我的血与泪

下一篇,我们就从这台机器的最底层开始。而那个让 Agent 能「自己干活」的循环,恰好也是两条通路分叉的起点:一条通向给人看的自由文本,一条通向喂给程序的结构化信息。也引出一个有趣的小问题:你问它一句话,它内部到底跑了几个来回?为什么这个数,不能直接拿去给用户当「第几轮对话」的计数?