Build a Natural‑Language Easysearch Assistant with LLM‑Powered Tool Use (No DSL Required)

This article shows how to create an Easysearch intelligent assistant that lets users manage indexes, write data, search and aggregate documents using Chinese natural language, by combining the DeepSeek large‑language model with OpenAI‑compatible function calling (Tool Use) and a lightweight Node.js executor.

Mingyi World Elasticsearch
Mingyi World Elasticsearch
Mingyi World Elasticsearch
Build a Natural‑Language Easysearch Assistant with LLM‑Powered Tool Use (No DSL Required)

Overview

The Easysearch intelligent assistant lets users control Easysearch—a Chinese search engine compatible with the Elasticsearch REST API—through Chinese natural‑language commands without writing DSL. It uses the DeepSeek LLM (accessed via the OpenAI SDK) with OpenAI‑compatible function calling (Tool Use) to interpret intent, select a predefined tool, fill its parameters, and let a local executor issue the actual HTTP request.

Tool definition ( tools.js )

Eight tools are declared, each with name, description and a JSON‑Schema parameters object. The tools fall into two categories:

Query : search_documents, aggregate_data, list_indices, get_mapping Write & structure : create_index, put_mapping, index_document, bulk_index Descriptions explicitly state when the tool should be used and what each parameter means, enabling the model to choose the correct tool and populate arguments.

Executor layer ( executor.js )

An Easysearch client is built with axios using configuration from .env. The function executeTool(toolName, toolInput) dispatches to the corresponding implementation:

Query tools construct Elasticsearch‑compatible DSL and call POST /_search or GET /_cat/indices / GET /_mapping.

Write tools send: PUT /{index} for

create_index
PUT /{index}/_mapping

for

put_mapping
POST /{index}/_doc

for single‑document indexing POST /_bulk with application/x‑ndjson for bulk indexing

Key implementation details include URL‑encoding index names with encodeURIComponent, using date_histogram with calendar_interval for time‑based aggregations, and handling bulk payloads as NDJSON.

Main program ( index.js )

An OpenAI client is created with baseURL: 'https://api.deepseek.com' and model: 'deepseek-chat'. For each user input the message is appended to the messages array and chat.completions.create is called with the declared tools and tool_choice: 'auto'. If the response contains tool_calls, the arguments string is stripped of // comments, parsed with JSON.parse, and passed to executeTool. The tool result is added back as a message with role: 'tool' and the loop repeats; otherwise the model’s text reply is returned. The CLI uses Node’s readline to present a “you:/assistant:” prompt and exits cleanly when stdin closes.

Setup & run

Requirements: Node.js 18+, a Cursor‑compatible environment, and a DeepSeek API key.

npm init -y
npm install openai axios dotenv

Copy .env.example to .env and set:

DEEPSEEK_API_KEY=sk-xxx
EASYSEARCH_URL=http://127.0.0.1:9200
EASYSEARCH_USER=
EASYSEARCH_PASS=

Run the assistant with: node index.js Example Chinese commands:

“建个 demo‑products 索引,要有 name、price、category、created_at”

“往 demo‑products 写一条:name 无线耳机,price 299”

“在 demo‑products 里搜带‘数码’的”

“按 category 聚一下,看每个类有多少条”

Testing flow

The repository includes test‑flow‑prompts.md, a scripted sequence that exercises the full pipeline: create an index with mappings, single and bulk writes, view mapping, full‑text search, aggregation, and total‑count verification.

Pitfalls & troubleshooting

Model returns text instead of invoking a tool – usually caused by unclear tool descriptions. Emphasize in the system prompt that data‑related actions must use tools and write precise descriptions.

401 authentication error – invalid DeepSeek API key or Easysearch credentials. Verify DEEPSEEK_API_KEY and Easysearch USER / PASS; leave them empty if the cluster has no auth.

JSON.parse error – the model adds comments or stray symbols in arguments. Strip comments with replace(///.*$/gm,'').trim() before parsing.

Readline error after piped input – stdin closed but the prompt is still called. Guard with process.stdin.destroyed or catch ERR_USE_AFTER_CLOSE.

400 error on aggregation/write – malformed DSL or bulk payload. Inspect the Easysearch error field and add logging in the executor to dump the request body.

Extensibility

Streaming output : add stream: true to the OpenAI call and display tokens incrementally.

Web UI : expose the same API via an Express server and build a simple chat page.

Model swap : change baseURL and model to any OpenAI‑compatible service (e.g., Kimi, Baillian, Ollama) without modifying tools or executor.

MCP packaging : wrap the tool set as an MCP server for reuse in Cursor, Claude Desktop, etc.

Architecture rationale

1. Tool as capability – each Easysearch operation is expressed as a standardized tool with explicit name, description and parameters. The model only needs to decide which tool to call and what arguments to supply.

2. API‑protocol alignment – Easysearch’s REST endpoints match Elasticsearch’s DSL, so tool parameters map one‑to‑one to HTTP request paths and bodies. The executor performs a thin conversion from parameters to request payloads, keeping the system stable and maintainable.

3. Separation of understanding and execution – the LLM produces structured tool_calls (tool name + arguments) but never issues HTTP requests itself. All network interactions are performed by local code, giving the user full control over security boundaries and allowing easy swapping of models or addition of new tools.

Project structure

easysearch-skills/
├── .env               # sensitive config (not committed)
├── .env.example       # template
├── .gitignore
├── package.json
├── tools.js           # tool declarations (OpenAI/DeepSeek format)
├── executor.js        # actual Easysearch calls
├── index.js           # dialogue loop & tool orchestration
└── test-flow-prompts.md # full test script
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

search engineLLMNode.jsDeepSeekTool UseEasysearchOpenAI Function Calling
Mingyi World Elasticsearch
Written by

Mingyi World Elasticsearch

The leading WeChat public account for Elasticsearch fundamentals, advanced topics, and hands‑on practice. Join us to dive deep into the ELK Stack (Elasticsearch, Logstash, Kibana, Beats).

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.