Hermes GitHub PR 审查 —— 自动化代码评审

第28篇:GitHub PR 审查 ------ 自动化代码评审

Hermes 可以通过 Webhook 自动监听 GitHub/GitLab 的 Pull Request,运行 AI 审查并发布评论,实现持续代码质量把关。

Step 1: 在 GitHub 创建 Webhook

  1. 仓库 → SettingsWebhooksAdd webhook
  2. Payload URL : http://your-server:8644/webhooks/github-pr
  3. Content type : application/json
  4. Secret: 与 route 配置匹配
  5. 选择 Let me select individual events → 勾选 Pull requests

Step 2: 添加路由配置

yaml 复制代码
# ~/.hermes/config.yaml
platforms:
  webhook:
    enabled: true
    extra:
      port: 8644
      secret: "global-fallback-secret"
      routes:
        github-pr:
          events: ["pull_request"]
          secret: "github-webhook-secret"
          prompt: |
            Review this pull request:
            Repository: {repository.full_name}
            PR #{number}: {pull_request.title}
            Author: {pull_request.user.login}
            URL: {pull_request.html_url}
            Diff URL: {pull_request.diff_url}
            Action: {action}
          skills: ["github-code-review"]
          deliver: "github_comment"
          deliver_extra:
            repo: "{repository.full_name}"
            pr_number: "{number}"

Step 3: 认证 gh CLI

bash 复制代码
gh auth login

Step 4: 测试

提交一个 PR,webhook 触发后 Hermes 会在 PR 上发布审查评论。

Delivery 选项

类型 说明
log 默认,日志输出(测试用)
github_comment 通过 gh CLI 发布 PR/issue 评论
telegram / discord / slack 各消息平台投递
email 邮件投递

Direct Delivery Mode(零 LLM 开销)

yaml 复制代码
routes:
  antenna-matches:
    secret: "antenna-webhook-secret"
    deliver: "telegram"
    deliver_only: true              # 零 LLM 开销
    prompt: "New match: {match.user_name} matched with you!"
    deliver_extra:
      chat_id: "{match.telegram_chat_id}"

GitLab MR 支持

yaml 复制代码
routes:
  gitlab-mr:
    events: ["merge_request"]
    secret: "your-gitlab-secret-token"
    prompt: |
      Review this merge request:
      Project: {project.path_with_namespace}
      MR !{object_attributes.iid}: {object_attributes.title}
      URL: {object_attributes.url}
    deliver: "log"

Payload 过滤器

支持操作符:existsequals/not_equalscontainsinregexall/any/not 组合

Webhook 安全

来源 验证方式
GitHub X-Hub-Signature-256 HMAC-SHA256
GitLab X-Gitlab-Token 明文密钥匹配
Generic V2 X-Webhook-Signature-V2 + 时间戳防重放

限速: 默认 30 请求/分钟,Body 限制: 默认 1 MB

动态订阅

bash 复制代码
hermes webhook subscribe github-issues \
  --events "issues" \
  --prompt "New issue #{issue.number}: {issue.title}" \
  --deliver telegram \
  --description "Triage new GitHub issues"

hermes webhook list
hermes webhook remove github-issues
hermes webhook test github-issues

Q&A

Q1: Webhook 路由中的 {variable} 语法支持嵌套字段吗? A1: 支持。{pull_request.user.login} 使用点号访问嵌套 JSON 字段。缺失的键保留字面量。{__raw__} 可转储整个 payload(截断 4000 字符)。

Q2: deliver_only: true 和普通模式有什么区别? A2: deliver_only: true 是直接投递模式,不经过 LLM 处理,零 token 开销。适合简单通知场景(如新匹配提醒)。普通模式会由 Agent 完整审查后再投递。

Q3: 如何防止 Webhook 被伪造攻击? A3: Hermes 验证 HMAC-SHA256 签名(GitHub/Generic V2)或明文密钥(GitLab)。Generic V2 还加入时间戳防重放(±300 秒)。确保配置的 secret 足够长且保密。

Metics Media 的 YouTube 自动选题管线一句话搞定研究 + 技能沉淀 + 定时自动化

第 28 篇 · Content Creation

Metics Media 的 YouTube 自动选题管线 一句话搞定研究 + 技能沉淀 + 定时自动化

每周手动搜 AI 工具、手动选题、手动排期,是内容创作者最消耗时间却又最无法跳过的苦力活。Metics Media 用 Hermes 做了一件不同的事:一句话指令,Agent 同时完成热门 AI 工具调研、将研究方法沉淀为可复用技能、并设置每周一上午 9 点自动运行的定时任务。本篇完整拆解这条「自进化」管线------从 Cron 调度引擎到 Skills 技能系统,从 Memory 跨会话记忆到 web_search 研究工作流。

作者 Metics Media 来源 YouTube 分类 Content Creation 验证级别 部分验证

PART 1

案例背景 + 溯源 + 整体架构

开篇心智钩子

如果你是一个 AI 领域的 YouTube 内容创作者,以下场景一定不陌生:每周一早上,你打开浏览器,在 Product Hunt、Hacker News、X/Twitter、GitHub Trending 之间来回切换,花两个小时搜集最近哪些 AI 工具火了;然后你把候选列表拉进 Notion,逐个评估"这个适不适合做教程";最后你还得手动在日历上排好发布计划,提醒自己下周二录视频、周四剪辑、周五发布。整个过程纯粹是体力劳动,没有任何创意产出。

更荒谬的是:你每周都在重复这个流程,但从未把"如何研究 AI 工具"这件事变成一个可复用的方法论。每次都是从零开始搜索,每次的判断标准都不一样,上周发现的工具这周就忘了。你的研究经验没有沉淀,你的选题流程没有自动化,你的时间永远消耗在"找选题"而不是"做内容"上。

Metics Media 在 YouTube 上分享了一个截然不同的做法:他们用 Hermes Agent,一句话指令同时完成了三件事------调研当前热门 AI 工具并筛选出最适合做教程的前三个、让 Agent 自动把研究方法沉淀为名为 youtube-video-research 的技能文件、然后用这个技能设置每周一上午 9 点自动运行的定时任务。从第二周开始,每周一早上打开 Telegram,选题报告已经躺在消息列表里了。

这正是 Hermes 区别于普通聊天机器人的核心能力:自进化。它不只执行你的指令,还会把执行过程中的方法论提炼成可复用的技能,然后把这些技能挂载到定时任务上,形成自动循环。一句话进去,一个自动化管线出来。

为什么这个案例值得拆解

它同时展示了 Hermes 的三个核心子系统如何协同工作:(1) Cron 定时调度引擎------支持自然语言创建任务、独立 session 执行、多平台投递;(2) Skills 技能系统------三层渐进式加载、自动创建、自我改进;(3) Memory 记忆系统------跨会话 FTS5 全文搜索召回。三个子系统在一条用户指令的驱动下形成闭环:研究 -> 沉淀 -> 自动化 -> 再研究。

案例基础信息

溯源信息

作者 Metics Media(YouTube 频道)

来源渠道 YouTube 视频

视频链接 youtube.com/watch?v=CwP...

官方收录 hermes-agent.nousresearch.com/docs/user-s...(Content Creation 分类)

涉及子系统 Cron 调度 + Skills 技能系统 + Memory 记忆 + web_search/web_extract

验证级别 部分验证 --- 有 YouTube 视频来源及 Hermes 官方用户故事收录,但无公开 GitHub 仓库/Gist 可供代码级验证

可验证性声明

本案例有明确的 YouTube 视频来源和 Hermes 官方用户故事页面收录,但用户未公开分享对应的 GitHub 仓库或 Gist。因此,验证级别标注为部分验证。本文的 Cron 命令、Skills 格式、Memory 路径等技术细节均来自 Hermes 官方文档的逆向重建,所有命令行语法和文件路径结构均有官方文档支撑。涉及具体业务逻辑的代码段标注为"重建实现",代表基于 Hermes 框架能力的合理推断。

原始用户指令

"Research the top trending AI tools right now and come back with the top three that would make for an interesting tutorial video. Create a new skill based on your approach and call it YouTube-video-research. Can you set up a weekly job that runs every Monday at 9:00 AM using that skill?"

--- Metics Media · YouTube 视频

指令结构拆解

这一条指令包含了三个明确操作,用句号分隔:

操作 1(研究)"Research the top trending AI tools right now and come back with the top three that would make for an interesting tutorial video." ------调研当前热门 AI 工具,筛选出最适合做教程视频的前 3 个。

操作 2(技能创建)"Create a new skill based on your approach and call it YouTube-video-research." ------将研究方法沉淀为名为 youtube-video-research 的技能。

操作 3(定时调度)"Can you set up a weekly job that runs every Monday at 9:00 AM using that skill?"------用该技能设置每周一上午 9 点自动运行的定时任务。

需求梳理:一句话触发三个子系统

表面上看,用户只是说了一句话。但 Hermes 要完成这条指令,需要协调三个核心子系统。以下是逐层拆解:

1 研究任务(web_search + web_extract)

Agent 调用 web_search 搜索当前热门 AI 工具,用 web_extract 提取每个工具的落地页详情,评估"视频教程潜力"(新颖度、复杂度、受众兴趣),排名输出前 3 名候选及理由。

2 技能创建(Skills 系统)

Agent 将整个研究流程总结为结构化 Markdown 技能文件,保存到 ~/.hermes/skills/youtube-video-research/SKILL.md。后续可被三层渐进式加载机制复用。

3 定时调度(Cron 引擎)

Agent 创建 Cron 任务,schedule 为 0 9 * * 1(每周一 9 点),注入 --skill youtube-video-research,设置投递目标为 --deliver origin(投递到创建任务的对话)。

4 记忆支撑(Memory 系统)

Cron 执行时创建全新 session(无历史记忆),但通过 MEMORY.mdUSER.md 跨会话召回环境事实和用户偏好,确保每次执行都"知道"用户是 YouTube 创作者、偏好什么类型工具。

Hermes 五层系统架构

要理解这条指令为什么能一句话搞定三件事,需要先理解 Hermes 的整体架构。以下是五层架构的文字版图解:

Layer 1 入口

CLI | Gateway 守护进程 | ACP | Batch Runner | API Server | Python Library

Layer 2 核心

AIAgent (run_agent.py) --- Prompt Builder / Provider Resolution / Tool Dispatch / Compression & Caching / 3 API Modes / Tool Registry (70+ tools)

Layer 3 存储

Session Storage (SQLite + FTS5) | Tool Backends (Terminal / Browser / Web / MCP / File / Vision)

Layer 4 子系统

Cron 调度引擎 (jobs.json + executions.db + .tick.lock) | Skills 系统 (SKILL.md, 三层加载) | Memory 系统 (MEMORY.md + USER.md, FTS5 + Honcho) | Web Search (web_search + web_extract + browser)

Layer 5 投递

origin (原对话) | local (本地文件) | telegram | discord | all (全平台扇出)

用户的一句话指令从 Layer 1 的 CLI 或 Gateway 进入,到达 Layer 2 的 AIAgent 核心引擎。AIAgent 解析指令后,分派到 Layer 4 的四个子系统:先用 web_searchweb_extract 完成研究,再用 Skills 系统创建技能文件,最后用 Cron 引擎创建定时任务。Layer 3 的 SQLite + FTS5 为 Memory 系统提供跨会话全文搜索能力。Layer 5 的投递层负责把 Cron 执行结果送到目标平台。

关键架构特性

Tool Registry(70+ 工具) :Hermes 内置 70 多个工具,web_search、web_extract、browser、code_execution、mcp_tool 等均通过统一 Tool Dispatch 调度。

3 API Modes :支持本地 API、云 API、MCP 三种模式,适配不同部署场景。

Compression & Caching:长对话自动压缩,工具结果缓存,降低 token 消耗。

Cron Job 数据流全景

当 Metics Media 发出"每周一上午 9 点自动运行"的指令后,Cron 引擎内部的数据流如下:

Step 1

调度器 tick :Gateway 守护进程每 60 秒 tick 一次调度器。调度器从 ~/.hermes/cron/jobs.json 加载所有任务,检查 next_run 字段是否到期。

Step 2

文件锁防重复 :调度器获取 ~/.hermes/cron/.tick.lock 文件锁,防止同一时刻多个 tick 并发执行同一任务。

Step 3

创建全新 AIAgent:调度器为到期任务创建一个全新的 AIAgent session------无历史记忆。这意味着 Cron 执行的 Agent 不会继承之前对话的上下文,它是一个"白纸" Agent。

Step 4

注入附加 Skills :调度器将任务配置中 --skill youtube-video-research 指定的技能文件内容注入到新 Agent 的上下文中。Agent 通过三层加载机制读取 SKILL.md

Step 5

