Skip to content

Commit ef82af5

Browse files
Improve RAG preset experience (#617) (#619)
* Default ML response processors to append outputs to ext in response * Auto-navigate to ml outputs tab if found; minor reformatting * Update presets to omit ext.ml_inference --------- (cherry picked from commit 2d1d174) Signed-off-by: Tyler Ohlsen <ohltyler@amazon.com> Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent c3e5de0 commit ef82af5

File tree

5 files changed

+65
-35
lines changed

5 files changed

+65
-35
lines changed

common/interfaces.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,8 @@ export type SearchPipelineConfig = {
281281
export type MLInferenceProcessor = IngestProcessor & {
282282
ml_inference: {
283283
model_id: string;
284-
input_map?: {};
285-
output_map?: {};
284+
input_map?: {}[];
285+
output_map?: {}[];
286286
[key: string]: any;
287287
};
288288
};

public/general_components/results/ml_response.tsx public/general_components/results/ml_outputs.tsx

+15-15
Original file line numberDiff line numberDiff line change
@@ -18,34 +18,26 @@ import {
1818
ML_RESPONSE_PROCESSOR_EXAMPLE_DOCS_LINK,
1919
} from '../../../common';
2020

21-
interface MLResponseProps {
22-
mlResponse: {};
21+
interface MLOutputsProps {
22+
mlOutputs: {};
2323
}
2424

2525
/**
26-
* Small component to render the ML response within a raw search response.
26+
* Small component to render the ML outputs within a raw search response.
2727
*/
28-
export function MLResponse(props: MLResponseProps) {
28+
export function MLOutputs(props: MLOutputsProps) {
2929
return (
3030
<>
3131
<EuiSpacer size="s" />
32-
<EuiText size="s">
33-
Showing results stored in <EuiCode>ext.ml_inference</EuiCode> from the
34-
search response.{' '}
35-
<EuiLink href={ML_RESPONSE_PROCESSOR_EXAMPLE_DOCS_LINK} target="_blank">
36-
See an example
37-
</EuiLink>
38-
</EuiText>
39-
<EuiSpacer size="m" />
40-
{isEmpty(props.mlResponse) ? (
41-
<EuiEmptyPrompt title={<h2>No response found</h2>} titleSize="s" />
32+
{isEmpty(props.mlOutputs) ? (
33+
<EuiEmptyPrompt title={<h2>No outputs found</h2>} titleSize="s" />
4234
) : (
4335
<EuiCodeEditor
4436
mode="json"
4537
theme="textmate"
4638
width="100%"
4739
height="100%"
48-
value={customStringify(props.mlResponse)}
40+
value={customStringify(props.mlOutputs)}
4941
readOnly={true}
5042
setOptions={{
5143
fontSize: '12px',
@@ -55,6 +47,14 @@ export function MLResponse(props: MLResponseProps) {
5547
tabSize={2}
5648
/>
5749
)}
50+
<EuiSpacer size="s" />
51+
<EuiText size="s" color="subdued">
52+
Showing ML outputs stored in <EuiCode>ext.ml_inference</EuiCode> from
53+
the search response.{' '}
54+
<EuiLink href={ML_RESPONSE_PROCESSOR_EXAMPLE_DOCS_LINK} target="_blank">
55+
See an example
56+
</EuiLink>
57+
</EuiText>
5858
</>
5959
);
6060
}

public/general_components/results/results.tsx

+20-14
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import React, { useState } from 'react';
7-
import { get } from 'lodash';
6+
import React, { useEffect, useState } from 'react';
7+
import { get, isEmpty } from 'lodash';
88
import {
99
EuiPanel,
1010
EuiFlexGroup,
@@ -14,25 +14,31 @@ import {
1414
import { SearchResponse } from '../../../common';
1515
import { ResultsTable } from './results_table';
1616
import { ResultsJSON } from './results_json';
17-
import { MLResponse } from './ml_response';
17+
import { MLOutputs } from './ml_outputs';
1818

1919
interface ResultsProps {
2020
response: SearchResponse;
2121
}
2222

2323
enum VIEW {
2424
HITS_TABLE = 'hits_table',
25+
ML_OUTPUTS = 'ml_outputs',
2526
RAW_JSON = 'raw_json',
26-
ML_RESPONSE = 'ml_response',
2727
}
2828

2929
/**
3030
* Basic component to view OpenSearch response results. Can view hits in a tabular format,
3131
* or the raw JSON response.
3232
*/
3333
export function Results(props: ResultsProps) {
34-
// selected view state
34+
// selected view state. auto-navigate to ML outputs if there is values found
35+
// in "ext.ml_inference" in the search response.
3536
const [selectedView, setSelectedView] = useState<VIEW>(VIEW.HITS_TABLE);
37+
useEffect(() => {
38+
if (!isEmpty(get(props.response, 'ext.ml_inference', {}))) {
39+
setSelectedView(VIEW.ML_OUTPUTS);
40+
}
41+
}, [props.response]);
3642

3743
return (
3844
<EuiPanel
@@ -55,12 +61,12 @@ export function Results(props: ResultsProps) {
5561
label: 'Hits',
5662
},
5763
{
58-
id: VIEW.RAW_JSON,
59-
label: 'Raw JSON',
64+
id: VIEW.ML_OUTPUTS,
65+
label: 'ML outputs',
6066
},
6167
{
62-
id: VIEW.ML_RESPONSE,
63-
label: 'ML response',
68+
id: VIEW.RAW_JSON,
69+
label: 'Raw JSON',
6470
},
6571
]}
6672
idSelected={selectedView}
@@ -73,14 +79,14 @@ export function Results(props: ResultsProps) {
7379
{selectedView === VIEW.HITS_TABLE && (
7480
<ResultsTable hits={props.response?.hits?.hits || []} />
7581
)}
82+
{selectedView === VIEW.ML_OUTPUTS && (
83+
<MLOutputs
84+
mlOutputs={getMLResponseFromSearchResponse(props.response)}
85+
/>
86+
)}
7687
{selectedView === VIEW.RAW_JSON && (
7788
<ResultsJSON response={props.response} />
7889
)}
79-
{selectedView === VIEW.ML_RESPONSE && (
80-
<MLResponse
81-
mlResponse={getMLResponseFromSearchResponse(props.response)}
82-
/>
83-
)}
8490
</>
8591
</EuiFlexItem>
8692
</EuiFlexGroup>

public/pages/workflows/new_workflow/quick_configure_modal.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -741,8 +741,7 @@ function updateRAGSearchResponseProcessors(
741741
llmInterface: ModelInterface | undefined
742742
): WorkflowConfig {
743743
config.search.enrichResponse.processors.forEach((processor, idx) => {
744-
// prefill ML inference. By default, store the inference results
745-
// under the `ext.ml_inference` response body.
744+
// prefill ML inference
746745
if (processor.type === PROCESSOR_TYPE.ML) {
747746
config.search.enrichResponse.processors[idx].fields.forEach((field) => {
748747
if (field.id === 'model' && fields.llmId) {
@@ -785,7 +784,7 @@ function updateRAGSearchResponseProcessors(
785784
...outputMap[0],
786785
value: {
787786
transformType: TRANSFORM_TYPE.FIELD,
788-
value: `ext.ml_inference.${fields.llmResponseField}`,
787+
value: fields.llmResponseField,
789788
},
790789
};
791790
} else {

public/utils/config_to_template_utils.ts

+26-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import { FormikValues } from 'formik';
7-
import { isEmpty } from 'lodash';
7+
import { get, isEmpty } from 'lodash';
88
import {
99
TemplateFlows,
1010
TemplateNode,
@@ -233,6 +233,31 @@ export function processorConfigsToTemplateProcessors(
233233
);
234234
}
235235

236+
// process where the returned values from the output map should be stored.
237+
// by default, if many-to-one, append with "ext.ml_inference", such that the outputs
238+
// will be stored in a standalone field in the search response, instead of appended
239+
// to each document redundantly.
240+
const oneToOne = formValues?.one_to_one as boolean | undefined;
241+
if (
242+
oneToOne !== undefined &&
243+
oneToOne === false &&
244+
processor.ml_inference?.output_map !== undefined
245+
) {
246+
const updatedOutputMap = processor.ml_inference.output_map?.map(
247+
(mapEntry) => {
248+
let updatedMapEntry = {};
249+
Object.keys(mapEntry).forEach((key) => {
250+
updatedMapEntry = {
251+
...updatedMapEntry,
252+
[`ext.ml_inference.${key}`]: get(mapEntry, key),
253+
};
254+
});
255+
return updatedMapEntry;
256+
}
257+
);
258+
processor.ml_inference.output_map = updatedOutputMap;
259+
}
260+
236261
// process optional fields
237262
let additionalFormValues = {} as FormikValues;
238263
Object.keys(formValues).forEach((formKey: string) => {

0 commit comments

Comments
 (0)