Telegram Channel
记录和分享有趣的信息。

Record and share interesting information.

contact: [email protected]
简单分享下我是怎么花最少的钱,但是又非常重度、高频的依赖 AI coding 的。

我目前的订阅是,最便宜的 copilot 和 codex。这两个的特点在于:codex 是按量付费的,而 copilot 是按次付费的。这个区别是最关键的,如果你更喜欢 cc,那么你可以把本文中的 codex 替换为 cc,一样的逻辑。

而作为 coding,其实工作可以拆分为两大类型,我相信其他大部分文字工作也可以这么拆分:

1. 计划阶段:此时会涉及非常高频交流,但是每次交流的内容都不多,你可以使用 codex 的最高思考模式,写下最核心的关键逻辑
2. 实施阶段:这是广义的实施,包括收集资料、撰写文档、coding、testing、debug 反复调试 都可以视为实施。

copilot 的按次付费,使它成为实施阶段的最佳性价比选择。发送一次 prompt 算一次费用,只要 agent loop 没有结束,期间一切的 tools 调用都不计费。只要通过 prompt 给它输入我们之前和 codex 聊好的 spec,接下来就让 copilot 吭哧吭哧的去把最脏最累但是没有特别高思考难度的活全部干完。

具体怎么让 copilot(我最爱用 gpt-5.4) 能够不中断的,一次性干完最多活,这里面需要调试 copilot 的 instructions,具体就不展开了,各有各的方法。但是我这里推荐一下我的 remote MCP server https://mcp.laisky.com/tools/get_user_requests

其中的这个 get_user_requests tool,相当于是在 MCP 上维护了一个 TODO list,而且是你可以动态编辑的 TODO list。你只需要在 instructions 里要求 copilot 频繁的,在每次子任务结束后,都去调用 get_user_requests,而且必须在连续两次调用 get_user_requests 为空后才能返回。你其实就拥有了在不打断 agent 一次任务的前提下,和 agent 沟通的能力,而利用这个能力,你就可以让 copilot 在一次计费里,干掉尽可能多的活。

举个我的例子,极端情况下,我很可能一天只需要跑 3 次 copilot,中间会停两次是因为我要吃午饭和晚饭,没精力去盯着 get_user_requests 的 requests queue 了。我甚至经常跑出 copilot 的 tokens quota limit,会被停用一段时间,估计很多人可能都不知道 copilot 还有limit 吧😂

Copilot 还有个我非常喜欢的地方是,如果你把配额用超了,它可以自动转为按次计费,每一次请求约为 $0.03 USD,很实惠。

如果你非常有钱,或者公司给无限的订阅资金,可以忽略这一条。和穷人们共勉。
https://developer.1password.com/docs/service-accounts/use-with-1password-cli/

最近折腾的一件事就是把服务器部署的密钥全部用 1Password 管理了。

以前的做法比较粗糙,我有一个 private github repo 专门存放各种密钥,每台主机上都在固定的位置 clone 这个 repo。

现在我在 1Password 上创建了一个 vault 专门存放这些密钥,然后为每一台主机创建一个 service account,给它访问这个 vault 的权限。每台主机上安装 1Password CLI,并使用对应的 service account 登录,就可以用下面的形式定义密钥了。

SESSION_SECRET=op://configs/oneapi/SESSION_SECRET
SQL_DSN=op://configs/oneapi/SQL_DSN
LOG_PUSH_TOKEN=op://configs/oneapi/LOG_PUSH_TOKEN


对于那些通过环境变量获得密钥的应用,直接使用 op run --env-file=./one-api/b1.env -- <ORIGINAL_COMMAND> 就可以了,1pwd cli 会自动解析这些环境变量并替换成对应的密钥值。
如果你不喜欢环境变量,也可以通过 1Password 的 SDK 在代码里直接获取密钥值。

这样做的优点是,可以在 1pwd 的网站上通过吊销 service account 的访问权限来快速撤销某台主机的密钥访问。可惜就是 audit log 仅对 Business 版本可用,还有就是 service account 的权限粒度仅支持 vault 级别,聊胜于无吧,对于个人服务来说至少比裸奔强多了。 Use service accounts with 1Password CLI | 1Password Developer
https://laisky.notion.site/Effective-context-engineering-for-AI-agents-Anthropic-2ddba4011a868170ac2ddd9017afadde?source=copy_link

Anthropic 介绍 context engineering 的文章。

- prompt engineering 主要关注如何撰写 system prompt。
- context engineering 则关注 agent 相关的所有工程问题。

注意力是稀缺的,context 过长,反而会导致模型能力下降(context rot)。

所谓 Agent,就是在 loop 内自动调用工具的 LLM。