运行任务 prompt:Agent 执行任务 prompt------"Research the top trending AI tools..."。Agent 调用 web_search 搜索、web_extract 提取、分析排名,输出前 3 名候选。

Step 6

投递响应 :根据 --deliver origin 配置,将结果投递到创建任务的对话。可选 local/telegram/discord/all。

Step 7

更新状态 :调度器更新 ~/.hermes/cron/executions.db 中的任务状态(claimed → running → completed/failed),并计算下一次 next_run 时间。

重要限制:Cron 会话无递归

Cron 执行的 AIAgent 会话不能递归创建更多 Cron 任务。这是 Hermes 的安全设计,防止调度循环------如果 Cron 任务可以创建 Cron 任务,就可能形成无限循环,导致资源耗尽。因此,Cron 任务的 prompt 应专注于"执行研究",而不是"再创建一个定时任务"。

三阶段执行顺序解析

理解 Hermes 如何处理"一句话三操作"的指令,关键在于理解 Agent 内部的执行规划逻辑。当 Metics Media 发出这条指令时,Agent 并非随机执行三个操作,而是遵循一条有依赖关系的执行链:

**为什么是这个顺序?**因为三个操作之间存在隐式依赖关系。操作 2(技能创建)依赖于操作 1(研究)的执行过程------Agent 需要完成研究,才能把研究方法总结为技能。操作 3(Cron 创建)依赖于操作 2(技能创建)的产物------Cron 任务需要引用 --skill youtube-video-research,如果技能文件还不存在,Cron 任务的注入就会失败。因此,研究先行、技能居中、Cron 收尾是唯一合理的执行顺序。

Agent 的 Prompt Builder 在解析指令时会识别这种依赖关系,自动将三个操作编排为串行序列。这不是用户需要指定的------Agent 自己推断出来的。这就是 Hermes 与传统脚本自动化工具的根本区别:用户描述"做什么",Agent 自己决定"怎么做"和"先做什么"

Cron 生命周期管理命令详解

Hermes 提供了完整的 Cron 生命周期管理命令集,覆盖任务从创建到销毁的全流程。以下是关键命令的深入解读:

hermes cron list :列出所有任务及其调度状态,包括 next_run 时间。适合在 VPS 上快速巡检所有定时任务是否正常。

hermes cron pause / resume :暂停和恢复是"软操作"------任务配置保留在 jobs.json 中,但调度器跳过它。适合在维护窗口期临时停止任务。

hermes cron run :立即触发执行,不影响 next_run 的计算。也就是说,手动触发后,下周一 9 点仍会按时执行。适合验证任务配置是否正确。

hermes cron edit :修改任务的 schedule、skill、deliver、name 等参数。修改后自动重新计算 next_run。适合从"origin 投递"切换到"telegram 投递"等场景。

hermes cron remove :永久删除任务,不可恢复。删除前建议先 hermes cron pause 确认无影响。

hermes cron status:查看调度器整体状态,包括 Gateway 是否运行、最近执行记录、失败统计。是排查"Cron 不执行"问题的第一命令。

PART 2

分步落地教程 + 全 Hermes 命令清单

从零搭建:六步完成自动化选题管线

以下是从零开始复刻 Metics Media 管线的完整步骤。每一步都附带可执行的命令和验证方法。

第一步:环境准备

Hermes 需要三个前置条件:Python 运行环境、LLM API Key(用于 Agent 推理)、Firecrawl API Key(用于 web_search 网络搜索)。

shell 复制代码
# 安装 Hermes(pip 全局安装)
pip install hermes-agent
# 验证安装
hermes --version
# 应输出类似: hermes 0.x.x
# 设置 LLM API Key(以 Nous Portal 为例)
# 方式一:通过 Portal 订阅(推荐,含 Firecrawl)
hermes setup --portal
# 按提示输入 Portal API Key,自动配置 LLM + Firecrawl
# 方式二:手动设置环境变量
# export OPENAI_API_KEY=sk-xxx # LLM 推理
# export FIRECRAWL_API_KEY=fc-xxx # 网络搜索

Firecrawl 是 web_search 的前提

web_searchweb_extract 工具依赖 Firecrawl API。如果你选择 Nous Portal 订阅,Firecrawl 已包含在内;如果使用独立 LLM API Key,需要单独申请 Firecrawl API Key 并通过 export FIRECRAWL_API_KEY=your_key 设置。没有 Firecrawl,Agent 无法完成"研究热门 AI 工具"这一步。

第二步:初始化配置------启用 persistent_memory 和 skill_generation

Hermes 的 Memory 和 Skills 子系统默认不一定开启。需要通过 hermes setup 启用两个关键配置项:persistent_memory(跨会话记忆持久化)和 skill_generation(技能自动创建)。

shell 复制代码
# 交互式初始化配置
hermes setup
# 在配置向导中,确保以下选项启用:
# [x] persistent_memory: true # 启用跨会话记忆(MEMORY.md + USER.md)
# [x] skill_generation: true # 启用技能自动创建
# [x] web_search: true # 启用网络搜索(需要 Firecrawl)
# 验证配置
hermes config show
# 应看到 persistent_memory: true 和 skill_generation: true

为什么这两个配置至关重要?persistent_memory 确保 Cron 执行的新 session 能通过 MEMORY.md 召回"用户是 YouTube 创作者、偏好做教程视频"等上下文。skill_generation 确保 Agent 在完成研究任务后,自动将研究流程总结为 SKILL.md 技能文件。没有这两个配置,用户的一句话指令只能完成"研究"这一步,无法"沉淀技能"和"跨会话记忆"。

第三步:发送用户指令触发三合一操作

配置就绪后,直接在 Hermes 对话中发送原始指令。Agent 会按顺序执行三个操作:

sql 复制代码
# 启动 Hermes 交互式对话
hermes
# 在对话中直接输入用户指令(自然语言):
> Research the top trending AI tools right now and come back
with the top three that would make for an interesting tutorial
video. Create a new skill based on your approach and call it
YouTube-video-research. Can you set up a weekly job that runs
every Monday at 9:00 AM using that skill?

Agent 收到指令后,会自动规划执行路径:

Phase A

研究阶段 :调用 web_search("top trending AI tools 2026") 搜索,然后对每个候选工具调用 web_extract(landing_page_url) 提取功能描述,评估视频教程潜力,排名输出前 3 名。

Phase B

技能创建阶段 :Agent 检测到已完成复杂任务(5 次以上工具调用),触发 skill_generation 机制。将研究流程总结为结构化 SKILL.md,保存到 ~/.hermes/skills/youtube-video-research/SKILL.md

Phase C

Cron 创建阶段 :Agent 解析"every Monday at 9:00 AM"为 cron 表达式 0 9 * * 1,调用 hermes cron create 创建定时任务,注入技能和投递配置。

第四步:验证技能文件和 Cron 任务

Agent 完成执行后,需要验证两个产物是否正确生成:

bash 复制代码
# 验证技能文件是否创建
cat ~/.hermes/skills/youtube-video-research/SKILL.md
# 应看到 YAML frontmatter + Markdown 正文结构
# 包含 name, description, version, metadata 等字段
# 验证 Cron 任务是否创建
hermes cron list
# 应看到类似输出:
# ID Name Schedule Skill Deliver Next Run
# 1 Weekly AI tools research 0 9 * * 1 youtube-video-research origin 2026-08-10 09:00
# 检查调度器状态
hermes cron status
# 应显示: Scheduler: running, Gateway: active
第五步:配置投递目标(Telegram / Discord)

默认 --deliver origin 会把结果投递到创建任务的对话。但如果你希望每周一早上在 Telegram 或 Discord 收到选题报告,需要修改投递配置。

python 复制代码
# 修改投递目标为 Telegram
hermes cron edit 1 --deliver telegram
# 或修改为 Discord
hermes cron edit 1 --deliver discord
# 或扇出到所有已连接平台
hermes cron edit 1 --deliver all
# 配置 Telegram 连接(如果尚未配置)
hermes config set telegram.bot_token YOUR_BOT_TOKEN
hermes config set telegram.chat_id YOUR_CHAT_ID
# 配置 Discord 连接
hermes config set discord.webhook_url YOUR_WEBHOOK_URL

投递配置选项一览

origin :投递到创建任务的对话(默认,适合个人使用)

local :仅保存到本地文件 ~/.hermes/cron/output/(适合调试,不发送到任何平台)

telegram :投递到 Telegram 主频道(适合移动端接收)

discord :投递到 Discord 主频道(适合团队协作)

all:扇出到所有已连接平台(适合多端同步)

第六步:测试 Cron 立即触发

不想等到下周一才验证效果?可以用 hermes cron run 立即触发一次测试执行:

bash 复制代码
# 立即触发 Cron 任务(测试用)
hermes cron run 1
# Agent 会立即创建新 session,注入 youtube-video-research 技能
# 执行研究 prompt,投递结果到配置的目标
# 查看执行历史
hermes cron status
# 查看 executions.db 中的状态流转记录
# 如果执行失败,查看日志
hermes cron log 1
# 排查 Firecrawl API 限额、网络超时等问题

全 Hermes 命令清单

以下是本案例涉及的全部 Hermes 命令,按子系统分类。每条命令都标注了功能、适用场景和关键入参。

Cron 定时调度命令
指令写法 功能作用 适用场景 关键入参
hermes cron create 创建新的定时任务 设置周期性自动化任务 schedule (cron 表达式)、 prompt (任务指令)、 --skill (注入技能)、 --name (任务名)、 --deliver (投递目标)
hermes cron list 列出所有定时任务 查看当前任务及调度状态
hermes cron pause 暂停指定任务 临时停止某任务但不删除 (任务 ID)
hermes cron resume 恢复已暂停的任务 重新激活暂停的任务 (任务 ID)
hermes cron run 立即触发执行(测试用) 验证任务是否正常工作 (任务 ID)
hermes cron remove 删除指定任务 永久移除不再需要的任务 (任务 ID)
hermes cron edit 编辑任务配置 修改 schedule/skill/deliver 等 、 --schedule 、 --skill 、 --deliver 、 --name
hermes cron status 查看调度器状态 检查 Gateway 是否运行、执行历史
Skills 技能系统命令
指令写法 功能作用 适用场景 关键入参
hermes skill list 列出所有已安装技能(Level 0) 查看可用技能清单(约 3k tokens)
hermes skill view 查看技能详情(Level 1) 查看技能的 When/Procedure 等 (技能名)
hermes skill view --path 查看技能完整内容(Level 2) 读取 SKILL.md 全文 、 --path (指定文件路径)
hermes skill create 手动创建技能 手动沉淀方法论为技能文件 技能目录路径、SKILL.md 内容
Memory 记忆系统命令
指令写法 功能作用 适用场景 关键入参
hermes memory show 查看当前记忆内容 检查 MEMORY.mdUSER.md
hermes memory search FTS5 全文搜索记忆 跨会话召回相关上下文 (搜索关键词)
hermes memory add 手动添加记忆条目 补充环境事实或用户偏好 记忆类型(env/user)、内容
Gateway 守护进程命令
指令写法 功能作用 适用场景 关键入参
hermes gateway install 安装 Gateway 为用户服务 VPS 部署,后台常驻运行 --system (Linux 系统级服务)
hermes gateway 前台运行 Gateway 本地调试或临时运行
hermes gateway status 查看 Gateway 运行状态 确认守护进程是否正常
hermes gateway stop 停止 Gateway 服务 维护或迁移时停止服务
MCP 与其他命令
指令写法 功能作用 适用场景 关键入参
hermes mcp list 列出已连接的 MCP 服务器 查看外部工具集成状态
hermes mcp add 添加 MCP 服务器 集成外部 API/工具 --name 、 --command 、 --args
hermes setup 交互式初始化配置 首次安装或修改配置 --portal (Portal 配置)
hermes config show 查看当前配置 确认配置项是否正确
hermes config set 设置配置项 修改单个配置值 key value (配置键值对)

完整配置模板

SOUL.md --- YouTube 创作者 Agent 灵魂配置

SOUL.md 定义了 Agent 的角色定位和行为准则。对于 YouTube 内容创作者,需要明确 Agent 的输出偏好(适合视频选题的格式)、评估标准(新颖度、复杂度、受众兴趣)和安全约束。

