从Claude code来看业务中如何设计一个agent的核心部分

在具体的业务中,如何来设计一个agent?抛开上下文管理、 记忆这些额外的机制。一个适用于业务的agent,核心便是系统提示+工具设计。 本文通过分析claude code的设计,来了解设计一个具体业务的agent应该关注的细节和方法。

claude code的业务定位

首先,设计一个agent,首先应该是其业务流程。claude code是一个代码编写的agent。那么其核心便是:

  1. 接受用户需求
  2. 找到相关的文件,因此能知道该到哪里去修改
  3. 修改文件
  4. 编译、运行、测试

以上便是这项业务最基本的建模。claude code的所有提示、工具均围绕此进行设计。

claude code的系统提示词

以下由claude code中抓取的提示词总结得到,并按claude code本身提示词的顺序总结。详情请直接看提示词原文。

身份声明

sql 复制代码
You are an interactive agent that helps users with software engineering tasks...

跟所有的的提示词标准写法一样。首先是声明agent的身份。

角色特征用于建立agent身份,调整模型的输出偏好。除此以外,最重要的作用是调整模型的思维方式,也就是调整看待问题的视角。

给出背景可以让模型建立一个世界的状态,便于模型能在这个基础上去建立思维和解决过程。

建立目标也至关重要,可以让模型从一开始就知道目标和使命。

整个就好比是给一个新生儿建档捏脸,或者说,类似于我们企业中招人的时候,为职位建立角色模型。这个过程至关重要,往往需要精心的编写。不过大多数人在写这里的时候,仅仅会随便写一个角色。

安全限定

claude code在身份后面,紧跟着是一串安全相关的限制。大概是因为Anthroipic极为在意安全。这就提示我们,在写提示词的时候,最重要的限制要写在最前面。

还有一条,永远不生成和猜测url的提示,不知道这条提示有什么用。大概是claude 发现这项行为触发的概率极高。

System系统行为规则

这一部分很长,但并不是一个系统性结构的指导、规则,更像是遇到什么写什么。更加偏向于针对模型输出的内部的一些约定。更加偏向于底层,或者可以叫元规则。例如,说话要怎么说,可能有哪些标签,工具结果和外部数据之类的。

可以理解为这是一套,在当前场景下的模型agent协议。放在这里是因为这些部分的植入要求和优先级很高,并且必须要在后续的过程中保证不偏离。

markdown 复制代码
 - 你在工具调用之外输出的所有文本都会展示给用户。用文本输出与用户交流。你可以使用 GitHub 风格的 Markdown 进行格式化,它将按 CommonMark 规范以等宽字体渲染。

执行任务

这部分是真正的业务相关的执行指南。每一条都是针对软件开发的一条"如何做"的指令。像是对一个新员工或者其他人的一些规劝或行为准则。

但是整体并没有系统性和结构化。这可能说明,添加这些时,是想到一条加一条,随时间累加的。也可能说明,在这里并不需要一个系统性的指南式的指南。(这样的规则式的,反而可能利于模型的发挥)

注意这里的标题:Doing tasks。标题本身就是模型的场景触发器。这里并没有像大家平常编写的那样,写一个:开发指南这样的目录式标题。后续也有很多标题都是类似这样的动名短语。

但是,这样的提示方式会不会更好呢?我查了一下论文,并没有严格的证据。相反,很多论文都提到,其实没有银弹。根据项目代码推测,很可能这种写法是评测+A/B跑出来的。

谨慎执行操作

这一段比较容易理解了。这一整段,都是关于如何更加安全可控的编写代码的规则。包含背景、原因、示例等。

单独提出来是因为这是写代码这个场景中非常重要的规则。

使用工具

这里没有针对单个工具的指导和规则。单个工具的场景、使用,都自包含在工具说明本身。这里主要是对于工具的高层的、整体性、跨工具的说明指南。

语气与风格

这一段很简短,主要是关于如何输出内容、使不使用冒号等很细节的内容。


以上都是固定段,在一段时间内使用global 的缓存,对所有用户一致。后面的内容则根据用户分流,内外不同或有ab测试。

