Skip to content

Commit 1b9885c

Browse files
Fix UI and answer gen issues (#2541)
* sort references * UI fixds * ui fixes * update defaults * update * update * update * update * update * Add results merge strategy * Add results merge strategy to thought process * update snapshots
1 parent 852d794 commit 1b9885c

File tree

12 files changed

+72
-7
lines changed

12 files changed

+72
-7
lines changed

app/backend/approaches/approach.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ async def run_agentic_retrieval(
261261
filter_add_on: Optional[str] = None,
262262
minimum_reranker_score: Optional[float] = None,
263263
max_docs_for_reranker: Optional[int] = None,
264+
results_merge_strategy: Optional[str] = None,
264265
) -> tuple[KnowledgeAgentRetrievalResponse, list[Document]]:
265266
# STEP 1: Invoke agentic retrieval
266267
response = await agent_client.retrieve(
@@ -298,7 +299,13 @@ async def run_agentic_retrieval(
298299

299300
results = []
300301
if response and response.references:
301-
for reference in response.references:
302+
if results_merge_strategy == "interleaved":
303+
# Use interleaved reference order
304+
references = sorted(response.references, key=lambda reference: int(reference.id))
305+
else:
306+
# Default to descending strategy
307+
references = response.references
308+
for reference in references:
302309
if isinstance(reference, KnowledgeAgentAzureSearchDocReference) and reference.source_data:
303310
results.append(
304311
Document(

app/backend/approaches/chatreadretrieveread.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ async def run_agentic_retrieval_approach(
235235
search_index_filter = self.build_filter(overrides, auth_claims)
236236
top = overrides.get("top", 3)
237237
max_subqueries = overrides.get("max_subqueries", 10)
238+
results_merge_strategy = overrides.get("results_merge_strategy", "interleaved")
238239
# 50 is the amount of documents that the reranker can process per query
239240
max_docs_for_reranker = max_subqueries * 50
240241

@@ -246,6 +247,7 @@ async def run_agentic_retrieval_approach(
246247
filter_add_on=search_index_filter,
247248
minimum_reranker_score=minimum_reranker_score,
248249
max_docs_for_reranker=max_docs_for_reranker,
250+
results_merge_strategy=results_merge_strategy,
249251
)
250252

251253
text_sources = self.get_sources_content(results, use_semantic_captions=False, use_image_citation=False)
@@ -259,6 +261,7 @@ async def run_agentic_retrieval_approach(
259261
{
260262
"reranker_threshold": minimum_reranker_score,
261263
"max_docs_for_reranker": max_docs_for_reranker,
264+
"results_merge_strategy": results_merge_strategy,
262265
"filter": search_index_filter,
263266
},
264267
),

app/backend/approaches/retrievethenread.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ async def run_agentic_retrieval_approach(
186186
search_index_filter = self.build_filter(overrides, auth_claims)
187187
top = overrides.get("top", 3)
188188
max_subqueries = overrides.get("max_subqueries", 10)
189+
results_merge_strategy = overrides.get("results_merge_strategy", "interleaved")
189190
# 50 is the amount of documents that the reranker can process per query
190191
max_docs_for_reranker = max_subqueries * 50
191192

@@ -197,6 +198,7 @@ async def run_agentic_retrieval_approach(
197198
filter_add_on=search_index_filter,
198199
minimum_reranker_score=minimum_reranker_score,
199200
max_docs_for_reranker=max_docs_for_reranker,
201+
results_merge_strategy=results_merge_strategy,
200202
)
201203

202204
text_sources = self.get_sources_content(results, use_semantic_captions=False, use_image_citation=False)
@@ -210,6 +212,7 @@ async def run_agentic_retrieval_approach(
210212
{
211213
"reranker_threshold": minimum_reranker_score,
212214
"max_docs_for_reranker": max_docs_for_reranker,
215+
"results_merge_strategy": results_merge_strategy,
213216
"filter": search_index_filter,
214217
},
215218
),

app/frontend/src/api/models.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export type ChatAppRequestOverrides = {
2727
seed?: number;
2828
top?: number;
2929
max_subqueries?: number;
30+
results_merge_strategy?: string;
3031
temperature?: number;
3132
minimum_search_score?: number;
3233
minimum_reranker_score?: number;

app/frontend/src/components/Settings/Settings.tsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface SettingsProps {
1515
temperature: number;
1616
retrieveCount: number;
1717
maxSubqueryCount: number;
18+
resultsMergeStrategy: string;
1819
seed: number | null;
1920
minimumSearchScore: number;
2021
minimumRerankerScore: number;
@@ -55,6 +56,7 @@ export const Settings = ({
5556
temperature,
5657
retrieveCount,
5758
maxSubqueryCount,
59+
resultsMergeStrategy,
5860
seed,
5961
minimumSearchScore,
6062
minimumRerankerScore,
@@ -108,6 +110,7 @@ export const Settings = ({
108110
const retrieveCountFieldId = useId("retrieveCountField");
109111
const maxSubqueryCountId = useId("maxSubqueryCount");
110112
const maxSubqueryCountFieldId = useId("maxSubqueryCountField");
113+
const resultsMergeStrategyFieldId = useId("resultsMergeStrategy");
111114
const includeCategoryId = useId("includeCategory");
112115
const includeCategoryFieldId = useId("includeCategoryField");
113116
const excludeCategoryId = useId("excludeCategory");
@@ -218,15 +221,33 @@ export const Settings = ({
218221
className={styles.settingsSeparator}
219222
label={t("labels.maxSubqueryCount")}
220223
type="number"
221-
min={1}
222-
max={20}
224+
min={2}
225+
max={40}
223226
defaultValue={maxSubqueryCount.toString()}
224227
onChange={(_ev, val) => onChange("maxSubqueryCount", parseInt(val || "10"))}
225228
aria-labelledby={maxSubqueryCountId}
226229
onRenderLabel={props => renderLabel(props, maxSubqueryCountId, maxSubqueryCountFieldId, t("helpTexts.maxSubqueryCount"))}
227230
/>
228231
)}
229232

233+
{showAgenticRetrievalOption && useAgenticRetrieval && (
234+
<Dropdown
235+
id={resultsMergeStrategyFieldId}
236+
className={styles.settingsSeparator}
237+
label={t("labels.resultsMergeStrategy")}
238+
selectedKey={resultsMergeStrategy}
239+
onChange={(_ev?: React.FormEvent<HTMLElement | HTMLInputElement>, option?: IDropdownOption) =>
240+
onChange("resultsMergeStrategy", option?.key)
241+
}
242+
aria-labelledby={includeCategoryId}
243+
options={[
244+
{ key: "interleaved", text: t("labels.resultsMergeStrategyOptions.interleaved") },
245+
{ key: "descending", text: t("labels.resultsMergeStrategyOptions.descending") }
246+
]}
247+
onRenderLabel={props => renderLabel(props, includeCategoryId, includeCategoryFieldId, t("helpTexts.resultsMergeStrategy"))}
248+
/>
249+
)}
250+
230251
<TextField
231252
id={retrieveCountFieldId}
232253
className={styles.settingsSeparator}

app/frontend/src/locales/en/translation.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@
8484
"minimumRerankerScore": "Minimum reranker score",
8585
"retrieveCount": "Retrieve this many search results:",
8686
"maxSubqueryCount": "Max subqueries",
87+
"resultsMergeStrategy": "Results merge strategy",
88+
"resultsMergeStrategyOptions": {
89+
"interleaved": "Interleaved",
90+
"descending": "Descending"
91+
},
8792
"includeCategory": "Include category",
8893
"includeCategoryOptions": {
8994
"all": "All"
@@ -144,6 +149,8 @@
144149
"Sets the number of search results to retrieve from Azure AI search. More results may increase the likelihood of finding the correct answer, but may lead to the model getting 'lost in the middle'.",
145150
"maxSubqueryCount":
146151
"Sets the maximum number of subqueries to use for the agentic retrieval query plan.",
152+
"resultsMergeStrategy":
153+
"Sets the strategy for merging results from multiple subqueries. Interleaved picks the top results from each subquery in round robin order, while descending sorts all results by reranker score.",
147154
"includeCategory":
148155
"Specifies a category to include in the search results. There are no categories used in the default data set.",
149156
"excludeCategory":

app/frontend/src/pages/ask/Ask.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export function Component(): JSX.Element {
3131
const [retrievalMode, setRetrievalMode] = useState<RetrievalMode>(RetrievalMode.Hybrid);
3232
const [retrieveCount, setRetrieveCount] = useState<number>(3);
3333
const [maxSubqueryCount, setMaxSubqueryCount] = useState<number>(10);
34+
const [resultsMergeStrategy, setResultsMergeStrategy] = useState<string>("interleaved");
3435
const [useSemanticRanker, setUseSemanticRanker] = useState<boolean>(true);
3536
const [useSemanticCaptions, setUseSemanticCaptions] = useState<boolean>(false);
3637
const [useQueryRewriting, setUseQueryRewriting] = useState<boolean>(false);
@@ -102,6 +103,9 @@ export function Component(): JSX.Element {
102103
setShowSpeechOutputAzure(config.showSpeechOutputAzure);
103104
setShowAgenticRetrievalOption(config.showAgenticRetrievalOption);
104105
setUseAgenticRetrieval(config.showAgenticRetrievalOption);
106+
if (config.showAgenticRetrievalOption) {
107+
setRetrieveCount(10);
108+
}
105109
});
106110
};
107111

@@ -136,6 +140,7 @@ export function Component(): JSX.Element {
136140
exclude_category: excludeCategory.length === 0 ? undefined : excludeCategory,
137141
top: retrieveCount,
138142
max_subqueries: maxSubqueryCount,
143+
results_merge_strategy: resultsMergeStrategy,
139144
temperature: temperature,
140145
minimum_reranker_score: minimumRerankerScore,
141146
minimum_search_score: minimumSearchScore,
@@ -196,6 +201,9 @@ export function Component(): JSX.Element {
196201
case "maxSubqueryCount":
197202
setMaxSubqueryCount(value);
198203
break;
204+
case "resultsMergeStrategy":
205+
setResultsMergeStrategy(value);
206+
break;
199207
case "useSemanticRanker":
200208
setUseSemanticRanker(value);
201209
break;
@@ -347,6 +355,7 @@ export function Component(): JSX.Element {
347355
temperature={temperature}
348356
retrieveCount={retrieveCount}
349357
maxSubqueryCount={maxSubqueryCount}
358+
resultsMergeStrategy={resultsMergeStrategy}
350359
seed={seed}
351360
minimumSearchScore={minimumSearchScore}
352361
minimumRerankerScore={minimumRerankerScore}

app/frontend/src/pages/chat/Chat.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const Chat = () => {
4747
const [minimumSearchScore, setMinimumSearchScore] = useState<number>(0);
4848
const [retrieveCount, setRetrieveCount] = useState<number>(3);
4949
const [maxSubqueryCount, setMaxSubqueryCount] = useState<number>(10);
50+
const [resultsMergeStrategy, setResultsMergeStrategy] = useState<string>("interleaved");
5051
const [retrievalMode, setRetrievalMode] = useState<RetrievalMode>(RetrievalMode.Hybrid);
5152
const [useSemanticRanker, setUseSemanticRanker] = useState<boolean>(true);
5253
const [useQueryRewriting, setUseQueryRewriting] = useState<boolean>(false);
@@ -135,6 +136,9 @@ const Chat = () => {
135136
setShowChatHistoryCosmos(config.showChatHistoryCosmos);
136137
setShowAgenticRetrievalOption(config.showAgenticRetrievalOption);
137138
setUseAgenticRetrieval(config.showAgenticRetrievalOption);
139+
if (config.showAgenticRetrievalOption) {
140+
setRetrieveCount(10);
141+
}
138142
});
139143
};
140144

@@ -215,6 +219,8 @@ const Chat = () => {
215219
include_category: includeCategory.length === 0 ? undefined : includeCategory,
216220
exclude_category: excludeCategory.length === 0 ? undefined : excludeCategory,
217221
top: retrieveCount,
222+
max_subqueries: maxSubqueryCount,
223+
results_merge_strategy: resultsMergeStrategy,
218224
temperature: temperature,
219225
minimum_reranker_score: minimumRerankerScore,
220226
minimum_search_score: minimumSearchScore,
@@ -312,6 +318,9 @@ const Chat = () => {
312318
case "maxSubqueryCount":
313319
setMaxSubqueryCount(value);
314320
break;
321+
case "resultsMergeStrategy":
322+
setResultsMergeStrategy(value);
323+
break;
315324
case "useSemanticRanker":
316325
setUseSemanticRanker(value);
317326
break;
@@ -534,6 +543,7 @@ const Chat = () => {
534543
temperature={temperature}
535544
retrieveCount={retrieveCount}
536545
maxSubqueryCount={maxSubqueryCount}
546+
resultsMergeStrategy={resultsMergeStrategy}
537547
seed={seed}
538548
minimumSearchScore={minimumSearchScore}
539549
minimumRerankerScore={minimumRerankerScore}

tests/snapshots/test_app/test_ask_rtr_text_agent/agent_client0/result.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"props": {
1919
"filter": null,
2020
"max_docs_for_reranker": 500,
21-
"reranker_threshold": 0
21+
"reranker_threshold": 0,
22+
"results_merge_strategy": "interleaved"
2223
},
2324
"title": "Use agentic retrieval"
2425
},

tests/snapshots/test_app/test_ask_rtr_text_agent_filter/agent_auth_client0/result.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"props": {
1919
"filter": "category ne 'excluded' and (oids/any(g:search.in(g, 'OID_X')) or groups/any(g:search.in(g, 'GROUP_Y, GROUP_Z')))",
2020
"max_docs_for_reranker": 500,
21-
"reranker_threshold": 0
21+
"reranker_threshold": 0,
22+
"results_merge_strategy": "interleaved"
2223
},
2324
"title": "Use agentic retrieval"
2425
},

tests/snapshots/test_app/test_chat_text_agent/agent_client0/result.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"props": {
1919
"filter": null,
2020
"max_docs_for_reranker": 500,
21-
"reranker_threshold": 0
21+
"reranker_threshold": 0,
22+
"results_merge_strategy": "interleaved"
2223
},
2324
"title": "Use agentic retrieval"
2425
},

tests/snapshots/test_app/test_chat_text_filter_agent/agent_auth_client0/result.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"props": {
1919
"filter": "category ne 'excluded' and (oids/any(g:search.in(g, 'OID_X')) or groups/any(g:search.in(g, 'GROUP_Y, GROUP_Z')))",
2020
"max_docs_for_reranker": 500,
21-
"reranker_threshold": 0
21+
"reranker_threshold": 0,
22+
"results_merge_strategy": "interleaved"
2223
},
2324
"title": "Use agentic retrieval"
2425
},

0 commit comments

Comments
 (0)