Skip to content

Comments

[onechat] add first set of base tools#223367

Merged
pgayvallet merged 20 commits intoelastic:mainfrom
pgayvallet:onechat-10121-first-tools
Jun 20, 2025
Merged

[onechat] add first set of base tools#223367
pgayvallet merged 20 commits intoelastic:mainfrom
pgayvallet:onechat-10121-first-tools

Conversation

@pgayvallet
Copy link
Contributor

@pgayvallet pgayvallet commented Jun 11, 2025

Summary

Fix https://github.com/elastic/search-team/issues/10121

Add a base set of retrieval oriented tools, and expose them to the default agent.

Tools

Warning: names are still TBD

We're starting to see two different "layers" of tool appear: "simple" tools, which are doing a simple programmatic (understand: no LLM) task, and "smart" tools, which are more like workflows, with some of the steps relying on a LLM.

This PR introduces the following tools:

Simple tools

Simple tools (name TBD) are "programmatic" tools not relying on an LLM for their execution.

This PR introduces this base set of tools:

  • get_document_by_id: resolve a full document based on its id/index.
  • list_indices: list the indices the current user has access to.
  • get_index_mappings: retrieve the full mappings based for a given index.
  • execute_esql: executes a provided ES|QL query

Smart tools

Smart tools can have multiple internal steps (even if it remains an implementation detail), and are using LLM calls for some, or all, of them.

Note: there are huge potential areas of improvement in the current implementation of all those smart tools. One of the intent of this work is precisely to identify such areas of improvement

index_explorer

Based on a natural language query, returns a list of indices that should be searched, and their corresponding mappings.

Screenshot 2025-06-17 at 16 44 32

generate_esql

Based on a natural language query, generates an ES|QL query.

  • use the nl-2-esql task under the hood
  • optional use index-explorer if index is not specified.
Screenshot 2025-06-17 at 16 51 56

relevance_search

Perform a "full-text search" based on given term and returns the most relevant highlights.

Screenshot 2025-06-17 at 16 59 49

natural_language_search

Retrieve data based on a natural language query.

Converts a natural language query to an ES|QL one then executes it, useing generate_esql and execute_esql under the hood.

Screenshot 2025-06-18 at 08 31 52

Researcher assistant

The second part of this PR is implementing a researcher agent for deep research tasks.

The researcher assistant is following a very classic "act->process->reflect" cycle.

Screenshot 2025-06-18 at 09 16 17

The implementation of the cycle is currently as follow:

1. Act

Given a research topic, the research history and a list of tools, select the tool best suited to search for this topic, and call it.

The tools exposed to the agent in this phase are:

  • index_explorer
  • relevance_search
  • nl_search

Note: later the whole act step could evolve to instead call sub search agent with planning and multi-step execution.

2. Process

Process the results from the latest act phase and create a corresponding entry in the search log.

At the moment, we're simply storing the whole tool call + results to the search log in a LLM-friendly format.

3. Reflect

Based on the main research query and the search log, identify where the information collected are enough to answer the question. If not, identify follow-up questions or sub-problems that it would be useful to solve to gather more information

What is out of scope of the current PR

  • Figuring out which set of tools should be exposed by default to the main agent (right now, all the tools listed in this PR are)

@pgayvallet pgayvallet added release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting v9.1.0 labels Jun 11, 2025
@pgayvallet
Copy link
Contributor Author

/ci

@pgayvallet
Copy link
Contributor Author

/ci

Copy link
Contributor Author

@pgayvallet pgayvallet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-review

Comment on lines +25 to +28
/**
* Tag associated to tools related to data retrieval
*/
retrieval: 'retrieval',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starting to see a pattern where we assign tags to tools to allow easily filtering for specific profiles (e.g search agent get assigned all the retrieval tools).

@pgayvallet
Copy link
Contributor Author

/ci

