惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog RSS Feed
K
Kaspersky official blog
Forbes - Security
Forbes - Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Proofpoint News Feed
G
GRAHAM CLULEY
V
Vulnerabilities – Threatpost
Security Latest
Security Latest
Scott Helme
Scott Helme
S
Securelist
美团技术团队
T
Threat Research - Cisco Blogs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
SegmentFault 最新的问题
W
WeLiveSecurity
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Apple Machine Learning Research
Apple Machine Learning Research
The Cloudflare Blog
AI
AI
L
Lohrmann on Cybersecurity
S
Security Affairs
Cloudbric
Cloudbric
SecWiki News
SecWiki News
爱范儿
爱范儿
雷峰网
雷峰网
Engineering at Meta
Engineering at Meta
C
Cyber Attacks, Cyber Crime and Cyber Security
大猫的无限游戏
大猫的无限游戏
N
News and Events Feed by Topic
I
InfoQ
S
Secure Thoughts
AWS News Blog
AWS News Blog
A
About on SuperTechFans
Schneier on Security
Schneier on Security
酷 壳 – CoolShell
酷 壳 – CoolShell
The Last Watchdog
The Last Watchdog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Check Point Blog
P
Palo Alto Networks Blog
博客园 - 【当耐特】
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Google DeepMind News
Google DeepMind News
Latest news
Latest news
I
Intezer
博客园_首页
C
CXSECURITY Database RSS Feed - CXSecurity.com
V
V2EX
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
D
Docker

暗无天日

