ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

CopilotKit 可换肤 Demo 的 Teach Mode:用 5 角色契约与演示-学习回路让 Agent 真正“学会”业务流程

2026/9/10 9:22:32 拓冰建站 浏览量
CopilotKit 可换肤 Demo 的 Teach Mode:用 5 角色契约与演示-学习回路让 Agent 真正“学会”业务流程 CopilotKit 可换肤 Demo 的 Teach Mode用 5 角色契约与演示-学习回路让 Agent 真正“学会”业务流程【免费下载链接】CopilotKitThe Frontend Stack for Agents Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKitTeach Mode 是 CopilotKit 开源仓库中reskinnable-demo示例展示的一种可证明的“演示式学习demonstration-driven learning”实现Agent 不知道某条业务过程人类在 UI 中演示一遍Agent 捕获并在 Intelligence 模式下持久化该过程随后一个全新线程里的 Agent 能无辅助地复现它。本文以banking银行皮肤为主线完整拆解 gate → unlock → record → persist → recall 的闭环、5 个角色GATE / UNLOCK / RECORDING / AGENT FRAMING / KNOWLEDGE BACKEND各自的约束不变量与源码落点并给出无需 Intelligence 后端即可运行的 REST 级验证脚本与 Intelligence 模式下的“新鲜 Agent 学习”验证步骤。读完你既能照搬这套 5 角色契约到自己的皮肤也能用文中的两条 grep 命令核查任何皮肤是否真正满足全部角色。本文内容以 examples/showcases/reskinnable-demo/docs/teach-mode/README.md 为骨架所有源码落点均来自该仓库对应文件写作时按原文档逐角色核对过实现。Teach Mode 是什么Agent 没有配方只有工具与目标“Teach mode”描述的是一条学习回路Agent 被分配了一个它从未被告知如何完成的任务一个人类在界面上演示解决方式这段演示被捕获并在 Intelligence 模式下写入持久化记忆最后一个全新的 Agent 在没有人类辅助、也没有在提示词里“预塞”配方的情况下成功完成同一类任务。Agent 不是被提示词喂出来的而是通过观察一个人做一遍而学会的。整个机制建立在一条核心不对称上Agent 被给予目标与工具但从未被给予“操作步骤procedure”一个gate闸门用只描述症状的错误拦住了显而易见的写入操作一个人类知道解锁方式并在 UI 中完成它该动作被捕获后来的 Agent 能自行应用它。在banking皮肤里这条被 gate 住的任务是审批一笔超出政策限额over-policy-limit的收费。一次完整的学习回路Agent A知道目标 工具但不知道操作步骤尝试显而易见的写入 │ ▼ GATE ──► 写入失败返回只描述症状的错误 (policy policy limit exceeded, HTTP 422 OVER_POLICY_LIMIT) 只说出问题是什么绝不透露修复方式 │ ▼ FRAMING ──► 提示词不包含配方 携带“干扰工具” 一个 ACTION DISCIPLINE 条款 ⇒ Agent 无法蒙混过关 它选择拒绝并主动提出学习。 │ ▼ UNLOCK ──► 人类在仪表盘上执行多步骤变通方案 以 JUSTIFYING 代码提交 exception → finalize → 链接到该收费 (DECOY 代码能提交但不会产生 justificationINVALID 代码被拒绝) │ ▼ SAVE ──► Agent 总结演示过程并在 Intelligence 模式下 通过 save_memory 持久化project 范围 │ ▼ Agent B全新线程不记得 Arecall_memory → 对另一笔超限收费 应用同一过程无需任何辅助 ◄── 这就是“学到了”的证明其中gate → unlock 半程今天就能用纯 REST 契约验证见下文“Verification”不需要任何 Intelligence 后端save → recall → 新 Agent 成功半程只有在 Intelligence 模式下才是持久化的在 OSS 模式下Agent 仍可在单次对话内学习但没有任何跨线程的持久化。5 角色契约与它们的承重不变量以下以与皮肤无关demo-agnostic的方式陈述。不变量invariant才是让这个 Demo 能“证明学习”而不是仅仅“把工作流演一遍”的关键。角色 1GATE —— 一个只返回“症状级错误”的失败写入审批一笔超限收费会被拒绝而拒绝信息只说明问题绝不说明修复方式。不变量错误必须只描述症状。它可以写 “policy policy limit exceeded”但绝不能提到 policy-exception 这条路径。错误信息一旦泄露配方Agent 一个来回就能推导出解法整个 Demo 就失效了。 Gate 还必须可被解除liftable一旦解锁到位在限额内或者已链接一个获批的 justifying exception同样的写入必须通过。banking的落点在 src/app/api/banking/v1/transactions/[id]/route.tsPUT更新交易时当状态被置为approved、交易不在政策限额内、且没有已批准的 exception 时返回422OVER_POLICY_LIMIT。从源码可以看到响应体的设计刻意“只命名症状”if ( patch.status approved !store.isWithinPolicyLimit(merged) !store.hasApprovedException(merged) ) { return new Response( JSON.stringify({ error: OVER_POLICY_LIMIT, message: ${store.findPolicy(existing.policyId)?.type} policy limit exceeded, }), { status: 422, headers: { content-type: application/json } }, ); }规则辅助函数isWithinPolicyLimit、hasApprovedException位于 src/skins/banking/data/store.ts。角色 2UNLOCK —— 一个有区分度的多步骤流程用来解除 Gate一个人类以及学习完成后的 Agent通过提交一个 JUSTIFYING 代码的 exception → finalize → 链接到该收费来解除 gate。代码目录catalogue混合了 justifying 代码与诱饵decoys未知代码被拒绝且不列出合法代码。不变量流程必须有区分度discriminating。只有 JUSTIFYING 代码能解除 gateDECOY 代码能成功提交为历史留档但不会产生 justificationINVALID 代码被拒绝且不枚举合法代码。Agent永远不会被告知哪些代码具备 justification—— 它必须从观察人类操作中学到这一点。banking的目录实现在 src/skins/banking/data/policy-exception-codes.tsPOLICY_EXCEPTION_CODES是展示给人类的选择清单前三个是 justifying其余是“看起来合理但只是留档”的诱饵JUSTIFYING_EXCEPTION_CODES是那三个真正能解锁的代码isValidExceptionCode用于拒绝未知代码isJustifying用于判定是否构成 justificationexport const POLICY_EXCEPTION_CODES: ReadonlyArrayPolicyExceptionCodeMeta [ // Justifying — these codes support approval of the policy exception. { code: EXC-BOARD-APPROVED, label: Board-approved spend }, { code: EXC-CONTRACTUAL-COMMITMENT, label: Contractual commitment }, { code: EXC-EMERGENCY-SPEND, label: Emergency spend }, // Non-justifying. Recorded for history; do not constitute a standing justification. { code: EXC-WILL-REIMBURSE, label: Employee will reimburse }, { code: EXC-ONE-TIME, label: One-time exception }, ];REST 侧由两个路由支撑提交 exceptionsrc/app/api/banking/v1/exceptions/route.ts开放POST。当代码不在目录中时返回422INVALID_EXCEPTION_CODE源码注释明确写着“我们故意不在这里枚举合法代码——那本身就是一种提示Agent 必须自己通过/knowledge找到目录。”finalizesrc/app/api/banking/v1/exceptions/[id]/finalize/route.tsfinalizePOST把 exception 链接到对应交易从而在代码构成 justification 时解除 policy-limit gate。角色 3RECORDING —— 演示在当前线程上被捕获人类演示期间Agent 用一个非方向性non-directional的等待卡片和一条实时记录流维持对话记录流逐条播报动作“Opened Dashboard”→“Filed the policy exception”→“Approved the charge”。不变量等待卡片必须保持非方向性。它绝不能列出步骤——重点恰恰是 Agent 还不知道这些步骤。被 gate 的状态与解锁后的效果之间的对比正是“保存”环节要提炼的信号。不变量可回放survives replayteach 链上卡片打印的一切内容都必须跟着工具结果tool result走即卡片读回的指令里。录制上下文是“live session”状态当已存储的线程被重新打开时它是空的——而这正是“线程存的是 AG-UI 流而不是文本”这句台词出现的时候。所以记录器recorder要在指令里上报自己的步数卡片打印上报的数字。一张靠解析自身渲染数步骤文案里的N.匹配来“重新推导”事实的卡片一旦某个步骤标签里含数字就会报出一个和下方列表不一致的数字。带往返测试round-trip test把“构造方”和“读取方”钉在一起的例子见 src/skins/commerce/teach-mode-directives.ts。不变量settle 不是回答a settle is not an answer“要我记住这个吗”卡片在两个按钮上都用字符串 settle所以typeof result string只能告诉你“卡片被回答了”什么也说明不了关于答案的内容。必须对指令做分类绝不能在“存在与否”上分支也绝不能把未识别的 settle 当作成功。这个搞错的话会在演讲者点了Dont save之后打出 “Saved. Ill use this next time” —— 舞台上断言了一次从未发生的持久化写入 —— 而且线程每次回放都会以同样的方式误渲染。banking的 RECORDING 是壳层shell所有而不是皮肤所有实现在 src/shell/teach/recording.tsxRecordingProvider、useRecording、RecordingFeed、RecordingVignette光晕的 CSS 是 src/app/globals.css 里的.recording-vignette颜色取自各皮肤的--brand-violet/--brand-indigo。banking、people和commerce曾各自发布过一份互有分歧的私有拷贝现在三者都统一导入这一个模块只有logStep的LABEL 是皮肤自己的词表。源码注释记录了这套实现的防错设计引用计数ref-counted避免重叠括号/卡片重挂/React StrictMode 双挂载导致光晕闪烁最小可见时长MIN_VISIBLE_MS 1200保证一闪而过的 bracket 不会让人看不见光晕feed 去重与“新窗口重置”保证同一个 tab 点两次不会让 feed 翻倍、第二次演示不会带着第一次的步骤开场演示代码是从 feed 推导出的getDemonstratedCode——提交 DECOY 就记录 DECOY写入照旧失败一个悄悄“纠正”操作员的记录器什么都证明不了。角色 4AGENT FRAMING —— 不给配方、塞干扰工具、强约束纪律系统提示词列出解锁所需的工具但绝不列出操作步骤并且携带看起来有用但根本解除不了 gate 的干扰工具。一条ACTION DISCIPLINE条款禁止 Agent 自创替代做法。不变量一次成功的解锁必须证明的是“学习”而非“提示词投喂prompt-stuffing”。因此(a) 提示词不给配方(b) 它携带干扰工具sendSpendAlert/requestCardReplacement/flagForReview让“调用了一个看起来合理的工具”≠“清除了 gate”(c) ACTION DISCIPLINE 让 Agent 停下来主动提出学习而不是瞎猜。在学习之前正确 framing 的 Agent不可能通过。banking的 framing 定义在 src/skins/banking/agent.ts。值得注意的是banking是整个应用里唯一一个 Agent 不在本进程执行的皮肤它是一个通过 AG-UI 访问的 Python LangChain 深度 Agentagent/目录由HttpAgent经BANKING_AGENT_URL默认http://localhost:8124/连接。也就是说该皮肤的 teach-flow 工具offerWorkflowRecording、awaitDashboardDemonstration、saveLearnedWorkflow以及recall_memory/save_memory是在远端 Agent 侧编排的源码注释中明确测量过跑这个 Agent 时浏览器的前端工具、Intelligence MCP 工具、a2ui 中间件和 HITL 工具调用往返都能照常绑定。因此本文关于 FRAMING 的讨论在概念上对应这套远端提示词。皮肤侧的工具注册在 src/skins/banking/tools.tsxofferWorkflowRecording向用户提议录制工作流、awaitDashboardDemonstration渲染“正在录制你的工作流”的实时卡片描述里明确写着“不要给用户逐步指引、不要告诉他们点哪里——你不知道这个过程这正是‘看着学’的意义所在”、saveLearnedWorkflow总结演示流程并请求保存。角色 5KNOWLEDGE BACKEND —— save → recall → 新 Agent 学会演示的流程被保存到持久化记忆一个新 Agent 把它召回并成功无辅助完成。运行时是env-gated按环境变量开关默认使用 OSS 的InMemoryAgentRunner配置了就使用CopilotKitIntelligence。不变量后端是一条可替换的接缝swappable seam。角色 #1–#2 不需要它就能被证明。OSS 模式下回路只在单次对话内有效持久的跨线程 / 跨用户召回需要 Intelligence 模式recall_memory/save_memory工具从启用了记忆的后端挂载上来。不变量先召回再拒绝recall before declining提示词必须让 Agent 在每次拒绝时先recall_memory再根据召回结果分支。一个把“你没有保存的通过办法”当作既定事实写死的提示词会让 Agent 在已经被教过之后仍然拒绝并提出录制演示成功、记忆正确保存但收益永远不会出现——提示词压倒了 Agent 已经知道的东西。运行时装配在 src/app/api/copilotkit/[[...slug]]/route.tsconst intelligenceApiUrl process.env.INTELLIGENCE_API_URL; const intelligenceWsUrl process.env.INTELLIGENCE_GATEWAY_WS_URL; const intelligenceApiKey process.env.CPK_INTELLIGENCE_API_KEY; const intelligenceEnabled Boolean( intelligenceApiUrl intelligenceWsUrl intelligenceApiKey, );三个环境变量同时存在时走CopilotKitIntelligenceenableEnterpriseLearning: true通过 MCP 中间件把平台侧recall_memory/save_memory挂到本地 Agent 上exposeMemoryRoutes: true打开面向客户端的/memories/*代理路由以便 web-inspector 的 Memory 标签页可用任意一个缺失就回退到纯 SSE 的CopilotRuntimeInMemoryAgentRunner——这是默认路径不允许回归。identifyUser回调按请求中的agentId/agent/:agentId/run|suggest|connect路径或/threads?agentId查询串解析各皮肤的identifyUser从而把记忆按成员/角色做作用域隔离无 agentId 的应用级路由/memories/*、/info走defaultSkinId皮肤的身份解析器。Per-skin divergence —— 记忆作用域memory scopebanking把学到的流程保存在scope:project后来的皮肤保存在scope:user并在提示词里说明因为本次部署中一个 Intelligence 后端被所有产品共享project 作用域的过程对从未学过它的皮肤也是可见的。新皮肤默认优先选user除非它确实独占自己的后端。还有第二个更硬核的原因一个皮肤的 intelligence/forget-memories.ts 如果跳过 project 作用域的行所有带这个文件的皮肤都这么做这样任何皮肤的 reset 都不会删掉另一个皮肤已种下的流程可用grep -n project src/skins/*/intelligence/forget-memories.ts核对那么它的 presenter reset物理上无法“解除教学”一条 project 作用域的记忆。在这种皮肤里把 beat 6 的流程存成 project 作用域第二次跑 Demo 时 Agent 开局就知道答案它不会拒绝、不会提出录制而这个 beat 看似完美实则什么都没证明。选作用域之前先查清楚自己皮肤的 sweep 到底会删掉什么。让 beat 5 种下的流程与 beat 6 学到的流程可区分是它们文案和路由提示词的任务每一条都明确说自己不是另一条而不是scope字段的任务。Per-skin divergence —— 工具命名这条链的形状是固定的offer → wait → summarize → confirm → persist名字不是。banking把中间两个叫awaitDashboardDemonstration/saveLearnedWorkflow后来的皮肤叫awaitDemonstration/saveLearnedProcedure。匹配你自己的皮肤而不是本文——并且注意开头的 grep 以offerWorkflowRecording为键这是所有皮肤共用的。各角色在 banking 皮肤中的落点一览角色文件#1 GATEsrc/app/api/banking/v1/transactions/[id]/route.ts —— 当审批会超出政策限额且未链接获批 exception 时PUT返回422OVER_POLICY_LIMIT规则辅助函数在 src/skins/banking/data/store.ts#2 UNLOCK目录 src/skins/banking/data/policy-exception-codes.tsPOLICY_EXCEPTION_CODES、JUSTIFYING_EXCEPTION_CODES、isValidExceptionCode、isJustifyingREST src/app/api/banking/v1/exceptions/route.ts开放POST src/app/api/banking/v1/exceptions/[id]/finalize/route.tsfinalizePOST#3 RECORDING壳层所有非皮肤所有—— src/shell/teach/RecordingProvider、useRecording、RecordingFeed、RecordingVignette光晕 CSS 是 src/app/globals.css 的.recording-vignette。只有logStep的 LABEL 是皮肤自己的#4 AGENT FRAMINGsrc/skins/banking/agent.ts —— 提示词不给配方、携带三个干扰工具、带 ACTION DISCIPLINE 条款并定义 teach-flow HITL 工具offerWorkflowRecording→awaitDashboardDemonstration→saveLearnedWorkflow外加recall_memory/save_memory#5 KNOWLEDGE BACKENDsrc/app/api/copilotkit/[[...slug]]/route.ts —— env-gatedCopilotKitIntelligenceOSSInMemoryAgentRunner默认键是INTELLIGENCE_API_URL/INTELLIGENCE_GATEWAY_WS_URL/CPK_INTELLIGENCE_API_KEYenableEnterpriseLearningexposeMemoryRoutes接好记忆工具与 inspector 的 Memory 标签页identifyUser按成员/角色划分记忆作用域叙述版流程当被要求审批一笔它没有保存过流程的超限收费时Agent 会拒绝“我还没有保存过审批超限收费的办法”并调用offerWorkflowRecording—— 不展示任何审批卡片。职员在真实仪表盘上演示Transactions → Pending → 提交 justifying exception → approve期间awaitDashboardDemonstration维持对话随后 Agent 执行saveLearnedWorkflowsave_memory之后的请求里它通过openPolicyException→finalizePolicyException→approveTransaction把这套流程应用到另一笔超限收费上。因为演示发生在另一个路由上teach/recall 工具由皮肤的Tools组件注册而不是某个单页这样它们能在导航后存活。用命令而非“名单”来判定皮肤是否实现 Teach Mode原文档特意不把“哪些皮肤实现了 teach mode”写进正文——写进文字里的名单正是这个仓库反复踩的坑src/shell/skin-roster-docs.test.ts就是因为一次 review 里发生过十六次而存在的。不变量是一个皮肤实现了 teach mode当且仅当它的Tools注册了录制交接recording hand-off。所以名单是命令不是句子grep -l offerWorkflowRecording src/skins/*/tools.tsx这条 grep 现在已经返回每一个已注册的皮肤用ls src/skins/对比teach mode 不再是子集功能。但grep 给你名单并不认证合规不要把它读成“名单上的每个皮肤都遵守全部 5 个角色”——本文档一个更早的版本正是在只看两个皮肤的情况下这么写的第三个皮肤立刻就证伪了它。角色 #3 的机械判定标准是皮肤是否把它的两条回放规则从渲染里抽出来放进teach-mode-directives.ts这同样是命令而非句子ls src/skins/*/teach-mode-directives.ts写作时逐角色核验的结果是banking、commerce、logistics全部满足 5 个角色。people满足 #1、#2、#4、#5而角色 #3 的两条回放不变量它满足一条、违反另一条——抄它之前两条都要读“可回放survives replay”——满足。people的awaitDemonstration渲染src/skins/people/tools.tsx在result里数\d\.\s而result是工具结果——即DemonstrationCard构建并交给respond?.()的“已观察步骤”指令tools.tsx:1337-1341编号也在其中。它不是在解析自己的渲染那个分支也不会打印与数字矛盾的列表。指令才是回放的对象所以计数是稳定的。但它仍然是脆弱的形态——它在解析一个计数而不是读取记录器上报的计数所以步骤标签里如果出现数字会被算进去——但这是健壮性缺口不是回放缺陷。“settle 不是回答”——违反。saveLearnedProcedure的渲染tools.tsx:1135-1139对任何字符串结果都打印 “Saved. Ill use this next time”而Dont save按钮就是用一个字符串 settle 的tools.tsx:1164-1167。卡片断言了一次从未发生的持久化写入——现场如此每次回放也一模一样这正是它能活下来的原因。所以要抄就抄回放行为被“钉住pinned”的皮肤——即上面teach-mode-directives.ts命令点名的那些。这些文件把两条规则从渲染中抽出来readDemonstratedStepCount、classifySaveProcedureResult让一个往返测试能同时拿住构造方与读取方。commerce和logistics是前两个airline和keel在重构时也发了同一对所以这种形态现在是常态而非例外。banking正确但手写、无断言所以它可以腐烂而不会触发任何失败。这些被钉住的文件是**刻意的兄弟文件siblings**而非一个共享模块皮肤对共享代码唯一的入向依赖是Skin契约而这些指令是领域措辞不是壳层机制。下面两条 grep 都不是裁决——命中只是“值得去读的地方”不是缺陷空结果也不代表合规# SMELL不是违规一张 teach 卡片通过 PARSING 指令来推导计数 # 而不是读取记录器上报的计数。这是 people 的命中——但不是 people 的缺陷。 grep -n result\.match src/skins/*/tools.tsx # people 真正缺陷的位置在 settle 的“存在与否”上分支。 # 在按钮不可能产生分歧的卡片上是合法的所以每个命中都要读 # 在“要我记住这个吗”卡片上它会在 _Dont save_ 之后打印 Saved。 grep -n typeof result string src/skins/*/tools.tsx合规皮肤在承重细节上偏离 banking 的地方本文都在内联的Per-skin divergence注记里点出来了。构建下一个皮肤之前请读完本文并跑完这两条命令。钉住回放teach-mode-directives.ts究竟在钉什么以 src/skins/commerce/teach-mode-directives.ts 为例看“构造方-读取方不可漂移”是如何被文件结构与测试钉住的。文件头注释给出了两条规则的动机卡片只陈述生产者上报的事实绝不通过解析渲染来重新推导事实。第一演示指令上报步数读取方只读上报值export function buildDemonstrationDirective({ steps, code }: { steps: string[]; code: string | null; }): string { const observed steps .map((label, index) ${index 1}. ${label}) .join(\n); return ( The user finished after ${steps.length} ${steps.length 1 ? step : steps}. Observed steps:\n${observed || (nothing captured)}\n (code ? The waiver code they used was ${code}. : No waiver code was captured.) ); } export function readDemonstratedStepCount(result: unknown): number | null { if (typeof result ! string) return null; const match /^The user finished after (\d) steps?\./.exec(result.trim()); return match ? Number(match[1]) : null; }注释记录了那条历史 bug卡片过去靠数/\d\.\s/匹配来“重新推导”步数结果像 “Marked down Aurora Throw to 1.50 under the floor” 或 “Filed waiver MARGIN-EXEC-OK at 12.5% margin” 这样的步骤标签会各贡献一个幻影步数卡片报的数字比下面列表印的多——而这恰恰是“录制是忠实的”这个论断所在的那个 beat。正则锚定在^开头也是为了让自由文本步骤标签里的数字不可能被误当成计数。第二保存分类器绝不把“未知的 settle”当成成功export type SaveProcedureOutcome pending | saved | declined | unknown; export function classifySaveProcedureResult(result: unknown): SaveProcedureOutcome { if (typeof result ! string) return pending; const text result.trim(); if (text.length 0) return pending; if (text SAVE_PROCEDURE_CONFIRMED) return saved; if (text SAVE_PROCEDURE_DECLINED) return declined; if (/declined|do not call save_memory/i.test(text)) return declined; if (/confirmed/i.test(text) /save_memory/i.test(text)) return saved; return unknown; }两个 settle 指令本身就是字符串常量SAVE_PROCEDURE_CONFIRMED指示“用户确认立即用 save_memory 持久化”SAVE_PROCEDURE_DECLINED指示“用户拒绝不要调用 save_memory”与分类器同文件共存“改一处就看得见另一处”。文件的往返测试teach-mode-directives.test.ts把构造方与读取方同时钉住防止它们漂移。模块刻意保持 server-safe 且无 React这样这些读取器值得单测且无需挂载 provider/线程/agent 注册。验证不依赖后端的证明今天就能跑—— 角色 #1 #2运行仓库自带的脚本对着一个运行中的 dev server。它驱动真实 REST 路由在 HTTP 层断言完整的 gate→unlock 契约不需要任何 Intelligence 栈pnpm dev # 另开一个终端默认 :3000 ./verify-teachable-gate.sh # BASE_URL 默认为 http://localhost:3000 BASE_URLhttp://localhost:3000 ./verify-teachable-gate.sh它按顺序断言A. GATE#1—— 审批一笔超限收费 →422OVER_POLICY_LIMIT且响应体不提及exception/unlock 路径只描述症状。B. UNLOCK#2—— 打开一个 justifying exception → finalize → 重新审批同一笔收费 →201gate 已解除。C. DECOY#2—— 非 justifying 代码能提交并 finalize但审批仍然是422。D. CATALOGUE#2—— 非法代码 →422INVALID_EXCEPTION_CODE且不枚举真实目录。存储是内存态的从 src/skins/banking/data/seed.json 播种。每个场景用一笔不同的种子超限交易所以一次运行不需要重置。想从零重跑重启 dev server或者POST皮肤的 gated presenter-reset 路由/api/banking/v1/dev/reset由PRESENTER_RESET_ENABLEDtrue启用侧边栏的 Reset 按钮也打这条路由。学习证明之前优先用 reset 路由。重启 dev server 只会重新播种内存存储其它什么都不做——持久化记忆活在 Intelligence 后端里重启杀不掉它。reset 路由还会遗忘并重新播种那段记忆这才是唯一能让 Demo 回到真正“未教过”状态的东西。它会在那半程失败时上报memoryError这句话是“回路开局就已学过”的唯一警告所以要把它展示出来而不是把响应压成一个状态码。新 Agent 学习证明 —— 角色 #3 #5Intelligence 模式这一步证明回路学到了而不只是 REST 能用。它需要配置好 env-gated 的CopilotKitIntelligence运行时INTELLIGENCE_API_URL、INTELLIGENCE_GATEWAY_WS_URL、CPK_INTELLIGENCE_API_KEY。基线Baseline。先 reset见上——持久化记忆比 dev server 重启活得久不 reset 的话开局就已经是“已学过”对照组会空转vacuously pass。然后在一个新线程里让 Agent 审批一笔超限收费。在角色 #4 的 framing 完好时它会拒绝并主动提出录制——不会发射任何干扰工具。这是对照组。教学Teach。人类在仪表盘上演示解锁justifying code → finalize → approve记录器卡片逐条播报每个步骤。保存Save。Agent 总结并调用save_memorykind:operationalscope:project是 bankinguser是后来的皮肤——见角色 #5。新 Agent 成功Fresh agent succeeds。在一个新线程里对人类的会话没有任何记忆请求审批另一笔超限收费。Agentrecall_memory→ 提交 justifying exception → finalize → approve——无辅助提示词里什么都没加。通过标准第 1 步拒绝第 4 步成功且唯一的变化就是保存下来的流程。这个差值就是学习。它的确定性 CI 版本是pnpm test:self-learning即 e2e/memory-learning.spec.ts脚本定义于 package.json用 aimock 提供的 LLM 驱动该流程对着真实的本地记忆后端跑。结语把“演示-学习”变成可证明的契约Teach Mode 的价值不在于“我们调了提示词让 Agent 看起来会了”而在于它把学习做成了一条可逐角色验证的契约gate 的错误只描述症状、unlock 的流程有区分度、recording 把事实装进工具结果而非渲染、framing 不给配方、后端是一条可换的接缝。grep -l offerWorkflowRecording src/skins/*/tools.tsx给你名单ls src/skins/*/teach-mode-directives.ts给你回放行为被钉住的候选而./verify-teachable-gate.sh让你在没有 Intelligence 后端时就能证明前半程pnpm test:self-learning让你在 CI 里证明后半程。复制一套时抄回放行为被钉住的皮肤commerce/logistics/airline/keel的同款形态记住“settle 不是回答”、演示步数要读上报值而不是数出来的值并且新皮肤默认把记忆存到scope:user。这样你的下一个皮肤才能像 banking 一样让 Agent 从“看着一个人做一遍”变成“真正会了”。【免费下载链接】CopilotKitThe Frontend Stack for Agents Generative UI. React, Angular, Mobile, Slack, and more. Makers of the AG-UI Protocol项目地址: https://gitcode.com/GitHub_Trending/co/CopilotKit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考