IcyBlog

记录实战dify搭建类perplexity搜索智能体

技术
2,357 12 分钟

前言

深度用了接近一年的perplexity,感觉很不错很不错,于是想自建一个累死的用于学习,此处使用dify

成品

_2026-07-03_16.57.19

思路

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的每一轮循环都要重新跑一次完整的深度思考

一次简单查询下来,思考时长加起来接近一分钟,而实际搜索本身耗时才几秒

解决办法也简单,无非几种:

  1. 关掉推理模式,搜索决策本身不需要很深的思考
  2. 把max tokens调低
  3. 更彻底的做法是拆开架构:调度决策用不开思考的模型,只在最后总结阶段单独接一个开了推理的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

评论

Markdown

评论区加载中…