智能体
dev.to ·
@ArisynData
为企业级 AI 版本化业务语义
文章讨论企业数据 agent 面临的语义版本化问题:SQL 可以完全可复现,但业务含义会随时间变化,例如 Revenue 定义从 v3 的确认收入变为 v4 的确认收入减去已批准调整。作者认为语义层需要引入版本、生效时间和审批状态等生命周期管理,而非仅做业务术语到指标的静态映射。
AI推荐理由 文章指出企业数据 agent 的 SQL 可复现但业务语义不可复现的问题,提出语义层需要版本、生效时间和审批状态等生命周期管理,并以 Revenue 定义从 v3 到 v4 的变化为例。该问题对企业级 AI 数据 agent 的落地有实际参考价值,但属于概念性论述,未提供实现或验证结果。
62
正文
Your SQL can be perfectly reproducible while your business meaning is not.
Suppose a user asks:
What was revenue in Q1?
Your data agent resolves Revenue, generates valid SQL, executes it successfully, and returns a number.
Now suppose Finance changed the definition of Revenue in June.
The old definition was:
Revenue v3
=
Recognized Revenue
Enter fullscreen mode
Exit fullscreen mode
The new definition is:
Revenue v4
=
Recognized Revenue
- Approved Adjustments
Enter fullscreen mode
Exit fullscreen mode
When the same user asks about Q1 in September, which definition should the agent use?
That is not an SQL problem.
It is a semantic versioning problem.
Enterprise data agents need more than a mapping from:
Business Term → Metric
Enter fullscreen mode
Exit fullscreen mode
They increasingly need:
Business Term
↓
Metric
↓
Version
↓
Effective Time
↓
Approval State
↓
Physical Mapping
Enter fullscreen mode
Exit fullscreen mode
If business meaning changes over time, the semantic layer needs a lifecycle.
Why a Static Semantic Layer Breaks Down
A basic semantic registry might store:
{
"id": "revenue",
"name": "Revenue",
"field": "finance_revenue.recognized_amount",
"aggregation": "SUM"
}
Enter fullscreen mode
Exit fullscreen mode
That works until the definition changes.
If the object is simply overwritten, you lose important information:
What was the previous definition?
When did the change become effective?
Who approved it?
Which answers used the old definition?
Should historical periods use the old or new logic?
Enter fullscreen mode
Exit fullscreen mode
A production semantic object should therefore be treated more like a versioned artifact than a mutable label.
Model Semantic Objects as Immutable Versions
One useful pattern is to separate the stable identity of a business concept from its versions.
Metric Identity
revenue
│
├── v1
├── v2
├── v3
└── v4
Enter fullscreen mode
Exit fullscreen mode
For example:
{
"metric_id": "revenue",
"version": 4,
"definition": "Recognized revenue after approved adjustments",
"expression": {
"type": "formula",
"value": "recognized_revenue - approved_adjustments"
},
"owner": "finance",
"status": "published",
"effective_from": "2026-06-01",
"effective_to": null
}
Enter fullscreen mode
Exit fullscreen mode
Do not mutate v3 into v4.
Create a new version.
That preserves historical meaning.
Separate Version Time From Business Time
This is where implementation gets interesting.
There are at least two relevant timelines.
System time
When was the semantic definition created or published?
created_at
published_at
deprecated_at
Enter fullscreen mode
Exit fullscreen mode
Effective business time
When is the definition supposed to apply?
effective_from
effective_to
Enter fullscreen mode
Exit fullscreen mode
These are not always the same.
Finance might approve a new metric definition on June 10 but make it effective from June 1.
So a semantic object may need:
{
"published_at": "2026-06-10T09:00:00Z",
"effective_from": "2026-06-01",
"effective_to": null
}
Enter fullscreen mode
Exit fullscreen mode
This distinction is essential for historical queries.
Resolve Semantics With Time Context
A semantic resolver should not simply do:
metric = registry.get("revenue")
Enter fullscreen mode
Exit fullscreen mode
It needs temporal context.
Conceptually:
metric = registry.resolve(
metric_id="revenue",
effective_at=query_time
)
Enter fullscreen mode
Exit fullscreen mode
For a question like:
What was revenue in January?
the pipeline becomes:
Question
↓
Intent Resolution
↓
Metric = Revenue
↓
Time Context = January
↓
Applicable Semantic Version
↓
Physical Mapping
↓
Query Plan
Enter fullscreen mode
Exit fullscreen mode
This is version-aware semantic resolution.
But Historical Queries Have Two Meanings
There is an important complication.
When someone asks:
What was Revenue in January?
they may mean:
Historical interpretation
Calculate Revenue using the definition that was valid in January.
or:
Restated interpretation
Calculate January data using today's Revenue definition.
These can produce different numbers.
So your semantic system may need an explicit policy:
{
"historical_metric_policy": "as_was"
}
Enter fullscreen mode
Exit fullscreen mode
or:
{
"historical_metric_policy": "restated"
}
Enter fullscreen mode
Exit fullscreen mode
In some environments, the right answer may depend on the metric itself.
If the system cannot determine the intended policy safely, clarification may be better than silently guessing.
Comparison Queries Are Harder
Now consider:
Compare Q1 and Q3 Revenue.
Suppose the definition changed in Q2.
If you use each period's historical definition:
Q1 → Revenue v3
Q3 → Revenue v4
Enter fullscreen mode
Exit fullscreen mode
the comparison may not be semantically consistent.
If you restate both periods using v4:
Q1 → Revenue v4
Q3 → Revenue v4
Enter fullscreen mode
Exit fullscreen mode
the comparison is consistent, but it no longer represents exactly what the organization reported in Q1.
This decision belongs in business governance.
The LLM should not invent the policy.
Version More Than Metrics
Metrics are the obvious case, but other semantic objects can change too.
Business terms
"Active Customer"
Enter fullscreen mode
Exit fullscreen mode
may change definition.
Semantic mappings
"Product Code"
→ product_master.material_id
Enter fullscreen mode
Exit fullscreen mode
may later become:
"Product Code"
→ product_dim.product_code
Enter fullscreen mode
Exit fullscreen mode
Dimensions
Region
Business Unit
Product Category
Customer Segment
Enter fullscreen mode
Exit fullscreen mode
can change structure.
Business rules
Valid Order
Eligible Customer
Completed Transaction
Enter fullscreen mode
Exit fullscreen mode
can change inclusion logic.
If a change can alter analytical results, it should be traceable.
A Generic Semantic Version Model
You can model semantic objects with a shared envelope:
{
"object_id": "metric.revenue",
"object_type": "metric",
"version": 4,
"lifecycle": {
"status": "published",
"owner": "finance",
"approved_by": "finance_governance"
},
"validity": {
"effective_from": "2026-06-01",
"effective_to": null
},
"provenance": {
"created_at": "2026-05-28T08:12:00Z",
"published_at": "2026-06-10T09:00:00Z",
"previous_version": 3
},
"payload": {
"definition": "...",
"expression": "...",
"physical_mapping": "..."
}
}
Enter fullscreen mode
Exit fullscreen mode
The payload differs by semantic object type.
The lifecycle and provenance model can remain consistent.
Add Lifecycle States
Versioning alone is not governance.
A new definition should not automatically become production truth.
A useful lifecycle might be:
Draft
↓
Review
↓
Validated
↓
Published
↓
Deprecated
Enter fullscreen mode
Exit fullscreen mode
This prevents a work-in-progress definition from being used by production agents.
For example:
{
"metric_id": "gross_margin",
"version": 5,
"status": "draft"
}
Enter fullscreen mode
Exit fullscreen mode
should not automatically replace:
{
"metric_id": "gross_margin",
"version": 4,
"status": "published"
}
Enter fullscreen mode
Exit fullscreen mode
in production query resolution.
Controlled Rollout Matters
Sometimes a semantic change needs to be tested before becoming the default.
Conceptually:
Gross Margin v5
↓
Test Workspace
↓
Selected Users
↓
Validation
↓
Production
Enter fullscreen mode
Exit fullscreen mode
This is similar to feature rollout in software systems.
The semantic definition itself becomes a governed production artifact.
A platform such as Semora already treats business semantic definitions, mappings, metrics and dimensions as governed objects alongside version and controlled-release management. That is the right architectural direction: meaning needs lifecycle management, not just storage.
Define Material vs. Non-Material Changes
Do not create a new analytical version for every edit.
A typo fix:
"recgonized revenue"
→
"recognized revenue"
Enter fullscreen mode
Exit fullscreen mode
does not change analytical behavior.
A formula change does.
A practical classification:
NON-MATERIAL
- spelling
- description wording
- examples
- documentation
MATERIAL
- formula
- aggregation
- source field
- semantic mapping
- filter rule
- inclusion/exclusion logic
- hierarchy
Enter fullscreen mode
Exit fullscreen mode
Only material changes need to create a new analytical version.
You can still audit non-material edits separately.
Compute a Semantic Diff
When a new version is created, show what changed.
Example:
Revenue v3 → v4
- expression:
- recognized_revenue
+ expression:
+ recognized_revenue - approved_adjustments
+ effective_from:
+ 2026-06-01
Enter fullscreen mode
Exit fullscreen mode
For mappings:
Product Code v1 → v2
- product_master.material_id
+ product_dim.product_code
Enter fullscreen mode
Exit fullscreen mode
A semantic diff is much easier to review than comparing two large JSON objects manually.
Dependency Analysis Before Publishing
Semantic objects rarely exist alone.
Suppose:
Gross Margin
Enter fullscreen mode
Exit fullscreen mode
depends on:
Revenue
Enter fullscreen mode
Exit fullscreen mode
If Revenue changes, downstream metrics may be affected.
Represent dependencies:
Revenue
↓
Gross Profit
↓
Gross Margin
Enter fullscreen mode
Exit fullscreen mode
Before publishing Revenue v4:
Change
↓
Dependency Graph
↓
Impacted Metrics
↓
Validation
↓
Publish
Enter fullscreen mode
Exit fullscreen mode
This is where semantic governance begins to resemble software dependency management.
Keep Semantic Versions in the Query Plan
Once a version is resolved, preserve it.
A semantic query plan should not contain only:
{
"metric": "revenue"
}
Enter fullscreen mode
Exit fullscreen mode
Prefer:
{
"metric": {
"id": "revenue",
"version": 4
}
}
Enter fullscreen mode
Exit fullscreen mode
Then downstream stages know exactly which meaning was selected.
Persist Versions Into Answer Lineage
The final answer should preserve the semantic version that produced it.
{
"answer_id": "ans_9281",
"question": "What was revenue in Germany in July?",
"semantic_evidence": {
"metric_id": "revenue",
"metric_version": 4,
"mapping_version": 2
},
"query_id": "q_18273"
}
Enter fullscreen mode
Exit fullscreen mode
Six months later, you can reconstruct the answer even if Revenue has moved to v5.
This is reproducible meaning.
Why SQL Versioning Is Not Enough
Imagine storing the generated SQL:
SELECT SUM(recognized_amount - adjustment_amount)
FROM finance_revenue;
Enter fullscreen mode
Exit fullscreen mode
That tells you what executed.
But it does not necessarily tell you:
Why this expression represented Revenue
Which business definition authorized it
Who owned that definition
When it became effective
Enter fullscreen mode
Exit fullscreen mode
SQL provenance and semantic provenance solve different problems.
Production AI analytics needs both.
Cache Carefully
Semantic versioning also affects caching.
A cache key like:
hash(question)
Enter fullscreen mode
Exit fullscreen mode
is unsafe if the semantic definition changes.
A better cache identity may include:
Question
+
Semantic Version
+
Data Source Version / Freshness
+
Policy Context
Enter fullscreen mode
Exit fullscreen mode
Conceptually:
cache_key = hash(
question,
metric_version,
mapping_version,
policy_version
)
Enter fullscreen mode
Exit fullscreen mode
Otherwise the system can return an answer generated under outdated semantics.
Version-Aware Retrieval
If semantic retrieval uses embeddings, versioning creates another issue.
Suppose both:
Revenue v3
Revenue v4
Enter fullscreen mode
Exit fullscreen mode
exist in the semantic index.
The retriever should not blindly return whichever vector is closest.
Retrieval needs governance filters:
semantic_search(
term="revenue",
status="published",
effective_at=query_time
)
Enter fullscreen mode
Exit fullscreen mode
Similarity identifies candidates.
Governance determines which candidate is valid.
Audit Every Semantic Resolution
For production use, log:
{
"question_id": "qst_182",
"term": "revenue",
"resolved_object": "metric.revenue",
"resolved_version": 4,
"effective_at": "2026-07-15",
"resolution_source": "semantic_registry"
}
Enter fullscreen mode
Exit fullscreen mode
This makes semantic decisions observable.
If an answer is disputed, you can inspect exactly which definition the system used.
A Reference Resolution Pipeline
Putting the pieces together:
Natural-Language Question
↓
Intent Resolution
↓
Business Concept
↓
Extract Time Context
↓
Semantic Registry
↓
Filter:
- published
- effective at time
- allowed for user
↓
Resolve Version
↓
Resolve Physical Mapping
↓
Relationship Context
↓
Semantic Query Plan
↓
SQL
↓
Answer
↓
Answer Lineage
Enter fullscreen mode
Exit fullscreen mode
The LLM does not decide which semantic version is authoritative.
The governed semantic layer does.
What to Test
Semantic versioning needs its own test cases.
Current definition
Question:
What is Revenue this month?
Expected:
Latest published effective version
Enter fullscreen mode
Exit fullscreen mode
Historical definition
Question:
What was Revenue in January?
Expected:
Historical version or governed restatement policy
Enter fullscreen mode
Exit fullscreen mode
Cross-version comparison
Question:
Compare Q1 and Q3 Revenue.
Expected:
Explicit comparison policy
Enter fullscreen mode
Exit fullscreen mode
Draft version
Revenue v5 = draft
Expected:
Production agent does not use it
Enter fullscreen mode
Exit fullscreen mode
Deprecated mapping
Product Code v1 = deprecated
Expected:
New queries use the published replacement
Enter fullscreen mode
Exit fullscreen mode
These are semantic correctness tests, not SQL syntax tests.
What to Measure
Useful operational metrics include:
% queries using published semantic objects
% answers with semantic version lineage
Semantic resolution failures
Queries affected by semantic changes
Deprecated-version usage
Average approval time for material changes
Enter fullscreen mode
Exit fullscreen mode
These help teams operate the semantic layer as production infrastructure.
Final Thoughts
Enterprise AI cannot treat business meaning as a static prompt.
Metrics change.
Mappings change.
Business rules change.
Dimensions change.
And historical questions still need to remain explainable and reproducible.
The architecture therefore needs to move from:
Term → Definition
Enter fullscreen mode
Exit fullscreen mode
to:
Term
↓
Governed Semantic Object
↓
Version
↓
Effective Time
↓
Approval State
↓
Physical Mapping
↓
Query
Enter fullscreen mode
Exit fullscreen mode
The key engineering principle is:
Version the meaning, not just the code that implements it.
Because a perfectly reproducible SQL query can still produce the wrong business answer if the system cannot reproduce the meaning that was valid when the question was asked.