mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-11 04:47:21 +00:00
Fixed classic RAG sending more passages than the model can take (#1168)
This commit is contained in:
1 parent
7342c436dd
commit
188d17688a
16 files changed
+847
-78
No files matched your search
@@ -233,9 +233,11 @@ Every check of an ERI data source signs in to its server, and one message checks
|
||||
|
||||
The data sources are checked again before each search, since rounds may have passed since they were offered, and then searched in parallel. A data source which fails is reported as not searched rather than left out, so that the model does not take its silence for finding nothing. Every passage goes through the same filter and into the same shape as with the classic RAG process, `IRetrievalContextExtensions.PrepareForModelAsync`: all passages of a search in one filter request, within one `PromptInjectionGuardService.BeginAction` per search, so that the user hears about what was filtered once per search, as soon as it is done. A page of the search holds passages up to 100,000 characters, measured after the filter, which can make a passage longer. A data source returns its matches in pages of its own, as many as it is set to return, see `RetrievalPaging`; each of them is cut into one or more pages of the search, numbered on across the pages of the data source, see `SemanticSearchTool.SearchAsync`. Where everything fits, both are the same. `has_more` is exact: when a page ends with a page of the data source which might have more, the search looks whether a further one holds any passage. A passage longer than a whole page is shortened, its surrounding content first, and filtered again, see `IRetrievalContextExtensions.ShortenToFitAsync`; its label tells the model, and the user is shown the shorter passage. A search of several data sources shares the first page among them. The data sources take turns: first the best passage of each, then the second best of each, and a data source stops at its first passage which no longer fits. Otherwise, the data source listed first would take the whole budget, or a shorter passage would take the place of a longer one above it. What does not fit is counted in the result, with a search of that data source alone, from page 1, as the way out; that search shows the passages read already once more. An image an ERI server returns is not passed on, in neither process: written as base64 text, it is nothing a model can look at, and it would take more room than all other passages together. The passage tells the model that an image matched and where it is, so that it can point the user to it. What an ERI server says its content is, its category, is passed on as "Source category". The passages become sources through `IRetrievalContext.ToSources()`, as with the classic process, and only the data sources whose passages reached the model raise the requirements of the chat. The passages which reached the model are also kept with the answer, through `ToolExecutionResult.Passages` and `ContentText.AddSources`: the result of the call is not saved, but the user can still read what the answer rests on after the chat was reloaded. The title of a source names the pages of all its passages, see `SourcePassageExtensions.NamePassagesInTitles`.
|
||||
|
||||
The classic process sends its passages along with every message, in the system prompt, and a provider refuses a message which exceeds the context window of the model. Its passages therefore get a budget, `PassageBudget`: half of the context window when it is known, `ModelProfile.Context`, counted in tokens through `ConversationTokenCounter` with the tokenizer of the provider, or the built-in one; otherwise 100,000 characters, as many as one page of `semantic_search`. When the tokenizer does not answer, characters count against the same limit, which leaves the passages less room rather than more. The budget applies to what the validation agent left, measured after the filter, each passage with the longest header it can get. The data sources take turns as in a search of several data sources, but a passage which does not fit is skipped, and the next ones still get their chance: there is no further page which could bring it later. A passage longer than the whole budget is shortened and filtered again, as in `semantic_search`. The model reads the passages grouped by data source, followed by how many were left out, and the user gets a warning with every answer which had to do without some, naming the ways out: Semantic Search, a lower token limit, or fewer data sources. Only the passages the model received are listed with the answer.
|
||||
|
||||
**Where a chat may send data afterward.** A data source holds the documents of the user or of their organization, so each one decides, as a mailbox does, where a chat may still send data once a search found something in it, `IDataSource.OutboundDataRestriction`, see "Outbound Data Restrictions" above. New data sources start with `ONLY_LINKS_FROM_CHAT`, the level of internal pages, and so do the ones saved before the setting existed. What counts is the effective level, `DataSourceOutboundDataExtensions.GetEffectiveOutboundDataRestriction`: the level of the data source, tightened by the minimum of the organization, `DataSourceSecuritySettings.MinimumOutboundDataRestriction`, and to `ONLY_CONFIGURED_SERVICES` for an ERI data source whose security policy is `SELF_HOSTED`. Its data must not leave the infrastructure of the organization through a tool either, while its links into the intranet stay readable: that level still allows the wiki and the allowed private hosts. The rule holds at runtime, so neither a data source saved earlier nor one a configuration plugin provides has to be edited for it; the dialogs only stop offering the less strict levels.
|
||||
|
||||
Both ways of searching ask one place what their passages demand, `DataSourceRequirements.Of`, with the data sources and the number of passages each one returned. Only the data sources with passages count, and the strictest effective level wins. On a tie, the data source which comes first by number, then by ID, is the one the chat names, so both ways name the same one, whatever order they searched in. The classic process asks right after retrieval, before the validation agent sees the passages, and counts a passage which that agent drops later as well. This keeps to the safe side, and a validation which fails or is canceled cannot skip the restriction. It sets the restriction on the chat before the request puts its tools together, so the restriction holds for the very answer the passages were found for. Provider confidence and data security stay as they were in the classic process, per selected data source and before retrieval, because its agents see the data.
|
||||
Both ways of searching ask one place what their passages demand, `DataSourceRequirements.Of`, with the data sources and the number of passages each one returned. Only the data sources with passages count, and the strictest effective level wins. On a tie, the data source which comes first by number, then by ID, is the one the chat names, so both ways name the same one, whatever order they searched in. The classic process asks right after the augmentation, with the passages the model receives. A passage which the validation agent drops, or which does not fit into the budget of the model, raises nothing: neither the model nor any of its tools ever sees it, and the validation agent which reads it has no tools. Otherwise, a data source of public papers could fill the budget while the passages of a confidential one stay out, and the chat would still lose the web search for good. A validation which fails hands every passage on, and one which is canceled ends the answer before any passage is sent. It sets the restriction on the chat before the request puts its tools together, so the restriction holds for the very answer the passages were found for. Provider confidence and data security stay as they were in the classic process, per selected data source and before retrieval, because its agents see the data.
|
||||
|
||||
## Searching Mailboxes
|
||||
|
||||
|
||||
Reference in new issue
Block a user