将 Sanity stale-content-digest 定时函数适配到自有 Schema:从 LLM 提示词到蓝图部署的完整实战

发布时间:2026/10/29 13:21:41

将 Sanity stale-content-digest 定时函数适配到自有 Schema:从 LLM 提示词到蓝图部署的完整实战 将 Sanity stale-content-digest 定时函数适配到自有 Schema从 LLM 提示词到蓝图部署的完整实战【免费下载链接】sanitySanity Studio – Rapidly configure content workspaces powered by structured content项目地址: https://gitcode.com/GitHub_Trending/sa/sanity本指南以examples/functions/stale-content-digest示例中的 LLM 适配提示词PROMPT.md为核心讲解如何把一份周一定时扫描过时内容 → 交给 Sanity Content Agent 审查 → 推送 Slack 摘要的 Sanity Function 配方从内置的movie演示模型改造成你自己的内容模型。读完你不仅能跑通两条接入路径moviedb 演示与已有项目还能掌握 GROQ 查询改写、TypeScript 接口同步、Agent 指令定制这三大改造点的底层原理并完成本地测试与生产部署。一、这个函数解决什么问题内容会悄悄过时引用过期、表述失真、链接失效编辑团队往往要等读者投诉才发现。人工巡检内容新鲜度既枯燥又难以持续。stale-content-digest正是针对这一场景的调度函数配方——每个周一早上它扫描数据集中长时间未更新的文档把摘要交给 Sanity Content Agent 审查再把过时清单推送到 Slack。它把 Sanity 的三项能力打包进一条工作流Scheduled Functions定时函数服务端 cron无需自建基础设施Agent Actions代理动作Content Agent 逐篇阅读文档并说明哪里看起来过时Slack 集成结论直接落到编辑团队日常所在的频道里。从 README.md 的定位看收益是及早发现漂移、每周仅一条低噪音消息、AI 代替人读完全部候选文档、零基础设施。二、前提条件Node.js v22.x启用了Functions和Agent Actions的 Sanity 账号。注意 Agent Actions 属于实验特性运行在vXAPI 通道源码中API_VERSION vX即为此注释见 index.tsSanity CLInpx sanity即可无需全局安装一个可以安装 bot 的 Slack 工作区需要管理员或应用安装权限。三、快速启动两条接入路径根据你是否已有 Sanity 项目选择两条路径之一两者共用下面的 Slack App 配置小节。路径 A用 moviedb 示例快速演示配方出厂时预接moviedbstarter一个带 Portable Textoverview字段的movie文档类型以及一份真实电影样例数据集。mkdir movies-project cd movies-project npx sanity init --template moviedb --import-dataset --output-pathstudioCLI 会依次询问组织、项目名和数据集。--output-pathstudio会把 Studio 代码放到./studiomovies-project/成为项目根目录后续命令都在此执行。接着初始化蓝图并添加配方npx sanity blueprints init npx sanity blueprints add function --example stale-content-digest第二条命令会把函数代码和一个半成品蓝图资源脚手架到functions/stale-content-digest/下一步需要手动补全蓝图。随后用下面的 蓝图参考配置 替换sanity.blueprint.ts并创建.envPROJECT_IDyour-sanity-project-id DATASETproduction SLACK_OAUTH_TOKENxoxb-your-bot-token SLACK_CHANNEL#your-test-channel DAYS_SINCE0PROJECT_ID可在studio/sanity.config.ts中找到或运行npx sanity projects list。DAYS_SINCE0会让所有电影都够格算作过时保证首次运行一定有输出。安装依赖——注意这里有两层项目根需要dotenv蓝图靠它加载环境变量moviedb starter 不自带而函数目录有自己独立的package.json内含sanity/client、sanity/functions、slack/web-api项目根的安装不会触及它npm install dotenv cd functions/stale-content-digest npm install cd ../..本地跑一次npx sanity functions test stale-content-digest --dataset production --with-user-token--with-user-token会把已登录 Sanity CLI 配置里的认证注入运行时让函数内的sanity/client能读取数据集。如果一切正常Slack 里会收到一份对各电影 overview 的毒舌点评。路径 B接入你已有的 Sanity 项目已有 Studio 和待审内容时走这条路径。在包含或希望存放Blueprint 配置的目录打开终端通常与 Studio 配置同级或上一级。然后完成下方 Slack App 设置若无蓝图则npx sanity blueprints initnpx sanity blueprints add function --example stale-content-digest打开sanity.blueprint.ts按 蓝图参考配置 更新若已有其他资源把defineRobotToken和defineScheduledFunction加进现有resources数组适配函数到你的 Schema本指南核心见 第六节创建或追加.envPROJECT_IDyour-sanity-project-id DATASETproduction SLACK_OAUTH_TOKENxoxb-your-bot-token SLACK_CHANNEL#content-team DAYS_SINCE180 STUDIO_URLhttps://your-studio.sanity.studioSTUDIO_URL可选设置后每条 Slack 发现都会带上打开对应文档的 Studio 深链。安装依赖同上两条命令本地运行同上npx sanity functions test命令。交互式迭代可把test换成dev若数据集太新导致查不出结果可临时把DAYS_SINCE调成0。四、蓝图配置与环境变量配方完整的sanity.blueprint.ts参考如下来自 README.md 的 Blueprint reference 小节import {defineBlueprint, defineRobotToken, defineScheduledFunction} from sanity/blueprints import dotenv/config import {env} from node:process const {PROJECT_ID, DATASET, DAYS_SINCE, SLACK_OAUTH_TOKEN, SLACK_CHANNEL, STUDIO_URL} env export default defineBlueprint({ resources: [ defineRobotToken({ name: stale-content-digest-robot, label: Stale Content Digest Robot, memberships: [ { resourceType: project, resourceId: PROJECT_ID, roleNames: [viewer], }, ], }), defineScheduledFunction({ name: stale-content-digest, src: ./functions/stale-content-digest, event: {expression: 0 8 * * 1}, timezone: UTC, memory: 1, timeout: 30, env: { PROJECT_ID, DATASET, DAYS_SINCE, SLACK_OAUTH_TOKEN, SLACK_CHANNEL, STUDIO_URL, }, robotToken: $.resources.stale-content-digest-robot.token, }), ], })要点robot token 被授予项目viewer角色只读即可完成查询cron 表达式0 8 * * 1表示每周一 08:00 UTC 运行robotToken: $.resources.stale-content-digest-robot.token是 JSONPath 引用把 robot token 注入函数运行时环境。函数目录下的 package.json 也内嵌了一份等价的blueprintResourceItem描述memory、timeout、cron、env 透传清单供blueprints add脚手架使用。环境变量一览变量说明必填PROJECT_IDSanity 项目 ID。蓝图 robot token 使用它函数客户端也直接读取定时函数处理器不会通过context.clientOptions拿到projectId。可在studio/sanity.config.ts或npx sanity projects list中找到是DATASET要查询的数据集如production由函数客户端直接读取是SLACK_OAUTH_TOKENSlack bot tokenxoxb-...是SLACK_CHANNEL频道名如#content-team是DAYS_SINCE过时阈值天数默认180否STUDIO_URLStudio 基础 URL设置后每条发现会附带文档深链否NOTIFY_WHEN_EMPTY设为true时即使没有发现也会发一条无过时内容消息默认false否SANITY_AUTH_TOKEN函数客户端用 API token。仅在不使用--with-user-token、且尚未部署 robot token 的场景如直接node调用才需要否五、Slack App 设置需要一个可投递摘要的 bot token在 Slack 应用管理页面点击Create New App → From scratch命名并选择工作区在OAuth Permissions → Bot Token Scopes中添加chat:write权限点击Install to Workspace完成安装复制 Bot User OAuth Token以xoxb-开头作为SLACK_OAUTH_TOKEN在摘要要落地的频道里运行/invite your-app-name把该频道名带#填入SLACK_CHANNEL。六、核心用 PROMPT 把函数适配到你的 Schema这是整个配方的灵魂所在。函数出厂指向movie文档类型和单个 Portable Textoverview字段而你的内容模型几乎必然不同。适配有两种姿势源码层面都收敛到 PROMPT.md 描述的步骤上编码 Agent推荐在项目根目录打开 Claude Code、Cursor 或 Codex直接说adapt functions/stale-content-digest/ to my schema。函数目录自带一份 AGENTS.md编码 Agent 会自动发现它并遵循其中指引先读 schema再改 GROQ 查询、TypeScript 接口与 Agent 指令。若多个类型都符合条件Agent 会反问你要定位哪个聊天式 LLM把 PROMPT.md 整份粘贴进 ChatGPT 或 Claude.ai。最好配合 Sanity MCP 使用让 LLM 能直接读你的 schema对应list_workspace_schemas与get_schema工具手改按 README 的 Customization 小节改 index.ts 的三处。无论哪种方式PROMPT 的核心流程都是先填两个占位符再走四步。占位符是TARGET DOCUMENT TYPE: fill in, e.g. documentation TARGET FIELDS: fill in one or more comma-separated fields to review for staleness, e.g. body or title, lead, body步骤 1先验证目标不要凭空发明确认你点名的文档类型和每个字段确实存在于 Sanity schema 中。优先用 Sanity MCP 的list_workspace_schemas和get_schema否则直接读 schema 文件通常在schemaTypes/或schemas/下。对每个字段记下它的_typestring、text、Portable Text 数组、字符串数组等——GROQ 投影怎么写取决于它。如果类型或任一字段不存在停下来请用户纠正而不是自行臆造字段名。这一点在 AGENTS.md 中被反复强调不要发明文档类型或字段名编辑前必须确认它们真实存在。步骤 2改 index.ts 的三处README 的 Customization 同源a. GROQ 查询STALE_QUERY常量见 index.ts。把_type movie换成你的类型投影出标题等价字段和每个目标字段。投影规则按字段类型决定字段类型GROQ 投影写法普通 string / textmyField或重命名Portable Text 数组myField: pt::text(myField)字符串数组myField: array::join(myField, )其他对象、引用等停下来问用户希望如何展平为纯文本如果你给了多个字段每个字段都要在 GROQ 里单独投影到自己的键名下不要预先拼接——Agent 提示词和 TypeScript 接口会分别引用它们。b. TypeScript 接口文件顶部的Movie见 index.ts。重命名它并把字段类型改成与查询返回值一致。c. Agent 指令提示词传给 agent action 的instruction字段见 index.ts。把毒舌影评人人设替换成贴合你内容类型的角色并且要明确写出你所在领域的过时长什么样——比如文档类是过时的 API 引用、营销内容类已失效的促销、资源页类断裂的链接。JSON 输出 schema 保持不变instruction: You are a content auditor. Review these articles: $documents. Flag overviews with outdated references, broken claims, or missing recent context. Respond in JSON: { findings: [{ title: ..., issue: ..., priority: high|medium|low }] }步骤 3更新用户可见文案index.ts里的日志消息和 Slack 消息头把 stale movies 换成 stale [你的内容类型]。对应源码中的Found ${stale.length} stale moviesindex.ts与*${findings.length} stale movies need attention*index.ts等处。步骤 4更新 Studio 深链如果文档类型的 slug 与movie不同需要改formatSlackMessage里的深链路径——源码中是${STUDIO_URL}/structure/movie;${id}|open in Studioindex.tsmovie即为文档类型 slug。完成后让 Agent 展示 diff并让它根据你的数据集给出首个可用的DAYS_SINCE建议。七、源码级拆解函数内部如何工作要真正理解这三处改动值得通读 index.ts 的完整执行链路入口export const handler scheduledEventHandler(async ({context}) {...})index.ts。scheduledEventHandler来自sanity/functions把函数包装成定时事件处理器客户端构造与文档事件处理器不同定时处理器不会从context.clientOptions拿到projectId/dataset只有 token。因此源码特意从 env经蓝图env块透传读取项目与数据集再从context.clientOptions?.token ?? SANITY_AUTH_TOKEN取 tokenindex.ts。这解释了为什么PROJECT_ID在环境变量表中是必填项也对应 README 排错第一条Configuration must contain projectId查询client.fetchMovie[](STALE_QUERY, {daysSince})执行 GROQdateTime(_updatedAt) dateTime(now()) - 60*60*24*$daysSince实现N 天未更新过滤空结果分支无过期文档时除非NOTIFY_WHEN_EMPTY true否则直接 return 不发 Slackindex.tsAgent 调用client.agent.action.prompt({instruction, instructionParams: {documents: JSON.stringify(stale)}, format: json})index.ts——$documents是模板变量被替换成序列化后的过时文档数组format: json要求结构化输出与Analysis接口{findings: Finding[]}对应消息格式化formatSlackMessage用标题到_id的 Map 把 Agent 返回的 finding 映射回文档并依STUDIO_URL决定是否生成深链index.ts发送new WebClient(SLACK_OAUTH_TOKEN).chat.postMessage({channel: SLACK_CHANNEL, text})index.ts。八、自定义与调优1. 把查询指向你的文档类型const STALE_QUERY *[_type post dateTime(_updatedAt) dateTime(now()) - 60*60*24*$daysSince]{ _id, title, _updatedAt, body: pt::text(body) }投影按字段类型选择同上表普通字符串直接投影Portable Text 用pt::text字符串数组用array::join更复杂的结构对象、引用在投影里先展平成字符串让 Agent 读到的永远是纯文本。2. 重写提示词贴合你的内容毒舌人设只是演示趣味。真实编辑场景应点名团队关心的具体过时形态并给出明确的 JSON 输出示例见第六节步骤 2c 的示例。收紧 JSON schema、给出期望输出样例也是排错中Agent 返回非法 JSON的标准解法。3. 调整调度改蓝图里的 cron 表达式即可event: { expression: 0 9 * * 1-5 } // every weekday at 09:00其他旋钮多类型把_type movie换成_type in [post, page, guide]换过时信号把_updatedAt换成自定义字段如lastReviewedAt更丰富的 Slack 排版把chat.postMessage换成 Block Kit 块。九、部署到生产本地测试无需部署即可验证逻辑要让函数真正按计划跑起来需要部署。关键认知定时函数位于组织级organization-scopedBlueprint而非项目级。首次部署前要先提升栈npx sanity blueprints promote提升是单向的已有项目级资源保持项目级新的定时函数落到组织级。随后npx sanity blueprints plan # 可选预览将被创建/更新/删除的资源 npx sanity blueprints deployblueprints plan是干跑不会改动栈。CI 里部署组织级栈目前需要个人用户 token不适合共享 CI runner因此在平台支持自动化组织级部署前请从开发者本机部署。十、本地测试与排错迭代时在test与dev间切换test跑单次dev提供交互式开发模式。常见问题速查详见 README.md 的 Troubleshooting 小节症状原因解法Configuration must contain projectId定时处理器不从context.clientOptions拿projectId而 env 中缺失或未加载PROJECT_ID确认.env有PROJECT_ID且蓝图函数env块透传了它有内容却没查出staleDAYS_SINCE对数据集年龄过大或 GROQ 过滤器不匹配类型调低DAYS_SINCE首次可试0核对类型与字段名Slack 收不到消息bot 不在目标频道或 token 缺chat:write在频道/invite your-app-name在 Slack 应用 OAuth 页核对 scopeAgent 返回非法 JSON提示词对模型太开放收紧 instruction 中的 JSON schema给出期望输出示例函数超时过期文档太多Agent 调用是瓶颈提高蓝图timeout、分批处理文档或收窄查询十一、相关示例同目录下还有可交叉参考的配方Auto-Summary 用 Content Agent 在每次更新时生成摘要展示了agent.action.generate配合target/documentId写回文档的用法Slack Notify 演示文档创建时推送 SlackStale Products Analysis 则是文档触发式的电商内容新鲜度分析展示了更复杂的嵌套 GROQ 投影modules网格内的产品引用展平与不同的过时判定逻辑可作为把本配方扩展到复杂模型的参考。【免费下载链接】sanitySanity Studio – Rapidly configure content workspaces powered by structured content项目地址: https://gitcode.com/GitHub_Trending/sa/sanity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/29 8:59:37