读:AI Agent 安全日志——从可见性与隐私的两难说起 - 暗无天日 AI写作的语言指纹——如何让文字不那么像机器 - 暗无天日 读:50 条 Claude Code 技巧——一个工程经理的六个月使用心得 读:AI 辅助开发为什么让 E2E 测试更有价值 - 暗无天日 读:在Emacs中使用Claude Code(Spacemacs适配版) - 暗无天日 Claude Code 背后的工程哲学——读 Agent Harness Engineering 读:Agent Harness Engineering——AI 智能体不只是模型,还有套件 - 暗无天日 browser-harness:让 AI 直接接管你的浏览器 - 暗无天日 读:Security-First CI/CD —— DevSecOps 自动化实践指南 TIL: 数字小键盘的小数点陷阱与行内算术求值 - 暗无天日 读:Immutability 不是万能药,它是一种权衡 - 暗无天日 Conducty:给 Claude Code 加上项目记忆和并行执行能力 - 暗无天日 读 — GitHub Trending 里的 Claude Code 技能包 读 — Prompt Caching 省钱指南 TIL: Emacs 中那些跟鼠标配合的冷门快捷键 - 暗无天日 读:Anvil——把 Emacs 变成 AI 的工具服务器 读:Emacs 代码折叠终极指南 - 暗无天日 读:Clojure 搭车客指南 - 暗无天日 git推送失败后恢复仓库损坏的完整记录 - 暗无天日 多智能体系统的两个有效模式——以及对 Claude Code 用户的启示 - 暗无天日 用 Org Babel 写 Literate 博文:扩展执行 + 定制导出 proced:Emacs 内置的进程查看器 - 暗无天日 从 proced 定制中学到的 Elisp 模式 读:让 Emacs proced 在 macOS 上显示 CPU 和内存 异步编程的函数着色税 - 暗无天日 链式调用的代价:JavaScript 和 Clojure 的共同教训 - 暗无天日 hyperfine:命令行基准测试工具 - 暗无天日 管道中的变量去哪了?——子 shell 作用域陷阱 - 暗无天日 开源包装器的信任陷阱:四个危险信号 - 暗无天日 程序员愿意为 AI 写文档,却不愿为同事写 - 暗无天日 mktemp: Shell 脚本中临时文件的安全陷阱与最佳实践 - 暗无天日 WSL9x —— 在 Windows 9x 里跑 Linux 内核 6.19 用 ox.el 做你想做的事 —— org-export 高级编程指南 读:Hot-wiring the Lisp Machine —— 用纯 Elisp 构建零依赖的 Org 静态站点生成器 Elisp 性能优化的六个实战教训 - 暗无天日 fcitx5 下 Emacs 无法切换输入法的排查 - 暗无天日 ERT 测试交互命令的三种方式 - 暗无天日 SEM Assistant: 当 Elisp 守护进程遇上 LLM 用 dmsg 给 Elisp 加上结构化调试日志 用 org-habit 追踪非每日习惯 - 暗无天日 Clojure X-Men:当编程语言特性变成超能力 - 暗无天日 TIL: 用 diff-hl 在 fringe 中显示 git 变更 读:llm-test —— 用 LLM agent 驱动 Emacs 测试 TIL: AI 时代的橡皮鸭调试 - 暗无天日 fcitx 启动后键盘输入卡顿的排查 - 暗无天日 TIL: 早期网页的图片热区导航 - 暗无天日 读 Seeing the Whole System 用 Emacs 自动生成每周链接推荐 - 暗无天日 读:ASCII control characters in my terminal 读 What to learn - 暗无天日 Lisp 的括号之痛——一个愚人节玩笑揭开的老伤疤 - 暗无天日 一本书该"线性读"还是"并行读" - 暗无天日 读 How to Monetize a Blog:一篇伪装成变现指南的讽刺文 Python Mock 第三方依赖的四种策略 - 暗无天日 Emacs Lisp 热重载实用指南 - 暗无天日 Prot 的 Emacs 配置哲学 - 暗无天日 TIL: 从直播对谈中学到的三个 Emacs 技巧 - 暗无天日 TIL: 自动使用项目虚拟环境的 Python - 暗无天日 TIL: 让 Help buffer 自动获得焦点 一条命令让本地开发用上 HTTPS —— slim 工具介绍 用 fsck 检查和修复 Linux 文件系统 排查Linux进程"卡死"实战:从strace到gdb全流程 - 暗无天日 PostgreSQL 索引:从基础到你可能不知道的高级用法 - 暗无天日 用 .pdbrc 自定义 Python 调试器 ANSI 转义码的标准化现状 - 暗无天日 终端程序的潜规则 - 暗无天日 PARA Org-mode 测试配置 - 暗无天日 AI越强越辣鸡?控制论说这是必然的 - 暗无天日 AI 越强越需要你盯着——反馈循环实操指南 - 暗无天日 你的AI代理正在偷你的密钥——四种你没想到的泄露通道 - 暗无天日 LLM 在 DevOps 中的三种角色 - 暗无天日 写作风格的反建议 - 暗无天日 反驳本质复杂性——Dan Luu 论为什么《没有银弹》错了 - 暗无天日 文件充满了危险——Dan Luu 谈文件系统的可靠性陷阱 - 暗无天日 AI 时代的 PARA 方法:用 Org-mode 和 AI 打造个人知识管理系统 Linux 数据去重学习笔记 - 暗无天日 创建跨平台 ZIP 文件的隐藏陷阱:Extra Field - 暗无天日 X11 Forwarding 排障指南 - 暗无天日 IP欺骗端口扫描:当别人冒充你去扫描别人 - 暗无天日 Linux 输入栈全景解析:从硬件按键到屏幕响应 - 暗无天日 Unix 系统中那些被埋没的配置开关——以 FontConfig 为例 - 暗无天日 在Linux上限制儿童使用电脑 - 暗无天日 GIF不仅仅是一种图片格式——用GIF流做些奇怪的事 - 暗无天日 Leiningen 学习笔记:Clojure 项目构建与管理从入门到实战配置 - 暗无天日 Google SRE Book 读书笔记 - 暗无天日 yes 管道 head 发生了什么 - 暗无天日 为什么 nohup 在 crontab 中不起作用 Bash中的Indirection与Nameref - 暗无天日 Linux PAM 简介 - 暗无天日 从Linux ISO文件启动计算机 - 暗无天日 用 Bash 打造一个Screen Locker 用GitHub Actions自动构建EGO博客 - 暗无天日 blocking I/O 的作用 - 暗无天日 mobileog 手机端同步提示Error:2 No such file 的解决方法 回收 WSL2 VHDX 文件占用空间 使用 org-mode columnview 生成任务列表 - 暗无天日 Emacs 作为 MPD 客户端 - 暗无天日 移动文件路径却不破坏org file link的方法 - 暗无天日 如何合理的导出help link 成HTML - 暗无天日 笑话理解之Biology - 暗无天日
读:从API调用到Agent循环——构建 Agent 的七个阶段 - 暗无天日
lujun9972,Claude Code · 2026-05-25 · via 暗无天日