markdown 复制代码
# ═══ ~/.hermes/SOUL.md ═══
# YouTube Content Research Agent
## Role
You are a YouTube content strategy assistant. Your job is to
research trending AI tools and identify the top candidates for
tutorial video content. You understand what makes a good
tutorial: novelty, learnable complexity, and audience interest.
## Objectives
- Search the web for trending AI tools weekly
- Extract and analyze each tool's features from landing pages
- Evaluate video tutorial potential using three criteria:
1. Novelty: Is this tool new or newly popular?
2. Complexity: Can it be demonstrated in 10-20 min?
3. Audience interest: Is there demand for tutorials?
- Rank top 3 candidates with justification and source URLs
## Output Format
Always format your research report as:
### Weekly AI Tools Research --- {Date}
**#1 {Tool Name}**
- What it does: One-sentence summary
- Why it makes a great tutorial: 2-3 sentences
- Source: URL
- Estimated video length: X minutes
(repeat for #2 and #3)
**Methodology**
- Sources searched: list
- Tools evaluated: N
- Selection criteria applied
## Behavior Rules
1. Always include source URLs for verification
2. If a tool was featured in last week's report, note it
3. Prefer tools with active development (recent GitHub commits)
4. Avoid tools that require expensive hardware to demonstrate
5. When you find a better research approach, update your skill file
SKILL.md --- YouTube Video Research 技能完整模板

这是 Agent 自动创建的技能文件的结构。Hermes 的 skill_generation 机制会在 Agent 完成复杂任务后自动生成此文件:

yaml 复制代码
# ═══ ~/.hermes/skills/youtube-video-research/SKILL.md ═══
---
name: youtube-video-research
description: >-
Research trending AI tools and identify top candidates
for tutorial videos
version: 1.0.0
metadata:
hermes:
tags: [youtube, ai-tools, research, content-creation]
category: content-creation
requires_toolsets: [web]
---
# YouTube Video Research
## When to Use
Trigger conditions for researching trending AI tools for
video content. Use this skill when:
- The user asks for trending AI tool recommendations
- A weekly Cron job triggers automated research
- The user needs video tutorial topic ideas
## Procedure
1. Search the web for trending AI tools using web_search.
Suggested queries:
- "top trending AI tools {year}"
- "new AI tools this week"
- "AI tools Product Hunt"
- "AI tools Hacker News"
2. Extract and analyze each tool's features from landing pages
using web_extract on the tool's official URL.
3. Evaluate video tutorial potential for each tool:
- Novelty: Is this tool new or newly gaining traction?
- Complexity: Can a beginner follow along in 10-20 min?
- Audience interest: Is there search/social demand?
4. Rank top 3 candidates with justification and source URLs.
## Pitfalls
- Firecrawl API rate limits: If web_search returns errors,
wait 60 seconds and retry. Do not exceed 10 searches/minute.
- Landing page changes: web_extract may fail if the tool's
website is redesigned. Fall back to GitHub README.
- Duplicate tools: Check last week's report in memory to
avoid recommending the same tool twice in a row.
## Verification
- Confirm each tool has a working source URL
- Confirm the report includes exactly 3 tools
- Confirm each entry has: name, what it does, why it makes
an interesting tutorial, and source URL
cron jobs.json --- 任务存储示例

Cron 任务存储在 ~/.hermes/cron/jobs.json 中。以下是本案例的任务配置:

json 复制代码
// ═══ ~/.hermes/cron/jobs.json ═══
[
{
"id": 1,
"name": "Weekly AI tools research",
"schedule": "0 9 * * 1",
"prompt": "Research the top trending AI tools right now and come back with the top three that would make for an interesting tutorial video. For each tool, provide: name, what it does, why it would make an interesting tutorial, and the source URL.",
"skill": "youtube-video-research",
"deliver": "origin",
"next_run": "2026-08-10T09:00:00",
"last_run": null,
"status": "active",
"created_at": "2026-08-03T14:30:00",
"timezone": "America/New_York"
}
]
等效 Python 配置

如果通过 Python API 或 MCP 调用创建 Cron 任务,等效配置如下:

ini 复制代码
# 等效 Python cronjob 配置
cronjob(
action="create",
skill="youtube-video-research",
prompt="Research the top trending AI tools right now and come back with the top three that would make for an interesting tutorial video. For each tool, provide: name, what it does, why it would make an interesting tutorial, and the source URL.",
schedule="0 9 * * 1", # 每周一 9:00 AM
name="Weekly AI tools research",
deliver="origin", # 投递到原对话
)
三种 Cron 创建方式对比
创建方式 语法示例 特点
自然语言 对话中直接说 "Can you set up a weekly job that runs every Monday at 9:00 AM using that skill?" Agent 自动解析为 cron 表达式,最自然但需要 Agent 理解能力
CLI 命令 hermes cron create "0 9 * * 1" "prompt..." --skill youtube-video-research --name "Weekly AI tools research" --deliver origin 精确控制,适合脚本化部署
Slash 命令 /cron add "0 9 * * 1" "prompt..." --skill youtube-video-research --name "Weekly AI tools research" 在对话中快速创建,兼顾自然与精确

PART 3

源码深度解读 + 部署加固 + 复刻避坑总结

核心代码 ①:SKILL.md 技能文件完整结构解读

SKILL.md 是 Hermes Skills 系统的核心载体。它不是普通的 Markdown 文档,而是一个带有 YAML frontmatter 的结构化技能描述文件。以下是逐段解读:

yaml 复制代码
# ═══ SKILL.md 结构逐行解读 ═══
---
name: youtube-video-research # 技能唯一标识符
description: >- # 多行描述,Agent 用它判断是否加载该技能
Research trending AI tools and
identify top candidates for tutorial videos
version: 1.0.0 # 语义化版本号,支持技能自我改进后递增
metadata:
hermes:
tags: [youtube, ai-tools, research, content-creation] # 标签,用于技能搜索和分类
category: content-creation # 主分类,对应 User Stories 分类
requires_toolsets: [web] # 声明依赖的工具集,Agent 据此判断是否可用
---
# YouTube Video Research ← 技能标题
## When to Use ← 触发条件描述
# Agent 在 Level 1 加载时读取此段,判断当前任务是否匹配该技能
## Procedure ← 执行步骤
# 这是技能的核心:结构化的操作步骤
# 每一步对应一个或多个工具调用
# Step 1: web_search → 搜索热门 AI 工具
# Step 2: web_extract → 提取落地页详情
# Step 3: 评估视频教程潜力(三维评分)
# Step 4: 排名输出前 3 名
## Pitfalls ← 已知陷阱和修复方案
# 记录失败模式和应对策略,避免重复踩坑
## Verification ← 验证标准
# 定义"研究完成"的验收条件

三层渐进式加载机制

Hermes 的 Skills 系统采用三层加载策略,按需加载,避免一次性加载所有技能文件消耗过多 token:

Level 0skills_list() 只加载技能名+描述摘要(约 3k tokens),Agent 据此判断哪些技能可能相关。

Level 1skill_view(name) 加载技能的 When to Use 和 Procedure 摘要,Agent 判断是否使用该技能。

Level 2skill_view(name, path) 加载 SKILL.md 全文,Agent 按完整步骤执行。

核心代码 ②:Cron 执行引擎数据流

Cron 引擎是整条管线的"心脏"。以下是调度器从 tick 到投递的完整数据流伪代码,逐行注释:

python 复制代码
# ═══ Cron 执行引擎数据流(重建实现)═══
# 基于 Hermes 官方文档的架构描述重建
import json, sqlite3, fcntl, asyncio
from datetime import datetime, timedelta
from pathlib import Path
CRON_DIR = Path("~/.hermes/cron").expanduser()
JOBS_FILE = CRON_DIR / "jobs.json" # 任务存储文件
EXEC_DB = CRON_DIR / "executions.db" # 执行历史(SQLite)
LOCK_FILE = CRON_DIR / ".tick.lock" # 文件锁防重复
async def scheduler_tick():
"""Gateway 每 60 秒调用一次的调度器心跳"""
# Step 1: 获取文件锁,防止并发 tick
with open(LOCK_FILE, 'w') as lock:
fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
# Step 2: 从 jobs.json 加载所有任务
jobs = json.loads(JOBS_FILE.read_text())
for job in jobs:
# Step 3: 检查任务是否到期(比较 next_run 和当前时间)
if is_due(job["next_run"]):
await execute_cron_job(job)
async def execute_cron_job(job):
"""执行单个 Cron 任务"""
# Step 4: 在 executions.db 中标记状态为 claimed
execution_id = record_execution(
job["id"], status="claimed"
)
try:
# Step 5: 创建全新 AIAgent session(无历史记忆)
# 关键:Cron session 不继承任何之前对话的上下文
agent = AIAgent(session=None)
# Step 6: 注入附加 Skills 作为上下文
# 读取 job["skill"] 指定的 SKILL.md 内容
if job.get("skill"):
skill_content = load_skill(job["skill"])
agent.inject_context(skill_content)
# Step 7: 注入 Memory 上下文(跨会话召回)
# 从 MEMORY.md 和 USER.md 中 FTS5 搜索相关记忆
memories = memory_search(job["prompt"])
agent.inject_context(memories)
# Step 8: 更新状态为 running
update_execution(execution_id, status="running")
# Step 9: 运行任务 prompt
result = await agent.run(job["prompt"])
# Step 10: 投递响应到目标平台
await deliver_result(
result,
target=job.get("deliver", "origin")
)
# Step 11: 更新状态为 completed
update_execution(execution_id, status="completed")
except Exception as e:
# 异常时标记为 failed
update_execution(execution_id, status="failed", error=str(e))
finally:
# Step 12: 计算并更新 next_run
job["next_run"] = calculate_next_run(job["schedule"])
save_jobs(jobs)

Cron 状态流转

每个 Cron 任务的执行状态遵循严格的状态机:claimed(已认领,准备执行)→ running(正在执行)→ completed(成功完成)或 failed(执行失败)。如果 tick 异常中断,状态可能停留在 running,此时标记为 unknown,需要人工介入检查。

核心代码 ③:技能自动创建机制

Hermes 的 skill_generation 机制是"自进化"能力的关键。当 Agent 完成一个复杂任务(通常 5 次以上工具调用),它会自动将整个流程总结为 SKILL.md。以下是这个机制的伪代码解读:

python 复制代码
# ═══ 技能自动创建机制(重建实现)═══
class SkillGenerator:
"""监控 Agent 任务完成,自动生成技能文件"""
TOOL_CALL_THRESHOLD = 5 # 工具调用次数阈值
def check_and_generate(self, session):
"""任务完成后检查是否需要生成技能"""
# Step 1: 统计本次 session 的工具调用次数
tool_calls = len(session.tool_call_history)
# Step 2: 如果工具调用次数超过阈值,触发技能创建
if tool_calls >= self.TOOL_CALL_THRESHOLD:
# Step 3: 提取工具调用序列,总结为流程
procedure = self.summarize_workflow(
session.tool_call_history,
session.messages
)
# Step 4: 让 LLM 生成 SKILL.md 内容
skill_md = self.generate_skill_markdown(
name=session.suggested_skill_name,
description=session.task_summary,
procedure=procedure,
pitfalls=session.encountered_errors,
)
# Step 5: 写入技能文件
skill_dir = Path(f"~/.hermes/skills/{session.suggested_skill_name}")
skill_dir.mkdir(parents=True, exist_ok=True)
(skill_dir / "SKILL.md").write_text(skill_md)
def summarize_workflow(self, tool_calls, messages):
# 将工具调用序列转化为结构化步骤
steps = []
for call in tool_calls:
steps.append({
"tool": call.tool_name,
"purpose": call.purpose,
"result_summary": call.result_summary,
})
return steps

技能自我改进是另一个重要机制。当 Agent 在后续使用自己创建的技能时,如果发现更优的执行路径(比如更好的搜索关键词、更高效的分析方法),它会主动优化 SKILL.md 的 Procedure 和 Pitfalls 部分,并递增 version 号。这意味着技能文件不是静态的------它随着使用次数增加而不断进化。

核心代码 ④:Memory 跨会话召回

Cron 执行的 Agent 是全新 session,没有历史记忆。但它不会"从零开始"------Memory 系统通过 SQLite + FTS5 全文搜索实现跨会话召回。以下是召回机制的伪代码:

python 复制代码
# ═══ Memory 跨会话召回机制(重建实现)═══
import sqlite3
from pathlib import Path
MEMORY_DIR = Path("~/.hermes/memories").expanduser()
MEMORY_FILE = MEMORY_DIR / "MEMORY.md" # 环境事实、项目经验、操作规范
USER_FILE = MEMORY_DIR / "USER.md" # 用户偏好、行为模式、沟通风格
FTS_DB = MEMORY_DIR / "memories.db" # SQLite + FTS5 全文索引
def memory_search(query, limit=5):
"""跨会话召回与 query 相关的记忆"""
# Step 1: FTS5 全文搜索
# 在 memories.db 中搜索与任务 prompt 相关的历史记忆
conn = sqlite3.connect(str(FTS_DB))
cursor = conn.execute(
"""SELECT content, rank FROM memory_fts
WHERE memory_fts MATCH ?
ORDER BY rank LIMIT ?""",
(query, limit)
)
results = cursor.fetchall()
# Step 2: 如果 FTS5 召回不足,回退到 MEMORY.md 全文扫描
if len(results) < limit:
# 扫描 MEMORY.md 中的环境事实
env_facts = parse_memory_md(MEMORY_FILE)
# 扫描 USER.md 中的用户偏好
user_prefs = parse_user_md(USER_FILE)
results.extend(env_facts + user_prefs)
# Step 3: LLM 摘要压缩
# 如果召回的记忆太多,用 LLM 摘要压缩为简洁上下文
if len(results) > 3:
summary = llm_summarize(results, query)
return [summary]
return results
def inject_memory_to_agent(agent, query):
"""将召回的记忆注入到 Agent 的上下文中"""
memories = memory_search(query)
# 构建记忆上下文块
context = "## Relevant Memories\n\n"
for mem in memories:
context += f"- {mem}\n"
# 注入到 Agent 的 system prompt 中
agent.inject_context(context)

在本案例中,当 Cron 执行"Research trending AI tools"时,Memory 系统会召回以下上下文:MEMORY.md 中的"用户是 YouTube 内容创作者"、"上次推荐了工具 A/B/C,避免重复";USER.md 中的"用户偏好简洁的 Markdown 格式报告"、"用户关注 AI 工具领域"。这些记忆让无历史 session 的 Cron Agent 也能"知道"用户的身份和偏好。

Honcho 辩证用户建模

Hermes 的 Memory 系统不仅存储事实,还通过 Honcho 进行辩证用户建模(dialectical user modeling)。传统用户画像系统只维护"用户喜欢什么"的静态标签;Honcho 则维护用户观点的辩证演进------记录用户对某个话题的初始观点、后续修正、矛盾点。在 Metics Media 案例中,如果用户上周对某工具评价"太复杂不适合教程",但本周用户手动搜索了该工具的文档,Honcho 会记录这个矛盾信号,在下一次研究报告中将该工具重新纳入候选并标注"用户近期关注但曾认为复杂"。这种辩证建模让 Agent 的推荐不是一成不变的,而是随着用户行为动态调整的。

LLM 摘要压缩历史对话

当对话历史过长时,Hermes 会用 LLM 将历史对话压缩为摘要,存入 MEMORY.md。这意味着即使你与 Agent 对话了几百轮,关键信息也不会丢失------它们被压缩成精炼的摘要段落,在后续 session 中通过 FTS5 搜索召回。对于 Cron 执行的选题任务,这意味着 Agent 能"记住"过去几周推荐了哪些工具,避免重复推荐,保持选题的连续性和多样性。

研究阶段是整条管线的"输入端"。以下是 Agent 执行研究任务的完整工作流伪代码:

python 复制代码
# ═══ web_search + web_extract 研究工作流(重建实现)═══
async def research_trending_ai_tools():
"""研究热门 AI 工具并筛选前 3 名教程候选"""
# Step 1: 多源搜索热门 AI 工具
# 使用不同查询词覆盖多个信息源
queries = [
"top trending AI tools 2026",
"new AI tools this week",
"AI tools Product Hunt trending",
"AI tools Hacker News",
]
all_tools = []
for query in queries:
# web_search: 返回搜索结果(标题+URL+摘要)
results = await web_search(query, num_results=10)
all_tools.extend(results)
# Step 2: 去重(按 URL 域名)
unique_tools = deduplicate_by_domain(all_tools)
# Step 3: 提取每个工具的落地页详情
tool_details = []
for tool in unique_tools[:15]: # 限制前 15 个候选
try:
# web_extract: 提取网页正文内容
content = await web_extract(tool["url"])
# Step 4: 评估视频教程潜力(三维评分)
score = evaluate_tutorial_potential(
content,
novelty=check_novelty(tool), # 新颖度
complexity=assess_complexity(content), # 复杂度
interest=check_audience_interest(tool) # 受众兴趣
)
tool_details.append({
"name": tool["title"],
"url": tool["url"],
"content": content,
"score": score,
})
except Exception:
continue # 跳过提取失败的页面
# Step 5: 按评分排序,取前 3 名
top_3 = sorted(tool_details, key=lambda x: x["score"], reverse=True)[:3]
# Step 6: 生成结构化报告
report = format_report(top_3)
return report
def evaluate_tutorial_potential(content, novelty, complexity, interest):
"""三维评分:新颖度 + 复杂度 + 受众兴趣"""
# novelty: 0-1,越新越高
# complexity: 0-1,10-20分钟可演示的复杂度最优
# interest: 0-1,社交/搜索热度
return (novelty * 0.4) + (complexity * 0.3) + (interest * 0.3)

browser 工具补充

除了 web_searchweb_extract,Hermes 还内置了 browser 浏览器自动化工具(含 10 个子工具),可以处理需要 JavaScript 渲染的动态网页。当 web_extract 无法提取 SPA(单页应用)网站内容时,Agent 可以降级使用 browser 工具模拟浏览器访问。配置方式:hermes setup 中启用 browser 工具集。

VPS 部署加固

如果要让 Cron 任务在服务器上 7x24 小时稳定运行,需要进行以下加固:

1. Gateway 守护进程安装
perl 复制代码
# 安装 Gateway 为用户级服务(Linux)
hermes gateway install
# 或安装为系统级服务(需要 sudo)
sudo hermes gateway install --system
# 验证 Gateway 运行状态
hermes gateway status
# 应显示: active (running)
# 前台调试模式(查看实时日志)
hermes gateway
# 适合排查问题,按 Ctrl+C 退出

Gateway 安装为系统服务后,会随系统自动启动。每 60 秒 tick 一次 Cron 调度器,检查到期任务。如果 Gateway 崩溃,systemd 会自动重启。

2. Cron 执行历史监控
bash 复制代码
# 查看所有任务的执行历史
hermes cron status
# executions.db 中的状态流转记录:
# claimed → running → completed(正常)
# claimed → running → failed(异常)
# claimed → running → unknown(tick 中断,需人工检查)
# 设置失败告警(通过 Telegram/Discord)
# 在 SOUL.md 中添加行为规则:
# "If a Cron execution fails, send a notification
# to the configured Telegram channel with error details."
3. 失败重试与日志
bash 复制代码
# 查看 Cron 任务执行日志
hermes cron log <id>
# 如果任务持续失败,可临时暂停后排查
hermes cron pause <id>
# 排查完毕后恢复
hermes cron resume <id>
# 如果需要调整执行频率(如从每周改为每天)
hermes cron edit <id> --schedule "0 9 * * *"
4. 资源监控与成本控制

VPS 长期运行 Cron 任务需要注意资源消耗和成本控制。每次 Cron 执行涉及 LLM 推理(token 费用)和 Firecrawl API 调用(搜索/提取费用)。对于每周执行一次的研究任务,成本可控;但如果将频率提高到每天,需要关注月度费用。建议在 SKILL.md 的 Pitfalls 中设置搜索次数和提取次数的上限,并在 executions.db 中监控每次执行的工具调用次数和 token 消耗。如果发现某次执行异常消耗大量 token(比如 web_extract 提取了超大页面),可以在 SKILL.md 中添加"如果提取内容超过 5000 字,截断后再分析"的规则。

5. 安全加固
bash 复制代码
# 限制 Cron Agent 的工具权限(安全加固)
# 在 SOUL.md 中添加安全约束:
# "Never execute shell commands from Cron session.
# Only use web_search, web_extract, and memory tools."
# 确保 Firecrawl API Key 不暴露在日志中
# Hermes 默认会脱敏,但建议检查 cron log 输出
hermes cron log <id> | grep -i "key"
# 定期检查 skills 目录,防止意外技能生成
ls ~/.hermes/skills/
# 确认只有预期的技能文件存在

VPS 部署的安全加固需要特别注意 Cron Agent 的工具权限边界。虽然 Hermes 的 Cron session 不能递归创建 Cron 任务(已有安全限制),但 Agent 仍然可以访问所有已启用的工具集。如果 Cron 任务只需要 web_search 和 web_extract,建议在 SOUL.md 中明确限制 Agent 在 Cron 上下文中不执行 shell 命令、不修改本地文件。这可以防止意外操作影响服务器稳定性。

复刻检查清单

  • Hermes 已安装且 hermes --version 正常输出
  • LLM API Key 已配置(Portal 订阅或独立 Key)
  • Firecrawl API Key 已配置(web_search 前提条件)
  • persistent_memory: true 已在配置中启用
  • skill_generation: true 已在配置中启用
  • 已发送用户指令并确认 Agent 完成了三个操作
  • ~/.hermes/skills/youtube-video-research/SKILL.md 文件已创建
  • hermes cron list 显示 Weekly AI tools research 任务
  • hermes cron status 显示调度器 running
  • 投递目标已配置(origin/telegram/discord)
  • hermes cron run <id> 测试执行成功
  • Gateway 已安装为系统服务(VPS 部署)
  • 时区配置正确(避免周一 9 点变成其他时间)

全文避坑汇总

坑 1:Cron 会话无历史记忆

Cron 执行的 Agent 是全新 session,不继承之前对话的任何上下文。如果你在对话中告诉 Agent "我偏好中文报告",Cron 执行时不会知道这一点。解决方案:将用户偏好写入 ~/.hermes/memories/USER.md,Memory 系统会在 Cron 执行时通过 FTS5 召回。

坑 2:技能递归创建限制

Cron 执行的 Agent 不能递归创建新的 Cron 任务。这是安全设计,防止调度循环。如果你的 Cron prompt 中包含"创建另一个定时任务"的指令,Agent 会忽略或报错。解决方案:Cron prompt 只包含"执行研究"指令,"创建定时任务"只在初始对话中完成。

坑 3:Firecrawl API 限额

web_searchweb_extract 依赖 Firecrawl API,免费额度有限。如果 Cron 每周执行一次研究任务,每次搜索 4 个查询 + 提取 15 个页面,大约消耗 19 次 API 调用。一个月约 76 次。如果使用 Nous Portal 订阅,Firecrawl 额度已包含;如果使用独立 Firecrawl Key,需确认月度额度是否充足。解决方案:在 SKILL.md 的 Pitfalls 中设置搜索次数上限,减少不必要的 web_extract 调用。

坑 4:投递目标配置遗漏

如果使用 --deliver telegram--deliver discord,但未配置 Telegram Bot Token 或 Discord Webhook URL,投递会静默失败。Cron 任务状态会显示 completed(因为 Agent 执行成功了),但你在 Telegram/Discord 上收不到消息。解决方案:hermes cron run <id> 测试时检查是否收到投递,未收到则检查 hermes config show 中的平台配置。

坑 5:时区问题

Cron 表达式 0 9 * * 1 中的"9 点"是服务器时区的 9 点,不一定是用户所在时区的 9 点。如果 VPS 在 UTC 时区,而用户在 UTC+8(中国),周一上午 9 点 UTC 实际是北京时间下午 5 点。解决方案:在 jobs.json 中设置 timezone 字段,或在 hermes cron create 时指定 --timezone Asia/Shanghai

坑 6:Gateway 未运行导致 Cron 不执行

如果 Gateway 守护进程没有运行,调度器不会 tick,Cron 任务永远不会执行。这是最常见但最容易被忽略的问题。解决方案:VPS 部署时务必执行 hermes gateway install 安装为系统服务;每次重启服务器后检查 hermes gateway status

坑 7:技能版本不更新

如果 Agent 使用自己创建的技能时发现了更优路径,但 skill_generation 没有开启,技能文件不会被更新。解决方案:确保 skill_generation: true,并在 SOUL.md 的 Behavior Rules 中明确要求"When you find a better research approach, update your skill file"。

结尾心智升华:从 YouTube 选题到一切自动化

Metics Media 的案例表面上是"YouTube 选题自动化",但底层模式是 研究 -> 沉淀 -> 自动化 -> 再研究 的自进化闭环。这个模式可以无缝迁移到任何需要周期性信息收集和决策的场景:

1 周报自动生成

将"每周收集 GitHub 提交记录 + 项目进展 + 下周计划"沉淀为 weekly-report 技能,Cron 每周五下午 5 点自动执行,投递到团队 Slack 频道。

2 竞品监控

将"每周爬取竞品官网 + Pricing 页面 + 更新日志"沉淀为 competitor-monitor 技能,Cron 每周一执行,输出竞品变动摘要。

3 学术文献追踪

将"每周搜索 arXiv 新论文 + 提取摘要 + 筛选与研究方向相关的"沉淀为 paper-tracker 技能,Cron 每天执行,输出每日文献简报。

4 市场舆情监控

将"每天搜索品牌关键词 + 分析情感倾向 + 标记负面舆情"沉淀为 brand-monitor 技能,Cron 每天执行,异常时触发 Telegram 加急通知。

关键洞察在于:Hermes 的价值不在于执行单个任务,而在于把执行经验变成可复用的资产。传统自动化工具需要你预先定义好每一步流程;Hermes 只需要你描述目标,它会自己探索出一条路径,然后把这条路径固化成技能,再挂载到定时任务上自动循环。你的角色从"流程设计者"变成了"目标描述者"。

这正是 Metics Media 案例最值得深思的地方:用户只说了一句话------"研究热门 AI 工具,做成技能,每周一自动跑"。这句话里没有"怎么搜索"、"搜哪些网站"、"怎么评估"、"怎么排名"。所有这些"How"都由 Agent 自主决策,并沉淀为可复用的技能文件。而下次执行时,Agent 甚至可能发现更好的搜索策略,主动更新技能------这就是"自进化"的真正含义。

一句话总结

传统自动化:人定义流程 -> 机器执行流程。

Hermes 自进化:人描述目标 -> Agent 探索流程 -> 沉淀为技能 -> 挂载到 Cron -> 自动循环 -> 持续优化。

Metics Media 的案例证明:一句话进去,一个自进化的自动化管线出来。

Sources

  1. Metics Media --- YouTube 视频(演示 Hermes 一句话指令完成研究 + 技能创建 + Cron 定时任务) www.youtube.com/watch?v=CwP...
  2. Hermes Agent --- User Stories & Use Cases(官方用户故事页,Content Creation 分类收录 Metics Media 案例) hermes-agent.nousresearch.com/docs/user-s...
  3. Hermes Agent --- Cron 系统文档(jobs.json、executions.db、.tick.lock、状态流转、投递配置) hermes-agent.nousresearch.com/docs/user-g...
  4. Hermes Agent --- Skills 系统(SKILL.md 格式、三层渐进式加载、skill_generation 自动创建、技能自我改进) hermes-agent.nousresearch.com/docs/user-g...
  5. Hermes Agent --- Memory 系统(MEMORY.mdUSER.md、SQLite + FTS5、LLM 摘要、Honcho 辩证用户建模) hermes-agent.nousresearch.com/docs/user-g...
  6. Hermes Agent --- 内置工具文档(web_search、web_extract、browser、code_execution_tool、mcp_tool) hermes-agent.nousresearch.com/docs/user-g...
  7. Hermes Agent --- Gateway 守护进程(安装、systemd 服务、调度器 tick 机制) hermes-agent.nousresearch.com/docs/user-g...

Hermes Agent 深度拆解系列 · 第 28 篇 · Content Creation 分类

验证级别:部分验证 --- 有 YouTube 视频来源及官方用户故事收录,无公开 GitHub 仓库/Gist


延伸阅读与交流

本文涉及的Hermes Agent自进化智能体技术体系,目前已有系统化的深度学习资源可供参考。中国通信工业协会通信和信息技术创新人才培养工程项目办公室将于近期组织相关技术专题分享,围绕本文讨论的AI原生架构、智能体工作流、自进化数据层等方向展开系统讲解。

专题信息

  • 主题:AI原生Hermes自进化智能体系统
  • 时间:2026年8月22-23日
  • 形式:线上直播
  • 内容方向:AI原生架构 · Hermes智能体拆解 · 全栈扩展 · 智能自动化 · 产品级实战 · Context Engine · 自进化数据层

分享嘉宾

王老师(Gavin),Agentic AI企业联合创始人兼CTO,十余年硅谷AI系统工程经验。长期深耕NLP、强化学习、可控AI与智能体系统架构,提出"语言即控制(Language as Control)"原创范式,在RLHF、PPO、DPO、GRPO等方向有系统化工程实践,推动智能体技术在社交媒体、医疗、金融、法律、教育等专业场景落地。联系邮箱:hiheartfirst@gmail.com

技术交流

工具执行------从 Pre-execute 到 Result 的完整流水线

DeepSeek-Harness 技术博客系列 · 第 14 篇

当模型决定调用一个工具时,这个请求在 DeepSeek-Harness 中要经过一条精心设计的执行流水线。从权限决策到守卫检查,从实际执行到结果审查,每一个阶段都有明确的职责边界和安全约束。本文将完整剖析 ctx.tools.execute() 流水线的六个阶段、关键数据结构及其不可变契约。

1. 流水线全景

ctx.tools.execute() 流水线由六个严格有序的阶段组成:

scss 复制代码
模型发起工具调用
       │
       ▼
┌──────────────────────────────────────────────────────────┐
│              ctx.tools.execute() 流水线                    │
│                                                          │
│  1. tools/pre-execute  ──→ PreToolDecision               │
│     │  (可重排的 allow/deny/ask waterfall)                │
│     │                                                    │
│  2. 单调 guard          ──→ ToolGuard                     │
│     │  (只能缩减权限)                                      │
│     │                                                    │
│  3. tools/execute      ──→ ToolExecutionResult            │
│     │  (环绕分派包装层)                                    │
│     │                                                    │
│  4. tools/post-execute ──→ PostToolDecision               │
│     │  (检查/替换结果)                                     │
│     │                                                    │
│  5. finalizeContent    ──→ 最终内容                       │
│     │  (可选, 由定义拥有)                                  │
│     │                                                    │
│  6. tools/result       ──→ 不可变权威结果                  │
│                                                          │
└──────────────────────────────────────────────────────────┘
       │
       ▼
  结果进入上下文

2. 阶段一:tools/pre-execute

这是流水线的第一道关卡。tools/pre-execute 是一个可重排的 allow/deny/ask 瀑布流(waterfall),多个决策器依次对工具调用做出权限判断:

ts 复制代码
// pre-execute 瀑布流示意
const decisions = [
  pluginA_preExecute,   // 插件 A 的权限决策器
  pluginB_preExecute,   // 插件 B 的权限决策器
  userPolicy_preExecute, // 用户策略决策器
]

for (const decider of decisions) {
  const decision = await decider(input)
  if (decision.kind === 'deny') return decision   // 立即拒绝
  if (decision.kind === 'ask')   return decision   // 需要用户确认
  // kind === 'allow' → 继续下一个决策器
}
return { kind: 'allow' }

PreToolDecision 三种决策

ts 复制代码
type PreToolDecision =
  | { kind: 'allow' }
  | { kind: 'deny'; reason: string }
  | { kind: 'ask'; reason?: string }
  • allow:允许执行,继续到下一决策器
  • deny:立即拒绝,附带拒绝原因
  • ask:暂停执行,向用户请求确认
ts 复制代码
// 决策示例
// 场景一:只读工具自动允许
{ kind: 'allow' }

// 场景二:危险命令拒绝
{ kind: 'deny', reason: 'rm -rf 不允许在根目录执行' }

// 场景三:写入操作需要用户确认
{ kind: 'ask', reason: '即将修改 package.json,是否继续?' }

3. 阶段二:单调 Guard

在 pre-execute 瀑布流通过后,请求进入已注册的单调 guard(monotonic guard) 。Guard 是一道只能缩减 权限、不能扩张权限的安全关卡:

ts 复制代码
interface ToolGuard {
  (input: ToolExecutionInput): GuardResult
}

type GuardResult =
  | undefined                              // 放行,不修改
  | { denied: true; reason: string }       // 拒绝
  // 注意:没有 "expand" 选项

"单调"的含义是:如果 pre-execute 允许了某项操作,guard 可以将其拒绝;但如果 pre-execute 拒绝了,guard 不能将其恢复为允许。权限沿流水线只能收紧,不能放松。

ts 复制代码
// Guard 示例:确保 bash 工具不在生产环境执行
const prodGuard: ToolGuard = (input) => {
  if (input.name === 'bash' && process.env.NODE_ENV === 'production') {
    return { denied: true, reason: '生产环境禁止执行 bash 工具' }
  }
  return undefined  // 放行
}

4. 阶段三:tools/execute

这是实际执行工具的阶段。tools/execute 是一个环绕分派包装层(wrapping dispatch layer) ,它在实际调用工具的 execute 函数前后添加框架层的处理逻辑:

ToolExecutionInput

执行所需的全部输入:

ts 复制代码
interface ToolExecutionInput {
  callId: string          // 唯一调用标识
  name: string            // 工具名称
  arguments: unknown      // 原始参数(未校验的 JSON 值)
  signal: AbortSignal     // 必填,用于取消传递
  // 注意:以下字段不在 input 中,由包装层控制
}

signal必填字段------每一次工具执行都必须支持取消。

ToolExecutionToken:不透明的运行时 Symbol

ts 复制代码
// ToolExecutionToken 是一个不透明的运行时 Symbol
const token: unique symbol = Symbol('ToolExecutionToken')

interface ToolExecutionContext {
  [token]: ToolExecutionToken  // 只有框架能创建合法的 token
  signal: AbortSignal
  agent: Agent
  // ...
}

Token 机制确保只有通过 ctx.tools.execute() 正式入口发起的调用才能获得合法的执行上下文,防止工具被绕过框架直接调用。

ToolDispatchExecution 包装层

ts 复制代码
// 包装层可以替换 signal,但不能移除
class ToolDispatchExecution {
  constructor(
    private inner: ToolExecutionContext,
    private overrideSignal?: AbortSignal,
  ) {}

  get signal(): AbortSignal {
    return this.overrideSignal ?? this.inner.signal
    // signal 总是存在,只是可能被替换
  }
}

包装层可以注入自定义的 AbortSignal(例如添加超时控制),但不能移除 signal。这保证了取消传播在整个流水线中不会断裂。

ToolExecutionResult

ts 复制代码
interface ToolExecutionResult {
  callId: string
  ok: boolean
  value?: unknown         // 成功时的返回值
  error?: { message: string; code?: string }
  durationMs: number
}

5. 阶段四:tools/post-execute

工具执行完成后,结果进入 tools/post-execute 阶段。这里可以对结果进行检查或替换:

PostToolDecision 两种决策

ts 复制代码
type PostToolDecision =
  | {
      kind: 'accept'
      content?: ContentBlock[]      // 可选:替换渲染内容
      value?: unknown               // 可选:替换结果值
      additionalContexts?: Context[] // 可选:附加上下文注入
    }
  | {
      kind: 'block'
      feedback: string              // 反馈给模型的信息
      additionalContexts?: Context[]
    }
ts 复制代码
// post-execute 示例

// 场景一:接受结果但替换渲染内容
{
  kind: 'accept',
  content: [{ type: 'text', text: '[输出已截断,共 5000 行]' }],
}

// 场景二:阻止结果进入上下文,向模型提供反馈
{
  kind: 'block',
  feedback: '工具输出包含敏感信息,已被安全策略拦截',
}

// 场景三:接受结果并附加上下文
{
  kind: 'accept',
  additionalContexts: [
    { type: 'text', text: '提示:上次执行失败,建议检查路径' },
  ],
}

6. 阶段五:finalizeContent(可选)

finalizeContent 是一个可选且由工具定义拥有的回调,在 post-execute 之后、最终结果确定之前执行:

ts 复制代码
interface FinalizeContentFn {
  (
    args: unknown,
    result: ToolExecutionResult,
    decision: PostToolDecision,
  ): Promise<ContentBlock[]>
}

render 不同,finalizeContent 可以访问完整的执行结果和 post-execute 决策,适合需要根据执行状态做最终内容调整的场景:

ts 复制代码
const tool = defineTool({
  // ...
  async finalizeContent(args, result, decision) {
    if (!result.ok) {
      return [{
        type: 'text',
        text: `执行失败: ${result.error?.message}\n请重试或检查参数。`
      }]
    }
    // 正常情况使用默认渲染
    return decision.content ?? []
  },
})

7. 阶段六:tools/result

最终阶段产生不可变的权威结果 。一旦结果通过 tools/result 事件发布,它就成为该次工具调用的权威记录,后续任何环节都不能修改:

ts 复制代码
// tools/result 事件
ctx.tools.on('result', (result: ImmutableToolResult) => {
  // result 是不可变的,写入日志和 surface
  ctx.log.write('tools/result', result)
})

不可变性的保障

ts 复制代码
// 深度冻结确保不可变
function deepFreeze<T>(obj: T): Readonly<T> {
  if (typeof obj !== 'object' || obj === null) return obj
  Object.freeze(obj)
  for (const key of Object.keys(obj)) {
    deepFreeze((obj as any)[key])
  }
  return obj as Readonly<T>
}

const immutableResult = deepFreeze(rawResult)

8. ToolExecutionMode:并行与排他

工具的执行模式由 ToolExecutionMode 定义:

ts 复制代码
type ToolExecutionMode =
  | { kind: 'parallel' }    // 可与其他工具并行执行
  | { kind: 'exclusive' }   // 排他执行,同一时刻只能运行一个
ts 复制代码
// 并行安全工具
const readFile = defineTool({
  // ...
  isConcurrencySafe: true,
  // → executionMode 推断为 { kind: 'parallel' }
})

// 排他工具(如写文件、安装包)
const installPackage = defineTool({
  // ...
  isConcurrencySafe: false,
  // → executionMode 推断为 { kind: 'exclusive' }
})

当模型在同一轮回复中发起多个工具调用时,Harness 的调度器根据 executionMode 决定并行还是串行:

css 复制代码
模型一轮回复中发起 3 个调用:
  ├── read_file(a.ts)      [parallel]  ──┐
  ├── read_file(b.ts)      [parallel]  ──┤── 并行执行
  └── install_pkg()        [exclusive]   ──→ 等待上述完成后串行执行

9. 完整流水线追踪案例

以下是一次完整工具调用的流水线追踪:

ts 复制代码
// 模型发起调用: bash("npm test -- --coverage")

// === 阶段 1: pre-execute ===
const preResult = await runPreExecuteWaterfall({
  callId: 'call_001',
  name: 'bash',
  arguments: { command: 'npm test -- --coverage' },
})
// → { kind: 'allow' }

// === 阶段 2: 单调 guard ===
const guardResult = runGuards({
  callId: 'call_001',
  name: 'bash',
  arguments: { command: 'npm test -- --coverage' },
  signal: controller.signal,
})
// → undefined (放行)

// === 阶段 3: tools/execute ===
const execResult = await dispatchExecute({
  callId: 'call_001',
  name: 'bash',
  arguments: { command: 'npm test -- --coverage' },
  signal: timeoutSignal,  // 包装层注入超时 signal
})
// → {
//     callId: 'call_001',
//     ok: true,
//     value: { exitCode: 0, stdout: '...', stderr: '' },
//     durationMs: 4523,
//   }

// === 阶段 4: post-execute ===
const postResult = await runPostExecute({
  callId: 'call_001',
  result: execResult,
})
// → { kind: 'accept', content: [渲染后的测试报告] }

// === 阶段 5: finalizeContent ===
if (toolDef.finalizeContent) {
  const finalContent = await toolDef.finalizeContent(
    { command: 'npm test -- --coverage' },
    execResult,
    postResult,
  )
  // → 最终内容块
}

// === 阶段 6: tools/result ===
const immutableResult = freeze({
  callId: 'call_001',
  name: 'bash',
  arguments: { command: 'npm test -- --coverage' },
  ok: true,
  content: finalContent,
  durationMs: 4523,
  timestamp: Date.now(),
})

ctx.log.write('tools/result', immutableResult)
// 结果进入 surface,成为模型下一步推理的上下文

Harness 的工具执行流水线通过六个严格有序的阶段,构建了一条从权限决策到不可变结果的完整安全链。pre-execute 的可重排瀑布流提供了灵活的权限控制,单调 guard 确保权限只减不增,post-execute 允许结果审查和替换,finalizeContent 给予工具定义最后的调整机会。ToolExecutionToken 的不透明 Symbol 机制和 signal 的不可移除约束,则为整个流水线提供了运行时的安全边界。


本文基于 DeepSeek-Harness 官方文档编写,旨在提供权威的技术解读。

041 | 表达式索引与 JSONB 设计抉择:什么时候该跳过 GIN,以及怎么划那条混合模式的线

导读:上一篇你已经会选 GIN 的两种 opclass 了。这一篇回答两个更难的问题------当你的查询只盯着一两个键时,为什么 B 树 表达式索引能把 GIN 按在地上摩擦?以及,面对"新字段加列还是塞 JSONB"这个永恒抉择,到底该怎么诚实地划清混合模式的那条线。

JSONB 上的表达式索引

上一篇讲 GIN 时我们埋了一个伏笔:GIN 是查询需要探查很多不同键时的正确答案

那反过来------如果查询只探查一个键呢

这时候 GIN 就是过度设计。问题变成了:凭什么要为整个文档的每一条路径付索引成本,而应用其实只关心 director

答案是表达式索引 。思路和第 9 章的 LOWER(email) 一模一样,只不过作用对象是 JSONB 提取。B 树 索引为每一行存储 (metadata ->> 'director') 的结果,按序排好;规划器在任何使用同样表达式的查询上,都会用上它:

sql 复制代码
CREATE INDEX idx_movies_metadata_director
ON movies ((metadata ->> 'director'));

注意那对双括号 ------任何非平凡索引表达式都必需。少了它们,解析器把它当成列名;有了它们,它才识别出这是一个"逐行求值的表达式"。


表达式索引什么时候胜过 GIN

三种模式里,表达式索引完胜 GIN。

模式一:单热键查询

如果应用最热的 JSONB 查询是"按导演找电影 ",而同一个 metadata blob 里还住着一千个没人过滤的键------那么在 (metadata ->> 'director') 上建一个 B 树,比给整个文档建 GIN 更小、读更快、写上便宜得多

差别就是:索引一个"像列的东西" ,对比索引一本书里的每个词

模式二:范围和不等式查询

B 树 支持 <>BETWEEN 和有序扫描。GIN 不支持

sql 复制代码
WHERE (metadata ->> 'release_year')::int BETWEEN 2010 AND 2020

这种查询只有对 cast 后的值建的表达式索引能伺候:

sql 复制代码
CREATE INDEX idx_movies_metadata_year
ON movies (((metadata ->> 'release_year')::int));

cast 是索引的一部分。查询必须用同样的 cast,规划器才会匹配上。

模式三:排序

同样的道理。ORDER BY (metadata ->> 'rating')::numeric DESC LIMIT 20 是 B 树 的天然用法;GIN 伺候不了。表达式索引可以,计划里没有排序步骤


精确匹配规则,再来一次

这条规则你在第 9 章见过------表达式索引在普通列上的版本:规划器只有在查询表达式和索引表达式逐字节匹配时(允许少部分语义等价规则)才会使用表达式索引

应用到 JSONB:

  • metadata ->> 'director' 匹配 metadata ->> 'director'
  • 不匹配 metadata -> 'director'------因为 -> 返回 JSONB,->> 返回 text。在 (metadata -> 'director') 上建索引完全合法(它存的是 JSONB 子文档),但它只伺候用同一个 JSONB 返回表达式写的查询,不伺候->> 写的文本等值查询。
  • 不匹配 LOWER(metadata ->> 'director'),除非索引就建在 lowered 形式上。
sql 复制代码
-- Index on text extraction.
CREATE INDEX idx_movies_director ON movies ((metadata ->> 'director'));

-- Matches:
WHERE metadata ->> 'director' = 'C. Nolan';

-- Does not match (different operator, JSONB return):
WHERE metadata -> 'director' = '"C. Nolan"'::jsonb;

两条查询返回同一批行。规划器只为其中一条选索引,不为另一条。

所以做法是:挑一种规范化形式,为它建索引,应用里每个查询都用同一种写法。不一致的提取方式,是一个团队最后搞出"覆盖同一种查询的三个索引、规划器一个都不选"的根源。


JSONB 上的复合表达式索引

表达式索引可以是复合的 ,和任何普通 B 树 一样。表达式和列可以自由混搭,最左前缀规则照样适用

sql 复制代码
CREATE INDEX idx_movies_year_director
ON movies (
        release_year,
        (metadata ->> 'director')
    );

这个索引能伺候:

sql 复制代码
WHERE release_year = 2010 AND metadata ->> 'director' = 'C. Nolan'

也能伺候:

sql 复制代码
WHERE release_year = 2010

但不伺候

sql 复制代码
WHERE metadata ->> 'director' = 'C. Nolan'

因为前导列没有被过滤。

权衡和任何复合 B 树 一样:顺序重要,前导列是入口


同一条查询的对比

第 12 章 sandbox 的一次实战对比,把权衡量化清楚了。两个索引都能伺候 WHERE metadata @> '{"director":"C. Nolan"}' 风格的查找------代价天差地别

sql 复制代码
-- The GIN index covers every key in the document.
CREATE INDEX gin_full ON movies USING GIN (metadata jsonb_path_ops);
-- pg_relation_size('gin_full'): roughly 12 MB on 50k movies.

-- The expression index covers only the director key.
CREATE INDEX expr_director ON movies ((metadata ->> 'director'));
-- pg_relation_size('expr_director'): roughly 1.2 MB on the same data.

GIN 索引是表达式索引的十倍大。它能伺候更广的查询集合。

  • 如果应用只跑 导演查找------表达式索引付十分之一的存储、十分之一的写成本
  • 如果应用还跑 WHERE metadata @> '{"languages": ["fr"]}'WHERE metadata @> '{"awards": [{"name":"Oscar"}]}'------GIN 索引靠同时伺候这三个查询挣回了它的体重

为实际有的负载建索引

提示

一条好用的启发式:

  • 能说出你查的键(一到三个) → 建表达式索引。
  • 说不出来(应用随便探查文档,或键由用户定义) → 建 GIN。

大多数生产 schema 落在"我能说出它们"这一档。


表面列与 JSONB 尾巴的组合

最干净的模式------我们后面还会反复回到它------是把一个热键提升成真实列,剩下的留在 JSONB

表达式索引就是"所有东西都在 JSONB 里 "和"热字段是真实列 "之间的那座桥。它也是迁移里很有用的暂存步骤:1. 先上表达式索引 2. 看查询计划稳定下来

  1. 跑一次回填,把那个键提升成列
  2. 在添加列的同一个迁移里,把表达式索引删掉

GIN 和表达式索引之间的选择,不是非此即彼 。它是一个问题:**你实际查了多少文档?**而对大多数 schema,诚实的回答是"一个已知的小子集"。


JSONB 对决关系设计

JSONB 是个工具。和所有工具一样,它在替代方案输的时候才赢,而不是在那之前

在生产里用 JSONB 最难的部分,不是操作符,也不是索引 。是为每一块数据,诚实地在"写时给 schema (schema-on-write)"和"读时给 schema (schema-on-read)"之间做选择

那场永恒的对话

对话通常是这样的。一个新的字段到来了。团队有两个选项:

  1. 加一个真实列。写迁移。更新模型类。字段要查就加索引。
  2. 塞进现有 JSONB blob。上线。

选项二在周五下午更快。选项一几乎总是对的

迁移的成本付一次------在字段上线的那次部署里。JSONB 的成本永远付

  • 每一次从它里面提取的查询
  • 每一个要处理更宽文档的索引
  • 每一次在读取时发生的类型转换
  • 每一个要记得"哪个字段在 JSONB 里、哪个不在"的开发者

不是反对 JSONB 的论证 。这是"在它真正赢的地方用它"的论证。


JSONB 在哪里赢

四种模式里,JSONB 是对的选择,不是懒的选择

1. 真正 schemaless 的元数据

一部电影的元数据可能包括奖项、别名标题、各地区的配音工作室、各国的审查剪辑版本,还有一百样别的东西。可能字段的集合是开放的,每行都不一样。JSONB 就是这种数据的正确形状------应用把它当一个文档来读。

2. 数据库不过滤的只追加 blob

Webhook 载荷、审计记录、原始 API 响应。存下来,按主键查出来,渲染出去 。JSONB就行,因为没有索引需要理解它的内容

3. 用户自定义的自定义字段

那种 SaaS 产品------客户按租户加自己的字段 。schema 是真正动态的。JSONB 加一个 WHERE tenant_id = ? AND data @> ? 是对的工具,再配一个租户感知的 GIN 索引让它变快。

4. 版本化配置,旧版本的行还活在表里

把版本存在 JSONB 里,让应用在读取时处理迁移。克制使用------这是一种维护模式,不是"永远跳过迁移"的借口。


JSONB 在哪里输

五种模式里,JSONB 是错的呼叫

1. 外键关系

customer_id 塞在 JSONB 里,是一个数据库无法强制的字符串 。数据会漂移;级联删除不会发生;报表跑出来是错的。外键属于真实列

2. 应用要聚合的数字列

sql 复制代码
SUM((metadata ->> 'price')::numeric)

每一行都要 cast 一次 。在百万行上,这是可测的代价。正确的形状是 NUMERIC 列。

3. 应用要大规模排序或过滤的字段

热查询里 WHEREORDER BYGROUP BY 涉及的任何东西,都应该是列 。表达式索引是暂存步骤,不是终点

4. 严格类型的字段

release_year 在 JSONB 里是个数字------直到有人插入了 "2020" ,cast 就在生产里开始报错。JSONB 不在写入时强制类型,应用必须自己强制。

5. 应该是 NOT NULL 的字段

必填字段进真实列带 NOT NULL。可选字段可以住 JSONB。


混合模式

在负载下撑得住的模式是混合的真实列存键,JSONB 存尾巴

sql 复制代码
CREATE TABLE movies (
    id            BIGSERIAL   PRIMARY KEY,
    title         TEXT        NOT NULL,
    director      TEXT,
    release_year  INT,
    runtime_min   INT,
    metadata      JSONB       NOT NULL DEFAULT '{}'::jsonb
);

titledirectorrelease_yearruntime_min真实列

  • 它们有类型
  • 它们可以 NOT NULL(也可以故意不设)
  • 它们接受普通索引
  • 它们出现在 EXPLAIN 计划里没有提取步骤

metadataJSONB 。它装那些可变的、schemaless 的、低基数的、应用来渲染的字段:别名标题、奖项列表、语言元数据、原始海报------所有那些每部电影都不同、又不驱动查询的东西。


字段该放哪一边?四道提问

判断一个字段该放在线之上还是线之下,按顺序回答:

  1. 它在 WHEREORDER BYGROUP BY 里被查吗? → 真实列。
  2. 它总是存在吗? → 真实列带 NOT NULL
  3. 它是外键吗? → 真实列带约束。
  4. 它是你会聚合的数字吗? → 真实列。
  5. 以上都不是? → JSONB 就行。

这个模式能扩到一亿行而无需重写。查询计划干净,索引窄,JSONB 列小到------要么在尾巴上建 GIN,要么在"你没预料到会需要"的那几个键上建几个表达式索引------就处理了长尾,又没让它喧宾夺主。


JSONB 让你付出的代价

诚实记一笔账。每一个 JSONB 列都要付:

  1. 写入无类型 。插入 "2020" 而不是 2020 被默默接受。bug 在查询里冒头,不在列边界
  2. 文档内无约束 。JSONB 键上没有 CHECK、没有 FOREIGN KEY、没有 UNIQUE。(能建唯一表达式索引,但很拧巴。)
  3. 查询更贵。每一次读取都付一次提取步骤。
  4. 行更大。规范化的 JSONB 比紧凑的类型化列开销更大。
  5. 索引选择更窄。GIN 行,表达式索引行,但词汇比常规列小。
  6. 迁移更难 。改变 JSONB 的形状是一个 UPDATE,不是一个 ALTER。在一亿行表上,那是一个回填项目

重要提示

JSONB 在生产里最常见的失败模式是:那个从小处开始的 schema 长大了

一列开始时是一百字节的"可选字段尾巴",现在是一个五 KB 的文档,里面还藏着外键------团队在调试本不该慢的慢查询

解药永远是提取 :把热键提升成列。越早做,越便宜


一张具体的图

cinetrack 的 movies 表伪 schema,那条线划清楚:

sql 复制代码
movies
├─ id              BIGINT      PRIMARY KEY            <- relational
├─ title           TEXT        NOT NULL               <- relational
├─ director_id     BIGINT      REFERENCES directors   <- relational, FK
├─ release_year    INT         INDEXED                <- relational, hot filter
├─ runtime_min     INT                                <- relational, sometimes filtered
├─ rating_avg      NUMERIC(3,1)                       <- relational, aggregated
└─ metadata        JSONB                              <- schemaless tail
                   {
                     "languages": [...],
                     "alternate_titles": [...],
                     "awards": [...],
                     "production": {...},
                     "color_format": "...",
                     "aspect_ratio": "..."
                   }

线之上的每一个字段 :被查询、被排序、被连接、被聚合。 线之下的每一个字段:被渲染,不被查询。

GIN 索引 建在 JSONB 列上,让那些"罕见的、元数据驱动的查询"成为可能。B 树 索引建在驱动热路径的列上。

这就是混合模式的全部画面:热字段是带类型、带约束、带 B 树 的真实列;冷字段是带 GIN 的 schemaless 尾巴。两者各司其职,互不越界。


本篇小结

抉择 记住这一点
GIN 还是表达式索引 只查一两个键选表达式索引;键不定、用户定义选 GIN
表达式索引的精确匹配 查询表达式必须和索引表达式逐字节一致 ,cast、->/->> 都算
复合表达式索引 最左前缀规则照常适用
表达式索引的体积 同一查询,B 树 通常是 GIN 的十分之一
表达式索引的角色 "全在 JSONB "到"热字段是列"之间的桥,也是迁移的暂存步骤
JSONB 赢在哪 真 schemaless 元数据、只追加不查的 blob、用户自定义字段、版本化配置
JSONB 输在哪 外键、聚合数字、热排序/过滤字段、严格类型、NOT NULL 字段
混合模式 真实列存键,JSONB 存尾巴。能扩到一亿行而不重写
最大的失败模式 schema 从小长到大。解药永远是提取,越早越便宜

下一篇把这套规则落到一张真表上------cinetrack 的电影元数据,五万行,八个查询走一遍,看混合模式在真实计划里长什么样。


上一篇040 - JSONB 操作符与 GIN 索引 下一篇042 - cinetrack 电影元数据 JSONB 实战


常见问题答疑(学员答疑)

Q1:表达式索引和 GIN 索引都有办法加速 JSONB 查询,我怎么判断该建哪一个?

核心判断标准就一条:你知道要被查询的 JSONB 键是哪些吗? 如果你能说出一个到三个固定键------比如你的应用 90% 的 JSONB 查询都是 WHERE metadata ->> 'director' = ?------那 B 树表达式索引是正确答案。它更小(通常是 GIN 的十分之一)、写入更快、还支持范围查询和排序。如果你说不出来------比如你的应用允许用户自定义字段搜索,或者键名本身是动态的------那 GIN 索引是唯一出路。一个实际的经验数据:在 5 万行数据上,GIN 索引约 12 MB,而覆盖同一个 director 键的 B 树表达式索引约 1.2 MB。差了一个数量级。所以绝大多数生产场景里,答案其实是"建表达式索引",因为你大概率知道哪些键是热的。

Q2:文章说"混合模式"是最好的方案,那我已经把所有字段都塞进 JSONB 了,怎么迁移出来?

这是所有走过头了的团队都要面对的问题。迁移路线是渐进的,不需要一步到位。第一步:先识别出热查询中涉及的那几个 JSONB 键------通常是 WHEREORDER BYGROUP BY 中的键。第二步:先在那些键上建表达式索引作为过渡工具,立刻把查询延迟降下来(这个改动零风险,只需一条 CREATE INDEX)。第三步:安排一个窗口期,用 ALTER TABLE ADD COLUMN 加真实列,再用一条批量 UPDATE 回填数据。第四步:修改应用代码指向新列,确认稳定后删掉表达式索引。关键在于这个过程是渐进的、可回滚的------每次只做一个键,每次变更都小到可以单独验证。不要试图一次把所有键全提出来,那会把一个可控的迁移变成一场冒险。

Q3:varchar(255) 在 MySQL 里是惯例,为什么在 Postgres 里这个习惯有害?

MySQL 的 varchar(255) 是一个历史编码技巧------它刚好能让行前缀索引在特定场景下生效。Postgres 里没有这个底层限制:textvarchar(255)varchar(1000) 底层存储一模一样,没有任何性能差异。你写的 varchar(255) 只是在每次 INSERT 和 UPDATE 时多执行了一次长度检查,白白交了一个微小的"比较税",却没给你带来任何真正的约束保护。真正有意义的约束是 CHECK 或业务驱动的长度限制------比如用户名的 50 字符上限、商品标题的 200 字符上限------这些限制反映了真实的业务规则,而不是某个数据库的行格式遗留产物。在 Postgres 里,要么用 text (无限制),要么用 varchar(N) 配合一个确实存在的业务规则。

第二十七篇:自托管Honcho------本地部署与配置指南

数据合规要求严格?不想用云服务?Honcho是开源的------你可以完全自托管。这篇博客带你走通本地部署。

为什么要自托管?

  • 数据合规:某些行业/地区要求数据不出内网
  • 成本控制:超大规模使用时托管费用可能很高
  • 定制需求:需要自定义嵌入模型或推理配置
  • 离线能力:在没有外网的环境中运行

前置条件

自托管Honcho需要:

  • Docker 和 Docker Compose
  • Python 3.10+(如果要运行SDK)
  • 至少一个LLM API Key(OpenAI、Anthropic或自定义端点)

快速启动

bash 复制代码
# 克隆Honcho仓库
git clone https://github.com/plastic-labs/honcho.git
cd honcho

# 复制环境变量模板
cp .env.example .env

# 编辑.env文件,填入你的配置
# 必需的配置项:
# - LLM API密钥(如OPENAI_API_KEY)
# - 数据库连接(默认使用Docker Postgres)

# 启动所有服务
docker compose up -d

环境变量配置

env 复制代码
# .env 文件

# LLM配置
OPENAI_API_KEY=sk-your-key-here
# 或使用Anthropic
ANTHROPIC_API_KEY=sk-ant-your-key-here

# 数据库
POSTGRES_USER=honcho
POSTGRES_PASSWORD=your-secure-password
POSTGRES_DB=honcho
DATABASE_URL=postgresql://honcho:your-secure-password@db:5432/honcho

# API服务
HONCHO_API_KEY=your-local-api-key
API_HOST=0.0.0.0
API_PORT=8000

# Worker配置
WORKER_CONCURRENCY=4

# 嵌入模型
EMBEDDING_MODEL=text-embedding-3-small
EMBEDDING_DIMENSION=1536

连接到本地实例

python 复制代码
from honcho import Honcho

# 连接到本地实例
honcho = Honcho(
    base_url="http://localhost:8000",  # 你的本地API地址
    api_key="your-local-api-key",
    workspace_id="my-local-app"
)

# 用法和托管版完全一样
user = honcho.peer("user-123")
session = honcho.session("test-session")
session.add_peers([user])
session.add_messages([user.message("Hello from local Honcho!")])

配置指南

更换嵌入模型
env 复制代码
# .env
EMBEDDING_MODEL=text-embedding-3-large
EMBEDDING_DIMENSION=3072

更换嵌入模型后,已有的向量数据需要重新生成。参考官方的"Changing Embeddings"文档了解迁移步骤。

自定义LLM端点
env 复制代码
# 使用自定义LLM端点(如本地部署的模型)
LLM_BASE_URL=http://localhost:11434/v1
LLM_MODEL=llama3
LLM_API_KEY=not-needed
调整推理配置
env 复制代码
# Deriver配置
DERIVER_MODEL=gpt-4o-mini
DERIVER_BATCH_SIZE=1000  # Token批处理阈值

# Summarizer配置
SUMMARY_SHORT_INTERVAL=20
SUMMARY_LONG_INTERVAL=60
SUMMARY_SHORT_TOKEN_LIMIT=1000
SUMMARY_LONG_TOKEN_LIMIT=4000

# Dreamer配置
DREAM_MIN_CONCLUSIONS=50
DREAM_COOLDOWN_HOURS=8
DREAM_IDLE_TIMEOUT_MINUTES=60

常见问题排查

问题一:推理任务积压
bash 复制代码
# 检查Worker状态
docker compose logs worker

# 如果Worker没有正常运行
docker compose restart worker

# 增加Worker并发
# 修改.env中的WORKER_CONCURRENCY=8(或更高)
docker compose up -d  # 重启以应用新配置
问题二:数据库连接失败
bash 复制代码
# 检查Postgres是否运行
docker compose ps db

# 查看数据库日志
docker compose logs db

# 如果端口冲突,修改docker-compose.yml中的端口映射
问题三:LLM API调用失败
bash 复制代码
# 验证API Key
curl https://api.openai.com/v1/models \
  -H "Authorization: Bearer $OPENAI_API_KEY"

# 检查API服务日志
docker compose logs api | grep -i error

生产部署建议

yaml 复制代码
# docker-compose.prod.yml 摘要
services:
  api:
    deploy:
      replicas: 2  # 多实例API
    environment:
      - WORKER_CONCURRENCY=8
  
  worker:
    deploy:
      replicas: 4  # 多Worker并行推理
  
  db:
    volumes:
      - honcho_db_data:/var/lib/postgresql/data
    deploy:
      resources:
        limits:
          memory: 4G  # 数据库内存限制

监控

bash 复制代码
# 查看所有服务状态
docker compose ps

# 实时日志
docker compose logs -f api worker

# 检查队列状态
curl http://localhost:8000/v3/workspaces/default/queue-status \
  -H "Authorization: Bearer your-api-key"

Q&A

Q1:自托管的成本跟托管版比起来如何?什么时候该选自托管?

A:自托管的成本主要是:LLM API调用费(跟托管版一样,你需要提供自己的API Key)+ 服务器费用。如果你每月LLM API费用超过 500,且用户量大,自托管可能更经济------因为托管版在此基础上还要加服务费。但如果你团队规模小、没有DevOps能力,托管版的便利性远超节省的成本。选择标准:数据合规要求→必须自托管;月LLM费用<500,且用户量大,自托管可能更经济------因为托管版在此基础上还要加服务费。但如果你团队规模小、没有DevOps能力,托管版的便利性远超节省的成本。选择标准:数据合规要求→必须自托管;月LLM费用< 500,且用户量大,自托管可能更经济------因为托管版在此基础上还要加服务费。但如果你团队规模小、没有DevOps能力,托管版的便利性远超节省的成本。选择标准:数据合规要求→必须自托管;月LLM费用<500→托管版更划算;有专职运维→可以考虑自托管。

Q2:自托管可以用开源模型做推理吗?比如用本地部署的Llama?

A:可以。Honcho支持自定义LLM端点------通过环境变量配置本地部署的模型。但要注意:1)推理质量取决于模型能力------Honcho的自定义推理模型(Neuromancer XR等)是专门训练的,用通用开源模型替代可能降质量;2)如果你只替换"生成LLM"(如Chat端点的答案合成),保留Honcho的自定义推理模型,质量影响较小。如果你想把推理模型也换成开源模型,需要走更深入的定制路径,官方建议联系他们讨论。

