mirror of
https://github.com/Tencent/WeKnora.git
synced 2026-09-21 05:43:43 +08:00
feat: Update agent system prompt and frontend citation handling for wiki sources
- Enhanced the agent system prompt to clarify citation formats for wiki and chunk sources, ensuring accurate inline citations. - Introduced a new citation format section in the prompt, detailing the required syntax for both wiki pages and knowledge chunks. - Updated the frontend to visually align wiki citations with knowledge base citations, improving user experience and consistency in citation presentation. - Implemented truncation for long wiki labels in citations to maintain visual consistency in chat bubbles. These changes improve the clarity and usability of citations in the agent system, enhancing the overall information retrieval process.
This commit is contained in:
@@ -439,18 +439,30 @@ templates:
|
||||
|
||||
6. **Synthesize:**
|
||||
- Build an answer grounded in content actually retrieved this turn.
|
||||
- Cite every source: wiki pages as `[[slug|display name]]`, chunks as `[knowledge_id#chunk_id]` (or the citation style expected by the product).
|
||||
- Attach citations inline using the formats defined in `<citation_format>` below.
|
||||
- When only one surface was reachable, note it briefly ("The bound KB only exposes X, so this answer is drawn entirely from X").
|
||||
</workflow>
|
||||
|
||||
<citation_format>
|
||||
Use EXACTLY these two formats (any other syntax renders as plain text):
|
||||
- Chunk (verifiable facts: quotes, numbers, code, names): `<kb doc="..." chunk_id="..." kb_id="..." />`
|
||||
- Wiki page (concepts / overviews / navigation): `[[slug|display name]]`
|
||||
|
||||
All values MUST come from tool results of this turn — never fabricate a `chunk_id`, `kb_id`, or `slug`.
|
||||
|
||||
Placement: inline on the same line as the sentence it supports, one per source per paragraph, never grouped at the end, never wrapped in backticks.
|
||||
|
||||
Example: WeKnora 采用混合检索。<kb doc="架构设计.md" chunk_id="abc123" kb_id="kb-01" /> 详见 [[hybrid-retrieval|混合检索]]。
|
||||
</citation_format>
|
||||
|
||||
<constraints>
|
||||
ABSOLUTE RULES:
|
||||
1. **Evidence-Based Facts:** Ground every factual claim in content you retrieved *this turn*, either from wiki pages or from source chunks.
|
||||
2. **Wiki Never Replaces RAG for Exact Quotes:** Wiki pages are summaries. If the user asks for a direct quote, numeric value, code, or table row, you MUST read the underlying chunks via `list_knowledge_chunks` or `wiki_read_source_doc`.
|
||||
2. **Wiki Never Replaces RAG for Exact Quotes:** Wiki pages are summaries. If the user asks for a direct quote, numeric value, code, or table row, you MUST read the underlying chunks via `list_knowledge_chunks` or `wiki_read_source_doc` and cite them with `<kb .../>`.
|
||||
3. **Mandatory Deep Read:** Whenever `grep_chunks` or `knowledge_search` returns matched `knowledge_id`s / `chunk_id`s, you MUST immediately call `list_knowledge_chunks` to read the full content. Do NOT rely on search snippets.
|
||||
4. **Mandatory Wiki Read:** `wiki_search` returns summaries only. If a wiki hit is relevant, you MUST call `wiki_read_page` before citing it.
|
||||
4. **Mandatory Wiki Read:** `wiki_search` returns summaries only. If a wiki hit is relevant, you MUST call `wiki_read_page` before citing it via `[[slug|name]]`.
|
||||
5. **Always Re-Retrieve:** Every new user question triggers fresh retrieval. Do not reuse retrieved content from earlier turns.
|
||||
6. **Cite Both Sides:** When your answer draws on wiki context plus chunk evidence, cite both (`[[wiki slug|name]]` + chunk refs). Make the evidence chain explicit.
|
||||
6. **Cite Both Sides When Both Contributed:** If a claim came from a wiki overview AND was verified against a source chunk, cite both.
|
||||
7. **Flag Contradictions:** If wiki contradicts source chunks, call `wiki_flag_issue` on the wiki page before submitting the final answer.
|
||||
</constraints>
|
||||
|
||||
|
||||
@@ -422,7 +422,7 @@ const DOMPurifyConfig = {
|
||||
],
|
||||
ALLOWED_ATTR: [
|
||||
'href', 'title', 'target', 'rel', 'data-tooltip', 'data-url', 'data-kb-id',
|
||||
'data-chunk-id', 'data-doc', 'class', 'role', 'tabindex', 'src', 'alt', 'data-protected-src',
|
||||
'data-chunk-id', 'data-doc', 'data-slug', 'class', 'role', 'tabindex', 'src', 'alt', 'data-protected-src',
|
||||
'width', 'height', 'style', 'id',
|
||||
// Mermaid SVG 支持的属性
|
||||
'd', 'fill', 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin',
|
||||
@@ -1647,9 +1647,27 @@ const preprocessMarkdown = (contentStr: string): string => {
|
||||
// as such, so the chat bubble must match.
|
||||
if (!slug) return match;
|
||||
|
||||
// Truncate long wiki labels the same way KB citations do, so both
|
||||
// kinds of citation pills stay visually consistent in narrow bubbles.
|
||||
const truncateMiddle = (text: string, maxLength = 13): string => {
|
||||
if (!text) return '';
|
||||
if (text.length <= maxLength) return text;
|
||||
const half = Math.floor((maxLength - 3) / 2);
|
||||
const start = text.slice(0, half + ((maxLength - 3) % 2));
|
||||
const end = text.slice(-half);
|
||||
return `${start}...${end}`;
|
||||
};
|
||||
|
||||
const safeSlug = escapeHtml(slug);
|
||||
const safeDisplay = escapeHtml(display);
|
||||
return `<a href="#" class="wiki-content-link citation-wiki" data-slug="${safeSlug}">${safeDisplay}</a>`;
|
||||
const safeDisplay = escapeHtml(truncateMiddle(display));
|
||||
const tipSlug = escapeHtml(slug);
|
||||
const tipDisplay = escapeHtml(display);
|
||||
// Render as the same pill shape the KB citation uses (class
|
||||
// `citation citation-wiki`) so the two retrieval sources share a
|
||||
// single visual language. Anchor tag is kept for accessibility
|
||||
// and keyboard handling; `data-slug` is preserved for the
|
||||
// existing click/keyboard handlers above.
|
||||
return `<a href="#" class="citation citation-wiki" data-slug="${safeSlug}" role="button" tabindex="0" title="${tipDisplay}"><span class="citation-icon wiki"></span><span class="citation-text">${safeDisplay}</span><span class="citation-tip"><span class="tip-title">${tipDisplay}</span><span class="tip-meta">${tipSlug}</span></span></a>`;
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -3047,6 +3065,13 @@ const handleAddToKnowledge = (answerEvent: any) => {
|
||||
background-image: url("../../../assets/img/zhishiku-thin.svg");
|
||||
}
|
||||
|
||||
/* Wiki page icon — inline open-book SVG tinted brand blue (matches
|
||||
.citation-wiki text color). Inlined as a data URI so no new asset
|
||||
file is required. */
|
||||
:deep(.citation .citation-icon.wiki) {
|
||||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230052d9' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M2 4.5h6a4 4 0 0 1 4 4v12a3 3 0 0 0-3-3H2z'/><path d='M22 4.5h-6a4 4 0 0 0-4 4v12a3 3 0 0 1 3-3h7z'/></svg>");
|
||||
}
|
||||
|
||||
.kb-float-popup {
|
||||
position: absolute;
|
||||
z-index: 10000;
|
||||
@@ -3140,6 +3165,40 @@ const handleAddToKnowledge = (answerEvent: any) => {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Wiki citation pill — same shape as KB / web citations but in brand blue
|
||||
so the reader can tell at a glance whether evidence came from a
|
||||
wiki-synthesized page or from a raw source chunk. */
|
||||
:deep(.citation.citation-wiki) {
|
||||
background: var(--td-brand-color-light);
|
||||
color: var(--td-brand-color);
|
||||
border: 1px solid var(--td-brand-color-focus);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
:deep(.citation.citation-wiki:hover) {
|
||||
background: var(--td-brand-color-light);
|
||||
border-color: var(--td-brand-color);
|
||||
color: var(--td-brand-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
:deep(.citation.citation-wiki:focus-visible) {
|
||||
outline: 2px solid var(--td-brand-color);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Embedded tooltip bubble — hidden; relies on browser-native `title`
|
||||
attribute for hover preview. Keeps parity with citation-kb, which
|
||||
also hides its inline tip in favor of the floatPopup. */
|
||||
:deep(.citation.citation-wiki .citation-tip) {
|
||||
display: none !important;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.tool-arguments-wrapper {
|
||||
margin-top: 8px;
|
||||
padding: 0 10px;
|
||||
|
||||
Reference in New Issue
Block a user