mcpField
O
objectstack-ai

objectstack-ai

github.com/objectstack-aiAgent 工作流76230 次安装今天更新
代码仓库

关于 objectstack-ai

objectstack-ai 介绍如何为 ObjectStack 应用定义 AI 技能和工具,面向编写 AI 元数据的开发者。开放版通过 MCP 将应用提供给外部 Agent,不包含应用内 Agent 运行时。

主要功能

  1. 01定义包含工具和指令的技能
  2. 02配置程序化触发条件
  3. 03将明确启用的操作公开为工具
  4. 04通过 MCP 发布 ObjectStack 应用
  5. 05配置知识来源与适配器
  6. 06验证技能中的工具引用

适用场景

  1. 01为 ObjectStack 应用编写技能
  2. 02向外部 Agent 提供应用操作
  3. 03让外部 Agent 访问应用数据和操作
  4. 04配置已索引的知识来源

MCP 相关

文档中的 @objectstack/mcp 插件通过 MCP 公开 ObjectStack 应用,包括架构检查、记录操作和明确启用的业务操作。调用受 OAuth 作用域、调用者权限和行级安全控制。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/objectstack-ai/objectstack --skill objectstack-ai

安装后在 Claude Code 中输入/objectstack-ai确认已加载。

附带文件evals/skills-tools-knowledge.jsonreferences/_index.md

详细介绍

AI Agent 设计 — ObjectStack AI 协议

