Retrieve knowledge
Search published knowledge, discover skills and answers together, and control relevance and result size.
Retrieve published knowledge for the user's task. Choose a retrieval method:
- Discovery combines FAQ answers and skill previews so the agent can choose what to use.
- Search returns one entry type when your application needs answers or skill previews, with a relevance threshold and result count for each request.
Both methods serve current publications. They exclude drafts, historical versions, and proposals.
Before you begin
Use a data-plane endpoint, playbook identifier, and API key with read permission. Publish the entries you want to retrieve before testing them.
Start with the quickstart's client setup with a reader key, then append this page's snippets in order. The examples use the published FAQ and skill from the task guides; keep them published until testing is complete.
Discovery
Discovery returns answers and skill previews within a shared result limit. Pins include required entries; a preview budget limits returned content.
Use Python's discover helper, send an HTTP discovery request, or call discover_entries through MCP. Load selected skill instructions and files with progressive disclosure.
Request up to five entries for the agent's task:
discovery = playbook.discover(
"Draft a reply for a customer whose refund shows Processing", limit=5
)
print(discovery.as_prompt())
from redis_iris.agent_playbooks import AgentPlaybooks
playbook = AgentPlaybooks.from_env()
print(playbook.client.get_playbook_health())
discovery = playbook.discover(
"Draft a reply for a customer whose refund shows Processing", limit=5
)
print(discovery.as_prompt())
import os
skill_id = os.environ["PLAYBOOK_SKILL_ID"]
pinned = playbook.discover(
"Draft a reply for a customer whose refund shows Processing",
pin=[skill_id],
)
selected_preview = pinned.pinned[0]
print(selected_preview.entry_id, selected_preview.version)
print("Result limit reached:", pinned.truncated)
print("Preview budget reached:", pinned.budget_truncated or False)
skill = playbook.skill(selected_preview)
print(skill.instructions)
resource = next((r for r in skill.resources if r.path == "references/reply-template.md"), None)
if resource is None:
raise ValueError("Reply template is missing")
response = playbook.skill_resource(selected_preview, resource.resource_id)
print(response.text)
faq_results = playbook.client.search_faqs(query="Where is my refund?", limit=5)
skill_results = playbook.client.search_skills(query="Draft a reply about a reported refund stage", limit=5)
print(faq_results.model_dump_json(by_alias=True, indent=2))
print(skill_results.model_dump_json(by_alias=True, indent=2))
tuned = playbook.client.search_faqs(query="Where is my refund?", min_score=0.75, limit=3)
print(tuned.items)
filtered = playbook.client.search_faqs(
query="Where is my refund?",
filter_={
"and_": [
{"eq": {"name": "locale", "value": "en-US"}},
{"eq": {"name": "topic", "value": "refund"}},
]
},
)
print(filtered.model_dump_json(by_alias=True, indent=2))
cat > discover.json <<'JSON'
{
"query": "Draft a reply for a customer whose refund shows Processing",
"limit": 5
}
JSON
iris --json agent-playbooks discover --input discover.json | jq .
set -euo pipefail
iris agent-playbooks health
cat > discover.json <<'JSON'
{
"query": "Draft a reply for a customer whose refund shows Processing",
"limit": 5
}
JSON
iris --json agent-playbooks discover --input discover.json | jq .
jq -n --arg id "$PLAYBOOK_SKILL_ID" '{
query: "Draft a reply for a customer whose refund shows Processing",
pinnedEntries: [{entryId: $id}],
limit: 5
}' > pinned-discover.json
iris --json agent-playbooks discover --input pinned-discover.json > pinned.json
jq '.pinnedEntries[0] | {entryId, version}' pinned.json
jq '{truncated, budgetTruncated: (.budgetTruncated // false)}' pinned.json
iris --json agent-playbooks faqs search 'Where is my refund?' --limit 5 | jq .
iris --json agent-playbooks skills search 'Draft a reply about a reported refund stage' --limit 5 | jq .
iris --json agent-playbooks faqs search 'Where is my refund?' --min-score 0.75 --limit 3 | jq .items
cat > filtered-search.json <<'JSON'
{
"query": "Where is my refund?",
"filter": {
"and": [
{"eq": {"name": "locale", "value": "en-US"}},
{"eq": {"name": "topic", "value": "refund"}}
]
}
}
JSON
iris --json agent-playbooks faqs search --input filtered-search.json | jq .
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/entries/discover" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"query":"Draft a reply for a customer whose refund shows Processing","limit":5}' | jq .
set -euo pipefail
set -euo pipefail
PLAYBOOK_API="${IRIS_AGENT_PLAYBOOKS_URL%/}/iris/data/v1/agent-playbooks/playbooks/$IRIS_AGENT_PLAYBOOKS_PLAYBOOK_ID"
curl --fail-with-body --silent --show-error \
"$PLAYBOOK_API/health" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" | jq .
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/entries/discover" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"query":"Draft a reply for a customer whose refund shows Processing","limit":5}' | jq .
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/entries/discover" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data "$(jq -n --arg id "$PLAYBOOK_SKILL_ID" '{query: "Draft a reply for a customer whose refund shows Processing", pinnedEntries: [{entryId: $id}], limit: 5}')" > discovery.json
jq '.pinnedEntries[0] | {entryId, version}' discovery.json
jq '{truncated, budgetTruncated: (.budgetTruncated // false)}' discovery.json
SKILL_ID=$(jq -er '.pinnedEntries[0].entryId' discovery.json)
SKILL_VERSION=$(jq -er '.pinnedEntries[0].version' discovery.json)
curl --fail-with-body --silent --show-error \
"$PLAYBOOK_API/skills/$SKILL_ID/versions/$SKILL_VERSION" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" > selected-skill.json
jq -r '.content.payload.skill.instructions' selected-skill.json
RESOURCE_ID=$(jq -er '.content.payload.skill.resources[] | select(.path == "references/reply-template.md") | .resourceId' selected-skill.json)
curl --fail-with-body --silent --show-error \
"$PLAYBOOK_API/skills/$SKILL_ID/versions/$SKILL_VERSION/resources/$RESOURCE_ID" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY"
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/faqs/search" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"query":"Where is my refund?","limit":5}' | jq .
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/skills/search" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"query":"Draft a reply about a reported refund stage","limit":5}' | jq .
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/faqs/search" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"query":"Where is my refund?","minScore":0.75,"limit":3}' | jq .items
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/faqs/search" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"query":"Where is my refund?","filter":{"and":[{"eq":{"name":"locale","value":"en-US"}},{"eq":{"name":"topic","value":"refund"}}]}}' | jq .
Python's unified SDK exposes matches as discovery.discovered and pins as discovery.pinned. as_prompt() renders their context for an agent. The CLI accepts the same JSON discovery request as cURL through --input FILE and returns the API response with --json.
How discovery selects entries
Discovery applies these steps:
- Resolve each pin to its current published version, preserving request order.
- Reserve result slots and preview budget for the pins.
- Rank matching FAQs and skills together using the query, attribute filter, and each type's similarity threshold. Exclude pinned entries from these matches.
- Fill the remaining slots in rank order. When a preview does not fit the remaining token budget, skip it and consider later candidates that may fit.
- Return pins in
pinnedEntriesand ranked matches indiscoveredEntries, with count and budget truncation signals.
If pins fill every result slot, discovery returns only the pins. An FAQ preview includes its question and answer. A skill preview includes its name, description, entry identifier, version, and file address.
Configure discovery
Discovery accepts these HTTP or CLI JSON fields and Python playbook.client.discover_entries arguments:
| HTTP/CLI field | Python argument | Use it to |
|---|---|---|
query |
query |
Describe the agent's task. Required even when supplying pins. |
filter |
filter_ |
Restrict semantic matches by attributes. Uses the same filter expressions as search; pins bypass it. |
limit |
limit |
Reduce the combined result count. Omission uses discovery.maxResults, which also caps an explicit limit. |
pinnedEntries |
pinned_entries |
Require published entries in request order. Each reference contains exactly one entryId or entryKey (entry_id or entry_key in Python). |
The unified playbook.discover(question, pin=[...]) helper used in this page accepts entry identifiers or keys as strings. It sends a default limit of 5, still bounded by discovery.maxResults. For MCP argument names, see MCP tools.
Your administrator sets the playbook controls:
| Setting | Default | Effect |
|---|---|---|
discovery.faqMinimumScore |
0.7 |
Minimum similarity for discovered FAQ matches. |
discovery.skillMinimumScore |
0.7 |
Minimum similarity for discovered skill matches. |
discovery.maxResults |
10 |
Combined result ceiling for pins and discovered matches. |
discovery.previewTokenBudgetEnabled |
false |
Enable the discovery preview ceiling. |
discovery.previewTokenBudget |
Unset | Estimated token ceiling, at least 64. It applies only when discovery.previewTokenBudgetEnabled is true. |
Discovery has no per-request similarity override. An administrator can adjust the playbook thresholds in its discovery policy.
Pin required knowledge
Use discovery pins when a task must include a known published entry. Supply exactly one entry identifier or entry key for each pin. Discovery returns pins in request order, separately from semantic matches.
Pins bypass similarity thresholds and the request filter. Choose pins for the intended audience yourself. They still consume result slots and preview budget.
A missing, unpublished, duplicate, or oversized pin fails the request. Use pins to test connectivity or include required content; evaluate semantic relevance without them.
Export the identifier of a published skill, such as the sample in Manage skills, before cleanup:
export PLAYBOOK_SKILL_ID='<published-skill-entry-id>'
import os
skill_id = os.environ["PLAYBOOK_SKILL_ID"]
pinned = playbook.discover(
"Draft a reply for a customer whose refund shows Processing",
pin=[skill_id],
)
selected_preview = pinned.pinned[0]
print(selected_preview.entry_id, selected_preview.version)
jq -n --arg id "$PLAYBOOK_SKILL_ID" '{
query: "Draft a reply for a customer whose refund shows Processing",
pinnedEntries: [{entryId: $id}],
limit: 5
}' > pinned-discover.json
iris --json agent-playbooks discover --input pinned-discover.json > pinned.json
jq '.pinnedEntries[0] | {entryId, version}' pinned.json
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/entries/discover" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data "$(jq -n --arg id "$PLAYBOOK_SKILL_ID" '{query: "Draft a reply for a customer whose refund shows Processing", pinnedEntries: [{entryId: $id}], limit: 5}')" > discovery.json
jq '.pinnedEntries[0] | {entryId, version}' discovery.json
Limit discovery previews
Use the preview budget to limit the knowledge returned in one discovery response. It excludes model framing, conversation history, loaded instructions, and fetched files. Your application still controls the model's total context.
| HTTP/CLI field | Unified Python property | Meaning when true |
|---|---|---|
truncated |
truncated |
Eligible fetched candidates exceed the slots left after pins. This does not count every match in the playbook. |
budgetTruncated |
budget_truncated |
Matching previews were skipped to fit the token ceiling. |
Empty results with budgetTruncated: true can mean matches did not fit. Shorten FAQ answers or skill descriptions, or raise the ceiling through your administrator. Increasing the result count does not increase the token budget. Type-specific search does not use this budget.
print("Result limit reached:", pinned.truncated)
print("Preview budget reached:", pinned.budget_truncated or False)
jq '{truncated, budgetTruncated: (.budgetTruncated // false)}' pinned.json
jq '{truncated, budgetTruncated: (.budgetTruncated // false)}' discovery.json
Load skills with progressive disclosure
Progressive disclosure lets an agent select a skill from its description before loading instructions and files. Discovery and skill search support the same loading steps.
- Discover previews. Retrieve names and descriptions so the agent can assess which skills match the task. FAQ answers are already included in the result.
- Select a skill. Keep the entry identifier and version from the same preview together.
- Load instructions. Retrieve that version's instructions and resource descriptors. With MCP, call
load_skillusing the selectedentry_idandversion. - Fetch files as needed. Retrieve only supporting files needed for the task. Use returned resource identifiers or URIs. With MCP, pass the returned
uritofetch_resource. - Add content to context. Your application chooses the instructions and files to give the model and controls any actions it takes.
The preview budget applies only to the first step, not loaded instructions, files, or total model context.
Reader keys can load only the current publication. MCP tools apply this restriction even to management keys. For example, discovery can return version 1, then loading fails because version 2 was published in the meantime. Rediscover once, select again, and load instructions and files from the newly returned version. Keeping an identifier/version pair does not reserve access to an older publication.
The example loads the skill selected in Pin required knowledge, then fetches its reply template. For a complete MCP client example, see Connect a client.
skill = playbook.skill(selected_preview)
print(skill.instructions)
resource = next((r for r in skill.resources if r.path == "references/reply-template.md"), None)
if resource is None:
raise ValueError("Reply template is missing")
response = playbook.skill_resource(selected_preview, resource.resource_id)
print(response.text)
SKILL_ID=$(jq -er '.pinnedEntries[0].entryId' discovery.json)
SKILL_VERSION=$(jq -er '.pinnedEntries[0].version' discovery.json)
curl --fail-with-body --silent --show-error \
"$PLAYBOOK_API/skills/$SKILL_ID/versions/$SKILL_VERSION" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" > selected-skill.json
jq -r '.content.payload.skill.instructions' selected-skill.json
RESOURCE_ID=$(jq -er '.content.payload.skill.resources[] | select(.path == "references/reply-template.md") | .resourceId' selected-skill.json)
curl --fail-with-body --silent --show-error \
"$PLAYBOOK_API/skills/$SKILL_ID/versions/$SKILL_VERSION/resources/$RESOURCE_ID" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY"
Use an SDK or cURL for this reader-only operation. The published CLI's skill-loading commands perform management lookup, which requires write or publish. Discovery and search CLI examples work with the reader key.
Search
Search returns ranked items of one entry type. Use it to find an answer, select a skill, or tune retrieval per request.
| Operation | Use it when | Result |
|---|---|---|
search_faqs |
Your application needs an answer. | Ranked FAQ matches with questions and answers. |
search_skills |
Your application needs a procedure. | Ranked skill previews with names, descriptions, and file addresses. |
Send a query that describes the task and relevant conditions. A support question such as “How can I check an existing refund?” is more useful than a query containing only “refund.”
Semantic matching compares your query with the FAQ question or the skill's name and description. Include the task and distinguishing conditions in those fields. FAQ answers, intents, metadata, skill instructions, and supporting files do not contribute to similarity scores. Attributes narrow the eligible matches through filters. These rules apply to both search and discovery.
Retain returned entry identifiers and versions with the content you select.
faq_results = playbook.client.search_faqs(query="Where is my refund?", limit=5)
skill_results = playbook.client.search_skills(query="Draft a reply about a reported refund stage", limit=5)
print(faq_results.model_dump_json(by_alias=True, indent=2))
print(skill_results.model_dump_json(by_alias=True, indent=2))
iris --json agent-playbooks faqs search 'Where is my refund?' --limit 5 | jq .
iris --json agent-playbooks skills search 'Draft a reply about a reported refund stage' --limit 5 | jq .
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/faqs/search" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"query":"Where is my refund?","limit":5}' | jq .
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/skills/search" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"query":"Draft a reply about a reported refund stage","limit":5}' | jq .
Control relevance and result count
Search accepts these HTTP fields and Python playbook.client.search_faqs or playbook.client.search_skills arguments:
| HTTP field | Python argument | Default | Use it to |
|---|---|---|---|
query |
query |
Required | Describe the task to match semantically. |
filter |
filter_ |
None | Restrict matches by entry attributes, such as locale or topic. |
minScore |
min_score |
The playbook's threshold for that entry type; initially 0.7 |
Set a similarity floor from 0 to 1 for this request. |
limit |
limit |
discovery.maxResults; initially 10 |
Request 1–50 results. An explicit search limit is not capped by the playbook's discovery limit. |
The threshold defaults come from discovery.faqMinimumScore and discovery.skillMinimumScore. Your administrator can change them. Search does not use discovery pins or the discovery preview budget.
Similarity ranks matches; it does not measure answer correctness. Test “Where is my refund?” against “How do I request a refund?” The first needs the sample status answer; the second needs different guidance. Compare results across paraphrases before choosing a threshold. Higher thresholds can remove useful matches too. If no relevant match remains, ask for clarification or route to support.
For example, override the FAQ search threshold and result count for one request:
tuned = playbook.client.search_faqs(query="Where is my refund?", min_score=0.75, limit=3)
print(tuned.items)
iris --json agent-playbooks faqs search 'Where is my refund?' --min-score 0.75 --limit 3 | jq .items
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/faqs/search" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"query":"Where is my refund?","minScore":0.75,"limit":3}' | jq .items
Select an audience with filters
Set attributes when authoring FAQs or uploading skills. Filter retrieval by those attributes to select a locale, product, or audience.
Filters use exact, typed comparisons. Each HTTP filter node has one operator: eq, and, or or. Python dictionaries use and_ and or_; eq is unchanged.
An equality filter matches a scalar attribute or a member of a list-valued attribute. Boolean true, integer 1, and string "true" are different values. Filters do not search metadata and do not replace playbook access grants.
filtered = playbook.client.search_faqs(
query="Where is my refund?",
filter_={
"and_": [
{"eq": {"name": "locale", "value": "en-US"}},
{"eq": {"name": "topic", "value": "refund"}},
]
},
)
print(filtered.model_dump_json(by_alias=True, indent=2))
cat > filtered-search.json <<'JSON'
{
"query": "Where is my refund?",
"filter": {
"and": [
{"eq": {"name": "locale", "value": "en-US"}},
{"eq": {"name": "topic", "value": "refund"}}
]
}
}
JSON
iris --json agent-playbooks faqs search --input filtered-search.json | jq .
curl --fail-with-body --silent --show-error \
-X POST "$PLAYBOOK_API/faqs/search" \
-H "Authorization: Bearer $IRIS_AGENT_PLAYBOOKS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"query":"Where is my refund?","filter":{"and":[{"eq":{"name":"locale","value":"en-US"}},{"eq":{"name":"topic","value":"refund"}}]}}' | jq .
Use entry lookup or list operations for management state. Lists use pagination cursors; search and discovery use result limits. See service limits and errors for request constraints and recovery.