260319学习总结笔记

算法相关

详见leetcode题解

LLM相关

1.MCP单次调用的上下文占用大于skill,因为MCP的资源与工具是暴露的,凡事都要走LLM过一遍,而skill是原子性的,其资源与工具都是封闭的

2.MCP 不替代 Function Call,而是标准化了 Function Call 的目标端

3.如何写好一个工具?

原则 说明 反例
原子性 一个工具只做一件事 process_data_and_send_email() 应拆分为两个工具
语义自描述 函数名和参数名即文档 fn(a, b)search_documents(query, limit)
幂等性 多次调用结果一致 查询类工具天然幂等;写入类需去重机制
无副作用(查询类) 读操作不修改状态 get_user() 不应触发日志更新

4.提示词工程与上下文工程的比较

维度 提示词工程 (Prompt Engineering) 上下文工程 (Context Engineering)
关注焦点 单个指令的措辞与结构 多轮对话中的信息状态管理
时间尺度 单次交互(Turn-level) 跨会话生命周期(Session-level)
核心问题 “如何问得更好” “如何让AI记得更准、用得更巧”
技术对象 Prompt Template、Few-shot示例 记忆系统、RAG、上下文窗口策略
优化目标 单次输出质量 长期一致性、连贯性、个性化

5.

┌─────────────────────────────────────────┐
│ 上下文工程 (Context) │
│ ┌─────────────────────────────────┐ │
│ │ 提示词工程 (Prompt) │ │
│ │ “在当前背景下,如何提问” │ │
│ └─────────────────────────────────┘ │
│ 记忆管理 | RAG | 会话状态 | 个性化 │
└─────────────────────────────────────────┘

6.如何避免不同用户上下文互相污染

1.为每个用户/租户部署独立的LLM实例、数据库和向量存储
2.使用租户ID或用户ID作为上下文标识,确保每个用户/租户的上下文是独立的
3.在每个会话中,根据用户/租户ID或会话ID来管理上下文,确保每个会话的上下文是独立的
4.强制租户ID传递
每个请求必须携带不可伪造的租户标识:
使用JWT令牌嵌入 tenant_id 和 user_id
在中间件层注入租户上下文,而非依赖用户输入
所有工作流节点必须通过guard-rail验证租户权限
会话状态隔离
采用Burn-After-Use(用后即焚)机制:
会话数据存储在临时缓存(如Redis),设置TTL自动过期
对话结束后主动清除上下文窗口和检索缓存
避免使用全局变量存储用户特定信息
5.短期记忆(对话上下文)
使用scoped memory keys:remember(user_id + session_id + key)
禁止在系统提示词中硬编码其他用户的信息
实现上下文沙箱,确保多轮对话不越界
长期记忆(用户画像)
按 user_id 或 tenant_id 分片存储
Mem0等平台通过存储层隔离实现默认安全

7.agent工具调用需要明确区分错误类型,避免对永久性错误进行无效重试

8.入参校验

现在有诸如Pydantic这样的校验库,不需要反复造轮子

9.Agent 系统可观测平台,是专门为 AI Agent 提供全链路监控、调试、评估与治理的一体化平台,解决 Agent 从开发到生产的 “黑盒” 问题,让你清晰看到 Agent 做了什么、为什么这么做、性能与成本如何、是否合规。

Datadog:AI Agent Monitoring,统一 Metrics/Traces/Logs,支持 OpenTelemetry,企业级告警。
New Relic:无代码 AI Agent 平台,动态运行时,深度整合 OTel 与 MCP,面向 SRE 运维。
Elastic Observability:开源栈、AI Assistant、根因分析、日志 / 指标 / 链路统一分析。
阿里云 / 腾讯云 / 华为云:云原生可观测 + AI 监控,无缝对接云服务,适合云上部署。

Web相关

1.HTTP版本

版本 发布时间 现状
HTTP/1.1 1997年 仍在广泛使用
HTTP/2 2015年 (RFC 7540) 目前主流,广泛部署
HTTP/3 2022年 (RFC 9114) 快速普及中,已有大量采用

2.

