首页/新闻资讯/正文详情

手搓Claude Code-第十章 system_prompt:从零构建可复用的系统提示词配置骨架

发布时间:2026/9/26 10:11:31 来源:云帆数科 栏目:资讯中心
手搓Claude Code-第十章 system_prompt:从零构建可复用的系统提示词配置骨架
1. 为什么你的 Agent 越跑越“健忘”从一段膨胀的 system_prompt 说起如果你写过最基础的 LLM Agentsystem_prompt 大概率就是一行字符串告诉模型它是谁、当前工作目录在哪、用 bash 解决问题。这个阶段很舒服改一行重启一次行为完全可预期。但当你开始给 Agent 加能力——读文件、写文件、子 Agent、技能库、记忆、上下文压缩——这个字符串会像滚雪球一样膨胀。我见过最夸张的一个版本启动时拼了 3000 多 token 的 system_prompt里面塞了技能目录、记忆索引、待办列表、用户偏好甚至还有一段“当用户说 remember 时要提取记忆”的元指令。问题不在于长而在于它只在程序启动时拼一次。用户第一句话是“帮我格式化代码”你注入了“用户偏好 Tab 缩进”的记忆这很合理。但用户第二句话变成“顺便读一下 README”跟缩进毫无关系那段记忆还赖在 prompt 里占 token。用户中途加载了一个新 skillprompt 里没有这个 skill 的说明。用户做完了 todo 的前两项prompt 里还显示“5 项待办全 pending”。这就是本章要解决的核心问题system_prompt 不应该是启动时的一次性快照而应该是每轮对话前后重新评估的上下文投影。换句话说prompt 的组装过程本身要工程化要能跟着会话状态走。这一章交付的东西很具体一个可复用的 system_prompt 配置骨架包含角色定义、工具约束、上下文注入三段结构一套 context 字典的维护逻辑以及在 Claude Code 里加载验证的具体动作。适合已经写过基础 Agent、正在被 prompt 膨胀困扰的 LLM Agent 开发者。下面所有代码都可以直接抄进你的项目里跑。2. 前置准备TaoToken 接入与 Claude Code 环境在动手改 system_prompt 之前得先有一个能稳定调用的模型入口。我这边用的是 TaoToken 的 API 网关它兼容 Anthropic 的 Messages 接口Claude Code 和自写的 Agent 都能直接接。你需要准备两样东西一个 API Key以及把 base_url 指向 TaoToken 的 API 地址。API Key 在控制台里生成地址是https://taotoken.net/api-keys生成后复制出来后面配置环境变量要用。环境变量这样设export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_AUTH_TOKEN你的API Key注意这里有个坑如果你本地同时装了官方 Anthropic SDK它可能会优先读ANTHROPIC_API_KEY而不是ANTHROPIC_AUTH_TOKEN。稳妥的做法是在代码里显式判断如果检测到ANTHROPIC_BASE_URL被设置过就把ANTHROPIC_AUTH_TOKEN清掉避免两个 token 打架。这个逻辑在后面的完整代码里会体现。如果你更想先验证模型通不通可以直接用模型对话页面发一条消息试试地址是https://taotoken.net/models。确认能正常返回之后再进入下面的配置环节。3. 可复制的 system_prompt 配置骨架3.1 三段式结构identity / tools / context先把骨架定下来。整个 system_prompt 由三部分组成第一段是identity角色定义相对静态写死在一个PROMPT_SECTIONS字典里。第二段是tools当前启用了哪些工具从 context 里动态取。第三段是context工作目录、相关记忆、待办状态等同样从 context 里动态取。用一句话概括prompt prompt_section context。prompt_section 是静态骨架context 是动态血肉。import os import json from pathlib import Path WORKDIR Path.cwd() MEMORY_INDEX WORKDIR / .memory / MEMORY.md PROMPT_SECTIONS { identity: ( You are a coding agent. Solve tasks by reading, writing, and executing code. Prefer minimal, verifiable changes. When the user says remember, extract it as a memory. ), } TOOL_HANDLERS { read_file: lambda path: Path(path).read_text(), write_file: lambda path, content: Path(path).write_text(content) or ok, list_dir: lambda path.: \n.join(os.listdir(path)), }PROMPT_SECTIONS里目前只有 identity 一段这是故意的。后续你要加“技能说明”“安全约束”这类相对固定的段落都往这个字典里塞组装函数不用改。3.2 context 字典会话状态的快照context 是这一章的核心数据结构。它记录当前会话的状态启用了哪些工具、加载了哪些记忆、工作目录在哪。每轮工具调用结束后从最新的 messages 里推断出新的 context再重新拼 prompt。def update_context(context: dict, messages: list) - dict: 根据当前 messages 重建 context 快照。 memories if MEMORY_INDEX.exists(): content MEMORY_INDEX.read_text().strip() if content: memories content return { enabled_tools: list(TOOL_HANDLERS.keys()), workspace: str(WORKDIR), memories: memories, }这里enabled_tools和workspace目前是写死的memories会随.memory/MEMORY.md文件变化而更新。这就是骨架的意义结构先立住具体哪些字段动态化后面按需补。3.3 组装函数与缓存避免每轮重复拼组装函数接收 context返回最终 prompt 字符串。但这里有个性能细节如果 context 没变没必要每轮都重新拼一遍。所以加一层缓存用 context 的 JSON 序列化结果作为 key。_last_context_key None _last_prompt None def get_system_prompt(context: dict) - str: global _last_context_key, _last_prompt key json.dumps(context, sort_keysTrue, ensure_asciiFalse, defaultstr) if key _last_context_key and _last_prompt: print( \033[90m[cache hit] system prompt unchanged\033[0m) return _last_prompt _last_context_key key _last_prompt assemble_system_prompt(context) loaded [identity, tools, workspace] if context.get(memories): loaded.append(memory) print(f \033[32m[assembled] sections: {, .join(loaded)}\033[0m) return _last_prompt def assemble_system_prompt(context: dict) - str: sections [PROMPT_SECTIONS[identity]] tools ,.join(context.get(enabled_tools, [])) if tools: sections.append(fAvailable tools: {tools}.) sections.append(fWorking directory: {context.get(workspace, WORKDIR)}) memories context.get(memories, ) if memories: sections.append(fRelevant memories:\n{memories}) return \n\n.join(sections)json.dumps的三个参数值得说一下sort_keysTrue保证相同内容产生相同字符串不受字典顺序影响ensure_asciiFalse保留中文不转义成\uXXXXdefaultstr兜底遇到无法序列化的对象直接转字符串防止报错。3.4 agent_loop两个注入节点最后把组装逻辑接进主循环。关键只有两个节点循环开始时拿一次 prompt每轮工具调用处理完后更新 context 再拿一次。def agent_loop(messages: list, context: dict): system get_system_prompt(context) while True: response client.messages.create( modelMODEL, systemsystem, messagesmessages, toolsTOOLS, max_tokens8000, ) messages.append({role: assistant, content: response.content}) if response.stop_reason ! tool_use: return results [] for block in response.content: if block.type ! tool_use: continue print(f\033[36m {block.name}\033[0m) handler TOOL_HANDLERS.get(block.name) output handler(**block.input) if handler else fUnknown: {block.name} print(str(output)[:200]) results.append({ type: tool_result, tool_use_id: block.id, content: output, }) messages.append({role: user, content: results}) context update_context(context, messages) system get_system_prompt(context)到这里骨架就完整了。你会发现它其实很朴素甚至有点“写死”——但正是这种朴素让动态注入的边界变得清晰哪些字段该跟着会话走哪些字段暂时固定一眼能看出来。4. 在 Claude Code 中加载并验证4.1 启动与首次组装把上面的代码存成s10_system_prompt/code.py在项目根目录跑起来。第一次进入交互时你会看到类似这样的输出[assembled] sections: identity, tools, workspace, memory s10 read the file code.py in s10_system_prompt read_file[assembled]这行日志是验证的关键。它告诉你这次拼 prompt 时加载了哪几段。如果.memory/MEMORY.md存在且有内容memory会出现在列表里如果文件不存在或为空就只有前三段。4.2 缓存命中验证紧接着发第二条指令比如“列出当前目录”。如果 context 没有变化你会看到[cache hit] system prompt unchanged这说明缓存生效了没有重复组装。这一步很重要因为如果每轮都重新拼长会话下 token 消耗和延迟都会上去。4.3 记忆注入验证现在往.memory/MEMORY.md里写一行内容比如“用户偏好 Tab 缩进”。再发一条指令观察日志[assembled] sections: identity, tools, workspace, memorymemory段被重新加载了说明update_context读到了文件变化缓存 key 变了触发了重新组装。你可以让模型复述一下当前 system_prompt 里包含哪些记忆确认注入真的生效。4.4 工具约束验证把TOOL_HANDLERS里删掉一个工具比如去掉write_file重启后再发指令。日志里的tools段会少一个工具名模型也不会再尝试调用被删掉的工具。这就是工具约束段的作用prompt 里声明了什么模型就只在这个范围内行动。5. 本篇常见错排查报错一ANTHROPIC_AUTH_TOKEN和ANTHROPIC_API_KEY冲突返回 401。原因通常是本地同时存在两个环境变量SDK 读了错误的那个。解决方式是在代码入口处显式清理if os.getenv(ANTHROPIC_BASE_URL): os.environ.pop(ANTHROPIC_AUTH_TOKEN, None)注意这行要放在load_dotenv之后、创建 client 之前。报错二json.dumps抛TypeError: Object of type XXX is not JSON serializable。说明 context 里混进了自定义对象。检查update_context的返回值确保所有字段都是字符串、列表或字典。如果确实需要放对象靠defaultstr兜底但更推荐在源头就转成可序列化类型。报错三日志一直显示[assembled]从不[cache hit]。说明 context 每轮都在变。最常见的原因是update_context里返回了带时间戳或随机数的字段或者memories每次读文件都带上了不同的空白字符。用strip()清理并检查是否有字段在无意义地变化。报错四模型不调用工具直接返回文本。先看日志里tools段有没有正确列出工具名。如果enabled_tools为空assemble_system_prompt会跳过工具段模型自然不知道有工具可用。检查TOOL_HANDLERS是否在update_context之前就定义好了。报错五改了PROMPT_SECTIONS但行为没变。缓存 key 只基于 context不包含PROMPT_SECTIONS。如果你改了静态段落需要重启进程或者把PROMPT_SECTIONS的版本号也纳入 key 的计算。6. 下一步把骨架接进你的真实项目这套骨架跑通之后你会发现它最大的价值不是代码本身而是把“prompt 里该放什么”这个问题从玄学变成了工程问题。identity 段回答“我是谁”tools 段回答“我能用什么”context 段回答“我现在知道什么”。三段各司其职动态的部分走 context静态的部分走 PROMPT_SECTIONS。如果你打算长期做编码类 Agent建议把 API Key 和接入配置固定下来用 Coding Plan 这类长期方案管理调用额度地址是https://taotoken.net/coding-plan。接入文档在https://taotoken.net/doc里面有 Messages 接口的完整参数说明对照着调max_tokens和tools字段比较方便。后续章节大概率会继续补update_context里那些写死的字段——比如让enabled_tools跟着技能加载动态变让workspace跟着子 Agent 切换。骨架已经立住了往里填肉就是时间问题。

