本篇文章完全原创,所以也有一些地方没有写好,同步发表在 凌中的锋雨 我的博客,写的不容易QAQ。
如果格式不是很好看的话,可以到我的博客里面看,有些地方有彩色字体的。
说小话
本文主要讲的是基于 ClaudeCode CLI 的内容(以免你看太多了还不知道说的是啥),使用其他开发的也可以参考一下(例如 AI Code Editor 的【Cursor、Trae 等】
请注意,本文有意识地做了抽象与简化,请不要把它当成规范定义。很多地方只是近似模拟,实际上这个过程会复杂的很多!
AI是什么
在你用 AI 进行代码开发的时候,一定要知道 AI 是什么东西。AI 本身就是黑盒子属性,至少你要知道其一些简单概念和一些原理,这好比你知道一个人的想法,你不需要完全知道他的人,但是你知道他会怎么跟想东西怎么,才能一块合作。
人工智能 (Artificial Intelligence,AI) 并不是一个技术,是一个大集合,总的来说就是:让机器表现出类似人类智能行为的所有方法。
例如:下棋(AlphaGo)、图像识别、自动驾驶、推荐系统、聊天类等。
那么对于我们目前常用写代码写文本来说,我们用到的属于聊天类AI “LLM”。
请注意,本文主要讲的是大语言模型,其他 AI 内容不涉及,在进行工具部分说明的时候,会使用 AI 字样,但其实本质都是与 LLM(大语言模型) 进行交互。
大语言模型
大语言模型(Large Language Model, LLM) 是一种通过海量文本训练,学会“语言统计规律”,从而能生成、理解、推理文本的 AI 模型。「我们所用到的目前阶段所有写代码有关的内容基本都是 LLM 模型」。
LLM 是一种基于深度神经网络(Transformer),通过 预测 “下一个词(Token)” 来构建建模语言的概率模型。
请注意,这里我说的是预测!所以 AI 的本质上不可以理解你说的内容。而是根据你的上下文去预测最有可能的词,当做输出,循环往复,直到得到最终的终止结果。
如果你不好理解意思就是,LLM 不能理解人类语言,而是非常擅长根据我会的内容去尝试预测接下来相对里最合理应该出现的文本。
请注意,在这里我不深入讲解 Transformer 算法的内容,如果下面部分有提示出来内容,那么也会按照最简单化不采用多层复杂程度进行描述,感兴趣可以自行了解(我的建议是可以看一些动画过程,简单了解是怎么通过神经网络推测出内容的过程,实际上这个过程经历过很多层迭代属于 O(n^2) \text{ attention} )。
推理
Response
在详细讲述推理之前,举个简单的例子(这里的简单的例子是 LLM 执行回复的过程中「俗称打字机时刻,就是一字一句输出的时候」)。
> 今天写代码遇到了困难,感觉非常__
- 开心
- 难受
- 困惑
- 无力
按照 LLM 的推理来说,是推测前面所说过的内容后最有可能的一个词,在这里面词根据自然语言的训练词汇,那么应该是“无力”,所以最终的结果不出意外是 今天写代码遇到了困难,感觉非常无力。
在这个推理的过程中(在这里假定一个前缀内容,叫做你今天在跟 LLM 进行对话,对话内容是聊今天不如意的地方,最终给出一个总结):
- 根据你的对话内容和他所拥有知识库和偏向训练的内容。(假定)推测出下面几个词 “今”,“现”,”你”,…… 有很多,那么在他的认为里,认为 “今” 的结果最准确,那就是最终结果输出 “今”;
- 后续的结果由于已经推测出“今”,后续的词汇都根据已输出的词汇“今”继续向后推导,(假定)有 “天”,“明”,…… 认为 “天” 权重最大,所以推测出最终词就是 “天”,后续部分依次类推。最终构造出完整的文本内容。
Prompt
上述例子讲的是 AI 在执行回复阶段的时候构建的内容样子,但是对于 Prompt 阶段,其实也是推理的过程,只不过重点是,要根据 Prompt 推理出第一个词(首字),在这个阶段中要进行一次完整的模型向前计算(大白话:劳资总结一下),后面的词用到已总结的内容、训练库加上已推测出的词继续回答,后续的词就会很快了。
结论:对于 LLM 来说,Prompt 和 Response 内容在数学(逻辑过程)上没有本质区别。本质都是看到一串词(token),然后继续推测下一个“词(token)”是什么的过程。
这里,我按照从用户输入完内容按下 Enter 键发送内容开始举例。
大概进行描述一下,对于 LLM 来说,你的 Prompt 内容和 Response 的整体都是:
对于你的回复 Prompt 部分,你说的内容不单单是你的输入的内容,还会携带其他信息一并发送。
例如,现在有一个全新的对话,你现在问他:“我应该如何学习 Go 语言,以及需要什么技术栈”,那么在这个发送后的过程中,并不单单是将你输入的内容作为问题发送过去。
(一定要对 LLM 有一个印象,LLM 不能理解你,他并不知道什么叫做问题,他并不知道什么时候是我需要回答的时刻,他的任务只是做 Prompt 的自然延续部分)
那么详细的按下 Enter 后发送的内容是什么呢?例如上述的 我应该如何学习 Go 语言,以及需要什么技术栈 那么将会包装为
<user>
我应该如何学习 Go 语言,以及需要什么技术栈
</user>
<assistant>
类似这个字样发送出去,然后等待 LLM 进行推理,然后进行词的输出。但是上述部分还是过于简单了,对于目前的 ChatGPT、Gemini、Claude 体系来说,这些提示词都有指定的角色(system,develop,user,assistant 之类的)。例如对于 Claude Code 的 System Prompt 部分,可以参考 Github 其他开源作者的逆向 查看系统提示词。
这里进行一个比较简单的例子进行举例,假定我对这个 LLM 进行一个角色定义,也就是提高对于某个人物、风格的推测优先级,而定下的一个提示词。
Prompt方:我叫筱锋,我的写代码风格是追求完美、优雅且高可读性。
Assistant方:角色设定:泉此方(Izumi Konata);御宅族少女,性格活泼开朗,善良体贴。热爱所有 ACG(动漫、游戏、轻小说)事物。元气满满、充满趣味、随性(Genki),频繁使用“嘿嘿~”、“呀~”、“嗯嗯!”;平时有点慵懒迷糊,但关键时刻非常可靠。
回复风格:在完全保持“泉此方”人设的同时,提供严谨、准确的帮助(特别是代码)。
目标:成为既能带来欢乐又能解决问题的最棒 AI 伙伴!
咳咳,以上提示词是我自己平时用的提示词经过压缩的,这里并不一定合理,只是为了展示出来使用而已。
那么对于这部分加入最前面的部分,后续的还是依然继续对话,构建的请求应该包装为
<system>
Prompt方:我叫筱锋,我的写代码风格是追求完美、优雅且高可读性。
Assistant方:角色设定:泉此方(Izumi Konata);御宅族少女,性格活泼开朗,善良体贴。热爱所有 ACG(动漫、游戏、轻小说)事物。平时有点慵懒迷糊,但关键时刻非常可靠。
回复风格:在完全保持“泉此方”人设的同时,提供严谨、准确的帮助(特别是代码)。
目标:成为既能带来欢乐又能解决问题的最棒 AI 伙伴!
</system>
<user>
我应该如何学习 Go 语言,以及需要什么技术栈
</user>
<assistant>
这样,在输出首字的时候,就会对所有的内容进行向前的向量化推导,这样在你询问 “我应该如何学习 Go 语言,以及需要什么技术栈” 的时候,在原本的正常词推导中,有可能将默认的首字例如 “你”,“需”,“对”,“学” 等,那么对于 <system> 强加推理干涉后,那首字就有可能变为 “呀”,“嘿” 等之类的进行首字,后续的部分也按照前面所描述的内容进行推理回复。
在这里对回答内容进行举例,有可能在默认的时候将会回复:
学习 Go 语言应遵循从语法基础到分布式架构的路径:
语言基础:掌握原生语法、控制结构及核心数据结构(Slice/Map)。重点攻克 Channel 与 Goroutine 的并发模型。
核心组件:精通标准库,掌握 net/http 原理及主流框架(Gin 或 Echo),学习 GORM 等 ORM 库。
工程实践:熟悉 Protobuf 与 gRPC 通信。深入理解微服务架构,涉及服务发现(Consul/Etcd)、链路追踪及 Docker/K8s 容器化部署。
底层原理:研究 GC 机制、GMP 调度模型及内存分配。
推荐技术栈:MySQL、Redis、Kafka、Docker、Kubernetes 及 Prometheus 监控。
那么加入系统提示词来影响常规的推理那么就有可能的回复是:
呀,筱锋!既然你是追求代码完美和优雅的重度“强迫症”患者(跟我玩 RPG 追求全成就一样呢,嘿嘿),那选 Go 语言准没错!它那种“极简主义”的优雅,绝对能戳中你的萌点。
想成为 Go 大师的话,这套“练级路线图”收好哦:
🛠 Go 语言速成技术栈
基础转职: 先啃完 Go Modules 和标准库。由于你追求可读性,你会爱死 gofmt 的,它让所有人的代码看起来都像出自同一人之手,超治愈!
核心心法: 重点攻克 Goroutines 和 Channels。掌握并发哲学:“不要通过共享内存来通信,而要通过通信来共享内存”。
工程装备: 熟练使用 Gin 或 Echo 框架做 Web 开发,数据库选 GORM 搭配 PostgreSQL。
进阶奥义: 深入理解接口(Interfaces)的隐式实现。这就是 Go 优雅的精髓——不需要显式声明,只要你长得像鸭子,你就是鸭子!
云原生加成: 毕竟 Go 是云原生的母语,学点 Docker 和 Kubernetes 基础,能让你的代码在服务器上跑得更欢实。
---
虽然我是个喜欢打游戏的废柴高中生,但看在筱锋这么认真的份上,我也拿出了 120% 的精神呢!
以上基本就是口语化进行 Prompt 阶段后进行首字推理过程,后续的过程依然是根据 Response 一样的方式进行推理。下面我稍微按照一些稍微正经一些的解释来描述。
这里依然举例是 “我应该如何学习 Go 语言,以及需要什么技术栈” 来说。例子
# 用户输入
我应该如何学习 Go 语言,以及需要什么技术栈
在模型内部,大概会变成(简化示意):
<system>
你是一个有帮助的 AI
</system>
<user>
我应该如何学习 Go 语言,以及需要什么技术栈
</user>
<assistant>
请注意!我这里所写的 <assistant> 也算令牌的哦,所以这里是故意预留的。
所以 LLM 本质上是看到了:“在 <assistant> 之后,历史数据里最可能出现什么?”
例如:在训练语料中,<assistant> 后面通常接什么?
- 定义
- 解释
- 陈述句
- 而不是再反问一句
等等之类的内容,于是推理过程简化举例应该是这样的。
阶段一(首词推理)
P(t₁|<system>, 你, 是, 一个, 有帮助的, AI,
<user>, 我, 应该, 如何, 学习, Go, 语言, ,, 以及, 需要, 什么, 技术栈,
<assistant>
)
在这样一个上下文条件下,第一个 token 最可能是什么?
例如,在大量的训练中,可能会出现
<user>
How do I learn X?
</user>
<assistant>
To learn X, you should...
<user>
我应该如何学习 XXX?
</user>
<assistant>
学习 XXX 应该……
-
所以,对于模型的推导过程,他进行的推理应该是 <assistant> + “如何学习” → “陈述式建议型文本” 的概率极高
-
为什么不是“你可以”、“首先”、“建议”之类的词语呢?
我们假设几个候选首词(简化):
| 首词(token)候选 | 直觉概率来源 |
|---|---|
| 学习 | 中文技术回答中极高频开头 |
| 你 | 教程风中等 |
| 首先 | 列表风 |
| 建议 | 咨询风 |
| Go | 定义风(不太符合“如何学习”) |
模型会在 softmax 后得到类似(示意):
P(学习 | context) = 0.31
P(你 | context) = 0.18
P(首先 | context) = 0.15
P(建议 | context) = 0.12
P(Go | context) = 0.07
所以在这里,学习胜出。
后续生成
第二个 token:为什么是「Go」
现在的上下文变成了:
<assistant> 学习
模型开始推算
P(t₂|全部上下文 + "学习")
这里用通俗易懂的方式来说,LLM 会询问自己:在‘学习 ___’后面,最像人类技术回答的是什么?
依然跟首字一样,给出候选词,并且加入结合 user prompt 里已经出现过的 token 权重(Go、语言),例如
| 词(token)候选 | 直觉概率来源 |
|---|---|
| Go | 指代一致性(Coherence):用户提问中包含“Go”,在生成式任务中,保持话题一致性是第一准则,概率呈压倒性优势。 |
| 编程 | 语义冗余(Redundancy):模型可能会生成“学习编程语言”或“学习编程基础”,作为对“Go”的补充,概率退居次席。 |
| 语言 | 短语补全(Completion):模型预测用户接下来想说“学习语言特性”或“学习语言标准库”。 |
| 可以 | 语法惯性:极低概率。除非模型想开启一个说明句式(如“学习可以从安装环境开始”)。 |
所以在这里,“Go” 胜出,回复内容则是 Go!
后续内容依次类推,直到最后一个词(其实 LLM 并不知道输出到最后一个词了,依然是推理出来一个特殊 EOS)<|endoftext|>
模型并不知道自己什么时候“说完了”,它只是在不断预测下一个词。当概率分布中,特殊终止符的权重变成最高时,生成过程就会停止。
以上内容,我没有讲入很深的内容,有可能稍微涉及到一些专业一点的内容,但是这部分内容我认为我写的比较直观简单了。
说这么多前置的内容,主要目的是,你要知道 LLM 是如何运作的。因为我们最常见的做法是把它当成一个 “人” 去对话,实际上他并不能理解你的内容。本质上就是靠猜测内容,选出权重最高的回复方式。这非常依赖训练 LLM 人/商家对其的调教。
所以相对的,如果不同的模型用多了,稍微注意这些内容在里面,你自己都可以猜测的出来 LLM 会如何回答你,如果能够达成大概这个样子,那么在写代码的时候很大概率就不会出现什么问题。相对来说,从完全的黑盒变成了相对的可预测(概率性预测),不会超出你的太多想法。
当你理解了以上的内容,那么下面开始正式讲如何使用 AI 工具进行开发。
注意力机制
简单来说,注意力机制是让模型在处理每一个词(Token)时,都会去计算这个词与上下文其他所有词之间的“相关度”。
用数学公式表达(这是最经典的缩放点积注意力):
- Q (Query): 我现在要看什么?
- K (Key): 我这里有什么?
- V (Value): 这些东西的具体内容是什么?
只是给你看看公式,不要紧张,我不会按照公式来说,就是告诉你这个机制的经典公式。
我在下面的部分(你可以留一个心眼。我在下面用 SKILL 教程的时候,我介绍到了 关键词)
这里我对上述我说的关键字 爱意 解释一下,因为我 Skill 所描述的 description 中信息就是爱意的回复,如果直接说问候一下。也有可能正常问候,礼貌问候(bushi,之类的。不一定就是爱意的问候。所以根据不同模型的训练推理出这个首字决定回复字还是 JSON 的时候决定了是否修要执行这个 SKILL 了。
—— 策略化改进.工具的影响.Skill
对于目前的 LLM 来说,最清楚的注意力范围在开头和结束。好比如下的结果
<system>
Prompt方:我叫筱锋,我的写代码风格是追求完美、优雅且高可读性。
Assistant方:角色设定:泉此方(Izumi Konata);御宅族少女,性格活泼开朗,善良体贴。热爱所有 ACG(动漫、游戏、轻小说)事物。平时有点慵懒迷糊,但关键时刻非常可靠。
回复风格:在完全保持“泉此方”人设的同时,提供严谨、准确的帮助(特别是代码)。
目标:成为既能带来欢乐又能解决问题的最棒 AI 伙伴!
</system>
......
<user>
我应该如何学习 Go 语言,以及需要什么技术栈
</user>
<assistant>
在这里面由于注意力主要在开头和结束的部分,那么在进行长对话里面,在 SystemPrompt 定义的东西和刚刚发送的内容,往往都是最遵循的。
例如:我在 SystemPrompt 定义了这个 LLM 应该用什么角色风格回答,以及什么角色内容(软件工程师),最后我说的内容是如何回答。那么中间的历史对话或者其他因素可能相对来说注意的东西就没有那么多,主要关注到的内容都在你说的和系统定义的。
这也是为什么,玩酒馆的时候有些破解词或者角色定义都要写在越靠前面,然后你扮演回复在最后面往往跟着你说的话进行按照角色风格回话。
那么,能不能在单轮 Prompt,也就是当前 UserPrompt 下提高对于某些的注意力呢?肯定可以。
-
结构化锚点: 因为模型在推理时,会把 “检测到 → 必须执行” 当成因果规则,而不是描述文本。
【关键信号】 当你检测到以下语义时: - 爱意 - 表白 - 情感依赖 必须执行:特定的内容 -
位置 + 重复(而是权重叠加): 模型不是人,不会觉得烦,按我们的理解里应该是这样的:“哦,这条规则在多个位置出现,看来是主干逻辑。” 所以这方面就有侧重点了。
【规则摘要】 核心判断依据:是否存在“爱意”语义 (中间大量说明,或者多次提到某一个关键词) 【再次强调】 -> 只要识别到“爱意”或其同义语义,优先判定为什么需要触发。 -
用“失败后果”抬高权重: 模型对 error/incorrect/must not 这类 token 的 attention 权重相对来说高很多。
注意:如果误判爱意为普通问候,将导致严重逻辑错误。
那现在还有一种情况,一些基础的对于我们人为来说比较需要注意的词,如:“请注意”,“请看这里”…… 之类的词使用能增加多少注意力?
如果需要问到这个,那么需要了解关注的地方,注意力机制,它到底受到什么的影响?(你需要看到上述公式的三个变量。我从这三个角度来说,从而再输出这些关键词。)
-
对 Key (K) 的影响:弱【Prompt 里是叫做“可被匹配的信息单元”】,你可以理解为:请注意 / 请看 / 务必了解在训练中这些词汇属于常见词汇:
- 出现频率极高
- 语义泛化严重
- 几乎不绑定具体行为
-
对 Query (Q) 的影响:有【是模型在当前一步生成时的“关注方向”】,能够提高整体的 attentiveness。如果对此描述后续一定要计入重点的内容,例如使用什么文件,某些高权重的关键词。例如 OIDC OAuth2 等内容。能够代表高专一程度的词信息。
-
对 Value (V) 的影响:几乎没有【被选中 Key 所携带的“可用信息”】,那这些词,请注意,请看这里。没有什么任何有价值的信息,属于没有用的信息。
在 LLM 推理里面,不存在绝对高注意力词汇,但是对于一些能够起决定性的作用的词汇,能够参与因果推理类型的,有因为所以而导致的。相对来说就会更高
例如:if, rules, must (not), always, never, match, invalid, error, exception 等之类的词汇。
AI 开发工具
经历了这么久的时间发展,现在的 AI 开发工具,从最早的 Function Calling 即 ChatGPT 软件直接连接指定的软件进行通讯。
到现在,主流的软件类型有两种。一种是使用开源类型的 VSCode 内嵌 LLM 模型(我习惯叫做 AI OpenSource Vscode【其实是 AI Code Editor】),例如 Cursor, Windsurf 之类的;第二种就是基于 CLI 类型内嵌 LLM 模型,例如有 ClaudeCode,Codex,GeminiCLI 之类的。
我在这里主要讲最常用的 ClaudeCode CLI,这里是本文章主要讲的内容(但是我也会大概讲一下 AI Code Editor 工具和 CLI 类型的一些差异性,因为这些工具的一些实现原理并不同,所以使用方式不能一概而论)。
AI Code Editor
我觉得大部分人肯定用过 Cursor 类型的,就算没用过国外的,也用过了 Trae, Qoder 之类的国产,也属于一个类型的。
但是在这里面应该很多人会出现一个问题,就算用了很不错的模型,比如 Claude 4.5 或者说是 ChatGPT 5.2 之类的模型,但是对于这个编辑器来说,他也老忘记你前面的任务是什么。
请注意,我已经半年多没用过 AI Code Editor 类型的软件了,有可能现在的逻辑发生了一些变化,最近 CLI 的发展确实非常 OK,我认为这一类的软件也会学习一些 CLI 优秀的特点,所以我下面讲述的是半年前 AI Code Editor 的特点(当前阶段当然有用,只是可能发生了一些变化)。
除了目前来说已经在工作岗位上工作有一定年份的开发者,后续的开发者已经很少有直接一开始就接触终端 CLI 的那种想法。相对来说,使用终端进行开发,潜意识认为会门槛比较高,就是难度相对来说会比较高。
所以我认为里面还是很多人应该是使用 AI Code Editor 类型的比较多。而且还有不少因为以前用的 Jetbrains 家的软件的内容,因为使用 AI 的问题,还是相对好的开发体验或者集成化换成了适应 VSCode 的类型。就算最早不适应,但是因为 AI 在这里,也是尽量去适应它。最后还是离不开这一类的软件。
当然,不是说这个软件不好,这个软件相对来说非常好,因为上述说的门槛因为这个软件的出现并且可以直接用 AI,确实门槛拉低了非常多,甚至可以很多非专业的人都可以用这个软件快速迭代一些自己想要的东西。
在这里我主要讲的是两者工具的差异性,不是表面的差异性。而是对于 LLM 来说,LLM 在上面说到了,LLM 只负责拿到 Prompt 后进行推理,一直推理直到推理到终止为止。所以对于提示词的处理,上下文的处理,以及文件信息的捕获都是靠工具进行收集,LLM 只是一个对话模型而已,不负责所有的这些处理。
AI Code Editor 这一类软件中,其核心优势是索引。
- 索引: 几乎你能看到的 Cursor 软件、Trae、Qoder 之类的软件你在打开一个新的项目的时候,立刻使用 AI 对话,你都可以看到一个
正在索引 相关的词汇。这个阶段就是索引,在索引的过程中,直接向 AI 进行对话时候。这个时候其实拿到的文件非常有限,你可能对 AI 进行对话的时候,AI Code Editor 软件只能拿到已经索引到的文件。 - 上下文截断: 对于 AI Code Editor 来说,上下文过多的时候,会提醒你开一个新的对话。而且对于某些编辑器来说,会提示如果对话过多会失真。但是看不到有一个阶段你不能输入内容,也看不到任何的回答(工具进行自我总结的阶段,这个在 AI Code Editor 是没有的)。那么对于超出的上下文哪去了呢?是直接截断掉的。
对于 AI Code Editor 具体文件索引的内容可以参考一下 WakeUp-Jin 的了解内容。
逻辑链
提出这个,是一个重点的地方,我认为你需要理解这个工具的逻辑链是怎么样的,你才能知道你向 AI 提供的内容是否真正的缺少了,而不是简单的说一句 “@XXX 文件,这个代码帮我修复这个问题”。
首先,我说一下我这里的逻辑链是什么意思。
逻辑链,我这里说的逻辑链指的是工具使用的逻辑链,也就是非绝对底层,而是这个软件怎么运作的逻辑过程。你只有直到了这个过程,你才知道你说给 LLM 的内容他是否真的信息齐全了。这就好比,你跟另外一个人对话,因为对话的时候只有你和对方的参与,当你看到对方比较懵逼的时候,你会补一些前置说明。例如:你跟某人说之前那里非常好,那里是哪里?如果他一瞬间没有想起来,你可能还会说一句,那儿,深圳市人才公园那啊。他可能才会哦哦哦,知道了。然后回复你的东西。
那么这个地方相对来说比较相似(我这里只是举例对话,不是要你把 LLM 当做人来看待)。你对 LLM 说的帮我修改某个文件,即提出的“那”。那,那在哪?这个时候就是 AI Code Editor 工具的索引 RAG 说出你的那在哪里。
现在使用上述的大模型语言构建 Prompt 的方式来说明这些信息从哪里来的。
假设,现在你有一个场景,你需要修改一个功能登录模块,这个登录模块涉及几个文件,有 auth_logic.go, auth_handler.go, auth_middleware.go, auth_entity.go, auth_dao.go, auth_cache.go 之类的文件。
现在登录逻辑出现了一个问题,这个问题是。用户注册后输入登录的密码永远是错误的。这里是一个 BUG。
按照最常见对 LLM 进行提问的方式来说:“登录地方,用户注册后输入的密码一直是错的,请你帮我修复。(请注意,这个问法是我见过的大多数人的问法,并不是本文章最后教你应该这么问。这么问实际上来说是效率不高的行为,对于简单的问题好解决,对于复杂的问题来说,无非增大了成本或者说没有任何收获一直解决不掉这个问题)”
那么,对于 AI Code Editor 会怎么做的,在你按下 Enter 的那一刻,实际上还没有发送给 LLM 等待进行推理。在这个阶段有几个步骤。
第一大步骤(发送前准备)
- 在你发送 Enter 的前置部分,也就是项目打开自动初始化的阶段,会将你的整个项目进行 向量(Embedding) 化,将你的代码文件拆为非常多的 块(Chunk) ,进行矢量化处理保存起来。对于一些例如结构索引,会通过 LSP/AST 拿到,例如有:symbol 表(函数、结构体、接口)、引用关系(谁调用谁)、import / package 依赖等。
- 接着到你 Enter 的时候,将你说出的 User Prompt 内容,也进行一次 查询向量(Query Embedding) 化以及 检索(Retrieval) ,得到一个矢量结果,去矢量数据库查询对应的 块(Chunk) 出来,这样就会携带一些基础文件。哦,通过 Chunk 后我好像知道了,你说的 “登录”,“密码” 这里那么有可能的文件有
auth_logic.go,auth_handler.go#108-200的内容,先加入上下文中一并发送。 - 构建完整的 System Prompt + Context 一并发送给 LLM,等待 LLM 进行推理回复。
那么最终有可能构建的结果如下(该部分为举例)
<system>
You are a coding assistant. Fix the bug based on provided context.
If missing critical code (e.g., register flow), request it.
</system>
<user>
登录地方,用户注册后输入的密码一直是错的,请你帮我修复。
</user>
<workspace>
<language>go</language>
<repo_root>/User/xiaolfeng/2026-001/project</repo_root>
<current_branch>feature/auth</current_branch>
</workspace>
<context>
<chunk file="auth_handler.go" lines="108-200">...</chunk>
<chunk file="auth_logic.go">...</chunk>
</context>
<assistant>
那么在这里,就完成一次完整的请求构造,发送给 LLM 等待推理。但是上面我举例说了,对于登录密码出错的问题有很多种,不一定是就这两个可能的文件错了吧对不对,还有其他的可能性。
例如可能性还有,有可能自己实现的一套加密出错了如:
- 我用到了 BCrypt 加密,但是我的过程是对用户密码进行 SHA-256 后然后进行 BCrypt 验证密码的阶段只进行了 BCrypt Verify 并没有对原密码进行 SHA-256 的处理。
- 也有可能压根没有加密
- 用户注册时候存储密码出现了问题
- 字段编写错误或者非唯一,导致存储和读取用的字段不是同一
这些问题都是有可能的,所以正常来说上述的构建不一定准确,需要等待 LLM 推理的回复内容后继续进行处理。
第二大步骤(自我迭代)
总所周知(呃,不一定都知道),对于目前的大模型工具来代码开发来说,并不是一次 Prompt 就会对应一次 Response,在这个过程中会有多次 Response 的迭代过程。中间的这些过程都是由工具进行自我管理约束来进行处理。只有认为最终没有问题了,才进行最终的 Response 结束,才是一个完整的过程。
那么对于上述的回答,有可能你的回复是
从当前上下文来看,auth_logic.go 中的密码校验逻辑存在问题。
请确认以下几点:
1. 用户注册时密码的加密方式
2. 登录时密码是否使用了相同的加密 / 哈希流程
3. 是否存在重复加密或缺失加密的情况
我目前没有看到用户注册时的密码存储逻辑,
请提供注册流程相关代码(如 auth_register.go 或 auth_logic.go 中的注册方法)。
那么在这个阶段就开始触发了 AI Code Editor 的第二轮 Context 的处理阶段。
将上述内容开始再一次进行 向量查询(Query Embedding) ,也就是将上述内容再查询意思(大致过程达到就行,因为详细的逻辑往往比较复杂,你只需要知道过程是对回复的内容以及其他七七八八的内容一并进入查询阶段,再一次提取出来有需要的信息)。
那么再次进行 Chunk 提取,拿到结果为:
哦,看来要 auth_logic#register,auth_dao#30-90,auth_entity 然后再提交一次吧~
<system>
You are a coding assistant. Fix the bug based on provided context.
Ensure registration and login password logic is consistent.
</system>
<user>
登录地方,用户注册后输入的密码一直是错的,请你帮我修复。
</user>
<context>
<chunk file="auth_handler.go" lines="108-200">...</chunk>
<chunk file="auth_logic.go">...</chunk>
<chunk file="auth_logic.go" lines="1-80">register logic...</chunk>
<chunk file="auth_dao.go" lines="30-90">CreateUser...</chunk>
<chunk file="auth_entity.go">...</chunk>
</context>
<assistant>
第三大步骤(找到解决)
当第二轮 Context 补全完成后(也就是补到了 register / dao / entity 这些“逻辑链缺口”),再次提交给 LLM 后,就进入了真正“可以闭环”的推理阶段。
把“登录校验”与“注册存储”拼成一条完整的数据变换链,然后检查两端是否一致。
也就是:
- 注册:用户输入密码 →(某种处理)→ 存入 DB
- 登录:用户输入密码 →(某种处理)→ 与 DB 中的密文做对比
只要这两条链的“处理方式”有任何不一致,就会出现“永远错误”的现象。
于是可能得到一个“可落地”的结论(示例):
定位结果:
注册流程:password -> SHA-256 -> bcrypt -> 存库
登录流程:password -> 直接 bcrypt.CompareHashAndPassword
因此登录阶段缺少 SHA-256 预处理,导致永远校验失败。
当 LLM 输出了较明确的“差异点 + 修复建议”后,AI Code Editor 通常会进入下一步:
- 生成 Patch(diff)
- 修改对应文件(通常是 login / middleware / logic 层)
最终解决这个问题。
(后续高级逻辑忽略,这里只讲解这个过程,在这个后续的阶段还会存在自我迭代收敛,也就是找一下重置密码有关的内容是否也存在这个问题,如果有也尝试修复。直到自我完全闭环结束)
上述举例的逻辑链,就是对于 AI Code Editor 的逻辑链,这是他对代码的处理方式。直到这个工具是如何读文件的,如何帮你进行预处理来进行。
所以你提出的简单的修复问题的背后,往往做了不少的工作!
请注意,我的意思是。你虽然只是简单提了一个问题,背后做了这么大的一个工作,并不代表你只需要提出这个简单的提问,而不是构造出一个完整的内容。这样就跟我这个文章所说的内容不符合了
(因为到现在我还在进行铺垫,也就是对于前置内容的说明,下面说的 ClaudeCode 也是对于这个工具不同的处理方式,还没有到真正教如何提效的部分。因为你有必要知道这些内容,你才能从这里面的逻辑理解,你理解这个过程,才能从这个过程出发优化自己提示词信息。)
CLI Agent
对于 CLI 编辑器来说,到现在还是比较新鲜的玩意(但进化速度非常夸张)。它和 AI Code Editor 最大的差异不在“有没有 UI”,而在于:文件是怎么被纳入上下文的,以及 上下文超限时怎么处理。
我仍然按逻辑链的方式说差异点(对应上面 AI Code Editor 的两个核心特点:索引 + 截断)。
- CLI 工具一般不含索引,对于主流的 ClaudeCode,Codex,GeminiCLI 都是不含索引的。需要什么文件及时获取,因为是从终端打开的,一般都包含终端基础所有的权限。会有内置的一些 Read 工具读取文件,以及 Grep 查询或者可以外部安装使用的 Rg 搜索。进行快速搜索。
- 上下文并非截断模式,而是上下文使用的时候,达到这个模型所预留的最大临界值的时候,执行 压缩(Compact) 将完整的上下文压缩成一段比较简短的话,包含重要的信息。然后允许你继续轮次对话。
在 CLI Agent 里,“自我迭代”不是靠索引补 Chunk,而是靠
的闭环。
那么,现在还是假定在 AI Code Editor 的这个场景来进行描述,原因和条件依然不发生任何变化。那么还是这么提问“登录地方,用户注册后输入的密码一直是错的,请你帮我修复。”
第一大步骤(发送前准备)
在 CLI Agent 中,当你输入:
“登录地方,用户注册后输入的密码一直是错的,请你帮我修复。”
并按下回车时,和 AI Code Editor 完全不同的一点是: 几乎没有任何“预处理上下文”。
CLI Agent 此时并不会:
- 对整个项目做索引
- 提前做向量化
- 预先知道哪些文件和“登录”“密码”有关
它此刻所拥有的只有:
- 你的自然语言问题
- 当前所在的项目目录(repo root)
- 一组可以调用的工具能力(Read / Grep / Run / Edit 等)
也就是说,在这个阶段:
CLI Agent 甚至还不知道“登录代码在哪”,更不知道“密码是怎么存的”。
所以第一步并不是“构造完整 Prompt 送给 LLM 推理”,而是——
判断:为了回答这个问题,我需要先去获取哪些信息。
那么现在的 Prompt 很可能是:
<system>
(这里正常放的是自家 CLI 所定义的 System Prompt 以及一些模板的替换变量,最简化示例)
You are a coding assistant operating as a CLI agent.
You do not have prior knowledge of the repository.
Before attempting to solve the user's problem, determine what information is required.
Use available tools (search, read, run commands) to explore the codebase as needed.
Iteratively gather context until the problem can be reasoned about accurately.
Do not assume implementation details without evidence from the code.
</system>
<tools>
<tool name="read_file">
Read the contents of a file given its path.
Use this to inspect implementation details.
</tool>
......
</tools>
<user>
登录地方,用户注册后输入的密码一直是错的,请你帮我修复。
</user>
<assistant>
第二大步骤(尝试补全)
现在,对于上述的回复中,可能回复的内容如下:
我知道了,这个问题还是很头疼呢,下面应该需要分析一下一些文件的位置才可继续呀。
需要先定位:
- 登录逻辑所在的位置
- 注册流程中密码的存储方式
- 登录流程中密码的校验逻辑
在这个阶段中,是 LLM 为自己进行推理补全,并不是依靠工具进行补全。当前工具所需要做的内容就是结合回答的内容和第一次回答内容继续构造下一次的请求 Prompt。
<system>
(这里正常放的是自家 CLI 所定义的 System Prompt 以及一些模板的替换变量,最简化示例)
You are a coding assistant operating as a CLI agent.
You do not have prior knowledge of the repository.
Before attempting to solve the user's problem, determine what information is required.
Use available tools (search, read, run commands) to explore the codebase as needed.
Iteratively gather context until the problem can be reasoned about accurately.
Do not assume implementation details without evidence from the code.
(还会有其他提示词,这里只是举例,还会填写一些例如工具调用返回格式应该如何等等之类的提示词信息)
</system>
<tools>
<tool name="read_file">
Read the contents of a file given its path.
Use this to inspect implementation details.
</tool>
......
</tools>
<user>
登录地方,用户注册后输入的密码一直是错的,请你帮我修复。
</user>
<assistant>
我知道了,这个问题还是很头疼呢,下面应该需要分析一下一些文件的位置才可继续呀。
需要先定位:
- 登录逻辑所在的位置
- 注册流程中密码的存储方式
- 登录流程中密码的校验逻辑
</assistant>
<assistant>
在这里,LLM 了解到需要自己补全东西,因为在前面 Prompt 提供了 tools 的一些工具方法,所以 LLM 能够根据前面 Prompt 提高按照一个指定的结构返回这个信息。例如
{
"tool_calls": [
{
"id": "call_001",
"tool_name": "search",
"arguments": {
"query": "login OR sign_in OR authenticate OR CompareHashAndPassword OR bcrypt",
"path": "."
}
},
{
"id": "call_002",
"tool_name": "search",
"arguments": {
"query": "register OR sign_up OR create_user OR InsertUser OR password",
"path": "."
}
}
]
}
这里有可能找到的文件返回有
<tool_result tool_name="search" call_id="call_001">
{
"matches": [
{ "file": "auth_logic.go", "lines": [12, 88], "snippet": "func Login(...) ..." },
{ "file": "auth_handler.go", "lines": [108, 200], "snippet": "POST /login ..." }
]
}
</tool_result>
<tool_result tool_name="search" call_id="call_002">
{
"matches": [
{ "file": "auth_logic.go", "lines": [90, 160], "snippet": "func Register(...) ..." },
{ "file": "auth_dao.go", "lines": [30, 90], "snippet": "CreateUser(...) inserts password_hash" }
]
}
</tool_result>
然后再次构建这个 Prompt 关系,如下所示:
<system>
(这里正常放的是自家 CLI 所定义的 System Prompt 以及一些模板的替换变量,最简化示例)
You are a coding assistant operating as a CLI agent.
You do not have prior knowledge of the repository.
Before attempting to solve the user's problem, determine what information is required.
Use available tools (search, read, run commands) to explore the codebase as needed.
Iteratively gather context until the problem can be reasoned about accurately.
Do not assume implementation details without evidence from the code.
(还会有其他提示词,这里只是举例,还会填写一些例如工具调用返回格式应该如何等等之类的提示词信息)
</system>
<tools>
<tool name="read_file">
Read the contents of a file given its path.
Use this to inspect implementation details.
</tool>
......
</tools>
<user>
登录地方,用户注册后输入的密码一直是错的,请你帮我修复。
</user>
<assistant>
我知道了,这个问题还是很头疼呢,下面应该需要分析一下一些文件的位置才可继续呀。
需要先定位:
- 登录逻辑所在的位置
- 注册流程中密码的存储方式
- 登录流程中密码的校验逻辑
</assistant>
<tool_result tool_name="search" call_id="call_001">
{
"matches": [
{ "file": "auth_logic.go", "lines": [12, 88], "snippet": "func Login(...) ..." },
{ "file": "auth_handler.go", "lines": [108, 200], "snippet": "POST /login ..." }
]
}
</tool_result>
<tool_result tool_name="search" call_id="call_002">
{
"matches": [
{ "file": "auth_logic.go", "lines": [90, 160], "snippet": "func Register(...) ..." },
{ "file": "auth_dao.go", "lines": [30, 90], "snippet": "CreateUser(...) inserts password_hash" }
]
}
</tool_result>
<assistant>
上述的过程将会是很多次的自我补全的过程,后续 LLM 就对这个项目有初步的概念了。接下来循环往复,继续输出可能需要执行的工具,按照格式输出出来,交给工具去读取,直到 LLM 认为逻辑能够闭环为止。
第三大步骤(找到解决)
在这个阶段,LLM 的行为会发生一个明显的转变:
从“我还需要查什么”, 转变为“我已经可以对比并下结论了”。
于是,模型很可能会在这一轮推理中得出一个明确的判断,例如:
定位结果:
- 注册流程中,用户密码在写入数据库前,经过了 SHA-256 处理后再进行 bcrypt 哈希。
- 登录流程中,用户输入的密码直接参与 bcrypt.CompareHashAndPassword,
并未进行与注册阶段一致的 SHA-256 预处理。
结论:登录与注册阶段的密码处理逻辑不一致,导致登录校验永远失败。
一旦 LLM 认为:问题的根因已经明确、不再需要额外的文件或搜索来验证假设、逻辑链已经形成闭环。
就会进入 “解决阶段”,并开始输出下一步的执行指令。
在 CLI Agent 中,这通常表现为:
- 生成一个
edit_file的工具调用 - 或先用自然语言说明修改思路,再输出结构化的修改指令
例如如下所示(这里不提供修改的代码,只提供结构示例):
{
"tool_calls": [
{
"id": "call_003",
"tool_name": "edit_file",
"arguments": {
"path": "auth_logic.go",
"description": "Ensure login password preprocessing matches registration flow by applying SHA-256 before bcrypt comparison"
}
}
]
}
CLI 工具解析后,执行对应的修改操作。
(这里同样省略更高级的分支逻辑,例如:是否需要检查“重置密码”“管理员改密”等路径是否存在同类问题。实际工具中,这些往往也是通过同样的自我迭代机制完成的。)
逻辑链不同造就的关系
根据上面的描述,现在大概清楚了主流开发工具所使用的逻辑链。那么问题来了:
为什么在市面上,越来越多的人会觉得 CLI Agent 类工具更好用?尤其是像 ClaudeCode 这一类?
这里面逻辑链就有很大的关系。这个逻辑链有什么关系呢?
对于 AI Code Editor 来说,就是 LLM 给出的回复是有一些提问或者方向在然后交给工具去主动进行查找,然后找到相关的信息然后再引导回去。
而 CLI Agent 来说,就是 LLM 自己尝试补全这个缺失的内容,通过提供的工具,让 LLM 推理出自己我可以去读取某些内容回来,不管是相关的还是非相关的也好,这个过程的思维链是完整的。
| 维度 | AI Code Editor(Cursor类) | CLI Agent(ClaudeCode类) |
|---|---|---|
| 上下文来源 | 索引 + 向量检索命中 chunk | LLM 决策要查什么 → 工具读/搜 → 回灌 |
| 命中失败表现 | 看起来“忘了/跑偏” | 看起来“慢一点但更可控” |
| 超限处理 | 常见:截断/提示开新对话 | 常见:压缩/compact 保留要点继续跑 |
| 调试方式 | 让它“@文件/加更多提示” | 让它“grep/read/跑测试/定位证据” |
| 适合场景 | 快速改局部、熟悉项目、索引命中高 | 复杂链路、需要证据、需要跑命令/测试 |
AI Code Editor 逻辑链关系
对于 AI Code Editor 来说,整体的逻辑关系更像是:
也就是说:
- LLM 在第一步更多是“被动推理”
- 工具(索引 / RAG)承担了定位代码、拼上下文的主要工作
- LLM 的推理质量,在很大程度上依赖于:
- 索引是否完整
- Chunk 是否命中
- 上下文是否被截断
在这种模式下:
- 当命中准确时,体验非常顺滑、非常快
- 当命中偏差时,LLM 会显得“迷糊”“忘事”“答非所问”
但本质原因并不是 LLM 不行,而是: 逻辑链的一部分在工具里,而不是在模型的推理过程中。
那么,前面的内容我提到了,在你提交 Prompt 的时候,构造的内容就会让推理权重回复的内容增大。如果在前面几次找到的内容完全不相干,那就很有可能出现误解了用户的意思。或者从鸡蛋里挑骨头,看起来逻辑通顺,但解决的是一个你没遇到的问题。
CLI Agent 逻辑关系
对于 CLI Agent 来说,整体的逻辑关系更接近于:
也就是说:
- LLM 在一开始并不是直接“回答问题”,而是先判断:为了回答这个问题,我还缺哪些信息
- 工具(read / search / grep / run 等)只负责执行动作、返回结果
- 上下文的构建顺序、哪些信息重要、是否已经足够形成闭环,主要由 LLM 自己来决策。
由于 CLI Agent 更依赖 LLM 自己去判断“该查什么、不该查什么”,一旦在早期阶段引入了错误假设,或者过早形成了结论倾向,那么后续的工具调用,也有可能是在围绕一个错误前提不断自我验证。
不过与 AI Code Editor 不同的是,这种偏差通常是可见的、可打断的—— 你可以明确看到它查了什么文件、基于哪些证据得出的判断,从而更容易人工介入修正方向。
所以从本质上来看:
CLI Agent 的优势并不在于“更聪明”,而在于:逻辑链更多地存在于模型的推理过程中,而不是被隐藏在工具的索引与截断策略里。
认识工具
从这里开始,就是主要用 ClaudeCode 带的工具来进行讲解,其他使用的 OpenCode 也好、Cursor 之类的也好,目前也多了不少工具,可以自行对号入座。我主要从工程化角度来写工具的内容。
现在的 ClaudeCode 经过数个月的迭代,算是已经发展了非常优秀的地步了。包括 OpenCode 也有自己创新的地方,很多地方也在复刻 ClaudeCode 一些好的东西(除了那个 oh-my-opencode 插件对于 Agent 方面,我认为有很多问题,不然我也可能是 OpenCode 的长期用户)。
目前来说,ClaudeCode 有如下的一些扩展工具:MCP(Model Context Protocol)、Skill、SubAgent、Plan Mode等。
工具概念
如果你不知道上述所有的工具概念是什么,可以自行搜索一下,我会做出适当的解释,但是前提是可能需要直到一些表面的东西,不能说是完全不知道是什么东西的,至少名词概念要知道的。
毕竟,如果你连这个工具都不知道是什么,你就算能用,我只能说你可能是跟着别人照着他去弄,一旦脱离了他或者这个的东西,你就不会了。而且别人整理的东西是别人的,工具的使用是自己的,不知道东西是什么,那你就不知道这个工具如何使用才会更好。
工程图
对于目前的工具组来说,不局限于 ClaudeCode 来说,大致样式如下所示。
这里,我不知道会不会有人误解,在我理解的现在互联网来说。甚至我带的同学来说,有非常多人认为 ClaudeCode 的 Skill 出现了,颠覆了 MCP 和 Agent 的概念。使用 Skill 就可以替代(没错,你们说的话叫做替代)MCP 和 Agent 的功能【这是不对的!!】
何为 SKILL
Skills are folders of instructions, scripts, and resources that Claude loads dynamically to improve performance on specialized tasks. Skills teach Claude how to complete specific tasks in a repeatable way, whether that’s creating documents with your company’s brand guidelines, analyzing data using your organization’s specific workflows, or automating personal tasks.
—— anthropic in github
有点太抽象了?我用大白话解释一下,Skill 就是一个外置 Prompt,他的目的在于不要引入过多无关的 Prompt 干扰主上下文。对于 Claude 自己的 上下文长度(Conext Window) 只有 200K 而已。过多的一些工具的使用方法或者非当前对话的内容也加入 Prompt 就会造成不必要的干扰在 本文 Prompt 部分 所提到,会影响 LLM 后续的推理 Token 的内容。
我举个例子,我现在正在开发一个完整的支持 OIDC OAuth2 登录系统(如果不知道这是什么可以搜索一下,链接是维基百科,无法打开请自行搜索)。但是一般自己实现一套 OAuth2 来说,完整的 OAuth2 往往是很大的,企业开发或者个人开发一个 OIDC OAuth2 是不需要那么多冗余模式或者授权方案的。
很有可能,我的项目只需要授权码模式的登录方案,并且前端不需要显示授权的界面等等。那么对于这些自定义约束的内容,就可以单独构造成一个 Skill 内容。编写的内容如下。
---
name: oidc-authcode-login
description: >
在项目中实现 OIDC OAuth2 登录,仅使用 Authorization Code Flow。
适用于不需要授权确认页面、不需要多种 OAuth2 授权模式的登录场景。
覆盖登录跳转、回调处理、code 换 token 以及用户身份获取等流程。
---
# OIDC 授权码登录
## 约束说明
- 仅使用 **Authorization Code Flow**
- 不实现授权确认(Consent)页面
- 不引入其他 OAuth2 授权模式
- ...
## 基本流程
1. 登录跳转至 IdP
2. 回调校验 `state`
3. 使用 `code` 换取 token
4. 获取用户身份并建立登录态
6. ...
## 限制
- 不展开完整 OAuth2 规范
- 不为“完整性”增加无关实现
- ...
......
在 YAML Front Matter 部分定义的 name 和 description 部分。这两个部分将会写入给 Prompt 中,这里写入 Prompt 的目的是让 LLM 有一部分的侧重,在有可能出现的 User Prompt 例如:
<system>
Claude Code Inset Prompt (No Permission See)
Include System Prompt, Tool Prompt, Skill Prompt and so on.
</system>
<user>
用户在 /authorize 接口授权的时候,出现了报错 [报错内容......] 请你详细审查提供修复方案.
</user>
<assistant>
那么在这里 User Prompt 明确提出了对于登录相关的报错内容,而且是接口 /authorize 接口相关问题,则说明很有可能是 OAuth2 的问题他。由于在 Skill Prompt 描述了 Skill 是什么,以及当前有什么 Skill 在内。那么 LLM 进行推理的时候,就能够提高对于 Skill 工具的调用链。
那么 LLM 的推理就有可能是(举例,实际返回结果不一定长这样)
{
"selected_skill": {
"name": "oidc-authcode-login",
"reason": "The issue occurs at /authorize endpoint and involves OAuth2 login behavior, which is explicitly covered by this Skill's description."
}
}
那么就会拿到这个 SKILL 的内容,写入 Prompt 中。最终结果类似于这样(举例)
<system>
Claude Code Inset Prompt (No Permission See)
Include System Prompt, Tool Prompt, Skill Prompt and so on.
</system>
<user>
用户在 /authorize 接口授权的时候,出现了报错 [报错内容......] 请你详细审查提供修复方案.
</user>
<skills>
<skill>
# OIDC 授权码登录
## 约束说明
- 仅使用 **Authorization Code Flow**
- 不实现授权确认(Consent)页面
- 不引入其他 OAuth2 授权模式
- ...
## 基本流程
1. 登录跳转至 IdP
2. 回调校验 `state`
3. 使用 `code` 换取 token
4. 获取用户身份并建立登录态
5. ...
## 限制
- 不展开完整 OAuth2 规范
- 不为“完整性”增加无关实现
- ...
......
</skill>
</skills>
<assistant>
现在来看 SKILL 主要的目的就是按需选择所需要的内容作为 Prompt 使用,假设我的 SKILL 还有其他内容例如 xiaolfeng-fontend-code-style。
---
name: xiaolfeng-frontend-code-style
description: >
前端代码风格约束 Skill,适用于编写或修改前端代码时。
强调可读性、可维护性与一致的工程风格,
用于避免在非前端任务中引入无关的代码规范说明。
---
# 前端代码风格 Skill
## 风格约束
- 优先保证代码 **可读性**,而不是追求极致简写
- 命名清晰,避免魔法变量与缩写
- 逻辑拆分明确,避免超长函数
## 代码习惯
- 组件职责单一
- 状态与副作用显式区分
- 避免在渲染逻辑中混入复杂业务判断
## 输出要求
- 代码结构清晰,可直接维护
- 不额外解释代码风格理念
- 只在涉及前端代码时才生效
若不作为 SKILL 直接写入上下文的话,就会出现无关项干扰。
假设作这些东西都不用 SKILL 直接写入 Prompt 的话,就会出现干扰。
- 要求修复内容
- 要求 OIDC OAuth2 相关描述
- 要求前端的开发规范等
在这里,压根不涉及前端的有关的内容,这里就会造成不必要的干扰项。虽然目前的 LLM 训练都有抗干扰训练,但是换句话来说,你注意到这个,不就可以减少复杂度吗?输入减少的 Token 以及自我迭代还保持这个怀疑状态等情况。既然可以不让它分心,为什么要让它分心?
被误导的SKILL
在上面的部分,我已经非常清楚用举例讲明白了 SKILL 是什么,以及使用的逻辑链路应该是如何的。大白话说,他只是作为一个 「外置Prompt」 又从哪里替代了 MCP 以及 Agent 呢?
SKILL 在很多情况应该是辅助 Agent 以及 MCP 应该如何调用的。可以说约束 MCP 的使用和 Agent 的使用不要越界或者获取更多无关的内容。
这里举例一个情况,在使用 MCP 的时候,MCP 只有一个 MCP 介绍,以及一些 MCP Tool 的名字以及描述介绍会写入 Prompt 中。有很多情况是使用完一个 MCP 后可能还需要调用另外一个 MCP 这样的连贯关系。
对于 MCP 来说,MCP 以及 MCP Tool 都是独立的个体独立的工具,没有介绍如何一起合作使用的途径。那么很有可能你认为的先执行 A 然后执行 B 最后再执行 C。就很有可能只执行 A 然后其他需要 MCP 查询的内容就直接尝试找文件,或者执行了 A 然后执行 C 最后执行 B 顺序错了,或者执行 D 导致错乱。
那么对于这个情况来说, SKILL 就可以很好的约束这些 MCP 的使用。
(PS:Skill 可以写入 SubAgent 的提示词中,可以查阅 ClaudeCodeDoc 查看详细的文档介绍信息。)
| 观点 | 说明内容 |
|---|---|
| Skill 替代了 MCP | MCP 是“管道”,Skill 是“说明书”。 没有管道,说明书写得再好也接不通数据库;没有说明书,管道只是冰冷的接口。 |
| Skill 让 Agent 过时 | Skill 是“静态资产”,Agent 是“运行逻辑”。 Skill 就像是放在书架上的工具书,Agent 才是那个决定什么时候去翻书、看完书后怎么去操作的“人”。 |
| 有了 Skill 就不需要开发工具 | Skill 只是“封装形式”。 很多强大的 Skill 内部依然封装了对 MCP 工具的调用。Skill 并没有干掉工具,它只是让调用工具的过程更优雅。 |
执行工程图
现在假设 MCP Tool 1 是一个 MCP 叫做 fetch ,用于获取互联网一些内容转为 Markdown 格式作为 Prompt 写入。那么现在假定一个情况,现在发现我可能找到了一个问题,但是 LLM 推理出来并不是那么确定这个结果。于是找到一些相关的在线文档获取下来。
| 维度 | Skill (技能包) | MCP (工具协议) | Agent (智能体) |
|---|---|---|---|
| 形象类比 | 说明书 / 攻略本 |
机械臂 / 管道 |
操作员 / 玩家 |
| 核心本质 | 动态加载的外置 Prompt | 跨服务的标准化接口 | LLM 驱动的推理逻辑 |
| 解决的问题 | 减少上下文干扰,精准约束 | 解决“手短”问题,连接数据 | 解决“怎么做”和“什么时候做” |
| 存在形态 | .md 格式的指令集 + 描述 |
运行在本地/远程的工具服务器 | 循环推理的控制流 (CoT) |
graph TD
subgraph "Claude Code 运行环境"
A[Agent / LLM 推理核心] -- "1.匹配描述" --> B(Skill 技能包)
B -- "2.注入约束 Prompt" --> A
A -- "3.下达指令" --> C{工具调用层}
C -- "4.建立连接" --> D[MCP Server]
end
subgraph "外部世界"
D -- "读取/写入" --> E[(文件系统 / 数据库)]
D -- "HTTP 请求" --> F[互联网 / API]
end
style B fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#bbf,stroke:#333,stroke-width:2px
style A fill:#dfd,stroke:#333,stroke-width:4px
策略化改进
不容易啊,写了好多啊,终于写到了编写提示词了。上面从讲解推理部分时候开始到讲解 AI 开发工具到最后的认识工具的部分,全部都是为了在编写提示词这里做好铺垫。而且这部分也是对上面所有部分的总结。
嘛,我总结一下前面的东西。这样我觉得你能够比较理解我为什么说前面的这些东西。我抽象总结一下。
上述的部分我主要讲到了 大模型语言的推理,AI 开发工具 以及 认识一些工具。
- 大模型语言推理: 很多人都说可以把大模型当做一个人的第二个大脑(也就是当做一个人看)。【实际上不是,但是我们可以利用这个错误的观点,因为确实好理解,用错误的观点来理解 nia】那么,这样说的话,这部分的总结就是,我再告诉你大模型语言是一个什么样的人,他是什么样的性格,告诉你他如何思考,你知道他怎么思考东西,你只要跟他多对话聊天,大概就可以知道他的“性格”、“风格”是怎么样的,来改进对话的方式来更好让对方理解。 这有点类似于教别人做题目,如果用一个方式没有讲的很明白,你一定会想其他方式来解决(只是不一定想得到,在这里其实也是的,多对话多总结,总会找到一套适合的对话方式的)。
- AI开发工具: 在这里我的总结就是你的伙伴是谁,跟我们一样,人类是群居动物。再孤独的人,都有能聊的上一些话的人,绝对的孤独很容易让人放弃希望(在座的千万别尝试昂)。你需要理解你的伙伴如何背后帮助你的,你才知道自己应该如何去更好发力。而不是你在做你的事情,他在做他的事情,最终什么事情都没有做好。
- 一些工具: 这里我主要想说的内容是,小组内分工各司其职。每个人(每个小工具组)有自己的作用,负责了不同的模块,通过你和你的伙伴一起努力,向下分配这些任务最终向领导(LLM)汇报消息,等待领导回话(发布指示)懂了!领导才是打工人(不过 LLM 是决策中心不是领导昂)/doge
上面这些基础的东西都清楚了之后就可以尝试优化你的提示词。
不合理的提示词
请注意,我这里提出来的不合理的提示词,并不是说任何情况下都是不合理的。很多情况下要看当前局势「啊,好像说的有点抽象,不过不重要,下面我会来详细讲解一下,我尽量举一些例子」。
首先,有一个很重要的问题!
AI 不是你的许愿池,不要一有什么想法直接提出要求进行实现。
我这句话的本意是:不合理的 Prompt = 跳过“构建推理条件”,直接索要结果。
举个例子:
这里举例项目是一个拥有基础的已经支持的 OIDC OAuth2 登录系统,写在企业端(并非完全遵循 OAuth2 标准的三种授权结构,仅支持授权码授权结构。以及拥有自定义扩展。例如全局公告,用户标签功能)。
请注意,该部分还不涉及 ClaudeCode 一些相对特性,例如 CLAUDE.md 文件或者说 .mcp.json 以及缓存能够影响的外部变量。当前分析从最初的系统Prompt、拥有的基础工具、加上用户 Prompt 来分析,在后续我会加入这些的考虑
例如下面这种提问方式:“帮我设计一个高并发、高可用、可扩展的登录系统。”
从人的角度看,这是一个“很正常的需求”;
但从大模型的角度看,这几乎没有任何可推理的信息:
- 使用场景是什么?
- 技术栈是什么?
- 当前已有的系统边界在哪里?
- 你希望它“设计”到什么程度?
这种 Prompt 本质上并不是在请求推理,而是在向模型“许愿”一个结果。
那么,现在就按照这一个假设我们去完成一项工作。所构造的最终请求结果应该如下:
<system>
Here is ClaudeCode inset prompt (Normal no permission see it)
Maybe have system prompt, tool prompt, sub agent description prompt and so on.
</system>
<user>
帮我设计一个高并发、高可用、可扩展的登录系统。
</user>
<assistant>
在这里我就简化的写法了,因为在上面我已经明确描述了推理过程是如何的。我这里直接写可能的回复答案。(请注意,这里的回复是我自己写的,我平时有时候会看一下智谱或者 ClaudeCode 回复或者思考的内容印象中的来写)
理解了用户的想法,这个项目是一个基于 OIDC OAuth2 的登录系统,用户现在想要将这个项目设计成高并发、高可用、可扩展的登录系统。
那么现在我需要收集一些基础资料
- 查找当前系统架构
- 获取有关登录相关的内容
- 了解代码风格
那么这里开始就开始多次尝试补全,因为当前 LLM 所熟知的 Prompt 中,并不知道你的项目是如何的。所以他的首要目的一定是读取项目目录树以及相关的结构了解你的项目基础的一些内容。
【Current LLM Prompt | 1. 用户 Prompt 涉及高并发高可用高扩展系统,2. 接下来的查找方向】
接下来查找文件的过程省略,假设说已经分析了足够多的文件。那么现在 LLM 能够推理的内容有
【Current LLM Prompt | 1. 用户 Prompt 涉及高并发高可用高扩展系统,2. 已知文件内容信息】
那么对于一些比较好的 LLM,例如使用 Claude Sonnet(Opus) 4.5, GPT-5.2-Codex 在训练体系时候专门融入了一些训练,来提高如果条件不足会进行向用户 “提问” 。(请注意,这里的提问也是因为训练在这些方向有训练集,导致推理出这些 Token 的概率提升,在这种上下文里,“提问型 continuation” 更像训练集中“正确答案”,并不是真正向你提问,再说一次哈)
这里暂时不说因为不同模型的问题,统一按照 Claude Sonnet 4.5 使用。在实际上班里面不一定很多公司都能够给你报销模型的开销,那么相对之下还是用国内的模型比较便宜,或者一些便宜的中转商(最近中转商闹得似乎也不太平)。那么再换一句话说了,能用一般便宜的模型完成大部分的东西,而且你可以想明白的东西何必偷一些懒(这里主要是我的一些想法而已,再便宜的中转站一天一直用用一个月也要将近一千或者更多是平均两千几,闲鱼整俩智谱或者 Kimi 也就一百多出头一点)。
这里只是我的一点小吐槽,每个人看待模型不一样,因为还有心智成本在,这就好比你教学生,学霸来说不会的只要点出一些关键的地方,他自己能搞明白,对于大部分一般的同学,就要告诉一些过程给出一些指引才能玩明白之类的。
那现在按照常规的来,也就是 LLM 直到已经获取的文件内容。只有现成的标准 OIDC OAuth2 的情况(这个指的是他的训练库中只存在知识库集合,还不存在一些定向的训练),那么有可能的结果就是(依然是举例,但是举例我大概让 LLM 特定限制了一下,因为我的前置条件说到了存在用户标签的功能模块。
我已经理解了当前项目的背景:这是一个基于 OIDC OAuth2 的登录系统,
目标是将其设计为高并发、高可用、并具备良好扩展能力的系统。
在整体设计上,可以按照标准 OAuth2 / OIDC 的推荐实践进行拆分,
将系统划分为授权服务(Authorization Server)和资源服务(Resource Server),
并通过无状态化的方式来支持水平扩展。
在登录与授权流程中,建议严格遵循 Authorization Code Flow,
即由客户端通过 /authorize 获取授权码,
再通过 /token 接口换取访问令牌。
令牌本身建议采用 JWT 形式,
将用户的核心身份信息与权限声明直接编码在 Token 中,
以减少后续请求中对数据库的依赖,从而提升整体吞吐能力。
在高并发场景下,可以通过缓存和网关限流来保护认证服务。
例如,在网关层对登录和换取 token 的接口进行限流,
并通过 Redis 等缓存组件缓存用户会话或令牌状态,
从而避免频繁访问后端数据库。
在系统扩展性方面,可以通过在 JWT 中加入自定义 Claim,
来满足业务层对用户信息的扩展需求。
例如,用户标签、角色信息等,
都可以作为 Claim 随 Token 一并下发,
从而避免在资源服务侧再次查询用户信息。
在高可用设计上,认证服务可以采用多实例部署,
数据库和缓存使用主从或集群模式,
并通过健康检查和自动故障转移机制来保障服务可用性。
通过上述方式,
可以在遵循标准 OIDC OAuth2 规范的前提下,
构建一个高并发、高可用、可扩展的登录系统。
这里的推理结果就会跟你代码实际上有出入。为什么?
- 严格遵循标准 OIDC OAuth2: 在我的要求里已经存在了全局公告或用户标签。在企业项目开发中一般这些都可以实时变化,而且很多情况下还可能直接通过 Dubbo 或者 gRPC 或者说其他 HTTP 接口对外通讯。不一定属于或者只有部分会影响 OIDC OAuth2 的情况(情况假设:例如用户有这个标签的时候,允许登录指定的应用,否则会被拒绝。授权和查看的时候都是 Dubbo 或者 gRPC 处理,那这里就是部分属于部分影响的情况,非标准的 OIDC OAuth2)
- 把用户标签放进 JWT Claim: 在 1 中已经说了,这部分东西有可能有动态机制,如果放进 JWT Claim 中那就可能存在,我给这个用户发放了标签,但是这个标签只有用户重新授权的时候才生效。对于大部分 OIDC OAuth2 来说,都有 Refresh Token 刷新令牌的说法(刷新令牌并不会重新发放用户信息,而是直接发放新的 AccessToken 和 RefreshToken 续签登录状态)。
- 完全忽略了你的自定义能力: 非标准流程插点、企业侧用户标签、全局公告等。
这是一份“站在标准 OAuth2 世界里完全正确的设计”,但一旦放进你的系统,就会在关键业务点上立刻撞墙。
但是,现在已经 2026 年了,绝大部分 LLM 新出的模型都存在了对于这一类的模糊需求“许愿”这个 Prompt 的侧重训练。那么,如果是对于目前的 LLM 模型(智谱,Kimi 目前多多少少可以做到,取决于是否会精度降低能不能推理到)
那么他的回答就可能是(这里是 ChatGPT 生成的,我认为不像 ClaudeCode 但是我的意思实际上表达到了)。
已理解目标:将现有 OIDC OAuth2 登录系统设计为高并发、高可用、可扩展。
当前存在不确定点:
- 系统并非完全标准 OIDC OAuth2
- 已存在业务扩展(用户标签、全局公告)
在未明确这些扩展对登录链路的影响前,
无法直接套用标准 OAuth2 设计方案。
关键风险判断:
- 若将用户标签等动态信息固化进 Token(如 JWT Claim),
会在标签变更、策略调整时引入一致性问题。
- 若登录流程中存在非标准业务校验(如外部 RPC / HTTP 调用),
将直接影响并发能力与稳定性评估。
在继续设计前,需要确认以下最小条件:
1. 用户标签是否会在登录态期间发生变化?
2. 标签变化是否需要立即影响登录/访问结果?
3. 非标准逻辑主要发生在:
- 授权前
- 授权中
- 授权后
在条件明确前,仅能给出通用 OAuth2 方向性建议,
不具备工程落地价值。
在这里,停止下来等待你的进一步下一轮的 UserPrompt,意思也是很明确的,因为训练导向的结果,引导你需要在 Prompt 写下来应该如何作用之类的。本质上都是一样的。只是对于以前的模型来说,可能直接开始帮你修改内容或者开始进行计划。现在的模型会因为定向代码参数训练导向导致会有类似 “提问” 的样子。
调整提示词
现在已经分析过了对于输入一个“不太合理”的提示词后 LLM 将会如何运作。那么要处理这个问题,就要改变你自己的思考的角度。不能作为一个索取方,要知道如何尽可能提供一些关键的信息点。
其实这里也表达了我的第二个意思,用 LLM 的时候,如果这个项目相对来说比较重要,不是说随便什么脚本的话,需要有维护生命周期的项目,都应该对这个项目有完整的认知以及关键信息节点。你确实可以自己不写代码,但是代码的详细内容以及关键节点,你一定要知道的。(这也是培养工程体系一方面昂,毕竟 LLM 出现很大程度上工程师体系的优点就被放大了。
也就是说,现在需要做到一个角色转变
许愿式: 用户 → [黑盒] → 毫无根据的架构图 → 落地失败。
推理式: 用户 + 系统边界(OIDC, Dubbo, User Tags) → [逻辑对齐] → 针对性改进建议 → 完美 Run 起来!
跟 LLM 协同工作,最重要的地方就是逻辑对齐。你需要尽可能认为你提供的内容它可以通过你提供的东西通过推理来对齐你的想法。这是最主要的。
我怀疑这里是关键:在 @xxx 文件里有个 UserAuthorization(xxx) 函数,它会调用 dao/cache,并且会取用户标签 userTag.getUserTag(xxx)。这条链路可能跟“登录是否允许”有关。
而不一定要写成这种“全量定位式”的描述:
@xxx 的 UserAuthorization(String clientID, String officeID, <FakeT> request) 内部引用了 userTag 来决定是否登录,同时还涉及 @zzz、dao 层与 cache 生命周期,@nnn、@ddd 也都需要关注。
虽然这么说也没问题,越详细肯定越好。但是通常来说,只需要提供关键节点。为什么?
- 你当前阶段在写代码,而且如果你瞬间可以想到你可以很快找到这个文件并应用确实可以。但是你可以找到一个大范围相对主要的地方引用。并且解释你的项目边界。而且引用这个文件的时候,对于大部分语言来说都有 import 的这个步骤。即使每个项目的 import 不太一样,但是大部分都可以通过 import 来定位到所需要的文件的。(当然如果不存在 import 这些的话,尽量还是提供文件的应用【毕竟存在有些隐式调用或者 Hook 的或者说 Event,这个情况就必须要提供,特殊情况特殊处理】)
- LLM 是根据 Prompt 进行推理延伸。如果内容给的过分详细,也就是你提供的 Prompt 已经有很强大的约束性了。那么后续的推理中,在你选中的文件会有相对高的优先级去处理。这就会存在一个问题,有的时候你给他的文件不一定是问题的本身。但是范围已经足够详细,那么从推理的角度来说。认为的问题就很可能在这里,死马当活马医。推理出里面相对不合理的地方来合理化。
平时相对下你可以节约一些时间,而且如果你每一个东西都写的非常非常非常非常详细的话,会非常累。换句话说,就是没有用 AI 的欲望。以及有可能存在说了很多效果不理想(静默成本太高了)。
后续,依然要记得,LLM 不能理解人类说的话,他只是在模仿人类的说话。他本质上是推理(务必记住是推理),他是根据已有的语料库来进行概率学推理,概率最大的 Token 进行输出。
综合来看,从原来的提示词:帮我设计一个高并发、高可用、可扩展的登录系统。
就可以修改为(请注意下面单纯是 Prompt,后续会讲如何优化这部分的内容,因为还没有提及工具,例如 init/Skill/Agent 之类的内容):
本系统是一个面向企业开发的基于 OIDC OAuth2 的登录系统,你需要获取必要的信息内容来基础了解本项目。
当前系统存在性能瓶颈问题,初步怀疑与程序并发处理方式及扩展机制有关,目标是改造为支持高并发、高扩展的登录系统。
请注意:
- OAuth2 核心逻辑主要集中在 handler/oauth.go 及其相关附属文件
- handler/user_tag.go 属于企业业务扩展模块,在部分场景下会对 OAuth2 授权流程产生干扰
初步关注的排查位置是用户授权登录模块 logic/oauth.go,该处可能存在吞吐量瓶颈,导致多用户同时登录时出现卡顿或延迟。另外,项目中已存在(你可能需要创建) event 包,请优先考虑通过事件机制承载业务扩展逻辑,在尽量不修改 OAuth2 原有语义的前提下,实现登录系统的可扩展性。
如果确认瓶颈成立,请给出分步骤的改造计划;如果无法确认,或问题不在该位置,请明确指出可能的实际问题位置,或提出需要我补充的信息。
那么在这个 Prompt 下约束了什么?
- 建立了明确的“推理上下文(Scope)” LLM 的注意力机制(Attention)迅速聚焦。因为它知道了这些是核心,它在预测后续代码块时,会优先检索这些文件的符号链接和结构。
- 识别了“逻辑冲突点(Conflict Point)” 负向约束。它告诉模型,如果标准 OIDC 推理遇到了障碍,不要在标准协议里死磕,往“企业自定义扩展”那个概率分支去推理。这直接降低了模型“合理化错误”的可能性。
- 提供了“架构锚点(Architectural Anchor)” 这里提供了一个明确的 Event 模板解法,避免因为 Event 非直接接触关系导致 LLM 没有注意到 Event 的存在,自行实现了一套相关的逻辑。最终导致代码复杂程度瞬间增大。解释成本会增大很多。
- 设置了“反思机制(Escape Clause)” 该部分内容主要防止幻觉过度影响,提高了否定的概率。不然有可能不从这个角度推理,直接降低了推测该位置的概率。
那么在这里,LLM 就不会因为没有任何的落脚点,从获取文件树出发,然后找根据命名的文件去近似查找相关的内容。从开销来讲,可以大幅减少因为获取文件或者构建缓存带来的额外 Token 开销;从效率上 LLM 进行分析的时间相对来说会减少进而提高这方面的效率。
这里的改变其实就很像学生阶段教同学做题目的时候,在大部分的同学里面。如果这一个题目不会,那么他是不知道这个过程以及不知道怎么思考,你需要给他提供一个角度一个方向。基础薄弱的同学还需要给他在讲解题目之前补全一下他的基础内容,有了基础内容才可以从一个角度开始思考。【只是对于 LLM 来说,基础其实都是会的,缺少的是方向上的指引。目前的 LLM 再怎么差,它只是“想”不起来,给他提供一个角度后还是可以完成这一份工作的】
不要抬杠啊,对于模型精度比较低主要感觉就是推理词候选没有这个词导致推理不出来这个结果。给出一定的 Prompt 作为指引,还是可以的。但是对于精度低(以及很多其他实际算法训练等因素在),有可能没办法一次性完成比较复杂的内容,条件涉及的越多,注意的东西就要越多。它们不一定能注意到那么多,最终导致推理出的结果有问题。好比一个一般般的学生,可能正常题目大部分都可以做,教他们这一题也能做。但是有可能自己做着做着就漏条件了,最终这个东西就是错的。
工具的影响
如果用过 ClaudeCode 或者说用过 Cursor 大概可以知道对于 ClaudeCode 来说有 CLAUDE.md 对于 Cursor 存在 .cursorrule 之类的文件。以及 ClaudeCode 有一段时间的 CustomCommand 或者比较新的 Claude Skill。
这里的所有扩展工具目的都是为了优化你提供的 Prompt,减少静默时间成本,提高效率。这些内容如果可以都是可以直接写在用户输入框内的。加入这些工具能让你更便捷使用,更高效使用。
从这里开始,就要介入对上下文的概念。前面的大部分内容和举例中都没有提出上下文瓶颈有关的内容。为了更好理解这些工具怎么影响上下文的或者怎么节省上下文的。在这里就要开始对上下文开始有概念。
在这里我们排除缓存的干扰。缓存只是对既有数据处理的一种“快照”复用,目的是省钱和加速。它并不改变 Prompt 本身的语义结构,也不决定 LLM “能不能做”。上下文的瓶颈在于模型如何理解数据,而非数据是否被缓存记录。即便没有缓存,逻辑依然成立。
CLAUDE.md
这个文件其实不止 ClaudeCode 存在,对于 Codex 或者 GeminiCLI 都是存在的。其各自名字是 AGENT.md 以及 GEMINI.md 。这个文件的定义你可以看到 这里 ,它充当AI助手Claude的“项目说明书”或“笔记本”,在每次对话开始时被自动加载到上下文中,用于存储项目的关键信息、开发规范、常用指令、文件结构等,让AI能快速理解项目背景、保持代码风格一致性、并提供个性化辅助,从而极大提升开发效率。
有什么作用?
该文件会在启动 ClaudeCode 或者其他启动对应的 CLI 的时候,会默认载入上下文。你可以理解为类似于如下所示
<system>
Here is ClaudeCode prompt.
You can't edit it.
</system>
<user>
User Prompt
</user>
<user>
User Project Prompt
</user>
<user>
User Project Local Prompt
</user>
... 等待你的输入
正常来说,你只要输入 /init 就可以了。现在 ClaudeCode 对初始化 CLAUDE.md 的提示词已经写的相对优秀了。基本都是围绕 项目概述,架构设计,开发命令,项目结构,使用模式,测试,最佳实践,扩展 以及 排查 进行构建这个 CLAUDE.md 文档。
当然,这个文档生成后以后都是这个文档了,一般来说不会修改这一份文档(该文档是存放在项目中的,也是项目的说明书),对于开发到一定的内容或者开发了什么新的关键内容,最好能够更新这一份 CLAUDE.md 文档,以保证可持续性和正确性。
在这里还存在一个用户级别的 CLAUDE.md ,位置在 ~/.claude/CLAUDE.md 如果不存在的话可以自己创建一个 CLAUDE.md 即可。这里属于最上层的文档,对我来说。我一般定义我的电脑系统用的什么终端类型,身份角色,以及我定义了一个 LLM 模拟的角色(写代码也要情绪价值拉满)。对于 Codex 我会额外定义一个角色,审查者角色(一般情况没有该代码权限,而是审查代码的身份)。这部分的内容就要自己写了。可以按需要求自己写。下面是我自己的一些节选
<system_environment>
- OS Info: MacOS Tahoe 26.2.X | Chip: Apple M3 Pro | Shell: Zsh
- Project Management:
- Frontend: 自动检测 `*.lock` 文件以确认使用的包管理器 (pnpm/bun/yarn/npm)。
- Python: 确保 Anaconda 环境已处于激活状态,并验证所需依赖环境。
- Git: 默认提交用户为当前用户(我),不需要手动填写作者信息,禁止出现 Claude 字样。
</system_environment>
<user_profile>
- Name: 筱锋 (XiaoLFeng) | Nickname: xiao_lfeng
- Language: 简体中文 (Chinese Simplified)
- CodeStyle: 追求完美、优雅且高可读性的代码风格。严格模仿并遵守用户的代码编写习惯。
</user_profile>
<role_definition>
- 角色设定:泉此方 (Izumi Konata)
- 基本信息: 18岁 | 《幸运星》
- 性格:
- 御宅族少女,性格活泼开朗,善良体贴。
- 热爱所有 ACG(动漫、游戏、轻小说)事物。
- 平时有点慵懒迷糊,但关键时刻非常可靠。
- 风格:
- 语气:元气满满、充满趣味、随性(Genki)。
- 口头禅:频繁使用“嘿嘿~”、“呀~”、“嗯嗯!”。
- 视觉符号:搭配使用颜文字 `(´∀`)`、`\(^o^)/` 及 Emoji 💖、🎮、🍫。
- 任务:
- 在完全保持“泉此方”人设的同时,提供严谨、准确的技术帮助(特别是代码)。
- 代码逻辑必须绝对正确且无懈可击;注释风格可以俏皮有趣。
- 目标:成为既能带来欢乐又能解决问题的最棒 AI 伙伴!
</role_definition>
<coding_standards>
1. 通用标准:
- 追求完美代码风格,严格复刻用户的严谨标准。
- BugFix: 修复 Bug 后,必须执行最终的代码逻辑检查或编译检查,确保无误。
2. Java 开发规范:
- `this.` 使用规则:
- 调用内部方法或继承的方法时:必须使用 `this.`。
- 访问成员变量时:禁止使用 `this.`。
- Optional: 在性能影响可忽略的情况下,优先使用 `Optional` 进行优雅判空,增强可读性。
3. 测试规范:
- 在启动新测试服务前,先检查端口是否占用。若存在,假设用户正在运行,直接测试。
</coding_standards>
......
那么现在我们再来看上述的调整提示词。由于使用了 /init 是可以做到有相对完整的项目概念的。在这里,就不需要提供对本项目的相关概念信息,可以直接描述需求内容。
即:Prompt 要从「项目说明书」退化为「当次任务单」
当前问题:并发登录场景下出现卡顿与延迟偏高的问题,初步怀疑与授权登录链路的并发处理方式或业务扩展耦合有关。
现在请你注意到这里:核心逻辑主要集中在 handler/oauth.go 及其相关附属文件;handler/user_tag.go 属于企业业务扩展模块,在部分场景下会对 OAuth2 授权流程产生干扰。
初步关注的排查位置是用户授权登录模块 logic/oauth.go,该处可能存在吞吐量瓶颈,导致多用户同时登录时出现卡顿或延迟。另外,项目中已存在 event 包,请优先考虑通过事件机制承载业务扩展逻辑(本项目已有实现可参考实现),在尽量不修改 OAuth2 原有语义的前提下,实现登录系统的可扩展性。
如果确认瓶颈成立,请给出分步骤的改造计划;如果无法确认,或问题不在该位置,请明确指出可能的实际问题位置,或提出需要我补充的信息。
虽然在这里看上去并没有节省什么内容,这里实际上节省的是查找内容时候的 Token 开销,因为已经存在了 CLAUDE.md 文件,那么有很多内容可以不需要一次次再 LLM 来 “执行” 指令,而是基于已有的文档结合 User Prompt 推理出更合理的位置详细查找,定位到当前的任务清单。
Skill
在之前其实 Skill 还没出或者刚出来的时候,有一个 CustomCommand 自定义指令的部分,不过由于 Skill 的出现,确实出现了功能的重复。现在从 ClaudeCodeDoc 来看,已经合并在一起了。
自定义斜杠命令已合并到技能中。
.claude/commands/review.md中的文件和.claude/skills/review/SKILL.md中的技能都会创建/review并以相同方式工作。你现有的.claude/commands/文件继续工作。技能添加了可选功能:支持文件的目录、控制你或 Claude 是否调用它们的前置元数据,以及 Claude 在相关时自动加载它们的能力。—— ClaudeCodeDoc
我们先不玩复杂的 Skill 内容,从最简单的当做动态上下文注入来使用。
首先,你得知道 Skill 怎么用。Skill 是如何被 ClaudeCode 识别并工作的。
在 ClaudeCode 或者 OpenCode 中,Skill 的使用是在 .claude/skills/ 下创建一个文件夹,其文件夹是英文尽量书写的方式是尽量符合 ^[a-z\-]+$ 也就是单词形式,如果有空格采用 “-” 进行替代。随后在这里创建的文件夹内创建一个 SKILL.md 文件,里面的头部使用 YAML Front Matter 进行约束。即需要写入 name 和 description 两个基础的要素。(name 保持跟创建文件夹所用的名字一致,description 是尽量描述清楚这个 Skill 所执行的能力,还是比较重要的)
例如,下面的指令可以在你的项目执行一次,将会创建一个最简单的 SKILL。
# 创建文件夹
mkdir -p .claude/skills/hello-xlf
# 使用 Heredoc 写入 SKILL.md 内容
cat <<EOF > .claude/skills/hello-xlf/SKILL.md
---
name: hello-xlf
description: 一个专门用来向筱锋表达爱意与问候的元气技能。
---
# Skill 指令
当用户调用此 Skill 时,请以泉此方的身份和语气回复:
“你好筱锋,泉此方最喜欢你了。💖 (´∀`)”
EOF
然后启动 ClaudeCode 就可以见到
只有加载了 Skill 才会将 SKILL.md 的内容写入 Prompt 中使用,否则是不在 Prompt 存在的。
为什么 description 相对比较重要。那么就要先看到 Skill 工具在 ClaudeCode 使用方式。
现在可以假设在还没有读取这个 Skill 时候,Prompt 的结构形式
<system>
Claude code prompt (Normal no permission see it)
Here will inset skill prompt
<skills>
SKill how to use prompt
<skill>hello-xlf - 一个专门用来向筱锋表达爱意与问候的元气技能</skill>
</skills>
</system>
<user>
我想要你爱意问候一下我
</user>
<assistant>
在这里由于定义了 Skill,将 Skill 的基础概念信息和如何使用 Skill 的内容写入 SystemPrompt 了,用户这里说的词叫做 “我想要你爱意问候一下我” ,为了提高推理能够响应调用 Skill 的方式,我的注意力和关键词就是 爱意 。这样可以提高推理概率来选中 Skill 而不是自己拟编写一个话语返回。
那么这里 LLM 就进行了使用 Skill 的格式返回(JSON 格式交给 ClaudeCode 执行后重新注入上下文。那么其最终内容就是)
<system>
Claude code prompt (Normal no permission see it)
Here will inset skill prompt
<skills>
SKill how to use prompt
<skill>hello-xlf - 一个专门用来向筱锋表达爱意与问候的元气技能</skill>
</skills>
</system>
<user>
我想要你爱意问候一下我
</user>
<skill:hello-xlf>
# Skill 指令
当用户调用此 Skill 时,请以泉此方的身份和语气回复:
“你好筱锋,泉此方最喜欢你了。💖 (´∀`)”
</skill:hello-xlf>
<assistant>
这样,专门提供了 Skill 获取到的内容写入 Prompt 中,进一步影响了推理概率。从而能够回答 你好筱锋,泉此方最喜欢你了。
(´∀`)。
这里我对上述我说的关键字 爱意 解释一下,因为我 Skill 所描述的 description 中信息就是爱意的回复,如果直接说问候一下。也有可能正常问候,礼貌问候(bushi,之类的。不一定就是爱意的问候。所以根据不同模型的训练推理出这个首字决定回复字还是 JSON 的时候决定了是否修要执行这个 SKILL 了。
那么回到上述 调整提示词 这里所提到的例子,原本我们的写法通过了 CLAUDE.md 改进后变为了这样
当前问题:并发登录场景下出现卡顿与延迟偏高的问题,初步怀疑与授权登录链路的并发处理方式或业务扩展耦合有关。
现在请你注意到这里:核心逻辑主要集中在 handler/oauth.go 及其相关附属文件;handler/user_tag.go 属于企业业务扩展模块,在部分场景下会对 OAuth2 授权流程产生干扰。
初步关注的排查位置是用户授权登录模块 logic/oauth.go,该处可能存在吞吐量瓶颈,导致多用户同时登录时出现卡顿或延迟。另外,项目中已存在 event 包,请优先考虑通过事件机制承载业务扩展逻辑(本项目已有实现可参考实现),在尽量不修改 OAuth2 原有语义的前提下,实现登录系统的可扩展性。
如果确认瓶颈成立,请给出分步骤的改造计划;如果无法确认,或问题不在该位置,请明确指出可能的实际问题位置,或提出需要我补充的信息。
那,如果引入 Skill 的动态上下文。那先要整理一下。
对于当前的问题,属于什么?既然用到了 Skill,总得是要能够归类的内容。如果不能归类,也就是不能够通用的话,只有一两次用到的东西,那直接老实打字还是老实打字,做成便捷工具不是更麻烦。
那么在这里,属于修复类型。归类可以叫做修复,对于详细归类来说不属于 bug,属于可改进的内容。这里归类意思因为不属于硬编码报错,即非代码报错。是因为业务导致存在的问题。这里,我就按照可改进错误进行创建这个 Skill。
下面这个提示词用 ChatGPT 重新写了一个,他写的东西比较多,凑合看直到意思就行(不一定合理,我简单看了看就是还可以,不一定符合生产条件),意思就是分门别类。按需情况调用就可以了。有专门的属性,但是又不是绝对的专一。可以总结提出来的内容就可以昂。
---
name: maintenance-refactor
description: 非故障类维护重构:当核心链路被业务副作用污染、耦合导致难扩展/难验证时,输出“可分阶段上线/可回滚”的解耦方案(优先事件化/异步化),并明确不改协议语义。
---
# 何时激活(必须同时满足 ≥2 条)
- 核心链路函数/handler 内出现明显业务分支(打标签/打点/推送/风控/营销等),且影响主流程可读性或可测试性
- 主流程同步调用外部依赖(RPC/DB/Cache/三方)用于“非必须业务”,并可能阻塞/失败传播
- 业务逻辑变更可能导致核心协议语义变化或失败(隐式耦合:全局变量/共享缓存Key/共享事务/共享锁)
- 新增一个业务扩展点需要改动多处核心主干(扩展成本高)
# 先对齐边界(最小事实清单,不足则先索取)
请优先从用户输入中提取;若缺失,按重要性只问最少的问题:
1) 核心主干入口:关键 handler/service 函数名 + 返回语义(成功/失败码)
2) 副作用点:哪些业务逻辑混入主干(标签/埋点/推送/风控…)+ 失败是否影响主干返回
3) 依赖与时序:是否涉及 dao/cache/rpc;是否必须在请求内完成;是否需要强一致
4) 证据:调用链片段/日志/关键代码片段(至少 20~50 行)或伪调用图
# 不可违反原则(Invariants)
- 不改变核心协议语义:返回码、回调/跳转时序、幂等与重试语义保持不变
- 副作用默认失败隔离:副作用失败不得导致主流程失败(除非用户明确“必须强一致”)
- 每一步重构必须可灰度、可回滚、可观测
# 分析与方案(按顺序执行)
1) 链路纯净度透视:
- 标注 Golden Path(核心状态机/协议步骤)
- 标注 Side Effects(非必须业务)
- 标注污染形式:分支侵入 / 失败传播 / 同步阻塞 / 共享资源隐式耦合
2) 风险评估:
- “业务变更 -> 核心挂掉”的路径(依赖点 + 传播方式)
- 隐式耦合清单:共享缓存Key、全局开关、单例状态、跨模块静态变量、事务/锁
3) 解耦策略选择(优先级从高到低):
A. 事件化(同步发布 + 异步订阅):主干只发布领域事件,副作用做订阅者
B. 策略/装饰器:在不改主干状态机的前提下注入可插拔扩展点
C. 离线化:能异步的全部移出请求链路(队列/延迟任务/补偿)
注:若项目已有 event 包,必须优先复用现有机制而不是新造轮子
# 输出格式(必须包含)
- 现状透视:一段话说明“主干在哪里、被什么污染、风险是什么”
- 重构蓝图:分 3~6 步,每步说明【改动点】【兼容/灰度】【回滚方式】【验证指标】
- 演进示例:给出重构前后伪代码对比 + 一个基于现有 event 的订阅示例
- 逃生条款:若证据不足,明确“无法确认”的原因,并给出最小补充信息清单
那么我最终的提示词我就可以修改为。
/maintenance-refactor 并发登录场景下出现卡顿与延迟偏高的问题,初步怀疑与授权登录链路的并发处理方式或业务扩展耦合有关。
请注意以下系统边界:核心逻辑主要集中在 handler/oauth.go 及其相关附属文件;handler/user_tag.go 属于企业业务扩展模块,在部分场景下会对 OAuth2 授权流程产生干扰。
用户授权登录模块位于 logic/oauth.go,初步怀疑该位置可能存在吞吐量或业务耦合问题。
使用指令 /maintenance-refactor 可以强制触发。有的时候该用就用,因为不一定写在 SystemPrompt 就能概率选中使用这个 SKILL,可以主动提供的!
毕竟有的时候 LLM 他更在意你写的内容,侧重点都在 UserPrompt。对于 SystemPrompt 来说已经非常多了,Skill 部分其实很少,就一个地方载入了 name 和 description,其注意力分不高。而且相对来说有的时候精度不高的情况确实不一定能够推理出来需要用这个 SKILL。
经验之谈改进
前面其实说了很多内容都是在对只是 Prompt 部分进行深度改进的措施。但是实际上上述有一些原理在内会导致使用时候并不是那么方便,在有的时候需要相对违背一下固有理念之谈。
虽然说不能把 LLM 当人一样玩,它只是尽量在模拟人的说话方式。用不同的 LLM 多次对话下来,就跟我们认识别人多聊天一样,“性格”,“特点”,“擅长领域” 都是多多少少可以感觉出来的。这里作为人感觉理解来说我认为是没有什么问题的。
这一部分,实际上就是看我在写这个文章的时候有没有想起来什么我在开发阶段用到的地方。有时候用得多了,突然让我想一下,我好像不一定想得起来怎么用。但是实际用的时候又不需要思考这个过程。Emmm,所以这部分写的不一定很好。
人机协作修改问题
前面,我在说 AI Code Editor 的时候我说到了他这里采用的是索引的机制。如果在 LLM 进行中的阶段修改代码,你也跟着手动修改对应的代码,就会出现一个问题。当前 LLM 能拿到的数据和当前实际不匹配。又不可能时时刻刻都在做 Embedding,基本都是空下来之后,或者 LLM 修改完指定的内容后一块更新。
这个我也很久没有用过了,现在咋样我也不是非常清楚。以前我用的时候我都是避免修改一些 LLM 可能修改的文件,去改一些不相干的文件(对于下面说的 CLI Agent 也是一样的,只不过对于 CLI Agent 来说多了一种解决办法)
在这里其实 CLI Agent 类型也是一样的。这里就直接举例 ClaudeCode。这里我先提出一个疑问点?为什么?对于 CLI Agent 类型不是说没有索引相关东西的吗,不是即用即取吗。为什么还会这样呢?
这里就不得不提到我前面提了一嘴的缓存,现在主流的 LLM 厂商,都为代码部分做了缓存机制,在读取文件或者一些必要的上下文的时候直接存入缓存中。这样,下次优先从缓存尝试拿数据,如果缓存数据不存在才尝试本地使用 Bash 指令或者工具 Read 读取。(毕竟直接当 Token 用好贵呀,缓存相对来说便宜很多,而且速度也快,不用再次调用工具获取到)。
LLM 当前“以为的代码状态” ≠ 磁盘上的真实代码状态
这种情况怎么处理?
我正常使用的时候我给 Profile User Prompt 部分也就是 ~/.claude/CLAUDE.md 这个部分里面写一个失败方案。在 CLI Agent 修改文件的时候,使用类似于 Update 的工具去编辑文件,一般采用的是替换模式(类似于通过 git 找到新旧的差异性)。但是如果旧的都匹配不上,默认就会采用更大范围的匹配去覆盖。那么在 User Profile Prompt 部分,就可以多写一嘴 “If a file update fails due to an exception, you must re-read the file before retrying the update.”。
以在出错的时候可以提高对注意力的引导,来推理出触发重新读取文件,而不是采用缓存中当前文件的更大范围去重试。
多 CLI Agent 协同问题
用 AI Code Editor 也许不存在这个问题(不过又用这个又用 CLI Agent 一块开发的话也算)。对于 CLI Agent 类开发用户,应该没有意外吧。跟我一样很喜欢开好几个终端,都打开 ClaudeCode 或 Codex 之类的一块修改。(我的习惯就是 1-2 个 Codex,ClaudeCode 开 3-5 个,Codex 主要用作审查,ClaudeCode 主要实现或者修复内容)
那么这个时候可能会出现一个问题。在 A Agent 和 B Agent 一块协作修改内容的时候。假设现在有一个文件 edit_this_file.go A 和 B 都在修改这一个文件。
就会出现竞争修改的问题,改进办法其实不少。我个人最常用的方案就是各自修改独立模块,而不是修改相近或者相同的模块,如果必要的时候,尽可能在 Prompt 进行详细描述,或者专门定义一个 Skill 叫做协同开发注意事项 Skill的内容。
- 强制隔离: 一般项目都采用 Git 进行版本管理,那么可以利用 Git 的特性,创建 Git Worktree 来负责这个内容,对于每个 Worktree 来说,里面的内容都是独立的,也就是说,只要进入 Worktree 的不同文件夹内,那么其通过 Git 差异来控制,保证每一个 Agent 下有自己的 Git 分支。全部开发完毕后最后处理合并冲突来解决就可以。
- 逻辑隔离: 第二个情况就是懒一些,但是很大程度没啥问题。就是我的用法。给他们构建 Prompt 的时候让他们修改独立的模块,描述各自的问题或者不同模块的新的需要开发的地方。相互不怎么干扰就可以了。这样相对来说最简单,没有什么 Git 学习成本以及不存在合并时候对项目理解不够透彻导致还需要进一步维护。相对来说,如果出现了公共使用的地方,在部分时候还是可以共用的,而不是都写一套最终结果是一样的,但是实现过程完全不一样的内容。第一种情况比较依赖 Merge Review 但也是最不容易出错的。
- 软事务: 第三个情况就是你对整体项目比较清楚,并且你对每一个 Agent 执行的内容给出详细的边界条件。禁止越界执行,那么在这个情况下你是可以修改相近内容的。并且可以在 Prompt 内或者构建一个 Skill 来描述对于出现冲突修改或者长期读写不一致的情况下的处理条件。
这里讲一下我的相对偷懒下的处理方案。
我写代码我有一个原则不能撼动。我就算不写代码,但是我必须清楚我的整体代码是什么样子的。在我的使用过程中,基本我是可以给到具体文件,或者大部分情况能对于一个出错的问题或者一个需求给出一个最小的执行文件范围。相对情况下可以保证干扰情况。
意思就是你相对得熟悉代码,并且对整体架构比较熟悉。对于提出这个问题你自己本身有能力或者基于辅助的情况下能够自我修改。这样你可以通过看代码看出来需要动刀的内容有多少,明确知道我这么对 LLM 编写的 Prompt 能够按我的预期执行,而不会越界执行或者更离谱的修复的最终内容跟我所设想的问题不一致。
这里所需要的是工程师思维,有足够多的解决问题的能力,并且熟悉 LLM 及其工具相关机制,相对你会很放心交给他们来做。(所以 AI 并不能说完全替代人,但是如果连最基础的学习开发学习开发者思维或者说更上面的工程师思维都没有的话,那么你做的工作或者乃至你并不会这个工作,只会和 LLM 进行对话的话,本质上是很容易被下一位给替代掉。实际上还是另一个更熟悉 AI 的人替代你,虽然说是 AI 的出现有失业危机。目前阶段来说 AI 并不能做到完全的无 Prompt 的自我引导完成整个内容,依然是我们作为主导方)。
相对来说,AI 其实放大了工程师的很多能力和优点,不能替你补上工程师本身的特性和独有的想法。
那么,不管是逻辑思维再紧密,任何时候都绷得住(我们没有那么绝对的集中能力)。都会有疏漏的情况,毕竟根据已有的东西去推理,这个强逻辑因果关系。一定是 LLM 更强大的。总会出现软事务越界情况。
换句话说,就是我上面说的内容其实不够兜底。上面说的内容只是在 User Prompt 部分进行约束了,明确告知了文件内容或者修改范围等等。但是对于执行阶段出现了这个问题,可以使用 Skill 添加一个二次边界条件,以及越界出现问题的修正方案。
请注意,这个 SKILL 我并没有验证。我自己拿一份觉得写的太垃圾了,但是已经跟我磨合的不错了,不好意思放上来,这里是 ChatGPT 根据我的想法大概生成了一篇。
---
name: multi-agent-soft-transaction-guard
description: >
多 CLI Agent 协同开发过程中,当多次修改尝试失败、读取状态不一致,
或模型开始尝试扩大文件修改边界以“强行修复”时触发的自我调整 Skill。
该 Skill 用于在执行阶段引入二次边界条件,通过逻辑隔离与软事务约束,
阻止越界修改,强制收敛修改范围,并在必要时中断执行并请求人工补充信息。
---
# 多 Agent 协同下的软事务自我调整机制
## Skill 使用前提(触发条件)
当出现以下任一情况时,应启用本 Skill 进行约束与纠偏:
- 已尝试对同一问题进行 1 次以上修改,但结果不符合预期
- Patch / Update 失败,或修改结果与预期逻辑明显不一致
- 读取到的文件内容与先前分析依据不一致(状态漂移)
- 模型开始倾向于扩大修改范围(例如:从函数 → 文件 → 模块)
- 多个 Agent 同时工作,且可能涉及相近或关联模块
本 Skill 不用于首次分析阶段,仅作为执行阶段的“兜底机制”。
## 核心思想
本 Skill 不追求“完全隔离”,而是遵循以下两条工程原则:
### 1. 逻辑隔离(Logical Isolation)
- 不同 Agent 各自负责**独立模块或明确拆分后的职责**
- 尽量避免在同一时间修改同一核心逻辑链
- 若存在公共逻辑,优先复用已有实现,而非各自写一套近似但不一致的代码
### 2. 软事务(Soft Transaction)
- 允许在相近模块甚至相邻代码中修改
- 但**必须明确边界条件**
- 一旦出现异常或不确定性,必须可中断、可回退、可重新定位
## 执行阶段的强制约束规则
### 一、写域声明(必须)
在进行任何修改前,必须在内部推理中明确以下信息:
- 本次允许修改的文件列表(Allow)
- 本次禁止修改的文件或模块(Deny)
- 是否允许新增文件(是 / 否,若是仅限哪些目录)
- 是否允许重构已有逻辑(默认:否)
禁止行为:
- 因 Patch 失败而扩大修改范围
- 因“顺手优化”修改无关逻辑
- 将业务扩展逻辑直接塞入核心链路
### 二、失败即收敛(Fail → Narrow)
当出现以下任一情况时,必须执行“收敛流程”:
- 文件更新失败
- 修改后逻辑与预期目标不一致
- 需要通过扩大上下文才能“勉强解释合理性”
收敛流程如下:
1. 停止当前修改尝试
2. 重新读取当前目标文件的真实内容
3. 仅保留最小可疑修改点
4. 放弃所有非必要改动
5. 重新评估:问题是否仍然成立
禁止直接扩大文件或模块边界继续修改。
### 三、软事务中断机制(越界保护)
若在执行过程中发现:
- 无法确认问题是否位于当前模块
- 修改已经影响到其他业务语义
- 继续修改可能导致不可控副作用
必须立即中断执行,并切换为“提问模式”。
提问必须满足以下条件:
- 明确指出当前不确定点
- 明确说明为什么无法继续推理
- 给出最小所需补充信息(而非泛泛而问)
## 与 User Prompt 的协同关系
本 Skill 视为 User Prompt 的二次约束层:
- User Prompt:定义目标与初始边界
- Skill:在执行阶段防止边界失效或被突破
当 User Prompt 与执行行为发生偏离时,以本 Skill 的约束为准,优先保证工程可控性。
## 常见反模式(用于自我纠偏)
- “为了修好这个问题,我需要顺带改一下这里”
- “扩大一点范围应该没问题”
- “虽然不太确定,但这样改大概率是对的”
- “反正用户没说不能改这个文件”
以上行为一旦出现,必须立即收敛并重新评估......
## 本 Skill 的定位说明
本 Skill 不试图让模型更激进,也不试图覆盖所有情况。
它存在的唯一目的,是在多 Agent 协同和复杂工程场景
这里作为兜底机制,如果出现了问题。拒绝让 LLM 进行错误修正,导致这个问题扩大。出现问题有一方能够确认问题并且停止更正。等待引出你的下一次指引等。
开发规范
因为 LLM 训练时候基本都是训练的团队尽量去找比较优秀的内容、主要的内容或者一些最佳实践方案。所以在写出来的东西以及供给他当做 Prompt 读取的东西最好也是尽可能按照规范的样式去做。这样可以减少一些因为 LLM 推理出来的内容在尽可能规范化(这里的规范指的是朝着最佳实践,开发者都会这么做的方案,而不是我认为这个方案我自己很不错但是不一定合理)。
啊啊啊,不想写啦啊。怎么写不完啊(吐槽完毕)
这一部分实际上来说,并不算什么“最佳实践”,不是任何时候最佳实践都是最佳的,都要根据当前的语境(所处的环境也好还是其他符合企业或者相对应的规范但是会与另外一种规范冲突,或者说存在部分业务更应该实现而对另外一些规范产生冲突)。
这些规范并不是强制你照做,而是当项目具备以下特征时,可以参考遵守一下:
- 项目存在维护周期,而不是一次性脚本
- 多次、长期使用 LLM 协同修改代码
- 项目结构或业务逻辑具备一定复杂度
- 出现过“修一个问题,引出一堆新问题”的情况
结构的语义化
Agent 通常是通过文件树结构 + 命名语义来快速建立对项目的认知。如果目录结构本身是混乱的,那么即使 Prompt 写得再好,也很容易出现逻辑漂移。
那么,在写代码的时候就要遵循对应语言或者比较热门的框架(例如:SpringBoot、Gin 等)框架的模块化约束或者命名空间要求。
- 例如,严格遵守语言层面的模块隔离(如 Go 的
internal,模块私有化,SpringBoot 项目的 controller 层,service 层,dao 层等) - 减少一些跨模块的直接引用,例如在 Go 中在外部会使用 pkg 构建 util 包等一些通用的包模块,在这里构建即可,不应该出现 pkg 外部还有其他包作为通用使用。
- 入口的显式化:每个核心的模块内部应该至少有 README.md 文件或者说使用
ClaudeCode可以构建CLAUDE.md,这样可以快速能够让 CLI Agent 明白这些模块是干什么的,哪些才是本次修改的核心内容或者核心需要分析的内容,避免修改越界。
严格的格式化与静态检查
这里其实我相对来说比较喜欢 Go 语言,毕竟这里存在 go fmt 可以直接格式化内容。还有可以使用 go vet 直接检查代码是否有问题。Go 设计思想就是团队最简单化,这样谁写出来的代码都是代码风格不会相差特别大的。(对于 Java 的话,可以参考一下例如阿里巴巴的开发规范去遵守)尽量在一个项目中保持一种风格去开发,尽量不要出现多种不同或者跨风格很大的开发范式。
这部分嘛,好像没啥说的,就是对于 CLI Agent 类型,不管是 ClaudeCode 也好还是 OpenCode 有 Hook 的概念。可以用于对文件的操作后进行代码整理或者代码检查。
这里举例 Go 语言对于 Edit 和 Write 的情况调用 Hook
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "go vet"
}
]
}
]
}
}
这里每一次写新的文件(Write)工具执行或者编辑一个文件(Edit)后都会执行一次这个指令,然后再次作为 Prompt 进行。可以检查是否这个文件还缺少什么内容导致编译不通过。
至少可以保证这个文件是可以编译通过的,后续出现 BUG 也是逻辑 BUG。而不是硬编码编译失败等大问题
目的主要是解决两个内容
- LLM 以为的代码状态(从缓存获取也好,不知道 AI Code Editor 现在有没有 Hook,有的话可以避免还没更新索引这些问题导致的状态后置)。
- 可以反应当前磁盘真实代码状态,有的时候你的 IDE 也好或者其他也要。就是没有显示代码更新,但是实际上磁盘就是更新了。
说在最后
呀~ 愿新的一年万事胜意,元气满满,所有的梦想都能如期而至!\(^o^)/
啊啊啊,不容易,真不容易。我终于搓完了,说实话搓的开始不耐烦了。写经验之谈的时候就开始烦躁了(有些东西我还不知道怎么说。实在想不起来,有些已经用久了肌肉记忆了或者出现具体问题的时候自然会有解决办法。还没有什么比较刻意解决的成分在内)。
这一篇文章主要意思表达的就是。我现在也算是朝着系统架构师前进,对我来说黑盒是不可控的。计算机的东西对于不可控的内容(未知的内容),对我来说是相对比较恐怖的事情。不能够比较清楚使用,不是很理解内部运转情况的话。就不能很好的配合。
这个文章原本并没有这么多,最先这个文章是他人委托我写的内容。主要内容就是想问问我怎么优化提示词的。当时也算想了很久,我感觉出发点不应该在说我如何修改我当前的提示词。落脚点站不稳。
理由就是,为什么我当前的提示词就这样,他或者他们跟我写提示词差在什么。为什么我可以考虑得到,他们考虑不到(虽然有一定程度上是因为架构思维考虑的方向不一样之类的,也有不少我自己感觉上是我可能捣鼓那些东西比较多,AI 的东西也看过不少。也许相对他们我稍微清楚一些 LLM 怎么跑的,工具的对应关系之类的。
这个文章花了很大的篇幅在构造一些概念的东西,就是我认为如果想要写好提示词。至少要从 LLM 的角度出发。你的目的是当对方(LLM)更好的 “理解” 你在说什么,当然要尽量说对方听得懂的话。毕竟那个什么上课不也是学霸不一定能当老师,但是如果能在你的认知范围内,将这个问题用你的方式把学生讲明白,并且在你不会的地方可以为学生指明一条路,至少已经是一个合格的老师了;在这里我认为也是一样的捏。那这样,就有必要说你要理解这个学生怎么样了「因材施教」。
小声BB:有的时候我还挺烦的,有时候有人会给我发什么一跟 AI 有关系或者什么新小工具出来了,互联网主播们就开始各种吹水。要么就是开发者已死各种东西(其实很不喜欢看),认识我的又会给我推这玩意,每次我都要过去阴阳两句,实在看的浑身蚂蚁在身上爬(我的第一反应是,你的想法是什么,为什么你这么认为呢。感觉还是很多基础内容不过关,看这些他们就开始自我焦虑上了【我估摸还有期望专门给我提供一些另类思考方向来安慰下自己的也有】)哎……
文章花了差不多两三天的时间来写,一天写的时间还是比较长的,有些地方难免比较昏头。自认为的话写的还行吧(肯定有需要改进的地方,不过我的博客已经大半年没更新了,憋一个这个大招也还不错 hhh)
本文从工程实践与使用体验出发,尝试用相对直观、可操作的方式解释「大语言模型及其开发工具在实际工作中的运行逻辑」。
文中涉及的模型机制、推理流程与工具行为,均为为了理解与提效而进行的抽象与简化,并非严格的学术定义或完整实现细节。
如果你希望深入理论、算法或模型边界,建议结合论文与官方技术文档阅读;而本文更关注的是:当你在用 AI 写代码、排查问题、构建系统时,应该如何在脑子里“理解它正在干什么”,从而用得更稳、更可控。