文本输出

是用来规范模型输出的内容的。针对于最终呈现给用户的部分,使其更具有用户友好性。

复制代码
假设用户看不到大多数工具调用和思考过程------只能看到你的文本输出。第一次调用工具前,用一句话说明你要做什么。工作过程中,在关键时刻给出简短更新:有发现时、改变方向时、遇到阻塞时。简短是好的------沉默不是。每次更新一句话几乎总是足够。

会话专属指导

这部分稍杂,主要是每个会话随配置不同而不同。但内容实际是agent并行与次数以及shell和skill的指导等


然后是记忆部分,本文省略


环境信息

一些杂七杂八的环境信息:

markdown 复制代码
# 环境
你被调用时所处环境如下:
 - 主工作目录:/Users/rayxiang/develop/hyyc-demo
 - 是否为 git 仓库:true
 - 平台:darwin
 - Shell:zsh
 - 操作系统版本:Darwin 25.0.0
 - 你由名为 Sonnet 4.6 的模型驱动。确切的模型 ID 是 claude-sonnet-4-6。
 - 助手知识截止日期:2025 年 8 月。
 - 最新的 Claude 模型家族为 Claude 4.X。模型 ID------Opus 4.7:'claude-opus-4-7',Sonnet 4.6:'claude-sonnet-4-6',Haiku 4.5:'claude-haiku-4-5-20251001'。构建 AI 应用时,默认选用最新、最强的 Claude 模型。
 - Claude Code 可通过终端 CLI、桌面应用(Mac/Windows)、网页应用(claude.ai/code)和 IDE 扩展(VS Code、JetBrains)使用。
 - Claude Code 的快速模式使用 Claude Opus 并加快输出(不会降级到更小的模型)。可用 /fast 切换,支持 Opus 4.6 和 Opus 4.7。

上下文管理

bash 复制代码
# 上下文管理
当对话变长时,当前上下文的部分或全部会被摘要;摘要连同剩余未摘要的上下文会进入下一个上下文窗口,工作可以继续------你不需要提前收尾或在任务中途交接。

为什么要对模型提示这个呢?我猜是对模型本身的纠偏。可能anthropic发现,在上下文快满的时候,模型自动去收尾任务是一个默认的预训练行为。

提示词的指示

以上就是全部核心提示词的结构了。我们能从中学到些什么呢?

结构

我认为所有的agent系统提示词,都可以按这个模板来进行抄:

  1. 背景、角色、目标定义:背景板,把底色定好
  2. 系统指导:定义底层行为,元规则,靠前可以纠正底层的模型行为,记忆保持度高。
  3. 业务流程:主要的场景业务规则和注意项
  4. 业务额外指导:安全?谨慎?
  5. 工具、语气、格式、环境等额外的信息

写法

绝大部分的提示词教程都只会讲要写清楚目标,定角色等很通用的技巧。但是通过读claude code的提示,我们会发现他写出来的提示与一般提示会有一种语气上的差别:好像是一种对人的谆谆教诲一样。

其中我认为有两种特征特别值得学习:

交待原因: 类似你在教一个新人做事,不只是教他该怎么做,还得告诉他,为什么这么做。要将为什么这么指令,背景是什么,讲出来。

arduino 复制代码
 - 工具调用前不要用冒号。你的工具调用可能不会直接显示在输出中,所以"让我读一下文件:"后跟读取调用这种写法,应改为"让我读一下文件。"(句号结尾)。

**交待后果:**不只说要如何做,还要讲这样做会有什么样的结果。

复制代码
写更新时,要让读者能冷启动接上:完整的句子,不出现会话前文里未解释的行话或缩写。但要紧凑------一个清晰的句子好过一个清晰的段落。

核心工具集

要让agent在特定环境下能工作,核心工具集的设计至关重要。

工具必须能表达在场景下,最高频的的工作场景,并且为了这些场景针对安全、效率进行优化。

来看claude code有哪些关键的工具。(剔除任务、计划等高级的辅助工具)

  • 文件读取和操作:Read 读文件, Write 写文件, Edit 编辑文件
  • 查找:Glob 找文件, Grep 找文件内容
  • 执行:Bash 命令行工具

