我被一个“工作流大师”气笑了:别让智能体被平台绑架, 不是任何时候都要用平台.

吐槽警告:本文尽量讲道理。平台并非原罪,过度依赖才是问题。


起因:一个只会“查下百度”的智能体

最近在项目组里,我看见一个“智能体”被郑重地上了 Dify 工作流。结果呢?它的全部本领是——查询一下百度,然后在结果上贴几句提示词。就这?说实话,我更愿意让大模型自己用工具,顺带保持上下文,甚至多轮澄清。为什么要把一条直线的事情,绕成一个固定死的流程图呢?


为什么我更倾向于用模型的“工具调用能力”

  • 灵活对话:模型可以边对话边决策是否调用工具,天然支持澄清问题、补充信息、反问用户。
  • 低耦合:工具是函数或接口,替换搜索源/数据源不用改一张复杂工作流图。
  • 易演进:今天只查百度,明天加个“重试+多源搜索+投票融合”,代码里加策略即可。
  • 状态连续:上下文和中间产物放在对话里或内存里,天然多轮;不需要在流程节点之间传一堆变量。

而工作流的常见问题是:

  • 固化路径:每一步都被框死,模型没有探索或自我修正的空间。
  • 迭代成本高:改一个分支得改连锁节点,还要发布版本、同步环境。
  • 调试不透明:出了问题只能看节点日志,难以复现模型“想法”与中间草稿。
  • 额外运维:不同环境分别维护 API Key、变量、连接器授权,版本漂移风险直线上升。
  • 适用场景固定: 工作流只能处理单一场景或者固定场景.

我最心累的一点:明明是“让模型更像人类地解题”,却把它束缚在一个流程图里走格子。

这么说我觉得你可能不能更贴切的体会到这种痛苦, 我举一个现实中面临的问题:

  • 我们配置了一个工作流
  • 用户输入一些常见的企业问题, 然后它会查询百度
  • 然后找出相关的案例
  • 然后分析汇总, 得到一篇标准的报告.

这看起来是好的, 但是假设用户输入了一句: 讲个笑话, 本意是想听一个笑话, 但是此时死板的工作流会去百度上搜索笑话, 然后分析汇总, 得到一篇标准的关于笑话的报告, 从不同的维度剖析笑话的本质....

此时, 若要解决这个问题, 那就必须在前置流程中增加一个语义判断节点.

但你以为这样就完了吗?

接下来好玩儿的来了, 此时用户输入了适合工作流的内容, 并得到了标准内容, 然后用户想让AI改写一下其中的某个部分, 或者指出了某部分的不合理, 让它重新百度一下. 你猜如何?

没错, 这个'智能体'又开始在百度上搜索不合理内容, 然后分析汇总, 从不同的角度剖析....

是的, 这样的智能体一点也不智能. 甚至是非常蠢, 说真的, 还不如直接用DeepSeek或者豆包呢. 这种做法成功的将大模型本身就具备的能力硬生生给开发成了智障.


一个更简单的做法:让模型自己“会用工具”

下面这段用“模型工具调用”的思路,做一件和“查百度+整合回答”一样的事,但更灵活,还能持续对话。

# 依赖: pip install openai httpx beautifulsoup4
# 说明: 仅示意“工具调用+对话”,实际生产建议使用正规的搜索API,而非直接抓HTML。
import httpx
from bs4 import BeautifulSoup
from openai import OpenAI

client = OpenAI(api_key="YOUR_API_KEY")  # 任意支持 tool/function-calling 的大模型都行

def search_baidu(query: str, top_k: int = 5):
    r = httpx.get("https://www.baidu.com/s", params={"wd": query}, timeout=10)
    r.raise_for_status()
    soup = BeautifulSoup(r.text, "html.parser")
    items = []
    for i, res in enumerate(soup.select(".result")[:top_k], 1):
        title = res.select_one("h3") or res.select_one("h3 a")
        snippet = res.get_text(" ", strip=True)[:200]
        items.append({"rank": i, "title": title.get_text(strip=True) if title else "N/A", "snippet": snippet})
    return items

