新闻详情

新闻详情

首页 / 资讯中心 / 详情

learn-claude-code -s10 实战:用 system prompt 与 json.dumps 构建可缓存的 agent 配置

发布时间:2026/9/29 21:43:08来源:尧图网络
learn-claude-code -s10 实战:用 system prompt 与 json.dumps 构建可缓存的 agent 配置
1. 为什么你的 Agent 每轮都在重复拼同一段 system prompt如果你正在跟着 learn-claude-code 的 s10 章节写 Agent大概率已经踩过这个坑system参数一开始是硬编码的字符串写着写着工具变多了、记忆文件加进来了、工作目录也要动态注入于是你开始用 f-string 拼字符串。跑起来没问题但每轮对话都在重新拼一遍哪怕这一轮的工具集、记忆状态、工作目录跟上一轮一模一样。问题的本质是system prompt 不是一段静态说明而是当前运行环境的配置快照。它应该反映此刻 Agent 到底有哪些工具、工作目录在哪、有没有加载记忆、是否处在特殊模式。硬编码会带来三个直接后果——可维护性差改工具描述可能误伤身份说明、不够动态没有.memory/MEMORY.md时还在告诉模型这里有记忆、浪费 token每轮都把所有能力说明塞进去无关内容还会分散模型注意力。s10 的解法是把 prompt 拆成多个可独立维护、按需加载、可缓存复用的 section再用json.dumps做稳定序列化来判断配置有没有变。这篇文章我会把 settings.json 骨架、TaoToken 统一 Key 接入、缓存命中验证动作完整走一遍你可以直接复制到自己的项目里跑。2. TaoToken 前置统一 Key 与 API 通道在动手改 prompt 之前先把模型调用通道固定下来。learn-claude-code 的示例默认走 Anthropic 的 messages 接口如果你本地同时试多个模型、多个项目Key 散落在各处会很乱。我的做法是统一走 TaoToken 的 API 通道一个 Key 覆盖对话和编码场景。你需要先拿到 Key打开 https://taotoken.net/api-keys 登录后创建一个 API Key复制保存。注意这个 Key 只在创建时完整显示一次丢了就重新建一个。拿到 Key 之后把它写进环境变量不要硬编码进代码export TAOTOKEN_API_KEYsk-你的key export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEY$TAOTOKEN_API_KEY这里有个细节learn-claude-code 的示例代码用的是anthropicSDK它默认读ANTHROPIC_API_KEY和ANTHROPIC_BASE_URL。把 base_url 指向 TaoToken 的 API 地址SDK 就会把请求发到统一通道你不用改任何业务代码。如果你用的是 Claude Code 这类命令行工具接入方式在 https://taotoken.net/doc 里有对应说明配置逻辑是一样的。注意base_url 只写到/api不要自己拼/v1/messages之类的路径SDK 会处理。3. 可复制的 settings.json 骨架与 prompt 组装代码先给一份 settings.json 骨架把模型、工具、prompt section 都外置成配置这样改工具描述不用动 Python 代码{ model: claude-sonnet-4-20250514, max_tokens: 8000, prompt_sections: { identity: You are a coding agent. Act, dont explain., tools: Available tools: bash, read_file, write_file., workspace: Working directory: {workspace} }, memory: { index_file: .memory/MEMORY.md, enabled: true } }workspace用占位符运行时替换成真实路径。接下来是核心的组装与缓存逻辑我按 s10 的思路整理成可直接跑的版本import json from pathlib import Path _last_context_key None _last_prompt None def load_settings(pathsettings.json): with open(path, r, encodingutf-8) as f: return json.load(f) SETTINGS load_settings() PROMPT_SECTIONS SETTINGS[prompt_sections] def update_context(context: dict, messages: list) - dict: 每轮工具调用后重新读取记忆文件刷新 context。 memory_file Path(SETTINGS[memory][index_file]) if SETTINGS[memory][enabled] and memory_file.exists(): content memory_file.read_text(encodingutf-8).strip() context[memories] content else: context[memories] return context def assemble_system_prompt(context: dict) - str: sections [] sections.append(PROMPT_SECTIONS[identity]) sections.append(PROMPT_SECTIONS[tools]) sections.append( PROMPT_SECTIONS[workspace].format(workspacecontext.get(workspace, .)) ) memories context.get(memories, ) if memories: sections.append(fRelevant memories:\n{memories}) return \n\n.join(sections) 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( [cache hit] system prompt unchanged) 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 [assembled] sections: {, .join(loaded)}) return _last_prompt这里最关键的一行是json.dumps(context, sort_keysTrue, ensure_asciiFalse, defaultstr)。三个参数各有用途sort_keysTrue保证{b:2,a:1}和{a:1,b:2}生成完全相同的字符串顺序不影响比较ensure_asciiFalse保留中文不转成\u7528\u6237让指纹可读defaultstr处理Path这类特殊对象避免序列化报错。为什么不用 Python 内置的hash()因为hash()有进程随机化同一个字典在不同进程里哈希值不同而且嵌套 dict/list 会直接报错。json.dumps生成的是纯文本指纹跨进程稳定嵌套结构也能处理。把组装逻辑接进 agent loop注意每轮工具调用后要重新评估 contextdef agent_loop(messages: list, context: dict): system get_system_prompt(context) while True: response client.messages.create( modelSETTINGS[model], systemsystem, messagesmessages, toolsTOOLS, max_tokensSETTINGS[max_tokens], ) 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 handler TOOL_HANDLERS.get(block.name) output handler(**block.input) if handler else fUnknown: {block.name} 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. 验证请求缓存命中与未命中的实际输出代码写完了怎么确认缓存真的生效最直接的办法是看控制台打印。第一次调用时 context 是全新的会走组装分支[assembled] sections: identity, tools, workspace紧接着再调一次context 没变应该命中缓存[cache hit] system prompt unchanged我实测下来连续两轮没有工具写入记忆时第二轮一定是 cache hit。一旦某个工具往.memory/MEMORY.md写了新内容update_context读到变化指纹就变了下一轮会重新组装并且 sections 里多出 memory[assembled] sections: identity, tools, workspace, memory如果你想更严谨地验证可以在get_system_prompt里加一行打印指纹长度或者把key写进日志文件对比。另一个验证角度是看 API 请求的 token 消耗缓存命中时你复用的是同一个字符串对象虽然发给模型的 token 数不变system prompt 本身还是要传但省掉了本地重复拼接的 CPU 开销更重要的是保证了 section 顺序稳定这对 API 层的 prompt cache 命中很关键。提示s10 的进程内缓存只避免重复字符串组装。真正的 API 级 prompt cache 还需要稳定的 section 顺序和动态边界标记Claude Code 官方用SYSTEM_PROMPT_DYNAMIC_BOUNDARY来区分静态段和动态段你可以把 identity、tools 这类不变内容放前面memory、workspace 放后面。5. 本篇常见错排查报错一TypeError: Object of type PosixPath is not JSON serializable原因是你往 context 里塞了Path对象而json.dumps默认不认识。解决方法是加defaultstr它会调用str()把 Path 转成普通字符串。如果你塞的是自定义类也可以传一个 lambda 做转换。报错二缓存永远不命中每轮都打印 assembled先检查 context 里有没有每次都变的字段比如时间戳、随机 ID、请求计数。这些字段一变指纹就变。把它们从 context 里剔除或者单独放到不参与指纹计算的地方。另一个常见原因是字典键顺序不稳定虽然sort_keysTrue能解决但如果你在别处手动拼了字符串再塞进 context顺序就乱了。报错三记忆更新了但 prompt 没变检查update_context是不是在每轮工具调用后都执行了。s10 的 loop 里context update_context(context, messages)和system get_system_prompt(context)必须放在messages.append之后、下一轮client.messages.create之前。漏掉这一步记忆文件改了也不会重新读取。报错四中文记忆内容变成\uXXXX这是ensure_ascii默认True导致的。加上ensure_asciiFalse就能保留中文。注意这个参数只影响序列化后的可读性不影响比较结果但保留中文能让日志更好排查。报错五多进程下缓存失效_last_context_key和_last_prompt是模块级全局变量只在单个进程内有效。如果你用多进程跑 Agent每个进程有独立的缓存这是正常的。跨进程共享缓存需要外部存储但通常没必要因为进程内缓存已经能覆盖大部分重复组装场景。6. 把通道和缓存一起固定下来到这里你的 Agent 应该已经能做到context 不变时复用 system promptcontext 变化时按需重新组装并且所有模型请求都走统一的 Key 和 API 通道。这套组合的价值在于你把配置快照和调用通道两件事都从业务代码里解耦出来了。接下来可以做的验证动作跑一轮带工具调用的对话观察控制台先出现[assembled]工具执行后如果没写记忆下一轮出现[cache hit]手动往.memory/MEMORY.md追加一行再跑一轮应该看到[assembled] sections: identity, tools, workspace, memory。如果这三步都符合预期说明缓存逻辑和记忆刷新都接对了。模型对话调试可以直接在 https://taotoken.net/model-chat 里对比不同 system prompt 的效果长期跑编码类 Agent 的话https://taotoken.net/coding-plan 里有按周期计费的方案比按量付费更适合高频调用接入文档和参数细节在 https://taotoken.net/doc 里能查到。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