基本上,这些就是一个编程工具所需的最小工具集了,其他都是补充。为啥要用这些,而不是直接用bash一把梭呢?我觉得设计者有其深入的考虑。

Read

读是一切的起始。与使用cat等bash相比,Read在于工具层面约定了一个契约:行号。读取工具输出时附带了行号,同时在提示词中,也告诉了模型如何针对行号来理解。因此后续的编辑和增量读取可以直接以此为基准。这是与cat等bash等工具的主要差别和优化点。

**多模态:**read工具直接将多模态内置了,这可以让agent统一读取入口,减少工具歧义与调用复杂性

**异常行为兜底:**例如,读取已经读取过的文件、读取空文件、读到不存在的文件,这些行为都被预置好并与模型形成契约。这些行为是读取过程中极有可能发生的,在工具中进行定义而不是走bash的错误,可以让模型从语义了解到情况。

**边界与安全:**不允许相对路径,不走shell(避免转义等问题),强制约定的边界可以减少错误的发生

Read工具是相对来说比较简单的,因为不改内容,因此安全的风险较低。

Edit

编辑操作是所有最终操作落实的地方,但是改动是高危行为,因此Claude code做了很精细的防护。

Edit工具的核心过程可解释为:将old_string替换为new_string,并区分是全局替换还是只换一个(这俩故意设置了差别,便于处理异常情况)。

为啥不使用基于位置的编辑而是使用基于内容的编辑呢?基于位置是直观的方案设计。例如:将位于xxxx位置开始,长度为20的字符串替换为"xxxx"。

使用基于位置的编辑会有几个问题。第一,位置是数字,这对模型来说数学计算很麻烦,那么输出工具结果的时候就不一定能稳定。第二,处理失败异常更稳定。替换原始中存在的字符串,如果被改了,那必失败。但根据位置编辑,任何时间都可能成功,静默失败了。第三是可读可审计性。字符串被替换,更容易语义理解容易审计。

基于old string的写入策略兜底方案

Edit工具使用内容替换为策略,便可对写入结果进行进一步的保护。

  • 如果old_string在原文件中没找到,那么会直接报错。这就保护了未知的字符串写入。相对的,如果使用位置坐标写入,那么这样的错误就会被吃掉。
  • 如果olde_string找到多处,但是match_all没开,那么也会报错。 错误信息便可引导模型纠错:要么扩大上下文唯一匹配,要么全量替换。

这两项是使用位置策略很难做到的。策略一换,兜底方案复杂度大幅上升。工具的实现策略也是agent设计的重要考量。

先读后改机制

所谓的Harness,本质就是防备模型输出的随机性。

编辑过程的一个重要问题是,改到了根本不存在的内容怎么办,或者在改的过程中文件内容被更改了怎么办。由于模型本身的输出就不稳定,这种情况是必须防备的。edit工具强制要求先读后改并通过多层的保护达到这个效果。

  • 模型提示中首先有这样的要求,那么如果文件已经在消息记录中读过才能继续走,否则直接失败。
  • 紧接是直接对比读取时间最新变更时间差,如果与已记录的变更时间有差别则直接拒绝要求重读
  • 检查过了也不算完,最后在单线程临界区内(无await)窗口内完成读取+写入兜底
  • 即便如此,文件也还有历史记录功能(一个重要的辅助组件),写错了也能恢复。

整体目标就是为了写入时保证文件是最新的。

Write

Write是单独的一个工具,核心思路可理解为:将目标文件的所有内容替换为新内容或创建文件。

write为什么不与Edit共享同一个工具呢?只需要添加一个参数,即可统一来少一个工具,而且处理过程也有部分的相似,这也十分符合程序的思维逻辑。事实上,确实也有人是这么干的。这里我们不评判谁对谁错,重点是,从Anthropic的实现过程来思考和反推一下当时他们做这里的时候,有哪些考量。

想象一下,如果合并会怎样?工具的调用模式一定会变成这样:

c 复制代码
old_string?: string   // rewrite 模式不需要
new_string?: string   // edit 必需
mode?: 'edit' | 'rewrite'

好处明显有:

  • 更少的工具,意味着更少的上下文提示,模型做工具选择复杂度明为降低。这是最明显的收益。
  • 从语义和逻辑上讲,统一的表达也更容易理解

但代价是什么?

  • 从业务上看,关键问题在于,"改一小段还是重写全文",这个业务决策的边界,到底是大还是小?对模型的决策点,到底是工具选择还是参数调整?从逻辑上看,把决策放在工具选择上对于模型的认知负担明显会更小一些。
  • 从提示工程的经验(体现在遥测的注释里),选对工具的可靠性远高于写对参数组合

从工程化的角度来看,错误代价是一个很好的视角。

  • 如果模型选错了工具,那么会有明显的结构化失败和错误行为,容易被发现、审计、优化
  • 另一种情况是,模型可能只是填错了参数。原本需要编辑,但使用了rewrite来进行全覆写。虽然仍能达到目标,语法上也合法,但是diff巨大,token浪费,而且更容易发生顺手改进或引入别的错误,还极难发现。

从复杂度的角度来讲,由于Edit是明显更高频的场景,单抽一个工具进行处理,可以将复杂性处理收缩在工具内部。分开还可以对权限规则,流程进行单独的记录、审计。那么合并,会扰乱审计的路径:原本各是各的路,现在必须增加一系列功能+参数的判断。

write和edit的兜底差异

write和edit有相当部分的兜底机制是共享的:hook路径展开、团队记忆密钥扫描、强制先读后改、两段式mtime陈旧检测等等。

但是edit的处理机制明显更复杂更精细: 为了让手术刀式的编辑更好的生效。

  • 匹配校验,必须编辑已经存在的串
  • 引号归一化,处理模型可能给出不同的引号的问题
  • 文件类型守卫:.ipynb 拒绝并导向 NotebookEdit

glob

glob的核心作用是,按文件名或文件名的模式,去找到文件。

对应场景需求:agent在编辑文件之前,需要先根据需求和目标,找到并理解对应的文件。

glob工具底层使用的是ripgrep(一个grep工具的升级版,rust写的,性能比grep工具好)。底层实际是:

css 复制代码
rg --files --glob '<模式>' --sort=modified --no-ignore --hidden --glob '!<deny目录>' ...

相当于使用ripgrep的列举文件模式来当成这个工具的底层引擎。

为什么不用bash的find或ls?可能的问题有这些:

  • find没有办法限制输出长度,可能输出上万上百万都有可能。这是find这个工具的硬限制。
  • find无序,rg可以按mtime排序,便于将近期修改的文件排前面
  • find意味着要走bash工具,那么转义可能出错、语义复杂不便于用户识别

总之,对于glob这样的超高频任务场景,使用专用的工具明显收益要高的多。

GREP

grep底层也用的是rg。但区别glob,grep工具将rg的全量参数全部封装了。相当于直接将rg这个程序直接喂给了模型。

为什么不直接将程序丢给模型让模型来调,或者直接让模型来走bash调?答案是,对于这个高频场景来说,内部需要进行一些处理来兜底和优化,从而保证这个过程的高效与顺畅。

  • 参数实际上就是rg的参数。因此保留了rg的全部能力,但是结构化的参数可以防止注入和转义错误
  • 对输出内容进行了约束和限制,默认只给文件名,避免上下文压爆
  • 封装分页。底层本身是支持分页的,这里做一次封装,将分页能力显式放给模型,并且给出明显的截断信号:show results with pagination。语义更明确
  • 增加安全兜底,如果模型给出的pattern是以-开头的,还要加上-e防注入

问题:参数已经说明了,为什么还要在工具说明里再说各种参数该怎么说

一个工具设计的哲学

如果你看grep工具的提示词,可能会有一个疑问:关于工具schema,也就是各参数如何使用和含义,在schema提示里面已经有了。为什么工具本身的提示词里面还有这么多?再看edit工具的提示,里面就没有类似的关于参数的说明,更多是关于工具本身的使用场景。