目录

  • Stage 1:最简调用
  • Stage 2:让输出可解析
    • 评注:** 系统提示词就是契约,跟传统软件开发里的接口定义是一个道理。你不是在跟模型聊天,你是在给它写规格说明书。传统接口靠编译器检查,LLM 的"接口"靠提示词约束 + 输出验证来保证:提示词引导模型输出正确格式,Pydantic 在模型不配合时兜底报错,两道防线少了哪一道都会出问题。
  • Stage 3:让它记住对话
    • 评注:** 理解 LLM 无状态,是搞清楚 LLM 应用设计的关键一步。很多人刚意识到这件事时会觉得"这怎么用",但换个角度想:正因为无状态,控制权全在你手里。对话历史由你管理,想截断就截断,想摘要就摘要,想让模型"忘掉"前面说的什么,直接不发给它就行。
  • Stage 4:工具调用
    • 评注:** 工具调用的本质是让 LLM 当"决策者",你的代码当"执行者"。模型决定调什么工具、传什么参数,你的代码负责实际执行并把结果喂回去。这个分工把 LLM 的能力(理解意图、生成参数)和程序的可靠性(确定性执行、错误处理)结合了起来。循环本身是通用的,从后面后面 Stage 7 可以看出,不管工具是做加法还是查数据库,循环逻辑一模一样。
  • Stage 5:可替换、可测试
    • 评注:** 这些模式都不是 AI 领域的新发明。Protocol 就是依赖倒置(DIP),Repository 就是数据访问抽象,Service 层就是业务编排。有后端开发经验的读者应该觉得很眼熟。原文的好处在于把这些经典模式落到了 LLM 应用的具体场景里。把"调 API"和"存数据"从业务逻辑中拔出来之后,你就可以给核心逻辑写单元测试了,而不用每次都真的去调一次 LLM。
  • Stage 6:人在回路中
    • 评注:** 置信度阈值是生产级 AI 应用中容易被忽视的设计决策。阈值设高了,模型几乎都要人工确认,自动化失去意义;设低了,错误静默溜过,用户失去信任。原文用的 0.8 只是个起点,实际项目中这个值需要根据业务场景的错误容忍度来调整。核心原则:让机器在它拿得准的时候自主行动,在它犹豫的时候及时交出控制权。
  • Stage 7:通用化循环
    • 评注:** 这一阶段揭示了一个重要的认知:Agent 框架的核心逻辑并不复杂。本质上就是一个 while 循环 + 工具注册表 + 消息历史管理。框架真正值钱的是周边的工程化细节:错误重试、并发控制、日志追踪、安全沙箱。理解了这一点之后,选择用框架还是自己写循环,就变成了一个工程决策:你的场景复杂到需要框架的周边能力吗?如果不需要,自己写一个循环可能比引入框架更合适。
  • 总结:这条学习路径教会了什么

原文:Learn Agentic AI in Python: A 10-Step Journey 把从"调一次 API"到"写一个完整 Agent 循环"拆成十个递进练习,再归纳成七个概念阶段。这篇文章是它的配套讲解,逐层解读每个阶段的设计决策,回答一个核心问题:从调一次 API 到写一个完整的 Agent,中间到底要补哪些东西?

Stage 1:最简调用