Q3:自托管如何升级Honcho版本?

A:标准流程:1)备份数据库(docker compose exec db pg_dump);2)拉取最新代码(git pull);3)检查changelog确认有没有breaking changes;4)重启服务(docker compose up -d),Docker会自动构建新镜像。如果有数据库migration,API服务启动时会自动执行。建议在非生产环境先测试升级。官方提供"SDK and API Compatibility Guide"帮助判断升级影响。


大模型日报-2026-09-01

1. 科大讯飞今日开源星火X2.5两款端侧大模型,打响"端侧战争"第一枪 科大讯飞于9月1日开源星火X2.5-4B和星火X2.5-1.7B两款端侧通用大模型,原生支持最长1M token上下文窗口,重点提升智能体、数学和通用理解等核心能力,面向车载、智能硬件、万物互联等端侧场景提供支持。9月7日还将正式发布星火X2.5(293B)基座模型,进一步升级代码、智能体等核心能力。业内评价这是国产大模型从"拼参数"转向"拼落地"的战略转折点。

2. 我国首个AI客服国标今起实施,"已读乱回"经营者将承担全责 9月1日起,国家标准《顾客联络服务 人工与智能客户服务协同要求》正式实施。这是我国首个聚焦人工客服与智能客服协同机制的国家标准,针对消费者长期诟病的AI客服"答非所问""转人工难""承诺不认账"等问题给出明确规范。随着大模型技术快速落地,AI客服乱象有望得到系统性整治。