STM32开发参考方案全攻略:从选型到调试实战 2026/9/29 22:41:08

STM32开发参考方案全攻略:从选型到调试实战

很多刚开始碰 STM32 的朋友,问的问题其实都差不多:手里有一块板子,想做个项目,但不知道怎么找参考方案;或者已经在开发了,遇到问题不知道上哪找靠谱的资料和平台。我自己这些年从标准外设库一路用到 HAL 库…

阅读更多 →
小店做AI获客?5步让客户主动搜到你 2026/9/29 22:41:08

小店做AI获客?5步让客户主动搜到你

小店做AI获客?5步让客户主动搜到你很多老板还没意识到,客户找服务的习惯已经变了——以前是翻平台一条条看,现在是直接问AI:"附近哪家修车靠谱?"AI推荐哪家,客户就去哪家。为什么现在是做AI获客的…

阅读更多 →
上海24小时自助健身房系统开发实战:从架构到部署全指南 2026/9/29 22:41:08

上海24小时自助健身房系统开发实战:从架构到部署全指南

上海24小时自助健身房系统开发实战:从架构到部署全指南 在健身行业数字化转型的浪潮中,上海等一线城市的24小时自助健身房模式逐渐成为主流。这类系统需要解决的核心问题包括:无人值守环境下的用户身份验证、设备控制、计费结算、远程监控以及…

阅读更多 →
windows搭建git服务器 2026/9/29 22:41:08

windows搭建git服务器

在 Windows 上自建 Git 服务器,最省心、最轻量的选择是 Gitea。它是一个用 Go 语言写的开源 Git 托管平台,界面和操作体验很像 GitHub,但只有一个可执行文件,对 Windows 环境非常友好 下面是在 Windows 上快速搭建 Gitea 的步骤&a…

阅读更多 →
作者有话说|AI编程入门:TaoToken统一Key接入Claude Code与Cursor的settings.json配置骨架 2026/9/29 22:41:07

作者有话说|AI编程入门:TaoToken统一Key接入Claude Code与Cursor的settings.json配置骨架

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

阅读更多 →
从Cline原理看AI Agent设计的一般范式:用TaoToken统一Key跑通ReAct与MCP配置 2026/9/29 22:41:01

从Cline原理看AI Agent设计的一般范式:用TaoToken统一Key跑通ReAct与MCP配置

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

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