每个 LLM 应用的起点都一样:创建客户端,调用 API,读取返回文本。以 Anthropic Python SDK 为例:

import anthropic

client = anthropic.Anthropic()
msg = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=256,
    messages=[{"role": "user", "content": "Say hi"}],
)
print(msg.content[0].text)

注意 content[0].text 而不是 .textcontent 是一个列表,每个元素是一个"块"(block),比如文本块、工具调用块等。现在你拿到的是 [{"type": "text", "text": "Hello!"}] ,后面引入工具调用时就会变成 [{"type": "text", ...}, {"type": "tool_use", ...}] ,但外层还是同一个列表。早点建立这个心智模型,后面加功能才不会措手不及。

Stage 2:让输出可解析

Stage 1 拿到了模型的文本回复,但输出的文本没有定式,模型今天可能输出"餐饮",明天可能输出"类别:餐饮(食品)",你没法直接用它做后续处理。解决方案是通过提示词明确输出格式,同时用 Pydantic 模型在收到结果后验证 LLM 返回是否符合格式。

from pydantic import BaseModel

class ExpenseResult(BaseModel):
    category: str
    confidence: float

result = ExpenseResult.model_validate_json(msg.content[0].text)

系统提示词要像 API 契约一样严格:说清楚"只输出 JSON",给出具体的字段结构,并禁止任何多余内容。"禁止多余内容"这几个字很重要,没有这几个字LLM总喜欢在 JSON 后面加一句友好的总结。

评注:** 系统提示词就是契约,跟传统软件开发里的接口定义是一个道理。你不是在跟模型聊天,你是在给它写规格说明书。传统接口靠编译器检查,LLM 的"接口"靠提示词约束 + 输出验证来保证:提示词引导模型输出正确格式,Pydantic 在模型不配合时兜底报错,两道防线少了哪一道都会出问题。

Stage 3:让它记住对话

Stage 1 和 2 解决了单次调用的问题——你能拿到结构化的回复了。但实际应用中用户会连续提问,模型需要理解上下文。可问题在于:LLM 本身没有状态、没有记忆,当前调用之外的上下文它一概不知。我们感知到的"连续对话",其实是你每次调用时把完整的消息历史重新发给它。

history = []

def ask(user_msg):
    history.append({"role": "user", "content": user_msg})
    reply = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=512,
        messages=history,
    ).content[0].text
    history.append({"role": "assistant", "content": reply})
    return reply

操作很简单:调用前追加用户消息,调用后追加助手回复。角色必须交替(user → assistant → user → ...)。数据存在你的请求里,不存在模型里。理解这一点,大部分关于"上下文窗口"和"记忆"的困惑就自然消解了。

评注:** 理解 LLM 无状态,是搞清楚 LLM 应用设计的关键一步。很多人刚意识到这件事时会觉得"这怎么用",但换个角度想:正因为无状态,控制权全在你手里。对话历史由你管理,想截断就截断,想摘要就摘要,想让模型"忘掉"前面说的什么,直接不发给它就行。

Stage 4:工具调用

Stage 1-3 构建了一个能记住上下文的聊天机器人,但它只能聊天,不能做事。工具调用把聊天机器人变成能执行动作的程序。核心循环比很多人想象的更简单:

while True:
    response = client.messages.create(
        ..., tools=TOOLS, messages=messages
    )
    if response.stop_reason == "end_turn":
        return response.content[0].text
    

上面这段伪代码省略了工具调用的处理逻辑,有两个需要注意的细节:

  1. 助手的回复要完整追加 response.content (不是只取文本),因为里面包含模型发出的工具调用块,下一轮循环模型需要看到这些块才能继续
  2. 工具执行结果要包在 user 角色的消息里返回,不是 assistant 。这看起来反直觉,但角色交替的规则要求这样做

评注:** 工具调用的本质是让 LLM 当"决策者",你的代码当"执行者"。模型决定调什么工具、传什么参数,你的代码负责实际执行并把结果喂回去。这个分工把 LLM 的能力(理解意图、生成参数)和程序的可靠性(确定性执行、错误处理)结合了起来。循环本身是通用的,从后面后面 Stage 7 可以看出,不管工具是做加法还是查数据库,循环逻辑一模一样。

