Skip to content

The Intent Store

An intent is one kind of search that users ask for, such as find vouchers or find employees. The Intent Store is the catalog of intents. It’s what the LLM chooses from, and what the NL Search Service checks every plan against: if a search isn’t in the Intent Store, NL Search can’t run it.

Each intent is a YAML file:

intents/find_vouchers.yaml
intent: find_vouchers
label: Vouchers
description: >-
Find accounts payable vouchers by supplier, amount,
entry date, and status.
category: ZZ_VOUCHERS # the search category to search
text_search: false # no free-text descriptions to match
examples:
- Vouchers over $10,000 from Acme entered last month
- Unpaid vouchers for Globex
- Vouchers entered this week that are still open
- Invoices from Initech we haven't paid
- Approved vouchers under $500
fields:
supplier:
attribute: VENDOR_NAME
type: text
operators: [contains]
amount:
attribute: GROSS_AMT
type: number
operators: [greater_than, less_than, between]
entered:
attribute: ENTERED_DT
type: date
operators: [on, before, after, between]
status:
attribute: VOUCHER_STATUS
type: code
operators: [equals, not_equals]
values:
open: O
approved: A
paid: P
Key What it does
intent The intent’s name, which plans refer to
label The name users see at the start of the summary, such as Vouchers
description What the intent finds. The LLM reads it to decide whether the intent fits the question
category The search category the plan runs against
text_search Whether plans can include words to search for, as well as filters
examples Questions this intent answers, used to match questions to intents and to teach the LLM
fields What users can filter on, each mapped to an attribute of the category’s search definition
synonyms Optional. The words users say, mapped to the words your data uses

Each field maps a word users understand, such as supplier, to an attribute of the search definition, such as VENDOR_NAME. A field can only filter on data that PeopleSoft indexes, so every attribute must be part of the search definition.

Point each intent at a category whose search definitions all have its attributes, which usually means a category with a single search definition, such as ZZ_VOUCHERS. A filter on an attribute that only some of the category’s definitions have leaves out every document from the others.

The field’s type decides which operators make sense, and how values are checked:

Type Operators Values
text equals, not_equals, contains Text, such as a supplier name
number equals, greater_than, less_than, between Numbers, without currency symbols or separators
date on, before, after, between Dates in YYYY-MM-DD format
code equals, not_equals One of the words in values
user equals Only me, meaning the user’s ID
employee equals Only me, meaning the user’s employee ID

The operators list on each field narrows these further. A plan that uses any other operator on the field is rejected.

For text, equals needs the attribute’s whole value, while contains matches when a word in the attribute starts with the value, so Acme matches Acme Corporation. Use contains for names, which users rarely type in full. The application class turns each operator into a Search Framework filter, such as ContainsWord for contains, and EqualsString for equals on text.

PeopleSoft stores many values as codes, such as P for a paid voucher. A code field lists the words users say, and the code each one stands for. The LLM chooses among the words, and the service turns them into codes, so “unpaid vouchers” becomes status not_equals paid, and then VOUCHER_STATUS not equal to P. Users never need to know the codes.

Many questions are about the person asking, such as “my open requisitions”. A user field handles them without the LLM knowing who that is:

intents/find_requisitions.yaml (excerpt)
fields:
requester:
attribute: REQUESTOR_ID
type: user
operators: [equals]

The only value a user field accepts is me. The plan says requester equals me, and PeopleSoft’s application class replaces me with the signed-in user’s ID, from %UserId, before it runs the search. For an attribute that holds an employee ID, such as EMPLID, use the employee type, and the application class uses %EmployeeId instead. Either way, the LLM never learns who asked.

For intents with text_search, synonyms maps the words users say to the word your data uses, so the LLM can put that word in the plan’s text:

synonyms:
laptop: notebook
display: monitor

With this, a question about laptops searches for notebook. On PeopleTools 8.63 and later, semantic search matches words by meaning, and synonyms matter less.

When the Intent Store loads, the service converts every intent’s examples into vector embeddings. For each question, it finds the intents with the most similar examples, and offers the LLM the closest five. The LLM picks one of them, or none.

When no intent fits, the plan’s intent is null, and the search page falls back to an ordinary keyword search with the question as typed, so the user still gets results.

The Intent Store is a folder of YAML files in version control. Every change is reviewed, and the service loads a released set of intents. Each plan records the Intent Store version it was made with, so you can always tell which definitions a search used.

  1. Check the search definition. Every field users will filter on must be an attribute of the search definition behind the category. If one isn’t, add the column to its query, map it as an attribute, redeploy the definition, and run a full index build. See From data to index.

  2. Write the intent file, with a clear description, the fields, and at least five varied examples.

  3. Add test questions, with the plans you expect, to the test set.

  4. Run the tests, and release the new Intent Store version when they pass.

  5. Check who can use it. NL Search doesn’t change who can find what: users who can’t search the category in PeopleSoft get no results from it here either. Check the definition’s security too, because a definition with no security is open to everyone.