WebSocket 长连接:一次 HTTP 握手成功后,建立持久双向 TCP 连接,服务端和客户端可以随时互相发消息。
HTTP轮询:客户端每隔固定时间发一次请求,问服务端有没有新数据。

3.websocket 服务端示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package main

import (
"log"
"net/http"
"time"

"github.com/gorilla/websocket"
)

// 定义升级器,将HTTP连接升级为WebSocket连接
var upgrader = websocket.Upgrader{
// 允许跨域(开发环境,生产环境需限制具体域名)
CheckOrigin: func(r *http.Request) bool {
return true
},
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}

// 客户端连接结构体(可选,用于管理多个客户端)
type Client struct {
conn *websocket.Conn
send chan []byte // 消息发送通道
}

// 全局客户端管理(简化版,生产环境建议用更安全的结构)
var clients = make(map[*Client]bool)

// 处理WebSocket连接
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
// 升级HTTP连接为WebSocket
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("升级连接失败:", err)
return
}
defer conn.Close()

// 创建客户端实例
client := &Client{
conn: conn,
send: make(chan []byte, 256),
}
clients[client] = true
log.Println("新客户端连接,当前在线数:", len(clients))

// 心跳检测:定时发送ping,确保连接不中断
go func() {
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for range ticker.C {
// 发送ping帧,客户端会自动回复pong
err := conn.WriteMessage(websocket.PingMessage, nil)
if err != nil {
log.Println("心跳发送失败:", err)
delete(clients, client)
return
}
}
}()

// 读取客户端消息的循环
for {
// 读取客户端发送的消息(类型:文本/二进制)
mt, message, err := conn.ReadMessage()
if err != nil {
log.Println("读取消息失败:", err)
delete(clients, client)
break
}

// 打印客户端消息
log.Printf("收到客户端消息: %s", message)

// 回复客户端(echo服务)
err = conn.WriteMessage(mt, append([]byte("服务端回复: "), message...))
if err != nil {
log.Println("发送消息失败:", err)
delete(clients, client)
break
}
}

log.Println("客户端断开连接,当前在线数:", len(clients))
}

// 静态文件服务(用于提供Vue页面)
func serveStatic(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "./index.html") // 假设Vue打包后的index.html在当前目录
}

func main() {
// 注册WebSocket处理路由
http.HandleFunc("/ws", handleWebSocket)
// 注册静态文件路由(测试用)
http.HandleFunc("/", serveStatic)

log.Println("服务端启动,监听端口8080...")
log.Fatal(http.ListenAndServe(":8080", nil))
}

4.示例说明

upgrader:核心升级器,负责将 HTTP 请求升级为 WebSocket 连接,CheckOrigin 用于跨域配置(生产环境需改为校验具体域名)。
心跳检测:通过定时发送 Ping 帧,确保长连接不被网关 / 防火墙断开(默认 30 秒一次)。
客户端管理:用 map 简单管理在线客户端(生产环境建议加互斥锁)。
消息循环:持续读取客户端消息,收到后立即回复(echo 逻辑),异常时清理客户端连接。

5.什么是 WebSocket 消息循环?

WebSocket 是全双工的通信协议(客户端和服务端可同时收发消息),但它的消息收发是事件驱动的 —— 不会主动 “推送” 消息,需要程序持续监听消息事件 / 读取消息流,这个 “持续监听 + 处理消息” 的逻辑就是消息循环。
简单来说:
对服务端:一直盯着每个客户端的连接,只要客户端发消息就立刻处理,直到连接断开。
对客户端:一直盯着和服务端的连接,只要服务端发消息就立刻接收,直到主动 / 被动断开。
在之前的 Go 代码中,服务端的消息循环体现在 handleWebSocket 函数的 for 循环里,这是最典型的服务端消息循环实现:

这歌不错:【依澄しあ】ルミネイト【kyiku】

kyuki真王朝了

令牌桶(Token Bucket)