Stage 5:可替换、可测试

到这一步聊天机器人能跑了,但代码通常也缠成一团,业务逻辑直接依赖 anthropicsqlite3 等外部库,没法单独测试。常见的解耦模式有三个:

  1. Protocol 模式 给 LLM 提供者定义接口,测试时可以传入一个带 .calls 列表的 MockProvider 替代真实 API
  2. Repository 模式 给持久层定义接口,内存字典和数据库后端实现同一个接口
  3. Service 层 通过构造函数接受上述两个依赖,负责编排:调 LLM → 解析结果 → 存储 → 返回

三个模式组合起来就是一套可测试的 Agent 架构,每一层职责单一,可以独立替换和测试。

评注:** 这些模式都不是 AI 领域的新发明。Protocol 就是依赖倒置(DIP),Repository 就是数据访问抽象,Service 层就是业务编排。有后端开发经验的读者应该觉得很眼熟。原文的好处在于把这些经典模式落到了 LLM 应用的具体场景里。把"调 API"和"存数据"从业务逻辑中拔出来之后,你就可以给核心逻辑写单元测试了,而不用每次都真的去调一次 LLM。

Stage 6:人在回路中

Stage 2 用 Pydantic 模型从 LLM 输出中解析出了 confidence 字段,但一直没说这个分数拿来干什么。拿到置信度之后,可以用它来决定是否需要人工介入:

def process(result, threshold=0.8):
    if result.confidence >= threshold:
        return result.category
    answer = input(f"Accept '{result.category}'? (Enter to confirm): ").strip()
    return answer or result.category

设计要点:让"接受"路径的操作成本最低(直接回车就行),只有用户不认同模型的分类时才需要手动输入修正。原文认为,有没有这一步,是"可信助手"和"偷偷把事情搞错的 AI"的分界线,也是"演示项目"和"生产级工作流"的差距。

评注:** 置信度阈值是生产级 AI 应用中容易被忽视的设计决策。阈值设高了,模型几乎都要人工确认,自动化失去意义;设低了,错误静默溜过,用户失去信任。原文用的 0.8 只是个起点,实际项目中这个值需要根据业务场景的错误容忍度来调整。核心原则:让机器在它拿得准的时候自主行动,在它犹豫的时候及时交出控制权。

Stage 7:通用化循环

前面 Stage 4 的工具循环里,工具名和函数的对应关系是写死的。这最后一步只改了一个地方,即把硬编码的函数调用替换成一个字典查找:

TOOL_FUNCTIONS = {
    "add": lambda a, b: a + b,
    "multiply": lambda a, b: a * b,

}

content = str(TOOL_FUNCTIONS[block.name](**block.input))

新增一个工具只需要加一条 schema 定义 + 一个字典条目。把 add / multiply 换成 search_webquery_dbsend_email ,循环逻辑完全一样。原文指出,LangChain、OpenAI Assistants 等框架底层也是这个模式。

评注:** 这一阶段揭示了一个重要的认知:Agent 框架的核心逻辑并不复杂。本质上就是一个 while 循环 + 工具注册表 + 消息历史管理。框架真正值钱的是周边的工程化细节:错误重试、并发控制、日志追踪、安全沙箱。理解了这一点之后,选择用框架还是自己写循环,就变成了一个工程决策:你的场景复杂到需要框架的周边能力吗?如果不需要,自己写一个循环可能比引入框架更合适。

总结:这条学习路径教会了什么

原文的结论很明确:框架在你能够自己写出底层之后才有意义。跳过底层直接上框架,一旦框架的行为跟你预期不一致,你连问题出在哪都查不出来。七个阶段都很小,单个看没什么特别的,串起来才构成完整的学习路径。做完之后,"Agentic AI" 的底牌就清楚了:一个循环、一套 schema、加上几个常见的设计模式。