3. "Token贷"落地:银行将大模型Token消耗量纳入授信参考指标 随着人工智能产业快速迭代,算力成为数字经济时代最核心的生产力之一。近期多家银行推出"Token贷"产品,将企业日常消耗的算力Token作为授信参考指标,为缺乏传统抵押物的轻资产科创企业打开融资新空间。此前广东省已落地首个词元经济专项金融产品"中银·算力Token贷",折射出银行授信从"看资产"到"看算力"的新趋势。

4. 全国首个化工行业AI大模型3.0 Pro在大连发布 8月31日,中科院大连化物所联合科大讯飞、阿里云等发布"智能化工大模型3.0 Pro",搭建"大模型---智能体---专业技能与工具---应用场景"四层体系,从过去的"能理解、会回答"升级为"能规划、会执行、可验证",并揭牌智能化工创新中心,打通实验室到工厂的转化链条,标志垂直行业大模型进入实质落地阶段。

5. OpenAI 9月DevDay定档9月29日,GPT-6悬念引爆全球AI圈 OpenAI官方宣布年度开发者盛宴DevDay定于2026年9月29日在旧金山举行,全程线上直播。业界普遍预期GPT-6将在此次大会上亮相,被视为2026年最大的技术悬念。此前报道显示,OpenAI已提交S-1上市申请,CEO奥特曼表示新一代旗舰模型将"第一个真正意义上发明新事物的模型",进一步逼近AGI门槛。

2026年重磅喜讯! 喜报!热烈祝贺Gavin大咖人工智能领域经典著作《企业级ChatGPT AI大模型应用开发实战(1000分钟视频)》中国水利水电出版社发行上市!

内容提要

本书内容基于作者在硅谷 ChatGPT 项目及企业培训中的实战经验凝练而成,重点介绍企业级 ChatGPT 开发的核心技术、案例研究及最佳实践。全书共 16 章,分为基础篇和实战篇两大部分。

基础篇:

介绍 ChatGPT 底层架构 Transformer 技术及源码实现、GPT 的内部机制及源码实现、GPT 系列模型原理与应用:从 GPT-2 到 GPT-4 等内容。

实战篇:

介绍基于 ChatGPT 的端到端语音聊天机器人项目实战,企业级 ChatGPT 开发的三大核心内部机制及案例实战,ChatGPT 插件的内部机制、源码及案例实战,ChatGPT 提示词开发实战,思维链及 ReAct 解析与实战,提示词本质解析及评估实战与源码解析,LangChain 大模型框架的七大核心组件及案例解析(上、下),LangChain 代理深入解析及源码解析,AutoGPT 源码解析及综合案例实战,使用 LangChain 构建问答聊天机器人案例实战,构建基于大模型的自治代理案例,Llama 2 模型与 LangChain 项目详解。书中每个知识点均配有相应的实现代码和实例。