版本范围。☁️ 表示云端 / Enterprise 功能,以下不再重复标注。 UI 内的 AI 运行时——ask / build Agent、产品内聊天、/api/v1/ai/*(@objectstack/service-ai)——仅随云端 / EE 提供,不属于开源框架。@objectstack/spec/ai 中的架构定义保持开放,因此无论哪种情况,你都可以将 *.skill.ts / *.tool.ts 编写为源代码,但它们只能在云端 / EE 主机中执行。在开源版本中没有产品内 Agent:通过 MCP(见下文)向你自己的 AI 开放应用,并使用 AI 编码 Agent(Claude Code、Cursor)以源代码模式编写元数据。

Agent  →  Skill  →  Tool
  │         │         │
  │         │         └─ Atomic operation (query, action, flow, API call)
  │         └─ Capability bundle with instructions & trigger conditions
  └─ Autonomous actor with role, instructions, and guardrails

Agent 是平台内部功能(☁️ ask / build;参考内容见底部)。Skill 是你的入口——通过编写 Skill 来扩展平台,并在 Skill 中指定工具来调用它们。


Skill 配置

Skill 是一组带有专属指令和触发条件的命名工具集合。

必填类型描述
namesnake_case唯一的 Skill ID(/^[a-z_][a-z0-9_]*$/)
labelstring显示名称
toolsstring[]此 Skill 授予的工具名称(允许使用尾随通配符,例如 action_*)——每个名称都必须能解析;详见下文的解析层级
可选用途
surface'ask' | 'build' | 'both'——平台 Agent 可以绑定此 Skill 的范围(默认 'ask')。加载时在 resolveActiveSkills 中强制执行:不兼容的绑定会导致快速加载错误(ADR-0063 §3)
descriptionSkill 的用途——Agent 会读取它来判断何时使用该 Skill
instructions针对此 Skill 上下文的提示词指导。开源版本会读取的唯一字段:@objectstack/mcp 会将其映射到 MCP prompts 基元,因此,instructions 为空或 active: false 的 Skill 根本不会作为提示词列出
triggerConditions以编程方式定义的激活规则(见下文)
active是否启用(默认 true)

Skill 没有 permissions 键——该键已在 17.0.0 中移除,因为它没有任何限制作用。应在 Agent 上进行限制(在 defineAgent 上设置 access / permissions,由聊天路由强制执行),或限制工具调用的操作(ADR-0066)。

指定工具名称:解析层级

skill.tools[] 条目会针对三个来源的并集进行解析(packages/lint/src/validate-ai-tool-references.ts 中的 collectToolUniverse):

  1. stack.tools[].name——你自己的 stack 所声明的记录。ADR-0109:默认的第三方路径不声明任何工具(见下文的 工具元数据)。
  2. PLATFORM_PROVIDED_TOOL_NAMES——静态注册的平台工具,从 packages/spec/src/system/constants/platform-tool-names.ts 中的 PLATFORM_TOOLS_BY_PACKAGE 展开而来:来自 service-ai 的数据 / 知识工具,以及来自 service-ai-studio 的架构 / 元数据 / 包工具。请查看该文件以获取准确集合:这是 lint 规则检查的注册表。
  3. action_<name>——你自己的 stack 中每个向 AI 开放的 Action 对应一个工具(PLATFORM_TOOL_FAMILY_PREFIXES)。任何应用功能的默认路径。

不属于上述三个来源的名称会触发 ai-skill-tool-unresolved(警告,ADR-0078 先以建议方式执行)。设置此规则的原因是:有一个经过审计的应用,通过 validate / lint 检查,却在 6 个 Skill 中发布了 10 个虚构工具,最终成为一个声称具备自身并不具备能力的副驾驶。

Skill 示例
import { defineSkill } from '@objectstack/spec';

export default defineSkill({
  name: 'case_management',
  label: 'Case Management',
  description: 'Triage, query, and escalate support cases.',
  instructions: `
    When managing cases:
    - Always check for duplicate cases before creating a new one.
    - Set priority by customer tier: Enterprise → High, Pro → Medium, Free → Low.
    - Escalated cases must summarise the actions already taken.
  `,
  // Every name resolves: two platform tools (rung 2) plus one action tool
  // materialised from this stack's own `escalate_case` Action (rung 3).
  tools: ['query_records', 'get_record', 'action_escalate_case'],
  triggerConditions: [
    { field: 'objectName', operator: 'eq', value: 'support_case' },
  ],
  active: true,
});
触发条件

每个条件的形式为 { field, operator, value },并与同级条件进行 AND 运算。value 的形式取决于 operator——不匹配会导致解析错误,不会进行类型转换(packages/spec/src/ai/skill.zod.ts:37-51, 139-202):

运算符含义value 必须是
eq等于字符串——数组采用引用相等,因此永远不会匹配
neq不等于字符串——数组会始终触发
in在列表中数组(允许空数组 [],且它是一个有效谓词)
not_in不在列表中数组
contains子字符串或数组子集二者皆可——两种写法都会执行

短语无法匹配:将路由规则写在 triggerConditions 中,并将自然语言意图写在 description / instructions 中,模型会读取这些内容。


将操作用作 AI 工具 — 默认路径 ☁️

通常,调用操作时无需手动编写工具定义。通过 defineObject({ actions: [...] }) 附加到对象的 Action,只有在选择公开时才会变为名为 action_<actionName> 的工具——必须设置 ai.exposed: true(默认值为 false),并提供长度不少于 40 个字符的 ai.description;否则解析会拒绝该配置(ADR-0011)。registerActionsAsTools() 会遍历选择公开的操作;公开绝不会自动发生,也没有用于取消公开的键。

三种操作类型可在无头模式下分发:

action.type分发方式接线配置
scriptIDataEngine.executeAction(object, target, ctx) — 与 Studio 的行工具栏相同无
api对 action.target 发起 HTTP 调用(默认基于 fetch)AIServicePlugin({ apiActionBaseUrl, apiActionHeaders }) 或自定义 apiClient
flowIAutomationService.execute(target, { triggerData })在内核中注册的 automation 服务

即使选择公开也会跳过: 仅限 UI 的类型(url、modal、form);以及危险变体——仅限声明了 mode: 'delete' / variant: 'danger' 的情况(confirmText 是对话框文案,不是破坏性操作的信号;ai.requiresConfirmation 无论上述条件如何都会覆盖此规则)——除非插件以 enableActionApproval: true 运行,此时这些操作会进入审批队列。

type:'api' 请求体组装(后者覆盖前者):用户参数 → recordIdParam(使用 recordIdField,默认值为 'id')→ bodyExtra。bodyShape: { wrap: 'data' } 会将用户参数嵌套在 data 下,同时让 recordIdParam 保持平级。

人在回路中。 AIServicePlugin({ enableActionApproval: true })(默认值为 false)不会执行危险操作,而是持久化一条 ai_pending_actions 记录,并返回 { status: 'pending_approval', pendingActionId };操作员可在 Studio 的 AI 待处理操作收件箱中(或通过 GET/POST /api/v1/ai/pending-actions/...)批准或拒绝。你的操作是否会被暂缓,完全由上述跳过规则决定——@objectstack/service-ai 中的 actionSkipReason(action, ctx) 和 actionRequiresApproval(action) 可分别回答这两个问题,Studio 的“AI 公开”诊断也使用相同的判定条件。


MCP — 开放版 AI 路径

@objectstack/mcp 通过模型上下文协议发布你的应用,让外部 Agent(Claude、Cursor、Codex 等)无需云端许可即可读取并操作它。(消费外部 MCP 服务是入站对应项:@objectstack/connector-mcp。)

import { MCPServerPlugin } from '@objectstack/mcp';

kernel.use(new MCPServerPlugin());

HTTP 接口默认启用,由运行时分发器按请求在 POST /api/v1/mcp 提供服务——无需启动任何内容(设置 OS_MCP_SERVER_ENABLED=false 可选择退出)。长驻的 stdio 传输有独立开关,且默认关闭:autoStart: true,或 OS_MCP_STDIO_ENABLED=true。(OS_MCP_SERVER_ENABLED=true 仍会启动它——此方式已弃用,并会在启动时发出警告。)

客户端随后可以看到的工具——来自 registerObjectTools / registerActionTools,每组工具都受调用方的 OAuth 作用域控制;每次调用均遵循调用方的权限和行级安全规则:

工具功能
list_objects, describe_object架构自省(默认过滤系统对象)
query_records, get_record读取——筛选、字段选择、排序、分页
aggregate_recordsGROUP BY 汇总;仅当数据桥接实现了 aggregate 时注册
validate_expression在公式写入元数据之前,按照构建时配置检查 CEL
create_record, update_record, delete_record写入;delete_record 标注为破坏性操作
list_actions, run_action供 AI 使用的业务 Actions——与上述相同,需选择启用 ai.exposed

知识源(RAG)

RAG 原语是 KnowledgeSource(@objectstack/spec/ai 中的 KnowledgeSourceSchema):一种声明式元数据,用于将 要索引的内容 与负责执行工作的 IKnowledgeAdapter 的 ID 配对。没有用于这些对象的 defineStack 集合——它们在运行时注册,☁️ search_knowledge 工具会向 Agent 暴露已注册的源。

接线(开放包)。 @objectstack/service-knowledge 中的 KnowledgeServicePlugin({ sources }) 会在启动时向内核注册 IKnowledgeService 和每个源(之后仍可使用 service.registerSource)。adapter ID 会解析到一个适配器插件——@objectstack/knowledge-memory ('memory',开发/测试)或 @objectstack/knowledge-ragflow('ragflow'); 若没有适配器插件,该 ID 将无法解析。

属性用途
id蛇形命名的源 ID
label / description显示元数据
adapter适配器 ID(例如 'ragflow'、'memory'),通过 IKnowledgeService.registerAdapter 解析
adapterConfig适配器专属配置(服务不解析其内容)
source要索引的内容——根据 kind 区分:'object' | 'file' | 'http'
embedding可选的 EmbeddingModelSchema 引用(provider、model、dimensions)——在内部管理嵌入的适配器(RAGFlow、Dify、Vectara)可以忽略它
vectorStore可选的 VectorStoreSchema 引用(provider、collection)——同样需要注意
refreshonRecordChange(对象源默认为 true)+ 可选的 cron(供外部调度器使用;不会自行调度)
aiExposedsearch_knowledge 是否可向 Agent 暴露此源(默认为 true)——设为 false 时会索引该源,但不会使其可供 Agent 搜索
source.kind字段数据规范
objectobject、contentFields[](至少 1 个;* = 每个可读文本字段)、metadataFields?、where?(ObjectQL where 语法)使用 where 将草稿和已归档行排除在索引之外;contentFields 只选择有意义的文本(绝不选择系统字段或 ID,谨慎使用 *);将查询时要用于筛选的字段(status、owner_id、tags)投影到 metadataFields 中
fileprefix(存储前缀,例如 kb/handbooks/)、mimeTypes?缩小前缀范围,而不是索引整个存储桶
httpurls[]、userAgent?明确列出 URL——没有爬虫
import { KnowledgeSourceSchema, type KnowledgeSource } from '@objectstack/spec/ai';

export const supportKb: KnowledgeSource = KnowledgeSourceSchema.parse({
  id: 'support_kb',
  label: 'Support Knowledge Base',
  adapter: 'ragflow',                       // or 'memory' for dev/test
  source: {
    kind: 'object',
    object: 'kb_article',
    contentFields: ['title', 'body'],       // concatenated into document content
    metadataFields: ['category', 'owner_id'], // projected for search-time filtering
    where: { published: true },             // index published articles only
  },
  refresh: { onRecordChange: true },        // re-index on record.* events
});

分块、top-K、分数阈值和重排器不属于平台元数据。 规范特意将它们排除在外(embedding.zod.ts):它们属于 适配器(adapterConfig)或应用代码。平台只承载嵌入和向量原语,因此可以在其上构建任意 RAG 策略。


工具元数据(defineTool)——非默认路径

默认:不声明工具记录。 技能会指定一个平台工具或一个 action_<name>(见上文阶梯)。ADR-0109:stack.tools 记录“仅用于 AI 展示优化(阶段 2:大模型描述、参数收窄、流程暴露),在该功能推出前 没有运行时读取者” (packages/spec/src/stack.zod.ts:595-602)。只有在需要优化现有能力的展示方式时才编写一条——绝不能用它新增能力,也绝不能让某项能力变得可执行:ToolSchema 没有 handler / implementation 字段,也没有框架执行器会加载通过元数据编写的工具。

ToolSchema 是严格的——未知键(拼写错误或已弃用的键)会导致解析错误,而不会被静默剔除。必填字段为 name / label / description 和 JSON Schema parameters 对象;可选字段为 objectName 和 outputSchema(⚠️ 实验性——工具记录中没有任何内容会读取它;应改为在操作上声明 ai.outputSchema,AI 运行时 ☁️ 会通过阻止不符合该模式的结果来强制执行)。在协议 17 中弃用:category、permissions、active、builtIn——这些字段都可以编写,但不起作用;与 requiresConfirmation 一同弃用。每项拒绝都会说明其替代方案。

应通过底层操作(action.requiredPermissions,ADR-0066)或工具所涉及的对象来限制工具能力;要撤销某项工具,只需将其从引用它的技能中移除。分类应设在操作上(action.ai.category——有效,但仅用于列表:会传递到工具上,从不发送给模型)。


模型配置

采样参数位于 Agent 的 model(AIModelConfigSchema)下——Agent 上没有顶层的 temperature / maxTokens(packages/spec/src/ai/agent.zod.ts:36-40):

键约定
provider内联枚举 openai | azure_openai | anthropic | local(默认值为 openai)。模型注册表条目(ModelProviderSchema)接受更多选项:还包括 google、cohere、huggingface、custom
model任意字符串——服务提供商自己的模型名称
temperaturemin(0).max(2),默认值为 0.7。超出 0–2 会导致解析错误
maxTokens / topP可选数字,架构不设上限

常见陷阱

  1. 误把 guardrails 当作关卡。 AI 运行时 ☁️ 会在每轮用户交互中执行 guardrails——令牌和时间限制,以及被拒绝的屏蔽工具名称和类别——但它只是限制,不是审批;AI 运行时 ☁️ 也会执行 memory——会回忆并反思长期笔记;longTerm.enabled 为 true 时,必须设置 maxEntries 和 reflectionInterval,且没有可选的存储后端——这两者都不是关卡。若要使用强制执行的关卡,请使用 enableActionApproval: true(审批队列 ☁️)、操作上的 ai.requiresConfirmation,或 MCP 工具绑定上的 approval: 'always'。AI 元数据编辑本身已有审批关卡:编辑会以草稿形式提交,必须由人工发布(ADR-0033)。 ⚠️ 工具上的 requiresConfirmation 已移除(ADR-0033 §2)——没有任何执行路径读取它,因此不会暂停执行;ToolSchema 是严格的,因此现在编写该字段会导致解析失败。不存在 requireApprovalFor 字段。
  2. 索引所有内容。 缺少 where 过滤条件和精心挑选的 contentFields 的知识源,会让草稿和模板内容填满索引,污染检索。元数据负责保证来源整洁;相关性调优属于适配器的职责。

App AI 蓝图

层文件模式
可复用技能src/skills/lead-qualification.skill.tsdefineSkill — instructions + 触发条件 + 每个名称都能解析的工具集;选择一个 surface
知识源src/knowledge/sales-kb.tsKnowledgeSourceSchema 元数据,通过 KnowledgeServicePlugin({ sources }) 在启动时注册
集中注册defineStack({ skills: [...] })agents / tools / skills 是 AI 技术栈仅有的集合——知识源不属于其中,Agent 由平台提供,而 tools 并非默认路径

元数据应用的默认做法:将业务能力放入 技能,将业务逻辑作为 AI 可调用的 Actions 暴露,通过 知识源 接入领域知识。

平台 Agent — 仅供参考 ☁️

agent 类型对第三方关闭(allowRuntimeCreate:false、 allowEnvironmentOverlay:false;ADR-0063 §2),且 os g agent 已弃用:由 stack 编写的 Agent 会被 listAgents() 过滤,被 loadAgent() 直接拒绝,并在聊天时返回 404。扩展平台要用技能,绝不要 添加 Agent。AgentSchema 的完整字段列表见 references/_index.md。

运行时恰好提供两个 Agent,按使用界面绑定——用户不会从列表中选择,所在的界面会决定使用哪个 Agent。ask 是 数据产品(≈ Claude Chat):面向终端用户,可对记录进行对话式读取 / 查询 / 探索,并运行应用公开的业务操作, 受 RLS 限制,规范 ID 为 ask(ASK_AGENT_NAME),也是任何未设置 app.defaultAgent 的应用的隐式副驾驶。build 是创作产品(≈ Claude Code):面向构建者,通过规划 → 起草 → 验证 → 发布,以 Agent 方式创作元数据,受治理机制约束, 由 Studio 通过 app.defaultAgent 固定。不存在逐轮意图分类器——发给 ask 的 build 类请求会被拒绝并引导至其他界面, 绝不会悄然转入创作流程(ADR-0063 §1/§5)。data_chat→ask 和 metadata_assistant→build 会通过别名表解析,以兼容旧书签和持久化的 agent_id;它们不是规范术语——始终使用 ask / build。

Agent 的工具集是其兼容当前界面的技能所拥有工具的并集——不存在全局回退机制(ADR-0064),因此从设计上讲,ask 无法进行 创作;停用某项技能(active: false)会撤销所有引用该技能的 Agent 的相应能力。内置技能:

技能surface所属工具
schema_readerbothlist_objects、describe_object、query_data
data_exploreraskquery_records、get_record、aggregate_data、visualize_data
actions_executoraskaction_*(对象公开的业务操作)
metadata_authoring + solution_designbuild元数据起草 / 验证 / 发布 + 蓝图提议 / 应用

这四项都是云运行时技能——在开源版中均无法解析,因此你自定义技能中的 surface / tools / triggerConditions 面向云端编写, 在开源版中不会生效;MCP 提供的是它们的 instructions。 visualize_data 是唯一会绘制图表的内置技能(内嵌的 data-chart 部分),且仅在接入分析服务(IAnalyticsService)时自动注册—— query_data / aggregate_data 返回数字,而非图表。

AgentSchema 中有两个键是墓碑字段,不是旧版选项——编写任一字段都会导致解析错误,并附带迁移说明 (packages/spec/src/ai/agent.zod.ts:234, :251):

已弃用的键在 protocol 17 中已移除 — 原因及替代方案
agent.tools内联字段会在完整注册表中按名称解析,不检查界面兼容性。这不是重命名:迁移会删除该键,并列出其中的每个工具;请将每个工具重新声明在技能中(ADR-0064)
agent.knowledge在 Agent 上声明来源 / 索引并不会限定检索范围——search_knowledge 会从模型的工具调用参数中获取 sourceIds。请在知识服务 / 来源级别限制范围;在 instructions 中说明预期的依据

验证你的工作

编写 *.skill.ts / *.tool.ts 后,在报告完成前运行作者时检查:

os validate     # Zod schema + CEL predicate validation + bindings (no artifact)
# or: os build  # the same gates, plus emits dist/

此检查会确认技能 / 工具元数据符合协议。此领域没有 CEL 站点——模型注册表中的 promptTemplate.system / .user 使用 template 方言({{var}});ToolSchema 不包含任何类型的表达式字段。在脚手架生成的项目中, 该检查命令为 npm run validate。参见 objectstack-platform → 验证你的工作。


参考资料

完整的 Zod 架构列表(附一行说明)请参阅 references/_index.md——其中包含指向 node_modules/@objectstack/spec/src/ 的索引。请始终 Read 源文件以确认字段的准确结构;不要凭记忆猜测属性名称。

评论

支持 Markdown