@pgayvallet pgayvallet marked this pull request as ready for review June 11, 2025 11:40
@pgayvallet pgayvallet requested a review from a team as a code owner June 11, 2025 11:40
@pgayvallet pgayvallet marked this pull request as draft June 12, 2025 05:45
@pgayvallet
Copy link
Contributor Author

/ci

@pgayvallet
Copy link
Contributor Author

/ci

@pgayvallet
Copy link
Contributor Author

/ci

@pgayvallet
Copy link
Contributor Author

/ci

@elasticmachine
Copy link
Contributor

💛 Build succeeded, but was flaky

Failed CI Steps

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
onechat 32 33 +1

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
@kbn/onechat-common 127 136 +9
@kbn/onechat-genai-utils - 75 +75
total +84

Public APIs missing exports

Total count of every type that is part of your API that should be exported but is not. This will cause broken links in the API documentation system. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats exports for more detailed information.

id before after diff
@kbn/onechat-genai-utils - 4 +4
Unknown metric groups

API count

id before after diff
@kbn/onechat-common 191 203 +12
@kbn/onechat-genai-utils - 79 +79
@kbn/onechat-server 176 177 +1
total +92

History

@pgayvallet pgayvallet marked this pull request as ready for review June 18, 2025 07:19
export type ToolFilterRule = ByToolIdRule | ByProviderIdRule;

const matches = (rule: ToolFilterRule, tool: ToolDescriptor): boolean => {
if (rule.type === 'by_tool_id') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: use an enum for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, I've been traumatized by enums and the fact they are not abstract (type) and require a concrete import, so I'm trying to avoid using them as much as possible, unless forced to because of some TS inference magical type I want to build.

But this is a very personal preference.

}

export const indexExplorer = async ({
query,
Copy link
Member

@joemcelroy joemcelroy Jun 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought: I dont have a good answer here but i pause on whether both query and indexPattern is needed. I can see indexPattern being useful for when specified in the prompt however.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. In practice today, that "indexPattern" param is even causing issues because for a prompt such as "please search for docs in the hr index", the LLM sometimes add a *hr* index pattern parameter causing troubles.

And yet I think we do need the option to let the LLMm specify that filter. So yeah, idk.

format: 'json',
});

