| name | searchcli-volcengine-ai-search |
| description | CLI for integrating Volcengine AI Search, recommendation, and conversational retrieval into agent and business systems |
| triggers | ["integrate AI search into my application","set up Volcengine search CLI","configure AI-powered search and recommendations","onboard data to Volcengine AI Search","build conversational retrieval with SearchCLI","tune search quality with Viking","create item search with SearchCLI","run search evaluation and tuning"] |
SearchCLI (Volcengine AI Search)
Skill by ara.so — Devtools Skills collection.
SearchCLI is the open-source CLI for Volcengine AI Search. It provides stable, tunable search, recommendation, and conversational retrieval capabilities for agent systems and business applications. Built with TypeScript, it offers agent-friendly workflows with installable skills, dry-runs, confirmation gates, and automated quality tuning.
What It Does
- Item & Catalog Search: Build search on structured business data
- Recommendation Flows: Connect recommendations to application scenes and user behavior
- Conversational Retrieval: Create RAG-style chat experiences grounded in application search
- Agent Workflows: Onboard data, configure applications, and validate behavior with reviewable steps
- Automated Tuning: Text-similarity evaluation and query tuning with LLM-based relevance judging
Installation
Requirements
- Node.js 20 or newer
- Git
- Volcengine AK/SK with AI Search access
Install SearchCLI
git clone git@github.com:volcengine/SearchCLI.git vs
cd vs
bash ./scripts/install.sh
Install as Agent Skills (for AI Agents)
npx skills add "git@github.com:volcengine/SearchCLI.git" -y -g
This installs bundled skills:
vs-shared
vs-item-onboarding
vs-search
vs-search-tuning
vs-chat
vs-recommend
Authentication
Using Environment Variables
If VIKING_AK and VIKING_SK are already in your environment:
vs auth import-env
vs auth status --json
Interactive Login
vs auth login
vs auth status --json
vs doctor --json
LLM Configuration (for Search Tuning)
For query generation and LLM-based relevance judging:
vs llm login
vs llm status --json
vs llm import-env
vs llm status --json
Verify LLM connectivity:
vs search tune llm-check --live --json
Core Command Groups
Authentication & Setup
vs auth login
vs auth import-env
vs auth status --json
vs llm login
vs llm import-env
vs doctor --json
Item Onboarding
vs item profile --file ./items.json --pretty
vs item plan --file ./items.json --goal "Build item search"
vs item apply --plan-dir ./.viking/item-plans/<plan> --dry-run
vs item apply --plan-dir ./.viking/item-plans/<plan> --confirm-review --wait-ready --run-trials
Dataset Management
vs dataset create --data @dataset-create.json
vs dataset ingest --dataset-id <id> --fields @<file>
vs dataset list --json
vs dataset describe --dataset-id <id> --json
Application Management
vs app list --json
vs app describe --app-id <id> --json
vs app create --data @app-config.json
vs app update --app-id <id> --data @update.json
Search Operations
vs search run --app-id <id> --query "search term" --json
vs search tune query-generate --dataset-id <id> --output ./queries.json
vs search tune plan --queries @queries.json --dataset-id <id>
vs search tune run --plan-dir ./plan --output ./results.json
vs search tune report --results @results.json --pretty
Recommendation
vs recommend run --app-id <id> --user-id <uid> --json
Conversational Retrieval
vs chat run --app-id <id> --query "What are the best products?" --json
Workflows
Dataset + App Provisioning (Full Onboarding)
Complete workflow for creating both dataset and search application:
vs item profile --file ./items.json --pretty
vs item plan --file ./items.json --goal "Build product search"
vs item apply --plan-dir ./.viking/item-plans/<plan-id> --dry-run
vs item apply \
--plan-dir ./.viking/item-plans/<plan-id> \
--confirm-review \
--wait-ready \
--run-trials
Dataset-Only Provisioning
When you only need data ingestion without application setup:
vs item plan --file ./items.json --goal "Ingest product data" --skip-app
vs dataset create --data @dataset-create.json
vs dataset ingest --dataset-id <dataset-id> --fields @<normalized-items-artifact>
The --skip-app flag works with vs item provision and vs item apply as a guardrail.
Video Dataset Provisioning
Always specify --type video explicitly for video datasets:
vs item profile --file ./videos.jsonl --type video --pretty
vs item plan --file ./videos.jsonl --type video --goal "Build video search"
vs item apply --plan-dir ./.viking/item-plans/<plan> --confirm-review --wait-ready
vs item plan --file ./videos.jsonl --type video --goal "Video data" --skip-app
vs dataset create --data @dataset-create.json
vs dataset ingest --dataset-id <id> --fields @<artifact>
Important: For video datasets, prefer dataset-create.json over --schema @schema.json to include DataFieldConfig and avoid MissingParameter.DefaultFieldStrategy errors.
Search Quality Tuning
Automated evaluation and tuning workflow:
vs search tune query-generate \
--dataset-id <dataset-id> \
--output ./eval-queries.json
vs search tune plan \
--queries @eval-queries.json \
--dataset-id <dataset-id>
vs search tune run \
--plan-dir ./.viking/search-tune-plans/<plan-id> \
--output ./results.json
vs search tune report \
--results @results.json \
--pretty
Code Examples
TypeScript: Item Data Structure
[
{
"id": "prod-001",
"name": "Wireless Headphones",
"description": "High-quality Bluetooth headphones with noise cancellation",
"category": "Electronics",
"price": 149.99,
"tags": ["audio", "bluetooth", "noise-canceling"],
"in_stock": true
},
{
"id": "prod-002",
"name": "Smart Watch",
"description": "Fitness tracking smartwatch with heart rate monitor",
"category": "Wearables",
"price": 299.99,
"tags": ["fitness", "health", "smartwatch"],
"in_stock": true
}
]
TypeScript: Dataset Create Payload
{
"Name": "product-catalog-v1",
"Type": "item",
"Schema": {
"Fields": [
{
"FieldName": "id",
"FieldType": "String",
"IsPrimaryKey": true
},
{
"FieldName": "name",
"FieldType": "String"
},
{
"FieldName": "description",
"FieldType": "Text"
},
{
"FieldName": "price",
"FieldType": "Float"
},
{
"FieldName": "tags",
"FieldType": "List<String>"
}
]
},
"DataFieldConfig": {
"DefaultFields": {
"Title": "name",
"Body": "description"
}
}
}
TypeScript: Search Application Config
{
"Name": "product-search-app",
"DatasetId": "<dataset-id>",
"SearchConfig": {
"RankingStrategy": "TextSimilarity",
"TextSimilarityConfig": {
"Fields": ["name", "description"],
"Weights": {
"name": 2.0,
"description": 1.0
}
}
}
}
Bash: Complete Onboarding Script
#!/bin/bash
set -e
vs doctor --json
vs item profile --file ./products.json --pretty
vs item plan --file ./products.json --goal "E-commerce product search"
PLAN_DIR=$(ls -dt ./.viking/item-plans/* | head -1)
vs item apply --plan-dir "$PLAN_DIR" --dry-run
vs item apply \
--plan-dir "$PLAN_DIR" \
--confirm-review \
--wait-ready \
--run-trials
echo "Onboarding complete. Check ./.viking/item-plans/ for artifacts."
TypeScript: Programmatic Search
import { execSync } from 'child_process';
function runSearch(appId: string, query: string): any {
const result = execSync(
`vs search run --app-id ${appId} --query "${query}" --json`,
{ encoding: 'utf-8' }
);
return JSON.parse(result);
}
function runRecommendation(appId: string, userId: string): any {
const result = execSync(
`vs recommend run --app-id ${appId} --user-id ${userId} --json`,
{ encoding: 'utf-8' }
);
return JSON.parse(result);
}
const searchResults = runSearch('app-123', 'wireless headphones');
console.log('Search results:', searchResults);
const recommendations = runRecommendation('app-123', 'user-456');
console.log('Recommendations:', recommendations);
TypeScript: Evaluation Query Generation
[
{
"query": "wireless bluetooth headphones",
"expectedRelevance": {
"prod-001": "high",
"prod-003": "medium"
}
},
{
"query": "fitness tracking watch",
"expectedRelevance": {
"prod-002": "high"
}
}
]
Configuration
Environment Variables
export VIKING_AK="your-access-key"
export VIKING_SK="your-secret-key"
export VIKING_LLM_BASE_URL="https://api.openai.com/v1"
export VIKING_LLM_API_KEY="sk-..."
export VIKING_LLM_MODEL="gpt-4"
vs auth import-env
vs llm import-env
Credential Storage
SearchCLI stores credentials securely:
- API Keys: Local secure credential store (not plain text config)
- LLM Base URL & Model: Stored as non-secret config
- Plan Artifacts:
./.viking/ directory (safe to version control after removing sensitive data)
Output Formats
Most commands support --json for machine-readable output:
vs auth status --json
vs dataset list --json
vs search run --app-id <id> --query "test" --json
Use --pretty for human-readable formatting:
vs item profile --file ./items.json --pretty
vs search tune report --results @results.json --pretty
Common Patterns
Incremental Data Updates
vs dataset ingest --dataset-id <id> --fields @new-items.json --mode append
vs dataset ingest --dataset-id <id> --fields @all-items.json --mode replace
Multi-Stage Verification
vs item apply --plan-dir <plan> --dry-run
vs item apply --plan-dir <plan> --confirm-review
vs item apply --plan-dir <plan> --confirm-review --run-trials
Search Result Validation
vs search run \
--app-id <app-id> \
--query "test query" \
--json > search-results.json
jq '.Results | length' search-results.json
Skill-Based Agent Integration
await agent.useSkill('vs-item-onboarding', {
file: './products.json',
goal: 'Build product search',
skipApp: false
});
await agent.useSkill('vs-search', {
appId: 'app-123',
query: 'wireless headphones'
});
Troubleshooting
Authentication Failures
vs auth status --json
vs auth login
echo $VIKING_AK
echo $VIKING_SK
vs doctor --json
Dataset Creation Errors
Error: MissingParameter.DefaultFieldStrategy (common with video datasets)
vs dataset create --name video-data --type video --schema @schema.json
vs dataset create --data @dataset-create.json
Solution: Always use dataset-create.json from the plan artifact, which includes both Schema and DataFieldConfig.
Item Ingestion Issues
vs dataset describe --dataset-id <id> --json
vs item profile --file ./items.json --pretty
vs dataset ingest --dataset-id <id> --fields @<normalized-artifact>
LLM Connectivity Issues
vs llm status --json
vs search tune llm-check --live --json
vs llm login
Plan Execution Failures
vs item apply --plan-dir <plan> --dry-run
ls -la ./.viking/item-plans/<plan>/
cat ./.viking/item-plans/<plan>/plan.json | jq .
Search Tuning Not Working
vs llm status --json
vs search tune llm-check --live --json
vs search tune query-generate --dataset-id <id> --output ./new-queries.json
ls -la ./.viking/search-tune-plans/<plan>/
Permission Errors
vs doctor --json
vs dataset list --json
vs app list --json
Agent Skill Installation
vs skill list
vs skill install all
vs skill validate
Best Practices
- Always use dry-run first:
--dry-run shows what will happen without executing
- Use confirmation gates:
--confirm-review adds human review step for critical operations
- Prefer dataset-create.json: Especially for video datasets, use full payloads over schema-only
- Store credentials securely: Never commit AK/SK to version control; use environment variables
- Version control plans: The
.viking/ directory contains reproducible plans (clean sensitive data first)
- Use JSON output for automation:
--json flag provides machine-readable output
- Validate with runtime trials:
--run-trials ensures end-to-end functionality
- Type video datasets explicitly: Always pass
--type video for video data
Related Resources