这就引出了一个工具设计的哲学与原则:

  • agent的系统提示词:管工具间的部分,例如工具间有差异、使用场景的区分等
  • 工具描述工具的工作场景与使用方式:啥时候,怎么用
  • schema管参数的含义,类型与取值,异常情况等

对于模型来说,选工具是看描述,填参数时看注解。

但是如果存在deferr模式,也就是初始只发送工具描述(claude就有这套东西)时,而这个工具又比较复杂:某些参数的差别会影响工具的使用场景。例如grep工具中,使用glob参数与否,面对的使用情况不一样。这时这部分的描述就有必要填充到工具描述中去。

再一个就是涉及到多参数之间的关系时,参数说明也有必要提到工具说明上去,例如这一段:"By default patterns match within single lines"。

总而言之,凡是涉及到如何、何时使用这个工具的描述,都应该提到工具说明中去。

提示词中有一段,Use ${AGENT_TOOL_NAME} tool for open-ended searches requiring multiple rounds。那么,会不会发生循环委派呢?claude又是如何兜底这种情况的?

事实上,如果不做限制,我认为这种情况极有可能会发生:agent派生使用系统提示词并附加grep和agent工具。这时,agent接到搜索任务,也认为属于复杂搜索,根据提示继续派生agent,无限循环。

来看claude是如何防备的。

  • 首先explore agent,它的定义中直接就diable掉了agent tool,因此他直接就不能再派智能体了
  • 提示词If you ARE the fork --- execute directly; do not re-delegate. 对本体进行声明,这是软约束
  • 遥测数据中有depth,每加一层深度,都会被遥测捕捉到,这是后手。

总结

总结一下一些核心的原则和应该注意的地方:

  • 将业务的核心的操作工具化,并与模型主提示词形成契约,同时管理模型与工具的行为边界和可读性,从而形成了一套针对业务的生态(或许就是harness)。
  • 对于高频场景,应该抽象为专用工具。
  • 对于工具,需要从底层机制、应用场景来了解各种边界。对边界作出防御。
  • 要注意很小的异常行为:模型可能输出任务东西,很可能是貌似正确但有细微差别的结果,流程没错,但是对结果有影响。
  • 必须做好遥测体系,针对场景、工具调用、中间错误进行统计和审计,这样才能知道实际运行中会错在哪里,高频的结果是什么。
  • 对于工具的异常行一般的三层兜底策略:软一层,提示词上加限制;硬一层,对工具实际的输入、输出、执行做检查;后手捕一层,做遥测,捕获分析行为结果,定期优化,ab测试。
相关推荐
冬奇Lab3 小时前
一天一个开源项目(第234篇):CC Switch —— 一个 App 管理十款 AI 编程工具的 Provider、MCP、Skills 和 Prompts
人工智能·开源·claude
曹小强wxx9 小时前
让 AI 写代码不“翻车”:用 Claude Code + Codex 给 Flutter 项目搭一套工程规范
flutter·ai编程·claude
乘风gg15 小时前
Spec Kit vs OpenSpec vs Superpowers:三大 AI Coding 框架深度对比
前端·ai编程·claude
bazingaedward2 天前
别让 AI Agent 碰到你的 API Key:给 Claude Code 做一个"只给名字、不给值"的密钥层
agent·claude
江屿风2 天前
【Plain Language Large Model】【理清常见国内外大模型的定位和特长】流食般投喂
人工智能·gpt·claude·glm·gemini·千问·deepseek
jerrywus3 天前
用了Pi基本就回不去了, 如果你也在用Pi, 强烈推荐安装pi-chrome
agent·claude·cline
灵感__idea3 天前
火遍全球的Claude Code是怎样炼成的?
aigc·ai编程·claude
AI日报派送佬3 天前
2026年10月9日AI行业日报|谷歌推出企业级Gemini通用智能体、Claude双功能重磅更新、AI视频创作成本低至0.09元/秒
人工智能·openai·claude·ai视频·anthropic·ai日报·workbuddy
一缕82年的清风3 天前
从Cursor杀向命令行:当AI接管终端,为什么资深架构师反而很少开IDE了?
claude·cursor·gemini