[Security Solution] [AI Assistant] Security AI Assistant - Citations#206683
[Security Solution] [AI Assistant] Security AI Assistant - Citations#206683KDKHD merged 93 commits intoelastic:mainfrom KDKHD:feature/security-assistant-content-references
Conversation
…y-assistant-content-references
…b.com:KDKHD/kibana into feature/security-assistant-content-references
…b.com:KDKHD/kibana into feature/security-assistant-content-references
…b.com:KDKHD/kibana into feature/security-assistant-content-references
…b.com:KDKHD/kibana into feature/security-assistant-content-references
| * @param size Size of ID to generate | ||
| * @returns an unsecure Id | ||
| */ | ||
| const generateUnsecureId = (size = 5): string => { |
There was a problem hiding this comment.
any reason not to use import { v4 as uuid } from 'uuid';?
There was a problem hiding this comment.
Yes, I purposefully chose not to use a UUID. These are some of the reasons:
- UUID is unnecessarily long. A message only has a small number of references and we don't need 30+ characters to represent their IDs.
- The longer the ID, the higher the chance that the LLM will not copy it correctly to the output. A shorter ID makes the references that are produced more reliable.
- Shorter ID results in fewer output tokens.
- When the output is streamed to the frontend we can quickly replace the short ids with the citation component. If the ids were longer, we would need to stream the full UUID before being able to insert the citation component. I tried using UUIDs at the beginning and it didn't look great because the long UUIDs were getting streamed in the middle of the response and it looked very choppy.
x-pack/platform/packages/shared/kbn-elastic-assistant/impl/assistant/assistant_body/index.tsx
Show resolved
Hide resolved
...security/plugins/elastic_assistant/server/ai_assistant_data_clients/conversations/helpers.ts
Outdated
Show resolved
Hide resolved
| }: { | ||
| indexEntry: IndexEntry; | ||
| esClient: ElasticsearchClient; | ||
| contentReferencesStore: ContentReferencesStore | false; |
There was a problem hiding this comment.
Was the intention to make contentReferencesStore optional? If yes, then we should be using contentReferencesStore?: ContentReferencesStore;. We should not mix different types here.
There was a problem hiding this comment.
I chose to use the type contentReferencesStore: ContentReferencesStore | false; instead of contentReferencesStore?: ContentReferencesStore; because if contentReferencesStore is optional, other devs (and future me) may forget to pass it as a parameter.
Using contentReferencesStore: ContentReferencesStore | false; requires devs to be deliberate about if they want to use the contentReferencesStore or not.
I can make it optional though if you think it would be better.
There was a problem hiding this comment.
If you want to enforce users to pass contentReferencesStore even if it is optional, then you can do that by explicitly defining it as undefined as well:
contentReferencesStore: ContentReferencesStore | undefined;
So, that users will have to call this as { contentReferencesStore: undefined }.
Btw, why would we want to make contentReferencesStore optional?
There was a problem hiding this comment.
If you want to enforce users to pass contentReferencesStore even if it is optional, then you can do that by explicitly defining it as undefined as well:
contentReferencesStore: ContentReferencesStore | undefined;
Good point. I will change it to this.
Btw, why would we want to make contentReferencesStore optional?
I made it optional when I was putting this whole feature behind a feature flag. The plan would be to make it not optional once the feature flag is gone.
| contentReferencesStore, | ||
| esClient, | ||
| }: { | ||
| contentReferencesStore: ContentReferencesStore | false; |
There was a problem hiding this comment.
same as above, should it be contentReferencesStore?: ContentReferencesStore; instead?
| assistantTools?: AssistantTool[]; | ||
| connectorId: string; | ||
| conversationId?: string; | ||
| contentReferencesStore: ContentReferencesStore | false; |
| ...(contentReferences ? { contentReferences } : {}), | ||
| }; | ||
|
|
||
| const isMetadataPopulated = Boolean(contentReferences) !== false; |
There was a problem hiding this comment.
I don't think we would need != false if we use const isMetadataPopulated = !!contentReferences;
| inference?: InferenceServerStart; | ||
| isEnabledKnowledgeBase: boolean; | ||
| connectorId?: string; | ||
| contentReferencesStore: ContentReferencesStore | false; |
.../assistant/get_comments/content_reference/components/content_reference_component_factory.tsx
Outdated
Show resolved
Hide resolved
…erimental_features.ts
…y-assistant-content-references # Conflicts: # oas_docs/output/kibana.serverless.yaml # oas_docs/output/kibana.yaml # x-pack/platform/packages/shared/kbn-elastic-assistant-common/docs/openapi/ess/elastic_assistant_api_2023_10_31.bundled.schema.yaml # x-pack/platform/packages/shared/kbn-elastic-assistant-common/docs/openapi/serverless/elastic_assistant_api_2023_10_31.bundled.schema.yaml # x-pack/platform/packages/shared/kbn-elastic-assistant/tsconfig.json # x-pack/solutions/security/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts
…y-assistant-content-references # Conflicts: # x-pack/solutions/security/plugins/elastic_assistant/scripts/draw_graph_script.ts # x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/index.test.ts # x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/index.ts # x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/run_agent.ts # x-pack/solutions/security/plugins/elastic_assistant/server/lib/langchain/graphs/default_assistant_graph/nodes/translations.ts
|
Starting backport for target branches: 8.x https://github.com/elastic/kibana/actions/runs/13023066804 |
💛 Build succeeded, but was flaky
Failed CI StepsTest Failures
Metrics [docs]Module Count
Public APIs missing comments
Async chunks
Page load bundle
Unknown metric groupsAPI count
History
cc @KDKHD |
💔 All backports failed
Manual backportTo create the backport manually run: Questions ?Please refer to the Backport tool documentation |
💚 All backports created successfully
Note: Successful backport PRs will be merged automatically after passing CI. Questions ?Please refer to the Backport tool documentation |
Note
Planning to merge before the 9.0 feature freeze.
Documentation update issue: elastic/security-docs#6473
Tip
Tip for the reviewer
As a starting point to review this PR I would suggest reading the section "How does it work (on a high level)" and viewing the hyperlinked code. The linked code covers the main concepts of this feature and the majority of the remaining changes in the PR are related to API schema updates and tests.
Summary
This PR adds citations to the security AI assistant. Citations are produced when tools are used and they are displayed in the LLM response as numbered superscript elements. A label appears when the user hovers over the numbered elements and clicking on the label opens a new tab that displays the cited data.
How to test:
How does it work (on a high level)?
Citations are stored inside the ContentReferencesStore object. When tools are called, the tools add citations to the ContentReferencesStore and pass the Id of the ContentReferences back to the LLM along side the result of the tool. The LLM can then use those contentReference IDs in its response by forming a response like:
The web client parses out the contentReference (
{reference(12345)}) from the assistant message and replaces it with the citation react component.Tools that are cited:
Include citations for the following tools:
alert_counts_tool -> cites to alerts page
knowledge_base_retrieval_tool -> cites knowledge base management page with specific entry pre-filtered
open_and_acknowledged_alerts_tool -> cites to specific alert
security_labs_tool -> cites knowledge base management page with specific entry pre-filtered
knowledge_base indices -> opens ESQL view selecting the particular document used
product_documentation -> cites documentation
Endpoints impacted
Considerations:
Once these blockers have been addressed, ContentReferencesStore could easily be refactored to the graph state.
On few occasions, you can nudge the LLM a bit more to include citations by appending "Include citations" to your message.
Furthermore, the settings menu has been updated to include anonymized values and citation toggles:

Checklist
Check the PR satisfies following conditions.
Reviewers should verify this PR satisfies this list as well.
release_note:breakinglabel should be applied in these situations.release_note:*label is applied per the guidelinesIdentify risks
Does this PR introduce any risks? For example, consider risks like hard to test bugs, performance regression, potential of data loss.
Describe the risk, its severity, and mitigation for each identified risk. Invite stakeholders and evaluate how to proceed before merging.
Release note
Adds in-text citations to security solution AI assistant responses.