tools = [
    {
        "type": "function",
        "function": {
            "name": "search_baidu",
            "description": "Search Baidu results and return top snippets",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string"},
                    "top_k": {"type": "integer", "default": 5, "minimum": 1, "maximum": 10},
                },
                "required": ["query"]
            }
        }
    }
]

def tool_router(name, args):
    if name == "search_baidu":
        return search_baidu(**args)
    raise ValueError("Unknown tool")

history = [{"role": "system", "content": "你是一个会使用搜索工具的助理。"}]

def chat(user_msg: str):
    history.append({"role": "user", "content": user_msg})
    resp = client.chat.completions.create(
        model="gpt-4o-mini",  # 任意支持工具调用的模型
        messages=history,
        tools=tools,
        tool_choice="auto",
        temperature=0.2
    )
    msg = resp.choices[0].message

    # 若模型请求调用工具
    if msg.tool_calls:
        for call in msg.tool_calls:
            result = tool_router(call.function.name, eval(call.function.arguments))
            history.append({
                "role": "tool",
                "tool_call_id": call.id,
                "name": call.function.name,
                "content": str(result)
            })
        # 再次让模型整合工具返回
        final = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=history,
            temperature=0.2
        )
        answer = final.choices[0].message.content
    else:
        answer = msg.content

    history.append({"role": "assistant", "content": answer})
    return answer

# 使用示例
print(chat("帮我看看今天北京的天气相关新闻,概括要点,并给出来源。"))
print(chat("把要点压缩为3条,并给出一个标题。"))

这段代码体现了三件事:

  • 模型能自主决定何时调用工具
  • 对话是连续的,能在第二轮继续压缩、改写
  • 搜索源可替换,扩展策略只需增添工具或调整“系统提示词”

工作流的“隐形成本”

  • 延迟叠加:节点一多,编排/网络/序列化的开销也多。总延迟近似为
    \( T_{\text{total}} \approx \sum_i T_{\text{node}_i} + T_{\text{orchestration}} \)
  • 版本爆炸:一个分支一个版本,开发/测试/预发/生产四套环境再乘以 N 个工作流,维护 API Key 和变量配置的人会崩溃。
  • 调试脱敏:平台常做脱敏或只展示“摘要日志”,遇到复杂 Prompt 交互时,问题定位效率大打折扣。
  • 迁移困难:换模型、换供应商、换策略,常常意味着“重新画图+重走审批”。

我不是反平台,我反“过度依赖”

平台有其价值,尤其是:

  • 团队协作、权限与审计
  • 可视化编排、非技术同学可参与
  • 统一的观测、配额与速率限制
  • 内置向量库、RAG 组件、Webhook/集成生态

但我反对把“能用代码三百行清爽搞定”的东西,强行放进工作流里,然后背上:

  • 灵活性损失
  • 额外延迟
  • 配置与密钥的重复维护
  • 复杂问题的低可调试性

API Key 的小吐槽

不同环境要单独维护 API Key,我见过的真实翻车:

  • 测试环境忘记更新 Key,生产正常、测试全挂,大家以为是模型坏了
  • 多平台串用同一 Key,配额莫名其妙见底
  • Key 放在平台变量里,调试脚本另设一份,谁在用、费用算谁的,最后没人说得清

最简单的方案往往是:用配置中心+密钥管理服务,应用层解耦;工具调用在代码里拆分责任边界,清清楚楚。


一张简表:什么时候用平台,什么时候用代码

场景 更推荐
低代码团队、需要可视化编排/审批/审计 平台
复杂动态推理、需要自由探索与重试策略 代码
多团队协作、统一监控与配额管控 平台
高度定制、频繁实验、快速迭代 代码

结语:让模型“像人”一点

我不反对 Dify 这类平台;我反对的是把它们当成“唯一的锤子”。一个只会“查下百度+贴提示词”的智能体,真的不需要一整套工作流去“装样子”。给模型一点自由,再给工程一点简洁,我们的系统会更快、更稳、更便宜,也更容易进化。

工具用在该用的地方,智能体就会更智能。

posted @ 2025-09-30 17:14  Only丿阿海  阅读(2)  评论(0)    收藏  举报