令牌桶(Token Bucket) 是一种经典的流量控制 / 限流算法,核心是以固定速率生成令牌、请求必须消耗令牌才能通过,既限制长期平均速率,又允许短时间突发流量,是高并发系统中最常用的限流方案之一。
系统按固定速率往 “桶” 里放令牌,桶满则丢弃;请求到达时,必须从桶中取走对应数量的令牌才能被处理;无令牌则限流(拒绝 / 排队)。
设定两个核心参数
桶容量(Capacity, C):桶最多能存多少令牌(决定最大突发量)
令牌生成速率(Rate, R):每秒生成多少令牌(决定长期平均速率)
令牌填充:以速率 R 持续向桶中添加令牌;桶满(达到 C)后,新令牌被丢弃

数据库

乐观锁

乐观锁是一种轻量级并发控制机制,核心假设是并发冲突概率低,读取数据时不加锁,仅在提交更新时校验是否被其他事务修改

Mysql死锁

1. 资源互斥访问顺序不一致

这是人为操作最容易导致的死锁。当两个事务对数据库表的操作顺序相反时,就容易触发。
场景描述:
事务 A:先更新 表 1,再更新 表 2。
事务 B:先更新 表 2,再更新 表 1。

2. 外键关联导致的死锁

父表 Class(班级),子表 Student(学生,关联班级 ID)。
事务 A:删除 Class 中的一条记录(会检查外键,锁住 Student 中对应的行)。
事务 B:先删除 Student 中的对应记录(锁住 Student 行),再删除 Class 记录。
两者操作顺序相反,且互相依赖对方资源,导致死锁。

3. 索引失效导致的死锁

InnoDB(MySQL 默认存储引擎)是基于行锁(Row Lock)工作的,但如果 SQL 语句中的索引失效,行锁就会降级为表锁(Table Lock)。
场景描述:
你有一个 user 表,主键是 id,普通字段 phone 建了索引。
事务 A 执行 UPDATE user SET name=’A’ WHERE phone=138xxxx;(走了索引,锁住行)。
事务 B 执行 UPDATE user SET name=’B’ WHERE id=999;(正常走主键索引)。
如果你写错 SQL,比如 WHERE phone LIKE ‘%xx’ 或 使用了函数运算,导致索引失效,InnoDB 会退化为表级锁,锁住整张表。此时如果两个事务同时操作,就会互相阻塞导致死锁。