相关推荐

量化因子筛选实战:相关性去重与RFE递归特征消除
量化因子筛选实战:相关性去重与RFE递归特征消除

做量化策略的时候,我经常遇到一种尴尬:因子库越堆越厚,可模型效果不升反降。一开始我以为是模型不够强,后来把特征相关性矩阵打出来看,才发现有一堆"换皮"特征——动量类指标换了周期就再算一遍,… · 2026/9/26 10:11:25

研究生英语综合教程上配套资源:课后答案、课文翻译与听力音频全解析
研究生英语综合教程上配套资源:课后答案、课文翻译与听力音频全解析

1. 这套资源到底解决了什么问题第一次拿到《研究生英语综合教程 上》的配套资源时,我正帮一个师弟整理考博英语的复习材料。他手里只有一本纸质教材,课后习题的答案对不上,听力音频也找不到,更别提课文翻译和重点词汇的整理了。这… · 2026/9/26 10:11:25

JDK 17 安装与配置全指南:环境变量、多版本共存与避坑实战
JDK 17 安装与配置全指南:环境变量、多版本共存与避坑实战

1. 为什么 JDK 17 值得单独写一篇安装配置指南JDK 17 是 Java 生态里一个绕不开的版本。它是继 JDK 8 和 JDK 11 之后的又一个长期支持版本,官方会持续提供安全更新和补丁,很多主流框架——Spring Boot 3.x、Spring Framework 6.x、Maven 的较新版本、Gr… · 2026/9/26 10:11:25

