From decca30bef94894a71a178787b80e7ddbcbaa81e Mon Sep 17 00:00:00 2001
From: secret-deus <1263403710@qq.com>
Date: Sun, 12 Jul 2026 11:50:23 +0800
Subject: [PATCH] Sync KnowledgeBase notes from Nutstore WebDAV.
Replace demo notes with 146 vault notes and diagram assets; keep credentials only in local .env.
---
public/assets/MoE路由.svg | 79 +
public/assets/Multi-Head-Attention.svg | 90 +
public/assets/Transformer架构.svg | 131 +
public/assets/反向传播原理.svg | 108 +
public/assets/推理两阶段PrefillDecode.svg | 105 +
public/assets/残差与主干的分工.svg | 90 +
public/assets/残差连接详解.svg | 181 +
public/assets/注意力矩阵推导.svg | 120 +
public/assets/知识图谱.svg | 166 +
public/assets/训练三阶段.svg | 122 +
src/content/notes/02-Issues/502排查总结.md | 380 ++
.../Ingress_reload_失败_health_api-tpa.md | 281 ++
.../阿里云NAT网关SNAT入方向流量异常排查.md | 437 ++
.../notes/04-Snippets/Nginx-alias-vs-root.md | 119 +
.../06-Tasks/迁移自建Nacos到MSE-优化方案.md | 327 ++
.../notes/06-Tasks/迁移自建Nacos到MSE.md | 847 ++++
.../07-定义Agent-从提示词工程到人设工程.md | 142 +
.../08-定义Task-从步骤控制到契约驱动.md | 129 +
.../09-定义Process-任务调度与信息传递.md | 154 +
.../10-多模态模型-让你的Agent拥有眼睛.md | 150 +
.../11-项目实践一-小红书爆款笔记生成项目.md | 146 +
...具设计哲学-从API到Agent-Native的范式跃迁.md | 16 +
...3-自定义工具封装-构建Tools的五步标准SOP.md | 302 ++
.../14-MCP协议-标准化定义工具接口.md | 186 +
.../15-王牌超能力-代码解释器与无头浏览器.md | 157 +
.../16-Skills生态-让Agent接入大量工具.md | 211 +
...目实战2-能力篇-XiaoPaw飞书本地工作助手.md | 207 +
...Prompt到Harness-记忆与上下文的设计范式.md | 181 +
...19-上下文的生命周期-Bootstrap剪枝与压缩.md | 247 +
.../Claude Code 从零构建 - 完整架构解析.md | 660 +++
.../Claude Code 从零构建 - 架构解析.md | 308 ++
.../07-Knowledge/Dev-Workflow Kit 学习笔记.md | 308 ++
.../How Claude Code Works - 姊妹项目概览.md | 114 +
.../00-introduction.md | 219 +
.../claude-code-from-scratch/01-agent-loop.md | 293 ++
.../claude-code-from-scratch/02-tools.md | 844 ++++
.../03-system-prompt.md | 422 ++
.../04-cli-session.md | 463 ++
.../claude-code-from-scratch/05-streaming.md | 663 +++
.../06-permissions.md | 648 +++
.../claude-code-from-scratch/07-context.md | 520 +++
.../claude-code-from-scratch/08-memory.md | 593 +++
.../claude-code-from-scratch/09-skills.md | 481 ++
.../claude-code-from-scratch/10-plan-mode.md | 697 +++
.../11-multi-agent.md | 578 +++
.../claude-code-from-scratch/12-mcp.md | 408 ++
.../claude-code-from-scratch/13-whats-next.md | 210 +
.../claude-code-from-scratch/14-testing.md | 607 +++
.../claude-code-from-scratch/CLAUDE.md | 10 +
.../claude-code-from-scratch/README.md | 302 ++
.../claude-code-from-scratch/_sidebar.md | 25 +
.../notes/07-Knowledge/go/Go 基础速查.md | 361 ++
.../gpu-cluster-ops/GPU 集群运维知识总览.md | 210 +
.../automation/GPU 驱动与固件管理.md | 679 +++
.../automation/集群自动化部署方案.md | 617 +++
.../hardware/GPU 服务器硬件选型指南.md | 403 ++
.../hardware/NVIDIA GPU 架构演进.md | 439 ++
.../hardware/NVLink 与 NVSwitch 拓扑详解.md | 396 ++
.../monitoring/DCGM 监控体系详解.md | 182 +
.../monitoring/GPU 集群可观测性方案.md | 744 +++
.../network/GPU 集群网络拓扑设计.md | 578 +++
.../network/NCCL 通信原理与调优.md | 202 +
.../network/RDMA 与 InfiniBand 详解.md | 438 ++
.../performance/GPU 集群性能调优指南.md | 766 ++++
.../scheduling/Device Plugin 与 DRA 对比.md | 494 ++
.../scheduling/GPU 资源分配与隔离策略.md | 170 +
.../scheduling/K8s GPU 调度机制详解.md | 647 +++
.../scheduling/Volcano 调度器实战.md | 170 +
.../storage/分布式文件系统选型.md | 122 +
.../storage/训练数据流水线设计.md | 523 +++
.../training/PyTorch 分布式训练实战.md | 493 ++
.../training/分布式训练框架对比.md | 263 ++
.../troubleshooting/GPU Xid 错误排查手册.md | 636 +++
.../troubleshooting/NCCL 通信故障诊断指南.md | 964 ++++
.../how-claude-code-works/01-overview.md | 459 ++
.../how-claude-code-works/02-agent-loop.md | 513 +++
.../03-context-engineering.md | 1033 +++++
.../how-claude-code-works/04-tool-system.md | 985 ++++
.../05-code-editing-strategy.md | 814 ++++
.../06-hooks-extensibility.md | 1230 +++++
.../how-claude-code-works/07-multi-agent.md | 1077 +++++
.../how-claude-code-works/08-memory-system.md | 699 +++
.../how-claude-code-works/09-skills-system.md | 546 +++
.../how-claude-code-works/10-plan-mode.md | 551 +++
.../11-permission-security.md | 986 ++++
.../12-user-experience.md | 833 ++++
.../13-minimal-components.md | 990 ++++
.../14-system-prompt-design.md | 3990 +++++++++++++++++
.../how-claude-code-works/15-task-system.md | 594 +++
.../how-claude-code-works/README.md | 253 ++
.../how-claude-code-works/_sidebar.md | 38 +
.../how-claude-code-works/quick-start.md | 340 ++
.../how-claude-code-works/reference.md | 102 +
.../k8s/K8s 1.28-1.36 版本更新总结.md | 313 ++
.../k8s/gateway-api/Gateway API 概述.md | 323 ++
.../k8s/gateway-api/HTTPRoute 核心能力详解.md | 924 ++++
.../versions/K8s 1.28 Planternetes 详解.md | 163 +
.../k8s/versions/K8s 1.29 Mandala 详解.md | 144 +
.../k8s/versions/K8s 1.30 Uwubernetes 详解.md | 154 +
.../k8s/versions/K8s 1.31 Elli 详解.md | 165 +
.../k8s/versions/K8s 1.32 Penelope 详解.md | 145 +
.../k8s/versions/K8s 1.33 Octarine 详解.md | 156 +
.../K8s 1.34 Of Wind and Will 详解.md | 175 +
.../k8s/versions/K8s 1.35 Timbernetes 详解.md | 180 +
.../k8s/versions/K8s 1.36 Haru 详解.md | 195 +
.../k8s/特性详解/API 网关流量管理.md | 369 ++
.../k8s/特性详解/ArgoCD GitOps 实战.md | 431 ++
.../k8s/特性详解/CEL 准入控制详解.md | 395 ++
.../k8s/特性详解/CNI 网络插件对比与排障.md | 295 ++
.../k8s/特性详解/DRA 动态资源分配详解.md | 339 ++
.../特性详解/Helm 与 Kustomize 配置管理.md | 377 ++
.../k8s/特性详解/In-place Pod 资源更新详解.md | 322 ++
.../k8s/特性详解/Istio 服务网格详解.md | 687 +++
.../k8s/特性详解/K8s 可观测性栈.md | 515 +++
.../k8s/特性详解/K8s 存储 GA 特性合集.md | 288 ++
.../k8s/特性详解/K8s 安全加固实战.md | 582 +++
.../k8s/特性详解/K8s 安全增强 GA 特性合集.md | 218 +
.../k8s/特性详解/K8s 故障排查方法论.md | 379 ++
.../特性详解/OCI Runtime 与镜像内部机制.md | 355 ++
.../OpenTelemetry Collector 深度运维.md | 491 ++
.../OpenTelemetry Instrumentation 实战.md | 579 +++
.../特性详解/OpenTelemetry 可观测性实践.md | 498 ++
.../k8s/特性详解/Pod 用户命名空间详解.md | 281 ++
.../Prometheus 存储引擎与高基数治理.md | 369 ++
.../k8s/特性详解/Sidecar 容器详解.md | 370 ++
.../k8s/特性详解/etcd 运维详解.md | 457 ++
.../07-Knowledge/k8s/特性详解/kagent 详解.md | 385 ++
.../k8s/特性详解/nftables kube-proxy 详解.md | 248 +
.../k8s/特性详解/容器运行时深度对比.md | 353 ++
.../k8s/特性详解/灰度发布与渐进式交付.md | 416 ++
.../linux/CPU 隔离与中断亲和性.md | 338 ++
.../07-Knowledge/linux/Linux 内核调优总览.md | 120 +
.../linux/NUMA 架构与亲和性调优.md | 245 +
.../07-Knowledge/linux/cgroup v2 详解.md | 250 ++
.../linux/大页内存与透明大页详解.md | 302 ++
.../07-Knowledge/linux/网络内核参数调优.md | 271 ++
.../2025-2026 前沿模型技术解析.md | 342 ++
.../llm-training/2025-2026 好用新技术全景.md | 862 ++++
.../llm-training/LLM 训练与推理流程.md | 960 ++++
.../llm-training/LLM 训练知识总览.md | 88 +
.../Tokenization 与 Embedding 详解.md | 756 ++++
.../llm-training/Transformer 架构基础.md | 887 ++++
.../llm-training/大模型架构对比.md | 496 ++
.../07-Knowledge/llm-training/显存计算详解.md | 199 +
.../07-Knowledge/llm-training/混合精度训练.md | 363 ++
.../07-Knowledge/mcp/MCP Server 工程实践.md | 478 ++
.../python/Python 运维开发实战.md | 603 +++
.../terraform/Terraform 基础设施即代码.md | 423 ++
.../terraform/Terraform 生产级实践.md | 472 ++
.../07-Knowledge/企业级多智能体设计实战.md | 136 +
src/content/notes/Obsidian-与本站.md | 52 -
src/content/notes/README.md | 46 +
src/content/notes/docs/06-permissions.md | 5 +
src/content/notes/交底书.md | 9 +
src/content/notes/写作约定.md | 47 -
...iroThinker-v1.5-30B Q5_K_M GGUF 的部署与调优.md | 249 -
src/content/notes/工作记录/2026-Q3-OKR.md | 26 +
.../工作记录/Bug追踪/OMS-appid处理问题.md | 84 +
src/content/notes/插件安装指南.md | 80 +
src/content/notes/欢迎.md | 10 -
160 files changed, 63591 insertions(+), 358 deletions(-)
create mode 100644 public/assets/MoE路由.svg
create mode 100644 public/assets/Multi-Head-Attention.svg
create mode 100644 public/assets/Transformer架构.svg
create mode 100644 public/assets/反向传播原理.svg
create mode 100644 public/assets/推理两阶段PrefillDecode.svg
create mode 100644 public/assets/残差与主干的分工.svg
create mode 100644 public/assets/残差连接详解.svg
create mode 100644 public/assets/注意力矩阵推导.svg
create mode 100644 public/assets/知识图谱.svg
create mode 100644 public/assets/训练三阶段.svg
create mode 100644 src/content/notes/02-Issues/502排查总结.md
create mode 100644 src/content/notes/02-Issues/Kubernetes/Ingress_reload_失败_health_api-tpa.md
create mode 100644 src/content/notes/02-Issues/Network/阿里云NAT网关SNAT入方向流量异常排查.md
create mode 100644 src/content/notes/04-Snippets/Nginx-alias-vs-root.md
create mode 100644 src/content/notes/06-Tasks/迁移自建Nacos到MSE-优化方案.md
create mode 100644 src/content/notes/06-Tasks/迁移自建Nacos到MSE.md
create mode 100644 src/content/notes/07-Knowledge/07-定义Agent-从提示词工程到人设工程.md
create mode 100644 src/content/notes/07-Knowledge/08-定义Task-从步骤控制到契约驱动.md
create mode 100644 src/content/notes/07-Knowledge/09-定义Process-任务调度与信息传递.md
create mode 100644 src/content/notes/07-Knowledge/10-多模态模型-让你的Agent拥有眼睛.md
create mode 100644 src/content/notes/07-Knowledge/11-项目实践一-小红书爆款笔记生成项目.md
create mode 100644 src/content/notes/07-Knowledge/12-工具设计哲学-从API到Agent-Native的范式跃迁.md
create mode 100644 src/content/notes/07-Knowledge/13-自定义工具封装-构建Tools的五步标准SOP.md
create mode 100644 src/content/notes/07-Knowledge/14-MCP协议-标准化定义工具接口.md
create mode 100644 src/content/notes/07-Knowledge/15-王牌超能力-代码解释器与无头浏览器.md
create mode 100644 src/content/notes/07-Knowledge/16-Skills生态-让Agent接入大量工具.md
create mode 100644 src/content/notes/07-Knowledge/17-项目实战2-能力篇-XiaoPaw飞书本地工作助手.md
create mode 100644 src/content/notes/07-Knowledge/18-从Prompt到Harness-记忆与上下文的设计范式.md
create mode 100644 src/content/notes/07-Knowledge/19-上下文的生命周期-Bootstrap剪枝与压缩.md
create mode 100644 src/content/notes/07-Knowledge/Claude Code 从零构建 - 完整架构解析.md
create mode 100644 src/content/notes/07-Knowledge/Claude Code 从零构建 - 架构解析.md
create mode 100644 src/content/notes/07-Knowledge/Dev-Workflow Kit 学习笔记.md
create mode 100644 src/content/notes/07-Knowledge/How Claude Code Works - 姊妹项目概览.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/00-introduction.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/01-agent-loop.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/02-tools.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/03-system-prompt.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/04-cli-session.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/05-streaming.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/06-permissions.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/07-context.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/08-memory.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/09-skills.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/10-plan-mode.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/11-multi-agent.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/12-mcp.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/13-whats-next.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/14-testing.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/CLAUDE.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/README.md
create mode 100644 src/content/notes/07-Knowledge/claude-code-from-scratch/_sidebar.md
create mode 100644 src/content/notes/07-Knowledge/go/Go 基础速查.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/GPU 集群运维知识总览.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/automation/GPU 驱动与固件管理.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/automation/集群自动化部署方案.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/hardware/GPU 服务器硬件选型指南.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/hardware/NVIDIA GPU 架构演进.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/hardware/NVLink 与 NVSwitch 拓扑详解.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/monitoring/DCGM 监控体系详解.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/monitoring/GPU 集群可观测性方案.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/network/GPU 集群网络拓扑设计.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/network/NCCL 通信原理与调优.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/network/RDMA 与 InfiniBand 详解.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/performance/GPU 集群性能调优指南.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/scheduling/Device Plugin 与 DRA 对比.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/scheduling/GPU 资源分配与隔离策略.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/scheduling/K8s GPU 调度机制详解.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/scheduling/Volcano 调度器实战.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/storage/分布式文件系统选型.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/storage/训练数据流水线设计.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/training/PyTorch 分布式训练实战.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/training/分布式训练框架对比.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/troubleshooting/GPU Xid 错误排查手册.md
create mode 100644 src/content/notes/07-Knowledge/gpu-cluster-ops/troubleshooting/NCCL 通信故障诊断指南.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/01-overview.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/02-agent-loop.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/03-context-engineering.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/04-tool-system.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/05-code-editing-strategy.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/06-hooks-extensibility.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/07-multi-agent.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/08-memory-system.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/09-skills-system.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/10-plan-mode.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/11-permission-security.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/12-user-experience.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/13-minimal-components.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/14-system-prompt-design.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/15-task-system.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/README.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/_sidebar.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/quick-start.md
create mode 100644 src/content/notes/07-Knowledge/how-claude-code-works/reference.md
create mode 100644 src/content/notes/07-Knowledge/k8s/K8s 1.28-1.36 版本更新总结.md
create mode 100644 src/content/notes/07-Knowledge/k8s/gateway-api/Gateway API 概述.md
create mode 100644 src/content/notes/07-Knowledge/k8s/gateway-api/HTTPRoute 核心能力详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/versions/K8s 1.28 Planternetes 详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/versions/K8s 1.29 Mandala 详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/versions/K8s 1.30 Uwubernetes 详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/versions/K8s 1.31 Elli 详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/versions/K8s 1.32 Penelope 详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/versions/K8s 1.33 Octarine 详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/versions/K8s 1.34 Of Wind and Will 详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/versions/K8s 1.35 Timbernetes 详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/versions/K8s 1.36 Haru 详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/API 网关流量管理.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/ArgoCD GitOps 实战.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/CEL 准入控制详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/CNI 网络插件对比与排障.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/DRA 动态资源分配详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/Helm 与 Kustomize 配置管理.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/In-place Pod 资源更新详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/Istio 服务网格详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/K8s 可观测性栈.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/K8s 存储 GA 特性合集.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/K8s 安全加固实战.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/K8s 安全增强 GA 特性合集.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/K8s 故障排查方法论.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/OCI Runtime 与镜像内部机制.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/OpenTelemetry Collector 深度运维.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/OpenTelemetry Instrumentation 实战.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/OpenTelemetry 可观测性实践.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/Pod 用户命名空间详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/Prometheus 存储引擎与高基数治理.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/Sidecar 容器详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/etcd 运维详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/kagent 详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/nftables kube-proxy 详解.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/容器运行时深度对比.md
create mode 100644 src/content/notes/07-Knowledge/k8s/特性详解/灰度发布与渐进式交付.md
create mode 100644 src/content/notes/07-Knowledge/linux/CPU 隔离与中断亲和性.md
create mode 100644 src/content/notes/07-Knowledge/linux/Linux 内核调优总览.md
create mode 100644 src/content/notes/07-Knowledge/linux/NUMA 架构与亲和性调优.md
create mode 100644 src/content/notes/07-Knowledge/linux/cgroup v2 详解.md
create mode 100644 src/content/notes/07-Knowledge/linux/大页内存与透明大页详解.md
create mode 100644 src/content/notes/07-Knowledge/linux/网络内核参数调优.md
create mode 100644 src/content/notes/07-Knowledge/llm-training/2025-2026 前沿模型技术解析.md
create mode 100644 src/content/notes/07-Knowledge/llm-training/2025-2026 好用新技术全景.md
create mode 100644 src/content/notes/07-Knowledge/llm-training/LLM 训练与推理流程.md
create mode 100644 src/content/notes/07-Knowledge/llm-training/LLM 训练知识总览.md
create mode 100644 src/content/notes/07-Knowledge/llm-training/Tokenization 与 Embedding 详解.md
create mode 100644 src/content/notes/07-Knowledge/llm-training/Transformer 架构基础.md
create mode 100644 src/content/notes/07-Knowledge/llm-training/大模型架构对比.md
create mode 100644 src/content/notes/07-Knowledge/llm-training/显存计算详解.md
create mode 100644 src/content/notes/07-Knowledge/llm-training/混合精度训练.md
create mode 100644 src/content/notes/07-Knowledge/mcp/MCP Server 工程实践.md
create mode 100644 src/content/notes/07-Knowledge/python/Python 运维开发实战.md
create mode 100644 src/content/notes/07-Knowledge/terraform/Terraform 基础设施即代码.md
create mode 100644 src/content/notes/07-Knowledge/terraform/Terraform 生产级实践.md
create mode 100644 src/content/notes/07-Knowledge/企业级多智能体设计实战.md
delete mode 100644 src/content/notes/Obsidian-与本站.md
create mode 100644 src/content/notes/README.md
create mode 100644 src/content/notes/docs/06-permissions.md
create mode 100644 src/content/notes/交底书.md
delete mode 100644 src/content/notes/写作约定.md
delete mode 100644 src/content/notes/在 RTX 5090 32GB 上用 Docker Compose + llama.cpp 运行 MiroThinker-v1.5-30B Q5_K_M GGUF 的部署与调优.md
create mode 100644 src/content/notes/工作记录/2026-Q3-OKR.md
create mode 100644 src/content/notes/工作记录/Bug追踪/OMS-appid处理问题.md
create mode 100644 src/content/notes/插件安装指南.md
delete mode 100644 src/content/notes/欢迎.md
diff --git a/public/assets/MoE路由.svg b/public/assets/MoE路由.svg
new file mode 100644
index 0000000..b111484
--- /dev/null
+++ b/public/assets/MoE路由.svg
@@ -0,0 +1,79 @@
+
\ No newline at end of file
diff --git a/public/assets/Multi-Head-Attention.svg b/public/assets/Multi-Head-Attention.svg
new file mode 100644
index 0000000..a93e090
--- /dev/null
+++ b/public/assets/Multi-Head-Attention.svg
@@ -0,0 +1,90 @@
+
\ No newline at end of file
diff --git a/public/assets/Transformer架构.svg b/public/assets/Transformer架构.svg
new file mode 100644
index 0000000..e8cf855
--- /dev/null
+++ b/public/assets/Transformer架构.svg
@@ -0,0 +1,131 @@
+
\ No newline at end of file
diff --git a/public/assets/反向传播原理.svg b/public/assets/反向传播原理.svg
new file mode 100644
index 0000000..b6e9c8c
--- /dev/null
+++ b/public/assets/反向传播原理.svg
@@ -0,0 +1,108 @@
+
\ No newline at end of file
diff --git a/public/assets/推理两阶段PrefillDecode.svg b/public/assets/推理两阶段PrefillDecode.svg
new file mode 100644
index 0000000..3c6e980
--- /dev/null
+++ b/public/assets/推理两阶段PrefillDecode.svg
@@ -0,0 +1,105 @@
+
\ No newline at end of file
diff --git a/public/assets/残差与主干的分工.svg b/public/assets/残差与主干的分工.svg
new file mode 100644
index 0000000..d92ec76
--- /dev/null
+++ b/public/assets/残差与主干的分工.svg
@@ -0,0 +1,90 @@
+
\ No newline at end of file
diff --git a/public/assets/残差连接详解.svg b/public/assets/残差连接详解.svg
new file mode 100644
index 0000000..63ae49c
--- /dev/null
+++ b/public/assets/残差连接详解.svg
@@ -0,0 +1,181 @@
+
\ No newline at end of file
diff --git a/public/assets/注意力矩阵推导.svg b/public/assets/注意力矩阵推导.svg
new file mode 100644
index 0000000..bc90cde
--- /dev/null
+++ b/public/assets/注意力矩阵推导.svg
@@ -0,0 +1,120 @@
+
\ No newline at end of file
diff --git a/public/assets/知识图谱.svg b/public/assets/知识图谱.svg
new file mode 100644
index 0000000..080e637
--- /dev/null
+++ b/public/assets/知识图谱.svg
@@ -0,0 +1,166 @@
+
\ No newline at end of file
diff --git a/public/assets/训练三阶段.svg b/public/assets/训练三阶段.svg
new file mode 100644
index 0000000..8b0979c
--- /dev/null
+++ b/public/assets/训练三阶段.svg
@@ -0,0 +1,122 @@
+
\ No newline at end of file
diff --git a/src/content/notes/02-Issues/502排查总结.md b/src/content/notes/02-Issues/502排查总结.md
new file mode 100644
index 0000000..5a94a88
--- /dev/null
+++ b/src/content/notes/02-Issues/502排查总结.md
@@ -0,0 +1,380 @@
+---
+title: "502排查总结"
+publish: true
+---
+
+# 502 排查总结
+
+## 1. 最初现象
+
+日志里看到:
+
+```text
+http_code: 502
+upstream_addr: health-ack
+upstream_response_time: 0.000
+upstream_connect_time: -
+upstream_header_time: -
+user_req: POST /portal/content/list HTTP/1.1
+```
+
+初步判断:**Nginx 没有从 upstream 拿到有效响应,所以返回 502**。
+
+---
+
+## 2. 确认 upstream 配置
+
+相关配置是:
+
+```nginx
+proxy_pass http://health-ack;
+
+upstream health-ack {
+ server 10.111.138.23:80 weight=50;
+ server 10.111.160.172:80 weight=50;
+}
+```
+
+另一个几乎一样的 upstream:
+
+```nginx
+upstream go-member-manager {
+ server 10.111.160.172:80 weight=50;
+ server 10.111.138.23:80 weight=50;
+}
+```
+
+因此一开始可以排除明显的 IP、端口配置错误。
+
+---
+
+## 3. 网络层验证
+
+`telnet` 正常,说明:
+
+```text
+Nginx -> 10.111.138.23:80
+Nginx -> 10.111.160.172:80
+```
+
+TCP 层是通的。
+
+所以不是:
+
+```text
+端口没开
+安全组拦截
+网络不通
+connect refused
+```
+
+---
+
+## 4. curl ingress 节点返回 404 的分支
+
+测试过:
+
+```bash
+curl http://10.111.138.23:80/portal/content/list
+```
+
+返回 404。
+
+一开始怀疑过 Ingress `Host` 没带导致 default backend 404,因为 Ingress 通常按 `Host + path` 匹配。后面确认实际域名是:
+
+```text
+api-health.qingsongjkkj.com
+```
+
+正确测试应该是:
+
+```bash
+curl -v -H "Host: api-health.qingsongjkkj.com" \
+http://10.111.138.23:80/portal/content/list
+```
+
+但后续根据数据看,这不是主因,因为问题不是大量 404,而是极少量 502。
+
+---
+
+## 5. 关键突破:异常日志里的 `$upstream_addr` 是 `health-ack`
+
+正常请求 upstream 会显示:
+
+```text
+10.111.138.23:80
+10.111.160.172:80
+```
+
+但异常 502 显示:
+
+```text
+upstream_addr: health-ack
+```
+
+然后确认 `log_format` 里确实是:
+
+```nginx
+$upstream_addr
+$upstream_response_time
+$upstream_connect_time
+$upstream_header_time
+```
+
+所以不是日志字段写错。
+
+Nginx 官方文档说明,`$upstream_addr` 正常记录 upstream server 地址;**如果没有选出 server,它会保留 upstream group 的名字**。因此 `upstream_addr = health-ack` 的含义不是"转发到了叫 health-ack 的机器",而是:这次请求进入 `health-ack` 组后,没有选出 `10.111.138.23` 或 `10.111.160.172`。([Nginx][1])
+
+---
+
+## 6. 核心结论
+
+更精确的直接原因是:
+
+> **`health-ack` upstream group 在某些极短时间窗口里没有可用 peer,所以 Nginx 直接返回 502。**
+
+也就是类似:
+
+```text
+请求进入 health-ack
+-> 没有选出 10.111.138.23:80
+-> 也没有选出 10.111.160.172:80
+-> upstream_addr 显示 health-ack
+-> 返回 502
+```
+
+---
+
+## 7. 为什么不是全量失败,而是极少量失败
+
+你补充的数据是:
+
+```text
+两个 upstream 节点都有大量请求
+总量很大
+502 约万分之二
+```
+
+这说明不是配置写死错误。如果配置错、Host 错、端口错,应该是大面积失败。
+
+更符合 Nginx 被动健康检查机制:
+
+```text
+某个 peer 出现 error / timeout / invalid_header
+-> 被临时标记 failed
+
+另一个 peer 也在短时间内出现失败
+-> 也被临时标记 failed
+
+刚好有请求进来
+-> health-ack 组内没有可用 peer
+-> 返回 502
+```
+
+Nginx upstream server 默认 `max_fails=1`、`fail_timeout=10s`,也就是在 `fail_timeout` 时间窗口内达到失败次数后,server 会被临时认为不可用。([Nginx][1])
+
+---
+
+## 8. 哪些错误会把 peer 打 failed
+
+真正会导致 peer 被判失败的,不是普通 404,而是这些连接级/协议级错误:
+
+```text
+connect() failed
+upstream timed out
+upstream prematurely closed connection
+recv() failed / connection reset by peer
+upstream sent invalid header
+```
+
+Nginx `proxy_next_upstream` 文档说明,`error`、`timeout`、`invalid_header` 会被视为 unsuccessful attempt;而 `http_403` 和 `http_404` 永远不会被视为 unsuccessful attempt。([Nginx][2])
+
+所以之前看到 404,不是核心。真正应该查 error log 里的:
+
+```bash
+grep -E "health-ack|no live upstreams|upstream timed out|prematurely closed|invalid header|connect\(\) failed|recv\(\(\) failed|reset by peer" \
+/data/qsc/openresty/nginx/logs/health/*error.log
+```
+
+其中:
+
+```text
+no live upstreams
+```
+
+是结果;
+
+```text
+timeout / reset / prematurely closed / invalid header
+```
+
+才是把 peer 打 failed 的原因。
+
+---
+
+## 9. "改 upstream 名就好了"的解释
+
+你后面说:
+
+> 改了个 upstream 名就没出现过了。
+
+这个现象支持"upstream group 运行时状态问题"。
+
+因为:
+
+```nginx
+upstream health-ack { ... }
+```
+
+和:
+
+```nginx
+upstream health-ack-new { ... }
+```
+
+即使里面 server 一模一样,对 Nginx 来说也是两个不同的 upstream group。
+
+改名会带来两个效果:
+
+```text
+1. reload Nginx
+2. 创建一个新的 upstream group,旧 health-ack 的运行时失败状态/连接状态不再影响它
+```
+
+所以不是后端 IP 变好了,而是绕开了旧 `health-ack` 这个共享 upstream group 的运行时状态。
+
+---
+
+## 10. 最关键发现:`health-ack` 被 9 处共用
+
+查到:
+
+```text
+260: proxy_pass http://health-ack;
+493: proxy_pass http://health-ack;
+509: proxy_pass http://health-ack;
+525: proxy_pass http://health-ack;
+613: proxy_pass http://health-ack;
+1024: proxy_pass http://health-ack;
+1056: proxy_pass http://health-ack;
+4293: proxy_pass http://health-ack;
+4321: proxy_pass http://health-ack;
+```
+
+这个是目前最关键的线索。
+
+说明 `health-ack` 不是一个业务单独使用,而是:
+
+```text
+多个 server / 多个 location / 多个域名
+共同使用同一个 upstream group
+```
+
+所以其中任何一个 location 出现连接级失败,都可能影响同一个 `health-ack` 组的 peer 状态。然后其他正常业务刚好撞到"无可用 peer"的短窗口,也会出现 502。
+
+这也解释了为什么:
+
+```text
+go-member-manager 配置一样但没问题
+health-ack 有问题
+```
+
+因为它们不是同一个 upstream group,运行时失败状态是分开的。
+
+---
+
+## 11. `api.duoerpharmacy.com` 废弃域名的判断
+
+你贴了:
+
+```nginx
+server_name api.duoerpharmacy.com;
+
+location / {
+ proxy_pass http://health-ack;
+}
+```
+
+它确实是 `health-ack` 的其中一个引用点。
+
+但你补充说:
+
+```text
+这个域名解析都没了
+```
+
+所以判断是:
+
+```text
+如果 access log 最近没有请求,它不是这次问题来源。
+如果 access log 还在写,即使 DNS 没了,也可能是 hosts、缓存、内网解析、直接 IP + Host 访问导致。
+```
+
+这个域名不一定是根因,但属于**废弃域名仍然代理到共享 upstream 的风险点**。建议清理或改成 `return 444/404`,不要继续打 `health-ack`。
+
+---
+
+# 当前结论
+
+目前最合理的结论是:
+
+> **502 的直接原因是:`health-ack` upstream group 在极少数时间窗口里无可用 peer,Nginx 选不出具体 IP,所以 `$upstream_addr` 显示 `health-ack` 并返回 502。**
+
+更深层原因倾向于:
+
+> **`health-ack` 被 9 个 location/server 共用,其中某些请求路径偶发产生 timeout/reset/prematurely closed/invalid_header 等连接级失败,导致同一个 upstream group 的 peer 被短暂标记 failed;由于默认 `max_fails=1/fail_timeout=10s` 较敏感,两个 peer 的失败窗口偶发重叠,就产生了万分之二左右的 502。**
+
+---
+
+# 建议处理
+
+先做三件事。
+
+第一,查 9 个引用点对应的完整 server/location:
+
+```bash
+nginx -T | sed -n '240,275p'
+nginx -T | sed -n '475,535p'
+nginx -T | sed -n '595,625p'
+nginx -T | sed -n '1005,1070p'
+nginx -T | sed -n '4275,4335p'
+```
+
+第二,查 error log,找真正把 peer 打 failed 的错误:
+
+```bash
+grep -E "health-ack|no live upstreams|upstream timed out|prematurely closed|invalid header|connect\(\) failed|recv\(\(\) failed|reset by peer" \
+/data/qsc/openresty/nginx/logs/health/*error.log
+```
+
+第三,把共享 upstream 拆开,不要 9 个业务共用一个 `health-ack`:
+
+```nginx
+upstream health_ack_portal {
+ server 10.111.138.23:80 weight=50 max_fails=3 fail_timeout=10s;
+ server 10.111.160.172:80 weight=50 max_fails=3 fail_timeout=10s;
+}
+```
+
+对应业务改成:
+
+```nginx
+proxy_pass http://health_ack_portal;
+```
+
+同时把默认的敏感策略调宽一点:
+
+```nginx
+max_fails=3 fail_timeout=10s
+```
+
+不建议一上来就:
+
+```nginx
+max_fails=0
+```
+
+因为那会关闭失败统计,后端真坏时 Nginx 还会继续打坏节点。
+
+[1]: https://nginx.org/en/docs/http/ngx_http_upstream_module.html?utm_source=chatgpt.com "Module ngx_http_upstream_module"
+[2]: https://nginx.org/en/docs/http/ngx_http_proxy_module.html?utm_source=chatgpt.com "Module ngx_http_proxy_module"
diff --git a/src/content/notes/02-Issues/Kubernetes/Ingress_reload_失败_health_api-tpa.md b/src/content/notes/02-Issues/Kubernetes/Ingress_reload_失败_health_api-tpa.md
new file mode 100644
index 0000000..4589d94
--- /dev/null
+++ b/src/content/notes/02-Issues/Kubernetes/Ingress_reload_失败_health_api-tpa.md
@@ -0,0 +1,281 @@
+---
+title: "Ingress_reload_失败_health_api-tpa"
+publish: true
+---
+
+# Ingress reload 失败问题总结(health controller / api-tpa)
+
+> 事件时间:2026-06-11(上周四)
+
+## 0. 排查工具:查 Ingress controller 内部 upstream / backend
+
+通过 controller 的 10246 端口可以直接拿到 controller 内存里的 backend / upstream 状态:
+
+```bash
+# 列出 controller 当前所有 backend
+curl -s http://localhost:10246/configuration/backends | jq .
+
+# 找具体 Ingress 对应的 backend
+curl -s http://localhost:10246/configuration/backends | \
+ jq '.[] | select(.name | contains("api-tpa"))'
+
+# 看某个 service 的 endpoints 是否被正确解析
+curl -s http://localhost:10246/configuration/backends | \
+ jq '.[] | {name, endpoints: .endpoints, service: .service}'
+```
+
+适用场景:
+
+```text
+- Ingress reload 失败时,确认 controller 端是否已经生成了新的 backend
+- 502 排查时,看 controller 选中的 upstream endpoint 是否和 Service 实际 endpoints 一致
+- 后端 Pod 扩缩容后,看 controller 端 endpoints 是否及时刷新
+- upstream_addr 显示 upstream group 名字(不是具体 IP)时,配合这个接口看是否所有 peer 都被标记 failed
+```
+
+> 10246 是 ingress-nginx controller 内部 metrics / debug 端口,需要在 controller Pod 本机(或 kubectl port-forward)访问。
+
+## 1. 直接故障现象
+
+Ingress controller reload Nginx 失败:
+
+```bash
+directive "error_log" is not terminated by ";" in /tmp/nginx/nginx-cfg2489516325:7086
+nginx: configuration file /tmp/nginx/nginx-cfg2489516325 test failed
+```
+
+这说明 **Ingress controller 生成出来的 nginx 配置语法错误**,导致 Nginx 无法 reload。
+
+---
+
+## 2. 直接原因
+
+生成的 nginx 配置里有这段:
+
+```nginx
+# Custom code snippet configured for host api-tpa.qingsongjkkj.com
+access_log /var/log/ingress/api-tpa.qingsongjkkj.com-access.log upstreaminfo; error_log /var/log/ingress/api-tpa.qingsongjkkj.com-error.log
+```
+
+问题是最后这一句:
+
+```nginx
+error_log /var/log/ingress/api-tpa.qingsongjkkj.com-error.log
+```
+
+末尾少了分号:
+
+```nginx
+;
+```
+
+正确应该是:
+
+```nginx
+error_log /var/log/ingress/api-tpa.qingsongjkkj.com-error.log error;
+```
+
+所以 Nginx 解析到下一段配置时,认为 `error_log` 指令没有正常结束,最终 reload 失败。
+
+---
+
+## 3. 为什么 Ingress YAML 里没看到 snippet
+
+查 `api-tpa.qingsongjkkj.com` 这个 Ingress 时,发现 metadata annotations 里没有:
+
+```yaml
+nginx.ingress.kubernetes.io/server-snippet
+nginx.ingress.kubernetes.io/configuration-snippet
+```
+
+但生成的 nginx 配置里却有:
+
+```nginx
+# Custom code snippet configured for host api-tpa.qingsongjkkj.com
+```
+
+说明这段自定义日志配置可能不是来自当前 Ingress YAML 本身,而可能来自:
+
+```text
+1. controller ConfigMap
+2. 自定义 nginx template
+3. 自动生成/注入逻辑
+4. 其他配置管理脚本
+```
+
+所以后续要继续 grep 来源:
+
+```bash
+kubectl get cm -A -o yaml | grep -nA10 -B10 "api-tpa.qingsongjkkj.com-error.log"
+
+kubectl get ingress -A -o yaml | grep -nA10 -B10 "api-tpa.qingsongjkkj.com-error.log"
+
+grep -R "api-tpa.qingsongjkkj.com-error.log" /data/build/k8s/prod/ingress/health -n
+```
+
+---
+
+## 4. 为什么 admission 没提前拦住
+
+集群里确实有 ValidatingWebhookConfiguration:
+
+```text
+VWC: ingress-nginx-admission
+service: ingress-nginx/ingress-nginx-controller-admission
+failurePolicy: Fail
+```
+
+但是这个 Service 的 selector 太宽:
+
+```yaml
+selector:
+ app.kubernetes.io/component: controller
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+```
+
+它没有带:
+
+```yaml
+qsc-platform: health
+```
+
+所以这个 admission Service 会选中多套 ingress controller,而不只是 health controller。
+
+查到的 endpoints 是:
+
+```text
+10.111.138.21:8443,10.111.138.22:8443,10.111.138.23:8443 + 9 more...
+```
+
+说明 admission Service 后面挂了多个 controller Pod。
+
+而 health controller 本身确实开了 webhook:
+
+```bash
+--controller-class=k8s.io/health-ingress-nginx
+--ingress-class=health
+--validating-webhook=:8443
+--validating-webhook-certificate=/usr/local/certificates/cert
+--validating-webhook-key=/usr/local/certificates/key
+```
+
+也就是说:**health controller 有校验能力,但 apiserver 调 admission 时不一定打到 health controller。**
+
+---
+
+## 5. 真实问题本质
+
+本质是:
+
+```text
+IngressClass health 对应 health-nginx-controller
+
+但是 ValidatingWebhookConfiguration 只配置了一个公共 admission Service
+
+这个 Service selector 太宽,选中了所有平台的 ingress-nginx controller
+
+所以提交 health Ingress 时,admission 请求可能被转发到 crm / med / baoxian / bigdata 等 controller
+
+这些 controller 发现 ingressClassName=health 不是自己负责的 class,可能直接跳过/放行
+
+最终坏 snippet 没有在 kubectl apply 阶段被拦截
+
+等 health controller 真正 reload nginx 时,才暴露语法错误
+```
+
+一句话总结:
+
+**不是 admission 完全没开,而是 health 这套 Ingress 的 admission 校验链路不可靠,存在漏检。**
+
+---
+
+## 6. 影响
+
+影响主要是:
+
+```text
+1. 新的 Ingress 配置无法 reload 生效
+2. controller 继续使用旧 nginx 配置
+3. 后续 Ingress 变更可能被阻塞
+4. 如果错误配置持续存在,controller 每次 reload 都会失败
+5. snippet 少一个分号就可能影响整套 health ingress controller
+```
+
+旧配置一般还能继续跑,但新变更不会生效。
+
+---
+
+## 7. 正确修复方向
+
+短期修复:
+
+```text
+找到产生 api-tpa 那段 access_log/error_log 的来源
+把 error_log 末尾补上分号
+最好写完整日志级别
+```
+
+正确格式:
+
+```nginx
+access_log /var/log/ingress/api-tpa.qingsongjkkj.com-access.log upstreaminfo;
+error_log /var/log/ingress/api-tpa.qingsongjkkj.com-error.log error;
+```
+
+长期修复:
+
+```text
+每个平台 ingress controller 单独拆 admission Service + ValidatingWebhookConfiguration
+```
+
+比如 health 单独建:
+
+```yaml
+apiVersion: v1
+kind: Service
+metadata:
+ name: health-nginx-controller-admission
+ namespace: ingress-nginx
+spec:
+ type: ClusterIP
+ ports:
+ - name: https-webhook
+ port: 443
+ targetPort: webhook
+ selector:
+ app.kubernetes.io/component: controller
+ app.kubernetes.io/instance: ingress-nginx
+ app.kubernetes.io/name: ingress-nginx
+ qsc-platform: health
+```
+
+然后 ValidatingWebhookConfiguration 指向:
+
+```yaml
+clientConfig:
+ service:
+ namespace: ingress-nginx
+ name: health-nginx-controller-admission
+ path: /networking/v1/ingresses
+ port: 443
+failurePolicy: Fail
+```
+
+但要注意:**证书也要重新匹配新的 Service DNS 名称**,否则 apiserver 调 webhook 会报 x509 证书不匹配。
+
+---
+
+## 8. 最终结论
+
+这次问题可以总结成:
+
+```text
+health ingress controller 生成的 nginx 配置中,自定义日志 snippet 的 error_log 少了分号,导致 nginx reload 失败。
+
+本应由 admission webhook 在提交 Ingress 时提前拦截,但当前 admission Service selector 过宽,混选了多套 ingress controller,导致 health Ingress 的校验请求可能打到非 health controller,从而被跳过放行。
+
+所以问题根因有两个:
+1. snippet 配置错误;
+2. admission webhook 配置不可靠,未按 ingressClass/platform 隔离。
+```
diff --git a/src/content/notes/02-Issues/Network/阿里云NAT网关SNAT入方向流量异常排查.md b/src/content/notes/02-Issues/Network/阿里云NAT网关SNAT入方向流量异常排查.md
new file mode 100644
index 0000000..76575af
--- /dev/null
+++ b/src/content/notes/02-Issues/Network/阿里云NAT网关SNAT入方向流量异常排查.md
@@ -0,0 +1,437 @@
+---
+title: "阿里云NAT网关SNAT入方向流量异常排查"
+publish: true
+---
+
+# 阿里云 NAT 网关 SNAT 入方向流量异常排查
+
+## 一、问题背景
+
+在阿里云公网 NAT 网关监控中,发现某个内网 IP 的 SNAT 入方向流量异常偏高。
+
+**异常内网 IP:**
+- `10.111.226.250`
+
+**现象:**
+- 入方向带宽高
+- 出方向带宽低
+- 流量稳定持续
+
+后续确认该 IP 是 Kubernetes 集群中的一个 Pod IP。
+
+---
+
+## 二、排查结论
+
+本次 NAT 网关入方向流量高,**并不是公网绕过 Ingress/Nginx 白名单访问服务**。
+
+实际链路更可能是:
+
+```
+Pod -> NAT 网关 -> 公网邮箱服务器
+公网邮箱服务器 -> NAT 网关 -> Pod
+```
+
+其中:
+- `10.111.226.250` 主动连接 `183.47.101.192:995`
+- `995` 是 POP3S 邮件收取端口
+- `183.47.101.192` 高度疑似 QQ 邮箱 POP3S 相关服务器
+
+因此 NAT 网关中看到的入方向高,实际是**公网邮箱服务器返回给 Pod 的数据流量**。
+
+---
+
+## 三、完整排查流程
+
+### 3.1 查看 NAT 网关 SNAT 转发实时数据排名
+
+**入口:**
+```
+阿里云控制台
+-> 公网 NAT 网关
+-> 监控
+-> SNAT 转发实时数据排名
+```
+
+发现内网 IP:
+- `10.111.226.250`
+
+在 SNAT 转发实时数据排名中流量最高,尤其是:
+- **入方向带宽高**
+
+并且该流量不是瞬时突发,而是**稳定持续存在**。
+
+---
+
+### 3.2 确认高流量 IP 是 Pod
+
+通过 Kubernetes 查询:
+
+```bash
+kubectl get pod -A -o wide | grep 10.111.226.250
+```
+
+确认:
+- `10.111.226.250` 是某个 Pod IP
+
+这一步说明异常流量不是普通 ECS 主机流量,而是某个业务 Pod 产生的 SNAT 流量。
+
+---
+
+### 3.3 理解 NAT 网关入方向和出方向
+
+阿里云 NAT 网关监控里的方向,不能简单理解成"公网访问服务"或者"服务访问公网"。
+
+在 SNAT 场景中:
+
+```
+Pod/ECS -> NAT 网关 -> 公网
+```
+这是 NAT 网关的**出方向流量**。
+
+公网返回:
+```
+公网 -> NAT 网关 -> Pod/ECS
+```
+这是 NAT 网关的**入方向流量**。
+
+因此:
+- **SNAT 入方向流量高** 通常表示:内网 Pod/ECS 正在从公网接收大量返回数据
+
+常见场景包括:
+- 下载文件
+- 拉取镜像
+- 调用外部接口返回大量数据
+- 收取邮件
+- 访问外部服务产生大响应
+
+**不等价于:**
+- 公网主动打进了业务服务
+
+---
+
+### 3.4 查看阿里云 NAT 网关流量分析
+
+在阿里云 NAT 网关流量分析中,继续查看高流量通信对象。
+
+**排查目标:**
+- 内网 IP:`10.111.226.250`
+
+查到流量最高的外部 IP,例如:
+- `183.47.101.192`
+
+然后查看外部 IP 的流量趋势。
+
+**重点对比:**
+- `10.111.226.250` 的 NAT 网关入方向流量趋势
+- `183.47.101.192` 的流量趋势
+
+如果二者趋势高度一致,例如:
+- 同时升高
+- 同时下降
+- 峰值时间一致
+- 持续时间一致
+
+则可以初步判断:
+- `10.111.226.250` 的高入方向流量,很可能由 `183.47.101.192` 返回的数据造成
+
+---
+
+### 3.5 抓包确认五元组
+
+在确认 Pod IP 和外部 IP 的趋势对应后,再进行抓包。
+
+可以在 Pod 所在节点或 debug 容器中抓包:
+
+```bash
+tcpdump -nn -i any 'host 10.111.226.250 and host 183.47.101.192 and (tcp or udp)'
+```
+
+或者只抓目标外部 IP 和端口:
+
+```bash
+tcpdump -nn -i any 'host 183.47.101.192 and port 995'
+```
+
+**抓到的典型五元组:**
+```
+183.47.101.192.995 -> 10.111.226.250.36008
+10.111.226.250.36008 -> 183.47.101.192.995
+```
+
+还出现了多个本地临时端口,例如:
+- `36008`
+- `48330`
+- `54676`
+
+都在与 `183.47.101.192:995` 通信。
+
+---
+
+## 四、如何从五元组判断连接方向
+
+**典型连接:**
+```
+10.111.226.250:36008 -> 183.47.101.192:995
+183.47.101.192:995 -> 10.111.226.250:36008
+```
+
+其中:
+- `10.111.226.250:36008` 是 Pod 的本地临时端口
+- `183.47.101.192:995` 是远端固定服务端口
+
+一般情况下,**客户端会使用临时端口访问服务端固定端口**。
+
+因此可以判断:
+- `10.111.226.250` 是**客户端**
+- `183.47.101.192:995` 是**服务端**
+
+也就是:
+- **Pod 主动连接了 `183.47.101.192:995`**
+
+如果是公网主动访问业务服务,常见形态应该更像:
+```
+公网 IP:随机端口 -> 业务服务 IP:80/443/业务端口
+```
+
+而不是:
+```
+公网 IP:995 -> Pod IP:随机端口
+```
+
+---
+
+## 五、识别 183.47.101.192:995
+
+**端口 `995` 对应服务:**
+- POP3S
+- POP3 over SSL/TLS
+
+常用于邮件客户端安全收取邮件。
+
+结合排查结果:
+- `183.47.101.192:995` 高度疑似 **QQ 邮箱 POP3S 服务**
+
+因此本次流量很可能是:
+- Pod 中的业务程序或任务在收取 QQ 邮箱邮件
+
+---
+
+## 六、为什么 Ingress/Nginx 白名单挡不住
+
+**Ingress/Nginx 白名单控制的是入站访问链路:**
+```
+公网用户 -> SLB/Ingress Nginx -> Service -> Pod
+```
+
+它限制的是:
+- **外部用户访问我的服务**
+
+但本次流量链路更像:
+```
+Pod -> NAT 网关 -> 公网邮箱服务器
+公网邮箱服务器 -> NAT 网关 -> Pod
+```
+
+这是:
+- **出站访问 (egress)**
+- **SNAT 流量**
+
+所以即使 Ingress/Nginx 配置了白名单,也**不会限制 Pod 主动访问公网**。
+
+---
+
+## 七、后续验证命令
+
+### 7.1 查 Pod
+
+```bash
+kubectl get pod -A -o wide | grep 10.111.226.250
+```
+
+记录:
+- namespace
+- pod name
+- node name
+- container name
+
+---
+
+### 7.2 查环境变量
+
+```bash
+kubectl exec -it -n -- sh
+```
+
+进入容器后执行:
+
+```bash
+env | grep -Ei 'mail|email|smtp|pop|imap|qq|995|465|587'
+```
+
+---
+
+### 7.3 查配置文件
+
+```bash
+grep -RniE 'mail|email|smtp|pop|imap|qq|995|465|587|183.47.101.192|pop.qq.com|smtp.qq.com' /app /etc 2>/dev/null
+```
+
+---
+
+### 7.4 查应用日志
+
+```bash
+kubectl logs -n --since=1h \
+ | grep -Ei 'mail|email|smtp|pop|imap|qq|995|183.47.101.192|pop.qq.com'
+```
+
+如果是多容器 Pod:
+
+```bash
+kubectl logs -n -c --since=1h \
+ | grep -Ei 'mail|email|smtp|pop|imap|qq|995|183.47.101.192|pop.qq.com'
+```
+
+---
+
+### 7.5 查当前连接
+
+```bash
+ss -ntp | grep '183.47.101.192:995'
+```
+
+可能看到类似:
+```
+ESTAB 0 0 10.111.226.250:36008 183.47.101.192:995 users:(("java",pid=123,...))
+```
+
+---
+
+### 7.6 使用 debug 容器排查
+
+如果业务容器中没有 `tcpdump`、`ss` 等工具,可以使用:
+
+```bash
+kubectl debug -it -n \
+ --image=nicolaka/netshoot \
+ --target= \
+ -- sh
+```
+
+进入后执行:
+
+```bash
+ss -ntp | grep '183.47.101.192:995'
+```
+
+或抓包:
+
+```bash
+tcpdump -nn -i any 'host 183.47.101.192 and port 995'
+```
+
+---
+
+### 7.7 抓 SYN 包确认谁主动发起
+
+```bash
+tcpdump -nn -i any 'host 183.47.101.192 and port 995 and tcp[tcpflags] & tcp-syn != 0'
+```
+
+如果看到:
+```
+10.111.226.250.36008 > 183.47.101.192.995: Flags [S]
+```
+
+说明:
+- **`10.111.226.250` 主动发起连接**
+
+如果看到:
+```
+183.47.101.192.995 > 10.111.226.250.36008: Flags [S.]
+```
+
+这是服务端返回 SYN ACK,也符合 Pod 主动连接外部服务的 TCP 三次握手过程。
+
+---
+
+## 八、如果确认不是预期流量,治理方向
+
+**Ingress 白名单不适合治理这个问题**。
+
+应该从**出方向访问控制**入手。
+
+### 可选方案:
+
+| 方案 | 作用 |
+|------|------|
+| Kubernetes NetworkPolicy | 限制 Pod 出方向访问 |
+| Cilium Egress Policy | 更细粒度控制 Pod 出公网 |
+| 阿里云安全组出方向规则 | 从节点/ECS 维度限制公网访问 |
+| 阿里云云防火墙 | 统一管控公网出方向访问 |
+| 应用配置治理 | 删除异常邮箱配置、脚本、定时任务或第三方依赖 |
+
+如果业务确实需要访问 QQ 邮箱,需要继续确认:
+- 是否为预期业务逻辑
+- 是否有死循环拉取邮件
+- 是否在下载大附件
+- 是否多个副本重复拉取
+- 是否有异常账号配置
+- 是否有第三方组件自动收取邮件
+
+---
+
+## 九、最终结论
+
+本次 NAT 网关入方向流量高的完整排查链路如下:
+
+1. 先从 NAT 网关 SNAT 转发实时数据排名发现 `10.111.226.250` 入方向带宽最高。
+
+2. 确认 `10.111.226.250` 是 Pod IP,并且流量稳定持续。
+
+3. 查看阿里云 NAT 网关流量分析,定位到流量最高的外部 IP。
+
+4. 对比外部 IP 的流量趋势和该 Pod 的 NAT 网关流量趋势,发现趋势高度对应。
+
+5. 在此基础上进行抓包,确认五元组。
+
+6. 抓包发现大量:
+ ```
+ 10.111.226.250:临时端口 <-> 183.47.101.192:995
+ ```
+
+7. 根据端口形态判断:
+ - `10.111.226.250` 是客户端
+ - `183.47.101.192:995` 是服务端
+
+8. `995` 是 POP3S 邮件收取端口,`183.47.101.192` 高度疑似 QQ 邮箱相关服务器。
+
+9. 因此 NAT 网关入方向高,实际是 **QQ 邮箱服务器返回给 Pod 的数据流量**。
+
+10. 该问题与 Ingress/Nginx 白名单无直接关系,因为 Ingress 白名单只限制公网入站访问,不限制 Pod 主动出公网访问。
+
+---
+
+## 十、关键词
+
+- 阿里云
+- NAT 网关
+- SNAT
+- 入方向流量
+- 出方向流量
+- Kubernetes
+- Pod
+- tcpdump
+- 五元组
+- POP3S
+- QQ 邮箱
+- Ingress 白名单
+- egress
+- NetworkPolicy
+- 云防火墙
+
+---
+
+**创建时间:** 2026-05-19
+**分类:** [[02-Issues/Network|Network Issues]]
diff --git a/src/content/notes/04-Snippets/Nginx-alias-vs-root.md b/src/content/notes/04-Snippets/Nginx-alias-vs-root.md
new file mode 100644
index 0000000..de731c3
--- /dev/null
+++ b/src/content/notes/04-Snippets/Nginx-alias-vs-root.md
@@ -0,0 +1,119 @@
+---
+title: "Nginx-alias-vs-root"
+publish: true
+---
+
+# Nginx alias vs root 区别与坑点
+
+## 核心区别
+
+| | `root` | `alias` |
+|---|---|---|
+| **语义** | 文档根目录 | 路径别名 |
+| **路径拼接** | `root` + `uri` | `alias` 替换 `location` 前缀 |
+| **适用场景** | 文件在 location 路径的子目录 | location 前缀不在文件路径中 |
+
+### alias 替换逻辑
+
+```nginx
+location /open/app {
+ alias /www/dist/;
+}
+```
+
+请求 `/open/app/index.html`:
+- 去掉 location 前缀 `/open/app`,剩余 `/index.html`
+- alias_path + 剩余 = `/www/dist/index.html`
+
+### root 路径拼接
+
+```nginx
+location /open/app/ {
+ root /www/dist/;
+}
+```
+
+请求 `/open/app/index.html`:
+- root + uri = `/www/dist/open/app/index.html`
+
+---
+
+## alias + try_files 的坑
+
+### 错误写法
+
+```nginx
+location /open/app {
+ alias /www/dist/open/app/;
+ try_files $uri $uri/ /open/app/index.html =404; # ❌ 回退路径不走 alias
+}
+```
+
+当回退到 `/open/app/index.html` 时:
+- alias **不参与回退路径解析**
+- 路径相对于 server root(默认 `/usr/share/nginx/html`)解析
+- 实际查找:`/usr/share/nginx/html/open/app/index.html` → **不存在 → 404**
+
+### 正确写法
+
+```nginx
+location /open/app {
+ alias /www/dist/open/app/;
+ try_files $uri $uri/ =404; # ✅ 让 $uri/ 自动找目录下的 index.html
+}
+```
+
+---
+
+## 场景选择
+
+| 情况 | 配置 | 示例 |
+|------|------|------|
+| location 前缀 = 文件夹名 | `alias` | `location /app/` → `alias /www/dist/` |
+| 文件在 location 的子目录 | `root` | `location /open/app/` → `root /www/dist/`(文件在 `/open/` 下) |
+| try_files SPA 回退 | **必须用 `root`** | alias 回退路径解析会出错 |
+
+---
+
+## 典型目录结构示例
+
+```
+dist/
+├── index.html # /app 的入口
+├── assets/
+└── open/
+ └── app/ # /open/app 的入口
+ └── index.html
+```
+
+### 对应配置
+
+```nginx
+# /app — 内容直接在 dist/ 下
+location /app {
+ alias /home/wwwroot/fe/fe-pifi/dist/;
+ try_files $uri $uri/ =404;
+}
+
+# /open/app — 内容在 dist/open/app/ 下
+location /open/app {
+ alias /home/wwwroot/fe/fe-pifi/dist/open/app/;
+ try_files $uri $uri/ =404;
+}
+```
+
+---
+
+## 经验总结
+
+1. **alias 路径必须和实际内容目录对齐**,不能省略中间路径
+2. **try_files 回退不要写绝对路径**,用 `$uri/` 让 Nginx 自动找 index.html
+3. **SPA(Vue/React)场景优先用 root**,配合 `/index.html` 回退
+4. **区分清楚**:URL 路径 vs 文件系统路径,两者不一定一致
+
+---
+
+## 相关
+
+- [[Nginx 配置踩坑记录]]
+- [[Vue SPA 部署]]
diff --git a/src/content/notes/06-Tasks/迁移自建Nacos到MSE-优化方案.md b/src/content/notes/06-Tasks/迁移自建Nacos到MSE-优化方案.md
new file mode 100644
index 0000000..44e1694
--- /dev/null
+++ b/src/content/notes/06-Tasks/迁移自建Nacos到MSE-优化方案.md
@@ -0,0 +1,327 @@
+---
+date: 2025-01-20
+tags: [任务计划, Nacos, MSE, 迁移优化]
+status: 待开始
+type: 任务执行
+title: "迁移自建Nacos到MSE-优化方案"
+---
+
+# 迁移自建Nacos到MSE - 优化方案
+
+## 优化概述
+
+**原方案问题**:
+- 人工介入点过多(T-0、T+10、T+15、T+30等多个时间点需要人工操作)
+- 分批重启策略繁琐(需要手动指定batch和size)
+- 检查清单依赖人工确认
+- 回滚触发依赖人工判断
+
+**优化目标**:
+- 从"30分钟紧张操作"变为"5分钟启动脚本,自动执行"
+- 减少90%的人工介入点
+- 自动化健康检查与回滚决策
+
+---
+
+## 核心优化点
+
+### 1. 多检查点合并 → 单一预检脚本
+
+**原方案**:
+- [ ] T-24h: 确认值班人员
+- [ ] T-2h: 发送最终通知
+- [ ] T-0: 确认备份完成
+- [ ] T-0: 确认环境正常
+- [ ] T-0: 确认脚本权限
+
+**优化后**:
+```bash
+# 执行单一预检脚本(迁移前自动运行)
+./scripts/pre-migration-check.sh
+# 自动检查并输出报告:
+# ✅ MSE连通性: 正常
+# ✅ K8s集群状态: 正常
+# ✅ 备份空间: 充足
+# ✅ 脚本权限: 正确
+# ✅ 通知已发送: 完成
+```
+
+**删除的人工检查**:
+
+| 原人工项 | 替代方案 |
+|---------|---------|
+| 确认各团队值班人员 | 自动通知系统(邮件/钉钉提前24h发送) |
+| 发送最终通知 | 定时任务自动发送 |
+| 配置文件正确性 | 自动化校验(语法检查+连接测试) |
+
+---
+
+### 2. 分批手动重启 → 自动滚动发布
+
+**原方案**:
+```bash
+# T+10: 人工执行第一批
+./scripts/restart-services-batch.sh --batch=1 --size=5
+# 人工检查... 确认无异常后继续
+
+# T+15: 人工执行剩余批次
+./scripts/restart-services-batch.sh --batch=2-10 --size=10
+```
+
+**优化后**:
+```bash
+# 单一命令,自动滚动执行
+./scripts/migration-orchestrator.sh \
+ --action=migrate \
+ --strategy=rolling \
+ --batch-percent=20 \
+ --health-check-interval=30s \
+ --auto-rollback-on-failure=true
+
+# 行为说明:
+# 1. 按20%批次自动推进
+# 2. 每批次后自动健康检查(30s间隔)
+# 3. 异常时自动回滚,无需人工判断
+# 4. 全程无需人工守在时间点
+```
+
+**时间线对比**:
+
+| 时间 | 原方案(人工) | 优化后(自动) |
+|------|---------------|---------------|
+| T+0 | 人工执行第一批 | 脚本自动开始滚动 |
+| T+10 | 人工检查、执行第二批 | 脚本自动推进下一批 |
+| T+15 | 人工执行剩余批次 | 脚本继续自动推进 |
+| T+30 | 人工最终验证 | 自动验证脚本输出报告 |
+
+---
+
+### 3. 人工回滚判断 → 自动回滚触发
+
+**原方案**:
+- 人工观察服务状态
+- 人工判断是否需要回滚
+- 人工执行回滚脚本
+
+**优化后**:
+```bash
+# 回滚条件自动检测
+auto_rollback_triggers:
+ - service_registration_count < threshold_80_percent
+ - error_rate > 5_percent_for_2_minutes
+ - health_check_failures > 3_consecutive
+
+# 触发后自动执行:
+1. 暂停迁移流程
+2. 自动执行 rollback-nacos.sh
+3. 自动重启服务恢复
+4. 发送告警通知
+```
+
+---
+
+### 4. 实施阶段合并与并行化
+
+**原方案流程**(串行、多人工点):
+```
+T-24h → 通知 → T-2h → 检查 → T-0 → 备份 → 切换 → T+10 → 重启1 → T+15 → 重启2 → T+30 → 验证
+```
+
+**优化后流程**(并行、自动化):
+```
+迁移前1天: pre-migration-check.sh(完全自动化)
+ ↓
+迁移窗口: migration-orchestrator.sh(一键执行)
+ ├── 备份(自动)
+ ├── 切换ConfigMap(自动)
+ └── 滚动重启(自动,内置健康检查)
+ └── 失败时自动回滚
+ ↓
+ validation.sh 持续监控15分钟,自动输出报告
+```
+
+---
+
+## 新脚本架构
+
+### 脚本1: pre-migration-check.sh
+```bash
+#!/bin/bash
+# 预迁移检查(迁移前1天自动运行)
+
+echo "=== Nacos迁移预检 ==="
+
+# 检查1: MSE连通性
+nc -zv mse-nacos-server 8848 || exit 1
+
+# 检查2: K8s集群状态
+kubectl cluster-info || exit 1
+kubectl get nodes | grep -q Ready || exit 1
+
+# 检查3: 备份空间
+df -h /backup | awk 'NR==2 {if($4+0 < 10) exit 1}'
+
+# 检查4: 脚本权限
+[ -x ./scripts/migration-orchestrator.sh ] || exit 1
+
+# 检查5: 自动发送通知
+python3 notify.py --type=pre_migration --to=teams
+
+echo "✅ 所有检查通过,系统已就绪"
+```
+
+### 脚本2: migration-orchestrator.sh(核心)
+```bash
+#!/bin/bash
+# 迁移编排器 - 一键执行全流程
+
+ACTION=$1 # migrate / rollback
+STRATEGY=${STRATEGY:-rolling}
+BATCH_PERCENT=${BATCH_PERCENT:-20}
+AUTO_ROLLBACK=${AUTO_ROLLBACK:-true}
+
+backup_data() {
+ echo "📦 执行备份..."
+ ./scripts/backup-nacos.sh
+}
+
+switch_config() {
+ echo "🔧 切换ConfigMap..."
+ kubectl apply -f k8s/configmap-mse.yaml
+}
+
+rolling_restart() {
+ echo "🚀 开始滚动重启..."
+
+ # 获取所有服务
+ services=$(kubectl get deployments -n prod -o name)
+ total=$(echo "$services" | wc -l)
+ batch_size=$((total * BATCH_PERCENT / 100))
+
+ batch_num=1
+ for service in $services; do
+ echo " 批次 $batch_num: 重启 $batch_size 个服务"
+
+ # 执行重启
+ kubectl rollout restart $service -n prod
+
+ # 等待并健康检查
+ sleep 30
+ if ! health_check; then
+ echo "❌ 健康检查失败"
+ [ "$AUTO_ROLLBACK" == "true" ] && auto_rollback
+ exit 1
+ fi
+
+ batch_num=$((batch_num + 1))
+ done
+}
+
+health_check() {
+ # 检查MSE服务注册数量
+ registered=$(curl -s mse-nacos-server:8848/nacos/v1/ns/service/list | jq '.count')
+ expected=${EXPECTED_SERVICES:-100}
+
+ if [ $registered -lt $((expected * 80 / 100)) ]; then
+ return 1
+ fi
+ return 0
+}
+
+auto_rollback() {
+ echo "🚨 触发自动回滚..."
+ kubectl apply -f k8s/configmap-legacy.yaml
+ kubectl rollout restart deployment -n prod
+ python3 notify.py --type=rollback --reason="健康检查失败"
+}
+
+final_validation() {
+ echo "✅ 执行最终验证..."
+ ./scripts/validation.sh --duration=15m --output=report
+}
+
+# 主流程
+if [ "$ACTION" == "migrate" ]; then
+ backup_data
+ switch_config
+ rolling_restart
+ final_validation
+ python3 notify.py --type=success
+elif [ "$ACTION" == "rollback" ]; then
+ auto_rollback
+fi
+```
+
+### 脚本3: validation.sh(持续验证)
+```bash
+#!/bin/bash
+# 持续验证脚本
+
+DURATION=${1:-15m}
+END_TIME=$(date -d "$DURATION" +%s)
+
+while [ $(date +%s) -lt $END_TIME ]; do
+ # 检查服务注册数
+ count=$(curl -s mse-nacos-server:8848/nacos/v1/ns/service/list | jq '.count')
+
+ # 检查错误率
+ error_rate=$(promql_query 'rate(http_requests_total{status=~"5.."}[5m])')
+
+ echo "$(date '+%H:%M:%S') - 注册服务: $count, 错误率: $error_rate"
+
+ sleep 60
+done
+
+echo "✅ 验证完成,生成报告..."
+```
+
+---
+
+## 人工介入点对比
+
+| 环节 | 原方案介入次数 | 优化后介入次数 |
+|------|---------------|---------------|
+| 预迁移检查 | 5+ | **0**(完全自动) |
+| 备份与切换 | 2 | **0**(脚本内自动) |
+| 分批重启 | 3+ | **0**(自动滚动) |
+| 健康检查 | 3+ | **0**(自动检测) |
+| 回滚决策 | 1(如需) | **0**(自动触发) |
+| 最终验证 | 1 | **0**(自动报告) |
+| **总计** | **15+** | **1**(只需启动脚本) |
+
+---
+
+## 执行命令速查
+
+```bash
+# 1. 预检(迁移前1天)
+./scripts/pre-migration-check.sh
+
+# 2. 执行迁移(迁移窗口)
+./scripts/migration-orchestrator.sh --action=migrate
+
+# 3. 如需手动回滚
+./scripts/migration-orchestrator.sh --action=rollback
+```
+
+---
+
+## 风险与应对
+
+| 风险 | 应对措施 |
+|------|---------|
+| 自动回滚误判 | 设置回滚阈值(如连续3次健康检查失败才触发) |
+| 脚本执行失败 | 保留人工介入入口,关键步骤支持--manual-mode |
+| 通知未送达 | 多渠道通知(邮件+钉钉+短信) |
+| 验证不全面 | 验证脚本覆盖核心指标(注册数、错误率、响应时间) |
+
+---
+
+## 下一步行动
+
+- [ ] 开发 pre-migration-check.sh 脚本
+- [ ] 开发 migration-orchestrator.sh 核心脚本
+- [ ] 开发 validation.sh 验证脚本
+- [ ] 在测试环境验证自动化流程
+- [ ] 确定回滚阈值参数
+- [ ] 配置自动通知渠道
diff --git a/src/content/notes/06-Tasks/迁移自建Nacos到MSE.md b/src/content/notes/06-Tasks/迁移自建Nacos到MSE.md
new file mode 100644
index 0000000..70a158d
--- /dev/null
+++ b/src/content/notes/06-Tasks/迁移自建Nacos到MSE.md
@@ -0,0 +1,847 @@
+---
+date: 2026-04-09
+tags: [任务计划, Nacos, MSE, 迁移]
+status: 待开始
+type: 任务执行
+title: "迁移自建Nacos到MSE"
+---
+
+# 迁移自建 Nacos 到 MSE
+
+## 任务概述
+
+| 字段 | 内容 |
+| ---- | ------------------- |
+| 任务名称 | 迁移自建 Nacos 到阿里云 MSE |
+| 创建时间 | 2026-04-09 |
+| 计划完成 | 待定(夜间低谷窗口) |
+| 实际完成 | |
+| 负责人 | |
+| 关联系统 | Nacos 配置中心、93 个注册服务 |
+
+## 背景与目标
+
+**现状**:
+- 自建 Nacos 1.3.2 集群(3 节点)
+- 内置 Derby 存储
+- 约 100 个配置项,93 个服务注册
+- K8s 内通过 ConfigMap/硬编码访问
+
+**目标**:
+- 迁移至阿里云 MSE Nacos
+- 内网地址:`mse-97f57750-nacos-ans.mse.aliyuncs.com:8848`
+- 鉴权方式:无
+- 全量迁移历史配置
+
+**停机窗口**:30 分钟(夜间低谷)
+**准备周期**:1 周
+
+---
+
+## 现状评估
+
+| 评估项 | 状态 | 备注 |
+|--------|------|------|
+| 配置导出 | ✅ 已完成 | 控制台导出所有配置 |
+| MSE 实例 | ✅ 已购买 | 地址已确认 |
+| 服务影响 | ⚠️ 高风险 | 93 个服务需重启 |
+| 回滚能力 | ⚠️ 待准备 | 需保留自建集群 |
+
+**潜在风险**:
+1. 部分服务硬编码 Nacos 地址,需逐个排查
+2. 批量重启 93 个服务,脚本必须经过充分测试
+3. 脚本逻辑错误可能导致批量故障
+
+---
+
+## 执行步骤
+
+### 阶段一:准备(D-7 到 D-1,共 7 天)
+
+#### D-7:任务启动 & 信息收集
+
+- [ ] **成立迁移小组**,明确分工
+- [ ] **收集完整信息**:
+ - 自建 Nacos 内网地址(完整集群地址列表)
+ - K8s 集群访问出口 IP 段(用于 MSE 白名单)
+ - 当前所有 Namespace 列表
+ - 各服务负责人联系方式
+
+- [ ] **MSE 基础配置**:
+ - [ ] MSE 控制台添加 K8s 出口 IP 白名单
+ - [ ] 测试网络连通性:`telnet mse-97f57750-nacos-ans.mse.aliyuncs.com 8848`
+ - [ ] 导入配置到 MSE(控制台导入已导出文件)
+ - [ ] 核对配置项数量(应 ≈ 100 个)
+ - [ ] 抽查 5-10 个关键配置内容
+
+#### D-6:全量扫描 & 清单整理
+
+- [ ] **扫描所有 Nacos 引用**:
+ ```bash
+ # 扫描 ConfigMap
+ kubectl get cm -A -o json | jq -r '.items[] | select(.data | tostring | contains("nacos")) | "\(.metadata.namespace)/\(.metadata.name)"' | sort | uniq > /tmp/cm-with-nacos.txt
+
+ # 扫描 Deployment 环境变量
+ kubectl get deploy -A -o json | jq -r '.items[] | select(.spec.template.spec.containers[].env[]?.value | contains("nacos")) | "\(.metadata.namespace)/\(.metadata.name)"' | sort | uniq > /tmp/deploy-with-nacos.txt
+
+ # 扫描硬编码在 args/command 中的
+ kubectl get deploy -A -o yaml | grep -B10 -A10 "nacos" | grep -E "(name:|namespace:|nacos)" > /tmp/deploy-nacos-details.txt
+ ```
+
+- [ ] **整理服务清单**:
+ - [ ] 汇总所有涉及的服务(去重后应 ≈ 93 个)
+ - [ ] 按业务域分组(订单/支付/用户/商品/...)
+ - [ ] 按优先级分级(P0 核心 / P1 重要 / P2 普通)
+ - [ ] 标注每个服务的 ConfigMap 引用方式(统一 ConfigMap / 独立 ConfigMap / 硬编码)
+
+- [ ] **输出《服务清单表》**:
+
+| 序号 | 服务名 | Namespace | 优先级 | 配置方式 | 负责人 | 重启批次 |
+| :-: | :-: | :-------: | :------: | :-------------: | :-: | :--: |
+| 1 | | | P0/P1/P2 | ConfigMap / 硬编码 | | 第1批 |
+| 2 | | | P0/P1/P2 | ConfigMap / 硬编码 | | 第1批 |
+| ... | ... | ... | ... | ... | ... | ... |
+
+#### D-5:脚本开发(第 1 天)
+
+- [ ] **开发脚本 1:ConfigMap 批量替换脚本**
+ ```bash
+ #!/bin/bash
+ # update-nacos-cm.sh
+ # 功能:批量更新所有包含 nacos 的 ConfigMap
+ ```
+ 要求:
+ - 支持 dry-run 模式(只打印不执行)
+ - 支持指定 Namespace
+ - 支持回滚(保存原 ConfigMap 到 backup)
+ - 输出变更清单
+
+- [ ] **开发脚本 2:服务分批重启脚本**
+ ```bash
+ #!/bin/bash
+ # restart-services-batch.sh
+ # 功能:按批次重启服务,等待就绪后再下一批
+ ```
+ 要求:
+ - 从文件读取服务列表
+ - 支持指定批次大小(默认 10 个)
+ - 每批等待 rollout status 成功(超时 120s)
+ - 失败时暂停,记录失败服务
+ - 输出执行报告
+
+- [ ] **开发脚本 3:状态检查脚本**
+ ```bash
+ #!/bin/bash
+ # check-mse-status.sh
+ # 功能:检查 MSE 服务注册状态
+ ```
+ 要求:
+ - 调用 MSE/Nacos OpenAPI 查询服务数量
+ - 对比预期服务列表,输出缺失服务
+ - 检查配置项数量
+
+- [ ] **开发脚本 4:一键回滚脚本**
+ ```bash
+ #!/bin/bash
+ # rollback-nacos.sh
+ # 功能:紧急回滚到自建 Nacos
+ ```
+ 要求:
+ - 从 backup 恢复 ConfigMap
+ - 批量重启所有服务
+ - 验证回滚结果
+
+#### D-4:脚本开发(第 2 天)
+
+- [ ] **完成所有脚本开发**
+- [ ] **代码评审**:至少 1 人 review 脚本逻辑
+- [ ] **异常场景处理**:
+ - ConfigMap 不存在时的处理
+ - rollout 超时处理
+ - 网络中断重试机制
+ - 部分失败继续还是停止
+
+#### D-3:脚本测试(测试环境)
+
+- [ ] **搭建测试环境**:
+ - 找一个非生产 Namespace
+ - 部署 3-5 个测试服务
+ - 配置指向测试 Nacos
+
+- [ ] **执行全量脚本测试**:
+ - [ ] 测试脚本 1:ConfigMap 替换(dry-run + 实际执行)
+ - [ ] 测试脚本 2:分批重启(验证批次控制、超时处理)
+ - [ ] 测试脚本 3:状态检查(验证 API 调用、数据准确性)
+ - [ ] 测试脚本 4:回滚(验证备份恢复逻辑)
+
+- [ ] **记录测试结果 & 修复问题**
+- [ ] **输出《脚本测试报告》**
+
+#### D-2:生产环境预演(只读操作)
+
+- [ ] **生产环境预演**:
+ - [ ] 执行脚本 1 dry-run,确认影响范围
+ - [ ] 核对服务清单准确性(与预演结果对比)
+ - [ ] 验证 MSE 白名单(从生产节点 telnet 测试)
+ - [ ] 确认备份存储位置(确保有写权限)
+
+- [ ] **准备生产执行包**:
+ - [ ] 所有脚本 + 配置文件
+ - [ ] 服务清单(最终版)
+ - [ ] 回滚方案(打印版,网络故障时可用)
+ - [ ] 各团队负责人联系方式
+
+#### D-1:最终确认
+
+- [ ] **迁移窗口确认**:
+ - [ ] 确认具体日期时间
+ - [ ] 确认各团队值班人员
+ - [ ] 发送最终通知(提前 24h)
+
+- [ ] **环境检查**:
+ - [ ] MSE 配置再次确认
+ - [ ] 自建 Nacos 状态检查
+ - [ ] K8s 集群状态检查
+ - [ ] 备份存储空间检查
+
+- [ ] **脚本最终检查**:
+ - [ ] 脚本文件完整性
+ - [ ] 执行权限
+ - [ ] 配置文件正确性
+
+---
+
+### 阶段二:实施(迁移当天,T-0)
+
+**时间窗口**:夜间低谷,30 分钟
+
+| 时间 | 动作 | 负责人 | 检查点 |
+|------|------|--------|--------|
+| T-0 | 开始窗口,通知各团队 | | |
+| T+0~5min | 执行备份脚本 | | 确认备份文件生成 |
+| T+5~10min | 执行 ConfigMap 替换脚本 | | 确认所有 CM 更新 |
+| T+10~25min | 执行分批重启脚本(第一批)| | 确认 MSE 有服务注册 |
+| T+25~30min | 执行分批重启脚本(剩余批次)| | 确认 93 个服务全部注册 |
+| T+30min | 执行状态检查脚本 | | 确认服务数、配置数正确 |
+| T+30min | 窗口结束,发送状态通知 | | |
+
+**详细步骤**:
+
+- [ ] **T+0:备份当前状态**
+ ```bash
+ ./scripts/backup-before-migration.sh
+ ```
+ - 导出当前所有服务列表
+ - 备份所有 ConfigMap(含 nacos 引用的)
+ - 保存到 `/backup/nacos-migration-$(date +%Y%m%d%H%M)/`
+
+- [ ] **T+5:更新 ConfigMap**
+ ```bash
+ ./scripts/update-nacos-cm.sh --apply
+ ```
+
+- [ ] **T+10:分批重启(第一批验证)**
+ ```bash
+ ./scripts/restart-services-batch.sh --batch=1 --size=5
+ ```
+ - 先重启 5 个非核心服务验证
+ - 检查 MSE 控制台是否有服务注册
+ - 确认无异常后继续
+
+- [ ] **T+15:批量重启剩余服务**
+ ```bash
+ ./scripts/restart-services-batch.sh --batch=2-10 --size=10
+ ```
+
+- [ ] **T+30:最终验证**
+ ```bash
+ ./scripts/check-mse-status.sh --expected-services=93
+ ```
+
+---
+
+### 阶段三:验证(T+30min ~ T+2h)
+
+- [ ] **功能验证**:
+ - [ ] 核心业务接口调用测试(采样 10% 服务)
+ - [ ] 配置热更新测试(修改一个配置,确认推送)
+ - [ ] 服务间调用测试(链式调用验证)
+
+- [ ] **监控检查**:
+ - [ ] 各服务日志检查(无 Nacos 连接错误)
+ - [ ] 业务监控指标正常(QPS、错误率、延迟)
+ - [ ] 告警检查(无异常告警)
+
+- [ ] **配置核对**:
+ - [ ] 随机抽查 20 个配置项,与自建对比
+
+---
+
+### 阶段四:收尾(D+1 到 D+7)
+
+- [ ] **D+1**:
+ - [ ] 更新运维文档
+ - [ ] 修改架构图
+ - [ ] 发送迁移完成通知
+
+- [ ] **D+2~D+7**:观察期
+ - [ ] 每日检查 MSE 状态
+ - [ ] 处理遗留问题(硬编码整改)
+
+- [ ] **D+7 后**:
+ - [ ] 确认稳定运行 1 周
+ - [ ] 下线自建 Nacos 集群
+ - [ ] 归档迁移文档
+
+---
+
+## 回滚方案
+
+**触发条件**:
+- 迁移后 30 分钟内无法恢复核心服务
+- 大量服务无法注册到 MSE
+- 配置丢失或错误导致业务异常
+- 脚本执行严重异常
+
+**回滚步骤**:
+```bash
+# 一键回滚
+./scripts/rollback-nacos.sh
+```
+
+手动回滚(脚本失效时):
+1. 从 `/backup/nacos-migration-*/` 恢复 ConfigMap
+2. 执行 `./scripts/restart-services-batch.sh --all`
+3. 验证自建 Nacos 服务注册
+
+**预计回滚时间**:15-20 分钟
+
+---
+
+## 影响范围
+
+| 系统/服务 | 影响描述 | 应对措施 |
+| ----------- | ----------- | ------------------ |
+| 93 个 K8s 服务 | 需重启,期间短暂不可用 | 夜间低谷执行,分批重启,脚本控制节奏 |
+| 配置中心 | 地址变更 | 提前导入配置,脚本批量更新 |
+| 服务发现 | 短暂中断 | 重启后自动恢复 |
+
+---
+
+## 脚本
+
+### 脚本 0: 迁移前备份
+
+```bash
+#!/bin/bash
+
+# ============================================================
+# 脚本 0: 迁移前备份脚本
+# 功能: 备份当前环境状态,用于对比和回滚
+# 用法: ./backup-before-migration.sh
+# ============================================================
+
+set -e
+
+export KUBECONFIG=${KUBECONFIG:-/root/.kube/config}
+BACKUP_ROOT="/backup/nacos-migration"
+TIMESTAMP=$(date +%Y%m%d_%H%M%S)
+BACKUP_DIR="$BACKUP_ROOT/pre_$TIMESTAMP"
+
+echo "========================================="
+echo " Nacos 迁移 - 迁移前备份"
+echo "========================================="
+echo "备份目标: $BACKUP_DIR"
+
+mkdir -p "$BACKUP_DIR/{configmaps,services,configs,deployments}"
+
+echo ""
+echo "--- 步骤 1: 备份所有 ConfigMap ---"
+CM_COUNT=0
+for ns in $(kubectl get ns -o json | jq -r '.items[].metadata.name'); do
+ kubectl get cm -n "$ns" -o json | jq -r \
+ '[.items[] | select(.data | tostring | contains("nacos"))] | .[].metadata.name' \
+ 2>/dev/null | while read -r cm; do
+ [ -z "$cm" ] && continue
+ kubectl get cm "$cm" -n "$ns" -o yaml > "$BACKUP_DIR/configmaps/${ns}_${cm}.yaml" 2>/dev/null || true
+ ((CM_COUNT++))
+ done
+done
+echo "✅ ConfigMap 备份完成"
+
+echo ""
+echo "--- 步骤 2: 导出服务注册列表 ---"
+SELF_BUILD_NACOS_URL="" # 填写自建 Nacos 控制台 URL
+if [ -n "$SELF_BUILD_NACOS_URL" ]; then
+ curl -s "${SELF_BUILD_NACOS_URL}/nacos/v1/ns/service/list" \
+ -X GET -G --data-urlencode "pageSize=1000" --data-urlencode "pageNo=1" \
+ > "$BACKUP_DIR/services/services.json" 2>/dev/null
+ SERVICE_COUNT=$(jq -r '.count // 0' "$BACKUP_DIR/services/services.json" 2>/dev/null)
+ echo "✅ 服务列表已导出 (当前 $SERVICE_COUNT 个服务)"
+else
+ echo "ℹ️ 未配置自建 Nacos URL,跳过服务列表导出"
+fi
+
+echo ""
+echo "--- 步骤 3: 导出 Deployment 状态 ---"
+kubectl get deploy -A -o wide > "$BACKUP_DIR/deployments/deploy-list.txt"
+echo "✅ Deployment 列表已保存"
+
+echo ""
+echo "--- 步骤 4: 导出配置信息 ---"
+if [ -n "$SELF_BUILD_NACOS_URL" ]; then
+ curl -s "${SELF_BUILD_NACOS_URL}/nacos/v1/cs/configs" \
+ -X GET -G --data-urlencode "pageNo=1" --data-urlencode "pageSize=1000" \
+ --data-urlencode "search=blur" --data-urlencode "dataId=" \
+ > "$BACKUP_DIR/configs/all-configs.json" 2>/dev/null
+ CONFIG_COUNT=$(jq -r '.totalCount // 0' "$BACKUP_DIR/configs/all-configs.json" 2>/dev/null)
+ echo "✅ 配置项已导出 (当前 $CONFIG_COUNT 个)"
+else
+ echo "ℹ️ 未配置自建 Nacos URL,跳过配置导出"
+fi
+
+echo ""
+echo "========================================="
+echo " 备份完成"
+echo "========================================="
+echo "备份目录: $BACKUP_DIR"
+du -sh "$BACKUP_DIR"/*
+echo ""
+echo "回滚命令参考:"
+echo " # 一键回滚(见下方回滚脚本)"
+```
+
+### 脚本 1: ConfigMap 批量替换
+
+```bash
+#!/bin/bash
+
+# ============================================================
+# 脚本 1: ConfigMap 批量替换脚本
+# 功能: 扫描所有包含 nacos 的 ConfigMap,批量替换地址
+# ============================================================
+
+set -e; set -o pipefail
+
+export KUBECONFIG=${KUBECONFIG:-/root/.kube/config}
+BACKUP_DIR="/tmp/nacos-cm-bak_$(date +%Y%m%d%H%M%S)"
+OLD_NACOS_ADDR=""
+NEW_NACOS_ADDR="mse-97f57750-nacos-ans.mse.aliyuncs.com:8848"
+NAMESPACE="${1:-}"
+DRY_RUN=false
+APPLY=false
+
+usage() {
+ echo "用法: $0 [选项]"
+ echo " -n, --namespace 指定命名空间(留空=全部)"
+ echo " -o, --old <地址> 旧 Nacos 地址(必须)"
+ echo " -N, --new <地址> 新 Nacos 地址"
+ echo " -d, --dry-run 只打印不执行"
+ echo " -a, --apply 实际执行替换"
+ echo " -h, --help 帮助"
+ echo ""
+ echo "示例:"
+ echo " $0 -n test -o 'nacos.default.svc.cluster.local:8848' -d"
+ echo " $0 -n test -o 'nacos.default.svc.cluster.local:8848' -a"
+ exit 0
+}
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -n|--namespace) NAMESPACE="$2"; shift 2 ;;
+ -o|--old) OLD_NACOS_ADDR="$2"; shift 2 ;;
+ -N|--new) NEW_NACOS_ADDR="$2"; shift 2 ;;
+ -d|--dry-run) DRY_RUN=true; shift ;;
+ -a|--apply) APPLY=true; shift ;;
+ -h|--help) usage ;;
+ *) echo "未知参数: $1"; usage ;;
+ esac
+done
+
+if [ -z "$OLD_NACOS_ADDR" ]; then
+ echo "错误: 必须指定旧 Nacos 地址 (-o)"
+ usage
+fi
+
+echo "--- 步骤 1: 扫描 ConfigMap ---"
+
+CM_LIST=$(kubectl get cm -A -o json | jq -r '
+ [.items[] |
+ select((.data | tostring | contains("'"$OLD_NACOS_ADDR"'")) or (.data | tostring | contains("nacos"))) |
+ "\(.metadata.namespace)|\(.metadata.name)"
+ ] | sort | unique
+')
+
+if [ -z "$CM_LIST" ]; then
+ echo "⚠️ 未找到包含 nacos 的 ConfigMap"; exit 0
+fi
+
+TOTAL_CM=$(echo "$CM_LIST" | wc -l); echo "找到 $TOTAL_CM 个需要检查的 ConfigMap"
+
+if [ -n "$NAMESPACE" ]; then
+ CM_LIST=$(echo "$CM_LIST" | grep "^${NAMESPACE}|" || true)
+ FILTERED_CM=$(echo "$CM_LIST" | wc -l)
+ echo "过滤后 (namespace=$NAMESPACE): $FILTERED_CM 个"
+fi
+
+echo ""
+echo "--- 步骤 2: 备份与替换 ---"
+
+MODIFIED_CMS=(); SKIPPED_CMS=()
+
+while IFS='|' read -r ns cm_name; do
+ [ -z "$cm_name" ] && continue
+ CM_YAML=$(kubectl get cm "$cm_name" -n "$ns" -o yaml)
+
+ if ! echo "$CM_YAML" | grep -q "$OLD_NACOS_ADDR"; then
+ echo "ℹ️ 跳过 [$ns/$cm_name]: 不包含旧地址"
+ SKIPPED_CMS+=("$ns/$cm_name"); continue
+ fi
+
+ if [ "$DRY_RUN" = true ]; then
+ echo "📋 DRY-RUN [$ns/$cm_name]: '$OLD_NACOS_ADDR' → '$NEW_NACOS_ADDR'"
+ MODIFIED_CMS+=("$ns|$cm_name"); continue
+ fi
+
+ if [ "$APPLY" != true ]; then
+ echo "ℹ️ 需要修改但未指定 -a: $ns/$cm_name"
+ MODIFIED_CMS+=("$ns|$cm_name"); continue
+ fi
+
+ mkdir -p "$BACKUP_DIR"
+ echo "$CM_YAML" > "$BACKUP_DIR/${ns}.yaml"
+ NEW_YAML=$(echo "$CM_YAML" | sed "s|${OLD_NACOS_ADDR}|${NEW_NACOS_ADDR}|g")
+ echo "$NEW_YAML" | kubectl replace -f -
+ echo "✅ 已更新: $ns/$cm_name"
+ MODIFIED_CMS+=("$ns|$cm_name")
+done <<< "$CM_LIST"
+
+echo ""
+echo "========================================="; echo " 执行报告"; echo "========================================="
+echo ""; echo "扫描总数: $(( ${#MODIFIED_CMS[@]} + ${#SKIPPED_CMS[@]} ))"
+echo "需要更新: ${#MODIFIED_CMS[@]}"; echo "跳过: ${#SKIPPED_CMS[@]}"
+
+if [ "${#MODIFIED_CMS[@]}" -gt 0 ]; then
+ echo ""; echo "--- 变更列表 ---"
+ for item in "${MODIFIED_CMS[@]}"; do echo " 🔄 $item"; done
+fi
+
+if [ "$APPLY" = true ] && [ "${#MODIFIED_CMS[@]}" -gt 0 ]; then
+ echo ""; echo "📦 备份位置: $BACKUP_DIR"; echo "🔙 回滚: 见下方回滚脚本"
+fi
+```
+
+### 脚本 2: 分批重启服务
+
+```bash
+#!/bin/bash
+
+# ============================================================
+# 脚本 2: 服务分批重启脚本
+# 功能: 按批次重启服务,等待就绪后再下一批
+# ============================================================
+
+set -e
+
+export KUBECONFIG=${KUBECONFIG:-/root/.kube/config}
+SERVICE_LIST_FILE="./scripts/service-list.csv"
+BATCH_SIZE=${1:-10}
+BATCH_NUM=${2:-}
+TIMEOUT_ROLLOUT=120s
+WAIT_INTERVAL=5s
+LOG_DIR="/tmp/nacos-restart_$(date +%Y%m%d%H%M%S)"
+
+mkdir -p "$LOG_DIR"
+
+usage() {
+ echo "用法: $0 [批次大小] [批次号]"
+ echo " $0 # 默认每批10个,所有批次"
+ echo " $0 5 # 每批5个"
+ echo " $0 10 1 # 只执行第1批(验证用)"
+ echo " $0 10 2-3 # 执行第2~3批"
+ echo ""
+ echo "CSV 格式: 服务名,Namespace,优先级,配置方式,批次"
+ exit 0
+}
+
+[[ "$1" == "-h" || "$1" == "--help" ]] && usage
+
+[ ! -f "$SERVICE_LIST_FILE" ] && { echo "错误: 服务清单不存在: $SERVICE_LIST_FILE"; exit 1; }
+
+echo "========================================="
+echo " Nacos 迁移 - 分批重启工具"
+echo "========================================="
+echo "清单: $SERVICE_LIST_FILE | 批次大小: $BATCH_SIZE | 日志: $LOG_DIR"
+echo ""
+
+ALL_SERVICES=()
+while IFS=',' read -r service ns priority method batch; do
+ [[ "$service" =~ ^#.* ]] && continue; [ -z "$service" ] && continue
+ ALL_SERVICES+=("${service}|${ns}|${priority}|${method}|${batch}")
+done < "$SERVICE_LIST_FILE"
+
+TOTAL=${#ALL_SERVICES[@]}; TOTAL_BATCHES=$(( (TOTAL + BATCH_SIZE - 1) / BATCH_SIZE ))
+echo "总服务数: $TOTAL | 总批次数: $TOTAL_BATCHES"
+
+START_BATCH=1; END_BATCH=$TOTAL_BATCHES
+if [ -n "$BATCH_NUM" ]; then
+ if [[ "$BATCH_NUM" =~ ^([0-9]+)-([0-9]+)$ ]]; then START_BATCH="${BASH_REMATCH[1]}"; END_BATCH="${BASH_REMATCH[2]}"
+ elif [[ "$BATCH_NUM" =~ ^[0-9]+$ ]]; then START_BATCH="$BATCH_NUM"; END_BATCH="$BATCH_NUM"; fi
+ echo "执行批次: $START_BATCH ~ $END_BATCH"
+fi
+
+echo ""
+echo "--- 步骤: 分批重启 ---"
+
+SUCCESS_LIST=(); FAIL_LIST=()
+
+for ((batch_idx = START_BATCH; batch_idx <= END_BATCH; batch_idx++)); do
+ start_idx=$(( (batch_idx - 1) * BATCH_SIZE )); end_idx=$(( start_idx + BATCH_SIZE ))
+ [ $end_idx -gt $TOTAL ] && end_idx=$TOTAL; batch_count=$(( end_idx - start_idx ))
+
+ echo ""; echo "═══ 第 $batch_idx / $TOTAL_BATCHES 批 ($batch_count 个) ═══"; echo ""
+ RESTARTED_DEPS=()
+
+ for ((i = start_idx; i < end_idx; i++)); do
+ IFS='|' read -r service ns priority method batch <<< "${ALL_SERVICES[$i]}"
+ echo -n " [$service] ($ns)... "
+
+ if ! kubectl get deployment "$service" -n "$ns" --request-timeout=10s &>/dev/null; then
+ echo "❌ Deployment 不存在"; FAIL_LIST+=("$service"); echo "$(date '+%H:%M:%S') FAIL $service/$ns: not found" >> "$LOG_DIR/failures.log"; continue; fi
+
+ if kubectl rollout restart "deployment/$service" -n "$ns" --request-timeout=30s &>/dev/null; then
+ if kubectl rollout status "deployment/$service" -n "$ns" --timeout="$TIMEOUT_ROLLOUT" >> "$LOG_DIR/${service}.log 2>&1; then
+ echo "✅ 成功"; SUCCESS_LIST+=("$service/$ns"); echo "$(date '+%H:%M:%S') OK $service/$ns" >> "$LOG_DIR/success.log"
+ else echo "⚠️ 超时(已触发)"; SUCCESS_LIST+=("$service/$ns"); echo "$(date '+%H:%M:%S') WARN $service/$ns: timeout" >> "$LOG_DIR/warnings.log"; fi
+ else echo "❌ 重启失败"; FAIL_LIST+=("$service/$ns"); echo "$(date '+%H:%M:%S') FAIL $service/$ns" >> "$LOG_DIR/failures.log"; fi
+
+ sleep 2
+ done
+
+ [ $batch_idx -lt $END_BATCH ] && { echo " 等待 $WAIT_INTERVAL..."; sleep "$WAIT_INTERVAL"; }
+done
+
+echo ""; echo "========================================="; echo " 执行报告"; echo "========================================="
+echo ""; echo "总处理: $TOTAL | ✅成功: ${#SUCCESS_LIST[@]} | ❌失败: ${#FAIL_LIST[@]}"
+
+if [ "${#FAIL_LIST[@]}" -gt 0 ]; then
+ echo ""; echo "❌ 失败列表:"; for f in "${FAIL_LIST[@]}"; do echo " ❌ $f"; done
+ echo ""; echo "日志: $LOG_DIR/failures.log"
+else echo ""; echo "🎉 全部完成!"
+fi
+echo ""; echo "详细日志: $LOG_DIR/"
+```
+
+### 脚本 3: MSE 状态检查
+
+```bash
+#!/bin/bash
+
+# ============================================================
+# 脚本 3: MSE 状态检查脚本
+# 功能: 检查 MSE/Nacos 服务注册状态,对比预期
+# ============================================================
+
+set -e
+
+MSE_HOST="mse-97f57750-nacos-ans.mse.aliyuncs.com"
+MSE_PORT=8848
+EXPECTED_SERVICES=93
+EXPECTED_CONFIGS=100
+NAMESPACE_ID="${1:-public}"
+CHECK_TYPE="${2:-all}"
+VERBOSE=false
+
+usage() {
+ echo "用法: $0 [namespace_id] [check_type] [选项]"
+ echo " check_type: all / services / configs"
+ echo " -s/--expected-services <数字>"
+ echo " -c/--expected-configs <数字>"
+ echo " -v/--verbose 详细输出"
+ exit 0
+}
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -s|--expected-services) EXPECTED_SERVICES="$2"; shift 2 ;;
+ -c|--expected-configs) EXPECTED_CONFIGS="$2"; shift 2 ;;
+ -v|--verbose) VERBOSE=true; shift ;;
+ -h|--help) usage ;;
+ *) ;;
+ esac
+done
+
+echo "========================================="
+echo " MSE 状态检查工具"
+echo "========================================="
+echo "MSE: ${MSE_HOST}:${MSE_PORT} | Namespace: ${NAMESPACE_ID} | 类型: $CHECK_TYPE"
+echo ""
+
+API_BASE="http://${MSE_HOST}:${MSE_PORT}/nacos/v1/ns"
+CONFIG_API_BASE="http://${MSE_HOST}:${MSE_PORT}/nacos/v1/cs"
+NS_PARAM=""
+[ -n "$NAMESPACE_ID" ] && NS_PARAM="?tenantId=${NAMESPACE_ID}"
+
+PASS=0; WARN=0; FAIL=0
+
+check_result() { local n="$1" e="$2" a="$3";
+ [ "$a" -eq "$e" ] && { echo " ✅ $n: $a / $e"; ((PASS++)); return; }
+ [ "$a" -ge $((e * 95 / 100)) ] && { echo " ⚠️ $n: $a / $e (±5%)"; ((WARN++)); return; }
+ echo " ❌ $n: $a / $e"; ((FAIL++))
+}
+
+if [ "$CHECK_TYPE" = "all" ] || [ "$CHECK_TYPE" = "services" ]; then
+ echo "━━━ 服务注册 ━━━"
+ SERVICE_COUNT=$(curl -s "${API_BASE}/service/list${NS_PARAM}" -X GET -G \
+ --data-urlencode "pageSize=9999" --data-urlencode "pageNo=1" 2>/dev/null | jq -r '.count // empty')
+ check_result "注册服务数" "$EXPECTED_SERVICES" "${SERVICE_COUNT:-0}"
+
+ if [ "$VERBOSE" = true ]; then
+ echo ""; echo " 详情:"
+ curl -s "${API_BASE}/service/list${NS_PARAM}" -X GET -G \
+ --data-urlencode "pageSize=9999" --data-urlencode "pageNo=1" 2>/dev/null | jq -r '.domains[]? // empty' | while read -r s; do echo " • $s"; done
+ fi
+ echo ""
+fi
+
+if [ "$CHECK_TYPE" = "all" ] || [ "$CHECK_TYPE" = "configs" ]; then
+ echo "━━━ 配置项 ━━━"
+ CONFIG_COUNT=$(curl -s "${CONFIG_API_BASE}/configs${NS_PARAM}" -X GET -G \
+ --data-urlencode "pageNo=1" --data-urlencode "pageSize=1000" \
+ --data-urlencode "search=blur" --data-urlencode "dataId=" --data-urlencode "group=" 2>/dev/null | jq -r '.totalCount // empty' | head -1)
+ check_result "配置项数" "$EXPECTED_CONFIGS" "${CONFIG_COUNT:-0}"; echo ""
+fi
+
+echo "━━━ 连通性 ━━━"
+HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 "http://${MSE_HOST}:${MSE_PORT}/nacos/" 2>/dev/null || echo "000")
+case "$HTTP_CODE" in 200|302) echo " ✅ MSE 可达 (HTTP $HTTP_CODE)"; ((PASS++)) ;; 000) echo " ❌ MSE 不可达"; ((FAIL++)) ;; *) echo " ⚠️ HTTP $HTTP_CODE"; ((WARN++)) ;; esac
+echo ""
+
+echo "========================================="; echo " 汇总"; echo "========================================="
+echo "✅通过: $PASS | ⚠️警告: $WARN | ❌失败: $FAIL"; echo ""
+[ $FAIL -gt 0 ] && { echo "❌ 存在问题!"; exit 1; }
+[ $WARN -gt 0 ] && { echo "⚠️ 有警告"; exit 2; }
+echo "🎉 全部正常!"; exit 0
+```
+
+### 脚本 4: 一键回滚
+
+```bash
+#!/bin/bash
+
+# ============================================================
+# 脚本 4: 一键回滚脚本
+# 功能: 紧急回滚到自建 Nacos
+# ============================================================
+
+set -e
+
+export KUBECONFIG=${KUBECONFIG:-/root/.kube/config}
+BACKUP_DIR="${1:-}"
+FORCE="${2:-}"
+
+usage() {
+ echo "用法: $0 [备份目录] [--force]"
+ echo " 不指定则自动查找最新备份 | --force 跳过确认"
+ exit 0
+}
+
+[[ "$1" == "-h" || "$1" == "--help" ]] && usage
+[ "$1" = "--force" ] && FORCE="--force" && BACKUP_DIR=""
+[ "$2" = "--force" ] && FORCE="--force"
+
+echo "╔══════════════════════════════════════╗"
+echo "║ ⚠️ Nacos 迁移 - 一键回滚工具 ║"
+echo "╚════════════════════════════════════╝"
+echo ""
+
+if [ -z "$BACKUP_DIR" ]; then
+ LATEST_BAK=$(ls -dt /tmp/nacos-cm-bak_* 2>/dev/null | head -1)
+ [ -z "$LATEST_BAK" ] && { echo "❌ 未找到备份!查找: /tmp/nacos-cm-bak_*"; exit 1; }
+ BACKUP_DIR="$LATEST_BAK"; echo "自动找到: $BACKUP_DIR"
+else
+ [ ! -d "$BACKUP_DIR" ] && { echo "❌ 目录不存在: $BACKUP_DIR"; exit 1; }
+fi
+
+echo "备份: $BACKUP_DIR"; echo ""
+ls -la "$BACKUP_DIR"/ | tail -n +2 | awk '{print " ", $NF}' 2>/dev/null; echo ""
+RESTORE_COUNT=$(ls "$BACKUP_DIR"/*.yaml 2>/dev/null | wc -l); echo "将恢复 $RESTORE_COUNT 个命名空间"; echo ""
+
+if [ "$FORCE" != "--force" ]; then
+ echo "⚠️ 此操作将:1.恢复ConfigMap 2.批量重启 3.切回自建Nacos"
+ echo -n "确认?(15s内输入y): "
+ read -t 15 CONFIRM; [[ "$CONFIRM" != "y"* && "$CONFIRM" != "Y"* ]] && { echo "已取消"; exit 0; }
+else echo "🔴 强制模式!"; fi
+echo ""; echo "开始回滚..."; echo ""
+
+echo "═══ 步骤1: 恢复 ConfigMap ═══"; echo ""
+CS=0; CF=0
+for f in "$BACKUP_DIR"/*.yaml; do [ -f "$f" ] || continue; ns=$(basename "$f" .yaml)
+ kubectl get namespace "$ns" &>/dev/null || { echo "⚠️ 命名空间不存在: $ns"; continue; }
+ kubectl apply -f "$f" --force --overwrite &>/dev/null && { echo "✅ $ns"; ((CS++)); } || { echo "❌ $ns"; ((CF++)); }
+done
+echo ""; echo "ConfigMap: ✅$CS / ❌$CF"
+[ "$CF" -gt 0 ] && { echo "⚠️ 有失败,继续?(y/n)"; read -t 10 C; [[ "$C" != "y" ]] && exit 1; }
+
+echo ""; echo "═══ 步骤2: 批量重启 ═══"; echo ""
+RS=0; RF=0; RL="/tmp/nacos-rollback_$(date +%Y%m%d%H%M).log"; touch "$RL"
+for ns_yaml in "$BACKUP_DIR"/*.yaml; do [ -f "$ns_yaml" ] || continue; ns=$(basename "$ns_yaml" .yaml)
+ for dep in $(kubectl get deploy -n "$ns" -o json | jq -r '.items[].metadata.name' 2>/dev/null); do
+ echo -n " $ns/$dep ... "
+ kubectl rollout restart "deployment/$dep" -n "$ns" --request-timeout=30s &>/dev/null \
+ && { echo "✅"; ((RS++)); echo "$(date '+%H:%M:%S') OK $ns/$dep" >> "$RL"; } \
+ || { echo "❌"; ((RF++)); echo "$(date '+%H:%M:%S') FAIL $ns/$dep" >> "$RL"; }
+ sleep 1
+ done
+done
+echo ""; echo "重启: ✅$RS / ❌$RF"; echo ""
+
+echo "═══ 步骤3: 验证 ═══"; echo ""
+for ns_yaml in "$BACKUP_DIR"/*.yaml; do [ -f "$ns_yaml" ] || continue; ns=$(basename "$ns_yaml" .yaml)
+ for dep in $(kubectl get deploy -n "$ns" -o json | jq -r '.items[].metadata.name'); do
+ echo -n " 检查 $ns/$dep... "
+ kubectl rollout status "deployment/$dep" -n "$ns" --timeout=120s &>/dev/null && echo "✅就绪" || echo "⚠️未就绪"
+ done
+done; echo ""
+
+echo "========================================="; echo " 回滚完成"; echo "========================================="
+echo "CM: ✅$CS/❌$CF | 重启: ✅$RS/❌$RF"; echo "日志: $RL"
+[ "$RF" -gt 0 ] && { echo "⚠️ 有失败! cat $RL | grep FAIL"; exit 1; }
+echo "🎉 回滚完成!请验证业务。"; exit 0
+```
+
+---
+
+- **MSE 控制台**:https://mse.console.aliyun.com/
+- **MSE 内网地址**:`mse-97f57750-nacos-ans.mse.aliyuncs.com:8848`
+- **自建 Nacos 地址**:待补充
+- **已导出配置**:`nacos-config-export.zip`
+- **脚本**:本文档下方「脚本」章节
+- **备份目录**:`/backup/nacos-migration-*/`
+
+---
+
+## 执行记录
+
+| 时间 | 操作 | 结果 | 备注 |
+| --- | --- | --- | --- |
+| | | | |
+
+---
+
+## 问题与解决
+
+
+
+
+---
+
+## 复盘总结
+
+
+
+
+---
+
+**状态**: 待开始
+**关联 Issue**:
diff --git a/src/content/notes/07-Knowledge/07-定义Agent-从提示词工程到人设工程.md b/src/content/notes/07-Knowledge/07-定义Agent-从提示词工程到人设工程.md
new file mode 100644
index 0000000..69164dd
--- /dev/null
+++ b/src/content/notes/07-Knowledge/07-定义Agent-从提示词工程到人设工程.md
@@ -0,0 +1,142 @@
+---
+date: 2026-04-09
+tags: [学习, 知识, Multi-Agent, Agent定义, Prompt Engineering, CrewAI]
+type: 学习笔记
+category: 体系课
+source: https://b.geekbang.org/member/course/detail/948519
+difficulty: 进阶
+parent: "[[企业级多智能体设计实战]]"
+title: "07-定义Agent-从提示词工程到人设工程"
+---
+
+# 07|定义Agent:从"提示词工程"到"人设工程"
+
+> 企业级多智能体设计实战 · 模块一第1讲 | 时长 38:37 | 讲师:晓寒
+
+## 概述
+
+构建 Multi-Agent 系统需要完成思维转换:从"面向过程的程序员"转变为"面向组织的团队经理"。本讲聚焦组建 MVP 团队的第一步——**定人(定义 Agent)**,提出 **RGB 模型**(Role / Goal / Backstory)作为 Agent 定义的核心框架。
+
+## 核心概念
+
+### 思维视角转换
+
+| 传统思维 | Multi-Agent 思维 |
+|----------|-----------------|
+| 面向过程的程序员 | 面向组织的团队经理 |
+| 第一步干嘛、第二步干嘛 | 如何组建高效协作的团队 |
+| 死磕流程编排 | 定人 → 定事 → 定流程 |
+
+### MVP 团队三步法
+
+```
+定人(定义 Agent)→ 定事(定义 Task)→ 定流程(定义 Process)
+```
+
+### RGB 模型——Agent 定义的三个核心维度
+
+#### R - Role(角色):模型知识领域的激活
+
+- **核心价值**:唤醒并锁定大模型在特定垂直领域的专业认知
+- **作用机制**:设定极其明确的角色定位后,模型在推理和生成时会自发调取匹配的专业词汇、分析框架和行业黑话
+- **示例**:`资深小红书增长策略专家`(而非 `乐于助人的 AI 助手`)
+
+#### G - Goal(目标):Agent 的决策偏好
+
+- **核心价值**:决定 Agent 在面临选择时的价值导向
+- **关键区别**:Goal ≠ 具体待办事项,而是**宏观的偏好设定**
+- **本质**:告诉 Agent "以什么标准来衡量好坏"——行动的罗盘
+- **示例**:`基于 CES 互动评分算法,为产品制定能穿透"L1 冷启动池"并具有长尾搜索价值的内容策略`
+
+#### B - Backstory(背景故事):Agent 的行为与边界
+
+- **核心价值**:设定处事风格、工作流心法和能力边界
+- **核心原则**:**只存心法,不存招式**——写思考模式,不写机械步骤
+- **作用机制**:划定 Agent 的权责边界,防止协作时"越俎代庖"
+- **应包含**:理论储备、思维心法、行为边界、语言要求
+
+## 关键要点
+
+1. **Agent 定义的底层仍是 Prompt**:框架在运行时将 RGB 属性拼接为 `You are {role}. {backstory}\nYour personal goal is: {goal}` 发送给大模型。理解这点有助于排查 Agent "不听话"的问题。
+2. **Goal 是罗盘,Task 是终点**:Goal 中不应写具体格式要求,否则与 Task 冲突会导致产出深度大幅下降。
+3. **Backstory 只存心法不存招式**:写死流程会使 Agent 变成强耦合的一次性脚本,丧失通用性。
+4. **Role 越具体越好**:宽泛的角色无法激活模型深度专业知识,也会破坏 Multi-Agent 协作效率。
+
+## 实践示例
+
+### CrewAI 定义 Agent 的标准代码
+
+```python
+content_strategist = Agent(
+ role='资深小红书增长策略专家',
+ goal='基于 CES 互动评分算法,为产品制定一套能穿透"L1 冷启动池"并具有长尾搜索价值的内容策略。',
+ backstory="""
+ 你曾是国内顶级 MCN 机构的内容总监,深谙小红书 2025 年的算法变迁。
+ 你不再相信简单的流量铺张,而是坚信"价值耕耘"和"KFS 闭环"。
+
+ ** 核心理论储备 **:
+ - CES 评分机制:关注 (8分) > 评论 (4分) > 收藏 (1分) > 点赞 (1分)
+ - 反漏斗模型 (Anti-Funnel):先锁定最精准的核心人群,再寻求破圈
+ - 语义工程 SOP:爆款标题公式【痛点场景】+【解决方案/情绪钩子】+【群体标签】
+
+ ** 思维心法 **:
+ 1. 反漏斗定位:找到产品最"痛"的细分场景
+ 2. 设计钩子:互动钩子 + 价值锚点
+ 3. 关键词布局:指定 3 个核心长尾词
+ 4. 分步骤慢思考:使用 IntermediateTool 保存中间结果
+
+ ** 行为边界 **:只负责输出策略大纲(Brief),绝对不要撰写最终的正文或示例文案。
+ ** 语言要求 **:所有思考过程、工具调用和最终输出都必须使用中文。
+ """,
+ verbose=True,
+ allow_delegation=False,
+ tools=[IntermediateTool()],
+ llm=AliyunLLM(model="qwen-plus", api_key=os.getenv("QWEN_API_KEY"), region="cn"),
+)
+
+# 执行任务
+messages = [{"role": "user", "content": "我今天健身了,感觉很累,但是很开心。帮我设计一篇笔记"}]
+result = content_strategist.kickoff(messages)
+```
+
+## 常见问题 / 坑点
+
+| 问题 | 原因 | 解决方案 |
+|------|------|----------|
+| Agent 产出内容浅显、缺乏专业性 | Role 设定太宽泛(如"你是一个 AI 助手") | 设定极度垂直的角色定位,激活模型专业领域知识 |
+| Agent 急于拼凑格式而忽略内容深度 | Goal 中写了具体格式要求,与 Task 冲突 | Goal 只写决策偏好和价值导向,具体格式放 Task |
+| Agent 变成一次性脚本,丧失通用性 | Backstory 中写死了具体执行步骤 | Backstory 只存心法(思考模式),不存招式(机械步骤) |
+| Multi-Agent 协作混乱 | Agent 角色边界模糊,其他 Agent 不知该委托什么任务 | 在 Backstory 中明确行为边界,用 `allow_delegation=False` |
+| 排查 Agent "不听话"无从下手 | 不理解 RGB 底层仍是 Prompt 拼接 | 理解框架将 RGB 组装为 System Prompt 的机制,精准定位冲突 |
+
+## 最佳实践
+
+1. **运用"元提示词"技巧**:让大模型帮你生成和优化 Prompt,而非纯靠人工编写
+2. **Role 要垂直精准**:`资深小红书增长策略专家` 远优于 `AI 助手`
+3. **Goal 要宏观抽象**:描述"做什么事能得到奖励",不描述具体输出格式
+4. **Backstory 要结构化**:分块写理论储备、思维心法、行为边界、语言要求
+5. **显式声明行为边界**:明确 Agent "该做什么、不该做什么",防止越权
+
+## 关联知识
+
+- [[企业级多智能体设计实战]](课程总览)
+- 下一讲:08|定义 Task——从"步骤控制"到"契约驱动"
+
+## 参考资源
+
+- 课程链接:https://b.geekbang.org/member/course/detail/948519
+- 示例代码:https://github.com/kid0317/crewai_mas_demo/blob/main/m2l3/m2l3_agent.py
+
+## 学习时间
+
+| 阶段 | 时间 | 备注 |
+|------|------|------|
+| 初次学习 | 2026-04-09 | 观看视频 + 整理笔记 |
+| 深入理解 | | |
+| 实战应用 | | |
+| 复习回顾 | | |
+
+---
+
+**状态**: 📖 已掌握
+**下次复习日期**: 2026-04-16
diff --git a/src/content/notes/07-Knowledge/08-定义Task-从步骤控制到契约驱动.md b/src/content/notes/07-Knowledge/08-定义Task-从步骤控制到契约驱动.md
new file mode 100644
index 0000000..9665746
--- /dev/null
+++ b/src/content/notes/07-Knowledge/08-定义Task-从步骤控制到契约驱动.md
@@ -0,0 +1,129 @@
+---
+date: 2026-04-09
+tags: [学习, 知识, Multi-Agent, Task设计, 契约驱动, Pydantic, CrewAI]
+type: 学习笔记
+category: 体系课
+source: https://b.geekbang.org/member/course/detail/948519
+difficulty: 进阶
+parent: "[[企业级多智能体设计实战]]"
+title: "08-定义Task-从步骤控制到契约驱动"
+---
+
+# 08|定义Task——从"步骤控制"到"契约驱动"
+
+> 企业级多智能体设计实战 · 模块一第2讲 | 时长 33:54 | 讲师:晓寒
+
+## 概述
+
+一切 AI 应用本质上都是在执行任务(Input → 执行 → Output)。本讲提出**"任务定义终点,而非路径"**的核心心法,引入**契约驱动**的任务设计模式,使用 Pydantic 定义结构化交付标准来掌控大模型输出的确定性。
+
+## 核心概念
+
+### 认知原点——一切 AI 应用皆为"Task"
+
+```
+Input(用户诉求) → 执行过程(思考、调用工具、协作) → Output(交付物)
+```
+
+未来 AI 应用评测的核心依据:对比"输入"和"产出"是否匹配预期标准。
+
+### 火车轨道 vs 里程碑(核心心法)
+
+| 模式 | 思维 | 风险 |
+|------|------|------|
+| 🚂 火车轨道(传统工作流) | 规定第一步做什么、第二步怎么做 | 中途意外 → 彻底脱轨崩溃 |
+| 🏁 里程碑(契约驱动) | 定义阶段交付成果,中间自主决策 | 灵活适应不确定性 |
+
+**核心原则:任务定义终点,而非路径。**
+
+### Pydantic 结构化交付标准
+
+使用 Pydantic 定义任务的目标输出结构,底层作用机制:
+
+1. **提示词注入**:框架将 Pydantic 定义转换为 JSON Schema,硬编码注入 System Prompt
+2. **结果提取与验证**:模型倾向于按 JSON 结构输出 → 框架 JSON 提取器抓取 → Pydantic 反向校验
+3. **确定性转化**:将不确定的自然语言文本转化为确定性的工程数据字典
+
+## 关键要点
+
+1. **Goal 是罗盘,Task 是终点**:Goal 描述决策偏好,Task 描述具体交付物
+2. **结构化交付标准 = 掌控确定性的最强武器**:Pydantic 不仅定义数据类型,更要在字段描述中写清质量标准
+3. **底层仍是 Prompt**:框架将 Pydantic schema 拼入 prompt,如 `Ensure your final answer strictly adheres to the following OpenAPI schema: {schema}`
+4. **契约驱动体现**:下游任务依赖上游任务的输出格式,`Crew.kickoff(inputs={...})` 将变量替换到 prompt 中
+
+## 实践示例
+
+### CrewAI Task 定义的标准代码
+
+```python
+from pydantic import BaseModel, Field
+from crewai import Task
+
+class ContentStrategyBrief(BaseModel):
+ target_audience: str = Field(..., description="目标人群画像,需包含核心痛点")
+ core_angle: str = Field(..., description="内容切入角度,需独特且具争议性/共鸣性")
+ hook_design: str = Field(..., description="互动钩子设计,包含争议问题和价值锚点")
+ keyword_plan: list[str] = Field(..., description="3个核心长尾关键词")
+ emotional_tone: str = Field(..., description="整体情绪基调")
+
+task_content_strategy = Task(
+ description="""
+ 基于用户的原始意图和视觉分析报告,制定小红书内容策略。
+
+ 用户的原始想法:
+ {user_raw_intent}
+
+ 视觉分析报告:
+ {visual_report}
+
+ ** 重要提示 **:
+ - 必须基于上游任务的视觉分析报告进行分析
+ - 策略要符合小红书平台的算法特点
+ - 所有输出必须使用中文
+ """,
+ expected_output="一个完整的 ContentStrategyBrief 结构化输出,包含所有必填字段。",
+ agent=content_strategist,
+ output_pydantic=ContentStrategyBrief, # 💡 强约束结构化输出
+)
+```
+
+## 常见问题 / 坑点
+
+| 问题 | 原因 | 解决方案 |
+|------|------|----------|
+| Agent 逻辑混乱、什么都做不好 | 注意力涣散的超级任务——多个不相关子目标塞进同一任务 | 每个任务聚焦单一里程碑,一个任务只做一件事 |
+| Agent 陷入死循环,不知何时输出 Final Answer | 未设定明确的验收标准(expected_output) | 必须提供清晰的 expected_output 和 output_pydantic |
+| Agent 幻觉严重、生搬硬套 | 流程步骤过度微操——规定过细的操作步骤 | 只定义交付标准(里程碑),不规定执行路径 |
+| 产出深度不够 | Pydantic 只定义了数据类型,没有质量标准 | 在 Field 的 description 中写清明确的质量判断标准 |
+
+## 最佳实践
+
+1. **Pydantic 中同时明确结构和判断标准**:`Field(..., description="需包含...")` 而非仅 `Field(..., description="标题")`
+2. **一个 Task 只做一件事**:搜索归搜索,写代码归写代码,文案归文案
+3. **用 expected_output 聚焦注意力**:明确的交付要求能强行聚焦大模型注意力
+4. **下游任务显式引用上游输出**:在 description 中用 `{variable}` 引用上游 TaskOutput
+
+## 关联知识
+
+- [[07-定义Agent-从提示词工程到人设工程]](上一定义 Agent)
+- [[09-定义Process-任务调度与信息传递]](下一讲流程编排)
+- [[11-项目实践一-小红书爆款笔记生成项目]](综合实战)
+
+## 参考资源
+
+- 课程链接:https://b.geekbang.org/member/course/detail/948519
+- 示例代码:https://github.com/kid0317/crewai_mas_demo/blob/main/m2l4/m2l4_task.py
+
+## 学习时间
+
+| 阶段 | 时间 | 备注 |
+|------|------|------|
+| 初次学习 | 2026-04-09 | 视频观看 + 笔记整理 |
+| 深入理解 | | |
+| 实战应用 | | |
+| 复习回顾 | | |
+
+---
+
+**状态**: 📖 已掌握
+**下次复习日期**: 2026-04-16
diff --git a/src/content/notes/07-Knowledge/09-定义Process-任务调度与信息传递.md b/src/content/notes/07-Knowledge/09-定义Process-任务调度与信息传递.md
new file mode 100644
index 0000000..c5e9046
--- /dev/null
+++ b/src/content/notes/07-Knowledge/09-定义Process-任务调度与信息传递.md
@@ -0,0 +1,154 @@
+---
+date: 2026-04-09
+tags: [学习, 知识, Multi-Agent, Process, 任务调度, Context, DAG, CrewAI]
+type: 学习笔记
+category: 体系课
+source: https://b.geekbang.org/member/course/detail/948519
+difficulty: 进阶
+parent: "[[企业级多智能体设计实战]]"
+title: "09-定义Process-任务调度与信息传递"
+---
+
+# 09|定义 Process——任务调度与信息传递
+
+> 企业级多智能体设计实战 · 模块一第3讲 | 时长 32:50 | 讲师:晓寒
+
+## 概述
+
+Process(流程)的本质是**任务的调度方式(Task Scheduling)**。本讲深度解析顺序执行(Sequential)模式,剖析 TaskOutput 与 Context 的数据传递机制,并揭示了 `crew.kickoff()` 背后的底层运行逻辑——本质上是一个由 Task List 和 TaskOutput List 双向互动的 for 循环。
+
+## 核心概念
+
+### Process 的本质
+
+Process 决定的是:一组 Task 启动后,以什么节奏执行?
+
+```
+Agent(数字员工) + Task(里程碑目标) + Process(调度策略) = Multi-Agent 系统
+```
+
+### 顺序执行(Sequential Process)
+
+最基础、最稳定、最实用的调度模式:
+- 开发者预先为每个 Task 分配好 Agent
+- `kickoff()` 后严格按任务列表顺序逐一执行
+- 轮到某个任务时,唤醒绑定的 Agent 进行思考、工具调用和结果输出
+
+### 数据传递的两大核心概念
+
+#### TaskOutput(任务输出 / 交接棒)
+
+每个 Task 执行完毕后封装的标准化数据对象,包含:
+
+| 字段 | 说明 |
+|------|------|
+| `description` | 当前任务的描述信息(回答什么问题) |
+| `raw` | 大模型返回的最原始字符串 |
+| `pydantic` | 经框架提取和反向校验后的强类型数据字典 |
+
+#### Context(上下文 / 信息依赖)
+
+| 传递方式 | 行为 | 风险 |
+|----------|------|------|
+| **隐式传递**(不设 context) | 框架将前面所有 TaskOutput 拼接为背景信息 | ❌ 上下文超载、注意力分散 |
+| **显式传递**(`context=[task_a]`) | 精准声明依赖,只传递指定任务的输出 | ✅ 推荐:精准、节省 Token |
+
+### kickoff() 底层五大执行步骤
+
+```
+1. 遍历 Task List(Task 1, 2, ... n)
+2. 分配 Agent(确认当前 Task 绑定的数字员工)
+3. 填入 Context(从 TaskOutput List 提取依赖,拼接成 Prompt)
+4. Agent 执行(触发 ReAct 循环,思考与行动)
+5. 解析 TaskOutput(存入 TaskOutput List,供后续循环调用)
+→ 不断循环,直到最后一个任务完成
+```
+
+## 关键要点
+
+1. **Process 本质就是调度算法**:将 AI 框架概念还原为传统软件工程的经典问题
+2. **显式 Context 构建有向无环图(DAG)**:通过 `context=[task_a, task_b]` 构建清晰的数据依赖
+3. **"做减法"是最核心原则**:多余且无关的上下文不仅浪费 Token,更会严重分散注意力
+4. **理解底层才能脱离框架**:kickoff() 本质是两个列表的双向 for 循环,完全可以手搓
+
+## 实践示例
+
+### Sequential + 显式 Context 的工程实现
+
+```python
+from crewai import Crew, Process, Task
+
+# 1. 初始任务:内容策划(无上游依赖)
+task_content_strategy = Task(
+ description="基于视觉报告,制定整体的小红书内容策略...",
+ expected_output="结构化的内容策略简报",
+ agent=content_strategist,
+)
+
+# 2. 下游任务:文案撰写(显式依赖内容策划)
+task_copywriting = Task(
+ description="基于内容策略,撰写小红书笔记文案...",
+ expected_output="包含标题和正文的文案",
+ agent=content_writer,
+ context=[task_content_strategy], # 💡 显式声明信息依赖
+)
+
+# 3. 末端任务:SEO 优化(多依赖)
+task_seo_optimization = Task(
+ description="对现有文案进行长尾关键词和 SEO 优化...",
+ expected_output="优化后的最终笔记",
+ agent=seo_optimizer,
+ context=[task_content_strategy, task_copywriting], # 💡 多依赖声明
+)
+
+# 4. 组装 Crew
+crew = Crew(
+ agents=[content_strategist, content_writer, seo_optimizer],
+ tasks=[task_content_strategy, task_copywriting, task_seo_optimization],
+ process=Process.sequential, # 顺序执行
+ verbose=True,
+)
+result = crew.kickoff(inputs={"visual_report": "{...}"})
+```
+
+## 常见问题 / 坑点
+
+| 问题 | 原因 | 解决方案 |
+|------|------|----------|
+| 产出质量大幅下滑 | 上下文超载(Context Overload)——隐式传递所有上游输出 | 始终显式指定 `context=[...]`,精准控制依赖 |
+| Token 成本飙升 | 不设 context,冗杂信息占用上下文窗口 | 做减法,只传递下游真正需要的数据 |
+| 系统整体耗时过长 | 任务拆分过细——把微操作拆成独立 Task | 平衡粒度,找到里程碑的合适粗细 |
+| 任务失败导致全链路崩溃 | Sequential 流水线的"单点故障" | 设计容错逻辑:Fail-Fast 或有边界重试机制 |
+| Agent 陷入死循环 | 任务拆分过粗,Agent 难以处理 | 将大任务拆为可独立验收的小里程碑 |
+
+## 最佳实践
+
+1. **始终显式指定 Context**:`context=[task_a, task_b]` 强制规范,倒逼理清数据流转
+2. **平衡任务粒度**:不过粗(死循环)不过细(Token 成本飙升)
+3. **构建健壮的错误处理**:API 宕机、模型超时时选择 Fail-Fast 或有边界重试
+4. **理解底层后可脱离框架**:两个列表 + for 循环即可实现基础调度引擎
+
+## 关联知识
+
+- [[08-定义Task-从步骤控制到契约驱动]](上一讲 Task 设计)
+- [[10-多模态模型-让你的Agent拥有眼睛]](下一讲多模态能力)
+- [[11-项目实践一-小红书爆款笔记生成项目]](综合实战)
+
+## 参考资源
+
+- 课程链接:https://b.geekbang.org/member/course/detail/948519
+- 示例代码:https://github.com/kid0317/crewai_mas_demo/blob/main/m2l5/m2l5_crew.py
+
+## 学习时间
+
+| 阶段 | 时间 | 备注 |
+|------|------|------|
+| 初次学习 | 2026-04-09 | 视频观看 + 笔记整理 |
+| 深入理解 | | |
+| 实战应用 | | |
+| 复习回顾 | | |
+
+---
+
+**状态**: 🌱 学习中
+**下次复习日期**: 2026-04-16
diff --git a/src/content/notes/07-Knowledge/10-多模态模型-让你的Agent拥有眼睛.md b/src/content/notes/07-Knowledge/10-多模态模型-让你的Agent拥有眼睛.md
new file mode 100644
index 0000000..e15a6f8
--- /dev/null
+++ b/src/content/notes/07-Knowledge/10-多模态模型-让你的Agent拥有眼睛.md
@@ -0,0 +1,150 @@
+---
+date: 2026-04-09
+tags: [学习, 知识, Multi-Agent, 多模态, 视觉模型, vCoT, Base64, CrewAI]
+type: 学习笔记
+category: 体系课
+source: https://b.geekbang.org/member/course/detail/948519
+difficulty: 进阶
+parent: "[[企业级多智能体设计实战]]"
+title: "10-多模态模型-让你的Agent拥有眼睛"
+---
+
+# 10|多模态模型:让你的 Agent 拥有"眼睛"
+
+> 企业级多智能体设计实战 · 模块一第4讲 | 时长 30:28 | 讲师:晓寒
+
+## 概述
+
+本讲聚焦**多模态文本生成模型**(Image-to-Text),而非文生图。核心公式为**视觉任务 = 图片 + Prompt**。通过自定义 `AddImageToolLocal` 工具,让 Agent 具备读取本地图片、Base64 编码、注入上下文的能力,并结合 vCoT(视觉思维链)和漏斗过滤架构实现企业级落地的正确姿势。
+
+## 核心概念
+
+### 多模态文本生成 vs 文生图
+
+| 方向 | 代表工具 | 输入 → 输出 |
+|------|----------|-------------|
+| 文生图(Text-to-Image) | Midjourney, Stable Diffusion | 文字 → 图片 |
+| **图生文(Image-to-Text)** | **本讲重点** | **图片 → 结构化文字/数据** |
+
+### 底层原理:模型如何"看懂"图片
+
+```
+图片 → 视觉编码器 → 视觉 Token 序列 → 与文本 Prompt 拼接 → 大模型联合推理 → 文字输出
+```
+
+图片的像素特征被视觉编码器切分并映射到大模型能理解的语义空间,与文本 Prompt 一起拼接成超长上下文。
+
+### 核心公式:视觉任务 = 图片 + Prompt
+
+- **图片**:提供具象的信息描述
+- **Prompt**:提供任务的分析逻辑(重点看什么、提取什么特征、按什么格式输出)
+- 常见误区:直接扔图片不给 Prompt,模型无法返回想要的结果
+
+### AddImageToolLocal 的作用
+
+原生 CrewAI 只支持网络 URL 的多模态请求。自定义工具的核心功能:
+
+1. 读取本地 JPG/PNG 文件
+2. 压缩图片至合适分辨率(控制 Token 消耗)
+3. 转换为 Base64 Data URL 格式
+4. 注入到 Agent 的上下文中
+
+### vCoT(Visual Chain of Thought)
+
+类似文本模型的 CoT,图片分析也需强制分步思考:
+
+| 步骤 | 动作 | 说明 |
+|------|------|------|
+| 1 | **Describe**(描述) | 陈述图片中客观看到的物体、颜色 |
+| 2 | **Reason**(推理) | 基于事实,结合业务背景进行推导 |
+| 3 | **Conclude**(结论) | 给出最终分析结论或输出 JSON |
+
+### 漏斗过滤架构(低成本批量处理)
+
+```
+海量图片 → [第一层] 低分辨率粗筛(廉价快速) → 命中图片 → [第二层] 高分辨率精筛(深度提取) → 结果
+```
+
+## 关键要点
+
+1. **图片必须压缩**:大模型不需要 4K/8K 极限高清,限制长边在 1024-2048 像素即可
+2. **Pydantic 强制结构化输出**:`output_pydantic=ImageAnalysis` 确保视觉分析结果可被下游消费
+3. **multimodal=True 是关键配置**:开启框架的多模态支持,Agent 才能处理图片输入
+4. **不要用大模型纯做 OCR**:除非文档有强语义的排版格式(复杂表格、架构图),此时多模态模型有降维打击优势
+
+## 实践示例
+
+### 多模态 Agent + 结构化输出的完整代码
+
+```python
+from crewai import Agent, Task, Crew
+from pydantic import BaseModel, Field
+from tools.add_image_tool_local import AddImageToolLocal
+
+# 1. 定义结构化输出模型
+class ImageAnalysis(BaseModel):
+ file_name: str = Field(..., description="图片文件名")
+ subject_description: str = Field(..., description="图片中主要物品、人物或场景的客观描述")
+ atmosphere_vibe: str = Field(..., description="图片传递的整体氛围感和情绪价值")
+ visual_details: list[str] = Field(..., description="至少 3 个关键的视觉细节亮点")
+
+# 2. 定义多模态 Agent
+visual_analyst = Agent(
+ role="资深视觉分析师",
+ goal="准确解析图片内容,提取核心视觉卖点和氛围感",
+ backstory="你是一位拥有多年经验的产品视觉分析师...",
+ llm=aliyun_vl_llm, # 绑定支持多模态的 LLM
+ multimodal=True, # 💡 开启多模态支持
+ tools=[AddImageToolLocal()], # 💡 赋予读取本地图片的工具
+)
+
+# 3. 定义任务
+analysis_task = Task(
+ description="请使用工具加载本地图片 {image_path},对图片进行整体与细节的多维度观察...",
+ expected_output="结构化的视觉分析结果",
+ agent=visual_analyst,
+ output_pydantic=ImageAnalysis, # 强制结构化输出
+)
+```
+
+## 常见问题 / 坑点
+
+| 问题 | 原因 | 解决方案 |
+|------|------|----------|
+| Token 账单飙升、请求超时 | 像素倾倒——直接扔 4K/8K 原图给模型 | 代码层压缩图片,长边限制在 1024-2048 像素 |
+| 纯文字提取准确率低 | 用大模型做 OCR——不经济且不如专业 OCR 引擎 | 纯文字场景用传统 OCR;复杂排版/表格/架构图才用多模态 |
+| 视觉幻觉(分析不准确) | 没有引导模型分步思考 | 使用 vCoT:Describe → Reason → Conclude |
+| 批量图片处理太慢太贵 | 逐张高分辨率处理 | 漏斗架构:低清粗筛 → 高清精筛 |
+| 原生 CrewAI 不支持本地图片 | 框架只支持网络 URL | 自定义 AddImageToolLocal 工具 |
+
+## 最佳实践
+
+1. **Prompt 引导视觉分析方向**:告诉模型重点看什么、提取什么特征
+2. **图片预处理是必修课**:压缩 + 分辨率限制,平衡精度与成本
+3. **vCoT 降低视觉幻觉**:强制三步走(描述 → 推理 → 结论)
+4. **结构化输出贯穿始终**:Pydantic 定义输出结构,便于下游任务消费
+
+## 关联知识
+
+- [[09-定义Process-任务调度与信息传递]](上一讲流程编排)
+- [[11-项目实践一-小红书爆款笔记生成项目]](综合实战)
+- [[07-定义Agent-从提示词工程到人设工程]](Agent RGB 模型)
+
+## 参考资源
+
+- 课程链接:https://b.geekbang.org/member/course/detail/948519
+- 示例代码:https://github.com/kid0317/crewai_mas_demo/blob/main/m2l6/m2l6_agent.py
+
+## 学习时间
+
+| 阶段 | 时间 | 备注 |
+|------|------|------|
+| 初次学习 | 2026-04-09 | 视频观看 + 笔记整理 |
+| 深入理解 | | |
+| 实战应用 | | |
+| 复习回顾 | | |
+
+---
+
+**状态**: 🌱 学习中
+**下次复习日期**: 2026-04-16
diff --git a/src/content/notes/07-Knowledge/11-项目实践一-小红书爆款笔记生成项目.md b/src/content/notes/07-Knowledge/11-项目实践一-小红书爆款笔记生成项目.md
new file mode 100644
index 0000000..21b4ed1
--- /dev/null
+++ b/src/content/notes/07-Knowledge/11-项目实践一-小红书爆款笔记生成项目.md
@@ -0,0 +1,146 @@
+---
+date: 2026-04-10
+tags: ["CrewAI", "Multi-Agent", "小红书", "项目实战", "FastAPI"]
+type: 学习笔记
+category: AI工程
+source: 极客时间《企业级多智能体设计实战》第11讲
+difficulty: 高级
+title: "11-项目实践一-小红书爆款笔记生成项目"
+---
+
+# 11|项目实践(一):小红书爆款笔记生成项目
+
+## 概述
+
+第一个核心项目实践,从0到1打造一个真正能够应用于企业级生产环境的复杂 Multi-Agent 系统:小红书爆款笔记生成引擎。集成了视觉分析、策略规划、文案撰写与SEO优化,并支持完整API调用的后端服务系统。
+
+**项目地址**:https://github.com/kid0317/crewai_mas_demo_m2l7
+
+## 核心概念
+
+### 1. 产品需求与业务目标
+
+**输入**:几张未修的图片 + 一段粗略的灵感或想法
+**输出**:结构化的、可直接落地的爆款笔记方案
+
+**核心业务流程**:
+- 单图多模态解析:每图独立输出视觉分析与P图方案
+- 全局内容策划:基于所有图片特征制定内容策略简报
+- 文案生成:符合小红书网感、自带Emoji的标题与正文
+- SEO与分发优化:提炼5-8个长尾标签 + 图片发布顺序建议
+
+### 2. 核心架构:Agent-Task-Process 深度设计
+
+**5大专业数字员工**:
+
+| Agent | 职责 | 特殊配置 |
+|-------|------|---------|
+| 视觉分析师 | 图片视觉分析、P图方案 | 多模态模型(qwen3-vl-plus) + AddImageToolLocal |
+| 内容撰写员 | 撰写符合小红书网感的文案 | 纯文本高智商模型 |
+| SEO专家 | 提炼标签、优化分发 | 懂KFS闭环和长尾关键词 |
+| 内容策划师 | 制定整体内容策略 | 协调各Agent输出 |
+| 编辑排版师 | 最终排版与格式优化 | - |
+
+**工程最佳实践**:Agent人设文案放在YAML配置,LLM和Tools绑定放在Python代码。
+
+### 3. 异步并发 + 串行混合编排
+
+**传统问题**:依次识别10张图会耗费极长时间,API严重超时。
+
+**解决方案**:
+- **多模态极速并发**:每张图并发执行"视觉分析Task"和"编辑方案Task"
+- **业务逻辑严密串行**:汇总为XhsVisualBatchReport后,按"内容策划→文案撰写→搜索优化"顺序执行
+
+### 4. FastAPI云原生部署
+
+**选型理由**:AI任务耗时数秒至数分钟,FastAPI基于uvloop的异步事件循环确保等待大模型时不阻塞服务器线程。
+
+**架构分层**:
+- Service层:封装调用逻辑、错误处理、监控日志埋点
+- API路由层:暴露run_xhs_note_flow HTTP接口
+- 前端接入:业务前端可直接调用
+
+## 关键要点
+
+1. **人设工程**:5个Agent各司其职,避免"全能Agent"反模式
+2. **YAML解耦**:Agent配置与代码分离,便于非技术人员调整
+3. **契约驱动**:所有核心产出强制遵循Pydantic结构化输出
+4. **显式依赖**:通过context参数精准传递上游结果,杜绝上下文污染
+5. **异步编排**:图片处理并行化,策略任务串行化,显著压缩等待时间
+
+## 实践示例
+
+### Agent定义(agents.py)
+```python
+def get_xhs_visual_analyst() -> Agent:
+ cfg_visual = _agent_cfg("xhs_visual_analyst") # 从YAML读取
+ return Agent(
+ config=cfg_visual,
+ multimodal=True, # 开启多模态
+ llm=get_llm(image_model="qwen3-vl-plus"),
+ tools=[AddImageToolLocal()],
+ )
+```
+
+### Task定义(tasks.py)
+```python
+def get_task_copywriting(content_strategy_task: Task) -> Task:
+ return Task(
+ description=cfg.get("description", ""),
+ expected_output=cfg.get("expected_output", ""),
+ agent=get_xhs_content_writer(),
+ context=[content_strategy_task], # 显式依赖上游
+ output_pydantic=XhsCopywritingOutput, # 结构化输出
+ async_execution=False,
+ )
+```
+
+### Process编排(flows.py)
+```python
+# 1. 图片并发处理
+visual_tasks = []
+for img in images:
+ visual_tasks.append(get_visual_analysis_task(img))
+ visual_tasks.append(get_edit_plan_task(img))
+
+# 2. 策略任务串行执行
+strategy_task = get_content_strategy_task(context=visual_tasks)
+copywriting_task = get_copywriting_task(context=[strategy_task])
+seo_task = get_seo_task(context=[copywriting_task])
+```
+
+## 常见问题/坑点
+
+| 问题 | 原因 | 解决方案 |
+|------|------|---------|
+| API接口超时 | 串行处理多张图片耗时太长 | 图片处理阶段改为异步并发 |
+| 上下文污染 | Task之间传递不清晰 | 使用显式context参数 + Pydantic约束 |
+| 输出格式不一致 | 没有结构化约束 | 所有核心产出必须遵循output_pydantic |
+| 人设调整困难 | 代码与配置混在一起 | YAML解耦,非技术人员可独立调整 |
+
+## 关联知识
+
+- [[07-定义Agent-从提示词工程到人设工程]]:Agent RGB模型
+- [[08-定义Task-从步骤控制到契约驱动]]:Task结构化输出
+- [[09-定义Process-任务调度与信息传递]]:Process模式
+- [[10-多模态模型-让你的Agent拥有眼睛]]:多模态能力
+
+## 参考资源
+
+- 课程源码:https://github.com/kid0317/crewai_mas_demo_m2l7
+- FastAI框架:https://github.com/kid0317/fastapi_base
+
+## 学习时间
+
+- 课程时长:42:50
+- 笔记整理:2026-04-10
+
+## 状态
+
+- [x] 课程学习
+- [ ] 代码实践
+- [ ] 项目复现
+
+## 下次复习日期
+
+2026-04-17
diff --git a/src/content/notes/07-Knowledge/12-工具设计哲学-从API到Agent-Native的范式跃迁.md b/src/content/notes/07-Knowledge/12-工具设计哲学-从API到Agent-Native的范式跃迁.md
new file mode 100644
index 0000000..4304329
--- /dev/null
+++ b/src/content/notes/07-Knowledge/12-工具设计哲学-从API到Agent-Native的范式跃迁.md
@@ -0,0 +1,16 @@
+---
+title: "12-工具设计哲学-从API到Agent-Native的范式跃迁"
+publish: true
+---
+
+---
+date: 2026-04-10
+tags: [AI, Agent, Tools, 工具设计, API, Agent-Native, 企业级]
+type: 学习笔记
+category: AI工程
+source: 极客时间「企业级多智能体设计实战」第12讲
+difficulty: 高级
+概述: 从API思维到Agent-Native工具思维的跃迁,探讨面向大模型的工具设计哲学,实现企业级多租户安全调用
+核心概念: [Native Function Calling, ReAct范式, 语义完整性, 建设性报错, contextvars, Hook拦截, 上下文隔离]
+关键要点:
+ - 传统API给
\ No newline at end of file
diff --git a/src/content/notes/07-Knowledge/13-自定义工具封装-构建Tools的五步标准SOP.md b/src/content/notes/07-Knowledge/13-自定义工具封装-构建Tools的五步标准SOP.md
new file mode 100644
index 0000000..6437045
--- /dev/null
+++ b/src/content/notes/07-Knowledge/13-自定义工具封装-构建Tools的五步标准SOP.md
@@ -0,0 +1,302 @@
+---
+date: 2026-04-10
+tags: [AI, Agent, Tools, 工具封装, SOP, API改造, 企业级]
+type: 学习笔记
+category: AI工程
+source: 极客时间「企业级多智能体设计实战」第13讲
+difficulty: 高级
+概述: 从传统API到Agent Tools封装的五步标准SOP,手把手实战百度搜索API的改造
+核心概念: [五步SOP, 语义重构, I/O瘦身, Pydantic描述, 建设性异常, 黑盒映射, 搜索结果格式化]
+关键要点:
+ - 五步SOP:语义重构→I/O瘦身→参数Prompt化→建设性异常→黑盒映射
+ - 语义重构:组合原子API,提供目标导向的闭环能力
+ - I/O瘦身:剔除冗余字段,保护Token上下文
+ - Pydantic描述:用Field充当使用说明书
+ - 建设性异常:自然语言包裹错误,激活自我纠错
+ - 黑盒映射:极简输入到复杂请求的暗中转换
+ - 结果格式化:清晰结构化输出帮助模型理解
+实践示例:
+ - BaiduSearchTool完整封装
+ - Pydantic模型定义搜索参数
+ - 错误码映射为自然语言提示
+ - 搜索结果格式化输出
+常见问题/坑点:
+ - 不要将复杂API直接暴露给大模型
+ - 避免返回原始JSON让模型自己解析
+ - 错误码必须转换为自然语言
+关联知识:
+ - [[12-工具设计哲学-从API到Agent-Native的范式跃迁]]
+ - [[14-MCP协议-标准化定义工具接口]]
+参考资源:
+ - 课程代码: https://github.com/kid0317/crewai_mas_demo/tree/main/m2l9
+学习时间: 34分钟
+状态: 已完成
+下次复习日期: 2026-04-17
+title: "13-自定义工具封装-构建Tools的五步标准SOP"
+---
+
+# 13|自定义工具封装:构建 Tools 的五步标准 SOP
+
+> 讲师:晓寒(前百度资深架构师)
+> 课程进度:66%
+
+## 一、课程目标
+
+将成百上千个历史遗留的传统API,平滑改造成大模型能轻松驾驭的**Agent Tools**。
+
+**核心交付物**:五步标准 SOP(Standard Operating Procedure)
+
+---
+
+## 二、五步标准 SOP 全景图
+
+### Step 1:语义完整性重构(聚合与拆解)
+
+**问题所在**:
+- 传统后端API是数据驱动、原子化的(CRUD)
+- 大模型是目标驱动的
+
+**反例**:
+```
+❌ 让大模型自己规划:
+ 1. get_user_by_name(name) → 获取ID
+ 2. check_permission(id) → 校验权限
+ 3. update_user_info(id, info) → 更新信息
+```
+
+**SOP动作**:在工具层进行接口聚合
+
+```
+✅ 提供语义完整的单一工具:
+ update_user_info_by_name(name, info)
+
+ 内部用Python代码依次调用那三个底层API
+```
+
+**原则**:让大模型做它擅长的「意图理解」,让代码做「确定性流转」。
+
+---
+
+### Step 2:I/O 瘦身(降噪增信)
+
+**问题所在**:传统API输入输出包含大量对大模型无意义的元数据
+
+**反例(臃肿的API输入)**:
+```json
+{
+ "messages": [{"content": "北京有哪些旅游景区", "role": "user"}],
+ "search_source": "baidu_search_v2",
+ "resource_type_filter": [{"type": "web", "top_k": 20}],
+ "search_filter": {
+ "match": {"site": ["www.weather.com.cn"]},
+ "query": {"filter": {"range": {"date": {"gte": "2026-01-01"}}}}
+ },
+ "search_strategy": "standard_search_v2",
+ "top_k": 5
+}
+```
+
+**SOP动作**:剔除冗余,保留精华
+
+```python
+✅ # Agent Tool 极简参数
+class BaiduSearchInput(BaseModel):
+ """百度搜索工具的输入参数"""
+ query: str = Field(
+ description="搜索关键词,需要清晰、准确地描述你想要查找的信息"
+ )
+ top_n: int = Field(
+ default=5,
+ description="期望返回的搜索结果数量(1-10),默认5条"
+ )
+```
+
+**要点**:
+- 剔除前端无关的元数据(messages, search_source等)
+- 核心参数:`query`(关键词)+ `top_n`(数量)
+- 其余复杂配置在**黑盒中静默处理**
+
+---
+
+### Step 3:参数 Prompt 化(Pydantic描述)
+
+**核心原则**:参数的`description`不是给程序员看的,是**给大模型看的使用说明书**。
+
+**实战代码**:
+```python
+from pydantic import BaseModel, Field
+
+class BaiduSearchInput(BaseModel):
+ """百度搜索工具的输入参数"""
+
+ query: str = Field(
+ description="""
+ 搜索关键词,需要清晰、准确地描述你想要查找的信息。
+ 如果查询涉及时间、地点等上下文,建议显式包含在查询中。
+ 例如:"2026年北京春节期间的旅游景点推荐" 比 "旅游景点" 效果更好。
+ """
+ )
+
+ top_n: int = Field(
+ default=5,
+ description="期望返回的搜索结果数量(1-10),默认5条。如果问题较复杂,可适当增加。"
+ )
+```
+
+**关键技巧**:
+- `Field`的`description`要包含**使用场景**和**最佳实践**
+- 给出**具体示例**(如"2026年北京春节期间...")
+- 说明**参数约束**(如范围1-10)
+
+---
+
+### Step 4:建设性异常处理(Constructive Error)
+
+**反例(糟糕的错误返回)**:
+```
+❌ 错误码1001
+❌ NullPointerException堆栈
+❌ 空字符串""
+```
+→ 大模型直接懵圈,陷入死循环
+
+**SOP动作**:用自然语言包裹错误,激活自我纠错
+
+**实战代码**:
+```python
+class BaiduSearchTool(BaseTool):
+ def _run(self, query: str, top_n: int = 5) -> str:
+ try:
+ # ... 调用API ...
+ result = call_baidu_api(query, top_n)
+
+ except APITimeoutError:
+ return """
+ 错误:搜索服务响应超时。
+ 原因:可能是网络问题或搜索服务器繁忙。
+ 解决提示:1) 稍后重试;2) 尝试使用更短、更具体的搜索词。
+ """
+
+ except Exception as e:
+ return f"""
+ 错误:搜索服务调用失败。
+ 原因:{str(e)}
+ 解决提示:检查网络连接,或稍后重试。如果问题持续,请尝试其他工具。
+ """
+```
+
+**错误码映射示例**:
+```python
+error_descriptions = {
+ "500": "服务调用超时,可能是服务器处理时间过长,请稍后重试或减少请求复杂度",
+ "502": "服务响应超时,可能是服务器响应时间过长,请稍后重试或尝试其它工具",
+ "216003": "API Key 认证失败,请检查 API Key 是否正确、是否已过期或是否有足够的权限",
+}
+```
+
+**输出格式**:`错误:xxx
+原因:xxx
+解决提示:xxx`
+
+---
+
+### Step 5:黑盒映射(极简→复杂)
+
+**核心机制**:在工具内部代码中,完成从极简输入到复杂API请求的暗中转换。
+
+**实战代码(BaiduSearchTool完整示例)**:
+```python
+from crewai.tools import BaseTool
+from pydantic import BaseModel, Field
+import requests
+
+class BaiduSearchInput(BaseModel):
+ """百度搜索工具的输入参数"""
+ query: str = Field(description="搜索关键词,需要清晰、准确地描述你想要查找的信息")
+ top_n: int = Field(default=5, description="期望返回的搜索结果数量(1-10),默认5条")
+
+class BaiduSearchTool(BaseTool):
+ """百度搜索工具,用于在互联网上搜索信息"""
+ name: str = "baidu_search"
+ description: str = """
+ 使用百度搜索引擎在互联网上查找相关信息。
+ 当你需要获取最新资讯、查找特定知识或验证信息时,请使用此工具。
+ 输入关键词和期望返回的结果数量,将返回搜索结果的标题、链接和内容摘要。
+ """
+ args_schema: type[BaseModel] = BaiduSearchInput
+
+ def _run(self, query: str, top_n: int = 5) -> str:
+ """执行搜索"""
+ # ========== 黑盒映射开始 ==========
+
+ # 1. 极简输入 → 复杂API请求体
+ payload = {
+ "messages": [{"content": query, "role": "user"}],
+ "search_source": "baidu_search_v2",
+ "resource_type_filter": [{"type": "web", "top_k": top_n}],
+ "search_strategy": "standard_search_v2",
+ "top_k": top_n
+ }
+
+ # 2. 调用底层复杂API
+ headers = {"Authorization": f"Bearer {API_KEY}"}
+ response = requests.post(API_URL, json=payload, headers=headers, timeout=30)
+
+ # 3. 处理响应
+ if response.status_code != 200:
+ return f"错误:API返回HTTP {response.status_code}..."
+
+ result = response.json()
+
+ if result.get("error_code"):
+ error_code = result["error_code"]
+ error_msg = result.get("error_msg", "未知错误")
+ # ... 映射为自然语言提示 ...
+
+ # 4. 格式化输出(结构化、易读)
+ references = result.get("references", [])
+ if not references:
+ return "未找到相关结果,建议尝试不同的关键词..."
+
+ results = [f"找到 {len(references)} 条搜索结果\n"]
+ for i, ref in enumerate(references[:top_n], 1):
+ results.append(f"结果{i}: [{ref['title']}] ({ref['url']})\n 内容摘要: {ref['content'][:200]}...\n")
+
+ return "\n".join(results)
+ # ========== 黑盒映射结束 ==========
+```
+
+---
+
+## 三、课程总结
+
+### 五步SOP速记
+
+| 步骤 | 核心动作 | 目的 |
+|------|---------|------|
+| 1. 语义重构 | 组合原子接口 | 提供目标导向的闭环能力 |
+| 2. I/O 瘦身 | 剔除冗余字段 | 保护珍贵的Token上下文 |
+| 3. 参数Prompt化 | Pydantic详尽描述 | 手把手教模型使用工具 |
+| 4. 建设性异常 | 自然语言包裹错误 | 激活模型的自我纠错能力 |
+| 5. 黑盒映射 | 极简→复杂的暗中转换 | 隐藏底层复杂性 |
+
+### 关键收获
+
+1. **任何企业遗留API都能被改造**:ERP、CRM、工单系统的API都能变成大模型的超级武器库
+2. **description是关键**:参数的描述质量直接决定工具调用成功率
+3. **错误处理必须人话化**:机器错误码对大模型是天书
+
+---
+
+## 四、关联知识
+
+- [[12-工具设计哲学-从API到Agent-Native的范式跃迁]] - 工具设计的底层哲学
+- [[14-MCP协议-标准化定义工具接口]] - 业界工具生态标准
+
+---
+
+## 五、参考资源
+
+- **课程代码**: https://github.com/kid0317/crewai_mas_demo/tree/main/m2l9
+- **工具基类**: `BaseTool` from `crewai.tools`
+- **参数建模**: `BaseModel`, `Field` from `pydantic`
diff --git a/src/content/notes/07-Knowledge/14-MCP协议-标准化定义工具接口.md b/src/content/notes/07-Knowledge/14-MCP协议-标准化定义工具接口.md
new file mode 100644
index 0000000..85753a1
--- /dev/null
+++ b/src/content/notes/07-Knowledge/14-MCP协议-标准化定义工具接口.md
@@ -0,0 +1,186 @@
+---
+date: 2026-04-10
+tags: ["MCP", "Model Context Protocol", "Anthropic", "Agent工具", "标准化"]
+type: 学习笔记
+category: AI工程
+source: 极客时间《企业级多智能体设计实战》第14讲
+difficulty: 高级
+title: "14-MCP协议-标准化定义工具接口"
+---
+
+# 14|MCP协议:标准化定义工具接口
+
+## 概述
+
+MCP(Model Context Protocol,模型上下文协议)是2024年Anthropic提出的革命性协议,正在彻底改变AI Agent与外部世界交互的方式。它通过标准化协议实现生态复用与架构解耦。
+
+## 核心概念
+
+### 1. 什么是MCP协议?
+
+**MCP本质**:一套"协议"(Protocol),不是具体软件或开源项目,类似HTTP协议。
+
+**两端架构**:
+- **MCP Client**:Agent或AI应用,负责理解用户自然语言、推理决策
+- **MCP Server**:提供底层工具和数据源(企业邮箱、数据库、OA系统)
+
+**核心机制**:Server按MCP标准格式暴露能力(工具名称、描述、参数JSON Schema),Client自动发现、理解、动态调用,无需硬编码业务逻辑。
+
+### 2. 核心价值
+
+| 价值 | 说明 |
+|------|------|
+| **生态复用** | Write Once, Use Anywhere。一次开发,CrewAI/LangChain/Claude客户端都能用 |
+| **架构解耦** | AI团队与后端团队权责分离,后端按标准提供接口,AI团队直接接入 |
+
+### 3. MCP资源获取渠道
+
+| 渠道 | 说明 |
+|------|------|
+| 官方收录 | registry.modelcontextprotocol.io(Anthropic维护) |
+| 第三方资源站 | Smithery.ai、MCP.so |
+| AI应用商店 | Cursor、Cline、Glama、Windsurf内置MCP商店 |
+| 托管基站 | Composio、Val Town(将代码转为Web Server) |
+| 开源社区 | awesome-mcp-servers、best-of-mcp-servers |
+
+### 4. 工具分布现状
+
+- **开发者工具**(绝大多数):git、数据库、流水线等
+- **通用AI工具**:浏览器、搜索、文档处理
+- **互联网大厂API**:Google Maps、Slack、飞书等
+- **垂类应用**(较少):金融、法律、股票行情等
+
+### 5. 自研MCP Server(FastAPI框架)
+
+**框架地址**:https://github.com/kid0317/fastapi_mcpserver_base
+
+**企业级特性**:
+- 高性能异步:支持2025 Streamable HTTP传输协议
+- 开箱即用:预集成JSON日志、Prometheus监控、API Key鉴权
+- 开发友好:装饰器模式,函数上加注解即可注册工具
+
+**核心开发步骤**:
+1. 定义工具逻辑(业务代码)
+2. 应用Prompt模板(规范名称、触发时机、适用边界)
+3. 参数精细化(取值边界、默认值、示例)
+
+**安全设计**:
+- 密钥加密存储(Fernet对称加密)
+- 身份映射:X-User-Id通过HTTP Header传递,AI接触不到敏感信息
+
+### 6. MCP Client集成(CrewAI)
+
+**代码位置**:https://github.com/kid0317/crewai_mas_demo/blob/main/m2l9/m2l9_mcp.py
+
+```python
+email_agent = Agent(
+ role="电子邮件收发员",
+ mcps=[MCPServerHTTP(
+ url="http://localhost:8005/mcp",
+ headers={
+ "Authorization": "Bearer your_key", # 传输层鉴权
+ "X-User-Id": "user01" # 业务层多租户
+ },
+ tool_filter=static_filter, # 安全过滤器
+ )]
+)
+```
+
+**工具过滤器(白名单)**:
+- 使用`create_static_tool_filter`限制Agent只能使用指定工具
+- 即使Server新增100个工具,Agent也看不到,防止安全风险
+
+**执行流程**:
+1. 工具发现:Agent启动时调用`tools/list`拉取Schema
+2. 决策规划:LLM匹配Schema中的"触发时机"决定是否调用
+3. 标准化执行:Agent通过协议请求,Server执行并返回JSON
+
+### 7. 底层注入机制
+
+框架底层的"暗箱操作":
+1. **自动握手与发现**:通过HTTP/SSE获取Tool List
+2. **过滤与防越权**:经static_filter剥离高危工具
+3. **Schema组装**:动态生成工具名,拼接到System Prompt
+4. **无缝调用**:大模型像使用本地工具一样调用远程微服务
+
+## 关键要点
+
+1. **协议标准化**:MCP是协议而非软件,两端按标准通信即可
+2. **一次开发多处使用**:Server开发一次,所有Client都能接入
+3. **安全白名单**:必须用tool_filter限制可见工具,防止风险
+4. **密钥隔离**:敏感信息走headers,绝不暴露给LLM
+5. **幂等设计**:网络抖动可能导致重试,工具必须支持request_id幂等
+
+## 实践示例
+
+### MCP Server开发(装饰器模式)
+```python
+from fastapi_mcpserver import mcp_tool
+
+@mcp_tool(
+ name="send_email",
+ description="发送邮件。触发时机:用户要求发送邮件时。适用边界:只支持PDF附件"
+)
+async def send_email(to: str, subject: str, body: str) -> str:
+ """参数已定义取值边界和示例"""
+ # 业务逻辑...
+ return "邮件发送成功"
+```
+
+### MCP Client集成
+```python
+from crewai.mcp import MCPServerHTTP
+from crewai.mcp.filters import create_static_tool_filter
+
+# 白名单过滤
+static_filter = create_static_tool_filter(
+ allowed_tool_names=["send_email", "read_inbox"]
+)
+
+agent = Agent(
+ role="邮件助手",
+ mcps=[MCPServerHTTP(
+ url="http://localhost:8005/mcp",
+ headers={"X-User-Id": user_id},
+ tool_filter=static_filter,
+ )]
+)
+```
+
+## 常见问题/坑点
+
+| 反模式 | 后果 | 解决方案 |
+|--------|------|---------|
+| 巨型MCP | 一个接口返回20+工具,占用13.7K Token | 保持克制和垂直,拆分多个Server |
+| 粒度过细 | 5-6次往返调用,Token和失败风险增加 | Server端做业务聚合,语义完整性 |
+| 同步阻塞 | 重I/O操作无心跳,Client超时断开 | 异步处理 + 心跳机制 |
+| 模型传安全参数 | 极高的越权风险 | 敏感信息走headers,不暴露给LLM |
+| 非幂等设计 | 网络重试导致重复执行 | 支持request_id,确保幂等性 |
+
+## 关联知识
+
+- [[12-工具设计哲学-从API到Agent-Native的范式跃迁]]:工具设计原则
+- [[13-自定义工具封装-构建Tools的五步标准SOP]]:工具封装方法论
+- [[16-Skills生态-让Agent接入大量工具]]:Skills与MCP的关系
+
+## 参考资源
+
+- FastAPI MCP框架:https://github.com/kid0317/fastapi_mcpserver_base
+- 邮件MCP示例:https://github.com/kid0317/mail_mcpserver
+- MCP官方注册表:https://registry.modelcontextprotocol.io
+- CrewAI MCP集成:https://github.com/kid0317/crewai_mas_demo/blob/main/m2l9/m2l9_mcp.py
+
+## 学习时间
+
+- 课程时长:35:14
+- 笔记整理:2026-04-10
+
+## 状态
+
+- [x] 课程学习
+- [ ] MCP Server实践
+- [ ] MCP Client集成
+
+## 下次复习日期
+
+2026-04-17
diff --git a/src/content/notes/07-Knowledge/15-王牌超能力-代码解释器与无头浏览器.md b/src/content/notes/07-Knowledge/15-王牌超能力-代码解释器与无头浏览器.md
new file mode 100644
index 0000000..fbdff9c
--- /dev/null
+++ b/src/content/notes/07-Knowledge/15-王牌超能力-代码解释器与无头浏览器.md
@@ -0,0 +1,157 @@
+---
+date: 2026-04-10
+tags: ["Code Interpreter", "Headless Browser", "AIO-Sandbox", "Agent能力", "安全隔离"]
+type: 学习笔记
+category: AI工程
+source: 极客时间《企业级多智能体设计实战》第15讲
+difficulty: 高级
+title: "15-王牌超能力-代码解释器与无头浏览器"
+---
+
+# 15|王牌超能力:代码解释器与无头浏览器
+
+## 概述
+
+为Agent装载三大王牌超能力:文件操作、代码解释器(Code Interpreter)和无头浏览器(Headless Browser),让Agent从"聊天机器人"升级为"数字白领"。
+
+## 核心概念
+
+### 1. 三大王牌超能力
+
+| 能力 | 说明 | 核心价值 |
+|------|------|---------|
+| **文件操作** | 读取、写入、局部编辑(Diff) | 精准修改大文件,不复写全文 |
+| **代码解释器** | 自主编写Python代码并执行 | 处理复杂数学、数据清洗、图表生成 |
+| **无头浏览器** | 自主打开网页、点击、截图 | 无API时抓取数据、视觉分析 |
+
+### 2. 安全风控:绝不能裸奔!
+
+**毁灭性风险**:
+- 幻觉生成`rm -rf *`,系统瞬间灰飞烟灭
+- Prompt Injection攻击,下载恶意脚本,沦为"肉鸡"
+
+**解决方案**:沙盒(Sandbox)隔离技术
+
+### 3. AIO-Sandbox架构
+
+**开源方案**:AIO-Sandbox,利用Docker容器隔离出独立环境
+
+**沙盒特性**:
+- Agent可在沙盒里肆意妄为写代码、装依赖、甚至搞崩溃系统
+- 重启Docker容器即可恢复如初
+- 通过MCP协议将沙盒工具暴露给外层Agent
+
+**沙盒工具库**(33+工具):
+- `sandbox_browser_screenshot`:屏幕截图
+- `browser_click` / `browser_scroll`:点击和滚动
+- `browser_get_clickable_elements`:获取可交互元素
+- `sandbox_execute_code`:执行Python/JS代码
+- `sandbox_execute_bash`:执行Shell命令
+- `sandbox_file_operations`:文件读写
+
+### 4. 代码实战:阿里股票早报
+
+**任务**:撰写基于真实数据的阿里巴巴港股早盘报告
+
+**Agent能力调度**:
+1. 写Python代码调用Yahoo Finance获取K线数据
+2. 唤醒无头浏览器百度搜索最新舆情
+3. 结合量化分析与舆情计算输出
+
+**完整代码**:https://github.com/kid0317/crewai_mas_demo/blob/main/m2l10/m2l10_sandbox.py
+
+```python
+quant_analyst = Agent(
+ role="全能金融数据与舆情分析师",
+ goal="使用代码抓取真实金融数据并进行量化分析,结合浏览器检索舆情,输出投资早报",
+ backstory="精通Python和金融量化分析,需要数据时优先写代码抓取,需要舆情时熟练操作浏览器",
+ mcp_servers=[MCPServerHTTP(url="http://localhost:8022")], # 挂载沙盒
+ llm=aliyun_llm,
+)
+```
+
+## 关键要点
+
+1. **Bash is All You Need**:Claude Code底层只有4个工具(read/write/edit/bash),但bash能完成任何任务
+2. **沙盒是必选项**:绝不允许在宿主机上直接赋权Agent运行代码
+3. **工具优先级**:代码调用API > 专业搜索工具 > 浏览器硬爬
+4. **预置依赖**:Docker镜像中预装pandas/requests/bs4等,避免反复pip install
+5. **强模型要求**:复杂代码逻辑和浏览器交互对模型智商要求极高,小参数模型会疯狂撞墙
+
+## 实践示例
+
+### 沙盒MCP挂载
+```python
+from crewai.mcp import MCPServerHTTP
+from crewai.mcp.filters import create_static_tool_filter
+
+# 白名单过滤,只暴露需要的工具
+SANDBOX_TOOL_FILTER = create_static_tool_filter(
+ allowed_tool_names=[
+ "sandbox_execute_bash",
+ "sandbox_execute_code",
+ "sandbox_file_operations",
+ "sandbox_browser_screenshot",
+ "browser_click",
+ "browser_scroll",
+ ]
+)
+
+sandbox_mcp = MCPServerHTTP(
+ url="http://localhost:8022/mcp",
+ tool_filter=SANDBOX_TOOL_FILTER,
+)
+```
+
+### 复杂任务定义
+```python
+task = Task(
+ description="""
+ 作为阿里巴巴港股个人工作助理,完成早盘报告:
+ 1)使用沙盒的浏览器和代码执行能力,获取阿里港股最新行情和30日K线数据
+ 2)用Python在沙盒中进行量化分析(涨跌幅、K线形态、支撑位)
+ 3)通过浏览器检索阿里最新新闻资讯(百度搜索)
+ 4)整合分析与舆情,撰写可直接发送的分析报告
+ """,
+ expected_output="符合AlibabaMorningReport Pydantic模型的JSON数据",
+ agent=quant_analyst,
+)
+```
+
+## 常见问题/坑点
+
+| 反模式 | 后果 | 解决方案 |
+|--------|------|---------|
+| **主机裸奔** | rm -rf *或恶意脚本直接摧毁系统 | 必须用Docker沙盒隔离 |
+| **stdout污染** | 代码夹杂Log或忘记print,Agent拿到乱码 | 清理输出,确保关键信息print到stdout |
+| **生吞HTML** | 直接把Raw HTML丢给模型,Token爆炸 | 用bs4解析提取关键信息 |
+| **忽视异步渲染** | SPA页面立即抓取,只能拿到loading空壳 | 等待页面加载完成再抓取 |
+| **小模型硬上** | 规划复杂逻辑失败,疯狂报错 | 使用足够强的模型(Claude 3.5+/GPT-4+) |
+
+## 关联知识
+
+- [[14-MCP协议-标准化定义工具接口]]:MCP协议与沙盒集成
+- [[16-Skills生态-让Agent接入大量工具]]:Skills设计哲学
+- [[17-项目实战2-能力篇-XiaoPaw飞书本地工作助手]]:沙盒在真实项目中的应用
+
+## 参考资源
+
+- 沙盒工具列表:https://github.com/kid0317/crewai_mas_demo/blob/main/m2l10/m2l10_mcp_tools.md
+- 阿里股票实战代码:https://github.com/kid0317/crewai_mas_demo/blob/main/m2l10/m2l10_sandbox.py
+- AIO-Sandbox项目:https://github.com/hughcrt/aio-sandbox
+
+## 学习时间
+
+- 课程时长:36:40
+- 笔记整理:2026-04-10
+
+## 状态
+
+- [x] 课程学习
+- [ ] 沙盒环境搭建
+- [ ] 代码解释器实践
+- [ ] 无头浏览器抓取
+
+## 下次复习日期
+
+2026-04-17
diff --git a/src/content/notes/07-Knowledge/16-Skills生态-让Agent接入大量工具.md b/src/content/notes/07-Knowledge/16-Skills生态-让Agent接入大量工具.md
new file mode 100644
index 0000000..28b3687
--- /dev/null
+++ b/src/content/notes/07-Knowledge/16-Skills生态-让Agent接入大量工具.md
@@ -0,0 +1,211 @@
+---
+date: 2026-04-10
+tags: ["Skills", "Agent能力", "MCP", "Claude Code", "工具生态"]
+type: 学习笔记
+category: AI工程
+source: 极客时间《企业级多智能体设计实战》第16讲
+difficulty: 高级
+title: "16-Skills生态-让Agent接入大量工具"
+---
+
+# 16|Skills生态:让Agent接入大量工具
+
+## 概述
+
+Skills的出现是为了让Agent不光能用工具,还能"按说明书用工具"。将高阶能力模块化,让Agent团队不仅有武器,还有一套传承的"武功秘籍"。
+
+## 核心概念
+
+### 1. Skills的本质
+
+**不是**:API、MCP Server、插件格式
+**是**:给LLM读的结构化操作手册
+
+**类比**:就像新员工入职时HR给的操作手册——"处理客户退款时,第一步先核实订单状态,第二步……"
+
+**底层哲学:Bash is All You Need**
+
+Claude Code底层只有4个工具:
+- read:读文件
+- write:写文件
+- edit:编辑文件
+- bash:执行命令行
+
+**Skills vs MCP的区别**:
+- MCP:预先封装能力成API → Agent调用 → 执行
+- Skills+Shell:把"怎么做"写成操作手册 → Agent按手册自己写代码 → bash执行
+
+### 2. 一个完整的Skill组成
+
+```
+skill-name/
+├── SKILL.md # 操作手册(必须)
+├── scripts/ # 执行脚本(可选)
+│ ├── extract.py
+│ └── utils.py
+├── references/ # 参考资料(可选)
+│ └── advanced-guide.md
+└── tests/ # 测试用例(可选)
+ └── test_skill.py
+```
+
+**SKILL.md结构**:
+- Overview:适用场景、核心能力
+- 操作流程:步骤1、步骤2……
+- 边界条件:能做什么、不能做什么
+- 异常处理:报错时怎么办
+- 示例:输入 → 处理 → 输出
+
+### 3. 两类Skill
+
+| 类型 | 说明 | 执行方式 |
+|------|------|---------|
+| **参考型** | 给主Agent读的参考资料,类似RAG | 直接读取内容 |
+| **任务型** | 需要单独执行的能力,创建Sub-Crew | 创建独立Agent执行 |
+
+### 4. 渐进式披露机制
+
+**问题**:Skills库很大(100+ Skills),全部塞进主Agent上下文会爆炸
+
+**解决方案**:
+1. **启动时**:只加载`load_skills.yaml`元数据(名称+一句话描述)
+2. **调用时**:主Agent判断需要哪个Skill,只加载该Skill的完整内容
+3. **执行时**:任务型Skill创建Sub-Crew,在隔离上下文中执行
+
+### 5. Skill工具实现
+
+**核心代码位置**:https://github.com/kid0317/crewai_mas_demo
+
+**SkillTool设计**:
+- 继承`BaseTool`,暴露`_run`和`_arun`
+- 用`PrivateAttr`声明`_skill_registry`(Pydantic V2兼容)
+- 用`field_validator`处理LLM传来的JSON对象
+- 约束放在Field description而非backstory
+
+**Sub-Crew工厂**:
+```python
+def build_skill_crew(skill_name: str, skill_instructions: str) -> Crew:
+ """工厂函数,每次调用返回全新实例"""
+ sandbox_mcp = MCPServerHTTP(
+ url=SANDBOX_MCP_URL,
+ tool_filter=SANDBOX_TOOL_FILTER, # 白名单过滤
+ )
+
+ skill_agent = Agent(
+ role=f"{skill_name.upper()} Skill 执行专家",
+ backstory=f"你掌握以下操作规范:\n\n{skill_instructions}",
+ mcp_servers=[sandbox_mcp],
+ )
+
+ return Crew(agents=[skill_agent], tasks=[...])
+```
+
+### 6. Skill与MCP的关系
+
+| 维度 | Skill | MCP |
+|------|-------|-----|
+| 定位 | 知识层(说明书) | 能力层(工具实现) |
+| 内容 | 操作流程、经验、约束 | 具体工具API |
+| 灵活性 | 自然语言描述复杂逻辑 | JSON Schema限制 |
+| 代码生成 | 现场写代码 | 预封装好的API |
+
+**协作模式**:
+- Skill负责"按什么步骤、用什么工具"
+- MCP负责"提供可用的原子能力"
+- Skill调用MCP工具完成复杂任务
+
+### 7. 企业级Skill管理
+
+**四要素**:
+1. **命名规范**:`{动词}-{名词}`,如`parse-pdf`、`generate-report`
+2. **Review流程**:新Skill提PR,工程师+安全工程师双Review
+3. **版本管理**:`load_skills.yaml`进Git,可回滚
+4. **使用统计**:埋点记录调用次数、成功率,定期清理僵尸Skill
+
+## 关键要点
+
+1. **Skill是操作手册**:不是API,是给LLM读的结构化文档
+2. **渐进式披露**:启动只加载元数据,调用时才加载完整内容
+3. **Sub-Crew隔离**:任务型Skill在独立上下文中执行,不影响主Agent
+4. **Skill+MCP协作**:Skill负责知识,MCP负责能力
+5. **严格命名规范**:避免相似Skill并存导致路由混乱
+
+## 实践示例
+
+### SKILL.md示例(parse-pdf)
+```markdown
+# parse-pdf Skill
+
+## Overview
+解析PDF文件,提取文字内容。支持文字层直接提取和OCR扫描识别。
+
+## 操作流程
+1. 检测PDF是否有文字层(用PyPDF2快速检测)
+2. 有文字层:使用pypdf提取
+3. 无文字层:使用OCR(Tesseract)识别
+4. 中文内容注意编码问题,优先用pdfplumber
+
+## 边界条件
+- 支持:PDF、扫描PDF
+- 不支持:加密PDF(需先解密)、损坏PDF
+
+## 异常处理
+- 乱码:尝试pdfplumber替代pypdf
+- OCR失败:检查图片清晰度,提示用户
+
+## 示例
+输入:data/report.pdf(扫描件)
+处理:检测到无文字层 → OCR识别
+输出:{"content": "提取的文字内容..."}
+```
+
+### load_skills.yaml
+```yaml
+skills:
+ parse-pdf:
+ enabled: true
+ type: task # task 或 reference
+ description: 解析PDF文件,支持文字层提取和OCR识别
+
+ generate-report:
+ enabled: true
+ type: task
+ description: 基于数据生成结构化报告
+```
+
+## 常见问题/坑点
+
+| 反模式 | 后果 | 解决方案 |
+|--------|------|---------|
+| 大量相似Skill并存 | 主Agent路由随机化,行为不一致 | 统一命名规范,定期清理 |
+| 不加审查信任外部Skill | 恶意SKILL.md劫持路由,脚本外传数据 | Review流程,检查scripts/权限 |
+| SKILL.md超过500行 | LLM注意力衰减,底部约束被忽略 | 按类型拆分,每个200行以内 |
+| 引用链超过两层 | 第三层文件永远不会被读取 | 扁平化引用结构 |
+| 让模型动态生成所有代码 | 结果不稳定、Token消耗大 | 能沉淀成脚本的优先预制 |
+
+## 关联知识
+
+- [[14-MCP协议-标准化定义工具接口]]:MCP与Skills的协作
+- [[15-王牌超能力-代码解释器与无头浏览器]]:沙盒工具的使用
+- [[17-项目实战2-能力篇-XiaoPaw飞书本地工作助手]]:Skills在实战中的应用
+
+## 参考资源
+
+- 课程源码:https://github.com/kid0317/crewai_mas_demo
+- XiaoPaw项目:https://github.com/kid0317/xiaopaw
+- Claude Code Skills:https://docs.anthropic.com/en/docs/skills
+
+## 学习时间
+
+- 课程时长:66:26
+- 笔记整理:2026-04-10
+
+## 状态
+
+- [x] 课程学习
+- [ ] Skill开发实践
+- [ ] Skills库管理
+
+## 下次复习日期
+
+2026-04-17
diff --git a/src/content/notes/07-Knowledge/17-项目实战2-能力篇-XiaoPaw飞书本地工作助手.md b/src/content/notes/07-Knowledge/17-项目实战2-能力篇-XiaoPaw飞书本地工作助手.md
new file mode 100644
index 0000000..fb6d389
--- /dev/null
+++ b/src/content/notes/07-Knowledge/17-项目实战2-能力篇-XiaoPaw飞书本地工作助手.md
@@ -0,0 +1,207 @@
+---
+date: 2026-04-10
+tags: ["XiaoPaw", "飞书", "工作助手", "Multi-Agent", "企业级应用"]
+type: 学习笔记
+category: AI工程
+source: 极客时间《企业级多智能体设计实战》第17讲
+difficulty: 高级
+title: "17-项目实战2-能力篇-XiaoPaw飞书本地工作助手"
+---
+
+# 17|项目实战2:能力篇——XiaoPaw飞书本地工作助手
+
+## 概述
+
+XiaoPaw(小爪子)是一个部署在飞书的企业级AI工作助手,能够接收文件、调度定时任务、通过沙盒执行代码。它是第12-16课工具设计经验的完整落地。
+
+**项目地址**:https://github.com/kid0317/xiaopow
+
+## 核心概念
+
+### 1. 两个真实场景演示
+
+**场景一:Excel数据分析报告**
+- 用户在飞书给XiaoPaw发Excel文件+一句话:"帮我分析这份饮食数据,写成报告发到飞书文档"
+- XiaoPaw自动保存文件到沙盒 → 激活xlsx Skill → AI用pandas分析 → 生成图表和洞察 → 调用feishu_ops Skill写入飞书文档
+- 几十秒后,飞书文档链接出现在对话框
+
+**场景二:每日股票分析推送**
+- 用户说:"每天早上九点,帮我分析茅台和腾讯的股价走势,发消息给我"
+- XiaoPaw理解这是定时任务 → 写入`cron/tasks.json` → 注册cron表达式`0 9 * * *`
+- 每天上午九点自动触发分析并推送结果
+
+### 2. 为什么选择飞书?
+
+**企业级生态复利效应**:
+- **数据闭环**:IM + 文档 + 表格 + 日历 + 审批,工作流不跳平台
+- **开放平台成熟**:完整的RESTful API + WebSocket推送
+- **用户习惯**:用户已在飞书工作,无需切换工具
+
+### 3. 两层MAS架构
+
+| 层级 | 职责 | 特点 |
+|------|------|------|
+| **主Crew** | 极简路由Agent | 理解用户意图,路由到对应Skill,不执行具体任务 |
+| **Sub-Crew** | 按需创建执行 | 每个Skill独立创建,上下文隔离,执行完即销毁 |
+
+**上下文隔离**:第3课理论的实际落地,主Agent上下文始终保持精简。
+
+### 4. 集成的9个Skills
+
+| Skill | 能力 | 场景 |
+|-------|------|------|
+| xlsx | Excel数据处理分析 | 数据分析报告 |
+| pdf | PDF解析与提取 | 文档处理 |
+| docx | Word文档操作 | 报告生成 |
+| feishu_ops | 飞书文档/表格/消息操作 | 结果输出 |
+| web_search | 网络搜索 | 信息获取 |
+| stock_analysis | 股票数据分析 | 投资分析 |
+| email | 邮件收发 | 邮件通知 |
+| calendar | 日历管理 | 日程安排 |
+| code_exec | 代码执行(沙盒) | 复杂计算 |
+
+### 5. Runner + Session设计
+
+**per-routing_key串行**:
+- 每个飞书会话(单聊/群聊)有独立的Session
+- 同一会话内消息串行处理,保证上下文连续性
+- 不同会话之间完全隔离
+
+**Session状态管理**:
+- Session文件:`{session_id}_ctx.json`(压缩快照)
+- 原始历史:`{session_id}_raw.jsonl`(append-only)
+
+### 6. Cron定时任务系统
+
+**设计特点**:
+- 支持三种调度模式:固定时间点、固定间隔、cron表达式
+- 热重载:检测`tasks.json`变化自动重新加载
+- 复用Runner管道:定时任务和用户消息走相同处理链路
+
+```python
+# Cron调度示例
+{"schedule": {"kind": "cron", "expr": "0 9 * * *", "tz": "Asia/Shanghai"}}
+```
+
+**触发流程**:
+1. CronService构造`is_cron=True`的InboundMessage
+2. 调用`runner.dispatch()`进入处理管道
+3. Agent执行分析任务 → 调用feishu_ops发送结果
+
+### 7. 进程启动与依赖注入
+
+**启动序列**(main.py):
+1. 读取config.yaml配置
+2. 初始化日志 + Prometheus指标
+3. 构建飞书HTTP Client
+4. 初始化SessionManager、FeishuSender等
+5. **安全关键**:凭证写入沙盒.config目录,LLM永远看不到
+6. 构建agent_fn工厂
+7. 构建Runner(注入agent_fn)
+8. 启动CronService(注入runner.dispatch)
+9. 并行启动所有服务
+
+**依赖链**:
+```
+agent_fn → sender
+runner → agent_fn
+cron_svc → runner.dispatch
+```
+
+## 关键要点
+
+1. **极简主Crew**:主Agent只做路由,不执行具体任务
+2. **Skill即服务**:每个Skill是独立的Sub-Crew,按需创建
+3. **飞书生态闭环**:IM、文档、表格一体化,数据不跳出平台
+4. **安全设计**:敏感凭证写沙盒,AI接触不到
+5. **热重载定时任务**:无需重启进程即可添加/修改定时任务
+
+## 实践示例
+
+### 飞书消息处理流程
+```python
+# 1. 接收飞书消息
+inbound = InboundMessage(
+ routing_key=chat_id, # 单聊/群聊ID
+ content=user_message,
+ msg_id=msg_id,
+)
+
+# 2. Runner路由到主Agent
+response = await runner.dispatch(inbound)
+
+# 3. 主Agent判断需要xlsx Skill
+skill_task = SkillTask(
+ skill_name="xlsx",
+ task_context="分析饮食数据并生成报告"
+)
+
+# 4. 创建Sub-Crew执行
+sub_crew = build_skill_crew("xlsx", skill_instructions)
+result = await sub_crew.kickoff(skill_task)
+
+# 5. Sub-Crew调用feishu_ops输出
+feishu_task = FeishuTask(
+ operation="create_doc",
+ title="饮食数据分析报告",
+ content=result
+)
+```
+
+### Cron任务定义
+```json
+{
+ "tasks": [
+ {
+ "id": "morning_stock_report",
+ "schedule": {
+ "kind": "cron",
+ "expr": "0 9 * * *",
+ "tz": "Asia/Shanghai"
+ },
+ "payload": {
+ "routing_key": "user_123",
+ "message": "分析茅台和腾讯股价"
+ }
+ }
+ ]
+}
+```
+
+## 常见问题/坑点
+
+| 问题 | 原因 | 解决方案 |
+|------|------|---------|
+| Session上下文混乱 | 多个会话消息混在一起 | per-routing_key串行,会话完全隔离 |
+| 定时任务不触发 | CronService未正确加载 | 检查tasks.json格式,查看日志 |
+| 沙盒执行失败 | 依赖包未预装 | Docker镜像预装常用包,Skill文档明确说明 |
+| 飞书API限流 | 调用频率过高 | 添加限流和重试机制 |
+| 敏感信息泄露 | API Key写在代码里 | 写入沙盒.config,AI接触不到 |
+
+## 关联知识
+
+- [[14-MCP协议-标准化定义工具接口]]:MCP集成
+- [[15-王牌超能力-代码解释器与无头浏览器]]:沙盒使用
+- [[16-Skills生态-让Agent接入大量工具]]:Skill设计与执行
+- [[18-从Prompt到Harness-记忆与上下文的设计范式]]:上下文管理
+
+## 参考资源
+
+- XiaoPaw项目:https://github.com/kid0317/xiaopow
+- 飞书开放平台:https://open.feishu.cn/
+- FastAPI基础框架:https://github.com/kid0317/fastapi_base
+
+## 学习时间
+
+- 课程时长:40:09
+- 笔记整理:2026-04-10
+
+## 状态
+
+- [x] 课程学习
+- [ ] 项目部署
+- [ ] Skill定制开发
+
+## 下次复习日期
+
+2026-04-17
diff --git a/src/content/notes/07-Knowledge/18-从Prompt到Harness-记忆与上下文的设计范式.md b/src/content/notes/07-Knowledge/18-从Prompt到Harness-记忆与上下文的设计范式.md
new file mode 100644
index 0000000..698d955
--- /dev/null
+++ b/src/content/notes/07-Knowledge/18-从Prompt到Harness-记忆与上下文的设计范式.md
@@ -0,0 +1,181 @@
+---
+date: 2026-04-10
+tags: ["Prompt Engineering", "Context Engineering", "Harness Engineering", "记忆系统", "上下文管理"]
+type: 学习笔记
+category: AI工程
+source: 极客时间《企业级多智能体设计实战》第18讲
+difficulty: 高级
+title: "18-从Prompt到Harness-记忆与上下文的设计范式"
+---
+
+# 18|从 Prompt 到 Harness:记忆与上下文的设计范式
+
+## 概述
+
+建立上下文工程的认知框架:理解记忆的本质、三代演进(Prompt→Context→Harness),以及上下文治理的核心——加法和减法。
+
+## 核心概念
+
+### 1. 记忆的本质
+
+**关键认知**:大模型没有记忆!
+
+**真相**:每次API调用都是独立的,模型不知道上一句说了什么。所谓"记住",是因为应用层把之前的对话历史塞进了message list。
+
+```python
+# "记忆"的全部真相
+messages = [
+ {"role": "system", "content": "你是XiaoPaw,飞书工作助手..."},
+ {"role": "system", "content": "用户偏好:周报格式先汇总再列计划..."}, # 这就是"记忆"
+ {"role": "user", "content": "帮我发周报"},
+ {"role": "assistant", "content": "好的,按你喜欢的格式..."},
+]
+```
+
+**记忆系统的本质**:设计一套机制,决定什么时候从"硬盘"加载到"内存",什么时候从"内存"写回"硬盘","内存"满了怎么腾空间。
+
+**类比电脑**:
+- 模型 = CPU(只计算,不存储)
+- 上下文窗口 = 内存RAM(容量有限,断电即失)
+- 外部存储 = 硬盘(持久化但需主动读取)
+
+### 2. 三代演进
+
+| 时代 | 时间 | 核心 | 控制权 | 代表 |
+|------|------|------|--------|------|
+| **Prompt Engineering** | GPT-3时代 | 人写全部 | 写内容 | 早期聊天机器人 |
+| **Context Engineering** | GPT-4时代 | 工程逻辑构建message list | 建message list | Workflow、单Agent |
+| **Harness Engineering** | 2026+ | 预加载索引+模型按需探索 | 造环境 | Claude Code、Cursor |
+
+**Harness概念**:OpenAI 2026年2月正式提出,字面意思是"马具"(缰绳、鞍具、挽具)。
+
+**三代类比**:
+- Prompt时代:你是**骑手**,手把手拉缰绳告诉马每一步怎么走
+- Context时代:你是**教练**,给它规划好赛道和路线
+- Harness时代:你是**牧场主**,建好围栏、水源、草料站,马自己决定去哪吃草
+
+**常见误区纠正**:Harness不是"完全放手"。Claude Code依赖CLAUDE.md预加载项目结构、rules/预加载约束、MEMORY.md自动注入记忆索引。正确理解:**预加载关键索引 + 模型按需探索的混合模式**。
+
+### 3. 治理框架:加法与减法
+
+**加法**:让模型知道它该知道的
+- 问题:不记得你是谁、说过的话反复提、SOP反复教
+- 手段:
+ 1. **Bootstrap预加载**:启动时固定加载(人设、规则、记忆索引)
+ 2. **工具返回注入**:Agent调用工具后结果自动进入上下文
+ 3. **记忆检索注入**:从持久化存储检索相关记忆注入
+ 4. **Skill按需加载**:渐进式披露,需要时才加载
+
+**减法**:让上下文没有不该有的
+- 为什么不能加?上下文窗口有物理上限
+- 为什么不应该加?
+ 1. **Context Rot**:上下文越大,注意力越分散
+ 2. **成本**:Transformer复杂度O(n²),上下文翻倍成本翻4倍
+- 手段:
+ 1. **压缩/截断**:旧对话压缩成摘要或直接截断
+ 2. **选择性遗忘**:主动丢弃低价值信息
+ 3. **Sub-agent隔离**:任务委派给子Agent,主Agent上下文精简
+
+### 4. 记忆系统的三大核心问题
+
+1. **记什么**(What):哪些信息值得记忆?
+2. **怎么存**(How):存储结构、检索方式
+3. **怎么取**(When):什么时候加载、怎么加载
+
+### 5. Context Rot底层机制
+
+**注意力是有限预算**
+
+Transformer生成每个token时,会"看一眼"上下文里所有其他token。上下文有1000个token,每个分到1/1000注意力;有100000个token,每个分到1/100000。
+
+**Context Rot物理根因**:不是模型"忘了",而是**注意力被稀释了**。
+
+**40%警戒线**:研究发现,上下文使用量超过约40%时,模型能力显著下降。
+
+**U型注意力分布**:模型对开头和结尾关注最多,中间最容易被忽略。
+- System Prompt放最前面:利用开头注意力高点
+- 最近对话最重要:利用结尾注意力高点
+- 中间历史对话:最容易丢失信息
+
+**Claude Code的System Reminder机制**:每次工具调用后,在消息末尾注入关键提醒,把重要信息推到U型曲线的"结尾高点"。
+
+## 关键要点
+
+1. **模型没有记忆**:你往messages里塞了什么,模型就知道什么
+2. **三代演进**:Prompt(写内容)→ Context(建message list)→ Harness(造环境)
+3. **治理核心**:加法让模型知道该知道的,减法让上下文没有不该有的
+4. **40%警戒线**:上下文超过40%后能力显著下降,要提前管理
+5. **U型分布**:关键信息放两头,中间要精简
+
+## 实践示例
+
+### Bootstrap预加载
+```python
+# 启动时固定加载
+system_prompt = """
+你是XiaoPaw,飞书工作助手。
+
+用户画像:
+- 职位:产品经理
+- 偏好:周报格式先汇总再列计划
+- 常用技能:xlsx分析、飞书文档操作
+
+工作规范:
+1. 收到文件先保存到沙盒
+2. 分析前先确认数据格式
+3. 输出结果优先用飞书文档
+"""
+```
+
+### 记忆检索注入
+```python
+# 从向量数据库检索相关记忆
+relevant_memories = vector_db.search(
+ query=user_message,
+ top_k=5,
+ filter={"user_id": current_user_id}
+)
+
+# 注入上下文
+messages.append({
+ "role": "system",
+ "content": f"相关历史记忆:\n{relevant_memories}"
+})
+```
+
+## 常见问题/坑点
+
+| 误区 | 真相 | 解决方案 |
+|------|------|---------|
+| 模型能记住我 | 模型没有记忆,是应用层塞的历史 | 理解message list机制 |
+| 窗口越大越好 | 超过40%能力显著下降 | 控制在40%以内,做减法 |
+| Harness=完全放手 | 实际是预加载+按需探索混合 | 预加载关键索引(CLAUDE.md、rules/) |
+| 只加不减 | Context Rot导致注意力稀释 | 加法减法必须平衡 |
+| 均匀分布注意力 | U型分布,中间容易被忽略 | 关键信息放两头 |
+
+## 关联知识
+
+- [[19-上下文的生命周期-Bootstrap剪枝与压缩]]:生命周期节点与代码实现
+- [[17-项目实战2-能力篇-XiaoPaw飞书本地工作助手]]:上下文隔离实践
+- [[16-Skills生态-让Agent接入大量工具]]:Skill按需加载
+
+## 参考资源
+
+- Andrej Karpathy谈Context Engineering
+- OpenAI Harness Engineering公告(2026年2月)
+- Liu et al. U型注意力分布研究(TACL 2024)
+
+## 学习时间
+
+- 课程时长:22:13
+- 笔记整理:2026-04-10
+
+## 状态
+
+- [x] 课程学习
+- [ ] Context Engineering实践
+- [ ] Harness设计
+
+## 下次复习日期
+
+2026-04-17
diff --git a/src/content/notes/07-Knowledge/19-上下文的生命周期-Bootstrap剪枝与压缩.md b/src/content/notes/07-Knowledge/19-上下文的生命周期-Bootstrap剪枝与压缩.md
new file mode 100644
index 0000000..8545ca3
--- /dev/null
+++ b/src/content/notes/07-Knowledge/19-上下文的生命周期-Bootstrap剪枝与压缩.md
@@ -0,0 +1,247 @@
+---
+date: 2026-04-10
+tags: ["Bootstrap", "剪枝", "压缩", "上下文生命周期", "CrewAI Hook"]
+type: 学习笔记
+category: AI工程
+source: 极客时间《企业级多智能体设计实战》第19讲
+difficulty: 高级
+title: "19-上下文的生命周期-Bootstrap剪枝与压缩"
+---
+
+# 19|上下文的生命周期:Bootstrap、剪枝与压缩
+
+## 概述
+
+Agent的上下文在运行过程中有哪些时刻可以干预?这些时刻就是上下文的生命周期节点。用CrewAI的backstory注入做Bootstrap,用`@before_llm_call` Hook在模型调用前实现剪枝和压缩。
+
+## 核心概念
+
+### 1. 上下文生命周期的本质
+
+**Workflow vs Agent的区别**:
+- **Workflow**:上下文直接写的,每一步message list在代码里显式构建,完全可控
+- **Agent**:上下文是"生长"出来的,ReAct循环中模型自己决定调什么工具,工具返回自动塞进message list
+
+**生命周期的本质**:在ReAct循环中能够干预上下文的**时机窗口**
+
+**六个节点**:
+1. **Bootstrap**(启动时):通过Agent的backstory注入system prompt
+2. **剪枝/压缩**(每次LLM调用前):通过`@before_llm_call` Hook拦截messages
+3. 工具调用前(③):CrewAI暂未细粒度支持
+4. 工具返回后(④):CrewAI暂未细粒度支持
+5. Task开始前(⑤):CrewAI暂未细粒度支持
+6. Task结束后(⑥):CrewAI暂未细粒度支持
+
+### 2. 不干预会怎样?
+
+**三种生产级崩溃**:
+
+| 崩溃类型 | 表现 | 根因 |
+|---------|------|------|
+| **上下文溢出** | Token超限,API报错 | 只加不减,无限增长 |
+| **注意力稀释** | 回答质量下降,关键信息被忽略 | Context Rot,超过40%警戒线 |
+| **成本失控** | 账单暴涨 | O(n²)复杂度,上下文翻倍成本翻4倍 |
+
+### 3. Bootstrap预加载
+
+**实现方式**:Agent的`backstory`参数
+
+```python
+agent = Agent(
+ role="助手",
+ goal="帮助用户完成任务",
+ backstory="""
+ 你是XiaoPaw,飞书工作助手。
+
+ 用户画像:
+ - 职位:产品经理
+ - 偏好:周报格式先汇总再列计划
+
+ 工作规范:
+ 1. 收到文件先保存到沙盒
+ 2. 分析前先确认数据格式
+ """ # Bootstrap内容
+)
+```
+
+**关键设计**:backstory内容会在Agent启动时自动注入为system prompt。
+
+### 4. 剪枝与压缩(@before_llm_call Hook)
+
+**Hook注册**:
+```python
+from crewai.hooks import before_llm_call
+from crewai import CrewBase
+
+@CrewBase
+class ContextManagedCrew:
+ @before_llm_call
+ def manage_context(self, context: LLMCallHookContext) -> None:
+ """每次LLM调用前执行"""
+ messages = context.messages # 直接引用,in-place修改
+
+ # 1. 检查上下文长度
+ total_tokens = estimate_tokens(messages)
+ threshold = context.llm.context_window_size * 0.4 # 40%警戒线
+
+ if total_tokens > threshold:
+ # 2. 执行压缩
+ self._compress_messages(messages)
+```
+
+**三大操作实现**:
+
+| 操作 | 时机 | 实现方式 |
+|------|------|---------|
+| **剪枝** | 单次调用前 | 截断中间历史,保留system+最近N轮 |
+| **压缩** | 超阈值时 | 用LLM将旧对话摘要成一句话 |
+| **快照恢复** | session恢复时 | 加载历史ctx + 追加新消息 |
+
+### 5. 代码实战:ContextManager
+
+**核心实现位置**:`m3l19/m3l19_context_mgmt.py`
+
+**压缩策略**:
+```python
+def _compress_messages(self, messages: List[Dict]) -> None:
+ """压缩旧消息,保留system和最近2轮"""
+ # 保留system消息
+ system_msgs = [m for m in messages if m.get("role") == "system"]
+
+ # 保留最近2轮对话(4条消息:user-assistant-user-assistant)
+ recent = messages[-4:] if len(messages) >= 4 else messages
+
+ # 中间部分压缩成摘要
+ middle = messages[len(system_msgs):-4]
+ if middle:
+ summary = self._summarize_with_llm(middle)
+ middle_compressed = [{"role": "system", "content": f"历史摘要:{summary}"}]
+
+ # 替换messages(in-place)
+ messages.clear()
+ messages.extend(system_msgs + middle_compressed + recent)
+```
+
+**Session恢复**:
+```python
+def _restore_session(self, context: LLMCallHookContext) -> None:
+ """用历史ctx替换context.messages + 追加新user消息"""
+ history = load_session_ctx(self.session_id)
+ self._history_len = len(history)
+
+ # 提取当前轮user消息
+ current_user_msg = next(
+ (m for m in reversed(context.messages) if m.get("role") == "user"),
+ {},
+ )
+
+ # 替换:历史 + 新user消息 → Agent看到连续上下文
+ context.messages.clear()
+ context.messages.extend(history)
+ if current_user_msg:
+ context.messages.append(current_user_msg)
+```
+
+### 6. @before_llm_call Hook底层机制
+
+**注册流程**:
+1. **标记检测**:装饰器在方法上打`is_before_llm_call_hook`标记
+2. **自动注册**:`@CrewBase`的`_register_crew_hooks()`扫描并注册
+3. **作用域绑定**:绑定到当前Crew实例,天然隔离
+4. **触发执行**:executor调用LLM前遍历执行,传入`LLMCallHookContext`
+5. **in-place生效**:`context.messages`是executor内部列表的直接引用
+
+**LLMCallHookContext可用信息**:
+```python
+context.messages # List[dict], mutable, in-place修改
+context.agent # 当前Agent对象
+context.task # 当前Task
+context.crew # Crew实例
+context.llm # LLM实例(可读context_window_size)
+context.iterations # 当前迭代次数
+```
+
+## 关键要点
+
+1. **六个生命周期节点**:Bootstrap→剪枝/压缩→工具前→工具后→Task前→Task后
+2. **CrewAI支持两个关键节点**:Bootstrap(backstory)、剪枝/压缩(@before_llm_call)
+3. **in-place修改**:Hook里直接修改`context.messages`,立即对框架可见
+4. **40%警戒线**:超过时触发压缩,不要等到快满才处理
+5. **Session恢复**:用历史ctx替换messages + 追加新消息,Agent感知不到中断
+
+## 实践示例
+
+### 完整ContextManager实现
+```python
+from crewai import CrewBase
+from crewai.hooks import before_llm_call
+from crewai.hooks.types import LLMCallHookContext
+
+@CrewBase
+class ManagedCrew:
+ def __init__(self, session_id: str):
+ self.session_id = session_id
+ self._history_len = 0
+
+ @before_llm_call
+ def context_hook(self, context: LLMCallHookContext) -> None:
+ """每次LLM调用前的上下文管理"""
+ # 1. Session恢复(首次)
+ if self._history_len == 0:
+ self._restore_session(context)
+
+ # 2. 检查长度
+ total_tokens = estimate_tokens(context.messages)
+ threshold = context.llm.context_window_size * 0.4
+
+ # 3. 超阈值则压缩
+ if total_tokens > threshold:
+ self._compress_messages(context.messages)
+ # 保存压缩后的快照
+ save_session_ctx(self.session_id, context.messages)
+```
+
+### 运行方式
+```bash
+cd m3l19 && python3 m3l19_context_mgmt.py
+
+# Session文件(自动生成):
+# ctx → workspace/sessions/{SESSION_ID}_ctx.json (压缩快照)
+# raw → workspace/sessions/{SESSION_ID}_raw.jsonl (原始完整历史)
+```
+
+## 常见问题/坑点
+
+| 问题 | 原因 | 解决方案 |
+|------|------|---------|
+| Hook不生效 | 忘记加`@CrewBase`或方法未标记 | 确保装饰器和基类正确 |
+| messages修改不生效 | 不是in-place修改 | 用`clear()`+`extend()`,不要赋值 |
+| 压缩后丢失关键信息 | 摘要不够精准 | 保留system和最近N轮,只压缩中间 |
+| Session恢复后上下文不连续 | 没有正确追加新消息 | 先提取当前user消息,再替换+追加 |
+| 压缩太频繁 | 阈值设置过低 | 40%是经验值,可根据实际情况调整 |
+
+## 关联知识
+
+- [[18-从Prompt到Harness-记忆与上下文的设计范式]]:上下文工程理论框架
+- [[17-项目实战2-能力篇-XiaoPaw飞书本地工作助手]]:Session管理实践
+
+## 参考资源
+
+- 课程源码:https://github.com/kid0317/crewai_mas_demo/tree/main/m3l19
+- CrewAI Hooks文档:https://docs.crewai.com/concepts/hooks
+
+## 学习时间
+
+- 课程时长:39:19
+- 笔记整理:2026-04-10
+
+## 状态
+
+- [x] 课程学习
+- [ ] Bootstrap实践
+- [ ] 剪枝压缩Hook实现
+- [ ] Session管理
+
+## 下次复习日期
+
+2026-04-17
diff --git a/src/content/notes/07-Knowledge/Claude Code 从零构建 - 完整架构解析.md b/src/content/notes/07-Knowledge/Claude Code 从零构建 - 完整架构解析.md
new file mode 100644
index 0000000..9733191
--- /dev/null
+++ b/src/content/notes/07-Knowledge/Claude Code 从零构建 - 完整架构解析.md
@@ -0,0 +1,660 @@
+---
+tags:
+ - coding-agent
+ - ai
+ - architecture
+ - claude-code
+ - llm
+date: 2026-07-01
+source: https://diwang.info/claude-code-from-scratch/
+github: https://github.com/Windy3f3f3f3f/claude-code-from-scratch
+title: "Claude Code 从零构建 - 完整架构解析"
+---
+
+# Claude Code 从零构建 - 完整架构解析
+
+> 用 ~4300 行代码(TypeScript + Python 双版本)复现 Claude Code 核心架构的分布教程。姊妹项目 [[How Claude Code Works - 姊妹项目概览]] 有 15 篇专题、33 万字源码级深度解析。
+
+---
+
+## 7 条核心洞察
+
+### 1. Agent 的本质是一个 while 循环
+
+```
+while true:
+ response = llm.call(messages)
+ if no tool_calls in response: break
+ for tool_call in response.tool_calls:
+ result = execute(tool_call)
+ messages.append(result)
+```
+
+所有复杂性——权限、上下文管理、记忆、多 Agent——都是围绕这个循环的增强和防护。
+
+### 2. 提示词是最便宜的代码
+
+系统提示词里的一句话,效果等同于一个 if 语句,实现成本是 0 行代码。很多行为问题的最优解不是写更多代码,而是写更好的提示词。
+
+### 3. 工具设计决定能力上限
+
+模型做它擅长的(理解意图、生成代码),工具做模型不擅长的(精确字符串匹配、文件系统操作、进程管理)。`edit_file` 是典型:模型生成要替换的内容,工具负责精确定位和替换。
+
+### 4. 上下文管理是 Agent 的"记忆力"
+
+上下文管理之于 agent,就像内存管理之于操作系统——用有限资源提供"无限"错觉。4 层压缩流水线让 agent 在有限窗口中保持对长对话的记忆。
+
+### 5. 安全不是事后补丁
+
+权限检查是 agent 循环的一个步骤,不是外挂的 middleware。**fail-closed 设计**:新工具如果忘记声明权限级别,被自动当作"需要确认"处理。
+
+### 6. 从 3000 行到 50 万行的差距在于边缘情况
+
+Claude Code 多出来的代码大多是:各运行环境兼容性、网络和 API 不可靠性、用户输入多样性、企业级审计和访问控制。从原型到产品,80% 的距离在这里。
+
+### 7. LLM 与代码的协作边界
+
+模型决定"做什么",代码确保"安全地做"。边界划得好,agent 既灵活又可靠。
+
+---
+
+## 项目结构
+
+```
+src/ # TypeScript 版 (~4291 行)
+├── agent.ts # Agent 循环:流式、并行、4层压缩、预算 (1501 行)
+├── tools.ts # 工具:13工具 + mtime防护 + 延迟加载 (858 行)
+├── cli.ts # CLI 入口:参数解析、REPL、预算 flags (371 行)
+├── memory.ts # 记忆系统:4类型 + 语义召回 + 异步预取 (376 行)
+├── mcp.ts # MCP 客户端:JSON-RPC over stdio (266 行)
+├── prompt.ts # System Prompt:@include + 模板 + 注入 (230 行)
+├── ui.ts # 终端输出:彩色显示、格式化、子Agent显示 (211 行)
+├── subagent.ts # 子Agent:3内置 + 自定义Agent发现 (199 行)
+├── skills.ts # 技能系统:目录发现 + inline/fork双模式 (175 行)
+├── session.ts # 会话持久化:保存/恢复/列表 (63 行)
+└── frontmatter.ts # 共享 YAML frontmatter 解析器 (41 行)
+
+python/ # Python 版 (~3811 行,功能一致)
+```
+
+---
+
+## 第 1 章:Agent Loop — 核心循环
+
+### 双层架构
+
+Claude Code 把 Agent Loop 拆成两层:
+
+- **QueryEngine**(~1155 行):会话级,管整个对话生命周期——用户输入处理、USD 预算检查、Token 统计、会话恢复
+- **queryLoop**(~1728 行):单轮级,管一次查询的执行——消息压缩、API 调用、工具执行、错误恢复
+
+queryLoop 签名是 `async function*`——异步生成器,选择原因:
+1. **背压控制**:消费端不处理完,生产端不继续
+2. **线性控制流**:所有循环分支用普通 `continue`/`break` 表达,不需要状态机
+
+### 七种 Continue Reason
+
+| # | 名称 | 触发场景 | 处理策略 |
+|---|------|----------|----------|
+| 1 | next_turn | 模型调用了工具 | 执行工具,结果推入消息,继续 |
+| 2 | collapse_drain_retry | PTL 错误,有暂存的折叠操作 | 提交折叠释放空间,重试 |
+| 3 | reactive_compact_retry | PTL 错误,折叠空间不够 | 强制全量摘要压缩,重试 |
+| 4 | max_output_tokens_escalate | 输出 Token 截断,首次 | 升级到更高 Token 限制(16K→64K),重试 |
+| 5 | max_output_tokens_recovery | 输出 Token 截断,升级不可用 | 注入续写提示,最多重试 3 次 |
+| 6 | stop_hook_blocking | 任务完成但 Stop Hook 拦截 | 继续执行循环 |
+| 7 | token_budget_continuation | API 侧 Token 预算耗尽 | 继续生成 |
+
+简化实现只处理第 1 种。
+
+### 错误扣留策略
+
+可恢复的错误不立即暴露给上层。当输出 Token 被截断时,先"扣留"错误,执行恢复逻辑,成功了用户完全无感知,失败了才最终暴露。大多数 `max_output_tokens` 和 `prompt_too_long` 错误都被这样静默处理。
+
+### 并行工具执行
+
+```
+串行:[========= API 流式响应 =========][tool1][tool2][tool3]
+并行:[========= API 流式响应 =========]
+ ↑ tool1 JSON 完成 → 立即执行
+ ↑ tool2 JSON 完成 → 立即执行
+```
+
+一个典型 API 响应有 5-30 秒的流式窗口,多个工具并发完成。
+
+### 消息数组增长方式
+
+每轮循环消息数组增长两条(一条 assistant,一条 user 工具结果)。工具结果用 `role: "user"` 推入是 Anthropic API 的协议要求。
+
+### 核心代码
+
+```typescript
+// agent.ts — 核心 Agent Loop
+private async chatAnthropic(userMessage: string): Promise {
+ this.anthropicMessages.push({ role: "user", content: userMessage });
+ await this.checkAndCompact();
+
+ while (true) {
+ if (this.abortController?.signal.aborted) break;
+ const response = await this.callAnthropicStream();
+ this.totalInputTokens += response.usage.input_tokens;
+ this.totalOutputTokens += response.usage.output_tokens;
+
+ const toolUses = response.content.filter(b => b.type === "tool_use");
+ this.anthropicMessages.push({ role: "assistant", content: response.content });
+
+ if (toolUses.length === 0) break; // 任务完成
+
+ const toolResults = [];
+ for (const toolUse of toolUses) {
+ const perm = checkPermission(toolUse.name, input, this.permissionMode);
+ if (perm.action === "deny") { toolResults.push(...); continue; }
+ if (perm.action === "confirm") {
+ const confirmed = await this.confirmDangerous(perm.message);
+ if (!confirmed) { toolResults.push(...); continue; }
+ }
+ const result = await executeTool(toolUse.name, input);
+ toolResults.push({ type: "tool_result", tool_use_id: toolUse.id, content: result });
+ }
+ this.anthropicMessages.push({ role: "user", content: toolResults });
+ }
+}
+```
+
+Python 版本逻辑完全一致,使用 `asyncio` 替代 Promise。
+
+---
+
+## 第 2 章:工具系统
+
+### 6 个核心工具 + 7 个扩展工具
+
+| 工具 | 类型 | 说明 |
+|------|------|------|
+| read_file | 核心 | 读取文件,带行号 |
+| write_file | 核心 | 写文件,自动创建父目录 |
+| edit_file | 核心 | 字符串替换编辑,唯一性检查 + 引号容错 |
+| list_files | 核心 | 文件列表(glob 模式) |
+| grep_search | 核心 | 内容搜索(系统 grep) |
+| run_shell | 核心 | 执行 shell 命令,30s 超时 |
+| web_fetch | 扩展 | HTTP 请求,去标签 + 超时 |
+| tool_search | 扩展 | 延迟工具发现 |
+| skill | 扩展 | 技能系统入口 |
+| agent | 扩展 | 子 Agent 启动 |
+| enter_plan_mode | 扩展 | 进入规划模式(deferred) |
+| exit_plan_mode | 扩展 | 退出规划模式(deferred) |
+
+### Claude Code 的 Tool 接口
+
+```typescript
+type Tool = {
+ name: string
+ aliases?: string[]
+ maxResultSizeChars: number
+ call(args, context, canUseTool, parentMessage, onProgress?): Promise>
+ description(input, options): Promise
+ prompt(options): Promise
+ inputSchema: Input // Zod Schema(运行时验证 + 类型推导)
+ isConcurrencySafe(input): boolean // 接收input:同工具不同参数可有不同安全语义
+ isReadOnly(input): boolean
+ checkPermissions(input, context): Promise
+ renderToolUseMessage(input, options): React.ReactNode
+ renderToolResultMessage?(content, progress, options): React.ReactNode
+}
+```
+
+**设计要点**:
+- `isConcurrencySafe(input)` 接收参数——BashTool 对 `ls` 返回只读,对 `rm` 返回非安全
+- `prompt()` 方法——每个工具向 system prompt 注入使用指南
+- FAIL-CLOSED 默认值:`isConcurrencySafe: () => false`(默认不可并发),`isReadOnly: () => false`
+
+### edit_file 的核心设计
+
+**为什么用 search-and-replace 而非其他方案?**
+
+| 方案 | 致命缺陷 |
+|------|----------|
+| 行号编辑 | 第一次插入 3 行后,后续所有行号偏移 |
+| AST 编辑 | 语法错误的文件 AST 解析直接报错 |
+| Unified diff | LLM 生成严格格式时表现很差 |
+| 全文件重写 | 浪费 Token;可能遗漏未修改代码 |
+| **字符串替换** | ✅ 无上述缺陷。幻觉安全:字符串不存在直接失败 |
+
+### 引号容错 + Diff 输出
+
+LLM 的 tokenization 可能将直引号映射为弯引号(`" → "`),没有容错这类编辑会 100% 失败。
+
+```typescript
+function normalizeQuotes(s: string): string {
+ return s
+ .replace(/[\u2018\u2019\u2032]/g, "'")
+ .replace(/[\u201C\u201D\u2033]/g, '"');
+}
+```
+
+### Read-before-edit + mtime 防护
+
+编辑文件前必须先读取。通过 `readFileState` Map(key=绝对路径,value=mtimeMs)检测外部修改。三个关键点:
+- 新文件跳过检查(创建新文件不需要先读)
+- mtime 比较:不一致说明被外部修改,返回警告而非静默覆盖
+- 写入后更新 mtime
+
+### ToolSearch 延迟加载
+
+不常用的工具标记 `deferred: true`,只发名称不发完整 schema。模型需要时通过 `tool_search` 按需激活。教程只有 2 个 deferred 工具(plan mode),但机制对扩展至关重要。
+
+### 大结果处理
+
+两层防线:`persistLargeResult`(>30KB 先写磁盘保留完整内容)→ `truncateResult`(>50KB 截断保留头尾)。与 truncateResult 的根本区别是 persistLargeResult 可恢复——模型随时可用 read_file 取回完整内容。
+
+---
+
+## 第 3 章:System Prompt 工程
+
+### 7 层递进结构
+
+```
+1. Identity → 我是谁?
+2. System → 运行环境的基本事实
+3. Doing Tasks → 怎么写代码?(反模式接种)
+4. Actions → 哪些操作需要确认?(爆炸半径框架)
+5. Using Tools → 怎么用工具?(偏好映射表)
+6. Tone & Style → 输出什么格式?
+7. Output Efficiency → 怎么更简洁?
+```
+
+### 反模式接种
+
+明确告诉模型"不要做什么"比只描述"要做什么"有效得多。Claude Code 的三条精确"不要":
+- **不要扩大范围**:修 bug 不需要顺手重构
+- **不要防御性编程**:不为不可能的场景加 try-catch
+- **不要过早抽象**:"Three similar lines > premature abstraction"
+
+### 爆炸半径框架
+
+不罗列"不能做 X、Y、Z",而是教模型二维评估:**可逆性 × 影响范围**。高风险 = 不可逆 + 影响共享环境(force push、删除云资源)。这比穷举规则扩展性强得多。
+
+### 工具偏好映射表
+
+模型默认会用训练数据中出现最多的方式(bash 命令),所以必须在提示词中明确引导:
+- Use `read_file` instead of `cat/head/tail`
+- Use `edit_file` instead of `sed/awk`
+- Use `list_files` instead of `find/ls`
+- Use `grep_search` instead of `grep/rg`
+
+### @include 语法与 Rules 自动加载
+
+CLAUDE.md 支持 `@` 语法引用外部文件:`@./relative` / `@~/path` / `@/absolute`。`.claude/rules/*.md` 自动加载。防护:visited Set 防循环、MAX_INCLUDE_DEPTH=5、找不到文件留注释不报错。
+
+### 模板变量
+
+```
+{{cwd}} — 工作目录 {{date}} — 当前日期 {{platform}} — 操作系统
+{{shell}} — Shell路径 {{git_context}} — Git状态 {{claude_md}} — CLAUDE.md
+{{memory}} — 记忆索引 {{skills}} — 技能列表 {{agents}} — Agent类型
+```
+
+`{{memory}}`、`{{skills}}`、`{{agents}}` 放在末尾利用近因效应。
+
+---
+
+## 第 5 章:流式输出与双后端
+
+### Anthropic 后端:SDK 内置 stream
+
+`stream.on("text")` 直接给文本增量,`stream.finalMessage()` 返回和非流式完全一样的 Message 对象。thinking blocks 过滤掉不存入历史——可能长达数千 token,对后续对话没有参考价值。
+
+### OpenAI 后端:手动 chunk 累积
+
+OpenAI tool_calls 的 `id` 和 `name` 只在第一个 chunk 出现,后续 chunk 只有 `arguments` 的增量片段。多个 tool_call 的 chunk 会交错到达,用 `index` 字段区分。
+
+### 流式工具执行(Anthropic)
+
+当 `content_block_stop` 事件触发时,并发安全的工具(read_file、list_files、grep_search、web_fetch)立即启动——不必等整个 API 响应完成。工具执行藏在模型生成的流式窗口内。
+
+### 并行工具执行(OpenAI)
+
+OpenAI 不支持下流式工具 block 事件,采用显式批量并行:将连续的安全工具分组,用 `Promise.all` / `asyncio.gather` 一次性执行。混合序列 `[read, read, write, read]` 分为三个批次:`[read||read]`、`[write]`、`[read]`。
+
+### 重试机制
+
+指数退避 + 随机抖动:`min(1000 * 2^attempt, 30000) + random(0, 1000)`。可重试:429/503/529 和网络瞬断;不可重试:400/401/404。
+
+### Extended Thinking
+
+三种模式:`adaptive`(claude-4.x 自动开启,budget 10000 tokens)、`enabled`(`--thinking` 显式开启,budget 最大化)、`disabled`(不支持 thinking 的模型)。
+
+---
+
+## 第 6 章:权限与安全
+
+### Claude Code 的 7 层纵深防御
+
+| 层 | 机制 | 核心作用 |
+|---|------|----------|
+| 1 | Trust Dialog | 首次进入目录确认信任 |
+| 2 | 权限模式 | 全局策略开关 |
+| 3 | 权限规则匹配 | allow/deny 规则,8 个来源 |
+| 4 | Bash AST 分析 | tree-sitter 解析,23 项安全检查 |
+| 5 | 工具级验证 | 危险文件路径和路径边界保护 |
+| 6 | 沙箱隔离 | macOS Seatbelt / Linux namespace |
+| 7 | 用户确认交互 | 对话框 + Hook + ML 分类器竞速 |
+
+### mini-claude 的 4 层简化
+
+**Layer 1:危险命令检测**(16 个正则,10 个 Unix + 6 个 Windows)
+
+- `\brm\s`、`\bgit\s+(push|reset|clean)`、`\bsudo\b`、`\bmkfs\b`、`\bdd\s`
+- `\bkill\b`、`\bpkill\b`、`\breboot\b`、`\bshutdown\b`、`>\s*\/dev\/`
+- Windows: `\bdel\s`、`\brmdir\s`、`\bformat\s`、`\bRemove-Item\s` 等
+
+**Layer 2:权限规则系统**(allow/deny,两个来源:用户级 + 项目级)
+
+规则格式:`"run_shell(npm test*)"` (尾部 `*` 前缀匹配)、`"read_file"` (裸工具名匹配所有调用)。deny 先于 allow 遍历——"先放开,再收紧"的配置方式因此成立。
+
+**Layer 3:统一权限检查**(`checkPermission`)
+
+优先级:deny 规则 > allow 规则 > 模式逻辑 > 内置危险检测 > 默认允许。
+触发确认的条件:run_shell + 危险命令、write_file/edit_file + 目标不存在。
+read_file、list_files、grep_search 永远安全。
+
+**Layer 4:会话级白名单**(`confirmedPaths` Set)
+
+用户确认一次后同一操作不再重复询问。拒绝时把 `"User denied this action."` 作为工具结果返回——LLM 看到后会调整策略。
+
+### 5 种权限模式
+
+| 模式 | 读工具 | 编辑工具 | Shell(安全) | Shell(危险) | 适用场景 |
+|------|--------|----------|-------------|-------------|----------|
+| default | ✅ | ⚠️ confirm(新文件) | ✅ | ⚠️ confirm | 日常使用 |
+| plan | ✅ | ❌ deny | ❌ deny | ❌ deny | 只规划不执行 |
+| acceptEdits | ✅ | ✅ | ✅ | ⚠️ confirm | 信任编辑 |
+| bypassPermissions | ✅ | ✅ | ✅ | ✅ | --yolo |
+| dontAsk | ✅ | ❌ deny | ✅ | ❌ deny | CI/非交互 |
+
+### 配置文件格式
+
+```json
+// ~/.claude/settings.json(用户级)或 .claude/settings.json(项目级)
+{
+ "permissions": {
+ "allow": ["read_file", "run_shell(npm test*)", "run_shell(git status)"],
+ "deny": ["run_shell(rm -rf*)", "run_shell(git push --force*)"]
+ }
+}
+```
+
+---
+
+## 第 7 章:上下文管理
+
+### 4 层渐进式压缩管道
+
+**第 0 层:执行时截断** — `truncateResult`,50K 硬限制,保留头尾。
+
+**第 0.5 层:大结果持久化** — `persistLargeResult`,>30KB 写磁盘保留完整内容,上下文只留 200 行预览。可恢复 vs 不可恢复的根本区别。
+
+**第 1 层:Budget** — 动态缩减历史中工具结果大小。双阈值(50%/70%)而非单阈值,利用率越高预算越紧。
+
+**第 2 层:Snip** — 替换过时的工具结果。利用率 > 60% 触发:
+- 同一文件多次 read_file → 只保留最新
+- 同类搜索结果超过 3 个 → snip 最旧
+- 最近 3 个 tool_result 永远保留
+- **只清 content 保留 tool_use**——模型仍知执行过什么操作
+
+**第 3 层:Microcompact** — 空闲 > 5 分钟触发,除最近 3 个外所有旧 tool_result → `"[Old result cleared]"`。基于 prompt cache TTL 到期判断。
+
+**第 4 层:Auto-compact** — 利用率 > 85% 触发,fork 子 Agent 生成摘要。必须在 turn boundary 调用(不能在 tool 循环中间),否则会破坏 tool_use/tool_result 配对。
+
+### 调用顺序
+
+Tier 1-3 在每次 API 调用**前**运行(零 API 成本),Tier 4 在 **turn boundary** 触发(用户输入 push 后、while 主循环前)。顺序也有意义:Budget 先压缩大结果,让 Snip 的去重判断更准确。
+
+---
+
+## 第 8 章:记忆系统
+
+### 核心约束
+
+**只记忆不可从当前项目状态推导的信息。** 代码模式、架构、文件路径——读代码和 `git log` 就能获得,记忆中的版本只会制造漂移。
+
+### 四种记忆类型
+
+| 类型 | 记什么 | 触发时机 |
+|------|--------|----------|
+| user | 用户身份、偏好、知识背景 | 了解到用户角色/偏好时 |
+| feedback | 对 Agent 行为的纠正**和肯定** | 用户纠正或肯定某行为时 |
+| project | 项目进展、决策、截止日期 | 了解到项目动态时 |
+| reference | 外部系统的定位信息 | 了解到外部系统位置时 |
+
+feedback 类型特别记录肯定——只记录"错误"会让模型避免重蹈覆辙,但也可能放弃已验证的好做法。project 类型相对日期必须转绝对日期。
+
+### 存储结构
+
+```
+~/.mini-claude/projects/{sha256}/memory/
+├── MEMORY.md # 索引文件
+├── user_prefers_concise_output.md
+├── feedback_no_summary_at_end.md
+└── project_auth_migration_q2.md
+```
+
+### 语义召回(sideQuery)
+
+用同一模型做语义选择(发送记忆清单:文件名 + 描述),比关键词匹配强得多——"部署流程"能匹配到"CI/CD 注意事项"。
+
+### 异步预取(startMemoryPrefetch)
+
+用户提交输入瞬间就启动召回,与第一次模型 API 调用并行。三个门控:多词查询(单次跳过)、会话预算(>60KB 停止)、记忆存在性。非阻塞轮询:settled 标志用 `.then()` 设置,每次循环迭代检查。
+
+### Freshness Warning
+
+超过 1 天的记忆附带警告:"此记忆已过时 X 天,记忆是时间点观察而非实时状态——关于代码行为的断言可能已过时,对照当前代码验证后再执行。"
+
+### 设计决策
+
+为什么用文件系统而非数据库?用户可直接编辑器读写、模型用已有 write_file/read_file 就能操作、可纳入 git 版本控制。
+
+---
+
+## 第 9 章:技能系统
+
+### SKILL.md 格式
+
+```markdown
+---
+name: commit
+description: Create a git commit with a descriptive message
+when_to_use: When the user asks to commit changes
+allowed-tools: run_shell, read_file
+user-invocable: true
+---
+Look at the current git diff and staged changes...
+The user's request: $ARGUMENTS
+Project skill directory: ${CLAUDE_SKILL_DIR}
+```
+
+### 双重调用路径
+
+**路径 1:用户手动** — REPL 中 `/commit` → `resolveSkillPrompt()` → `agent.chat()`
+**路径 2:模型程序化** — 调用 `skill` 工具 → 得到展开后的 prompt 文本 → 在下一回合按此执行
+
+本质上 skill 工具是**元工具**——返回值不是数据而是指令。
+
+### 执行模式
+
+- **inline**(默认):prompt 直接注入当前对话
+- **fork**:创建独立子 Agent(`isSubAgent: true, permissionMode: "bypassPermissions"`),工具受 `allowedTools` 白名单约束
+
+fork 适合需要大量工具调用的技能(如代码审查读多个文件),避免污染主对话上下文。
+
+### 发现与加载
+
+从 `.claude/skills/`(用户级 + 项目级)加载,用 Map 去重实现"项目级覆盖用户级"。
+
+---
+
+## 第 10 章:Plan Mode
+
+### 状态变量
+
+`prePlanMode`(进入前模式,用于恢复)、`planFilePath`(plan 文件路径)、`baseSystemPrompt`(不含 plan 注入)、`contextCleared`。
+
+### Plan 系统提示
+
+约束行为(明确禁止编辑和 shell)、声明 plan 文件(唯一可写路径)、规定工作流(Explore → Design → Write → Exit)。最后一句"Do NOT ask the user to approve"是关键——否则模型常问"这个计划可以吗?"而不调用 `exit_plan_mode`。
+
+### 权限集成
+
+Plan Mode 的 read-only 通过 `checkPermission()` 强制执行。**精巧设计**:plan 文件路径作为参数传入,只有完全匹配才放行——系统提示词说"只能写 plan 文件"不只是建议,是代码强制约束。**双重保障**:提示词引导(减少无效调用)+ 权限拦截(即使模型无视提示词)。
+
+### 4 选项审批工作流
+
+| 选项 | 权限切换 | 上下文 | 适用场景 |
+|------|----------|--------|----------|
+| 1. Clear + Execute | → acceptEdits | 清空 | 计划完善,上下文已长 |
+| 2. Execute | → acceptEdits | 保留 | Agent 已有足够上下文 |
+| 3. Manual | → 恢复原模式 | 保留 | 逐步审批每修改 |
+| 4. Keep Planning | 不变 | 保留 | 给反馈让 Agent 继续调整 |
+
+### CLI 三个入口
+
+`--plan` 启动时进入、`/plan` 会话中途切换、`enter_plan_mode` 工具 Agent 自主判断。
+
+---
+
+## 第 11 章:多 Agent 架构
+
+### Sub-Agent(fork-return)模式
+
+用 ~199 行的 `subagent.ts` 实现。核心洞察:**子 Agent 本质上就是一个配置不同的 Agent 实例**——同一套 agent loop 同时服务主 Agent 和子 Agent。
+
+### 三种内置类型
+
+| 类型 | 工具集 | System Prompt |
+|------|--------|---------------|
+| Explore | read_file, list_files, grep_search, run_shell | 只读约束,快速代码探索 |
+| Plan | read_file, list_files, grep_search | 结构化规划输出 |
+| General | 全工具(排除 agent) | 通用独立任务 |
+
+### 关键实现细节
+
+- **outputBuffer** 三态:`null`=主Agent(直接打印)、`[]`=子Agent(开始收集)、`[...]`=积累中
+- **runOnce**:开启 buffer → chat() → 收集 → 关闭 buffer,生命周期边界清晰
+- **权限继承**:子 Agent 默认 bypassPermissions,但 Plan Mode 必须继承(否则安全漏洞)
+- **子 Agent 不能创建子 Agent**:General Agent 工具列表过滤掉 agent,防止递归嵌套
+
+### 自定义 Agent 类型
+
+`.claude/agents/*.md` 文件定义,frontmatter 复用 `parseFrontmatter()`。项目级(`.claude/agents/`)覆盖用户级(`~/.claude/agents/`)。
+
+---
+
+## 第 12 章:MCP 集成
+
+### 核心思路
+
+**spawn 子进程 → JSON-RPC 握手 → 发现工具 → 前缀注册 → 透明路由**。对 Agent Loop 来说,MCP 工具和内置工具没有区别——都是名字 + schema + 执行函数。
+
+### ~266 行实现,无 SDK 依赖
+
+| 组件 | 职责 |
+|------|------|
+| McpConnection | 子进程管理 + JSON-RPC 通信 |
+| McpManager | 多连接生命周期 + 配置加载 + 工具路由 |
+
+### 三段式前缀命名
+
+`mcp__serverName__toolName` — 一个名字同时解决冲突(不同服务器同名工具)和路由(从名字提取服务器名)。
+
+### 关键设计
+
+- **JSON-RPC over stdio**:零配置,进程生命周期自动绑定父进程
+- **15 秒超时**:MCP 服务器常用 npx 启动,首次需下载包
+- **懒连接**:首次 chat 时而非启动时——用户可能只想问快问题
+- **配置来源**:settings.json(用户级) + settings.json(项目级) + .mcp.json
+- **失败静默**:MCP 连接失败只输出日志,Agent 继续用内置工具
+
+### Agent 集成(仅两处改动)
+
+1. 首次 chat 时 `mcpManager.loadAndConnect()`,MCP 工具追加到 `this.tools`
+2. 工具调用路由:`if (this.mcpManager.isMcpTool(name)) return this.mcpManager.callTool(name, input)`
+
+---
+
+## 与 Claude Code 完整对比
+
+| 维度 | Claude Code | Mini Claude Code |
+|------|-------------|------------------|
+| 定位 | 生产级编程智能体 | 教学/最小可用实现 |
+| 工具数量 | 66+ 内置工具 | 13 个 |
+| 工具执行 | 并发 + streaming 早期启动 | 并行 + streaming 早期启动 |
+| API 后端 | 仅 Anthropic | Anthropic + OpenAI 兼容 |
+| 上下文管理 | 5 级压缩流水线 | 4 层 + 大结果持久化 |
+| 权限系统 | 7 层 + AST 分析 | 5 模式 + 声明式规则 + 正则 |
+| 编辑验证 | 14 步流水线 | 引号容错 + 唯一性 + mtime + diff |
+| 记忆系统 | 4 类型 + 语义召回 | 4 类型 + 语义召回 + 异步预取 |
+| 技能系统 | 6 源 + inline/fork | 2 源 + inline/fork |
+| 多 Agent | Sub-Agent + Coordinator + Swarm | Sub-Agent(3 内置 + 自定义) |
+| MCP 集成 | mcpClient.ts + 动态工具发现 | JSON-RPC over stdio |
+| 代码量 | 50 万+ 行 | ~4300 行(TS)/ ~3800 行(Python) |
+
+---
+
+## 未实现的能力
+
+| 能力 | 预计代码量 | 未实现原因 |
+|------|-----------|-----------|
+| Hooks 系统 | ~300 行 | 核心挑战在发现/加载/错误隔离,非 Agent 原理问题 |
+| Coordinator/Swarm | ~500-600 行 | 更多是 prompt engineering 问题 |
+| LSP 集成 | ~1000 行 | 需管理 LSP 服务器进程,环境障碍高 |
+| Prompt Caching | ~30 行 | 上线应第一个加,投入产出比最高 |
+| Bash AST 安全分析 | ~600 行 | tree-sitter 是 C/C++ 原生库 |
+
+---
+
+## 渐进式增强路线图
+
+### 第一阶段(1-2 天):性能优化
+- **Prompt Caching**(~30 行):给系统提示词静态部分加 `cache_control` 标记
+
+### 第二阶段(3-5 天):可扩展性
+- **Hook 系统**(~300 行):command hook,spawn 子进程传 JSON
+- **Tool 类型系统**(~200 行):从 switch/case 到插件化 Tool 接口
+
+### 第三阶段(1-2 周):可靠性与安全
+- **7 种错误恢复**(~400 行):PTL 自动压缩重试、API 过载指数退避
+- **Bash AST 安全分析**(~600 行):tree-sitter 解析 23 项检查
+
+### 第四阶段(2-4 周):高级能力
+- **Coordinator**(~500 行)、**Swarm**(~600 行)、**LSP 集成**(~1000 行)
+
+---
+
+## 运行命令速查
+
+```bash
+npm start # 交互式 REPL
+npm start -- --resume # 恢复上次会话
+npm start -- --yolo # 跳过安全确认
+npm start -- --plan # Plan 模式
+npm start -- --accept-edits # 自动批准编辑
+npm start -- --dont-ask # CI 模式
+npm start -- --max-cost 0.50 # 费用限制
+npm start -- --max-turns 20 # 轮次限制
+```
+
+## REPL 命令
+
+| 命令 | 功能 |
+|------|------|
+| `/clear` | 清空对话历史 |
+| `/cost` | 显示累计 token 用量和费用 |
+| `/compact` | 手动触发对话压缩 |
+| `/memory` | 列出所有已保存的记忆 |
+| `/skills` | 列出可用的技能 |
+| `/` | 调用已注册的技能 |
+
+## 相关链接
+
+- GitHub: https://github.com/Windy3f3f3f3f/claude-code-from-scratch
+- 在线文档: https://diwang.info/claude-code-from-scratch/
diff --git a/src/content/notes/07-Knowledge/Claude Code 从零构建 - 架构解析.md b/src/content/notes/07-Knowledge/Claude Code 从零构建 - 架构解析.md
new file mode 100644
index 0000000..e667f02
--- /dev/null
+++ b/src/content/notes/07-Knowledge/Claude Code 从零构建 - 架构解析.md
@@ -0,0 +1,308 @@
+---
+tags:
+ - coding-agent
+ - ai
+ - architecture
+ - claude-code
+ - llm
+date: 2026-07-01
+source: https://diwang.info/claude-code-from-scratch/
+github: https://github.com/Windy3f3f3f3f/claude-code-from-scratch
+title: "Claude Code 从零构建 - 架构解析"
+---
+
+# Claude Code 从零构建 - 架构解析
+
+## 项目概述
+
+**[Claude Code From Scratch](https://github.com/Windy3f3f3f3f/claude-code-from-scratch)** 是一个教学项目,用 **~4300 行代码**(TypeScript + Python 双版本)复现了 Claude Code 的核心架构。不是 demo,而是一份**分步教程**——13 章内容,每步都对照真实源码讲解。
+
+姊妹项目 **[How Claude Code Works](https://github.com/Windy3f3f3f3f/how-claude-code-works)** 有 12 篇专题、33 万字,从源码级别深度解析 Claude Code 架构。
+
+## 核心洞察(7 条)
+
+### 1. Agent 的本质是一个 while 循环
+
+```
+while true:
+ response = llm.call(messages)
+ if no tool_calls in response: break
+ for tool_call in response.tool_calls:
+ result = execute(tool_call)
+ messages.append(result)
+```
+
+所有的复杂性——权限、上下文管理、记忆、多 Agent——都是围绕这个循环的增强和防护。
+
+### 2. 提示词是最便宜的代码
+
+系统提示词里的一句话,效果等同于一个 if 语句,实现成本是 0 行代码。Agent 开发中很多行为问题的最优解不是写更多代码,而是写更好的提示词。
+
+### 3. 工具设计决定能力上限
+
+让模型做它擅长的(理解意图、生成代码),让工具做模型不擅长的(精确字符串匹配、文件系统操作、进程管理)。`edit_file` 是典型:模型生成要替换的内容,工具负责精确定位和替换。
+
+### 4. 上下文管理是 Agent 的"记忆力"
+
+上下文管理之于 agent,就像内存管理之于操作系统——用有限资源提供"无限"错觉。4 层压缩流水线让 agent 在有限窗口中保持对长对话的记忆。
+
+### 5. 安全不是事后补丁
+
+权限检查是 agent 循环的一个步骤,不是外挂的 middleware。**fail-closed 设计**:新工具如果忘记声明权限级别,被自动当作"需要确认"处理。
+
+### 6. 从 3000 行到 50 万行的差距在于边缘情况
+
+Claude Code 多出来的代码大多是:各运行环境兼容性、网络和 API 不可靠性、用户输入多样性、企业级审计和访问控制。从原型到产品,80% 的距离在这里。
+
+### 7. LLM 与代码的协作边界
+
+模型决定"做什么",代码确保"安全地做"。边界划得好,agent 既灵活又可靠。
+
+## 13 章教程结构
+
+### Phase 1: 构建可用的 Coding Agent
+
+| 章节 | 内容 | 对应源码 |
+|------|------|----------|
+| 1. Agent Loop | 核心循环:调用 LLM → 执行工具 → 重复 | query.ts |
+| 2. 工具系统 | 13 个工具 + mtime 防护 + 延迟加载 | Tool.ts + 66 工具 |
+| 3. System Prompt | 提示词工程 + @include 语法 | prompts.ts |
+| 4. CLI 与会话 | REPL、Ctrl+C、会话持久化 | cli.tsx |
+| 5. 流式输出 | 双后端 + 流式工具执行 + 并行执行 | api/claude.ts |
+| 6. 权限与安全 | 5 模式 + 声明式规则 + 危险检测 | permissions/ |
+| 7. 上下文管理 | 4 层压缩 + 大结果持久化 | compact/ |
+
+### Phase 2: 进阶能力
+
+| 章节 | 内容 | 对应源码 |
+|------|------|----------|
+| 8. 记忆系统 | 4 类型记忆 + 语义召回 + 异步预取 | memory.ts |
+| 9. 技能系统 | 技能发现 + inline/fork 双模式 | SkillTool/ |
+| 10. Plan Mode | 只读规划 + 4 选项审批工作流 | EnterPlanMode |
+| 11. 多 Agent | Sub-Agent fork-return 架构 | AgentTool/ |
+| 12. MCP 集成 | JSON-RPC over stdio 连接外部工具 | mcpClient.ts |
+| 13. 架构对比 | 完整对比 + 扩展方向 | 全局 |
+| 14. 功能测试 | 19 项手动测试覆盖全部功能 | test/ |
+
+## 项目结构(TypeScript 版,共 ~4291 行)
+
+```
+src/
+├── agent.ts # Agent 循环:流式、并行、4 层压缩、预算 (1501 行)
+├── tools.ts # 工具:13 工具 + mtime 防护 + 延迟加载 (858 行)
+├── cli.ts # CLI 入口:参数解析、REPL、预算 flags (371 行)
+├── memory.ts # 记忆系统:4 类型 + 语义召回 + 异步预取 (376 行)
+├── mcp.ts # MCP 客户端:JSON-RPC over stdio (266 行)
+├── prompt.ts # System Prompt:@include + 模板 + 注入 (230 行)
+├── ui.ts # 终端输出:彩色显示、格式化、子 Agent 显示 (211 行)
+├── subagent.ts # 子 Agent:3 内置 + 自定义 Agent 发现 (199 行)
+├── skills.ts # 技能系统:目录发现 + inline/fork 双模式 (175 行)
+├── session.ts # 会话持久化:保存/恢复/列表 (63 行)
+└── frontmatter.ts # 共享 YAML frontmatter 解析器 (41 行)
+```
+
+Python 版功能一致,~3811 行。
+
+## Agent Loop 核心设计
+
+### 双层架构
+
+- **QueryEngine**(~1155 行):会话级,管整个对话生命周期——用户输入处理、USD 预算检查、Token 统计、会话恢复
+- **queryLoop**(~1728 行):单轮级,管一次查询的执行——消息压缩、API 调用、工具执行、错误恢复
+
+设计意图:关注点分离——QueryEngine 不需要知道"PTL 错误怎么恢复",queryLoop 不需要知道"用户输入怎么解析"。
+
+### queryLoop 设计选择
+
+签名是 `async function*`(异步生成器),原因:
+1. **背压控制**:消费端不处理完,生产端不继续
+2. **线性控制流**:所有循环分支用普通 `continue`/`break` 表达,不需要状态机
+
+### 七种 Continue Reason
+
+| # | 名称 | 触发场景 | 处理策略 |
+|---|------|----------|----------|
+| 1 | next_turn | 模型调用了工具 | 执行工具,结果推入消息,继续 |
+| 2 | collapse_drain_retry | PTL 错误,有暂存的折叠操作 | 提交折叠释放空间,重试 |
+| 3 | reactive_compact_retry | PTL 错误,折叠空间不够 | 强制全量摘要压缩,重试 |
+| 4 | max_output_tokens_escalate | 输出 Token 截断,首次 | 升级到更高 Token 限制(16K→64K),重试 |
+| 5 | max_output_tokens_recovery | 输出 Token 截断,升级不可用 | 注入续写提示,最多重试 3 次 |
+| 6 | stop_hook_blocking | 任务完成但 Stop Hook 拦截 | 继续执行循环 |
+| 7 | token_budget_continuation | API 侧 Token 预算耗尽 | 继续生成 |
+
+简化实现只处理第 1 种:有 tool_use 就继续,否则停。
+
+### 错误扣留策略
+
+可恢复的错误不立即暴露给上层。当输出 Token 被截断时,如果直接 yield 错误,UI 会显示报错——但 queryLoop 后续的恢复逻辑其实能自动处理。所以先"扣留"错误,执行恢复逻辑,成功了用户完全无感知,失败了才最终暴露。大多数 `max_output_tokens` 和 `prompt_too_long` 错误都被这样静默处理掉了。
+
+### 并行工具执行
+
+```
+串行:[========= API 流式响应 =========][tool1][tool2][tool3]
+并行:[========= API 流式响应 =========]
+ ↑ tool1 JSON 完成 → 立即执行
+ ↑ tool2 JSON 完成 → 立即执行
+```
+
+Claude Code 用 `StreamingToolExecutor` 在 API 流式响应期间并行执行工具。一个典型 API 响应有 5-30 秒的流式窗口,在这个时间里多个工具可以并发完成,2-3x 加速。
+
+## 消息数组增长方式
+
+理解 Agent Loop 的关键——每轮循环消息数组增长两条(一条 assistant,一条 user 工具结果):
+
+```
+第 1 轮:
+ messages = [
+ { role: "user", content: "帮我修复 bug" }
+ { role: "assistant", content: [text + tool_use(read_file)] }
+ { role: "user", content: [tool_result("文件内容...")] }
+ ]
+
+第 2 轮(LLM 看到文件内容后决定编辑):
+ messages = [
+ ...前 3 条,
+ { role: "assistant", content: [text + tool_use(edit_file)] }
+ { role: "user", content: [tool_result("编辑成功")] }
+ ]
+
+第 3 轮(LLM 认为任务完成):
+ messages = [
+ ...前 5 条,
+ { role: "assistant", content: [text("已修复!")] } ← 无 tool_use → break
+ ]
+```
+
+工具结果用 `role: "user"` 推入是 Anthropic API 的协议要求,必须通过 `tool_use_id` 关联回对应的调用。
+
+## AbortController:优雅中断
+
+```typescript
+async chat(userMessage: string): Promise {
+ this.abortController = new AbortController();
+ try {
+ await this.chatAnthropic(userMessage);
+ } finally {
+ this.abortController = null;
+ }
+ printDivider();
+ this.autoSave();
+}
+
+abort() {
+ this.abortController?.abort();
+}
+```
+
+`abort()` 被调用后 signal 变为 `aborted`,循环在下一个检查点退出。signal 同时传给 API 调用,确保网络请求也能被取消。
+
+## 与 Claude Code 完整对比
+
+| 维度 | Claude Code | Mini Claude Code |
+|------|-------------|------------------|
+| 定位 | 生产级编程智能体 | 教学 / 最小可用实现 |
+| 工具数量 | 66+ 内置工具 | 13 个工具(6 核心 + web_fetch + tool_search + skill + agent + plan mode) |
+| 工具执行 | 并发 + streaming 早期启动 | 并行执行 + streaming 早期启动 |
+| 上下文管理 | 4 级压缩流水线 | 4 层压缩 + 大结果持久化(>30KB) |
+| 权限系统 | 7 层 + AST 分析 | 5 种模式 + 声明式规则 + 正则检测 |
+| 编辑验证 | 14 步流水线 | 引号容错 + 唯一性 + mtime 防护 + diff 输出 |
+| 记忆系统 | 4 类型 + 语义召回 | 4 类型 + 语义召回 + 异步预取 |
+| 技能系统 | 6 源 + inline/fork | 2 源 + inline/fork |
+| 多 Agent | Sub-Agent + Coordinator + Swarm | Sub-Agent(3 内置 + 自定义) |
+| MCP 集成 | mcpClient.ts + 动态工具发现 | McpManager + JSON-RPC over stdio |
+| 代码量 | 50 万+ 行 | ~4300 行(TS)/ ~3800 行(Python) |
+
+## 核心能力清单
+
+- **Agent 循环**:自动调用工具、处理结果、持续迭代
+- **13 个工具**:读写编辑文件(mtime 防护)、搜索、Shell、WebFetch、ToolSearch(延迟加载)、技能、子 Agent、Plan Mode
+- **流式输出**:逐字实时显示,Anthropic + OpenAI 双后端,streaming 工具早期执行
+- **并行工具执行**:只读工具自动并发,2-3x 加速
+- **4 层上下文压缩**:budget 截断 → stale snip → microcompact → auto-compact + 大结果持久化(>30KB 写磁盘)
+- **权限系统**:5 种模式 + `.claude/settings.json` 声明式 allow/deny 规则 + 16 个危险命令正则
+- **记忆系统**:4 类型记忆 + 语义召回(sideQuery 调模型选择相关记忆)+ 异步预取
+- **技能系统**:`.claude/skills/` 目录加载,支持 inline 注入和 fork 子 Agent 两种执行模式
+- **多 Agent**:Sub-Agent fork-return 模式(3 内置类型 + `.claude/agents/` 自定义类型)
+- **MCP 集成**:JSON-RPC over stdio 连接外部工具服务器
+- **System Prompt**:@include 语法递归引入、.claude/rules/ 自动加载
+- **Extended Thinking**:支持 adaptive/enabled/disabled 三模式
+- **预算控制**:`--max-cost` 费用限制 + `--max-turns` 轮次限制
+- **会话持久化**:自动保存对话,`--resume` 恢复
+- **错误恢复**:API 限流/过载时指数退避 + 随机抖动重试(最多 3 次),Ctrl+C 优雅中断
+- **跨平台**:Windows / macOS / Linux,自动检测 shell
+
+## 未实现的能力与原因
+
+| 能力 | 预计代码量 | 未实现原因 |
+|------|-----------|-----------|
+| **Hooks 系统** | ~300 行 | 核心挑战在发现/加载/错误隔离/JSON 数据协议,非 Agent 原理问题 |
+| **Coordinator/Swarm** | ~500-600 行 | 更多是 prompt engineering 问题而非代码架构问题 |
+| **LSP 集成** | ~1000 行 | 需要管理 LSP 服务器进程、客户端协议实现,环境障碍高 |
+| **Prompt Caching** | ~30 行 | 投入产出比最高,上线应第一个加,但需仔细设计分区策略 |
+| **Bash AST 安全分析** | ~600 行 | tree-sitter 是 C/C++ 原生库,需 node-gyp 编译环境 |
+
+## 渐进式增强路线图
+
+### 第一阶段:性能与成本优化(1-2 天)
+- **Prompt Caching**(~30 行):给系统提示词静态部分加 `cache_control: { type: "ephemeral" }` 标记,多轮对话节省 50%+ 输入 token 成本
+
+### 第二阶段:可扩展性(3-5 天)
+- **Hook 系统**(~300 行):command hook,spawn 子进程传 JSON,根据 `{"action": "allow"}` / `{"action": "deny"}` 决定
+- **Tool 类型系统**(~200 行):从硬编码 switch/case 到插件化 Tool 接口/Protocol
+
+### 第三阶段:可靠性与安全(1-2 周)
+- **7 种错误恢复策略**(~400 行):PTL 自动压缩重试、API 过载指数退避、工具失败反馈模型自修复
+- **Bash AST 安全分析**(~600 行):tree-sitter 解析 23 项静态检查
+
+### 第四阶段:高级 Agent 能力(2-4 周)
+- **Coordinator 模式**(~500 行):大任务拆分给多个专业 Agent
+- **Swarm 模式**(~600 行):多 Agent 对等通信、并行探索
+- **LSP 集成**(~1000 行):毫秒级类型错误反馈
+
+## 运行命令速查
+
+```bash
+# TypeScript
+npm start # 交互式 REPL
+npm start -- --resume # 恢复上次会话
+npm start -- --yolo # 跳过安全确认
+npm start -- --plan # Plan 模式:只分析不修改
+npm start -- --accept-edits # 自动批准文件编辑
+npm start -- --dont-ask # CI 模式
+npm start -- --max-cost 0.50 # 费用限制(美元)
+npm start -- --max-turns 20 # 轮次限制
+
+# Python
+mini-claude-py # 交互式 REPL
+mini-claude-py --resume # 恢复上次会话
+mini-claude-py --yolo # 跳过安全确认
+```
+
+## REPL 命令
+
+| 命令 | 功能 |
+|------|------|
+| `/clear` | 清空对话历史 |
+| `/cost` | 显示累计 token 用量和费用估算 |
+| `/compact` | 手动触发对话压缩 |
+| `/memory` | 列出所有已保存的记忆 |
+| `/skills` | 列出可用的技能 |
+| `/` | 调用已注册的技能(如 `/commit`) |
+
+## 配置 API
+
+```bash
+# Anthropic 格式(推荐)
+export ANTHROPIC_API_KEY="sk-ant-xxx"
+export ANTHROPIC_BASE_URL="https://aihubmix.com" # 可选代理
+
+# OpenAI 兼容格式
+export OPENAI_API_KEY="sk-xxx"
+export OPENAI_BASE_URL="https://api.openai.com/v1"
+```
+
+## 相关链接
+
+- GitHub: https://github.com/Windy3f3f3f3f/claude-code-from-scratch
+- 在线文档: https://diwang.info/claude-code-from-scratch/
+- 姊妹项目: https://github.com/Windy3f3f3f3f/how-claude-code-works
diff --git a/src/content/notes/07-Knowledge/Dev-Workflow Kit 学习笔记.md b/src/content/notes/07-Knowledge/Dev-Workflow Kit 学习笔记.md
new file mode 100644
index 0000000..a695fab
--- /dev/null
+++ b/src/content/notes/07-Knowledge/Dev-Workflow Kit 学习笔记.md
@@ -0,0 +1,308 @@
+---
+date: 2026-04-13
+tags: [学习, AI, 开发流程, 自动化, OpenClaw]
+type: 学习笔记
+category: AI工具
+source: dev-workflow-kit-main.zip
+difficulty: 高级
+title: "Dev-Workflow Kit 学习笔记"
+---
+
+# Dev-Workflow Kit 学习笔记
+
+## 概述
+
+Dev-Workflow Kit 是一个基于 OpenClaw 实现的 **AI 辅助开发工作流套件**,将软件开发全流程(需求分析 → 技术方案 → 编码 → 审查 → 部署)自动化编排。包含 17 个独立 skills,按需求复杂度自动匹配 L1/L2/L3 三级流程。
+
+## 核心概念
+
+### 1. 架构设计
+
+#### 三层加载机制
+1. **元数据层**(常驻上下文):每个 skill 的 `name` + `description`(约 100 词)
+2. **指令层**(触发时加载):SKILL.md 正文,包含完整的执行步骤和流程定义
+3. **资源层**(按需读取):`references/` 目录下的参考文档和 `scripts/` 目录下的脚本
+
+#### 设计原则
+- **松耦合**:每个 skill 独立可用,dev-workflow 只是编排层
+- **文件驱动**:skill 间仅通过文件的**本地绝对路径**流转,禁止传递摘要
+- **质量内建**:规格设计阶段并行产出,编码阶段同步写单测
+- **最少卡点**:只在真正需要人工判断的节点暂停
+- **凭证安全**:产出物中禁止写入密码/Token/密钥
+
+### 2. 三级流程
+
+#### L1 快速修复(5-10 分钟)
+```
+IF 改动点 ≤ 3 且行数 ≤ 10:
+ → L1-Lite(主 Agent 直接改代码,沙盒初始化豁免)
+ELSE:
+ → L1-Standard(委派 coding-agent subagent)
+```
+
+**流程**:分支检查 → 编码 → code-review → 部署 → 自测 → 提测交接 → 知识沉淀(轻量)
+
+**卡点**:1 个(提测确认)
+
+#### L2 标准功能
+```
+1. 需求分析(requirement-analysis)
+2. 规格设计(tech-spec + test-spec 并行)→ [规格确认卡点]
+3. 编码与测试(coding-agent)
+4. 代码审查(code-review,不通过则 bugfix 循环)
+5. 部署到测试环境
+6. 自测验证(test-executor)
+7. 提测交接(qa-handoff)→ [提测确认卡点]
+8. 知识沉淀
+9. 上线收尾
+```
+
+**卡点**:2 个(规格确认、提测确认)
+
+#### L3 复杂功能
+与 L2 相同,但:
+- 知识沉淀更完整(含 ADR 架构决策记录)
+- 增加 **需求澄清卡点**(requirement-clarification)
+
+**卡点**:3 个(需求澄清、规格确认、提测确认)
+
+### 3. 核心 Skills(17 个)
+
+#### 编排层
+- **using-dev-workflow**:入口 skill,必须在任何开发任务前调用
+- **dev-workflow**:总编排器,按需求复杂度自动分派 L1/L2/L3 流程
+
+#### 需求阶段
+- **requirement-analysis**:将原始需求转换为结构化需求文档
+- **confluence**:拉取 Confluence/Wiki 文档内容
+
+#### 规格设计阶段
+- **tech-spec**:基于结构化需求生成技术方案
+- **test-spec**:基于结构化需求生成测试用例
+- **yapi**:YAPI 接口文档管理
+
+#### 编码阶段
+- **coding-agent**:基于技术方案生成功能代码并同步编写单元测试
+
+#### 审查阶段
+- **code-review**:代码审查,不通过则触发 bugfix 循环
+
+#### 测试阶段
+- **test-executor**:执行自测(API 测试/远程 API 测试/联调测试)
+
+#### 部署阶段
+- **jenkins**:触发 Jenkins 构建
+
+#### 提测阶段
+- **qa-handoff**:提测交接(YAPI 同步、提测单生成、邮件通知)
+
+#### 知识管理
+- **knowledge-init**:为项目生成知识库(概述、代码地图、库表摘要、业务流程)
+- **knowledge-deposit**:需求完成后增量沉淀开发经验
+
+#### 其他
+- **git-commit**:生成符合 Conventional Commits 规范的提交信息
+- **send-email**:发送邮件(支持 SMTP)
+- **retro**:生成复盘报告
+
+### 4. 状态管理
+
+#### 状态文件
+位置:`{需求目录}/.workflow-state.json`
+
+核心字段:
+- `level`:流程级别(L1/L2/L3)
+- `currentPhase`:当前阶段
+- `phases`:各阶段状态(pending/in_progress/completed/failed/rolled_back)
+- `checkpoints`:卡点确认状态
+- `services`:涉及的服务列表
+- `auditLog`:审计日志
+
+#### 状态更新命令
+```bash
+# 通过脚本更新,禁止直接编辑 JSON
+STATE_CMD="python3 scripts/sandbox_state.py --sandbox-dir {sandboxDir}"
+
+# 阶段流转
+$STATE_CMD update-phase --phase requirement-analysis --status in_progress
+$STATE_CMD update-phase --phase requirement-analysis --status completed --output "specs/结构化需求.md"
+
+# 添加服务
+$STATE_CMD add-service serviceId=finance-trade serviceName=finance-trade \
+ gitUrl=https://code.qschou.com/finance/finance-trade.git \
+ localPath=/path/to/repo branch=feature/xxx
+
+# 设置卡点
+$STATE_CMD set-checkpoint --name spec-confirmation --status confirmed
+```
+
+### 5. 编码阶段的三层降级策略
+
+```
+Layer 1: tmux + CLI(可监控、可纠偏)
+ ↓ tmux 不可用
+Layer 2: exec 后台 + CLI(可看日志、不能纠偏)
+ ↓ 所有 CLI 都不可用
+Layer 3: Native 模式(subagent 用 read/write/exec 直接改代码)
+```
+
+**CLI 优先级**:`claude` → `codex` → `cursor-agent` → `gemini` → `opencode`
+
+### 6. 需求分析质量把控
+
+#### 风险预判 Checklist(6 项必检)
+1. **新增字段全链路**:从数据入口到最终展示/导出,每个环节都覆盖了吗?
+2. **新旧兼容性**:旧数据、旧模板、旧接口的用户怎么办?
+3. **工具方法兼容性**:现有的掩码、校验、格式化等通用方法是否能正确处理新值?
+4. **数据时间偏移**:定时任务的执行时间和数据的实际落表时间是否一致?
+5. **多通道互斥**:同一业务对象的多种处理路径之间是否互斥?
+6. **跨系统字段语义**:同名或相似字段在不同系统中含义是否一致?
+
+#### 歧义检测 Checklist(8 项必检)
+1. 多对多关系不明确
+2. 回调/通信机制未定义
+3. 异常场景未覆盖
+4. 边界条件未定义
+5. 状态转移不完整
+6. 数据来源不明确
+7. 触发时机不明确
+8. 权限与隔离不明确
+
+#### 待确认项质量红线
+- **必须带决策选项**:给出 2-3 个具体方案供选择
+- **必须标明不确认的后果**:说清楚不确认会导致什么
+- **必须关联下游影响**:标注影响技术方案的哪个模块
+- **P0 必须当场确认**:P0 问题不确认则停止流程
+
+## 关键要点
+
+### 1. 核心执行规则
+1. **code-review 不通过时触发 bugfix 循环,不跳过**
+2. **状态更新必须通过 `sandbox_state.py`,禁止直接编辑 `.workflow-state.json`**
+3. **角色分离**:编排层禁止直接编码(L1-Lite 除外),所有编码委派给 coding-agent subagent
+4. **沙盒强制**:流程入口必须通过 `sandbox_init.py` + `sandbox_verify.py` 初始化并校验沙盒
+5. **执行隔离**:tech-spec、test-spec、coding-agent、code-review 作为 subagent 执行(上下文隔离)
+6. **验证优先**:任何声称"完成"前,必须先运行验证命令并展示输出
+
+### 2. 文件流转规则
+| 文件 | 谁写 | 谁读 |
+|------|------|------|
+| 结构化需求.md | requirement-analysis | 所有下游 |
+| 技术方案.md | tech-spec | coding-agent、code-review、qa-handoff |
+| 测试用例.md | test-spec | coding-agent、test-executor |
+| ddl.sql | tech-spec | DBA、部署阶段 |
+
+**传递规则**:禁止传递文件内容摘要,只传本地绝对路径。子任务自行 `read` 读取完整文件。
+
+### 3. 本地验证门禁
+code-review 通过后、git commit 前执行:
+```
+Java: mvn compile -q -DskipTests && mvn test
+Go: go build ./... && go test ./...
+Vue: npm run build && npm test
+```
+
+### 4. 编码权限边界
+| 允许 | 禁止 |
+|------|------|
+| 读写 `code/<项目名>` 下 Worktree 代码 | 修改主工作区代码 |
+| 执行单元测试、代码格式化 | 执行数据库变更、安装新依赖 |
+| 在 feature 分支提交代码 | 在 test/master/main 分支写操作 |
+| `git rebase master` | `git merge test`(反向合并) |
+
+## 实践示例
+
+### 1. 初始化需求沙盒
+```bash
+# 初始化沙盒
+python3 scripts/sandbox_init.py \
+ --name "jd-chargeback-alert" \
+ --jira-id FINANCE-1475 \
+ --level L2 \
+ --knowledge-root /path/to/dev-knowledge
+
+# 校验沙盒完整性
+python3 scripts/sandbox_verify.py \
+ --sandbox-dir ~/dev-workspace/feature-20260413-jd-chargeback-alert
+```
+
+### 2. 断点续跑
+```bash
+# 读取状态文件
+cat ~/dev-workspace/feature-xxx/.workflow-state.json
+
+# 恢复流程
+# 1. 检查 currentPhase
+# 2. 检查该阶段 status:
+# - completed → 进入下一阶段
+# - in_progress → 检查产出物完整性,决定续跑或重做
+# - failed → 检查 retryLog,决定重试或等人工
+# - rolled_back → 检查 changeHistory,从回退目标阶段开始
+```
+
+### 3. 触发开发流程
+```
+用户输入:"开始需求开发,需求文档在 /path/to/需求.docx"
+
+AI 动作:
+1. 调用 using-dev-workflow skill
+2. 调用 dev-workflow skill
+3. 判定流程级别(L1/L2/L3)
+4. 初始化沙盒
+5. 进入需求分析阶段
+```
+
+## 常见问题 / 坑点
+
+| 问题 | 原因 | 解决方案 |
+|------|------|----------|
+| AI 跳过了某个阶段 | 认为任务太简单 | 强制指定级别:`--level L2` |
+| 编码跑偏 | AI 自行决策架构 | 偏离检测:`drift_detect.py` |
+| CLI 启动失败 | tmux 未安装 | 自动降级到 Layer 2 或 Layer 3 |
+| 状态文件损坏 | 直接编辑 JSON | 使用 `sandbox_state.py` 更新 |
+| 知识库找不到 | 路径配置错误 | 设置 `DEV_KNOWLEDGE_ROOT` 环境变量 |
+| 多服务并行冲突 | 改动有交叉引用 | 自动合并为串行任务 |
+
+## 适用场景分析
+
+### ✅ 适合的场景
+1. **中大型企业**:有完善的研发流程、CI/CD、测试环境
+2. **成熟团队**:团队成员有丰富的软件工程经验
+3. **复杂业务系统**:需要严格的需求分析、技术方案、代码审查
+4. **长期维护项目**:需要知识沉淀和经验复用
+
+### ❌ 不适合的场景
+1. **初创团队**:流程太重,影响快速迭代
+2. **小项目/原型开发**:过度工程化
+3. **非技术团队**:需要理解完整的软件工程流程
+4. **快速试错场景**:流程卡点会拖慢节奏
+
+## 关联知识
+
+- [[AI 编程工具对比]]
+- [[软件工程最佳实践]]
+- [[Git 工作流]]
+- [[CI/CD 流程设计]]
+
+## 参考资源
+
+- 项目来源:dev-workflow-kit-main.zip
+- 相关文档:
+ - `README.md` - 项目介绍
+ - `docs/faq.md` - 常见问题
+ - `skills/*/SKILL.md` - 各 skill 详细说明
+ - `skills/*/references/` - 参考文档和模板
+
+## 学习时间
+
+| 阶段 | 时间 | 备注 |
+| ---- | ---------- | ----------- |
+| 初次学习 | 2026-04-13 | 解压并详细阅读项目文档 |
+| 深入理解 | | |
+| 实战应用 | | |
+| 复习回顾 | | |
+
+---
+
+**状态**: 📖 已掌握
+**下次复习日期**: 2026-05-13
diff --git a/src/content/notes/07-Knowledge/How Claude Code Works - 姊妹项目概览.md b/src/content/notes/07-Knowledge/How Claude Code Works - 姊妹项目概览.md
new file mode 100644
index 0000000..16e4351
--- /dev/null
+++ b/src/content/notes/07-Knowledge/How Claude Code Works - 姊妹项目概览.md
@@ -0,0 +1,114 @@
+---
+tags:
+ - coding-agent
+ - ai
+ - architecture
+ - claude-code
+ - llm
+date: 2026-07-01
+source: https://github.com/Windy3f3f3f3f/how-claude-code-works
+docs: https://windy3f3f3f3f.github.io/how-claude-code-works/
+title: "How Claude Code Works - 姊妹项目概览"
+---
+
+# How Claude Code Works - 姊妹项目概览
+
+> 15 篇专题,33 万字,**从源码级别深度解析 Claude Code 的 50 万行 TypeScript 源码架构**。姊妹项目 [[Claude Code 从零构建 - 完整架构解析]] 是 ~4300 行的动手教程。
+
+---
+
+## 项目规模
+
+| 指标 | 数值 |
+|------|------|
+| 源码总行数 | 512,000+ |
+| TypeScript 文件 | 1,884 |
+| 内置工具 | 66+ |
+| 压缩流水线级数 | 4 级 |
+| 权限防御层数 | 5 层 |
+
+---
+
+## 系统架构全景
+
+```
+用户输入 → QueryEngine(会话管理) → query(主循环) → Claude API
+ ↓
+ 解析响应
+ ↙ ↘
+ 文本输出 工具执行引擎
+ (流式输出) ↙ ↓ ↘ ↓ ↘
+ 读文件 编辑 Shell 搜索 MCP
+ ↓
+ 结果回注 → query
+```
+
+---
+
+## 15 篇专题
+
+| # | 专题 | 核心内容 |
+|---|------|----------|
+| 01 | 概述 | 技术选型(Bun/React/Zod)、6 条核心设计原则、9 阶段 235ms 启动 |
+| 02 | 系统主循环 | 双层架构、7 种 Continue Sites 故障恢复、StreamingToolExecutor |
+| 03 | 上下文工程 | 4 级压缩流水线、压缩后 5 文件恢复+技能重激活、缓存断裂检测 |
+| 04 | 工具系统 | 66 工具注册与并发、MCP 7 种传输、OAuth 2.0+PKCE |
+| 05 | 代码编辑策略 | search-and-replace 抗幻觉设计、14 步验证、编辑前强制读取 |
+| 06 | Hooks 与可扩展性 | 23+ Hook 事件、5 种 Hook 类型、6 阶段执行管道 |
+| 07 | 多 Agent 架构 | 子 Agent 4 种执行模式、Worktree 隔离、Coordinator+Swarm |
+| 08 | 记忆系统 | 4 种记忆类型、Sonnet 语义召回、后台记忆提取 Agent、记忆漂移防御 |
+| 09 | 技能系统 | 6 层来源与优先级、懒加载与 Token 预算分配、Inline/Fork 双模式 |
+| 10 | Plan 模式 | 两条进入路径、5 阶段工作流、附件节流、Phase 4 四种实验变体 |
+| 11 | 权限与安全 | 5 层纵深防御、tree-sitter AST 23 项检查、竞速确认+200ms 防误触 |
+| 12 | 用户体验设计 | 自研 Ink 渲染器、Yoga Flexbox 布局、虚拟滚动、Vim 模式 |
+| 13 | 最小必要组件 | 7 个最小组件框架、最小 vs 生产逐项对照、500行→50万行演进路线 |
+| 14 | 系统提示词设计 | 7 层递进式架构、反模式接种、爆炸半径框架、7 条 Agent 提示词原则 |
+| 15 | 任务管理系统 | 文件级存储+并发锁、三层变更检测、依赖追踪、多 Agent 协调 |
+
+---
+
+## 关键发现
+
+### 为什么 Claude Code 感觉快?
+
+1. **全链路流式输出** — 每生成一个 token 立刻展示
+2. **工具预执行** — 模型说"我要读某个文件"时,文件其实已经在读了。利用 5-30 秒流式窗口藏起约 1 秒工具延迟
+3. **9 阶段并行启动** — 不相关初始化并行执行,关键路径压到 ~235ms
+
+### 出错了怎么办?— 静默恢复
+
+能恢复的错误用户根本看不到。对话超长→悄悄压缩+自动重试。token 达上限→自动 4K→64K 再重试。7 种不同的"继续"策略对应 7 种故障恢复路径。
+
+### 对话太长?— 4 级渐进式压缩
+
+不是一刀切,分 4 级逐步处理:裁剪→去重→折叠→摘要。每级都可能释放足够空间。压缩后自动恢复最近编辑的 5 个文件内容。
+
+### 安全防护 — 5 层纵深防御
+
+1. 权限模式 → 2. 规则匹配 → 3. **Bash AST 分析(23 项检查)** → 4. 用户确认(200ms 防抖) → 5. Hook 校验。任何一层拦住就不执行。
+
+### 66 工具协同
+
+所有工具遵循同一套接口规范。第三方 MCP 工具和内置工具走完全相同的执行流水线。只读自动并行,写操作自动串行。输出 >100K 自动落盘。
+
+### 多 Agent 协作
+
+三种模式:**子 Agent**(fork-return)、**协调器**(纯编排,不能自己读文件写代码)、**Swarm**(点对点通信)。Git Worktree 给每个 Agent 独立代码副本防冲突。
+
+---
+
+## 阅读建议
+
+- **只有 10 分钟?** → 读快速入门
+- **理解核心原理?** → 按顺序:主循环 → 上下文工程 → 工具系统
+- **自己造一个 AI Agent?** → 先读最小必要组件,再跟 claude-code-from-scratch 动手
+- **定制 Claude Code?** → Hooks + 记忆系统 + 技能系统
+- **关注安全?** → 权限与安全 + 代码编辑策略
+
+---
+
+## 相关链接
+
+- GitHub: https://github.com/Windy3f3f3f3f/how-claude-code-works
+- 在线文档: https://windy3f3f3f3f.github.io/how-claude-code-works/
+- 姊妹教程: https://github.com/Windy3f3f3f3f/claude-code-from-scratch
diff --git a/src/content/notes/07-Knowledge/claude-code-from-scratch/00-introduction.md b/src/content/notes/07-Knowledge/claude-code-from-scratch/00-introduction.md
new file mode 100644
index 0000000..aff9aa9
--- /dev/null
+++ b/src/content/notes/07-Knowledge/claude-code-from-scratch/00-introduction.md
@@ -0,0 +1,219 @@
+---
+title: "00-introduction"
+publish: true
+---
+
+# 引言:为什么从零造一个 Claude Code?
+
+## 本章目标
+
+理解项目定位、技术栈选择和整体架构,5 分钟内跑起来你自己的 coding agent。
+
+## 为什么要从零造?
+
+### AI 编程的三个阶段
+
+AI 辅助编程大致经历了三个阶段:**代码补全**(Copilot)→ **聊天助手**(Cursor Chat)→ **自主 Agent**(Claude Code)。
+
+前两个阶段的共同限制是:**模型不能执行操作**。它只能给建议,无法自己跑测试看结果。
+
+Claude Code 是一个质的飞跃。你说"给这个项目加用户注册功能",它会自己搜索路由定义、读取数据库模型、创建 handler 文件、注册路由、写测试、运行 `npm test`、看到失败、修复、再跑——循环十几次,直到通过为止。
+
+这就是 **受控工具循环 Agent**:模型是决策者,代码只是执行环境。
+
+### Agent-first 意味着什么
+
+传统程序里,代码逻辑决定行为——`if/else` 都是程序员预先写好的。Agent 架构反过来:**模型决定下一步做什么**,代码只提供循环框架和工具。
+
+整个系统的核心是一个 `while (true)` 循环:
+
+```
+while (true) {
+ 调用模型 → 模型返回响应
+ if (响应包含工具调用) → 执行工具 → 把结果喂回模型 → 继续循环
+ if (响应只是文本) → 任务完成,退出循环
+}
+```
+
+**只有当模型的响应不包含任何工具调用时,循环才会退出**——是模型,而不是代码逻辑,决定任务是否完成。
+
+### 为什么不直接读源码
+
+Claude Code 的开源快照有 50 万行 TypeScript:66+ 工具、React/Ink TUI、MCP 协议、OAuth 认证、多代理系统……直接读很容易迷失在边界情况和抽象层里。
+
+我们的做法:**只保留最小必要组件**,用 ~3400 行代码复现核心能力(记忆、技能、多 Agent、权限规则、分级压缩、预算控制、Plan Mode),每一步对照真实源码讲解。就像造卡丁车来理解汽车原理——引擎、方向盘、刹车都在,空调音响先不管。
+
+## 核心概念速览
+
+**Agent Loop**:思考—行动—观察的循环。模型收到请求后决定调用哪个工具,系统执行工具并把结果反馈给模型,模型继续思考,直到不再发出工具调用。
+
+**工具系统**:工具是 Agent 和真实世界交互的桥梁。我们在 System Prompt 里描述每个工具的名字和参数,模型需要时返回结构化的工具调用请求,代码执行后把结果喂回去。
+
+**上下文工程**:模型的表现完全取决于它看到了什么。上下文窗口有限(200K tokens),但复杂任务可能跑几十轮——所以需要压缩。我们实现了 4 级压缩:裁剪大块输出 → 摘要工具结果 → 模型总结整段对话,每级比上一级激进,系统尽量用最轻的方式解决问题。
+
+**System Prompt**:每次 API 调用前组装的第一条消息,告诉模型当前操作系统、工作目录、Git 状态、项目规则(CLAUDE.md)、可用工具列表。这些上下文直接影响模型的决策质量。
+
+**权限与安全**:能执行任意 Shell 命令的 Agent 需要安全控制。我们实现了 5 种权限模式,从"全部放行"到"全部询问用户"——写文件前检查是否允许,危险操作需要确认。
+
+## 架构全景
+
+```mermaid
+graph TB
+ User[用户输入] --> CLI[cli.ts
CLI 入口 / REPL]
+ CLI --> Agent[agent.ts
Agent 主循环]
+ Agent --> Prompt[prompt.ts
System Prompt]
+ Agent --> API{API 后端}
+ API -->|Anthropic| AnthropicSDK[Anthropic SDK]
+ API -->|OpenAI 兼容| OpenAISDK[OpenAI SDK]
+ Agent --> Tools[tools.ts
工具系统]
+ Tools --> FS[文件读写]
+ Tools --> Shell[Shell 命令]
+ Tools --> Search[搜索工具]
+ Tools --> SkillTool[skill 工具]
+ Tools --> WebFetch[web_fetch]
+ Agent --> SubAgent[subagent.ts
子 Agent]
+ SubAgent -.->|fork-return| Agent
+ Agent --> Memory[memory.ts
记忆系统]
+ Prompt --> Memory
+ Prompt --> Skills[skills.ts
技能系统]
+ Agent --> MCP[mcp.ts
MCP 集成]
+ MCP --> ExtTools[外部工具服务器]
+ Agent --> Session[session.ts
会话管理]
+ Agent --> UI[ui.ts
终端 UI]
+
+ style Agent fill:#7c5cfc,color:#fff
+ style Tools fill:#e8e0ff
+ style CLI fill:#e8e0ff
+ style Memory fill:#ffe0e0
+ style Skills fill:#ffe0e0
+ style SubAgent fill:#e0ffe0
+ style MCP fill:#e0f0ff
+```
+
+主线很清晰:**用户输入 → CLI → Agent Loop → 模型决策 → 工具执行 → 结果反馈 → 循环直到完成**
+
+各组件职责:
+
+- **`cli.ts`**:解析命令行参数,提供交互式 REPL
+- **`agent.ts`**:核心引擎(~1263 行)。组装消息、调用 API、解析响应、执行工具、压缩上下文、控制预算
+- **`prompt.ts`**:把静态提示词模板和动态环境信息(OS、目录、Git 状态、记忆、技能)拼成 System Prompt
+- **`tools.ts`**:13 个工具的定义 + 执行逻辑 + 权限检查 + 延迟加载
+- **`memory.ts` / `skills.ts`**:记忆让 Agent 跨会话记住信息(支持语义召回),技能提供可复用的操作序列,两者都在启动时注入 System Prompt
+- **`subagent.ts`**:当任务超出单个上下文窗口时,fork 子 Agent 处理子任务,完成后返回结果
+- **`mcp.ts`**:MCP 协议客户端,通过 JSON-RPC over stdio 连接外部工具服务器
+- **`session.ts`**:把对话历史写到磁盘,支持 `--resume` 恢复
+- **`ui.ts`**:终端颜色和格式化输出
+
+| 文件 | 行数 | 职责 |
+|------|------|------|
+| `agent.ts` | ~1263 | Agent 主循环:消息构造、API 调用、工具编排、流式执行、子 Agent、4 层压缩、预算控制、Plan Mode |
+| `tools.ts` | ~850 | 工具定义 + 执行:13 个工具 + 5 种权限模式 + mtime 防护 + 延迟加载 |
+| `cli.ts` | ~371 | CLI 入口、参数解析、REPL 交互 |
+| `memory.ts` | ~325 | 记忆系统:4 类型 + 文件存储 + 语义召回 + 异步预取 |
+| `mcp.ts` | ~266 | MCP 客户端:JSON-RPC over stdio、工具发现与调用转发 |
+| `ui.ts` | ~211 | 终端输出:颜色、格式化 |
+| `skills.ts` | ~175 | 技能系统:目录发现 + frontmatter 解析 + inline/fork 双模式 |
+| `subagent.ts` | ~199 | 子 Agent 配置(3 内置 + 自定义 Agent 发现) |
+| `prompt.ts` | ~154 | System Prompt 构造:模板 + @include + 变量替换 + 记忆/技能注入 |
+| `session.ts` | ~63 | 会话持久化:JSON 文件存储 |
+| `frontmatter.ts` | ~41 | YAML frontmatter 解析器 |
+| `python/` | — | Python 版完整实现(`mini_claude/` 包,~2920 行) |
+
+## 技术栈
+
+TypeScript 和 Python 两个版本分别实现,选你熟悉的看就行。
+
+
+#### **TypeScript**
+
+```
+TypeScript — 类型安全,与 Claude Code 同语言
+@anthropic-ai/sdk — Anthropic 官方 SDK
+openai — OpenAI 兼容后端支持
+chalk — 终端颜色输出
+glob — 文件模式匹配
+```
+
+#### **Python**
+
+```
+Python 3.11+ — 简洁易读
+anthropic — Anthropic 官方 SDK
+openai — OpenAI 兼容后端支持
+```
+
+
+没有框架、没有构建工具链,只有最基础的依赖。
+
+## 快速开始
+
+
+#### **TypeScript**
+
+```bash
+git clone https://github.com/Windy3f3f3f3f/claude-code-from-scratch.git
+cd claude-code-from-scratch
+npm install
+export ANTHROPIC_API_KEY=sk-ant-xxx
+npm run dev
+```
+
+#### **Python**
+
+```bash
+git clone https://github.com/Windy3f3f3f3f/claude-code-from-scratch.git
+cd claude-code-from-scratch/python
+pip install -e .
+export ANTHROPIC_API_KEY=sk-ant-xxx
+mini-claude-py "hello"
+```
+
+
+启动后:
+
+```
+ Mini Claude Code — A minimal coding agent
+
+ Type your request, or 'exit' to quit.
+ Commands: /clear /cost /compact /memory /skills /plan
+
+>
+```
+
+试试 `read src/agent.ts and explain the main loop`。
+
+### 其他选项
+
+```bash
+mini-claude --yolo "run all tests" # 跳过所有确认
+mini-claude --plan "analyze this codebase" # 只分析不修改
+mini-claude --accept-edits "refactor" # 自动批准文件编辑
+mini-claude --dont-ask "check style" # 需确认的操作自动拒绝
+mini-claude --thinking "analyze this bug" # 启用 Extended Thinking
+mini-claude --resume # 恢复上次会话
+mini-claude --max-cost 0.50 --max-turns 20 # 预算控制
+```
+
+## 各章概览
+
+| 章节 | mini-claude 文件 | Claude Code 对应源码 | |
+| ------------------------------------------- | ------------------ | --------------------------------------- | ---------------------------------------------- |
+| **Phase 1: 构建一个可用的 Coding Agent** | | | |
+| [[claude-code-from-scratch/01-agent-loop | 1. Agent Loop]] | `agent.ts` 的 `chatAnthropic()` | `src/query.ts` 的 `queryLoop` |
+| [[claude-code-from-scratch/02-tools | 2. 工具系统]] | `tools.ts` | `src/Tool.ts` + `src/tools/` (66+ 工具) |
+| [[claude-code-from-scratch/03-system-prompt | 3. System Prompt]] | `prompt.ts` | `src/constants/prompts.ts` |
+| [[claude-code-from-scratch/04-cli-session | 4. CLI 与会话]] | `cli.ts` + `session.ts` | `src/entrypoints/cli.tsx` |
+| [[claude-code-from-scratch/05-streaming | 5. 流式输出]] | `agent.ts` 的两套 stream 方法 | `src/services/api/claude.ts` |
+| [[claude-code-from-scratch/06-permissions | 6. 权限与安全]] | `tools.ts` 的 `checkPermission()` + 规则配置 | `src/utils/permissions/` (52KB) |
+| [[claude-code-from-scratch/07-context | 7. 上下文管理]] | `agent.ts` 的 `checkAndCompact()` | `src/services/compact/` |
+| **Phase 2: 进阶能力** | | | |
+| [[claude-code-from-scratch/08-memory | 8. 记忆系统]] | `memory.ts` | `src/utils/memory.ts` |
+| [[claude-code-from-scratch/09-skills | 9. 技能系统]] | `skills.ts` | `src/utils/skills.ts` + `src/tools/SkillTool/` |
+| [[claude-code-from-scratch/10-plan-mode | 10. Plan Mode]] | `agent.ts` + `tools.ts` + `cli.ts` | `EnterPlanMode` / `ExitPlanMode` |
+| [[claude-code-from-scratch/11-multi-agent | 11. 多 Agent]] | `subagent.ts` + `agent.ts` | `src/tools/AgentTool/` |
+| [[claude-code-from-scratch/12-mcp | 12. MCP 集成]] | `mcp.ts` | `src/services/mcpClient.ts` |
+| [[claude-code-from-scratch/13-whats-next | 13. 架构对比]] | 全局对比 | 全局对比 |
+
+---
+
+> **下一章**:从最核心的部分开始——Agent Loop,这是整个 coding agent 的心脏。
diff --git a/src/content/notes/07-Knowledge/claude-code-from-scratch/01-agent-loop.md b/src/content/notes/07-Knowledge/claude-code-from-scratch/01-agent-loop.md
new file mode 100644
index 0000000..25e3de4
--- /dev/null
+++ b/src/content/notes/07-Knowledge/claude-code-from-scratch/01-agent-loop.md
@@ -0,0 +1,293 @@
+---
+title: "01-agent-loop"
+publish: true
+---
+
+# 1. Agent Loop — 核心循环
+
+## 本章目标
+
+实现 coding agent 的心脏:一个 while 循环,不断调用 LLM → 检查是否需要执行工具 → 执行工具 → 把结果喂回 LLM → 重复,直到 LLM 认为任务完成。
+
+```mermaid
+graph TB
+ subgraph Agent Loop
+ A[用户消息] --> B[调用 LLM API]
+ B --> C{响应包含
tool_use?}
+ C -->|是| D[执行工具]
+ D --> E[工具结果推入消息]
+ E --> B
+ C -->|否| F[输出文本
结束循环]
+ end
+
+ style B fill:#7c5cfc,color:#fff
+ style D fill:#e8e0ff
+```
+
+## Claude Code 怎么做的
+
+### 双层架构
+
+Claude Code 把 Agent Loop 拆成两层:
+
+- **QueryEngine**(~1155 行):会话级,管整个对话生命周期——用户输入处理、USD 预算检查、Token 统计、会话恢复
+- **queryLoop**(~1728 行):单轮级,管一次查询的执行——消息压缩、API 调用、工具执行、错误恢复
+
+这样拆的好处是关注点分离:QueryEngine 不需要知道"PTL 错误怎么恢复",queryLoop 不需要知道"用户输入怎么解析"。
+
+### queryLoop:异步生成器
+
+queryLoop 签名是 `async function*`——异步生成器。选这个而不是回调/事件的原因:
+
+1. **背压控制**:消费端不处理完,生产端不继续,天然防止事件堆积
+2. **线性控制流**:所有循环分支用普通 `continue` / `break` 表达,不需要状态机
+
+### 七种 Continue Reason
+
+循环有 7 个继续位置,对应 7 种不同场景:
+
+| # | 名称 | 触发场景 | 处理策略 |
+|---|------|---------|---------|
+| 1 | `next_turn` | 模型调用了工具 | 执行工具,结果推入消息,继续 |
+| 2 | `collapse_drain_retry` | PTL 错误,有暂存的折叠操作 | 提交折叠释放空间,重试 |
+| 3 | `reactive_compact_retry` | PTL 错误,折叠空间不够 | 强制全量摘要压缩,重试 |
+| 4 | `max_output_tokens_escalate` | 输出 Token 截断,首次 | 升级到更高 Token 限制(16K→64K),重试 |
+| 5 | `max_output_tokens_recovery` | 输出 Token 截断,升级不可用 | 注入续写提示,最多重试 3 次 |
+| 6 | `stop_hook_blocking` | 任务完成但 Stop Hook 拦截 | 继续执行循环 |
+| 7 | `token_budget_continuation` | API 侧 Token 预算耗尽 | 继续生成 |
+
+我们的简化实现只处理第 1 种:有 tool_use 就继续,否则停。
+
+### 错误扣留策略
+
+这是个值得单独说的设计:**可恢复的错误不立即暴露给上层**。
+
+当输出 Token 被截断时,如果直接 yield 错误给 QueryEngine,UI 会显示报错——但 queryLoop 后续的恢复逻辑其实能自动处理这个问题。所以 Claude Code 的做法是先"扣留"错误,执行恢复逻辑,成功了用户完全无感知,失败了才最终暴露。大多数 `max_output_tokens` 和 `prompt_too_long` 错误都被这样静默处理掉了。
+
+### 并行工具执行
+
+Claude Code 用 `StreamingToolExecutor` 在 API 流式响应期间并行执行工具:
+
+```
+串行(我们的实现):
+ [========= API 流式响应 =========][tool1][tool2][tool3]
+
+并行(Claude Code):
+ [========= API 流式响应 =========]
+ ↑ tool1 的 JSON 完成 → 立即执行
+ ↑ tool2 的 JSON 完成 → 立即执行
+```
+
+一个典型 API 响应有 5-30 秒的流式窗口,在这个时间里多个工具可以并发完成。
+
+## 我们的实现
+
+把双层架构合并成一个 `Agent` 类,核心是 `chatAnthropic()` 方法:
+
+
+#### **TypeScript**
+```typescript
+// agent.ts — chatAnthropic 方法(核心 Agent Loop)
+
+private async chatAnthropic(userMessage: string): Promise {
+ this.anthropicMessages.push({ role: "user", content: userMessage });
+ // 在 turn boundary 触发 auto-compact:此时最后一条消息是纯文本 user,
+ // compactAnthropic 内部的 slice(0, -1) 不会切断 tool_use ↔ tool_result 配对(详见第 7 章)
+ await this.checkAndCompact();
+
+ while (true) {
+ if (this.abortController?.signal.aborted) break;
+
+ const response = await this.callAnthropicStream();
+
+ // 累计 token 用量
+ this.totalInputTokens += response.usage.input_tokens;
+ this.totalOutputTokens += response.usage.output_tokens;
+ this.lastInputTokenCount = response.usage.input_tokens;
+
+ // 提取 tool_use block
+ const toolUses: Anthropic.ToolUseBlock[] = [];
+ for (const block of response.content) {
+ if (block.type === "tool_use") toolUses.push(block);
+ }
+
+ // assistant 响应推入历史
+ this.anthropicMessages.push({ role: "assistant", content: response.content });
+
+ // 没有工具调用 → 任务完成
+ if (toolUses.length === 0) {
+ printCost(this.totalInputTokens, this.totalOutputTokens);
+ break;
+ }
+
+ // 串行执行每个工具
+ const toolResults: Anthropic.ToolResultBlockParam[] = [];
+ for (const toolUse of toolUses) {
+ if (this.abortController?.signal.aborted) break;
+
+ const input = toolUse.input as Record;
+ printToolCall(toolUse.name, input);
+
+ // 权限检查(详见第 6 章)
+ const perm = checkPermission(toolUse.name, input, this.permissionMode, this.planFilePath);
+ if (perm.action === "deny") {
+ toolResults.push({ type: "tool_result", tool_use_id: toolUse.id,
+ content: `Action denied: ${perm.message}` });
+ continue;
+ }
+ if (perm.action === "confirm" && perm.message && !this.confirmedPaths.has(perm.message)) {
+ const confirmed = await this.confirmDangerous(perm.message);
+ if (!confirmed) {
+ toolResults.push({ type: "tool_result", tool_use_id: toolUse.id,
+ content: "User denied this action." });
+ continue;
+ }
+ this.confirmedPaths.add(perm.message);
+ }
+
+ const result = await executeTool(toolUse.name, input);
+ printToolResult(toolUse.name, result);
+ toolResults.push({ type: "tool_result", tool_use_id: toolUse.id, content: result });
+ }
+
+ // 工具结果以 user 消息推入(Anthropic API 要求)
+ this.anthropicMessages.push({ role: "user", content: toolResults });
+ }
+}
+```
+#### **Python**
+```python
+# agent.py — _chat_anthropic 方法(核心 Agent Loop)
+
+async def _chat_anthropic(self, user_message: str) -> None:
+ self._anthropic_messages.append({"role": "user", "content": user_message})
+ # 在 turn boundary 触发 auto-compact:此时最后一条是纯文本 user,
+ # _compact_anthropic 内部的 [:-1] 不会切断 tool_use ↔ tool_result 配对(详见第 7 章)
+ await self._check_and_compact()
+
+ while True:
+ if self._aborted:
+ break
+
+ self._run_compression_pipeline()
+ response = await self._call_anthropic_stream()
+
+ self.total_input_tokens += response.usage.input_tokens
+ self.total_output_tokens += response.usage.output_tokens
+ self.last_input_token_count = response.usage.input_tokens
+
+ tool_uses = [b for b in response.content if b.type == "tool_use"]
+
+ self._anthropic_messages.append({
+ "role": "assistant",
+ "content": [self._block_to_dict(b) for b in response.content],
+ })
+
+ if not tool_uses:
+ if not self.is_sub_agent:
+ print_cost(self.total_input_tokens, self.total_output_tokens)
+ break
+
+ tool_results = []
+ for tu in tool_uses:
+ if self._aborted:
+ break
+ inp = dict(tu.input) if hasattr(tu.input, 'items') else tu.input
+ print_tool_call(tu.name, inp)
+
+ # 权限检查(详见第 6 章)
+ perm = check_permission(tu.name, inp, self.permission_mode, self._plan_file_path)
+ if perm["action"] == "deny":
+ tool_results.append({"type": "tool_result", "tool_use_id": tu.id,
+ "content": f"Action denied: {perm.get('message', '')}"})
+ continue
+ if perm["action"] == "confirm" and perm.get("message") \
+ and perm["message"] not in self._confirmed_paths:
+ confirmed = await self._confirm_dangerous(perm["message"])
+ if not confirmed:
+ tool_results.append({"type": "tool_result", "tool_use_id": tu.id,
+ "content": "User denied this action."})
+ continue
+ self._confirmed_paths.add(perm["message"])
+
+ result = await self._execute_tool_call(tu.name, inp)
+ print_tool_result(tu.name, result)
+ tool_results.append({"type": "tool_result", "tool_use_id": tu.id, "content": result})
+
+ self._anthropic_messages.append({"role": "user", "content": tool_results})
+```
+
+
+### 消息数组的增长方式
+
+理解 Agent Loop 的关键:消息数组是怎么增长的。
+
+```
+第 1 轮:
+ messages = [
+ { role: "user", content: "帮我修复 bug" }
+ { role: "assistant", content: [text + tool_use(read_file)] }
+ { role: "user", content: [tool_result("文件内容...")] }
+ ]
+
+第 2 轮(LLM 看到文件内容后决定编辑):
+ messages = [
+ ...前 3 条,
+ { role: "assistant", content: [text + tool_use(edit_file)] }
+ { role: "user", content: [tool_result("编辑成功")] }
+ ]
+
+第 3 轮(LLM 认为任务完成):
+ messages = [
+ ...前 5 条,
+ { role: "assistant", content: [text("已修复!")] } ← 无 tool_use → break
+ ]
+```
+
+每轮循环消息数组增长两条:一条 assistant,一条 user(工具结果)。模型每次都能看到完整历史,这是它能"记住"之前做过什么的原因。工具结果用 `role: "user"` 推入是 Anthropic API 的协议要求,结果必须通过 `tool_use_id` 关联回对应的调用。
+
+### AbortController:优雅中断
+
+
+#### **TypeScript**
+```typescript
+async chat(userMessage: string): Promise {
+ this.abortController = new AbortController();
+ try {
+ await this.chatAnthropic(userMessage);
+ } finally {
+ this.abortController = null;
+ }
+ printDivider();
+ this.autoSave();
+}
+
+abort() {
+ this.abortController?.abort();
+}
+```
+#### **Python**
+```python
+async def chat(self, user_message: str) -> None:
+ self._aborted = False
+ try:
+ if self.use_openai:
+ await self._chat_openai(user_message)
+ else:
+ await self._chat_anthropic(user_message)
+ finally:
+ pass
+ if not self.is_sub_agent:
+ print_divider()
+ self._auto_save()
+
+def abort(self) -> None:
+ self._aborted = True
+```
+
+
+`AbortController` 是标准的中断机制:`abort()` 被调用后 signal 变为 `aborted`,循环在下一个检查点退出。signal 同时传给 API 调用,确保网络请求也能被取消。
+
+---
+
+> **下一章**:循环的核心动力是工具——没有工具,LLM 只是一个聊天机器人。我们来看工具系统的实现。
diff --git a/src/content/notes/07-Knowledge/claude-code-from-scratch/02-tools.md b/src/content/notes/07-Knowledge/claude-code-from-scratch/02-tools.md
new file mode 100644
index 0000000..ad47322
--- /dev/null
+++ b/src/content/notes/07-Knowledge/claude-code-from-scratch/02-tools.md
@@ -0,0 +1,844 @@
+---
+title: "02-tools"
+publish: true
+---
+
+# 2. 工具系统
+
+## 本章目标
+
+定义 6 个核心工具(读文件、写文件、编辑文件、列文件、搜索、Shell)+ 5 个扩展工具(skill、agent、web_fetch、tool_search、plan mode),让 LLM 能真正操作你的代码库。实现编辑防护(read-before-edit + mtime 检查)和延迟加载(deferred tools)机制。
+
+```mermaid
+graph LR
+ LLM[LLM 响应] --> |tool_use block| Dispatch[executeTool
分发器]
+ Dispatch --> RF[read_file]
+ Dispatch --> WF[write_file]
+ Dispatch --> EF[edit_file]
+ Dispatch --> LF[list_files]
+ Dispatch --> GS[grep_search]
+ Dispatch --> RS[run_shell]
+ Dispatch --> SK[skill]
+ Dispatch --> AG[agent]
+ Dispatch --> WEB[web_fetch]
+ Dispatch --> TS[tool_search]
+ Dispatch --> EP[enter_plan_mode
deferred]
+ Dispatch --> XP[exit_plan_mode
deferred]
+ RF --> Result[工具结果字符串]
+ WF --> Result
+ EF --> Result
+ LF --> Result
+ GS --> Result
+ RS --> Result
+ SK --> Result
+ AG --> Result
+ WEB --> Result
+ TS --> Result
+ EP --> Result
+ XP --> Result
+
+ style Dispatch fill:#7c5cfc,color:#fff
+ style EF fill:#e8e0ff
+ style RF fill:#e8e0ff
+```
+
+## Claude Code 怎么做的
+
+### Tool 接口 — 每个工具的完整契约
+
+Claude Code 的每个工具都遵循统一的 `Tool` 泛型接口,不是简单函数签名,而是完整的行为契约:
+
+```typescript
+type Tool = {
+ name: string
+ aliases?: string[] // 废弃别名,平滑迁移
+ maxResultSizeChars: number // 超过则持久化到磁盘
+
+ call(args, context, canUseTool, parentMessage, onProgress?): Promise>
+
+ description(input, options): Promise // 发给 API 的工具描述
+ prompt(options): Promise // 注入 system prompt 的使用指南
+
+ inputSchema: Input // Zod Schema(运行时验证 + 类型推导)
+ inputJSONSchema?: ToolInputJSONSchema
+
+ isConcurrencySafe(input): boolean // 接收 input:同一工具不同参数可有不同安全语义
+ isReadOnly(input): boolean
+ isDestructive?(input): boolean
+ checkPermissions(input, context): Promise
+
+ renderToolUseMessage(input, options): React.ReactNode // 每个工具自带渲染
+ renderToolResultMessage?(content, progress, options): React.ReactNode
+}
+```
+
+几个设计要点:
+
+**`isConcurrencySafe(input)` 接收参数**——这意味着同一工具对不同输入可以有不同安全语义。BashTool 对 `ls` 返回 `isReadOnly: true`,对 `rm` 返回 `false`。比给整个工具打标签精确得多。
+
+**`prompt()` 方法**——每个工具可以向 system prompt 注入自己的使用指南。FileEditTool 注入"精确匹配"规则,BashTool 注入安全执行提醒。工具行为指引和工具定义紧密关联,而非散落在全局 prompt 文件里。
+
+**渲染方法**——每个工具自带渲染逻辑,新增工具不需要修改全局渲染代码。
+
+### buildTool 工厂 — Fail-Closed 默认值
+
+```typescript
+const TOOL_DEFAULTS = {
+ isConcurrencySafe: () => false, // 默认不可并发
+ isReadOnly: () => false, // 默认有写入副作用
+ isDestructive: () => false,
+ checkPermissions: () => ({ behavior: 'allow', updatedInput }),
+}
+```
+
+这是 **fail-closed** 设计:错误标记"只读"工具为"非只读"后果是不必要的权限弹窗(烦人但安全);反向错误——错误标记"写入"工具为"只读"——可能让它在没有权限检查的情况下并发执行(危险且隐蔽)。默认值只能选安全的方向。
+
+### 工具注册 — 三层流水线
+
+```mermaid
+flowchart TD
+ L1["Layer 1: getAllBaseTools()
核心工具直接 import
+ Feature-gated 条件导入"] --> L2["Layer 2: getTools()
运行时上下文过滤
SIMPLE模式 / deny规则 / isEnabled()"]
+ L2 --> L3["Layer 3: assembleToolPool()
内置工具 + MCP桥接工具
分区排序 + 去重"]
+ L3 --> Final[最终工具池]
+```
+
+Layer 1 的 Feature-gated 工具通过条件 `require()` 加载:
+
+```typescript
+const SleepTool = feature('PROACTIVE') || feature('KAIROS')
+ ? require('./tools/SleepTool/SleepTool.js').SleepTool
+ : null
+```
+
+`feature()` 是 Bun 打包器的编译时宏。外部构建时求值为 `false`,整个 `require()` 被死代码消除——内部工具在外部二进制中物理上不存在。
+
+Layer 3 的分区排序:内置工具按字母序在前,MCP 工具追加在后,不做全局排序。原因是 API 服务器在最后一个内置工具之后设置了缓存断点,分区确保添加 MCP 工具不影响内置工具的缓存命中。
+
+### 工具执行生命周期 — 8 个阶段
+
+```mermaid
+flowchart TD
+ Input[模型输出 tool_use block] --> Find["1. 工具查找"]
+ Find --> Validate["2. 输入验证(Zod + 业务逻辑)"]
+ Validate --> Parallel["3. 并行启动"]
+
+ subgraph 并行
+ Hook["Pre-Tool Hook"]
+ Classifier["Bash 安全分类器"]
+ end
+
+ Parallel --> Hook
+ Parallel --> Classifier
+ Hook --> Perm["4. 权限检查(Hook→工具→规则→分类器→交互确认)"]
+ Classifier --> Perm
+
+ Perm --> Exec["5. tool.call()(流式进度)"]
+ Exec --> Result["6. 结果处理(大结果持久化到磁盘)"]
+ Result --> PostHook["7. Post-Tool Hook"]
+ PostHook --> Emit["8. tool_result 返回给模型"]
+```
+
+几个值得关注的阶段:
+
+**Stage 2 两阶段验证**:Phase 1 是 Zod Schema(字段类型),Phase 2 是业务逻辑(如 FileEditTool 检查 old_string 是否唯一)。分离确保低成本检查先执行,减少不必要的磁盘 I/O。
+
+**Stage 3 并行启动**:Pre-Tool Hook 和 Bash 分类器同时启动,各需数十到数百毫秒,并行化降低权限检查总延迟。
+
+**Stage 6 大结果处理**:结果超过 `maxResultSizeChars` 时,完整内容保存到 `~/claude-code/tool-results/`,模型收到文件路径 + 截断指示符,需要时通过 FileReadTool 主动拉取。
+
+> **核心设计哲学:错误是数据,不是异常。** 任何阶段的错误都转换为带 `is_error: true` 的 `tool_result` 返回给模型,让模型自我纠正。
+
+### 并发控制
+
+```typescript
+private canExecuteTool(isConcurrencySafe: boolean): boolean {
+ const executingTools = this.tools.filter(t => t.status === 'executing')
+ return (
+ executingTools.length === 0 ||
+ (isConcurrencySafe && executingTools.every(t => t.isConcurrencySafe))
+ )
+}
+```
+
+规则很简单:非并发安全的工具必须独占执行;多个并发安全工具可以同时跑。`StreamingToolExecutor` 不等模型输出完所有 tool_use blocks,一旦检测到完整 block 就立即启动执行——工具执行延迟约 1 秒,模型流式输出持续 5-30 秒,大部分工具可以完全隐藏在流式窗口内。
+
+并发上限 `MAX_TOOL_USE_CONCURRENCY = 10`。
+
+### edit_file 的核心设计
+
+FileEditTool 执行前有 14 步验证(按 I/O 成本排序:先检查内存状态,再访问磁盘),其中最关键的三个:
+
+**读取前置检查**:代码层面的强制约束,不只是 prompt 建议。未先读取文件则拒绝执行,确保模型基于文件当前状态编辑而非过时记忆。
+
+**外部修改检测**:通过 mtime 检测文件在读取后是否被外部修改(比如用户在 IDE 中编辑了同一个文件),解决真实竞争条件。
+
+**配置文件保护**:对 `.claude/settings.json` 等,验证会模拟执行编辑后做 JSON Schema 校验,防止看似合理的编辑损坏配置格式。
+
+### 为什么用 search-and-replace
+
+在确定 search-and-replace 之前,有几种备选方案:
+
+| 方案 | 致命缺陷 |
+|------|---------|
+| 行号编辑 | 位置相关:第一次插入 3 行后,后续所有行号偏移,多步编辑需要复杂重算 |
+| AST 编辑 | 语法错误的文件恰恰最需要编辑,而 AST 解析器遇到语法错误会直接报错 |
+| Unified diff | LLM 生成严格格式时表现很差:hunk header 行号、`+`/`-`/空格前缀任一出错则 patch 无法应用 |
+| 全文件重写 | 大文件浪费 Token;模型可能遗漏未修改代码;用户无法快速 review |
+| **字符串替换** | ✅ 无上述缺陷 |
+
+search-and-replace 最被低估的优势是**幻觉安全**:模型提供了一个文件中不存在的字符串,工具直接失败,模型重新读取文件纠正记忆。全文件重写则可能静默地把错误的内容写入文件。
+
+## 我们的简化决策
+
+| Claude Code 的设计 | 我们的简化 | 简化理由 |
+|-------------------|-----------|---------|
+| 66+ 工具类,每个独立目录 | 1 个文件 + 6 个函数 | 教程不需要工业级模块化 |
+| 8 阶段生命周期 | 直接 switch 分发 + 执行 | 省略 Hook、权限检查、分类器 |
+| StreamingToolExecutor 并发 | 串行逐个执行 | 避免并发复杂度 |
+| 14 步验证流水线 | 唯一性检查 + 引号容错 | 保留最关键的 2 个验证 |
+| 三级大结果限制 | 单层 50K 截断 | 足够防止上下文爆炸 |
+| MCP 7 种传输 + OAuth | 不支持 MCP | 教程聚焦核心概念 |
+
+核心理念:**保留设计哲学,砍掉工程复杂度**。
+
+## 我们的实现
+
+### 工具定义:静态数组
+
+
+#### **TypeScript**
+```typescript
+// tools.ts — 工具定义(Anthropic Tool schema 格式)
+
+export const toolDefinitions: ToolDef[] = [
+ {
+ name: "read_file",
+ description: "Read the contents of a file. Returns the file content with line numbers.",
+ input_schema: {
+ type: "object",
+ properties: {
+ file_path: { type: "string", description: "The path to the file to read" },
+ },
+ required: ["file_path"],
+ },
+ },
+ {
+ name: "write_file",
+ description: "Write content to a file. Creates the file if it doesn't exist, overwrites if it does.",
+ input_schema: {
+ type: "object",
+ properties: {
+ file_path: { type: "string", description: "The path to the file to write" },
+ content: { type: "string", description: "The content to write to the file" },
+ },
+ required: ["file_path", "content"],
+ },
+ },
+ {
+ name: "edit_file",
+ description: "Edit a file by replacing an exact string match with new content. The old_string must match exactly.",
+ input_schema: {
+ type: "object",
+ properties: {
+ file_path: { type: "string", description: "The path to the file to edit" },
+ old_string: { type: "string", description: "The exact string to find and replace" },
+ new_string: { type: "string", description: "The string to replace it with" },
+ },
+ required: ["file_path", "old_string", "new_string"],
+ },
+ },
+ // ... list_files, grep_search, run_shell
+];
+```
+#### **Python**
+```python
+# tools.py — 工具定义(Anthropic Tool schema 格式)
+
+tool_definitions: list[ToolDef] = [
+ {
+ "name": "read_file",
+ "description": "Read the contents of a file. Returns the file content with line numbers.",
+ "input_schema": {
+ "type": "object",
+ "properties": {
+ "file_path": {"type": "string", "description": "The path to the file to read"},
+ },
+ "required": ["file_path"],
+ },
+ },
+ # ... write_file, edit_file, list_files, grep_search, run_shell
+]
+```
+
+
+这些定义直接传给 Anthropic API 的 `tools` 参数,格式完全一致,不需要任何转换。
+
+**为什么用静态数组而非类?** Claude Code 用类体系是因为 66+ 工具需要继承、多态、独立测试。6 个工具用一个数组 + 一个 switch 就够了,简单性本身就是价值。
+
+### 工具执行:switch 分发器
+
+
+#### **TypeScript**
+```typescript
+export async function executeTool(
+ name: string,
+ input: Record
+): Promise {
+ let result: string;
+ switch (name) {
+ case "read_file": result = readFile(input as { file_path: string }); break;
+ case "write_file": result = writeFile(input as { file_path: string; content: string }); break;
+ case "edit_file": result = editFile(input as { file_path: string; old_string: string; new_string: string }); break;
+ case "list_files": result = await listFiles(input as { pattern: string; path?: string }); break;
+ case "grep_search": result = grepSearch(input as { pattern: string; path?: string; include?: string }); break;
+ case "run_shell": result = runShell(input as { command: string; timeout?: number }); break;
+ default: return `Unknown tool: ${name}`;
+ }
+ return truncateResult(result); // ← 50K 字符保护
+}
+```
+#### **Python**
+```python
+async def execute_tool(name: str, inp: dict) -> str:
+ handlers = {
+ "read_file": _read_file,
+ "write_file": _write_file,
+ "edit_file": _edit_file,
+ "list_files": _list_files,
+ "grep_search": _grep_search,
+ "run_shell": _run_shell,
+ }
+ handler = handlers.get(name)
+ if not handler:
+ return f"Unknown tool: {name}"
+ return _truncate_result(handler(inp))
+```
+
+
+`default` 分支返回 `Unknown tool: ${name}` 而非抛异常——体现"错误是数据"的设计,让模型能自我纠正幻觉出的工具名。
+
+### 逐个工具详解
+
+#### read_file
+
+
+#### **TypeScript**
+```typescript
+function readFile(input: { file_path: string }): string {
+ try {
+ const content = readFileSync(input.file_path, "utf-8");
+ const lines = content.split("\n");
+ const numbered = lines
+ .map((line, i) => `${String(i + 1).padStart(4)} | ${line}`)
+ .join("\n");
+ return numbered;
+ } catch (e: any) {
+ return `Error reading file: ${e.message}`;
+ }
+}
+```
+#### **Python**
+```python
+def _read_file(inp: dict) -> str:
+ try:
+ content = Path(inp["file_path"]).read_text()
+ lines = content.split("\n")
+ numbered = "\n".join(f"{i+1:4d} | {line}" for i, line in enumerate(lines))
+ return numbered
+ except Exception as e:
+ return f"Error reading file: {e}"
+```
+
+
+加行号是为了让 LLM 定位代码位置,但 `edit_file` 匹配时用的是实际内容字符串,不是行号。
+
+#### edit_file — 最关键的工具
+
+
+#### **TypeScript**
+```typescript
+function editFile(input: {
+ file_path: string;
+ old_string: string;
+ new_string: string;
+}): string {
+ try {
+ const content = readFileSync(input.file_path, "utf-8");
+
+ // 唯一匹配检查
+ const count = content.split(input.old_string).length - 1;
+ if (count === 0)
+ return `Error: old_string not found in ${input.file_path}`;
+ if (count > 1)
+ return `Error: old_string found ${count} times. Must be unique.`;
+
+ const newContent = content.replace(input.old_string, input.new_string);
+ writeFileSync(input.file_path, newContent);
+ return `Successfully edited ${input.file_path}`;
+ } catch (e: any) {
+ return `Error editing file: ${e.message}`;
+ }
+}
+```
+#### **Python**
+```python
+def _edit_file(inp: dict) -> str:
+ try:
+ path = Path(inp["file_path"])
+ content = path.read_text()
+
+ # 引号容错匹配
+ actual = _find_actual_string(content, inp["old_string"])
+ if not actual:
+ return f"Error: old_string not found in {inp['file_path']}"
+
+ count = content.count(actual)
+ if count > 1:
+ return f"Error: old_string found {count} times in {inp['file_path']}. Must be unique."
+
+ new_content = content.replace(actual, inp["new_string"], 1)
+ path.write_text(new_content)
+
+ diff = _generate_diff(content, actual, inp["new_string"])
+ quote_note = " (matched via quote normalization)" if actual != inp["old_string"] else ""
+ return f"Successfully edited {inp['file_path']}{quote_note}\n\n{diff}"
+ except Exception as e:
+ return f"Error editing file: {e}"
+```
+
+
+唯一匹配检查是核心:出现 0 次说明模型对文件内容记忆有误(幻觉检测),出现 > 1 次则要求模型提供更多上下文来唯一标识修改点。"宁可失败也不猜测"——静默替换第一个匹配远比告知失败危险。
+
+#### 引号容错 + Diff 输出
+
+LLM 的 tokenization 可能将直引号映射为弯引号(`"` → `"`),没有容错机制这类编辑会 100% 失败。
+
+
+#### **TypeScript**
+```typescript
+function normalizeQuotes(s: string): string {
+ return s
+ .replace(/[\u2018\u2019\u2032]/g, "'") // curly single → straight
+ .replace(/[\u201C\u201D\u2033]/g, '"'); // curly double → straight
+}
+
+function findActualString(fileContent: string, searchString: string): string | null {
+ if (fileContent.includes(searchString)) return searchString;
+ const normSearch = normalizeQuotes(searchString);
+ const normFile = normalizeQuotes(fileContent);
+ const idx = normFile.indexOf(normSearch);
+ if (idx !== -1) return fileContent.substring(idx, idx + searchString.length);
+ return null;
+}
+```
+#### **Python**
+```python
+def _normalize_quotes(s: str) -> str:
+ s = re.sub("[\u2018\u2019\u2032]", "'", s)
+ s = re.sub('[\u201c\u201d\u2033]', '"', s)
+ return s
+
+def _find_actual_string(file_content: str, search_string: str) -> str | None:
+ if search_string in file_content:
+ return search_string
+ norm_search = _normalize_quotes(search_string)
+ norm_file = _normalize_quotes(file_content)
+ idx = norm_file.find(norm_search)
+ if idx != -1:
+ return file_content[idx:idx + len(search_string)]
+ return None
+```
+
+
+关键细节:匹配成功后返回**文件中的原始字符串**而非标准化版本,替换时保持文件原始字符风格。
+
+编辑成功后生成简易 diff,行号通过计算 `old_string` 前面有几个 `\n` 得出:
+
+```
+Successfully edited src/app.ts (matched via quote normalization)
+
+@@ -15,1 +15,1 @@
+- const msg = "hello";
++ const msg = "world";
+```
+
+#### write_file
+
+
+#### **TypeScript**
+```typescript
+function writeFile(input: { file_path: string; content: string }): string {
+ try {
+ const dir = dirname(input.file_path);
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
+ writeFileSync(input.file_path, input.content);
+ return `Successfully wrote to ${input.file_path}`;
+ } catch (e: any) {
+ return `Error writing file: ${e.message}`;
+ }
+}
+```
+#### **Python**
+```python
+def _write_file(inp: dict) -> str:
+ try:
+ path = Path(inp["file_path"])
+ path.parent.mkdir(parents=True, exist_ok=True)
+ path.write_text(inp["content"])
+ lines = inp["content"].split("\n")
+ line_count = len(lines)
+ preview = "\n".join(f"{i+1:4d} | {l}" for i, l in enumerate(lines[:30]))
+ trunc = f"\n ... ({line_count} lines total)" if line_count > 30 else ""
+ return f"Successfully wrote to {inp['file_path']} ({line_count} lines)\n\n{preview}{trunc}"
+ except Exception as e:
+ return f"Error writing file: {e}"
+```
+
+
+自动创建父目录(`mkdir -p` 效果)避免模型还得额外调用 shell 命令。System Prompt 里告诉 LLM 优先用 `edit_file`,只对新文件用 `write_file`。
+
+#### grep_search
+
+
+#### **TypeScript**
+```typescript
+function grepSearch(input: {
+ pattern: string;
+ path?: string;
+ include?: string;
+}): string {
+ try {
+ const args = ["--line-number", "--color=never", "-r"];
+ if (input.include) args.push(`--include=${input.include}`);
+ args.push(input.pattern);
+ args.push(input.path || ".");
+ const result = execSync(`grep ${args.join(" ")}`, {
+ encoding: "utf-8",
+ maxBuffer: 1024 * 1024,
+ timeout: 10000,
+ });
+ const lines = result.split("\n").filter(Boolean);
+ return lines.slice(0, 100).join("\n") +
+ (lines.length > 100 ? `\n... and ${lines.length - 100} more matches` : "");
+ } catch (e: any) {
+ if (e.status === 1) return "No matches found.";
+ return `Error: ${e.message}`;
+ }
+}
+```
+#### **Python**
+```python
+def _grep_search(inp: dict) -> str:
+ pattern = inp["pattern"]
+ path = inp.get("path") or "."
+ include = inp.get("include")
+
+ try:
+ args = ["grep", "--line-number", "--color=never", "-r"]
+ if include:
+ args.append(f"--include={include}")
+ args.extend(["--", pattern, path])
+ result = subprocess.run(args, capture_output=True, text=True, timeout=10)
+ if result.returncode == 1:
+ return "No matches found."
+ if result.returncode != 0:
+ return f"Error: {result.stderr}"
+ lines = [l for l in result.stdout.split("\n") if l]
+ output = "\n".join(lines[:100])
+ if len(lines) > 100:
+ output += f"\n... and {len(lines) - 100} more matches"
+ return output
+ except Exception as e:
+ return f"Error: {e}"
+```
+
+
+`--color=never` 禁用 ANSI 颜色代码(输出给模型看的,不需要颜色)。Python 版本的 `--` 分隔符确保以 `-` 开头的 pattern 不被误解析为 grep 选项。
+
+grep 退出码 1 表示"无匹配"不是错误,2+ 才是真正错误,需要分别处理。结果截断为前 100 条,附加 `... and N more matches` 提示。
+
+Claude Code 用 ripgrep (`rg`),我们用系统 `grep`——功能够用,少一个依赖。
+
+#### run_shell
+
+
+#### **TypeScript**
+```typescript
+function runShell(input: { command: string; timeout?: number }): string {
+ try {
+ const result = execSync(input.command, {
+ encoding: "utf-8",
+ maxBuffer: 5 * 1024 * 1024,
+ timeout: input.timeout || 30000,
+ stdio: ["pipe", "pipe", "pipe"],
+ });
+ return result || "(no output)";
+ } catch (e: any) {
+ const stderr = e.stderr ? `\nStderr: ${e.stderr}` : "";
+ const stdout = e.stdout ? `\nStdout: ${e.stdout}` : "";
+ return `Command failed (exit code ${e.status})${stdout}${stderr}`;
+ }
+}
+```
+#### **Python**
+```python
+def _run_shell(inp: dict) -> str:
+ try:
+ timeout = inp.get("timeout", 30)
+ result = subprocess.run(
+ inp["command"],
+ shell=True,
+ capture_output=True,
+ text=True,
+ timeout=timeout,
+ )
+ if result.returncode != 0:
+ stderr = f"\nStderr: {result.stderr}" if result.stderr else ""
+ stdout = f"\nStdout: {result.stdout}" if result.stdout else ""
+ return f"Command failed (exit code {result.returncode}){stdout}{stderr}"
+ return result.stdout or "(no output)"
+ except subprocess.TimeoutExpired:
+ return f"Command timed out after {inp.get('timeout', 30)}s"
+ except Exception as e:
+ return f"Error: {e}"
+```
+
+
+失败时同时返回 stdout 和 stderr——很多编译器在 stderr 输出错误的同时,stdout 可能有有用的部分输出。`"(no output)"` 避免模型在命令成功但无输出时(`mkdir`、`touch`)产生困惑。
+
+Claude Code 的 BashTool 分布在 18 个源文件中,有 AST 解析命令、沙箱执行、23 个安全检查。我们只做 timeout 保护(安全机制在第 6 章详述)。
+
+### 工具结果截断
+
+
+#### **TypeScript**
+```typescript
+const MAX_RESULT_CHARS = 50000;
+
+function truncateResult(result: string): string {
+ if (result.length <= MAX_RESULT_CHARS) return result;
+ const keepEach = Math.floor((MAX_RESULT_CHARS - 60) / 2);
+ return (
+ result.slice(0, keepEach) +
+ "\n\n[... truncated " + (result.length - keepEach * 2) + " chars ...]\n\n" +
+ result.slice(-keepEach)
+ );
+}
+```
+#### **Python**
+```python
+MAX_RESULT_CHARS = 50000
+
+def _truncate_result(result: str) -> str:
+ if len(result) <= MAX_RESULT_CHARS:
+ return result
+ keep_each = (MAX_RESULT_CHARS - 60) // 2
+ return (
+ result[:keep_each]
+ + f"\n\n[... truncated {len(result) - keep_each * 2} chars ...]\n\n"
+ + result[-keep_each:]
+ )
+```
+
+
+保留头尾而非只保留头部,因为很多命令的关键输出在末尾(编译错误摘要、测试结果统计)。截断提示明确告知模型内容被截断,模型可据此决定是否用 `grep_search` 或 `read_file` 获取完整内容。
+
+### WebFetch 工具
+
+让 Agent 能访问 URL 获取内容——查文档、读 API 响应、抓取网页信息:
+
+
+#### **TypeScript**
+```typescript
+// tools.ts — web_fetch 定义
+{
+ name: "web_fetch",
+ description: "Fetch a URL and return its content as text. For HTML pages, tags are stripped.",
+ input_schema: {
+ type: "object",
+ properties: {
+ url: { type: "string", description: "The URL to fetch" },
+ max_length: { type: "number", description: "Maximum content length (default 50000)" },
+ },
+ required: ["url"],
+ },
+}
+
+// tools.ts — web_fetch 执行
+case "web_fetch": {
+ const url = input.url as string;
+ const maxLength = (input.max_length as number) || 50000;
+ const controller = new AbortController();
+ const timeout = setTimeout(() => controller.abort(), 30000);
+ try {
+ const res = await fetch(url, {
+ signal: controller.signal,
+ headers: { "User-Agent": "mini-claude/1.0" },
+ });
+ clearTimeout(timeout);
+ if (!res.ok) { result = `HTTP error: ${res.status} ${res.statusText}`; break; }
+ let text = await res.text();
+ if (contentType.includes("html")) {
+ // 去掉 script/style 标签,HTML 标签转空格,处理 HTML 实体
+ text = text
+ .replace(/