这歌好听[【kyiku】一成不变的内心令人畏惧/このままの心で怖かった](https://www.bilibili.com/video/BV1YZ421j7uF)

联合索引

联合索引(也叫复合索引)是数据库中基于多个列共同创建的索引,区别于只基于单个列的 “单列索引”。它的核心是:把多个列的值组合起来作为索引的 key,按照 “先第一列、再第二列、最后第三列……” 的优先级排序,形成一个有序的索引结构。

左前缀法则

联合索引(复合索引)的左前缀法则是数据库索引使用中最核心、最基础的规则之一,理解它能直接决定你的 SQL 查询是否能高效利用索引,避免全表扫描。
一、核心概念(通俗解释)
把联合索引想象成一本按 “省份 + 城市 + 区” 排序的电话簿:
电话簿的排序规则是:先按省份(第一列)排,省份相同再按城市(第二列)排,城市相同再按区(第三列)排。
左前缀法则就是:只有从最左侧的列开始查询,才能利用到这本电话簿的排序规则。比如:
查 “江苏省” 的所有记录 → 能直接定位(用了第一列);
查 “江苏省南京市” 的所有记录 → 能定位(用了第一 + 第二列);
查 “南京市” 的所有记录 → 无法直接定位(跳过了省份,电话簿里南京可能在江苏、广西等不同省份下,只能全本翻);
查 “江苏省南京市秦淮区” → 能定位(用了全部列)。

什么是 AT 模式?

AT 模式 = (Seata 里的一种)分布式事务方案。保证多个服务、多个数据库操作,要么一起成功,要么一起失败。

死信队列

死信队列:管消息异常,处理消费失败的消息,不堵系统、不丢消息。

Mysql超卖与加锁

会的,超卖问题在纯 MySQL 架构下不仅会出现,而且是高并发场景下的高频问题 —— 核心原因是多线程/多请求同时操作库存数据,导致数据一致性被破坏,和是否用分布式架构无关(AT 模式是解决分布式场景的超卖,单库也会有)。

一、先看为什么会出现(用最直观的例子)

假设商品库存 stock = 1,现在有 2 个用户同时下单:

时间 用户A请求 用户B请求 库存实际值
T1 查询库存:1 查询库存:1 1
T2 扣减库存:1-1=0 扣减库存:1-1=0 1
T3 提交事务,库存更新为0 提交事务,库存更新为0 0

最终结果:库存变成 0,但两个用户都下单成功 → 超卖

本质是:MySQL 默认的 READ COMMITTED/REPEATABLE READ 隔离级别,无法阻止“查询-扣减”这个非原子操作的并发问题。

二、纯 MySQL 下超卖的常见场景

  1. 高并发下单:秒杀、促销时,大量请求同时查库存、扣库存;
  2. 未加锁/锁粒度不对:比如只查不锁、用了行锁但条件不对(如查范围);
  3. 事务未控制:扣库存的 SQL 没放在事务里,或事务提交时机错误;
  4. 乐观锁使用不当:比如版本号没生效,或重试逻辑缺失。

三、纯 MySQL 怎么解决超卖(从易到难)

方案1:悲观锁(简单直接,适合低并发)

核心:查询库存时就加锁,不让其他请求修改,直到当前事务完成。

1
2
3
4
5
6
7
8
9
10
11
-- 开启事务
BEGIN;
-- 查询并加行锁(FOR UPDATE 是关键),只有当前事务能改这条数据
SELECT stock FROM goods WHERE id = 1 FOR UPDATE;
-- 检查库存,不足则回滚
IF stock > 0 THEN
UPDATE goods SET stock = stock - 1 WHERE id = 1;
COMMIT; -- 提交事务,释放锁
ELSE
ROLLBACK; -- 库存不足,回滚
END IF;

⚠️ 缺点:高并发下锁等待会导致性能下降,甚至超时。

方案2:乐观锁(推荐,适合高并发)

核心:不提前锁数据,扣减时校验库存是否被修改,避免并发覆盖。

1
2
3
4
5
6
-- 扣减库存时,加条件 stock > 0 且 版本号匹配(或直接用 stock)
UPDATE goods
SET stock = stock - 1, version = version + 1
WHERE id = 1 AND stock > 0;

-- 执行后判断影响行数:>0 说明扣减成功,=0 说明库存不足(超卖)

✅ 优点:无锁等待,性能高;缺点:需要业务层处理“扣减失败”的情况(比如返回“库存不足”)。

方案3:使用 MySQL 原子操作(极简)

核心:把“查库存+扣库存”合并成一条 SQL,利用 MySQL 单条 SQL 的原子性避免并发问题。

1
2
3
4
5
6
-- 一条 SQL 完成校验+扣减,天然原子性,不会出现中间态
UPDATE goods
SET stock = stock - 1
WHERE id = 1 AND stock > 0;

-- 同样判断影响行数:>0 成功,=0 失败

✅ 最优解(单库场景):最简单、性能最好,没有并发漏洞。

四、和 AT 模式的关系

  • 纯 MySQL 方案:解决单库的超卖问题;
  • Seata AT 模式:解决多库/多服务的超卖问题(比如订单库和库存库不在一个服务,AT 保证扣库存和创建订单要么都成,要么都回滚)。

总结

  1. 超卖是 MySQL 单库高并发下的必然问题,核心是“查询-扣减”非原子操作导致的并发覆盖;
  2. 纯 MySQL 解决超卖的核心思路:把“查+扣”做成原子操作(单条 SQL/加锁),避免并发修改;
  3. AT 模式是分布式场景的补充,解决跨服务的库存+订单一致性,而非单库超卖本身。

如果需要,我可以给你一段 Java + MySQL 的完整代码示例,演示如何用乐观锁/原子 SQL 彻底解决超卖问题。

个人感觉使用 MySQL 原子操作最舒服

其他

求职语境下的OC是何意味

OC = Offer Call,指录用意向电话。
OC ≠ 正式 Offer:OC 是口头意向,不具备法律约束力。
存在 “毁 OC” 风险:少数公司可能因 HC 冻结、业务调整等原因,在 OC 后不发正式 Offer。
稳妥做法:收到 OC 后,耐心等待正式邮件 Offer并仔细核对条款;签约前不轻易拒绝其他机会

PVZ2

芦笋战机削成废品了

前端

HTML5 语义化标签有哪些

HTML5 语义化标签的核心是用有意义的标签代替无语义的

/,让标签本身就能表达页面结构和内容含义,而非仅靠样式或脚本定义。
标签 含义(语义) 典型使用场景

页面 / 区块的头部(页眉) 网站导航、logo、标题、搜索框
公告
欢迎来到清风的个人博客!
目录
  1. 1. 260319学习总结笔记
    1. 1.1. 算法相关
    2. 1.2. LLM相关
      1. 1.2.1. 1.MCP单次调用的上下文占用大于skill,因为MCP的资源与工具是暴露的,凡事都要走LLM过一遍,而skill是原子性的,其资源与工具都是封闭的
      2. 1.2.2. 2.MCP 不替代 Function Call,而是标准化了 Function Call 的目标端
      3. 1.2.3. 3.如何写好一个工具?
      4. 1.2.4. 4.提示词工程与上下文工程的比较
      5. 1.2.5. 5.
      6. 1.2.6. 6.如何避免不同用户上下文互相污染
      7. 1.2.7. 7.agent工具调用需要明确区分错误类型,避免对永久性错误进行无效重试
      8. 1.2.8. 8.入参校验
      9. 1.2.9. 9.Agent 系统可观测平台,是专门为 AI Agent 提供全链路监控、调试、评估与治理的一体化平台,解决 Agent 从开发到生产的 “黑盒” 问题,让你清晰看到 Agent 做了什么、为什么这么做、性能与成本如何、是否合规。
    3. 1.3. Web相关
      1. 1.3.1. 1.HTTP版本
      2. 1.3.2. 2.
      3. 1.3.3. 3.websocket 服务端示例
      4. 1.3.4. 4.示例说明
      5. 1.3.5. 5.什么是 WebSocket 消息循环?
      6. 1.3.6. 这歌不错:【依澄しあ】ルミネイト【kyiku】
      7. 1.3.7. 令牌桶(Token Bucket)
    4. 1.4. 数据库
      1. 1.4.1. 乐观锁
      2. 1.4.2. Mysql死锁
        1. 1.4.2.1. 1. 资源互斥访问顺序不一致
        2. 1.4.2.2. 2. 外键关联导致的死锁
        3. 1.4.2.3. 3. 索引失效导致的死锁
      3. 1.4.3. 这歌好听[【kyiku】一成不变的内心令人畏惧/このままの心で怖かった](https://www.bilibili.com/video/BV1YZ421j7uF)
      4. 1.4.4. 联合索引
      5. 1.4.5. 左前缀法则
      6. 1.4.6. 什么是 AT 模式?
      7. 1.4.7. 死信队列
      8. 1.4.8. Mysql超卖与加锁
        1. 1.4.8.1. 一、先看为什么会出现(用最直观的例子)
        2. 1.4.8.2. 二、纯 MySQL 下超卖的常见场景
        3. 1.4.8.3. 三、纯 MySQL 怎么解决超卖(从易到难)
          1. 1.4.8.3.1. 方案1:悲观锁(简单直接,适合低并发)
          2. 1.4.8.3.2. 方案2:乐观锁(推荐,适合高并发)
          3. 1.4.8.3.3. 方案3:使用 MySQL 原子操作(极简)
        4. 1.4.8.4. 四、和 AT 模式的关系
        5. 1.4.8.5. 总结
      9. 1.4.9. 个人感觉使用 MySQL 原子操作最舒服
    5. 1.5. 其他
      1. 1.5.1. 求职语境下的OC是何意味
      2. 1.5.2. PVZ2
    6. 1.6. 前端
      1. 1.6.1. HTML5 语义化标签有哪些
    7. 1.7. hexo推送更新:
      1. 1.7.1. 1. 清理本地生成的静态文件(避免缓存问题)
      2. 1.7.2. 2. 重新生成静态博客文件
      3. 1.7.3. 3. 部署到你的博客服务器(如GitHub Pages/Gitee Pages)
      4. 1.7.4. 快捷组合指令(clean + generate + deploy)
最新文章