@sim-design/training
v1.1.0
Published
实训教学平台组件库。把「运行训练模型 / 创建模型 / 编辑模型」三类能力以 React 组件形式提供给外部宿主工程集成。
Readme
@sim-design/training
实训教学平台组件库。把「运行训练模型 / 创建模型 / 编辑模型」三类能力以 React 组件形式提供给外部宿主工程集成。
@sim-design/training/runtime— 运行时:渲染并驱动一份训练模型(学员端)@sim-design/training/creator— 创建向导StepByStepCreator+ 模型编辑器ModelEditor(教师 / 运营端)@sim-design/training/types— 稳定契约类型与宿主注入适配器(仅类型 + 少量工具函数)
技术栈:React 18 + TypeScript + Ant Design 5 + Zustand。包为纯 ESM(
"type": "module")。
⚠️ 重要前置(先读这一段)
- 必须由宿主安装的 4 个依赖(库不打包它们):
react@^18.2、react-dom@^18.2、antd@^5.29、@coze/api。前三者是peerDependencies,@coze/api需一并安装。 - 其余依赖随包自带(
echarts/recharts/framer-motion/zustand/@dnd-kit/*/@monaco-editor/react/@babel/standalone/json-rules-engine/react-live/react-markdown等),宿主无需也不应单独安装。代价是解包体积约 10MB(其中DialogueFormPlugin单 chunk ≈ 4.65MB),建议在路由层对各页面做懒加载以避免一次性加载大 chunk。 - 浏览器环境:运行时依赖
localStorage/sessionStorage(会话恢复与 token 缓存)。SSR 场景需确保仅客户端渲染。 - AI 能力依赖扣子(Coze)平台:角色对话、实时指导、智能答疑、AI 评估,以及创建向导的全部生成步骤都要调用 Coze。纯「运行已有模型 + 确定性评分」可不接 Coze(详见《Coze / AI 接入前置》一章)。
- 无需引入任何 CSS 文件:组件以内联样式 + antd 的 CSS-in-JS 为主,产物不产出独立
.css,集成时不要去import样式文件。
安装
npm install @sim-design/training
# 宿主自备 peer 依赖
npm install react react-dom antd @coze/api导出子路径
| 子路径 | 主要导出 | 提供能力 |
|---|---|---|
| @sim-design/training | 下列全部 + 适配器 / 工具函数 | 聚合根入口 |
| @sim-design/training/runtime | TrainingRuntime,类型 TrainingEngineProps / TrainingResult | 运行时组件 |
| @sim-design/training/creator | StepByStepCreator、ModelEditor、setTokenInvalidHandler | 创建 / 编辑组件 |
| @sim-design/training/types | 全部契约类型 + 适配器函数 | 仅类型 + 适配器(无 React 组件) |
import { TrainingRuntime } from '@sim-design/training/runtime';
import { StepByStepCreator, ModelEditor } from '@sim-design/training/creator';
import type { TrainingModel, StepByStepCreatorProps } from '@sim-design/training/types';
import {
createLocalStorageCreatorPersistence,
setTokenInvalidHandler,
} from '@sim-design/training';快速开始:运行一份训练模型
import { ConfigProvider } from 'antd';
import zhCN from 'antd/locale/zh_CN';
import { TrainingRuntime, type TrainingResult } from '@sim-design/training/runtime';
import type { TrainingModel, Case } from '@sim-design/training';
export default function TrainingPage({
model, // 完整 TrainingModel 对象(推荐直接传,见下方“取数优先级”)
selectedCase, // 从 model.cases 中挑选的一个案例
}: {
model: TrainingModel;
selectedCase?: Case;
}) {
return (
<ConfigProvider locale={zhCN}>
<TrainingRuntime
trainingModel={model}
selectedCase={selectedCase}
studentId="stu-2026-001"
currentUser={{ userId: 'u-1001', name: '张三' }}
onComplete={(r: TrainingResult) => console.log('训练完成,平均分:', r.totalScore)}
onStepComplete={(s) => console.log('单步完成:', s)}
onError={(e) => console.error('运行时错误:', e.message)}
/>
</ConfigProvider>
);
}运行时组件 TrainingRuntime
@sim-design/training/runtime 的 TrainingRuntime 即容器组件 TrainingModelContainer 的别名导出。它根据传入的训练模型 + 选中案例,渲染「阶段 → 步骤」流程,逐步驱动各插件、收集学员操作、产出评估并回调宿主。
Props(TrainingEngineProps)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| trainingModel | TrainingModel | 否¹ | 直接传入的完整模型,运行时主数据 |
| modelId | string | 否¹ | 模型 ID;无 trainingModel 时据此异步加载(见下方注意) |
| selectedCase | Case | 否 | 当前选中案例,注入业务数据 / 角色池;切换会清空已填数据、对话与能力缓存 |
| studentId | string | 是 | 学员标识,用于会话归属、能力画像初始化、结果回填 |
| currentUser | { userId: string; name: string } | 是 | 当前用户;userId 用于换取 Coze token |
| onComplete | (result: TrainingResult) => void | 否 | 最后一步产生评估后触发,回传整场结果 |
| onStepComplete | (stepResult: StudentOperationResult) => void | 否 | 每步评估产生时触发 |
| onError | (error: Error) => void | 否 | 模型加载失败等错误时触发 |
¹ trainingModel 与 modelId 至少提供其一,否则渲染「配置错误」提示。
运行时还接收
botId与onSwitchCase两个 prop(botId:覆盖model.botId的 Coze 智能体;onSwitchCase:视图内切换案例的回调),它们运行时生效,但未列入导出的TrainingEngineProps类型。如需类型安全地传入,可参考@sim-design/training/types中的TrainingRuntimeProps(它额外包含这两个字段),但运行时入口真正导出、用于编译校验的类型是TrainingEngineProps。
trainingModel / modelId 取数优先级
- 优先级:
trainingModel(对象)>modelId(字符串);二者皆空 → 渲染错误提示。 - 传
trainingModel:直接使用,不发起任何网络请求。生产环境推荐这种方式——由宿主自行从后端取模型后整对象传入。 - 传
modelId:当 store 内还没有模型时触发内置loadModel(modelId)。注意:当前该路径走的是内置 mock(仅modelId === 'banking-personal-001'有数据,其它 ID 抛Training model not found),并非真实后端。除非你替换数据源,否则不要依赖modelId路径,请直接传trainingModel。 selectedCase由宿主从model.cases中挑选传入;容器不会根据model.defaultCaseId自动选默认案例,需宿主自行据此挑初值。selectedCase.caseId变化时会清空 FormRegistry 已填数据、对话缓存、证据与能力数据并重建能力图谱。
回调触发时机与参数
onStepComplete(stepResult):每当产生新的步骤评估时触发。stepResult为StudentOperationResult,其中operationData即该步的EvaluationReport。onComplete(result):在「最后一步且已产生评估且会话已建立」时触发。result: TrainingResult,totalScore为各步评估的平均分。注意completedStages取的是总阶段数,startTime/endTime为回调瞬时时间(非真实起止);若需精确时长,宿主请自行记录。onError(error):模型加载失败等错误时触发,参数为标准Error。
宿主接入前提
- antd ConfigProvider:非强制,但推荐在外层包一层
<ConfigProvider locale={zhCN}>以统一主题与中文文案、挂载message容器。组件自身主题由model.uiConfig.theme解析,与 antd 主题相互独立。 - 视图模式:运行时支持
classic/immersive/dashboard三种视图,默认dashboard。当前通过内部appConfig控制(updateAppConfig尚未在公共入口导出,如需切换请联系库维护方暴露该入口)。 - Coze token:运行时 AI 调用由内置
tokenManager基于currentUser.userId自动换取短期 token(OAuth jwt-bearer 流程),宿主无需手动传 Coze token,但必须保证tokenManager依赖的 JWT 签发后端在宿主环境可用,且配置了有效botId(见《Coze / AI 接入前置》)。
创建向导 StepByStepCreator
五步式向导,通过对话 + AI 生成产出一份完整 TrainingModel。宿主通过 props 注入 token、持久化与通知能力。
Props(StepByStepCreatorProps)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| cozeToken | string | 否¹ | 静态 Coze Token(无法刷新,无自愈能力) |
| getToken | TokenProvider | 否¹ | 动态 token 提供器 (forceRefresh?: boolean) => string \| Promise<string>,优先级高于 cozeToken |
| persistence | CreatorPersistenceAdapter | 否 | 进度持久化;不传时回退到 createLocalStorageCreatorPersistence()(localStorage,默认 30 分钟过期) |
| notify | CreatorNotifyAdapter | 否 | 通知适配器;不传时回退到 antd message |
| onComplete | (model: TrainingModel) => void | 是 | 五步走完、全局验收 pass 且终检通过后回调,返回完整模型 |
| onCancel | () => void | 是 | 用户取消时回调(取消前会弹二次确认,进度已自动保存可续编) |
¹ cozeToken 与 getToken 至少传其一,否则首次取 token 时抛「缺少 Coze Token」。
token:静态 vs 动态 + 4101 自愈
getToken优先于cozeToken。cozeToken是一次性静态串,即使上层forceRefresh=true也只能返回旧值(无自愈)。getToken(forceRefresh?):forceRefresh=true表示「清缓存并重新换取」,用于 token 失效自愈。- 4101 自愈需宿主注册一次:底层在扣子返回 4101(Bearer token 不合法)时,会回退到模块级回调换新 token 重试一次。该回调不由组件自动注册,宿主须在应用入口调用:
import { setTokenInvalidHandler } from '@sim-design/training/creator';
useEffect(() => {
setTokenInvalidHandler(() => getToken(true)); // 开启全局 4101 自愈
return () => setTokenInvalidHandler(null);
}, [getToken]);用静态
cozeToken时无此自愈能力;若创建流程耗时较长可能跨越 token 生命周期,请改用getToken并注册上面的 handler。
五步流程概览
- 意图收集 — 对话式收集训练蓝图,完成后自动触发大纲生成
- 流程大纲 — AI 生成阶段 / 步骤骨架与能力图谱,支持对话式迭代修改
- 步骤细节 — 两段式:环节一生成阶段契约 + 步骤任务包 + 字段声明(待确认);确认后环节二把各插件配置「落地」为
initData/runtimeRules/evaluationRules - 案例生成 — 先生成案例变体包,再生成案例实例数据(含逐案例答案键
stepAnswers) - 全局验收 — 产出发布门禁
pass/block与验收报告;仅pass才允许完成
onComplete(model) 返回的是合并好基本信息、能力图谱、caseSchema、cases 的完整 TrainingModel,可直接持久化或投入运行时。
最小接入
import { StepByStepCreator } from '@sim-design/training/creator';
<StepByStepCreator
getToken={getToken} // 或最简:cozeToken="xxxx"
onComplete={(model) => saveModel(model)}
onCancel={() => history.back()}
/>模型编辑器 ModelEditor
对一份已存在的 TrainingModel 做可视化编辑(多 Tab 面板),最终把改好的完整模型经 onSave 交回宿主。
Props(ModelEditorProps)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| model | TrainingModel | 是 | 待编辑的完整模型(初始状态) |
| onSave | (model: TrainingModel) => void | 是 | 点「保存」且本地校验通过后触发,参数为编辑后的完整模型 |
| onCancel | () => void | 是 | 点「返回」触发 |
| getToken | TokenProvider | 否 | 仅在面板内使用 AI 辅助编辑时需要;纯手动编辑可不传 |
| notify | CreatorNotifyAdapter | 否 | ⚠️ 当前实现未消费——提示统一走 antd message,传入不改变行为 |
| children | ReactNode | 否 | ⚠️ 当前实现未渲染——预留扩展位 |
诚实提示:
notify与children虽在契约中声明,但当前ModelEditor实现并未实际使用,请勿据此预期效果。
可编辑面板
基本信息 / 全局规则 / 阶段与步骤(含各步骤 initData·runtimeRules·evaluationRules·jumpRules,按插件类型路由到专用编辑器)/ 案例库 / 案例字段结构(caseSchema)/ 能力图谱 / 预览 / 外观配置(uiConfig)/ 原始 JSON。
onSave 语义
- 保存完全由宿主接管:组件内部无任何持久化逻辑,仅做本地格式校验(
modelId/name/domain/stages等必填),通过后才回调onSave(editedModel)。 onSave是同步回调:组件调用后立即提示「保存成功」,不会await,也不读返回值。若宿主保存是异步且可能失败,需在onSave内自行处理错误与提示。- 回传的是一份完整
TrainingModel(保留modelId、createdAt等未编辑字段)。
import { ModelEditor } from '@sim-design/training/creator';
<ModelEditor
model={model}
getToken={getToken} // 仅 AI 辅助编辑时用到
onSave={async (edited) => {
try { await api.updateModel(edited); } catch (e) { /* 自行兜底 */ }
}}
onCancel={() => history.back()}
/>宿主注入适配器
从 @sim-design/training(或 /types)导出,用于把宿主的 token / 存储 / 通知能力注入创建器。
import {
createLocalStorageCreatorPersistence,
resolveTokenProvider,
resolveCreatorNotify,
} from '@sim-design/training';TokenProvider=(forceRefresh?: boolean) => string | Promise<string>。forceRefresh=true→ 清缓存强制重取。CreatorPersistenceAdapter={ load(): CreatorContext | null; save(ctx): void; clear(): void }(均可返回 Promise)。createLocalStorageCreatorPersistence({ storageKey?, expireMs? }):默认 keyadmin_creator_context、过期 30 分钟;超期load()返回null。
CreatorNotifyAdapter={ success(msg); error(msg); warning(msg); info?(msg) }。不传则回退 antdmessage。setTokenInvalidHandler(handler | null):注册 / 清除模块级 4101 token 失效自愈回调(见上文创建器章节)。
核心数据契约 TrainingModel
权威类型来自 @sim-design/training/types。一个 TrainingModel 是一次实训的完整描述:声明业务领域、全局通过线、案例数据结构、案例库、能力图谱,以及由「阶段 → 步骤」构成的训练流程树。
顶层结构
| 字段 | 类型 | 必填 | 含义 |
|---|---|---|---|
| modelId | string | 是 | 模型唯一 ID |
| name | string | 是 | 模型名称 |
| domain | 'banking' \| 'insurance' \| 'trade' | 是 | 专业领域:银行 / 保险 / 外贸 |
| businessType | string | 否 | 业务类型 |
| targetPosition | string | 否 | 目标岗位 |
| description | string | 是 | 模型描述 |
| learningObjectives | string | 否 | 学习目标(顶层为整段文本,区别于 Stage/Step 的 string[]) |
| trainingLevel | 'undergraduate' \| 'vocational' \| 'technical' | 否 | 实训层次 |
| trainingType | string | 否 | 实训类型 |
| ideologicalElements / ideologicalRatio | string / number | 否 | 思政元素 / 占比(0–100) |
| botId | string | 否 | 运行时对话 Coze 智能体 ID;运行时取值 model.botId \|\| props.botId |
| uiConfig | ModelUIConfig | 否 | 模型级 UI 配置(参与「模型级 → 插件分区 → 步骤级」三层合并) |
| globalRules | GlobalRules | 是 | { stagePassScore; stepPassScore; timeout(秒) } |
| caseSchema | CaseSchema | 否 | 案例数据结构定义,约束所有 cases[] 字段形态 |
| cases | Case[] | 否 | 案例库 |
| defaultCaseId | string | 否 | 默认案例 ID |
| abilityMap | AbilityMap | 否 | 岗位能力图谱 |
| stages | Stage[] | 是 | 阶段列表,训练流程主干 |
| createdAt / updatedAt | Date | 否 | 时间戳 |
层级:TrainingModel → Stage[] → Step[]
Stage 关键字段:stageId / stageName / description / businessType / order(必填),stageGoal / deliverables / entryCriteria / completionCriteria / commonMistakes(可选),stageAssessment(阶段评估配置:跨步一致性检查 / 交付物核验 / 目标判据 / passPolicy.stepWeights 加权通过),steps: Step[]。
Step 关键字段与职责三分类:
| 字段 | 必填 | 职责 |
|---|---|---|
| stepId / stepName / pluginId / order | 是 | 标识与排序 |
| pluginType | 是 | 插件类型,决定渲染哪个插件(见枚举表) |
| initData | 是 | 初始数据 —— 学员看到什么 / 初始态(题面、表单结构、决策题组、推演节点…),形态随 pluginType 变化 |
| runtimeRules | 是 | 运行时规则 —— 过程中怎么约束 / 响应(实时校验、对话扰动 / 阶段 / 分支 / 阻力、流程门禁、单据判分基准…) |
| evaluationRules | 否 | 评估规则 —— 结束后怎么打分(dimensions 维度、businessRules、referenceAnswer / requiredPoints) |
| jumpRules | 否 | 条件跳转 |
| entryAnimation | 否 | 进入动画 { type; narration } |
| targetAbilities | 否 | 关联 abilityMap 的目标能力 { abilityId; targetLevel; weight } |
速记:initData = 看什么 / 初始态;runtimeRules = 过程怎么约束 / 响应;evaluationRules = 结束怎么打分。三者互不重叠。
PluginType 九个枚举值:
| 枚举 | 字面量 | 插件 |
|---|---|---|
| FORM_FILLING | form-filling | 表单填写(单据 / 合同,多表单 + 实时校验 + 实时指导 + 高保真布局) |
| DIALOGUE | dialogue | 对话交互(客户沟通,支持运行时扰动 / 阶段 / 分支 / 阻力) |
| DIALOGUE_FORM | dialogue-form | 对话式表单(边聊边填) |
| PROCESS_OPERATION | process-operation | 流程操作 |
| DOCUMENT_REVIEW | document-review | 单据审核(标记不符点,自带规则判分) |
| DECISION_MAKING | decision-making | 决策判断(标注 → 决策 → 理由两栏式) |
| CASE_ANALYSIS | case-analysis | 案例分析 / 方案设计(产出文档报告,自带评估) |
| STRATEGY_LAB | strategy-lab | 策略实验室(决策模拟 + 多节点推演) |
| KNOWLEDGE_LEARNING | knowledge-learning | 知识学习 |
Case 与 CaseSchema
CaseSchemaField:path(运行时按精确路径取值,如customerInfo.年龄、角色池.role-1.客户类型——必须与案例对象实际键路径一致)/type/label/purpose/usage('display'|'evaluation')/ 可选rule、enumValues、maxLength、children。CaseSchemaConstraint:字段间约束(derived/consistent/conditional),用于案例生成与一致性校验。Case:caseId/name/description/difficulty/scenario(必填),customerInfo/businessData(业务数据,结构由 CaseSchema 驱动;顶层领域中文键也可能是真正承载者,应 schema 驱动取值),角色池: Record<角色编号, RoleConfig>,可选riskPoints、stepAnswers。Case.stepAnswers(逐案例答案键):Record<stepId, 答案键>。分工——Step 出「考卷 + 评分标准」(案例无关基线,放evaluationRules/runtimeRules);Case 出「答案键」(案例特定正确答案)。运行时按stepId取Case.stepAnswers[stepId],存在则覆盖 Step 基线。答案字符串支持{路径}/[表达式],运行时按当前案例解析。
评估与结果类型
EvaluationReport(单步评估):totalScore/dimensions: DimensionResult[]/highlights/improvements/nextStepAdvice/pass/stepId?。DimensionResult:name/score/feedback/errors?/suggestions?。StageAssessmentReport(阶段评估产出):stageId/totalScore/pass/stepBreakdown/consistencyIssues/deliverableResults/goalAchievement/highlights/improvements。StudentOperationResult(单步操作产出):stepId/operationType/operationData/operationLog/timestamp/evidenceSummary?。EvidenceSummary(跨步骤传递的摘要证据):sourceStepId/title/summary/keyFacts[{label,value}]/riskFlags?/conclusion?/rawRef?。TrainingResult(整场结果,onComplete回传):sessionId/studentId/modelId/completedStages/totalScore/evaluationHistory: EvaluationReport[]/operationLog/startTime/endTime。
AbilityMap 能力图谱
AbilityMap = { targetPosition; version; abilities: AbilityNode[]; totalWeight }。AbilityNode = { id; name; category('basic'|'core'|'comprehensive'); weight; description?; children?; relatedSteps? }。关联回路:Step.targetAbilities[].abilityId ↔ AbilityNode.id,AbilityNode.relatedSteps[] ↔ Step.stepId。
最小可运行 JSON 骨架(1 stage / 1 step / 1 case)
{
"modelId": "model-demo-001",
"name": "养老规划师·客户面谈示范",
"domain": "insurance",
"businessType": "养老规划面谈",
"targetPosition": "养老规划师",
"description": "演示用最小模型",
"botId": "7300000000000000000",
"globalRules": { "stagePassScore": 60, "stepPassScore": 60, "timeout": 1800 },
"caseSchema": {
"fields": [
{ "path": "customerInfo.姓名", "type": "string", "label": "客户姓名", "purpose": "标识服务对象身份", "usage": ["display"] },
{ "path": "customerInfo.年龄", "type": "number", "label": "客户年龄", "purpose": "评估养老规划适配性", "usage": ["display", "evaluation"], "rule": "45-60 临退休人群" }
],
"constraints": []
},
"cases": [
{
"caseId": "case-001", "name": "临退休张先生", "description": "55 岁临退休客户的养老规划诉求",
"difficulty": "medium", "scenario": "张先生即将退休,关心养老金缺口与稳健配置。",
"customerInfo": { "姓名": "张建国", "年龄": 55 }, "businessData": {},
"riskPoints": ["养老金替代率不足"],
"角色池": { "role-1": { "角色编号": "role-1", "角色名称": "临退休客户张先生", "角色类型": "客户", "沟通风格": "谨慎、关注本金安全" } },
"stepAnswers": { "step-001": { "referenceAnswer": "应识别养老金缺口并提出稳健型配置建议", "requiredPoints": ["测算替代率", "强调本金安全", "给出补充方案"] } }
}
],
"defaultCaseId": "case-001",
"abilityMap": {
"targetPosition": "养老规划师", "version": "1.0", "totalWeight": 1,
"abilities": [ { "id": "ab-needs", "name": "需求挖掘", "category": "core", "weight": 1, "relatedSteps": ["step-001"] } ]
},
"stages": [
{
"stageId": "stage-001", "stageName": "面谈与方案建议", "description": "完成客户面谈并产出方案建议",
"businessType": "养老规划面谈", "stageGoal": "准确识别客户养老需求并给出合规建议", "order": 1,
"stageAssessment": {
"consistencyChecks": [],
"deliverableChecks": [ { "deliverable": "方案建议", "criteria": ["覆盖养老金缺口测算"] } ],
"goalCriteria": ["需求识别准确", "建议合规稳健"],
"passPolicy": { "stepWeights": { "step-001": 1 }, "passScore": 60 }
},
"steps": [
{
"stepId": "step-001", "stepName": "撰写养老规划方案", "pluginId": "case-analysis",
"pluginType": "case-analysis", "order": 1,
"initData": { "title": "养老规划方案设计", "materials": ["客户基本信息", "现有资产概况"] },
"runtimeRules": {},
"evaluationRules": {
"dimensions": [ { "name": "需求识别准确性", "weight": 0.5, "checkPoints": ["替代率测算"] }, { "name": "建议合规性", "weight": 0.5 } ],
"businessRules": ["不得承诺保本高收益"],
"referenceAnswer": "应识别养老金缺口并提出稳健型配置建议",
"requiredPoints": ["测算替代率", "强调本金安全"]
},
"entryAnimation": { "type": "scene-change", "narration": "你坐在张先生对面,面谈即将开始……" },
"targetAbilities": [ { "abilityId": "ab-needs", "targetLevel": 80, "weight": 1 } ]
}
]
}
]
}各插件
initData/runtimeRules内部结构随pluginType而定,顶层契约保持稳定、插件内部以any灵活承载——这是有意为之。
Coze / AI 接入前置
运行时 AI 评估、创建向导生成、角色对话 / 指导 / 答疑等能力均依赖扣子(Coze 国内版,https://api.coze.cn)。
Token 形态与流向
库内置 tokenManager 走 JWT-Bearer OAuth 流程(非长期 PAT):宿主后端用应用私钥签发 RS256 JWT → 前端拿 JWT 换取短期 access_token(约 1 天有效) → 注入所有 Coze 调用,缓存于 localStorage 并到期前主动刷新。
- 运行时:由容器基于
currentUser.userId自动获取,宿主无需手动传 token,但需保证 JWT 签发后端可用。 - 创建器 / 编辑器:宿主传
getToken(推荐)或cozeToken。 - 4101 自愈:扣子返回 4101 时自动换新 token 重试一次;模块级兜底需宿主注册
setTokenInvalidHandler(() => getToken(true))(见创建器章节)。
需在扣子平台预置的智能体(bot)
智能体 botId 集中在 configs/agentConfig.ts,系统提示词见 docs/coze-prompts/。按用途:
- 创建类:
INTENT_DISCOVERY(意图)、MODEL_OUTLINE(大纲)、MODEL_DETAIL(细节契约)、CASE_VARIANT_GENERATOR(案例变体)、CASE_INSTANCE_GENERATOR(案例实例 + 答案键)。 - 落地类(创建环节二,按插件各一):
LANDING_DIALOGUE/LANDING_DIALOGUE_FORM/LANDING_FORM_FILLING/LANDING_CASE_ANALYSIS/LANDING_DOCUMENT_REVIEW/LANDING_DECISION_MAKING/LANDING_STRATEGY_LAB/LANDING_GENERIC(兜底,botId为空需自配)。 - 运行时 / 评估类:
ACTOR_AGENT(角色扮演)、EVALUATOR_AGENT(评估)、COACH_AGENT(实时指导)、TUTOR_AGENT(答疑)、STAGE_EVALUATOR_AGENT(阶段评估)、STRATEGY_LAB(推演)、FORM_LAYOUT_GENERATOR(表单布局生成)等。
agentConfig.ts中的botId硬编码指向当前部署的扣子工作空间。宿主接入须在自己的工作空间新建 / 替换 bot 并回填botId,同时把对应系统提示词同步到扣子平台。运行时主对话 bot 写入各TrainingModel.botId。
宿主最小前置清单
- 开通扣子平台并完成 API 访问开通;
- 按上表新建 bot、配置系统提示词、回填
botId; - 搭建可签发 RS256 JWT 的 token 后端(或自管 token 直接提供
cozeToken/getToken); - 把 token 注入组件,并在入口注册
setTokenInvalidHandler。
不接 Coze 的能力边界
- 可用:运行已有模型(步骤渲染、插件交互、学员填写 / 操作、声明式实时校验、确定性评分如表达式 / 答案键比对)、后台对已有模型的手工查看与编辑。
- 不可用:创建向导的全部 AI 生成、运行时的角色对话 / 实时指导 / 智能答疑 / AI 维度评估 / 阶段评估 / 策略推演 / 表单布局 AI 生成。
打包结构与依赖策略
- 入口:
vite.lib.config.ts以 4 个入口(index/runtime/creator/types)做 ESM 库构建,输出dist/*.js;类型由tsconfig.build.json(emitDeclarationOnly)输出到dist-types/。 - 外置依赖(不打包,宿主提供):
react、react-dom、antd、@coze/api。 - 随包自带:上述 4 项之外的全部依赖打进产物(换取宿主零额外安装,代价是约 10MB 解包体积)。
- 样式:lib 构建未启用 tailwind;以内联样式 + antd CSS-in-JS 为主,无独立
.css。 - 静态资源:
dist/images/healthcare/bg.jpg随包(被运行时容器与策略实验室引用)。 files:["dist", "dist-types", "README.md"]——确保 JS、图片、完整 193 个.d.ts与说明随包,源码 / 测试 / 配置不进包。
本地构建与发布
| 命令 | 作用 |
|---|---|
| npm run build:lib | 库构建:vite build --config vite.lib.config.ts && tsc -p tsconfig.build.json |
| npm run pack:lib | 构建 + npm pack,本地打 .tgz 自检(不上传) |
| npm run publish:lib | 构建 + npm publish --access public |
| prepublishOnly | npm publish / npm pack 前自动触发 build:lib |
发布 runbook:
# 1. 升版本号(scoped 包同版本号不可重复发布)
npm version patch # 或 minor / major
# 2. 登录 npm(scoped 包需有 @sim-design 组织发布权限)
npm login # npm whoami 验证
# 3. 构建并自检进包内容
npm run build:lib
npm pack # tar -tf <包名>-<版本>.tgz 核对:4 入口 JS + 图片 + 完整 dist-types + README
# 4. 正式发布
npm publish --access public
# 5. 校验
npm view @sim-design/training version已知限制 / 注意事项
modelId路径走内置 mock:运行时仅banking-personal-001有 mock 数据,生产请直接传trainingModel对象。- 运行时无
externalTokenprop:运行时 AI token 由内置tokenManager(依赖 JWT 签发后端)管理,当前无法通过 prop 直接注入外部 token。 ModelEditor的notify/children未被消费:传入无效果。updateAppConfig未公开导出:视图模式(classic/immersive/dashboard)切换入口当前未暴露。- 包体积约 10MB:建议对接入页面做路由级懒加载。
- 仅浏览器环境:依赖
localStorage/sessionStorage,SSR 需仅客户端渲染。
本地开发(库维护方)
cd client
npm install
npm run dev # 启动应用态开发服务器(端口 3000)
npm run test # vitest
npm run build:lib # 产出库注:
client/.npmrc若存在编码异常(UTF-16)会在 npm 命令时产生无害告警,建议删除或以 UTF-8 重写。