中兴光猫实战改造:桥接、SN/MAC与地区码修改全攻略
中兴光猫实战改造:桥接、SN/MAC与地区码修改全攻略

1. 中兴光猫实战改造的核心逻辑与准备工作1.1 为什么越来越多人折腾光猫运营商给的光猫,默认状态下就是个“黑盒”——路由模式、自带WiFi、远程管理全开,用户能碰的只有表面那点设置。但实际用下来问题不少:光猫拨号再转发一层,N… · 2026/9/26 12:00:42

Java连接MySQL全攻略:从JDBC驱动原理到排查实战
Java连接MySQL全攻略:从JDBC驱动原理到排查实战

做 Java 后端这几年,我见过太多新人在第一道坎上摔跟头:Java 怎么连 MySQL?网上教程良莠不齐,照着抄一遍,有人报 ClassNotFoundException,有人被时区乱码折腾到怀疑人生,还有人连了半小时只看到… · 2026/9/26 12:00:42

C#代码复杂度警示录:20个真实案例揭示如何编写更简洁、可维护的代码
C#代码复杂度警示录:20个真实案例揭示如何编写更简洁、可维护的代码

作为C#开发者,我们都希望编写干净、可维护且可扩展的代码。但即便怀着最好的初衷,也容易陷入让代码难以阅读、测试或扩展的模式。随着时间的推移,小的捷径可能演变成大的混乱——导致Bug频发、开发疲劳和系统脆弱。 本文将列举20个清晰的信号… · 2026/9/26 12:00:42