别找临时中转:用 TaoToken 给 OpenCode 做兼容通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/29 13:21:05

绕开DeepSeek官网排队:硅基流动托管推理接入实战

简介:这份文档面向希望稳定使用 DeepSeek、又不想被官网“服务器繁忙”提示打断的 AI 使用者与开发者,围绕借助硅基流动平台调用 DeepSeek 满血版这一思路展开,兼顾本地部署吃配置、高并发请求受限等实际痛点,适合入门到进阶的模型…

2026/10/29 13:21:05

计算机专业转型网络安全:职业路径与技术栈解析

1. 计算机专业毕业生的职业迷思与现状 2008年我刚从某高校计算机系毕业时,班里90%的同学都直奔互联网大厂的开发岗位,仿佛写代码是计算机专业唯一的出路。十几年后的今天,当我以网络安全工程师的身份回看这段经历,发现这个行业正在…

2026/10/29 13:21:05

AI Agent开发中的三大工程挑战与解决方案

1. Agent工程中的核心痛点解析在AI Agent开发领域,数据清洗、权限开通和接口稳定性这三个问题被从业者戏称为"三大脏活累活"。这些工作看似基础,却消耗了开发团队近60%的工程时间。以金融领域的智能客服Agent为例,数据清洗可能涉及…

2026/10/29 13:21:05

