crewai — 本课题摘录
读了哪几篇: 01-agent-loop(Agent 执行循环)。
其余三篇(Crew 编排、Flow 引擎、横切设施)本轮没读——属多 agent 与工作流课题。
这一家在本课题里的位置:它是"怎么认出模型要调工具"这一问的双轨方案代表。
它对本课题回答了什么
决定二:怎么认出模型要调工具 —— 两条路,开循环前二选一
| 路径 | 模型怎么表达"我要调工具" | 什么时候走这条 |
|---|---|---|
| 原生工具调用 | 直接返回结构化的调用对象 | 模型声明自己支持,且确实挂了工具 |
| 文本 ReAct | 输出 Thought: … / Action: … / Action Input: … 纯文本,框架正则解析 | 模型不支持,或原生调用被拒绝时降级 |
(依据:前沿库 · CrewAI · Agent 执行循环 —— 开循环前按 supports_function_calling 且有工具二选一,走 _invoke_loop_native_tools 或 _invoke_loop_react)
决定二的关键:运行时降级,而不是启动时判断
这是最值得抄的一条。 模型声称支持不等于真支持——网关可能不支持、模型版本可能变。它的做法是:
选了原生路径 → 真跑起来报「不支持原生工具调用」的错
│
▼
往历史里塞一句「 请改用文本格式调工具」的说明
│
▼
当场切回文本 ReAct,这次执行不失败
(依据:前沿库 · CrewAI · Agent 执行循环 —— 原生路径捕获到 is_native_tool_calling_unsupported_error 时,先往历史追加「请用文本格式调工具」的说明,再改走 _invoke_loop_react,不让整次执行失败)
这条对我们直接有用。 换厂商这件事本课题不管,但"同一个模型在运行时才暴露出不支持某个能力"是循环必须处理的——它给的答案是能力探测放在运行时、降级路径事先备好。
决定二补充:文本协议的解析要能容忍半残的 JSON
文本路径下,工具输入是模型手写的 JSON,经常是半残的。它先过一道自动修复。 (依据:前沿库 · CrewAI · Agent 执行循环 —— 文本 ReAct 路径下工具输入先过 _safe_repair_json 用 json_repair 容错修复,因为 LLM 经常吐出半残 JSON)
既没有动作也没有最终答案时,抛解析错误,循环捕获后把格式说明喂回让模型重试——又 一次"报错即教学"。
停用词是文本路径的配套件: ReAct 靠 Observation 这类停用词截断模型输出,免得模型自己把观测也编出来。用不用取决于模型支不支持停用词。
(依据:前沿库 · CrewAI · Agent 执行循环 —— ReAct 模式靠 Observation 之类停用词截断输出,是否使用取决于模型 supports_stop_words())
跟 smolagents 的"把代码闭合标签加进停止序列"是同一招:让模型在该停的地方停,而不是让它把系统该说的话也编出来。
决定三:结果怎么回填 —— 原生路径每轮只执行第一个调用
一个明确的取舍:即使模型一次返回多个工具调用,也只执行第一个,然后让模型看着结果再想。 (依据:前沿库 · CrewAI · Agent 执行循环 —— _handle_native_tool_calls 每轮只执行第一个 tool call,注释说明这是为了「每个工具后都能反思」,让 LLM 基于结果再决定下一步)
执行完还会主动塞一条"请基于刚才的结果继续推理"的提示再进下一轮。
这跟 vercel-ai-sdk / openai-agents-js 的"并行执行这一轮的所有调用"是直接对立的选择。 对立点在于:并行省时间,串行 + 反思省错误。这是本课题一个要自己拍板的 地方。
决定四:什么时候停 —— 三个兜底 + 一条硬契约
| 情况 | 处理 |
|---|---|
| 迭代超过上限 | 强制收尾,逼出一个"最终答案" |
| 上下文长度超限 | 裁剪历史后继续重试 |
| 解析失败 | 把格式说明喂回让模型改正 |
(依据:前沿库 · CrewAI · Agent 执行循环 —— 三处保护分别是 handle_max_iterations_exceeded 强制收尾、respect_context_window 时 handle_context_length 裁剪后 continue、handle_output_parser_exception 把格式说明喂回)
硬契约:循环只在拿到"最终答案"时退出;否则末尾直接抛错说"没能给出最终答案"。
这一条比 cline 的"抛错兜底"更明确:它不允许循环悄悄结束——要么有答案,要么明确失败。