Notepad++可信安装指南:规避签名失效与中文路径崩溃
Notepad++可信安装指南:规避签名失效与中文路径崩溃

简介:本资源为Windows平台下开箱即用的Notepad 7.5.8官方安装包,面向程序员、Web开发者及轻量级文本编辑需求者,解决系统记事本功能单一、缺乏语法高亮与插件扩展能力的问题。压缩包为ZIP格式,大小13.2MB,内含完整安装… · 2026/9/26 12:00:42

RT-Thread 星火一号 STM32F407 BSP 开发指南:从快速上手到设备树驱动
RT-Thread 星火一号 STM32F407 BSP 开发指南:从快速上手到设备树驱动

操作系统嵌入式物联网嵌入式OSRTOS 【免费下载链接】rt-thread RT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/ 项目地址: https://gitcode.com/gh_mirrors/rt/rt-thread 点击查看 免费下载 本文围绕… · 2026/9/26 12:00:42

HTML+CSS+JS响应式网页源码实战避坑指南
HTML+CSS+JS响应式网页源码实战避坑指南

简介:这是一份面向Web前端初学者与中级开发者的意大利风味餐厅主题响应式网站HTML源码,适用于课程设计、毕业项目或小型商业站点快速搭建。资源采用纯HTML5CSS3JavaScript实现,无需后端依赖,完整呈现餐厅介绍、菜单展示、在线预约… · 2026/9/26 12:00:36

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21

OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40

向下兼容与向上兼容:接口设计中的兼容性策略与工程实践
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践

一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码