return response.map(({ index, status, health, uuid, 'docs.count': docsCount, pri, rep }) => ({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder what list index information is useful here for LLM. Personally for the index explorer, only index, docsCount is useful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea if having some kind of low level utility function for the most common ES requests (e.g listing indices, mappings and so on) that we can use to compose our tools.

Agreed that for index explorer, most of those info are likely useless. We need to tweak that with evaluation too.

index,
size,
retriever: {
rrf: {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: i would group all text fields together into one retriever and then each semantic_text field as individual retrievers. RRF would not be applied if its just all text fields.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++. I wanted to keep it as a follow up because it requires performMatchSearch to know about field types, and it doesn't at the moment

/**
* Converts an ES|QL /_query columnar response to a JSON representation
*/
export const esqlResponseToJson = (esql: EsqlResponse): Array<Record<string, any>> => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried, and unless I missed something I think it doesn't really work with the ES client 🙈.

Copy link
Member

@joemcelroy joemcelroy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks great! One thing want to try is the trigger when it uses the researcher tool vs relevence / esql tool directly.

We need to expand the prompt to give more examples when relevence / esql tool is used but we can do that separately in another PR.

@pgayvallet pgayvallet merged commit 04b294e into elastic:main Jun 20, 2025
11 checks passed
akowalska622 pushed a commit to akowalska622/kibana that referenced this pull request Jun 25, 2025
## Summary

Fix elastic/search-team#10121

Add a base set of retrieval oriented tools, and expose them to the
default agent.

## Tools

**Warning: names are still TBD**

We're starting to see two different "layers" of tool appear: "simple"
tools, which are doing a simple programmatic (understand: no LLM) task,
and "smart" tools, which are more like workflows, with some of the steps
relying on a LLM.

This PR introduces the following tools:

### Simple tools

Simple tools (name TBD) are "programmatic" tools not relying on an LLM
for their execution.

This PR introduces this base set of tools:

- `get_document_by_id`: resolve a full document based on its id/index.
- `list_indices`: list the indices the current user has access to.
- `get_index_mappings`: retrieve the full mappings based for a given
index.
- `execute_esql`: executes a provided ES|QL query

### Smart tools

Smart tools can have multiple internal steps (even if it remains an
implementation detail), and are using LLM calls for some, or all, of
them.

*Note: there are huge potential areas of improvement in the current
implementation of all those smart tools. One of the intent of this work
is precisely to identify such areas of improvement*

#### `index_explorer`

Based on a natural language query, returns a list of indices that should
be searched, and their corresponding mappings.

<img width="984" alt="Screenshot 2025-06-17 at 16 44 32"
src="https://github.com/user-attachments/assets/edff3964-31e3-40ea-a761-adf7c45fcb17"
/>


#### `generate_esql`

Based on a natural language query, generates an ES|QL query.

- use the `nl-2-esql` task under the hood
- optional use `index-explorer` if `index` is not specified.

<img width="891" alt="Screenshot 2025-06-17 at 16 51 56"
src="https://github.com/user-attachments/assets/ce141d6b-dd4f-4eb9-ab32-823b81bc810b"
/>


#### `relevance_search`

Perform a "full-text search" based on given term and returns the most
relevant highlights.

<img width="1071" alt="Screenshot 2025-06-17 at 16 59 49"
src="https://github.com/user-attachments/assets/1f873e70-e277-424d-93e4-24b269a554e5"
/>

#### `natural_language_search`

Retrieve data based on a natural language query.

Converts a natural language query to an ES|QL one then executes it,
useing `generate_esql` and `execute_esql` under the hood.

<img width="768" alt="Screenshot 2025-06-18 at 08 31 52"
src="https://github.com/user-attachments/assets/cb319831-17ed-4ad7-9e1f-2fe90c2472fa"
/>

## Researcher assistant

The second part of this PR is implementing a researcher agent for deep
research tasks.

The researcher assistant is following a very classic
"act->process->reflect" cycle.

<img width="960" alt="Screenshot 2025-06-18 at 09 16 17"
src="https://github.com/user-attachments/assets/c24be323-ecf2-4c43-88fb-eaf874b18afc"
/>

The implementation of the cycle is currently as follow:

**1. Act**

Given a research topic, the research history and a list of tools, select
the tool best suited to search for this topic, and call it.

The tools exposed to the agent in this phase are:
- `index_explorer`
- `relevance_search`
- `nl_search`

*Note: later the whole `act` step could evolve to instead call sub
search agent with planning and multi-step execution.*

**2. Process**

Process the results from the latest `act` phase and create a
corresponding entry in the search log.

At the moment, we're simply storing the whole tool call + results to the
search log in a LLM-friendly format.

**3. Reflect**

Based on the main research query and the search log, identify where the
information collected are enough to answer the question. If not,
identify follow-up questions or sub-problems that it would be useful to
solve to gather more information

## What is out of scope of the current PR

- Figuring out which set of tools should be exposed by default to the
main agent (right now, all the tools listed in this PR are)

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
pgayvallet added a commit that referenced this pull request Jun 26, 2025
## Summary

Follow-up of #223367
Fix elastic/search-team#10259

This PR introduce the concept of agent **mode**, and expose the "deep
research" agent as a mode instead of a tool.

## Examples

### Calling the Q/A (default) mode

```curl
POST kbn:/internal/onechat/chat
{
  "nextMessage": "Find all info related to our work from home policy"
}
```

### Calling the researcher mode

```curl
POST kbn:/internal/onechat/chat
{
  "mode": "researcher",
  "nextMessage": "Find all info related to our work from home policy"
}
```

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting release_note:skip Skip the PR/issue when compiling release notes v9.1.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants