跳转到内容

快速开始

marivo init 初始化项目(参见安装), 然后编写你的声明。一个最小 Marivo 项目包含 manifest、数据源声明 和语义声明:

your-project/
marivo.toml
models/
datasources/
warehouse.py
semantic/
sales/
_domain.py

先声明数据源:

import marivo.datasource as md
md.duckdb(
name="warehouse",
path="warehouse.duckdb",
ai_context={
"business_definition": "Local DuckDB warehouse for sales analysis.",
"guardrails": ["Use only for development or approved local analysis."],
},
)

再声明语义对象:

import marivo.datasource as md
import marivo.semantic as ms
ms.domain(
name="sales",
ai_context={
"business_definition": "Sales order analysis domain.",
"guardrails": ["Revenue metrics should only use completed orders."],
},
)
orders = ms.entity(
name="orders",
datasource=md.ref("datasource.warehouse"),
source=ms.table("orders"),
primary_key=["order_id"],
ai_context={
"business_definition": "One row per sales order.",
"guardrails": ["Exclude cancelled test data in metric definitions."],
},
)
region = ms.dimension_column(
name="region",
entity=orders,
column="region",
ai_context={
"business_definition": "Sales region assigned to the order.",
"guardrails": ["Do not treat missing region as a real region."],
},
)
order_date = ms.time_dimension_column(
name="order_date",
entity=orders,
column="order_date",
granularity="day",
is_default=True,
ai_context={
"business_definition": "Calendar date when the order was placed.",
"guardrails": ["Use this as the default time axis for order metrics."],
},
)
@ms.metric(
entities=[orders],
additivity="additive",
name="revenue",
ai_context={
"business_definition": "Total completed order amount.",
"guardrails": ["Use only where order amount is already net of cancellations."],
},
)
def revenue(orders):
return orders.amount.sum()

你不必手写这些对象。marivo init 已经把 marivo-semantic 技能 安装到 .claude/skills/.codex/skills/,因此在项目中运行的编码智能体(Claude 代码或 Codex)可以和你一起构建 语义层。把它指向你的表并提出请求:

使用 marivo-semantic 技能为 sales 领域中的 orders 表建模。

该技能会引导智能体走一个有纪律的编写循环,每次只处理一个对象:

  • 遵循 ladder —— 领域 → 实体 → 维度 → 时间维度 → 度量 → 指标 → 关系 —— 让每个对象的依赖先于它存在。
  • 先规划,再编写。 对每个对象,智能体先调用 ms.prepare_* API(例如 ms.prepare_metric),根据返回的 brief 分支判断,再把声明写入 models/semantic/<domain>/_domain.py
  • 验证后再前进。 每写完一个对象就运行 ms.verify_object(ref),在它失败时不会继续。
  • 收尾时设闸。 最后运行 ms.readiness(),在把目录交给分析之前解决阻塞项。

智能体只会就那些无法从数据或项目文档推断的决策征询你(例如某个金额是否已扣除退款)。它产出 的,正是上面展示的同一批 Python 声明 —— 可以像其他代码一样在 git 中评审。

分析前先探索目录:

import marivo.semantic as ms
catalog = ms.load()
catalog.list().show()
report = catalog.readiness()
if report.status == "blocked":
report.show()

目录就绪后,开启分析会话:

import marivo.analysis as mv
session = mv.session.get_or_create(name="revenue-check", question="Why did Q4 drop?")
catalog = session.catalog
revenue = catalog.get("sales.revenue")
region = catalog.get("sales.orders.region")
current = session.observe(
revenue,
timescope={"start": "2026-10-01", "end": "2027-01-01"},
grain="month",
dimensions=[region],
)
baseline = session.observe(
revenue,
timescope={"start": "2025-10-01", "end": "2026-01-01"},
grain="month",
dimensions=[region],
)
delta = session.compare(current, baseline)
attribution = session.decompose(delta, axis=region)
attribution.show()

同样的项目结构,可以从一次性脚本一路扩展到经过评审、可共享的分析项目。三个习惯决定 了差别。

把语义层当作共享的知识库来建设

Section titled “把语义层当作共享的知识库来建设”

语义层不只是触达表的管道 —— 它是智能体在分析之前所读取的知识库。在每个对象上 投入 ai_context

  • business_definition —— 这个指标或维度在业务上意味着什么
  • guardrails —— 智能体必须遵守的规则:必需的过滤、排除项、范围限制。
  • synonymsexamples —— 让智能体把自然语言问题解析到正确的对象,而不是靠猜。

一个充分丰富的对象,无需人类介入就能回答智能体的“我能用它吗,怎么用?”。就绪检查守住底线: 缺失 business_definition 会阻塞分析,缺失 guardrails 会发出警告。完整的 ai_context 契约参见 语义层

一个 Marivo 项目就是纯文本:marivo.toml 加上 models/ 下的 Python 文件。这让语义 layer 成为一个可评审、可共享的工件 —— 把它当作应用代码来对待。

  • 对契约做版本控制。 提交 marivo.tomlmodels/。对指标定义或 guardrail 的每一次 改动都会以 diff 的形式呈现。
  • 像评审代码一样评审语义改动。 通过 pull 请求合入定义改动,让领域负责人在 智能体使用之前批准一个指标的含义
  • 通过仓库共享。 任何 clone 该项目的人 —— 以及任何在其中运行的智能体 —— 都得到同一份 可信目录。
  • 把状态与密钥排除在 git 之外。.marivo/ 加入 .gitignore:它保存的是项目 本地的会话与证据状态,不是契约。凭据以 *_env 引用的形式编写,从环境(或 缓存于 user-global 的 ~/.marivo/secrets.toml)解析 —— 它们从不写入项目。

一个典型的 .gitignore

.marivo/

加载后运行 ms.readiness(),并在任何分析会话之前解决阻塞项。一个项目可以在 就绪检查仍为 blocked 时成功加载,因此绝不要把一个 blocked 的目录交给智能体。参见 就绪检查