第 16 期:实战 — 构建企业知识问答系统
系统架构
graph TB
subgraph "数据入库层"
Docs[企业文档] --> Upload[批量上传]
Upload --> Chunk[智能分段]
Chunk --> Embed[Embedding]
Embed --> VDB[(Weaviate 向量库)]
end
subgraph "应用层 (Dify Chatflow)"
User[员工提问] --> QC[Question Classifier]
QC -->|专业问题| KR[Knowledge Retrieval]
QC -->|闲聊| Chat[直接对话]
KR --> VDB
KR --> LLM[LLM 生成回答]
LLM --> Source[附加引用来源]
Source --> Answer[Answer 节点]
Chat --> Answer
end
subgraph "前端展示层"
Answer --> WebApp[Dify Web App]
Answer --> API[嵌入企业内网]
Answer --> WeCom[企业微信机器人]
end步骤一:批量导入文档
import os
import requests
CONSOLE_TOKEN = "your-console-token"
DATASET_ID = "your-dataset-id"
BASE_URL = "http://localhost/console/api"
def upload_documents(folder_path: str):
"""批量上传文件夹中的所有文档"""
for filename in os.listdir(folder_path):
if filename.endswith(('.pdf', '.txt', '.md', '.docx')):
filepath = os.path.join(folder_path, filename)
with open(filepath, 'rb') as f:
response = requests.post(
f"{BASE_URL}/datasets/{DATASET_ID}/document/create-by-file",
headers={"Authorization": f"Bearer {CONSOLE_TOKEN}"},
files={"file": (filename, f)},
data={
"indexing_technique": "high_quality",
"process_rule": '{"mode": "automatic"}'
}
)
if response.status_code == 200:
print(f"✅ 上传成功: {filename}")
else:
print(f"❌ 上传失败: {filename} - {response.text}")
upload_documents("/path/to/company/docs")
步骤二:配置 Chatflow
LLM 节点的 System Prompt 设计:
# 角色
你是「XX公司」的内部知识助手,负责回答员工关于公司政策、产品技术、流程规范的问题。
# 上下文
{{#knowledge_retrieval.result#}}
# 回答规则
1. 仅基于上述"上下文"中的信息回答
2. 如果上下文中没有相关信息,回复:"抱歉,我在现有文档中没有找到相关信息。建议联系 [email protected]。"
3. 如有引用,标注文档来源
4. 使用清晰的 Markdown 格式
5. 回答要专业但易懂
步骤三:嵌入企业内网
<!-- 在企业内网页面嵌入 Dify Chatbot -->
<iframe
src="http://dify.internal.company.com/chatbot/your-app-token"
style="width: 100%; height: 600px; border: none; border-radius: 12px;"
allow="microphone">
</iframe>
<!-- 或使用浮动按钮 -->
<script>
window.difyChatbotConfig = {
token: 'your-app-token',
baseUrl: 'http://dify.internal.company.com'
};
</script>
<script src="http://dify.internal.company.com/embed.min.js" defer></script>
步骤四:引用溯源
# 解析回答中的引用来源
def format_answer_with_sources(api_response: dict) -> str:
answer = api_response["answer"]
sources = api_response.get("metadata", {}).get("retriever_resources", [])
if sources:
answer += "\n\n---\n📚 **参考来源:**\n"
for i, src in enumerate(sources, 1):
answer += f"{i}. {src['document_name']} (相关度: {src['score']:.2f})\n"
return answer