本书适合有一定 Python 基础的 ChatGPT 爱好者阅读,主要面向从事大模型应用开发、机器学习、数据挖掘或深度学习的专业人员,高等院校相关专业的师生,以及相关领域的科研人员。

本书附赠丰富的学习资源,具体如下:①同步学习资源,即 16 集同步教学视频,视频时长共计约 1000 分钟;②教师授课的辅助资源,即 187 个案例知识点、15 个项目实战的全部源代码。

前言

在当今快速发展的科技时代,人工智能(artificial intelligence,AI)技术正以惊人的速度改变着人们的生活和工作方式。在这个新时代的浪潮中,大模型技术成为AI领域的一颗耀眼新星。ChatGPT作为大模型技术的重要应用之一,正在引领着人机交互领域的革新浪潮。本书将带领读者深入探索大模型新时代,通过ChatGPT实战项目和内部解析,深入掌握基于ChatGPT的大模型应用开发领域的关键技术,并解密ChatGPT的底层架构和实现原理。

本书主要内容

本书通过ChatGPT实战项目的方式,为读者呈现一个全面、系统的学习路径,从基础知识的介绍开始,带领读者深入了解ChatGPT的工作原理和实际应用。本书非常适合具备Python基础的读者学习。

全书共16章,分为基础篇和实战篇两大部分。 基础篇包括第1~3章;实战篇包括第4~16章。

