[
https://issues.apache.org/jira/browse/CAMEL-24977?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Luigi De Masi resolved CAMEL-24977.
-----------------------------------
Fix Version/s: 4.23.0
Resolution: Fixed
> Add provider-agnostic semantic evaluation across Camel EIPs and error handling
> ------------------------------------------------------------------------------
>
> Key: CAMEL-24977
> URL: https://issues.apache.org/jira/browse/CAMEL-24977
> Project: Camel
> Issue Type: New Feature
> Components: camel-ai, camel-core, camel-yaml-dsl, eip
> Reporter: Luigi De Masi
> Assignee: Luigi De Masi
> Priority: Major
> Fix For: 4.23.0
>
>
> h2. Motivation
> Provide a provider-agnostic semantic evaluation API and Camel language so
> route authors can ask named questions about message content and use the
> resulting boolean decisions, categories, or scores across EIPs. For example,
> classify a support message, assess urgency, decide whether another attempt is
> worthwhile after a failure, validate whether an output addresses a request,
> or check whether a permitted action serves an approved task. The reusable
> capability is semantic evaluation; routing, validation, error handling and
> contextual action checks are applications of that capability.
> CAMEL-24871 added the Jev integration. This proposal builds on that work by
> separating the common question/evaluation contract from provider-specific
> implementations and using existing Camel EIP expression and predicate APIs.
> Jev can implement the common SPI, and other hosted or local classifiers can
> implement it without requiring Jev wire compatibility.
> The desired authoring experience is declarative: named questions in the same
> YAML file as routes, automatic provider-adapter discovery, and direct use
> through Camel's language integration. Route authors should not need to
> instantiate a predicate or adapter bean for the normal case.
> This is a design proposal. The syntax below illustrates the intended
> behavior; public names, packaging and exact DSL/schema details require
> community review. It does not claim that the proposed semantic language is
> already available.
> Keep the artifact name {{camel-semantic}} and language identifier
> {{semantic}}. Use *Semantic Evaluation* as the public catalog title and
> describe it as: "Evaluate named questions about message content to produce
> boolean decisions, categories and scores through provider adapters."
> h2. Common semantic evaluation contract
> * Define provider-independent question and result types for categorical
> Choice, yes/no judgments (including probability-to-boolean decision policy),
> and scoring against descriptive ordered levels. Preserve the useful shape of
> Jev Choice/Noul/Score through its adapter; final common type names should not
> force other providers to adopt Jev terminology.
> * Separate the selected category/value, probabilities, provider confidence,
> uncertainty policy and operational errors. A probability, a confidence
> measure and a guarantee of correctness are not interchangeable. Preserve
> provider metadata where useful without requiring all providers to report the
> same optional fields.
> * A provider component advertises an adapter implementing the common SPI. The
> adapter maps questions/state to its backend, validates supported
> capabilities, and maps typed results back to the common contract.
> * Expose evaluations through Camel's existing {{Language}}, {{Expression}}
> and {{Predicate}} contracts. Predicate use requires a boolean decision or
> explicit comparison/threshold policy; a category string is not implicitly a
> predicate.
> * Keep provider credentials, model selection, transport/inference
> configuration, and provider-specific resources with the implementing
> component. Define thread safety, bounded evaluation, cancellation and
> lifecycle behavior. Synchronous Predicate/Expression evaluation must document
> any blocking inference call.
> h2. Named questions and state in YAML
> Support a dedicated top-level {{semantic.question}} declaration from the
> initial version, alongside route definitions. The following is proposed
> syntax:
> {code}
> - semantic:
> question:
> department:
> type: choice
> state: ${header.myState}
> instructions: Which department should handle this message?
> criteria:
> billing: Invoices, payments, and refunds
> technical: Bugs, outages, and technical problems
> other: Everything else
> - route:
> id: ticket-routing
> from:
> uri: direct:tickets
> steps:
> - setProperty:
> name: department
> expression:
> language:
> language: semantic
> expression: "ref:department"
> - choice:
> when:
> - expression:
> simple:
> expression: "${exchangeProperty.department} == 'billing'"
> steps:
> - to: direct:billing
> - expression:
> simple:
> expression: "${exchangeProperty.department} ==
> 'technical'"
> steps:
> - to: direct:technical
> otherwise:
> steps:
> - to: direct:general
> {code}
> Each question owns its input-state selector. An optional language default can
> be configured:
> {code}
> camel.language.semantic.default-state=${body}
> {code}
> Proposed precedence: question {{state}}, then configured {{default-state}},
> then built-in {{${body}}}. Use Camel Simple expressions for these selectors
> initially. Compile/initialize selectors during route setup and evaluate
> against the current exchange at runtime. Only an absent selector inherits the
> default: a malformed selector or an explicitly selected header that evaluates
> to null must not silently cause different data to be classified. Input values
> are data, not recursively evaluated expressions.
> Question declarations need loader, validation, schema and tooling support.
> Provide the YAML resolver from {{camel-semantic}} through the YAML DSL
> extension mechanism; the core YAML DSL must not depend on the semantic
> component. Keep YAML support optional for Java applications using semantic
> evaluation. Resolve references before traffic where possible; reject
> duplicate names, unknown references and unsupported question capabilities.
> Define behavior across multiple route resources and reload without retaining
> obsolete definitions. Loading/validating declarations must not perform
> inference.
> h2. Adapter discovery and explicit selection
> The language must not require a provider endpoint URI such as
> {{jev:decisions}}. With exactly one advertised adapter implementation
> available, discover and select it automatically. With none, report a missing
> provider; with multiple, report the candidates and require explicit
> selection. Do not choose by classpath order or construct every provider
> during discovery.
> Allow an explicit reference to an existing registered instance:
> {code}
> camel.language.semantic.adapter=mySemanticAdapter
> {code}
> Alternatively, accept a fully qualified class name:
> {code}
> camel.language.semantic.adapter=com.example.MySemanticAdapter
> {code}
> The example class is illustrative. Use plain bean or class names, without
> {{#bean:}} or {{#class:}} prefixes. Registry lookup takes precedence over
> class resolution; this uses normal property binding without extending the
> core property-configurer SPI. For a class-selected or discovered adapter, the
> semantic infrastructure should resolve and type-check the class through
> Camel, instantiate it using the context Injector, register it once for the
> language configuration, and integrate its lifecycle. Reuse referenced beans
> without duplicating their existing lifecycle ownership. Define registry
> ownership, collision handling and startup-failure cleanup; binding an object
> does not itself establish service lifecycle management.
> Provider configuration must remain effective even when the route contains no
> provider endpoint. For example, a Jev adapter must honor the configured Jev
> component's credentials and connection options. A manually declared adapter
> bean is an optional customization path, not a prerequisite for normal
> operation.
> h2. Choice integration through the existing model
> Keep Camel's existing Choice, When and expression models unchanged. Boolean
> questions can be used directly as ordinary when predicates. For category
> questions, evaluate once using Set Property or Set Header and compare the
> stored category using ordinary Choice predicates:
> {code:java}
> from("direct:tickets")
> .setProperty("department").language("semantic", "ref:department")
> .choice()
> .when(exchangeProperty("department").isEqualTo("billing"))
> .to("direct:billing")
> .when(exchangeProperty("department").isEqualTo("technical"))
> .to("direct:technical")
> .otherwise()
> .to("direct:general")
> .end();
> {code}
> * Perform one evaluation each time execution reaches the Set Property or Set
> Header step. Branch predicates reuse the stored result without invoking the
> provider again.
> * Place that evaluation step inside a loop or retry path when changed state
> must be reevaluated. Nested decisions can use distinct properties to retain
> independent results. There is no implicit exchange-wide semantic-result cache.
> * Valid categories without an explicit matching branch follow ordinary Choice
> otherwise behavior. Inference and invalid-response failures follow Camel
> error handling; uncertainty requires an explicit policy.
> * Keep Choice precondition behavior unchanged. Message-dependent semantic
> predicates belong in runtime routes, not in startup preconditions evaluated
> against a dummy exchange.
> * Use existing Java, XML and YAML expression/predicate forms. No Choice
> selector, literal when-value syntax, core EIP model changes or new routing
> EIP is included in this issue.
> h2. Evaluation across other EIPs
> The following are candidate uses, not a requirement to introduce
> semantic-specific changes to every EIP.
> || EIP / integration point || Example question or benefit || Integration ||
> | Filter | Is this message relevant to this workflow? | A boolean predicate.
> Existing regression tests already cover semantic filtering. |
> | Validate | Does this bug report describe an actionable problem? | A boolean
> decision supplies the validation predicate; negative decisions use normal
> validation failure handling. |
> | Set Header / Set Property | Attach department, sentiment or urgency to a
> message. | Store a category or score for explicit reuse by subsequent
> processors. |
> | Aggregate: grouping | Group feedback by delivery, pricing or usability. |
> Use a category as part of the correlation key, retaining tenant/case
> boundaries and bounded aggregation windows where needed. |
> | Aggregate: completion | Does the accumulated conversation contain enough
> information to proceed? | Evaluate a boolean completion predicate against
> selected aggregate state, alongside a size or timeout completion condition. |
> | Recipient List | Send a complaint to support and the relevant product team.
> | Map a category, or multiple independent decisions, to configured
> recipients. |
> | Routing Slip | Select a document-processing sequence. | Map a document
> category to a predefined sequence of endpoints. |
> | Enrich | Choose the appropriate knowledge source for a support request. |
> Map a topic to a configured enrichment endpoint; ordinary code retrieves and
> merges the additional data. |
> | Loop | Continue refinement while the updated output remains incomplete. |
> Reevaluate a semantic predicate against current state, with an explicit
> iteration/time budget. |
> | Sort | Order a batch of tickets by assessed urgency. | Score each item
> once, then compare stored scores with a deterministic comparator. |
> | On Exception / retryWhile | Given this failure, is another attempt
> worthwhile? | Use a boolean predicate with an explicit retry budget checked
> before inference. {{retryWhile}} replaces the normal {{maximumRedeliveries}}
> decision; the predicate must enforce the cap itself. A negative decision or
> exhausted budget follows the configured escalation path. |
> | Contextual action validation | Does this proposed action serve the approved
> task? | Apply existing identity, permission and tenant checks first, then
> Validate with a semantic predicate before the action. Negative, uncertain or
> failed evaluations must not execute the action. No dedicated semantic
> {{AuthorizationPolicy}} implementation is required. |
> | Intercept / Intercept Send To Endpoint | Does this outgoing message require
> review? | Use {{onWhen}} to conditionally intercept processing or divert a
> send across selected routes. When enforcing a gate, configure interception to
> prevent the original send on rejection. |
> | Dynamic Router | Given the updated state, which processing step should run
> next? | Map a category to a configured endpoint after each step. Enforce a
> hop budget and explicitly return {{null}} from the routing expression to
> finish. |
> | Split with Filter or Validate | Which individual records are relevant or
> acceptable? | Split an existing collection, then evaluate each item. Semantic
> evaluation does not itself extract or generate the collection. |
> | Poll Enrich / To Dynamic | Which configured source or service should handle
> this content? | Classify first, then map the label to an approved endpoint.
> This extends the destination-mapping pattern used for Enrich. |
> | Throttle | Is this request routine or expensive to process? | Classify into
> configured workload groups, then apply deterministic rate or concurrency
> limits. The model does not invent limits. |
> | On Completion | Does this completed interaction warrant follow-up? |
> Evaluate for auditing, review or follow-up processing. This cannot prevent
> actions already performed. |
> Validate, metadata assignment and Aggregate can consume Predicate/Expression
> results directly. Recipient List, Routing Slip and Enrich require a mapping
> from semantic labels to route-author-defined destinations. The classifier
> does not invent endpoint addresses or processing steps.
> For aggregate completion, the aggregation strategy must expose the relevant
> accumulated content; the classifier does not implicitly remember earlier
> exchanges. The default completion predicate sees the aggregated exchange,
> while {{eagerCheckCompletion}} uses the incoming exchange. State selection
> must match that behavior.
> For Sort, the EIP expression selects the collection and the comparator
> determines ordering. Inference belongs before comparison. For loops or
> changed input, explicit result reuse must not hide relevant state changes.
> Bounded retry and contextual action validation use existing Camel hooks and
> are part of the focused documentation and integration-test scope. Prepare
> current failure context in {{onExceptionOccurred}}, before the retry
> predicate; {{onRedelivery}} runs later. A retry-predicate evaluation error
> propagates as an error and does not automatically execute the normal
> escalation route. For contextual action validation, keep authentication,
> permissions and tenant boundaries authoritative; semantic evaluation is an
> additional check, and its failures must prevent execution.
> h2. Broader Camel applications
> * *AI tool and MCP routes:* check whether a proposed tool action fits the
> approved task before executing it, alongside existing permissions. Camel
> exposes tools through ordinary routes, so contextual validation can be
> applied there. See [Camel's tool authorization
> example|https://camel.apache.org/blog/2026/09/securing-ai-agent-tools/].
> * *Input and output quality checks:* ask "Is this request sufficiently
> specified?" or "Does this answer address the request?" Route-level validation
> can surround an AI component. Direct integration into LangChain4j's internal
> guardrail interfaces would require an additional bridge; the semantic
> language does not provide that bridge. See [LangChain4j Agent guardrail
> support|https://camel.apache.org/components/4.22.x/langchain4j-agent-component.html].
> * *Retrieval relevance and ranking:* evaluate retrieved documents against the
> question, filter irrelevant passages, and score candidates before
> deterministic sorting. This combines Split, Filter, Set Property and Sort; it
> complements retrieval rather than implementing a search engine.
> The additional combinations are integration candidates inferred from existing
> extension points, not a claim that all combinations have been tested.
> Evaluation quality depends on the provider and question. Keep candidate
> exploration distinct from the initial regression coverage below; no
> semantic-specific changes to the core EIP models are required.
> h2. Acceptance criteria and initial coverage
> # A common provider-independent question/result contract and adapter SPI
> support direct semantic Expression/Predicate use without requiring manual
> predicate instances.
> # A YAML file can declare named questions under {{semantic.question}} and
> reference them from routes. Loader, schema, validation and tooling support
> agree on the proposed configuration.
> # Adapter discovery, bean-reference override and class-name override are
> tested, including missing/ambiguous providers, wrong types, instance reuse,
> configuration and lifecycle behavior.
> # Question state overrides the language default; omitting both uses the body.
> Invalid selectors and missing selected state produce useful errors without
> silent input substitution.
> # Choice integration uses the unchanged EIP model: store a category once per
> evaluation step and route with ordinary predicates. Tests cover invocation
> counts, first/later/otherwise branches, preservation of message content and
> reevaluation after state changes in a loop. Boolean questions remain usable
> directly as predicates.
> # Demonstrate Choice, Filter, Validate, Set Header / Set Property, Aggregate,
> Recipient List, Routing Slip, Enrich, bounded Loop and Sort integration.
> Document the additional candidate integrations and their mapping/state
> requirements without assuming every EIP needs a core change.
> # Document and test bounded semantic retry: approval followed by success,
> negative decision and budget exhaustion leading to escalation, refreshed
> failure state, no inference after the budget is exhausted, and propagation of
> timeout, malformed-response and uncertainty errors without another attempt.
> # Document and test contextual action validation: ordinary permission denial
> prevents inference and action; a permitted action proceeds only after a
> positive semantic decision; negative, uncertain and failed evaluations
> prevent execution. Use existing Validate and authorization services without
> introducing a dedicated semantic authorization policy.
> # Provide a Jev adapter and validate the contract with deterministic test
> adapters, including a second implementation and capability mismatch cases. Do
> not claim interchangeability of model quality, probabilities or calibration.
> # Tests cover meaningful result mappings, invocation counts,
> threshold/uncertainty policy, explicit result reuse, changed-state
> reevaluation, timeouts/failures and preservation of message content. Routine
> tests require no live model credentials.
> # Document the supported property namespaces and runtime configuration paths.
> Coordinate with the generic-language starter work in CAMEL-24913 and
> CAMEL-24914 rather than assuming language configuration is generated
> automatically.
> h2. Boundaries and references
> Choosing a local inference runtime (pure JVM/WASM versus native inference),
> model weights, or a particular hosted service is outside this proposal's
> initial decision. A provider can implement Jev API compatibility, but the
> common SPI does not require it and does not imply equivalent proprietary
> model behavior or calibration. The SPI's final package, discovery metadata
> and public syntax remain open to design review.
> Related work:
> * CAMEL-24871 — Jev component and semantic EIP integration background.
> * CAMEL-24913 — Jev Spring Boot starter configuration.
> * CAMEL-24914 — Starter generation for languages backed by the generic model.
> * CAMEL-17755 — Existing Choice precondition design.
> * [Camel Language
> SPI|https://github.com/apache/camel/blob/main/core/camel-api/src/main/java/org/apache/camel/spi/Language.java]
> * [Choice
> model|https://github.com/apache/camel/blob/main/core/camel-core-model/src/main/java/org/apache/camel/model/ChoiceDefinition.java]
> * [Aggregate
> EIP|https://camel.apache.org/components/next/eips/aggregate-eip.html]
> * [Intercept|https://camel.apache.org/components/next/eips/intercept.html]
> * [Dynamic Router
> EIP|https://camel.apache.org/components/next/eips/dynamicRouter-eip.html]
> * [On Completion|https://camel.apache.org/manual/oncompletion.html]
> * [Retry predicates|https://camel.apache.org/manual/exception-advanced.html]
> * [System One Models|https://systemonemodels.org/]
> _AI-generated by Codex on behalf of
> [luigidemasi|https://github.com/luigidemasi]._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)