
PostHog AI 可信指令注入完全指南用type: instructions安全地引导 Agent【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthogPostHog AI 的面板集成中type: instructions是唯一被保留的特殊上下文项类型——它的value会进入posthog_trusted_context可信块成为 Agent 必须遵循的行为指引而不是像其他上下文项那样落入不可信数据块。本文以 PostHog 仓库中 injecting-instructions.md 为骨架结合 workflowAgentContext.ts 这一参考实现与products/posthog_ai/frontend的相关源码完整讲解指令项的形状、可信/不可信边界、去重与安全约束以及如何用它向 Agent 声明技能名与 MCP 工具目录。读完本文你将掌握在 PostHog 产品面中安全注入指令、避免提示注入、防止指令被去重剪枝的完整实战方案。指令项唯一被保留的上下文类型在 PostHog AI 的附加上下文体系中AttachedContextItem的type字段是一个任意字符串绝非枚举insight、dashboard、trace、text、hog_flow_editor_state都可以按需发明。但其中有一个值被系统保留——instructions。定义见 contextTypes.tsexport interface AttachedContextItem { type: string key?: string | number label?: string value?: string hidden?: boolean dismissGroup?: string }type: instructions与普通项的唯一区别在渲染路径它的value会进入posthog_trusted_context块成为Agent 被告知要遵循的指引而其他所有类型进入posthog_untrusted_context不可信块。在 runStreamLogic.ts 中可以找到这两个块的常量定义上下文块正是在消息发送时被前置拼接进去的。用它来表达三件事用户当前打开了什么页面、倾向于使用哪些工具、以及当前页面上这个东西指的是什么。最小的注册示例来自原文档const ISSUES_QUERY_TOOL_CONTEXT_ITEM: AttachedContextItem { type: instructions, hidden: true, value: The user has the error tracking issue list open. When you call query-error-tracking-issues-list, the filters from your query (filter group, status, date range, search, ordering, assignee) are also applied to the open page, so the user sees matching issues both in this chat and on screen., }要点除非这条指令本身就应该以标签芯片的形式展示给用户否则一律设置hidden: true。注册方式与任何其他上下文项完全相同——通过api/logics暴露的注册入口组件路径走useAttachedContextkea logic 走registerContextdisposabletype是唯一的差异点。可信意味着静态指令的安全边界指令必须只携带你自己构建期的字符串。绝不能出现用户输入的实体名、被摄取ingested的值或从二者插值出来的字符串。原因很直接可信上下文是 Agent 会照做的方向如果那里混入一个精心构造的实体名就等于对下一个阅读该线程的人发起提示注入——包括共享任务上的其他用户。由此得出强制分工程序化数据与用户数据→ 放在普通untrusted项上原样注入即可。用户未保存的编辑器状态通常是手里最有价值的信息不要把它清洗成苍白的安全文本放进不可信块并保持原样。指令需要指向会变化的东西哪个 id 被打开、哪一步被选中→不要插值。把指针放到一个 untrusted 项上让静态指令按字段名引用它// Static. Names the field, carries no id. value: The user has the email editor open. The hog_flow_editor_state items editing_email_action_id field names the open action; the latest editor state wins over anything earlier in the conversation.这段示例在 workflowAgentContext.ts 中有完整实现——buildEmailEditingContextItems里那条指令同样是纯静态文本只提hog_flow_editor_state项的editing_email_action_id字段名不携带任何 id。为什么会变的指针必须走 untrusted 项按精确文本去重这还有第二个原因。指令按任务的精确文本去重打开 A、打开 B、再打开 A此时 B 留下的陈旧钉子反而是最新存活的文本A 的指令因为和早前完全一致被剪掉了。而编辑器状态项的值每次状态变化都会改变因此永远会重新发送。这正是 workflowAgentContext.ts 在调用点同时记录两个原因的原因既守住安全边界又保证动态指针不会被去重剪枝。万不得已要插值先做形状白名单如果确实必须把标识符插进可信文本先白名单它的形状。workflowAgentContext.ts 在任何一个 action id 进入可信文本之前都会先经过SAFE_ACTION_ID校验// Action IDs are arbitrary strings a workflow writer controls, and this one gets interpolated // into a trusted instructions context item; anything outside a generated-ID shape must not // reach trusted context, or a crafted ID becomes a prompt injection against the next reader. const SAFE_ACTION_ID /^[A-Za-z0-9_-]{1,128}$/ function findEmailAction(workflow: HogFlow | null, actionId: string | null): HogFlow[actions][number] | null { if (!actionId || !SAFE_ACTION_ID.test(actionId)) { return null } // ... }之所以必须这样做是因为 action id 是工作流作者控制的任意字符串——不在白名单内拦截它就可能成为注入载体。校验失败时直接返回null指令根本不会被附加。在可信上下文中命名技能与工具目录真正值得放进可信上下文的两类东西是你的产品技能名skill names和 MCP 工具名tool names——它们都以构建期源的形式存在于仓库中这恰恰使它们在这里是安全的。技能来自products/*/skills/的技能构建流水线。每个产品技能都会被安装进 Agent 的沙箱因此执行框架已经按名称和描述列出了它并能在一次调用中加载正文——你只需点名即可无需内嵌内容。写作规范见 writing-skills其中给出了hogli init:skill、hogli lint:skills、hogli build:skills、hogli sync:skill的完整工作流。MCP 工具名来自你的products/name/mcp/tools.yaml。Agent 已经能通过 exec MCP 工具触达每一个工具info tool会返回完整输入 schema。先点名工具能避免 Agent 把回合浪费在工具发现上。实现规范见 implementing-mcp-tools。workflowAgentContext.ts 的两个标准动作workflowAgentContext.ts 为这个目的附加了两样东西1. 一条静态的 preamble 指令告诉 Agent 在第一次工具调用前先加载哪个技能、以及哪些 exec 命令覆盖了产品workflows-*前缀 少数最要紧的命令const PREAMBLE_CONTEXT_ITEM: AttachedContextItem { type: instructions, hidden: true, dismissGroup: SKILL_DISMISS_GROUP, value: The user has the PostHog workflow editor open. Load the ${BUILDING_WORKFLOWS_SKILL} skill before your first tool call; it covers the action/edge graph schema and the patch workflow. Act through the workflows MCP tools (the exec workflows-* commands: workflows-get, workflows-patch-graph, workflows-update, workflows-test-run, workflows-publish, workflows-logs, and the rest). Do not search for tools; use the exec info tool command when you need a full input schema., }注意BUILDING_WORKFLOWS_SKILL building-workflows是构建期常量workflows-*工具名与 products/workflows/mcp/tools.yaml 中enabled: true的工具workflows-get、workflows-patch-graph、workflows-update、workflows-test-run、workflows-publish、workflows-logs等一一对应。2. 一条可见的type: skill芯片让用户能看到并能拆下附加了什么const SKILL_CHIP_CONTEXT_ITEM: AttachedContextItem { type: skill, key: BUILDING_WORKFLOWS_SKILL, label: Building workflows skill, dismissGroup: SKILL_DISMISS_GROUP, }点名而不是内嵌不要把技能 markdown 或逐工具的 description 嵌入 payload。原因有三上下文块跟随每条消息传输一份技能正文在一条任务链上要消耗数万 token它重复了沙箱中已有的来源技能正文已经安装在沙箱里Agent 一次调用即可加载内嵌还需要 codegen 与 CI drift 检查来维持一致性且副本仍会与沙箱实际安装的渲染版技能产生分歧。技能名与工具名是 Agent 自己能解析的稳定标识符点名即可。同时要保持提及的工具名与产品 YAML 同步重命名一个工具会让指令变成死指针而且没有任何机制能捕获它——唯一会暴露问题的时刻是 Agent 第一次调用失败时。最后用共享的dismissGroup把整捆指令绑在一起让可见芯片与隐藏指令作为一个整体拆下。在 workflowAgentContext.ts 中SKILL_DISMISS_GROUP同时挂在 preamble 指令与 skill 芯片上关闭芯片即连带拆下隐藏的指令负载而非只隐藏芯片。条件式指令集按页面状态切换引导指令可以随用户在页面上的行为而变化。同一个文件只在邮件接管email takeover打开期间附加额外的指令包并且以 URL 参数确实解析到真实邮件动作为门禁——残留的?editoremail参数绝不能把 Agent 翻转到错误的框架下。要正确地计算条件并向下传递而不是信任查询字符串本身。workflowAgentContext.ts 中的实现export function isEditingEmailAction(workflow: HogFlow | null, searchParams: Recordstring, any): boolean { return searchParams.editor email !!findEmailAction(workflow, (searchParams.node as string) ?? null) }isEditingEmailAction返回true的唯一条件是URL 说editoremail并且node参数通过了SAFE_ACTION_ID校验、且确实能在当前工作流里找到一个 email action。节点/标签页的 URL 同步会保留外来 search params所以仅凭参数存在绝不能触发 email 编辑框架——必须双重确认。条件满足时buildWorkflowAgentContext才把buildEmailEditingContextItems()的整捆附加进去静态指令this email 指向哪个字段、内容修改优先用workflows-patch-action-email、designing-email-templates技能芯片、以及声明模板库工具清单的第二条指令三者共享EMAIL_EDITING_DISMISS_GROUP。配合使用动态状态走 untrusted静态指令只做引导把完整方案拼起来就是buildWorkflowAgentContextworkflowAgentContext.ts做的事情PREAMBLE_CONTEXT_ITEMinstructionshidden——声明技能与工具目录SKILL_CHIP_CONTEXT_ITEMskill可见——用户可见、可拆的技能芯片EDITOR_STATE_CONTEXT_ITEMinstructionshidden——静态指引读取时优先用hog_flow_editor_state项的实时状态需要持久化状态时才调用workflows-gethog_flow_editor_stateuntrustedhidden——序列化后的实时编辑器状态值随状态变化所以永远重新发送其中editing_email_action_id字段就是上文按字段名引用的动态指针hog_flowuntrusted可见——已保存工作流的引用key: id。关于编辑器状态本身还有两处细节值得注意详见 injecting-context.mdserializeWorkflowEditorState以EDITOR_STATE_MAX_CHARS 64_000为预算超预算时省略elide重型嵌套部分并替换为去取完整值的标记保持 JSON 可解析盲目截断做不到同时用redactWorkflowSecretInputs按 schema 脱敏密钥并fail closed——schema 不可用时仍在加载、抓取失败、模板被删除默认脱敏所有值并清除已脱敏条目的编译字节码因为字节码可能内嵌字面量。验证方式从 integrating-with-posthog-ai 的验证章节可以确认这样检查注入是否正确落地用pnpm --filterposthog/frontend typescript:check校验类型运行应用并在你的页面上打开侧边面板。上下文默认不可见所以要主动确认它落地了非hidden的附加项会以芯片形式出现在 composer 的上下文栏中Agent 应该能在不被告知 id 的情况下回答关于你附加对象的问题。小结PostHog AI 的指令注入可以浓缩为三条纪律可信即静态type: instructions只承载构建期字符串会变的指针放 untrusted 项指令按字段名引用点名而非内嵌在可信上下文中只声明技能名与 MCP 工具名正文与描述让 Agent 自己从沙箱和info tool解析条件要算对附加条件式指令集时以真实资源解析结果为门禁并用共享dismissGroup让芯片与隐藏指令整体拆装。遵循这三条你就能在不打开提示注入缺口、不浪费上下文 token 的前提下让 Agent 准确理解用户此刻在看什么、应该优先用什么工具、这里的这个指什么。【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考