第1章 ChatGPT底层架构Transformer技术及源码实现,详解最大似然估计、最大后验概率、贝叶斯Transformer及自编码与自回归语言模型的内部机制。

第2章 GPT的内部机制及源码实现,剖析GPT运行机制、掩码机制、Decoder-Only模式,详解数据流动生命周期及GPT-2源码。

第3章 GPT系列模型原理与应用:从GPT-2到GPT-4,解析ChatGPT提示词流程、GPT-2运行机制,可视化解读GPT-3/4的内部机制。

第4章 基于ChatGPT的端到端语音聊天机器人项目实战,涵盖ChatGPT API开发、前后端构建(ReAct+FastAPI)及项目优化。

第5章 企业级ChatGPT开发的三大核心内部机制及案例实战,解析企业级开发核心,演示Notion问答对话AI案例。

第6章 ChatGPT插件的内部机制、源码及案例实战,详解插件工作原理、检索插件源码及全流程开发实战。

第7章 ChatGPT提示词开发实战,基于LangChain框架的提示词、思维链、链式提示词及模型评估开发。

第8章 思维链及ReAct解析与实战,剖析思维链推理、ReAct技术原理、框架源码及案例实战。

第9章 提示词本质解析及评估实战与源码解析,包含问答评估、代理评估源码解析及提示词本质探讨。

第10~11章 LangChain大模型框架的七大核心组件及案例解析(上、下),涵盖模型、词嵌入、提示词、内存、回调、数据连接、代理等核心组件及聊天机器人综合案例。

第12章 LangChain代理深入解析及源码解析,详解代理工作原理及AutoGPT源码解析。

第13章 AutoGPT源码解析及综合案例实战,剖析AutoGPT内部机制及其在LangChain代理、内存、PromptGenerator中的应用。

第14章 使用LangChain构建问答聊天机器人案例实战,涵盖GPT-4代码生成全流程及LangChain开发实战。

第15章 构建基于大模型的自治代理案例,详解自治代理原理、工具、示例及开源实现源码。

第16章 Llama 2模型与LangChain项目详解,包括模型部署(Replicate)、Hugging Face/LangChain实践、检索增强生成及自定义提示词RetrievalQA开发。

本书特色

●深入探索,全面剖析。 本书涵盖ChatGPT案例实战、LangChain项目实战及框架源码解析等多个层面的内容。每章都深入探讨相关技术与案例,并提供源码解析,使读者能够全面了解ChatGPT和LangChain等技术的内部机制与开发原理,为实际项目的应用提供有力指导。

●实战剖析,项目揭秘。 本书每章都提供具体的案例实战与项目解析,引导读者通过实际操作和代码理解技术细节和底层逻辑。通过理论结合实践的方式,使读者能够更好地运用所学知识,深入了解项目和框架的实现细节。

●前沿突破,技术驱动。 本书介绍了一系列突破性的技术,如ChatGPT、LangChain、Transformer、Prompt、Llama 2、AutoGPT、BabyAGI、CoT、ToT、ReAct、MRKL等。通过对这些技术的深入剖析,读者可以了解相关技术的发展和应用,并了解它们在实际项目中的具体应用场景和效果。

●源码解析,细致讲解。 本书对LangChain框架的关键技术进行了逐行源码剖析。读者可以深入理解源码实现和机制原理,从而更好地理解技术细节和底层逻辑,并将其应用于实际开发工作中。

本书还为读者提供了丰富的知识和实用的技能,帮助读者在ChatGPT和LangChain领域取得突破性的进展。无论是初学者还是有一定经验的开发者,都可以从本书中获得有价值的学习资源。

配套资源

为便于教与学,本书配有同步教学视频(约1000分钟)、源代码、数据集、教学课件、教学大纲、安装程序。

作者简介

王家林

美国斯坦福大学计算机专业毕业。曾在美国担任硅谷顶级机器学习和人工智能实验室主任、杰出AI工程师及首席机器学习工程师,专精于对话式人工智能(conversational AI)。现担任硅谷某知名对话机器人公司CTO,自2019年起专注于基于红队测试(red teaming)的责任型AI(responsible AI),并热衷于构建生成式AI/大语言模型教练系统(GenAI/LLM coaching systems)。在硅谷任职期间,曾领导多个GenAI/LLM解决方案项目,成功平衡企业业务需求下的大模型推理(reasoning)系统与幻觉(hallucinations)及偏见(biases)风险的最小化。

作为数据科学、机器学习、NLP、ChatGPT及大模型等领域25本书的主要作者,王家林对利用人工智能提供解决方案,以及通过机器学习驱动的NLP与LLM流程帮助组织实现数据驱动决策充满热情。他曾领导Apple、PayPal、Chase Bank、Faethm、LinkedIn等公司的11个重大NLP项目。

在NLP、对话式AI、大数据及基于AWS的无服务器(serverless)技术方面,拥有丰富的机器学习咨询经验。

段智华

中国电信股份有限公司上海分公司高级工程师。长期从事大模型与智能体技术领域,专注Agentic AI、Harness Agent等前沿方向研究。

新书购买链接

《企业级ChatGPT AI大模型应用开发实战(1000分钟视频)》 购买链接:item.jd.com/15389212.ht...

相关推荐
涛涛ing2 小时前
OpenAI Astra 泄露:零样本生成 3D 网页,前端开发者慌了吗?
前端
ssshooter3 小时前
现在网页都能提供 MCP 了?!
前端·人工智能·程序员
杉氧3 小时前
状态管理变迁史:为什么我们放弃了 Redux 选择 Zustand?
android·前端·react native
cidy_983 小时前
OpenCode 手动配置火山方舟 Agent Plan 教程
前端
鹏多多3 小时前
PC 网站接入微信登录,这 10 个坑我替你踩完了!
前端·javascript·vue.js
律宏阔4 小时前
微信小程序使用 Orval + OpenAPI 自动生成接口:Axios 兼容踩坑记录
前端·微信小程序
律宏阔4 小时前
微信小程序集成 TDesign 完整记录:解决 NPM packages not found
前端·微信小程序
律宏阔4 小时前
微信小程序 ECharts 瘦身实战:分包异步化 + componentPlaceholder 避开主包 2MB 限制
前端·微信小程序
夏天要喝冰可乐4 小时前
从 Idea 到开源插件:我用 Vibe Coding 做了「文章摆渡」
前端·ai编程·vibecoding