智能体(Agent)与工作流系统的核心差异与技术实现

1. 概念辨析:Agent与工作流的本质差异最近AI领域涌现出大量打着"Agent"旗号的产品和框架,但仔细观察就会发现,其中很多本质上只是传统工作流系统的变种。要识别真正的智能体(Agent),我们需要先明…

2026/10/29 13:21:05

技能不是关键词堆砌:从深度拆解到技能栈组合与迁移

1. 先分清技能、经验、工具名:很多人把简历写成了购物清单 我这些年看过上千份简历、做过几十次面试,也带过不少新人,发现一个特别普遍的问题:大家一说"skills",第一反应就是往简历上堆关键词——Vue、React…

2026/10/29 13:16:04

影刀RPA实战:职场效率提升与自动化创收指南

1. 项目概述:当RPA遇上职场效率革命 那天晚上9点半,我盯着电脑屏幕上一排未处理的Excel表格,突然意识到自己正在重复第37次"复制-粘贴-校验"的操作。就在这个瞬间,我决定让影刀RPA这个数字员工接手这些机械劳动。经过一…

2026/10/28 14:42:12

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/28 15:28:56

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/28 3:32:29

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/29 0:03:42

学生选课系统DFD图绘制指南:边界划分与分层校验实战

简介:文档以顶层与第一层DFD图为核心,完整刻画学生选课系统的逻辑模型,面向软件工程课程设计、系统分析学习及毕设前期建模人群。顶层图界定系统边界,外部实体包括管理员、教师和学生三类角色;第一层图进一步细化用户登…

2026/10/29 0:03:42

JIRA敏捷落地:Scrum角色权限、Sprint与燃尽图避坑指南

简介:围绕“基于JIRA的敏捷开发项目管理”这一主题,面向产品负责人、Scrum Master及研发测试成员,梳理Scrum角色分工、迭代流程与JIRA工具配置的对应关系,适合初、中级团队导入敏捷管理时参考。压缩包共1个docx文件,大…

2026/10/29 0:03:42

SEMI S8人机工程验收实战:从条款拆解到现场实测的完整指南

简介:面向半导体设备设计、制造与运维工程师及安全合规人员,这份资料聚焦SEMI标准体系下的设备安全规范,重点收录SEMI S8-0308《半导体制造设备人体工程学工程安全指南》。内容围绕设备设计原则、错误与事故预防、人体工程学适配三大主线展开…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