How to Use the Channel Finder#

The Channel Finder translates natural language queries (e.g., “beam current,” “terminal voltage”) into control system addresses (e.g., SR:DCCT:Current, TMVST). It uses LLM-based pipelines, so a query can use everyday terms rather than exact channel names.

See also

Hellert et al. (2025), From Natural Language to Control Signals, arXiv:2512.18779.

Choosing a Pipeline#

Set the active pipeline in config.yml:

channel_finder:
  pipeline_mode: in_context  # or "hierarchical" or "middle_layer"

When pipeline_mode is unset, OSPREY auto-detects: it uses the first pipeline that has a database configured, preferring middle layer, then hierarchical, then in-context.

Pipeline

Best for

In-Context

Small/medium systems (< few hundred channels)

Hierarchical

Large systems with strict naming patterns

Middle Layer

Large systems organized by function (MML)

In-Context Pipeline#

Loads the entire channel database into the LLM context for direct semantic matching.

How it works: a single inner-LLM call — the complete channel database is embedded in the system prompt and the model returns the most relevant channels in one shot (no query-splitting or iterative-correction stage).

The database uses a flat JSON structure loaded by TemplateChannelDatabase, with standalone entries and template entries for device families:

{
  "channels": [
    {"template": false, "channel": "TerminalVoltageReadBack",
     "address": "TerminalVoltageReadBack",
     "description": "Actual value of the terminal potential"},
    {"template": true, "base_name": "BPM", "instances": [1, 10],
     "sub_channels": ["XPosition", "YPosition"],
     "address_pattern": "BPM{instance:02d}{suffix}",
     "description": "Beam Position Monitors"}
  ]
}

Build a database from CSV, then validate and preview:

osprey channel-finder build-database --use-llm
osprey channel-finder validate
osprey channel-finder preview

Note

build-database writes to data/processed/channel_database.json by default, while the pipelines — and a bare validate / preview — read the database referenced in config.yml (under data/channel_databases/). After building, either point the commands at the new file with --database or update the config path — otherwise you are silently validating the old database.

Hierarchical Pipeline#

Navigates a nested hierarchy (system, family, device, field, subfield) using recursive LLM-guided selection at each level.

The database defines levels and a naming pattern:

{
  "hierarchy": {
    "levels": [
      {"name": "system", "type": "tree"},
      {"name": "family", "type": "tree"},
      {"name": "device", "type": "instances"},
      {"name": "field", "type": "tree"},
      {"name": "subfield", "type": "tree"}
    ],
    "naming_pattern": "{system}:{family}[{device}]:{field}:{subfield}"
  },
  "tree": { }
}

Advanced features: navigation-only levels, friendly names via _channel_part, optional levels with _is_leaf, and custom separators via _separator.

Validate and preview:

osprey channel-finder validate
osprey channel-finder preview --depth 4 --sections tree,stats

Middle Layer Pipeline#

A React agent explores the database using query tools (list_systems, list_families, inspect_fields, list_channels, get_common_names, statistics, validate, and — when DuckDB is installed — query_channels).

The database follows MATLAB Middle Layer (MML) functional organization (System -> Family -> Field -> ChannelNames). Convert from MML exports:

python -m osprey.services.channel_finder.utils.mml_converter \
   --input path/to/mml_exports.py:MML_ao_SR \
   --output data/channel_databases/middle_layer.json

Web Interface#

Launch the browser-based channel explorer:

osprey channel-finder web
osprey channel-finder web --port 9000

Configuration Reference#

Key config.yml settings:

channel_finder:
  pipeline_mode: in_context  # "in_context", "hierarchical", or "middle_layer"
  pipelines:
    in_context:
      database: {type: template, path: data/channel_databases/in_context.json}
    hierarchical:
      database: {type: hierarchical, path: data/channel_databases/hierarchical.json}
    middle_layer:
      database: {type: middle_layer, path: data/channel_databases/middle_layer.json}
  benchmark:
    dataset_path: data/benchmarks/queries.json
    # Concurrency and output dir are set per run via CLI flags
    # (osprey channel-finder benchmark --concurrency / --output-dir);
    # they are not read from config.yml.

Framework Integration#

Each pipeline is exposed to the agent through a dedicated MCP server (channel_finder_in_context, channel_finder_hierarchical, channel_finder_middle_layer). The active server is selected from channel_finder.pipeline_mode in config.yml and wired into the agent’s artifacts when you run osprey build (or osprey claude regen after editing the config). There is no public Python find_channels(...) entry point — drive the resolver from natural language via the agent, or invoke the CLI directly:

osprey channel-finder generate     # build database from template
osprey channel-finder benchmark    # evaluate on a query dataset

Tip

Use osprey eject service channel_finder to copy the channel finder service source into your project for custom modifications.