Appearance
Answer 组件
概述
Answer组件是RAGFlow工作流的终端输出组件,负责接收上游组件生成的内容并将其作为最终答案返回给用户。它是工作流的最后一个环节,处理结果格式化、引用整理、以及与用户的交互反馈。
主要功能
- 📤 工作流最终输出和结果展示
- 📋 答案格式化和美化处理
- 🔗 引用信息整理和展示
- 💬 支持流式和批量输出模式
- ⏸️ 支持多轮对话的暂停点
适用场景
- 聊天机器人的最终回答展示
- 知识问答系统的结果输出
- 报告生成的最终呈现
- 多轮对话的中间暂停点
- 工作流执行结果的统一输出
参数配置
基础参数
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
response_format | string | 否 | "text" | 响应格式类型 |
show_citations | boolean | 否 | true | 是否显示引用信息 |
max_display_length | number | 否 | 0 | 最大显示长度(0为不限制) |
格式化参数
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
markdown_enabled | boolean | 否 | true | 启用Markdown渲染 |
auto_wrap | boolean | 否 | true | 自动换行处理 |
highlight_keywords | boolean | 否 | false | 关键词高亮显示 |
详细说明
response_format (响应格式)
- 类型: 字符串枚举
- 可选值:
"text","markdown","html","json" - 描述: 指定最终输出的格式类型
- 默认值:
"text"
show_citations (显示引用)
- 类型: 布尔值
- 描述: 是否在答案末尾显示引用来源信息
- 默认值:
true
max_display_length (最大显示长度)
- 类型: 正整数
- 描述: 限制显示内容的最大字符数,0表示不限制
- 用途: 防止过长内容影响用户体验
输入输出
输入格式
Answer组件接受上游组件的任何内容:
json
{
"content": "要展示的最终答案内容",
"component_id": "upstream_component_id",
"reference": [...], // 可选的引用信息
"metadata": {...} // 可选的元数据
}输出格式
json
{
"content": "格式化后的最终答案",
"component_id": "answer_component_id",
"display_format": "text",
"references_shown": true,
"truncated": false,
"user_interaction_required": true,
"timestamp": "2024-01-12T10:30:00Z"
}前端实现
节点组件
typescript
// web/src/pages/flow/canvas/node/answer-node.tsx
export function AnswerNode({ id, data, isConnectable, selected }: NodeProps) {
return (
<section className={`${styles.ragNode} ${selected ? styles.selectedNode : ''}`}>
{/* 只有输入连接点,没有输出 */}
<Handle
type="target"
position={Position.Left}
isConnectable={isConnectable}
className={styles.handle}
/>
<NodeHeader id={id} name={data.name} label={data.label} />
<div className={styles.nodeBody}>
<div className={styles.nodeInfo}>
<Icon component={CheckCircleOutlined} className={styles.nodeIcon} />
<span className={styles.nodeDescription}>最终输出</span>
</div>
<div className={styles.configSummary}>
<div className={styles.configItem}>
<span className={styles.configLabel}>格式:</span>
<span className={styles.configValue}>
{data.form.response_format || 'text'}
</span>
</div>
</div>
<div className={styles.statusBadges}>
{data.form.show_citations && (
<span className={styles.statusBadge}>
<Icon component={LinkOutlined} />
引用
</span>
)}
{data.form.markdown_enabled && (
<span className={styles.statusBadge}>
<Icon component={FormatPainterOutlined} />
Markdown
</span>
)}
</div>
</div>
</section>
);
}配置表单
typescript
// web/src/pages/flow/form/answer-form/index.tsx
const AnswerForm: React.FC<IOperatorForm> = ({ onValuesChange, form }) => {
return (
<Form form={form} layout="vertical" onValuesChange={onValuesChange}>
<Form.Item
name="response_format"
label="响应格式"
tooltip="选择最终输出的格式类型"
>
<Select placeholder="选择响应格式">
<Option value="text">纯文本</Option>
<Option value="markdown">Markdown</Option>
<Option value="html">HTML</Option>
<Option value="json">JSON</Option>
</Select>
</Form.Item>
<Form.Item
name="show_citations"
label="显示引用信息"
valuePropName="checked"
>
<Switch checkedChildren="显示" unCheckedChildren="隐藏" />
</Form.Item>
<Form.Item
name="markdown_enabled"
label="启用Markdown渲染"
valuePropName="checked"
>
<Switch checkedChildren="启用" unCheckedChildren="禁用" />
</Form.Item>
<Form.Item
name="max_display_length"
label="最大显示长度"
tooltip="0表示不限制长度"
>
<InputNumber
min={0}
max={10000}
style={{ width: '100%' }}
placeholder="0(不限制)"
/>
</Form.Item>
</Form>
);
};后端实现
参数类
python
# agent/component/answer.py
class AnswerParam(ComponentParamBase):
"""Answer组件参数"""
def __init__(self):
super().__init__()
self.response_format = "text" # 响应格式
self.show_citations = True # 显示引用
self.max_display_length = 0 # 最大显示长度
self.markdown_enabled = True # Markdown渲染
def check(self):
"""参数验证"""
valid_formats = ["text", "markdown", "html", "json"]
if self.response_format not in valid_formats:
raise ValueError(f"响应格式必须是: {valid_formats}")
if self.max_display_length < 0:
raise ValueError("最大显示长度不能为负数")组件类
python
class Answer(ComponentBase):
"""Answer组件实现"""
component_name = "Answer"
def _run(self, history, **kwargs):
"""
处理最终答案输出
"""
# 获取上游输入
input_df = self.get_input()
if input_df.empty:
content = "没有可显示的内容。"
references = []
else:
content = input_df.iloc[0]["content"]
references = input_df.iloc[0].get("reference", [])
# 格式化内容
formatted_content = self._format_content(content)
# 添加引用信息
if self._param.show_citations and references:
formatted_content = self._add_citations(formatted_content, references)
# 长度截断
if self._param.max_display_length > 0:
formatted_content = self._truncate_content(formatted_content)
return pd.DataFrame([{
"content": formatted_content,
"component_id": self._id,
"display_format": self._param.response_format,
"references_shown": self._param.show_citations and bool(references),
"truncated": len(content) > self._param.max_display_length > 0,
"user_interaction_required": True,
"timestamp": datetime.now().isoformat()
}])
def _format_content(self, content):
"""格式化内容"""
if self._param.response_format == "markdown" and self._param.markdown_enabled:
return self._enhance_markdown(content)
elif self._param.response_format == "html":
return self._convert_to_html(content)
elif self._param.response_format == "json":
return self._structure_as_json(content)
else:
return content
def _add_citations(self, content, references):
"""添加引用信息"""
if not references:
return content
citation_text = "\n\n---\n**参考来源:**\n"
for i, ref in enumerate(references, 1):
citation_text += f"{i}. {ref.get('document_name', '未知来源')}"
if ref.get('page_number'):
citation_text += f" (第{ref['page_number']}页)"
citation_text += "\n"
return content + citation_text使用示例
示例1: 基础文本输出
json
{
"component_name": "Answer",
"params": {
"response_format": "text",
"show_citations": true,
"max_display_length": 0
}
}示例2: Markdown格式输出
json
{
"component_name": "Answer",
"params": {
"response_format": "markdown",
"show_citations": true,
"markdown_enabled": true,
"max_display_length": 2000
}
}示例3: 结构化JSON输出
json
{
"component_name": "Answer",
"params": {
"response_format": "json",
"show_citations": false,
"max_display_length": 0
}
}最佳实践
1. 格式选择建议
- text: 简单问答场景
- markdown: 需要富文本展示
- html: Web页面嵌入
- json: API接口返回
2. 引用展示优化
python
def format_citations(references):
"""优化引用格式"""
if not references:
return ""
grouped_refs = {}
for ref in references:
doc_name = ref.get('document_name', '未知文档')
if doc_name not in grouped_refs:
grouped_refs[doc_name] = []
grouped_refs[doc_name].append(ref.get('page_number'))
citation_parts = []
for doc_name, pages in grouped_refs.items():
if pages and all(p for p in pages):
page_list = sorted(set(p for p in pages if p))
citation_parts.append(f"{doc_name} (第{','.join(map(str, page_list))}页)")
else:
citation_parts.append(doc_name)
return "参考来源:" + ";".join(citation_parts)3. 长度控制策略
- 保留完整句子
- 智能截断位置
- 添加截断提示
常见问题
Q1: Answer组件是否必需?
A: 是的,每个工作流必须包含至少一个Answer组件作为输出端点。
Q2: 可以有多个Answer组件吗?
A: 可以,多个Answer组件用于不同的输出场景或条件分支。
Q3: 如何处理空输入?
A: Answer组件会显示默认提示信息,不会报错。
Q4: 引用格式可以自定义吗?
A: 可以通过修改组件参数和后端逻辑来自定义引用格式。
相关组件
前置组件
典型工作流模式
Generate → Answer
Retrieval → Generate → Answer
Begin → Categorize → [处理路径] → Answer
Template → Answer组件版本: v1.0.0
最后更新: 2025-01-12