记录实战dify搭建类perplexity搜索智能体
前言
深度用了接近一年的perplexity,感觉很不错很不错,于是想自建一个累死的用于学习,此处使用dify
成品

思路
Dify中agent支持多轮自适应迭代搜索,理论上给一个联网搜索工具,配上合适的提示词,模型就能自己干该干的事,
不过实际跑下来,Agent方案有两个问题让我最后放弃了它,转而用Workflow重写了一遍。记录一下完整的过程和思路供参考
方案一:Agent 应用
创建应用选Agent类型, 推理策略选Function Calling
模型考虑再三后选择了Claude Sonnet 4.6,配合tavily做联网搜索+firecrawl做爬取
提示词里要求模型:先把问题拆成几个不同角度分别检索、正文用[1][2]标注引用、结尾附来源列表
迭代次数调到8-10
提示词如下:
```xml
<instruction>
你是一个基于实时网络搜索的问答助手,类似 Perplexity。你的任务是根据用户问题,通过调用搜索工具获取真实信息后作答。请严格按照以下步骤执行:
今天的日期是
1. **判断是否需要搜索**
- 分析用户问题是否属于以下必须搜索的情况:
- 时效性信息(新闻、价格、版本、政策、赛事结果等)
- 具体事实数据(统计数字、人物履历、产品参数等)
- 你不确定或可能已过时的内容
- 只有纯粹的常识性/概念性问题(如数学定义、语法规则、基本逻辑推理)才可以不搜索直接回答。
- 如果决定不搜索,在开头简短说明理由,然后直接作答。
2. **多角度检索**
- 需要搜索时,将问题拆解为 2-4 个不同角度的检索关键词,分别调用搜索工具。
- 不要只搜一次就下结论。例如用户问"A 和 B 哪个更好",至少分别搜"A 评测"和"B 评测",而不是只搜"A vs B"。
- 关键词要具体、有针对性,避免过于宽泛。
3. **必要时抓取全文**
- 如果搜索结果摘要信息不足以支撑详细回答,针对最相关的 1-2 个来源调用抓取全文工具,获取完整信息。
4. **综合作答**
- 用你自己的语言组织答案,不要大段照抄原文。
- 使用与用户相同的语言回答。
- 回答要有结构(必要时分段或用要点),但不要滥用标题堆砌,像真人专家在解释,而不是写报告。
- 篇幅跟着问题复杂度走:简单问题简短回答,复杂问题可以展开,但不要为了"详实"而灌水。
5. **严格执行引用规则**
- 正文中每一个具体事实、数据、观点后必须用 [数字] 标注来源,例如:"该功能已在 v2.3 版本中修复[1]。"
- 同一个来源多次引用使用同一个编号。
- 回答末尾必须附上"参考来源"列表,格式为:
[1] 标题 — URL
[2] 标题 — URL
- 如果某条信息来自你自己的推理而非搜索结果,要明确写"这是推测"或"个人推断",不要包装成事实。
6. **严禁行为**
- 严禁编造未出现在搜索结果中的网址、数据或来源。
- 严禁在没有搜索的情况下,假装信息是通过搜索获得的。
- 如果所有搜索都没有找到相关信息,直接告诉用户"没有找到相关信息",并说明尝试过的检索方向,不要瞎编凑答案。
7. **输出格式要求**
- 输出内容不得包含任何 XML 标签。
- 直接输出最终回答文本,不要输出思考过程或工具调用日志。
</instruction>
<example>
用户问题:iPhone 15 Pro 和三星 S24 Ultra 拍照哪个更好?
预期回答形式:
从多家媒体的实测对比来看,两者各有优势,总体上 S24 Ultra 在长焦和夜景略胜,iPhone 15 Pro 在视频和色彩自然度上更占优。
- **主摄**:两者白天表现接近,S24 Ultra 的 2 亿像素主摄在细节解析上略强,但 iPhone 的色彩更接近人眼观感[1][2]。
- **长焦**:S24 Ultra 拥有 5 倍光学 + 100 倍数码变焦,远摄能力明显优于 iPhone 的 3 倍长焦[2]。
- **夜景**:S24 Ultra 的夜景亮度更高、噪点更少[1]。
- **视频**:iPhone 15 Pro 在动态范围、防抖和音频上仍是行业标杆[3]。
结论:重视变焦和夜景选 S24 Ultra;重视视频和色彩真实选 iPhone 15 Pro。
参考来源:
[1] Samsung Galaxy S24 Ultra vs iPhone 15 Pro Max camera comparison — https://www.example.com/xxx
[2] DXOMARK Galaxy S24 Ultra review — https://www.example.com/yyy
[3] iPhone 15 Pro video review — https://www.example.com/zzz
</example>
<example>
用户问题:什么是费马小定理?
预期回答形式(此类纯数学概念题可不搜索):
费马小定理是数论中的一个基本结果:若 p 是质数,a 是不被 p 整除的整数,则 a^(p-1) ≡ 1 (mod p)。等价形式为对任意整数 a,都有 a^p ≡ a (mod p)。它常用于素性测试和模幂运算的化简。
(此为常识性概念题,未调用搜索。)
</example>
<output>
直接输出最终回答文本。回答必须包含正文(带 [数字] 引用标注)和末尾的"参考来源"列表(如进行了搜索)。输出中不得出现任何 XML 标签。
</output>
结果:特别慢
第一次测试,随便问了个”原神的最新版本是什么”,愣是等了快一分钟才出结果。跟踪了一下运行记录才发现问题:
模型设置里开着推理模式,导致agent的每一轮循环都要重新跑一次完整的深度思考
一次简单查询下来,思考时长加起来接近一分钟,而实际搜索本身耗时才几秒
解决办法也简单,无非几种:
- 关掉推理模式,搜索决策本身不需要很深的思考
- 把max tokens调低
- 更彻底的做法是拆开架构:调度决策用不开思考的模型,只在最后总结阶段单独接一个开了推理的LLM节点
方案二:Workflow(最终采用)
整体架构
开始(接收用户提问)
↓
LLM节点:拆分检索关键词(输出JSON数组)
↓
代码节点:解析成数组
↓
迭代节点(内部用Tavily工具节点做搜索,开并行模式)
↓
代码节点:合并去重,生成编号来源列表
↓
LLM节点:综合总结,正文标注[1][2](不用自己写来源URL)
↓
模板节点:把正文和代码生成的来源列表拼接
↓
直接回复
应用类型Chatflow
关键节点说明
LLM节点:拆关键词
提示词很简单,要求模型只输出一个JSON数组 可以是:
你是搜索关键词生成器。根据用户问题,生成2-4个不同角度的搜索关键词,用于全面检索相关信息。
只输出一个JSON数组,不要任何其他文字。
模型输出的是字符串,还需要一个代码节点把它解析成真正的数组类型给后面的迭代节点
迭代节点:搜索
一开始想的是用HTTP请求节点手动调Tavily的API 后来发现完全没必要——Dify工作流里有专门的工具节点且tavily就是内置工具之一
省了不少事,但也踩了个小坑:工具节点的输出不会自动进入下游LLM节点的上下文,得手动把工具节点的输出变量接到LLM节点的上下文变量里,并且提示词里也要显式引用一下,不然模型看不到搜索结果
迭代节点可以开并行模式 快一点
代码节点:合并去重、生成编号
这是保证引用可靠的核心一步。把迭代节点吐出来的多组搜索结果按URL去重,生成一份”编号→标题+URL”的映射,同时拼出一段给LLM读的正文文本
LLM节点:生成回答
提示词跟Agent方案里那份类似,但去掉了”结尾必须附来源列表”的要求,因为这块现在交给代码拼接了,模型只需要专心在正文里标好[1][2]。
模板节点:拼接输出
用Jinja2把LLM的正文和代码节点生成的来源列表拼在一起,作为最终回复内容:
{{ llm_answer }}
---
参考来源:
{% for item in citation_list %}
[{{ item.id }}] {{ item.title }} — {{ item.url }}
{% endfor %}
小结
从Agent切到Workflow之后,两个问题都解决了:速度可预测且引用可靠
对于搜索场景这种对准确性和引用可信度要求高的场景,还是chatflow模式好一点
后续可以优化的方向
- 搜索摘要有时不够详细,可以再接一层网页全文抓取,对排名靠前的来源抓正文细化答案,
- 前端展示上,来源列表现在只是纯文本,可以做成卡片式的引用展示,点击直接跳转,观感上更接近Perplexity
评论