context 注入的两种方式:
1. 在推理前,利用 RAG 检索和注入 context(延迟低)
2. 在 Agent 运行的过程中,通过 tools 自动检索和读取(可以 progressive disclosure,信息更准确)。推荐使用类文件系统的信息索引方式,这些文件的路径本身,也包含重要的信息。

long-horizon tasks 的 context 优化工具箱:
- compaction:压缩 context,仅保留关键信息。记忆信息拆分不同的 TTL 层级,然后按照不同的文件路径进行组织和存储。
- structured note-taking:context 外部的记忆工具,如 TODO list
- multi-agent architectures:拆分子任务,coordinator 仅派发任务和接收 sub-agent worker 的摘要。不要试图用一个上下文维护大型项目的全部信息。

Anthropic 还有一篇 Effective harnesses for long-running agents 感觉只是对本文的 multi-agent architectures 的一些实践小经验总结,信息量不多。

👆 prev Notion—The AI workspace that works for you.
https://laisky.notion.site/Building-Effective-AI-Agents-Anthropic-2ddba4011a868146b90bf176d265cf81?source=copy_link

虽然人们喜欢说 agent 取代了 workflow,但是 agent 本身其实也是由一系列的 workflow 最小功能单元组成的。

区别在于,workflow 是由固定的逻辑和工具组成的。而 agent 则是由 LLM 动态选择工具和生成逻辑组成的。

本文介绍了用来构建 agent 的 workflow 功能单元:

- chain: 最常见的串行流水线
- routing: 动态判断任务类型,传递给不同的下游
- parallel: 并行处理多个任务
- orchestrating: 类似于 parallel,但是下游的任务是动态生成的,而不是预定义的并行流水线
- evaluator-optimizer: 如果存在一个清晰的验收标准,那么添加一个 feedback loop 可以显著提升输出质量

agents 的执行路径是动态生成的,无法预测准确执行步数和资源消耗。但是为了防止死循环等问题,应该对资源消耗、步数等预设停机条件。

👇 next Notion—The AI workspace that works for you.
最近都在重度使用 https://jules.google.com/,Google 出品的自动代码优化工具。我主要用来给我的项目找 BUG,效果非常显著。

免费用户可以并行 2 个任务(声称是 3 个,实际上只能运行 2 个😓)。

选择好项目、branch 后,点击下面预设的 Performance、Design、Security 生成 prompt。然后建议把执行计划改为 Start(单次执行),而不是默认的 Scheduled,防止占用有限的任务配额。(如果你是尊贵的付费用户那请忽略)

免费用户只能选用 gemini-3-flash。我个人的使用体验是,它找 BUG 的能力非常强,但是修复的能力比较弱。我目前的使用方法是,把 BUG REPORT 粘贴给其他更强力的模型来修复,最近每天都能找出很多陈年老 BUG,每天都在打击我身为老程序员的自尊😭

不过换个思路,这也是一个去刷开源项目 PR 的机会。
https://laisky.notion.site/Agent-Skills-Comprehensive-Guide-2e4ba4011a868055b2b0e2e128da1538?source=copy_link

学习了一下 Anthropic 的 Agent Skills 设计。通过在文件系统中定义一套文件结构,让 Agent 可以按需加载(Progressive Disclosure)相关的技能描述和脚本。

Skills 通过 metadata + instructions + scripts 定义一个领域技能。Agent 在启动时全量加载 metadatas,然后按需加载 instructions,而 instructions 会指导 agent 调用 scripts。scripts 的内容不会被加载,只有 output 会被加载进入 context。

通过一个三层的 lazy-loading 设计,相当于 RAG + tools,既减少了对 context 的占用,也赋予了 agent 工具调用的能力。

但是我认为,Anthropic 没有选择优化 MCP,而是硬造了一个新轮子,给 Agent 世界带来更多的混乱,有些可惜。

Skills 的功能完全可以通过对 MCP 的些微优化来实现,只需要在 MCP 中增加两个 tools:

- find_skills(query): 根据 query 查找相关的 skills metadata 列表
- describe_skill(skill_id): 根据 skill_id 获取对应的 instructions。instructions 内会指导 agent 如果通过调用其他 tools 完成任务。

实际上,已经有很多人发布了相关的 skills-mcp 工具,只要搜索 github skills-mcp 就能找到很多。
https://laisky.notion.site/msanft-CVE-2025-55182-Explanation-and-full-RCE-PoC-for-CVE-2025-55182-2c2ba4011a8681b89b60cf02827a6276?source=copy_link

之前提到的 next/react 严重服务端 RCE 漏洞 CVE-2025-55182

攻击者传递两个 chunk。chunk 0 作为攻击载体,chunk 1 作为正常 chunk,然后:

1. 利用自定义 then 将 chunk.prototype.then 挂载到 chunk 0,使得 chunk 0 变成 thenable,成为可被执行的 Promise
2. chunk 1 中,通过 $@0,将 chunk 0 作为 decodeReplyFromBusboy 的返回值,被 await 执行(thenable 对象都会被作为 Promise 而被 await 执行)
3. chunk0 中,通过自定义 react 状态机 status,触发 initializeModelChunk 中对 _response 的读取
4. 在 chunk 0 中,$B 会让 react 调用 response._formData.get()。但是 chunk 0 自定义了 _response 中的 _formData 和 _get,导致读取 _response body 的操作变成了一次代码执行

在我看来严重隐患似乎存在于两个地方:

1. 允许用户操作 prototype 的 function constructor,可以通过限制仅允许访问 ownProperty 来抑制
2. $@0 直接将 chunk 返回,而且 react 会将这个 chunk 视为一个可信的内部对象,这个对象通过 status 来控制状态,_response、_get 来控制数据。也就是说,外部的不可信输入直接控制了状态和数据。我觉得这个设计的问题可比 prototype 的访问越权严重多了。 Notion—The AI workspace that works for you.
https://www.notion.so/laisky/Cloudflare-outage-on-November-18-2025-2bcba4011a8681e79964ff8933d3c5b2

CloudFlare 对于 2025-11-18 的故障报告。边缘服务设定了严格的内存限制,其中bot modules 限制了能够处理的规则行数。当接收到超过限制的规则文件后导致 panic。而新的 FL2 系统在 bot modules panic 时,没能仅降级 bot 服务,而是全链路 panic,导致全站 5xx。旧版的 FL 系统就很好的仅降级了 bot score 服务,没有对用户业务造成中断。

我个人认为的经验教训就是:

1. bot modules panic 不是问题,有助于尽早暴露错误,但是必须被隔离。
2. FL2 在 bot modules panic 后,应该进行告警和服务降级,而不是整体 panic(Blast Radius)
3. chaos engineering 应该对各种交互都进行测试,比如文件过大、格式错误等等。任何关键服务都不应该信任外部输入,即使这个外部输入来自友方。 Cloudflare outage on November 18, 2025 | Notion
https://laisky.notion.site/Time-Zone-Handling-for-Software-Engineers-A-Comprehensive-Technical-Handbook-2b3ba4011a8680f2b895f51f19b62dad?source=copy_link

让 DeepResearch 帮忙总结了一篇关于时区的报告。最近都不怎么喜欢搜索文章了,想到什么问题就扔给 DeepResearch 让它给我写一篇报告。

因为中国只有一个时区,很多开发人员都会忽略时区问题,我加入很多团队都帮忙处理过时区相关的问题(另一个经常被忽略的是编码问题)。

首先,在用户看不见的后端使用 UTC 时间是一个很好的习惯,但是 UTC 并不是银弹,并不能取代时区。

时区并不仅仅只是相对于 UTC 的一个固定偏移量,而是代表某一地区时间变化的历史和规则。比如某地可能在某一个时刻,决定让时钟拨快或拨慢一小时,这些规则的处理都必须依赖准确的当地时区数据,而不是 UTC 能够解决的。同理,不同的时区也不能随意的互相替换,即使在当前时刻它们的 UTC 偏移量相同。

比如关于冬令时/夏令时的调整,就会导致当地的某一时刻在两个不同时区出现两次,而另一个时刻则根本不存在。

关于时间的存储,UTC 仅能满足对于时刻的存储需求。只要涉及到当地事件、时间的相对计算、日程安排(牵涉星期、月份日期、节假日)等,都必须结合使用当地时区信息进行计算。而且由于用户可能会进行跨时区迁移,最好能够让用户自行选择自己的时区信息(比如 Google Calendar 的做法)。

重点:

* 如果你只需要时刻信息(Instant),使用 UTC 存储和传输是一个好习惯。
* 但是如果你需要任何基于当地时间的计算,必须携带时区信息。

BTW,时区的英文缩写存在重名,在沟通中不要使用简写。比如 CST 既可以是 China Standard Time 也可以是 Central Standard Time。 我以前和美国的团队协作时就遇到过歧义。 Notion—The AI workspace that works for you.
《Optimize generative AI applications with pgvector indexing: A deep dive into IVFFlat and HNSW techniques》,由 aws 撰写的一片关于 pgvector 索引的文章。

在 LLM RAG 领域,为了处理较长的输入,通常会将文本拆分成较小的 chunks,然后在一些预处理后,将这些 chunks 通过 embeddings 模型生成 vector,存储于向量数据库中。当用户发起查询时,系统会将查询文本同样通过 embeddings 模型生成 vector,然后在向量数据库中进行相似度搜索,找到最相关的 chunks 作为上下文补充。

