背景痛点:为什么一上手机器人就被“技术黑话”劝退?
第一次打开 GitHub,搜索“对话机器人”,结果蹦出 Chatbot、Composer、Agent 三个关键词,文档一个比一个玄乎。
想做个能查天气的小助手,结果有人让你上 Rasa,有人让你写 Prompt,还有人让你画流程图。
最尴尬的是,吭哧两周把 Agent 搭上线,发现并发一高就 OOM,其实业务只是固定问答,用规则就能搞定。
选错技术路线,返工两次,老板问“为什么别人三天上线,你要三周?”——这就是区分三者的现实意义。
技术对比:一张表看懂 Chatbot vs Composer vs Agent
| 维度 | Chatbot(规则/ML) | Composer(流程编排) | Agent(自主决策) |
|---|---|---|---|
| 核心特征 | 关键词匹配或意图分类,对话路径固定 | 把多轮对话拆成可复用节点,可视化拖拽 | 大模型当“大脑”,可动态调用工具、改写计划 |
| 响应延迟 | 低(本地正则<10 ms) | 中(节点跳转 20~50 ms) | 高(LLM 推理 500~2000 ms) |
| 开发复杂度 | 低,上手即写 if/else | 中,需理解状态机、画布概念 | 高,需掌握 Prompt 工程、工具回调、纠错 |
| 典型场景 | 固定 FAQ、客服兜底菜单 | 订单查询、工单流转、审批流 | 开放域闲聊、多工具联合(查天气+发邮件) |
实现示例:三行代码跑通最小原型
以下示例均用 Python 3.9+ 测试通过,依赖只装必要包,注释把“为什么”写清,方便直接改。
1. Chatbot:基于关键词的最小规则机器人
# pip install flask from flask import Flask, request, jsonify app = Flask(__name__) FAQ = { "运费": "全场满99包邮", "退货": "7天无理由退货" } @app.post("/chat") def chat(): q = request.json.get("query", "") # 默认兜底 ans = FAQ.get(q, "暂未找到答案,请输入关键词:运费/退货") return jsonify({"reply": ans}) if __name__ == "__main__": app.run()异常处理:未传 JSON 时 Flask 会抛 400,已内置;若需更友好,可捕获 BadRequest。
2. Composer:用状态机编排“查订单→改地址”流程
# pip install transitions from transitions import Machine class OrderBot: states = ["start", "ask_order_id", "ask_address", "done"] def __init__(self): self.machine = Machine( model=self, states=OrderBot.states, initial="start", auto_transitions=False ) self.machine.add_transition("trigger_order", "start", "ask_order_id") self.machine.add_transition("input_id", "ask_order_id", "ask_address") self.machine.add_transition("input_addr", "ask_address", "done") bot = OrderBot() # 模拟用户输入 bot.trigger_order() # start -> ask_order_id bot.input_id() # ask_order_id -> ask_address bot.input_addr() # ask_address -> done print("当前状态:", bot.state) # -> done异常处理:若状态跳转失败,transitions 会抛出 MachineError,用 try/except 包住即可返回友好提示。
3. Agent:让大模型自己决定要不要调用天气 API
# pip install openai requests import os, json, requests, openai from openai import OpenaiError client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) def search_weather(city: str) -> str: """伪天气工具,真实场景可接火山引擎天气 API""" return f"{city}今天25°C,晴" tools = [{ "name": "search_weather", "description": "查询城市天气", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}} }] def agent_run(user_input: str): try: response = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": user_input}], tools=tools, tool_choice="auto" ) msg = response.choices[0].message if msg.tool_calls: # 模型决定调用工具 city = json.loads(msg.tool_calls[0].function.arguments)["city"] return search_weather(city) return msg.content except OpenaiError as e: return f"模型调用失败:{e}" print(agent_run("北京天气如何?"))异常处理:捕获 OpenaiError 并返回文本,避免前端直接暴露堆栈。
生产考量:内存、并发与状态管理
- 内存占用
- Chatbot 只加载字典,百 KB 级;Composer 随节点数线性增长,MB 级;Agent 需加载大模型,显存 2~6 GB。
- 并发处理
- Chatbot 无状态,直接水平扩展;Composer 需共享状态存储(Redis),否则多实例状态不一致;Agent 每次请求都伴随后端 LLM 调用,需做流控或缓存。
- 对话状态管理策略
- Chatbot:可放内存,重启即清空,适合低频。
- Composer:推荐外置状态机+Redis,支持断点续聊。
- Agent:把历史消息拼进 Prompt,需控制 token 长度;可定期摘要,避免超限。
避坑指南:新手最容易踩的 3 个坑
- 用 Agent 做固定流程
症状:把 Prompt 写成“第一步…第二步…”,结果大模型偶尔跳过步骤。
解决:流程一旦确定,用 Composer 画节点,比 Prompt 更可靠。 - 状态放全局变量
症状:Flask 多线程下用户 A 的状态被用户 B 覆盖。
解决:用线程隔离(threading.local)或直接把状态丢进 Redis。 - 忽略 LLM 延迟
症状:并发一上来,接口 5 s 才返回,用户体验崩。
解决:流式输出(stream=True)+ 前端分段渲染,或把 Agent 降级为 Composer 兜底。
互动环节:你的业务适合谁?
假设你要给 10 万骑手做“派送问题答疑”机器人,对话内容 80% 是“如何修改收货地址”“运费谁出”等固定问题,偶尔出现新表述。你会:
A. 直接用 Chatbot 关键词匹配
B. 用 Composer 把“查订单→改地址”画成流程
C. 用 Agent 让大模型自由回答
欢迎留言选 A/B/C 并说说理由,我们一起讨论最优解。
写在最后:把选型思路落到手上
把上面的最小原型跑通后,你会发现:
- 规则最快,别笑 if/else,它常是 MVP 的救命稻草;
- 流程图一旦超过 10 个节点,Composer 的拖拽比写代码更直观;
- 只有当业务真的“说不准下一步要问什么”时,Agent 才值得付出算力成本。
如果你已经手痒,想亲手把“耳朵-大脑-嘴巴”串成一条完整实时通话链路,不妨看看这个动手实验——
从0打造个人豆包实时通话AI
实验把火山引擎的 ASR、LLM、TTS 三件套封装成可运行的 Web 项目,本地装个 Node 就能跑。
我跟着一步步搭完,大概花了 40 分钟,最惊喜的是音色可以一键切换,延迟稳定在 600 ms 左右,对小白足够友好。
选完技术路线,再亲手跑通一条端到端链路,你会对“对话系统”四个字有全新的体感。