postgres 搭配 pgvector 插件,是一种常见的向量数据库实现方式。在向量数据库中进行查询,其实就是寻找和目标向量“最相似”的一组向量,“相似”的度量手段有三种:

* L2 距离(Euclidean Distance):计算两个向量之间的欧氏距离。
* Cosine 相似度(Cosine Similarity):计算两个向量之间的夹角余弦值。
* 内积(Inner Product):计算两个向量的点积。可以衡量向量的相似性。

默认情况下,也就是不建立索引时,pgvector 会进行遍历搜索。为了提高搜索性能,提供了两种索引索引:

* IVFFlat 索引(Inverted File with Flat quantization):IVFFlat 是一种基于有监督聚类的近似最近邻搜索算法。它通过将向量空间划分为多个 regions。搜索时,首先仅需要搜索各个 regions 的中心点,找出相关 region 后,再搜索 region 内的向量。
* HNSW 索引(Hierarchical Navigable Small World graphs):HNSW 是一种基于图结构的近似最近邻搜索算法。可以理解为 skiplist,先从最上层(节点最少的层)开始搜索,找到最近点后,作为下一层的起始点继续搜索,逐层往下,直到最底层。

这两种索引都可以显著减少搜索时需要比较的向量数量,从而提升查询速度。而且,为了避免局部最优解,可以设定以多个起始点的方式进行搜索。

文中对 58.6 K 个,总大小为 364 MB 的向量集进行了测试(pgvector 0.6):

* 不使用索引,搜索耗时 650 ms
* 使用 IVFFlat 索引,建立索引 15.5 s,搜索耗时 2.4 ms
* 使用 HNSW 索引,建立索引 30 s,搜索耗时 1.58 ms

可以看出,使用索引对搜索性能提升是很大的。

👆 prev
https://tee.fail/ wiretap 的团队继续发力,TEE 加密芯片对内存加密使用了确定性算法,同样的明文会生成同样的密文,导致可以通过内存分析破译私钥。继上次破解 SGX 老款芯片后,这次把最新款的 TDX 和 SEV-SNP 也攻破了,可以说 TEE 全军覆灭。

AMD 和 Intel 都表示不会修复,内存监听和改写不属于 TEE 的防御范畴。

看来,TEE 确实只能用来防内鬼,并不能构成一个可以放心地托管给别人的飞地。

* prev
继续学习 Context Engineering 相关的文章,主要看了这两篇:

- 来自 Augment 的 《How we made code search 40% faster for 100M+ line codebases using quantized vector search》
- 来自 Anthropic 的 《Contextual Retrieval in AI Systems》

📒 关于 query 的性能:

1. 利用 ANN 大幅减少 embeddings vectors 数量,提高检索速度。
我理解类似于对向量进行聚类,然后只对聚类中心进行搜索,最后再在聚类内进行精确搜索。
但是不确定 Augment 是自己手写了一个 ANN 的聚合层,还是直接使用了类似 pg_vector 的 IVF 等功能。
2. 对 ANN 方案的优化,对 embeddings index 做 SNAPSHOT。只有搜索的 chunk 在 SNAPSHOT 中时才触发 ANN 加速,否则走传统的线性扫描。
这样就可以适应无时不刻都在动态更新的代码库。

📒 关于 query 的准确率和召回率:

1. embeddings vectors 擅长 semantic search,但对精确匹配不友好。结合 BM25 来提高精确匹配的能力。
2. 在 embeddings 以前,先为 chunk 添加上下文信息
有一个优化技巧是,先利用 prompt cache 缓存全文,然后再使用这个 cache 为每一个 chunk 生成上下文。
3. 玄学参数,每次 RAG 提供 20 个 context chunks 的效果最好。Anthropic 的做法是,用混合搜索检索出 400 个 chunks,然后使用 cohere rerank 选出 top20。
4. rerank 会带来额外的延迟,所以 chunks 数量和延迟是一个 trade-off。

👇 next
读了一本很有趣的书,《漫步华尔街》。本书的核心思想可以概括为:市场是有效的,历史上的交易策略往往只是偶然成功,长期来看最有效的投资策略就是“买入并持有”,而最有价值的买入对象就是广泛分散的指数基金。(本书的出版时间早于指数基金的兴起)

本书的内容,就是以学者的审慎态度,对各种流行的投资策略进行了分析,破除那些以讹传讹的投资神话,以及各种泡沫和金融造假的案例,来论证上述观点。其中一个很有趣的例子是,作者还提到了广为流传的“市场与女士的裙摆高度有关”的分析方法,证明历史上牛市与否实际上与裙摆高度并无关系。 #book

- 摘抄
Back to Top Telegram Channel